@levr-one/auth 1.1.1 → 1.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/config.d.ts +12 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +68 -8
- package/dist/config.js.map +1 -1
- package/dist/config.test.js +50 -1
- package/dist/config.test.js.map +1 -1
- package/dist/connection-error.d.ts +24 -0
- package/dist/connection-error.d.ts.map +1 -0
- package/dist/connection-error.js +56 -0
- package/dist/connection-error.js.map +1 -0
- package/dist/connection-error.test.d.ts +2 -0
- package/dist/connection-error.test.d.ts.map +1 -0
- package/dist/connection-error.test.js +63 -0
- package/dist/connection-error.test.js.map +1 -0
- package/dist/logout-args.d.ts +36 -0
- package/dist/logout-args.d.ts.map +1 -0
- package/dist/logout-args.js +100 -0
- package/dist/logout-args.js.map +1 -0
- package/dist/logout-args.test.d.ts +2 -0
- package/dist/logout-args.test.d.ts.map +1 -0
- package/dist/logout-args.test.js +72 -0
- package/dist/logout-args.test.js.map +1 -0
- package/dist/status-report.d.ts +91 -0
- package/dist/status-report.d.ts.map +1 -0
- package/dist/status-report.js +145 -0
- package/dist/status-report.js.map +1 -0
- package/dist/status-report.test.d.ts +2 -0
- package/dist/status-report.test.d.ts.map +1 -0
- package/dist/status-report.test.js +159 -0
- package/dist/status-report.test.js.map +1 -0
- package/dist/token-store.d.ts +43 -2
- package/dist/token-store.d.ts.map +1 -1
- package/dist/token-store.js +89 -25
- package/dist/token-store.js.map +1 -1
- package/dist/token-store.test.js +116 -0
- package/dist/token-store.test.js.map +1 -1
- package/dist/workspace-store.d.ts +13 -1
- package/dist/workspace-store.d.ts.map +1 -1
- package/dist/workspace-store.js +25 -2
- package/dist/workspace-store.js.map +1 -1
- package/dist/workspace-store.test.js +46 -0
- package/dist/workspace-store.test.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { parseLogoutArgs } from './logout-args.js';
|
|
3
|
+
describe('parseLogoutArgs', () => {
|
|
4
|
+
it('defaults to the configured backend when nothing is named', () => {
|
|
5
|
+
expect(parseLogoutArgs([])).toEqual({ kind: 'configured' });
|
|
6
|
+
});
|
|
7
|
+
// review F-002. `args.indexOf('--backend')` saw only the space-separated
|
|
8
|
+
// form, so `--backend=<url>` fell through to the CONFIGURED backend —
|
|
9
|
+
// clearing one the operator had not named, and exiting 0.
|
|
10
|
+
it.each([
|
|
11
|
+
['space-separated', ['--backend', 'http://localhost:9480']],
|
|
12
|
+
['inline', ['--backend=http://localhost:9480']],
|
|
13
|
+
])('accepts the %s --backend form', (_label, args) => {
|
|
14
|
+
expect(parseLogoutArgs(args)).toEqual({
|
|
15
|
+
kind: 'backend',
|
|
16
|
+
url: 'http://localhost:9480',
|
|
17
|
+
});
|
|
18
|
+
});
|
|
19
|
+
it.each([
|
|
20
|
+
['space-separated', ['--env', 'staging']],
|
|
21
|
+
['inline', ['--env=staging']],
|
|
22
|
+
])('accepts the %s --env form', (_label, args) => {
|
|
23
|
+
expect(parseLogoutArgs(args)).toEqual({ kind: 'env', env: 'staging' });
|
|
24
|
+
});
|
|
25
|
+
it('normalizes a trailing slash on --backend', () => {
|
|
26
|
+
expect(parseLogoutArgs(['--backend=https://api.levr.now/'])).toEqual({
|
|
27
|
+
kind: 'backend',
|
|
28
|
+
url: 'https://api.levr.now',
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
it('recognises --all', () => {
|
|
32
|
+
expect(parseLogoutArgs(['--all'])).toEqual({ kind: 'all' });
|
|
33
|
+
});
|
|
34
|
+
// Fails CLOSED: an unrecognised argument must never fall back to a default
|
|
35
|
+
// target, which is the whole-file-wipe failure mode via argument parsing.
|
|
36
|
+
it.each([
|
|
37
|
+
[['--target', 'http://localhost:9480']],
|
|
38
|
+
[['--backened=http://localhost:9480']],
|
|
39
|
+
[['http://localhost:9480']],
|
|
40
|
+
[['--backend', 'http://x', '--extra']],
|
|
41
|
+
])('rejects unknown arguments %j', (args) => {
|
|
42
|
+
const r = parseLogoutArgs(args);
|
|
43
|
+
expect(r.kind).toBe('error');
|
|
44
|
+
expect(r.kind === 'error' && r.message).toMatch(/Unknown argument/);
|
|
45
|
+
});
|
|
46
|
+
it('rejects two targets rather than silently picking one', () => {
|
|
47
|
+
const r = parseLogoutArgs(['--backend=http://localhost:9480', '--all']);
|
|
48
|
+
expect(r.kind).toBe('error');
|
|
49
|
+
expect(r.kind === 'error' && r.message).toMatch(/only one of/);
|
|
50
|
+
});
|
|
51
|
+
it.each([
|
|
52
|
+
['a bare flag', ['--backend']],
|
|
53
|
+
['an empty inline value', ['--backend=']],
|
|
54
|
+
['a following flag', ['--backend', '--all']],
|
|
55
|
+
])('rejects --backend with no url (%s)', (_label, args) => {
|
|
56
|
+
expect(parseLogoutArgs(args).kind).toBe('error');
|
|
57
|
+
});
|
|
58
|
+
it.each(['localhost:8580', 'ftp://x', '/tmp/nope', 'api.levr.now'])('rejects %s as a backend url', (value) => {
|
|
59
|
+
const r = parseLogoutArgs([`--backend=${value}`]);
|
|
60
|
+
expect(r.kind).toBe('error');
|
|
61
|
+
expect(r.kind === 'error' && r.message).toMatch(/Not a backend url/);
|
|
62
|
+
});
|
|
63
|
+
it('rejects an unknown environment name', () => {
|
|
64
|
+
const r = parseLogoutArgs(['--env=staging-typo']);
|
|
65
|
+
expect(r.kind).toBe('error');
|
|
66
|
+
expect(r.kind === 'error' && r.message).toMatch(/Unknown environment/);
|
|
67
|
+
});
|
|
68
|
+
it.each(['local', 'staging', 'production'])('accepts --env %s', (env) => {
|
|
69
|
+
expect(parseLogoutArgs([`--env=${env}`])).toEqual({ kind: 'env', env });
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
//# sourceMappingURL=logout-args.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logout-args.test.js","sourceRoot":"","sources":["../src/logout-args.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAEnD,QAAQ,CAAC,iBAAiB,EAAE,GAAG,EAAE;IAC/B,EAAE,CAAC,0DAA0D,EAAE,GAAG,EAAE;QAClE,MAAM,CAAC,eAAe,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,CAAC,CAAC;IAC9D,CAAC,CAAC,CAAC;IAEH,yEAAyE;IACzE,sEAAsE;IACtE,0DAA0D;IAC1D,EAAE,CAAC,IAAI,CAAC;QACN,CAAC,iBAAiB,EAAE,CAAC,WAAW,EAAE,uBAAuB,CAAC,CAAC;QAC3D,CAAC,QAAQ,EAAE,CAAC,iCAAiC,CAAC,CAAC;KAChD,CAAC,CAAC,+BAA+B,EAAE,CAAC,MAAM,EAAE,IAAI,EAAE,EAAE;QACnD,MAAM,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC;YACpC,IAAI,EAAE,SAAS;YACf,GAAG,EAAE,uBAAuB;SAC7B,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,IAAI,CAAC;QACN,CAAC,iBAAiB,EAAE,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;QACzC,CAAC,QAAQ,EAAE,CAAC,eAAe,CAAC,CAAC;KAC9B,CAAC,CAAC,2BAA2B,EAAE,CAAC,MAAM,EAAE,IAAI,EAAE,EAAE;QAC/C,MAAM,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE,CAAC,CAAC;IACzE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0CAA0C,EAAE,GAAG,EAAE;QAClD,MAAM,CAAC,eAAe,CAAC,CAAC,iCAAiC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;YACnE,IAAI,EAAE,SAAS;YACf,GAAG,EAAE,sBAAsB;SAC5B,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kBAAkB,EAAE,GAAG,EAAE;QAC1B,MAAM,CAAC,eAAe,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IAC9D,CAAC,CAAC,CAAC;IAEH,2EAA2E;IAC3E,0EAA0E;IAC1E,EAAE,CAAC,IAAI,CAAC;QACN,CAAC,CAAC,UAAU,EAAE,uBAAuB,CAAC,CAAC;QACvC,CAAC,CAAC,kCAAkC,CAAC,CAAC;QACtC,CAAC,CAAC,uBAAuB,CAAC,CAAC;QAC3B,CAAC,CAAC,WAAW,EAAE,UAAU,EAAE,SAAS,CAAC,CAAC;KACvC,CAAC,CAAC,8BAA8B,EAAE,CAAC,IAAI,EAAE,EAAE;QAC1C,MAAM,CAAC,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC;QAChC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC7B,MAAM,CAAC,CAAC,CAAC,IAAI,KAAK,OAAO,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAC;IACtE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sDAAsD,EAAE,GAAG,EAAE;QAC9D,MAAM,CAAC,GAAG,eAAe,CAAC,CAAC,iCAAiC,EAAE,OAAO,CAAC,CAAC,CAAC;QACxE,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC7B,MAAM,CAAC,CAAC,CAAC,IAAI,KAAK,OAAO,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;IACjE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,IAAI,CAAC;QACN,CAAC,aAAa,EAAE,CAAC,WAAW,CAAC,CAAC;QAC9B,CAAC,uBAAuB,EAAE,CAAC,YAAY,CAAC,CAAC;QACzC,CAAC,kBAAkB,EAAE,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;KAC7C,CAAC,CAAC,oCAAoC,EAAE,CAAC,MAAM,EAAE,IAAI,EAAE,EAAE;QACxD,MAAM,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACnD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,IAAI,CAAC,CAAC,gBAAgB,EAAE,SAAS,EAAE,WAAW,EAAE,cAAc,CAAC,CAAC,CACjE,6BAA6B,EAC7B,CAAC,KAAK,EAAE,EAAE;QACR,MAAM,CAAC,GAAG,eAAe,CAAC,CAAC,aAAa,KAAK,EAAE,CAAC,CAAC,CAAC;QAClD,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC7B,MAAM,CAAC,CAAC,CAAC,IAAI,KAAK,OAAO,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,mBAAmB,CAAC,CAAC;IACvE,CAAC,CACF,CAAC;IAEF,EAAE,CAAC,qCAAqC,EAAE,GAAG,EAAE;QAC7C,MAAM,CAAC,GAAG,eAAe,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC;QAClD,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC7B,MAAM,CAAC,CAAC,CAAC,IAAI,KAAK,OAAO,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,qBAAqB,CAAC,CAAC;IACzE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,SAAS,EAAE,YAAY,CAAC,CAAC,CAAC,kBAAkB,EAAE,CAAC,GAAG,EAAE,EAAE;QACtE,MAAM,CAAC,eAAe,CAAC,CAAC,SAAS,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;IAC1E,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure decision logic behind `tq:status` (internal).
|
|
3
|
+
*
|
|
4
|
+
* Lives outside `cli.ts` for the same reason `scripts/setup-mcp-workspace.lib.ts`
|
|
5
|
+
* lives outside `setup-mcp.ts`: that module ends in a self-executing `switch`,
|
|
6
|
+
* so importing it from a test would run a CLI command against the developer's
|
|
7
|
+
* real `~/.tq`. Everything here is pure — the caller does the fs reading and
|
|
8
|
+
* passes the parsed values in.
|
|
9
|
+
*
|
|
10
|
+
* ## The defect this exists to prevent
|
|
11
|
+
*
|
|
12
|
+
* `tq:status` used to render its per-environment block from the three
|
|
13
|
+
* hardcoded `ENV_URLS` presets, while `tq:login` stores a token under the
|
|
14
|
+
* backend's real URL. On any local that is not literally `http://localhost:8080`
|
|
15
|
+
* — every worktree, every DEV_TLS checkout — the block therefore reported a
|
|
16
|
+
* backend the user had not logged into and could not refresh: a stale
|
|
17
|
+
* `local: expired 157366m ago (active)` that survived every login, sitting
|
|
18
|
+
* directly beneath a `Status: valid` line describing a different token.
|
|
19
|
+
*
|
|
20
|
+
* The load-bearing assertion in the tests is that a backend absent from
|
|
21
|
+
* `ENV_URLS` is still listed, and that "active" is decided by URL rather than
|
|
22
|
+
* by environment name.
|
|
23
|
+
*/
|
|
24
|
+
/** One rendered row of the stored-token table. */
|
|
25
|
+
export interface TokenRow {
|
|
26
|
+
/** True for the backend `~/.tq/config.json` currently points at. */
|
|
27
|
+
active: boolean;
|
|
28
|
+
url: string;
|
|
29
|
+
/** `local` / `staging` / `production` / `custom`. */
|
|
30
|
+
label: string;
|
|
31
|
+
/** e.g. `valid 738m`, `expired 12m ago`. */
|
|
32
|
+
expiry: string;
|
|
33
|
+
}
|
|
34
|
+
export declare function formatExpiry(expiresAt: number, now: number): string;
|
|
35
|
+
/**
|
|
36
|
+
* Human label for a stored backend URL.
|
|
37
|
+
*
|
|
38
|
+
* `resolveEnvFromUrl` only recognises the three `ENV_URLS` presets, so every
|
|
39
|
+
* worktree-offset local and every DEV_TLS local comes back unnamed — which is
|
|
40
|
+
* most of a working machine's token map. Loopback and the `.levr.test` dev
|
|
41
|
+
* domain are local by construction, so name them rather than render a dozen
|
|
42
|
+
* indistinguishable `custom` rows.
|
|
43
|
+
*/
|
|
44
|
+
export declare function labelForBackend(url: string): string;
|
|
45
|
+
/**
|
|
46
|
+
* Build the stored-token table from the backends the token map ACTUALLY holds.
|
|
47
|
+
*
|
|
48
|
+
* `activeUrl` is matched by URL, never by environment name: the name `local`
|
|
49
|
+
* maps to the hardcoded `:8080` preset, which on a worktree is a different
|
|
50
|
+
* backend from the configured one.
|
|
51
|
+
*
|
|
52
|
+
* Active row first, then alphabetical — deterministic, so the table does not
|
|
53
|
+
* reshuffle between runs.
|
|
54
|
+
*/
|
|
55
|
+
export declare function buildTokenRows(entries: ReadonlyArray<{
|
|
56
|
+
url: string;
|
|
57
|
+
tokens: {
|
|
58
|
+
expiresAt: number;
|
|
59
|
+
};
|
|
60
|
+
}>, activeUrl: string | undefined, now: number): TokenRow[];
|
|
61
|
+
/**
|
|
62
|
+
* Map a `levr` MCP URL to the backend URL that `~/.tq/oauth-tokens.json` and
|
|
63
|
+
* `~/.tq/workspace.json` are keyed by, so the MCP entry can be compared
|
|
64
|
+
* against the configured backend.
|
|
65
|
+
*
|
|
66
|
+
* The MCP host is not the API host for the hosted environments — both are
|
|
67
|
+
* reached through the client origin's `/api` proxy — so the levr URL cannot be
|
|
68
|
+
* compared directly. The aliases are DERIVED from `PRESETS` rather than
|
|
69
|
+
* written out, so they cannot drift from the environment definitions.
|
|
70
|
+
*
|
|
71
|
+
* Twin of `identityKeyFromLevrUrl` in `scripts/setup-mcp-workspace.lib.ts`,
|
|
72
|
+
* which resolves the same key on the WRITE side. `scripts/` imports no
|
|
73
|
+
* workspace package, so the two cannot share code today; deriving from
|
|
74
|
+
* `PRESETS` is what keeps this copy honest.
|
|
75
|
+
*/
|
|
76
|
+
export declare function backendUrlForLevrMcp(levrUrl: string): string;
|
|
77
|
+
/** The `levr` server entry, extracted from a parsed `.mcp.json`. */
|
|
78
|
+
export interface LevrMcpEntry {
|
|
79
|
+
url: string;
|
|
80
|
+
workspaceId?: string;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Pull the `levr` entry out of a parsed `.mcp.json`.
|
|
84
|
+
*
|
|
85
|
+
* Returns undefined for every shape that does not carry a usable URL —
|
|
86
|
+
* missing file, wrong type, no `levr` server, no `url`. Reporting nothing is
|
|
87
|
+
* correct here: the section is diagnostic, and a guess about which control
|
|
88
|
+
* plane an agent is talking to is worse than silence.
|
|
89
|
+
*/
|
|
90
|
+
export declare function levrEntryFrom(parsed: unknown): LevrMcpEntry | undefined;
|
|
91
|
+
//# sourceMappingURL=status-report.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status-report.d.ts","sourceRoot":"","sources":["../src/status-report.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAKH,kDAAkD;AAClD,MAAM,WAAW,QAAQ;IACvB,oEAAoE;IACpE,MAAM,EAAE,OAAO,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,qDAAqD;IACrD,KAAK,EAAE,MAAM,CAAC;IACd,4CAA4C;IAC5C,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAGnE;AAED;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAkBnD;AAED;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAC5B,OAAO,EAAE,aAAa,CAAC;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE;QAAE,SAAS,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,CAAC,EACtE,SAAS,EAAE,MAAM,GAAG,SAAS,EAC7B,GAAG,EAAE,MAAM,GACV,QAAQ,EAAE,CAYZ;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAiB5D;AAED,oEAAoE;AACpE,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,OAAO,GAAG,YAAY,GAAG,SAAS,CAsBvE"}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure decision logic behind `tq:status` (internal).
|
|
3
|
+
*
|
|
4
|
+
* Lives outside `cli.ts` for the same reason `scripts/setup-mcp-workspace.lib.ts`
|
|
5
|
+
* lives outside `setup-mcp.ts`: that module ends in a self-executing `switch`,
|
|
6
|
+
* so importing it from a test would run a CLI command against the developer's
|
|
7
|
+
* real `~/.tq`. Everything here is pure — the caller does the fs reading and
|
|
8
|
+
* passes the parsed values in.
|
|
9
|
+
*
|
|
10
|
+
* ## The defect this exists to prevent
|
|
11
|
+
*
|
|
12
|
+
* `tq:status` used to render its per-environment block from the three
|
|
13
|
+
* hardcoded `ENV_URLS` presets, while `tq:login` stores a token under the
|
|
14
|
+
* backend's real URL. On any local that is not literally `http://localhost:8080`
|
|
15
|
+
* — every worktree, every DEV_TLS checkout — the block therefore reported a
|
|
16
|
+
* backend the user had not logged into and could not refresh: a stale
|
|
17
|
+
* `local: expired 157366m ago (active)` that survived every login, sitting
|
|
18
|
+
* directly beneath a `Status: valid` line describing a different token.
|
|
19
|
+
*
|
|
20
|
+
* The load-bearing assertion in the tests is that a backend absent from
|
|
21
|
+
* `ENV_URLS` is still listed, and that "active" is decided by URL rather than
|
|
22
|
+
* by environment name.
|
|
23
|
+
*/
|
|
24
|
+
import { resolveEnvFromUrl } from './token-store.js';
|
|
25
|
+
import { PRESETS } from './config.js';
|
|
26
|
+
export function formatExpiry(expiresAt, now) {
|
|
27
|
+
const mins = Math.round((expiresAt - now) / 1000 / 60);
|
|
28
|
+
return now >= expiresAt ? `expired ${-mins}m ago` : `valid ${mins}m`;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Human label for a stored backend URL.
|
|
32
|
+
*
|
|
33
|
+
* `resolveEnvFromUrl` only recognises the three `ENV_URLS` presets, so every
|
|
34
|
+
* worktree-offset local and every DEV_TLS local comes back unnamed — which is
|
|
35
|
+
* most of a working machine's token map. Loopback and the `.levr.test` dev
|
|
36
|
+
* domain are local by construction, so name them rather than render a dozen
|
|
37
|
+
* indistinguishable `custom` rows.
|
|
38
|
+
*/
|
|
39
|
+
export function labelForBackend(url) {
|
|
40
|
+
const preset = resolveEnvFromUrl(url);
|
|
41
|
+
if (preset)
|
|
42
|
+
return preset;
|
|
43
|
+
try {
|
|
44
|
+
const { hostname } = new URL(url);
|
|
45
|
+
if (hostname === 'localhost' ||
|
|
46
|
+
hostname === '127.0.0.1' ||
|
|
47
|
+
hostname === '[::1]' ||
|
|
48
|
+
hostname === 'levr.test' ||
|
|
49
|
+
hostname.endsWith('.levr.test')) {
|
|
50
|
+
return 'local';
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
// Not a parseable URL — fall through to `custom`.
|
|
55
|
+
}
|
|
56
|
+
return 'custom';
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Build the stored-token table from the backends the token map ACTUALLY holds.
|
|
60
|
+
*
|
|
61
|
+
* `activeUrl` is matched by URL, never by environment name: the name `local`
|
|
62
|
+
* maps to the hardcoded `:8080` preset, which on a worktree is a different
|
|
63
|
+
* backend from the configured one.
|
|
64
|
+
*
|
|
65
|
+
* Active row first, then alphabetical — deterministic, so the table does not
|
|
66
|
+
* reshuffle between runs.
|
|
67
|
+
*/
|
|
68
|
+
export function buildTokenRows(entries, activeUrl, now) {
|
|
69
|
+
return entries
|
|
70
|
+
.map((e) => ({
|
|
71
|
+
active: !!activeUrl && e.url === activeUrl,
|
|
72
|
+
url: e.url,
|
|
73
|
+
label: labelForBackend(e.url),
|
|
74
|
+
expiry: formatExpiry(e.tokens.expiresAt, now),
|
|
75
|
+
}))
|
|
76
|
+
.sort((a, b) => {
|
|
77
|
+
if (a.active !== b.active)
|
|
78
|
+
return a.active ? -1 : 1;
|
|
79
|
+
return a.url.localeCompare(b.url);
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Map a `levr` MCP URL to the backend URL that `~/.tq/oauth-tokens.json` and
|
|
84
|
+
* `~/.tq/workspace.json` are keyed by, so the MCP entry can be compared
|
|
85
|
+
* against the configured backend.
|
|
86
|
+
*
|
|
87
|
+
* The MCP host is not the API host for the hosted environments — both are
|
|
88
|
+
* reached through the client origin's `/api` proxy — so the levr URL cannot be
|
|
89
|
+
* compared directly. The aliases are DERIVED from `PRESETS` rather than
|
|
90
|
+
* written out, so they cannot drift from the environment definitions.
|
|
91
|
+
*
|
|
92
|
+
* Twin of `identityKeyFromLevrUrl` in `scripts/setup-mcp-workspace.lib.ts`,
|
|
93
|
+
* which resolves the same key on the WRITE side. `scripts/` imports no
|
|
94
|
+
* workspace package, so the two cannot share code today; deriving from
|
|
95
|
+
* `PRESETS` is what keeps this copy honest.
|
|
96
|
+
*/
|
|
97
|
+
export function backendUrlForLevrMcp(levrUrl) {
|
|
98
|
+
const base = levrUrl.replace(/\/+$/, '').replace(/\/v1\/mcp$/, '');
|
|
99
|
+
// ONLY the two hosted presets. `PRESETS.local` must never join this list:
|
|
100
|
+
// under DEV_TLS it is `LOCAL_HTTPS`, whose clientUrl+`/api` is
|
|
101
|
+
// `https://ai.levr.test:3020/api` — a real key in the token map that has to
|
|
102
|
+
// resolve VERBATIM. Adding it would rewrite that key to
|
|
103
|
+
// `https://api.levr.test:8080` and make the entry unreachable, and the
|
|
104
|
+
// "keys a DEV_TLS local verbatim" test would still pass, because
|
|
105
|
+
// `isTestEnv()` makes PRESETS.local the plain-HTTP variant. The test below
|
|
106
|
+
// that asserts this exclusion holds under TLS is the one that would catch
|
|
107
|
+
// it. (review F-006)
|
|
108
|
+
for (const preset of [PRESETS.staging, PRESETS.production]) {
|
|
109
|
+
if (base === `${preset.clientUrl}/api`)
|
|
110
|
+
return preset.apiUrl;
|
|
111
|
+
}
|
|
112
|
+
// Everything else keys verbatim: that base IS the URL the backend was
|
|
113
|
+
// reached at when its token was stored (worktree locals, DEV_TLS).
|
|
114
|
+
return base;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Pull the `levr` entry out of a parsed `.mcp.json`.
|
|
118
|
+
*
|
|
119
|
+
* Returns undefined for every shape that does not carry a usable URL —
|
|
120
|
+
* missing file, wrong type, no `levr` server, no `url`. Reporting nothing is
|
|
121
|
+
* correct here: the section is diagnostic, and a guess about which control
|
|
122
|
+
* plane an agent is talking to is worse than silence.
|
|
123
|
+
*/
|
|
124
|
+
export function levrEntryFrom(parsed) {
|
|
125
|
+
if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
126
|
+
return undefined;
|
|
127
|
+
}
|
|
128
|
+
const servers = parsed.mcpServers;
|
|
129
|
+
if (servers === null || typeof servers !== 'object')
|
|
130
|
+
return undefined;
|
|
131
|
+
const levr = servers.levr;
|
|
132
|
+
if (levr === null || typeof levr !== 'object')
|
|
133
|
+
return undefined;
|
|
134
|
+
const { url, headers } = levr;
|
|
135
|
+
if (typeof url !== 'string' || !url)
|
|
136
|
+
return undefined;
|
|
137
|
+
const wsId = headers !== null && typeof headers === 'object'
|
|
138
|
+
? headers['Workspace-Id']
|
|
139
|
+
: undefined;
|
|
140
|
+
return {
|
|
141
|
+
url,
|
|
142
|
+
workspaceId: typeof wsId === 'string' && wsId ? wsId : undefined,
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
//# sourceMappingURL=status-report.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status-report.js","sourceRoot":"","sources":["../src/status-report.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status-report.test.d.ts","sourceRoot":"","sources":["../src/status-report.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { PRESETS } from './config.js';
|
|
3
|
+
import { backendUrlForLevrMcp, buildTokenRows, formatExpiry, labelForBackend, levrEntryFrom, } from './status-report.js';
|
|
4
|
+
const NOW = 1_700_000_000_000;
|
|
5
|
+
const at = (minutes) => ({ expiresAt: NOW + minutes * 60_000 });
|
|
6
|
+
describe('buildTokenRows', () => {
|
|
7
|
+
// The regression this whole module exists for: the old block rendered the
|
|
8
|
+
// three hardcoded ENV_URLS presets, so a worktree-offset local was invisible
|
|
9
|
+
// and the `:8080` row it printed instead could never be refreshed.
|
|
10
|
+
it('lists a backend that is not one of the three presets', () => {
|
|
11
|
+
const rows = buildTokenRows([{ url: 'http://localhost:9480', tokens: at(60) }], 'http://localhost:9480', NOW);
|
|
12
|
+
expect(rows.map((r) => r.url)).toEqual(['http://localhost:9480']);
|
|
13
|
+
});
|
|
14
|
+
it('decides "active" by url, not by environment name', () => {
|
|
15
|
+
const rows = buildTokenRows([
|
|
16
|
+
{ url: 'http://localhost:8080', tokens: at(-99999) },
|
|
17
|
+
{ url: 'http://localhost:9480', tokens: at(60) },
|
|
18
|
+
], 'http://localhost:9480', NOW);
|
|
19
|
+
// Both are "local" by name. Only the configured URL is active — marking
|
|
20
|
+
// the :8080 preset active is exactly the old bug.
|
|
21
|
+
expect(rows.filter((r) => r.active).map((r) => r.url)).toEqual([
|
|
22
|
+
'http://localhost:9480',
|
|
23
|
+
]);
|
|
24
|
+
expect(rows.every((r) => r.label === 'local')).toBe(true);
|
|
25
|
+
});
|
|
26
|
+
it('puts the active row first, then sorts the rest alphabetically', () => {
|
|
27
|
+
const rows = buildTokenRows([
|
|
28
|
+
{ url: 'https://api.levr.now', tokens: at(60) },
|
|
29
|
+
{ url: 'http://localhost:8080', tokens: at(60) },
|
|
30
|
+
{ url: 'http://localhost:9480', tokens: at(60) },
|
|
31
|
+
], 'http://localhost:9480', NOW);
|
|
32
|
+
expect(rows.map((r) => r.url)).toEqual([
|
|
33
|
+
'http://localhost:9480',
|
|
34
|
+
'http://localhost:8080',
|
|
35
|
+
'https://api.levr.now',
|
|
36
|
+
]);
|
|
37
|
+
});
|
|
38
|
+
it('marks nothing active when the configured backend has no token', () => {
|
|
39
|
+
const rows = buildTokenRows([{ url: 'https://api.levr.now', tokens: at(60) }], 'http://localhost:9480', NOW);
|
|
40
|
+
expect(rows.some((r) => r.active)).toBe(false);
|
|
41
|
+
});
|
|
42
|
+
it('marks nothing active when there is no configured backend', () => {
|
|
43
|
+
const rows = buildTokenRows([{ url: 'https://api.levr.now', tokens: at(60) }], undefined, NOW);
|
|
44
|
+
expect(rows.some((r) => r.active)).toBe(false);
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
describe('formatExpiry', () => {
|
|
48
|
+
it('reports remaining minutes while valid', () => {
|
|
49
|
+
expect(formatExpiry(NOW + 90 * 60_000, NOW)).toBe('valid 90m');
|
|
50
|
+
});
|
|
51
|
+
it('reports elapsed minutes once expired', () => {
|
|
52
|
+
expect(formatExpiry(NOW - 12 * 60_000, NOW)).toBe('expired 12m ago');
|
|
53
|
+
});
|
|
54
|
+
it('treats the exact expiry instant as expired', () => {
|
|
55
|
+
expect(formatExpiry(NOW, NOW)).toBe('expired 0m ago');
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
describe('labelForBackend', () => {
|
|
59
|
+
it('names the presets', () => {
|
|
60
|
+
expect(labelForBackend('https://api.levr.now')).toBe('staging');
|
|
61
|
+
expect(labelForBackend('https://api.levr.one')).toBe('production');
|
|
62
|
+
expect(labelForBackend('http://localhost:8080')).toBe('local');
|
|
63
|
+
});
|
|
64
|
+
it('names a worktree-offset loopback backend local', () => {
|
|
65
|
+
expect(labelForBackend('http://localhost:9480')).toBe('local');
|
|
66
|
+
expect(labelForBackend('http://127.0.0.1:9480')).toBe('local');
|
|
67
|
+
});
|
|
68
|
+
it('names the DEV_TLS dev domain local', () => {
|
|
69
|
+
expect(labelForBackend('https://ai.levr.test:3020/api')).toBe('local');
|
|
70
|
+
expect(labelForBackend('https://api.levr.test:8080')).toBe('local');
|
|
71
|
+
});
|
|
72
|
+
it('names the levr.test apex local, not just its subdomains', () => {
|
|
73
|
+
expect(labelForBackend('https://levr.test:3020')).toBe('local');
|
|
74
|
+
});
|
|
75
|
+
it('falls back to custom for a remote backend', () => {
|
|
76
|
+
expect(labelForBackend('https://backend.testquality.net')).toBe('custom');
|
|
77
|
+
});
|
|
78
|
+
it('falls back to custom for an unparseable url', () => {
|
|
79
|
+
expect(labelForBackend('not a url')).toBe('custom');
|
|
80
|
+
});
|
|
81
|
+
it('does not treat a lookalike host as local', () => {
|
|
82
|
+
// `.endsWith('.levr.test')` must not match an attacker-ish suffix host.
|
|
83
|
+
expect(labelForBackend('https://evil-levr.test.example.com')).toBe('custom');
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
describe('backendUrlForLevrMcp', () => {
|
|
87
|
+
it('maps the hosted staging MCP url to the api host it is keyed by', () => {
|
|
88
|
+
expect(backendUrlForLevrMcp('https://ai.levr.now/api/v1/mcp')).toBe('https://api.levr.now');
|
|
89
|
+
});
|
|
90
|
+
it('maps the hosted production MCP url to the api host it is keyed by', () => {
|
|
91
|
+
expect(backendUrlForLevrMcp('https://ai.levr.one/api/v1/mcp')).toBe('https://api.levr.one');
|
|
92
|
+
});
|
|
93
|
+
it('keys a worktree local verbatim', () => {
|
|
94
|
+
expect(backendUrlForLevrMcp('http://localhost:9780/v1/mcp')).toBe('http://localhost:9780');
|
|
95
|
+
});
|
|
96
|
+
it('keys a DEV_TLS local verbatim, keeping the /api prefix', () => {
|
|
97
|
+
// This exact string is a real key in the token map — rewriting it would
|
|
98
|
+
// make the entry unreachable.
|
|
99
|
+
expect(backendUrlForLevrMcp('https://ai.levr.test:3020/api/v1/mcp')).toBe('https://ai.levr.test:3020/api');
|
|
100
|
+
});
|
|
101
|
+
it('keeps two different worktree ports distinct', () => {
|
|
102
|
+
expect(backendUrlForLevrMcp('http://localhost:8180/v1/mcp')).not.toBe(backendUrlForLevrMcp('http://localhost:8580/v1/mcp'));
|
|
103
|
+
});
|
|
104
|
+
// review F-006. `PRESETS.local` must never join the alias loop: under
|
|
105
|
+
// DEV_TLS its clientUrl+/api is `https://ai.levr.test:3020/api`, a real key
|
|
106
|
+
// in the token map that has to resolve verbatim. Asserting against
|
|
107
|
+
// PRESETS.local itself pins the exclusion in BOTH modes — a hardcoded
|
|
108
|
+
// DEV_TLS string cannot, because isTestEnv() forces the plain-HTTP preset
|
|
109
|
+
// and the assertion would pass over a broken function.
|
|
110
|
+
it('never aliases the local preset, whichever variant is active', () => {
|
|
111
|
+
const localMcp = `${PRESETS.local.clientUrl}/api/v1/mcp`;
|
|
112
|
+
expect(backendUrlForLevrMcp(localMcp)).toBe(`${PRESETS.local.clientUrl}/api`);
|
|
113
|
+
expect(backendUrlForLevrMcp(localMcp)).not.toBe(PRESETS.local.apiUrl);
|
|
114
|
+
});
|
|
115
|
+
it('tolerates a trailing slash', () => {
|
|
116
|
+
expect(backendUrlForLevrMcp('https://ai.levr.now/api/v1/mcp/')).toBe('https://api.levr.now');
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
describe('levrEntryFrom', () => {
|
|
120
|
+
const config = {
|
|
121
|
+
mcpServers: {
|
|
122
|
+
levr: {
|
|
123
|
+
type: 'http',
|
|
124
|
+
url: 'https://ai.levr.now/api/v1/mcp',
|
|
125
|
+
headers: { 'Workspace-Id': 'ws-1' },
|
|
126
|
+
},
|
|
127
|
+
'qinetic-mcp': { type: 'stdio' },
|
|
128
|
+
},
|
|
129
|
+
};
|
|
130
|
+
it('extracts the url and the Workspace-Id header', () => {
|
|
131
|
+
expect(levrEntryFrom(config)).toEqual({
|
|
132
|
+
url: 'https://ai.levr.now/api/v1/mcp',
|
|
133
|
+
workspaceId: 'ws-1',
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
it('returns the url alone when no Workspace-Id is pinned', () => {
|
|
137
|
+
expect(levrEntryFrom({ mcpServers: { levr: { url: 'http://x/v1/mcp' } } })).toEqual({ url: 'http://x/v1/mcp', workspaceId: undefined });
|
|
138
|
+
});
|
|
139
|
+
it.each([
|
|
140
|
+
['null', null],
|
|
141
|
+
['an array', []],
|
|
142
|
+
['a string', 'nope'],
|
|
143
|
+
['no mcpServers', {}],
|
|
144
|
+
['no levr server', { mcpServers: { 'qinetic-mcp': { type: 'stdio' } } }],
|
|
145
|
+
['a levr server with no url', { mcpServers: { levr: { type: 'http' } } }],
|
|
146
|
+
['a non-string url', { mcpServers: { levr: { url: 42 } } }],
|
|
147
|
+
['an empty url', { mcpServers: { levr: { url: '' } } }],
|
|
148
|
+
])('returns undefined for %s', (_label, input) => {
|
|
149
|
+
expect(levrEntryFrom(input)).toBeUndefined();
|
|
150
|
+
});
|
|
151
|
+
it('ignores a non-string Workspace-Id rather than rendering it', () => {
|
|
152
|
+
expect(levrEntryFrom({
|
|
153
|
+
mcpServers: {
|
|
154
|
+
levr: { url: 'http://x/v1/mcp', headers: { 'Workspace-Id': 7 } },
|
|
155
|
+
},
|
|
156
|
+
})).toEqual({ url: 'http://x/v1/mcp', workspaceId: undefined });
|
|
157
|
+
});
|
|
158
|
+
});
|
|
159
|
+
//# sourceMappingURL=status-report.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status-report.test.js","sourceRoot":"","sources":["../src/status-report.test.ts"],"names":[],"mappings":"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"}
|
package/dist/token-store.d.ts
CHANGED
|
@@ -60,6 +60,23 @@ export declare function loadTokensForEnv(env: EnvName): StoredTokens | null;
|
|
|
60
60
|
* `--target <url>` and the CLI fetches the matching token entry by URL.
|
|
61
61
|
*/
|
|
62
62
|
export declare function loadTokensForUrl(url: string): StoredTokens | null;
|
|
63
|
+
/**
|
|
64
|
+
* Every backend the token map actually holds, with its canonical key.
|
|
65
|
+
*
|
|
66
|
+
* `loadTokensForEnv` can only ever see the three hardcoded `ENV_URLS`
|
|
67
|
+
* presets, so a worktree-offset local (`http://localhost:9480`), a DEV_TLS
|
|
68
|
+
* local, or any custom backend is invisible to it — while `saveTokens` keys
|
|
69
|
+
* on the token's real `apiBaseUrl`. Anything that wants to SHOW what is
|
|
70
|
+
* stored, rather than resolve one named environment, must enumerate the real
|
|
71
|
+
* keys or it will report on a backend the user never logged into. (internal)
|
|
72
|
+
*
|
|
73
|
+
* Malformed entries are dropped, so every returned `tokens` is a usable
|
|
74
|
+
* `StoredTokens` — expired included, since expiry is the caller's to display.
|
|
75
|
+
*/
|
|
76
|
+
export declare function listTokenEntries(): Array<{
|
|
77
|
+
url: string;
|
|
78
|
+
tokens: StoredTokens;
|
|
79
|
+
}>;
|
|
63
80
|
/**
|
|
64
81
|
* Save tokens for the current environment.
|
|
65
82
|
* Upserts the entry keyed by the token's apiBaseUrl.
|
|
@@ -69,11 +86,35 @@ export declare function saveTokens(tokens: StoredTokens): void;
|
|
|
69
86
|
* Save tokens for a specific environment by name.
|
|
70
87
|
*/
|
|
71
88
|
export declare function saveTokensForEnv(env: EnvName, tokens: StoredTokens): void;
|
|
89
|
+
/**
|
|
90
|
+
* Remove the stored token for exactly ONE backend.
|
|
91
|
+
*
|
|
92
|
+
* @returns true when an entry was removed, false when that backend had none.
|
|
93
|
+
*
|
|
94
|
+
* Never touches another backend's entry, and never removes the file except
|
|
95
|
+
* when the entry cleared was the last one — at which point an empty map and a
|
|
96
|
+
* missing file mean the same thing.
|
|
97
|
+
*/
|
|
98
|
+
export declare function clearTokensForUrl(url: string): boolean;
|
|
99
|
+
/**
|
|
100
|
+
* Remove EVERY stored token, for every backend.
|
|
101
|
+
*
|
|
102
|
+
* Only ever reached through an explicit opt-in (`tq:logout --all`). This used
|
|
103
|
+
* to be the silent fallback of `clearTokens()` whenever the current backend
|
|
104
|
+
* could not be resolved — so an absent `~/.tq/config.json` with no
|
|
105
|
+
* `TQ_BACKEND_URL` set destroyed a dozen backends' credentials while the
|
|
106
|
+
* operator believed they were logging out of one. The single `.bak` survives
|
|
107
|
+
* that once, not twice. (internal D2)
|
|
108
|
+
*/
|
|
109
|
+
export declare function clearAllTokens(): void;
|
|
72
110
|
/**
|
|
73
111
|
* Clear stored tokens for the current environment.
|
|
74
|
-
*
|
|
112
|
+
*
|
|
113
|
+
* Refuses when the current backend cannot be resolved rather than falling
|
|
114
|
+
* back to wiping the file — see `clearAllTokens` for what that fallback used
|
|
115
|
+
* to do. Returns false when nothing was removed, for any reason.
|
|
75
116
|
*/
|
|
76
|
-
export declare function clearTokens():
|
|
117
|
+
export declare function clearTokens(): boolean;
|
|
77
118
|
/**
|
|
78
119
|
* Attempt to restore tokens from backup (.bak file)
|
|
79
120
|
* Returns true if backup was restored successfully.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"token-store.d.ts","sourceRoot":"","sources":["../src/token-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAKH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C,MAAM,MAAM,OAAO,GAAG,OAAO,GAAG,SAAS,GAAG,YAAY,CAAC;AAyBzD;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS,CAMlE;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAEtD;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,mBAAmB,CACjC,GAAG,EAAE,MAAM,GAAG,SAAS,GACtB,MAAM,GAAG,SAAS,CAGpB;AAiED;;;;;;;;GAQG;AACH,wBAAgB,UAAU,IAAI,YAAY,GAAG,IAAI,CAmBhD;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,OAAO,GAAG,YAAY,GAAG,IAAI,CAMlE;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI,CAOjE;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,YAAY,GAAG,IAAI,CAarD;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,YAAY,GAAG,IAAI,CAIzE;AAED
|
|
1
|
+
{"version":3,"file":"token-store.d.ts","sourceRoot":"","sources":["../src/token-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAKH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C,MAAM,MAAM,OAAO,GAAG,OAAO,GAAG,SAAS,GAAG,YAAY,CAAC;AAyBzD;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS,CAMlE;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAEtD;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,mBAAmB,CACjC,GAAG,EAAE,MAAM,GAAG,SAAS,GACtB,MAAM,GAAG,SAAS,CAGpB;AAiED;;;;;;;;GAQG;AACH,wBAAgB,UAAU,IAAI,YAAY,GAAG,IAAI,CAmBhD;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,OAAO,GAAG,YAAY,GAAG,IAAI,CAMlE;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI,CAOjE;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,gBAAgB,IAAI,KAAK,CAAC;IACxC,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,YAAY,CAAC;CACtB,CAAC,CAID;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,YAAY,GAAG,IAAI,CAarD;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,YAAY,GAAG,IAAI,CAIzE;AAaD;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAqBtD;AAED;;;;;;;;;GASG;AACH,wBAAgB,cAAc,IAAI,IAAI,CAQrC;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,IAAI,OAAO,CAWrC;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,IAAI,OAAO,CAiCjD;AAED;;GAEG;AACH,wBAAgB,eAAe,IAAI,OAAO,CAIzC;AAED;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,CAEzC;AAED;;GAEG;AACH,wBAAgB,QAAQ,IAAI,MAAM,CAEjC;AAMD;;;GAGG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,GAAG,SAAS,CAiBrD"}
|