Files
siftlode/frontend/src/lib/api/tokens.contract.test.ts
T
peter db56f25387 feat(files): API tokens in Settings, the Hub folder in Files, a notice before a token runs out
Settings gains an API tokens tab: a row per token (name and prefix; each
folder with its rights; last use and expiry, "expires soon" marked),
revoked from its menu behind a confirm. A new token is the Hub exchange in
one click, or folders and rights picked per folder (no Write where an
upload cannot land); expiry 30/90 days, 1 year or never (warned). The
token shows once in the same dialog, with Copy and a ready curl line.

The Hub folder closes the Sources in the Files rail, takes uploads and
moved-in files. A token about to run out warns its user once, a week
before (the Files GC's sixth pass); the notice opens the tokens tab.
2026-10-14 23:33:34 +02:00

27 lines
1.3 KiB
TypeScript

// @vitest-environment jsdom
import { readFileSync } from "node:fs";
import { resolve } from "node:path";
import { describe, expect, it } from "vitest";
import { TOKEN_EXPIRY_DAYS, TOKEN_RIGHTS } from "./tokens";
// The token dialog's choices, held to what the backend takes (apitokens.py, routes/tokens.py), read
// from their source as text — the backend cannot be imported here. A right the server does not know
// is a 422 for the whole token; an expiry past its ceiling likewise.
const backend = (file: string) =>
readFileSync(resolve(__dirname, `../../../../backend/app/${file}`), "utf-8");
describe("the token dialog's choices", () => {
it("are the backend's rights, in its order", () => {
const body = backend("apitokens.py").match(/^class Right\(StrEnum\):\n([\s\S]*?)\n\n/m)?.[1];
expect(body, "apitokens.py no longer defines Right").toBeTruthy();
const rights = [...body!.matchAll(/=\s*"(\w+)"/g)].map((m) => m[1]);
expect(TOKEN_RIGHTS).toEqual(rights);
});
it("last no longer than the backend allows", () => {
const max = Number(backend("routes/tokens.py").match(/^_MAX_EXPIRY_DAYS = (\d+)$/m)?.[1]);
expect(max).toBeGreaterThan(0);
for (const days of TOKEN_EXPIRY_DAYS) if (days !== null) expect(days).toBeLessThanOrEqual(max);
});
});