@doist/outline-cli 1.8.0 → 1.10.0
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/CHANGELOG.md +12 -0
- package/dist/commands/account.d.ts +2 -0
- package/dist/commands/account.js +107 -0
- package/dist/commands/account.js.map +1 -0
- package/dist/commands/auth.d.ts +0 -12
- package/dist/commands/auth.js +63 -28
- package/dist/commands/auth.js.map +1 -1
- package/dist/index.js +19 -4
- package/dist/index.js.map +1 -1
- package/dist/lib/api.js +20 -9
- package/dist/lib/api.js.map +1 -1
- package/dist/lib/auth-output.d.ts +21 -0
- package/dist/lib/auth-output.js +38 -0
- package/dist/lib/auth-output.js.map +1 -0
- package/dist/lib/auth-provider.d.ts +43 -17
- package/dist/lib/auth-provider.js +104 -36
- package/dist/lib/auth-provider.js.map +1 -1
- package/dist/lib/auth.d.ts +32 -11
- package/dist/lib/auth.js +54 -13
- package/dist/lib/auth.js.map +1 -1
- package/dist/lib/errors.d.ts +1 -1
- package/dist/lib/errors.js.map +1 -1
- package/dist/lib/global-args.d.ts +25 -0
- package/dist/lib/global-args.js +50 -1
- package/dist/lib/global-args.js.map +1 -1
- package/dist/lib/outline-account.d.ts +7 -1
- package/dist/lib/outline-account.js +10 -0
- package/dist/lib/outline-account.js.map +1 -1
- package/dist/lib/skills/content.d.ts +1 -1
- package/dist/lib/skills/content.js +23 -0
- package/dist/lib/skills/content.js.map +1 -1
- package/dist/lib/user-records.d.ts +8 -1
- package/dist/lib/user-records.js +17 -1
- package/dist/lib/user-records.js.map +1 -1
- package/dist/lib/user-ref-store.d.ts +16 -0
- package/dist/lib/user-ref-store.js +37 -0
- package/dist/lib/user-ref-store.js.map +1 -0
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
## [1.10.0](https://github.com/Doist/outline-cli/compare/v1.9.0...v1.10.0) (2026-05-24)
|
|
2
|
+
|
|
3
|
+
### Features
|
|
4
|
+
|
|
5
|
+
* **auth:** add `token` command group (save + view) ([#80](https://github.com/Doist/outline-cli/issues/80)) ([99789cc](https://github.com/Doist/outline-cli/commit/99789cc48b9afa9fc53959427f9121f8d3c12cd9))
|
|
6
|
+
|
|
7
|
+
## [1.9.0](https://github.com/Doist/outline-cli/compare/v1.8.0...v1.9.0) (2026-05-24)
|
|
8
|
+
|
|
9
|
+
### Features
|
|
10
|
+
|
|
11
|
+
* **account:** account command group (cli-core attachers) ([#79](https://github.com/Doist/outline-cli/issues/79)) ([01bd6a6](https://github.com/Doist/outline-cli/commit/01bd6a60af135bbfda894b56d5a6d2b2229b70a8)), closes [#77](https://github.com/Doist/outline-cli/issues/77)
|
|
12
|
+
|
|
1
13
|
## [1.8.0](https://github.com/Doist/outline-cli/compare/v1.7.0...v1.8.0) (2026-05-21)
|
|
2
14
|
|
|
3
15
|
### Features
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { emitView } from '@doist/cli-core';
|
|
2
|
+
import { attachAccountListCommand, attachAccountRemoveCommand, attachAccountUseCommand, } from '@doist/cli-core/auth';
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
import { TOKEN_ENV_VAR } from '../lib/auth-constants.js';
|
|
5
|
+
import { logClearResult } from '../lib/auth-output.js';
|
|
6
|
+
import { createOutlineTokenStore, resolveActiveAccountSource, } from '../lib/auth-provider.js';
|
|
7
|
+
import { CliError } from '../lib/errors.js';
|
|
8
|
+
import { getRequestedUserRef, isAccessible } from '../lib/global-args.js';
|
|
9
|
+
/** `<label> (id:<id>)` with an accessibility-aware default marker. */
|
|
10
|
+
function accountLine(account, isDefault) {
|
|
11
|
+
const marker = isDefault ? (isAccessible() ? ' [default]' : chalk.green(' (default)')) : '';
|
|
12
|
+
return `${account.label} ${chalk.dim(`(id:${account.id})`)}${marker}`;
|
|
13
|
+
}
|
|
14
|
+
/** Tidy machine projection shared by `list` and `current` — drops the OAuth client id. */
|
|
15
|
+
function projectAccount(account, isDefault) {
|
|
16
|
+
return {
|
|
17
|
+
id: account.id,
|
|
18
|
+
label: account.label,
|
|
19
|
+
teamName: account.teamName,
|
|
20
|
+
baseUrl: account.baseUrl,
|
|
21
|
+
isDefault,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
export function registerAccountCommand(program) {
|
|
25
|
+
const account = program.command('account').description('Manage stored CLI accounts');
|
|
26
|
+
const store = createOutlineTokenStore();
|
|
27
|
+
const list = attachAccountListCommand(account, {
|
|
28
|
+
store,
|
|
29
|
+
description: 'List stored Outline accounts',
|
|
30
|
+
renderText: ({ accounts }) => {
|
|
31
|
+
if (accounts.length === 0) {
|
|
32
|
+
return 'No stored accounts. Run `ol auth login` to add one.';
|
|
33
|
+
}
|
|
34
|
+
return accounts.map(({ account, isDefault }) => accountLine(account, isDefault));
|
|
35
|
+
},
|
|
36
|
+
renderJson: ({ account, isDefault }) => projectAccount(account, isDefault),
|
|
37
|
+
});
|
|
38
|
+
attachAccountUseCommand(account, {
|
|
39
|
+
store,
|
|
40
|
+
description: 'Set the default account (matched by Outline user id or display name)',
|
|
41
|
+
});
|
|
42
|
+
// `current` resolves the active credential's source directly (env / stored /
|
|
43
|
+
// legacy) rather than going through the generic account attacher, which only
|
|
44
|
+
// models stored accounts. `--json` / `--ndjson` emit a discriminated envelope.
|
|
45
|
+
account
|
|
46
|
+
.command('current')
|
|
47
|
+
.description('Show the active account (honours --user and OUTLINE_API_TOKEN)')
|
|
48
|
+
.option('--json', 'Emit machine-readable JSON output')
|
|
49
|
+
.option('--ndjson', 'Emit machine-readable NDJSON output')
|
|
50
|
+
.action(async (options) => {
|
|
51
|
+
const view = { json: Boolean(options.json), ndjson: Boolean(options.ndjson) };
|
|
52
|
+
const requested = getRequestedUserRef();
|
|
53
|
+
const resolution = await resolveActiveAccountSource(requested);
|
|
54
|
+
if (resolution?.source === 'stored') {
|
|
55
|
+
const { account: acc, isDefault } = resolution;
|
|
56
|
+
emitView(view, { source: 'stored', account: projectAccount(acc, isDefault) }, () => {
|
|
57
|
+
const lines = [accountLine(acc, isDefault), ` Base URL: ${acc.baseUrl}`];
|
|
58
|
+
if (acc.teamName)
|
|
59
|
+
lines.push(` Team: ${acc.teamName}`);
|
|
60
|
+
return lines;
|
|
61
|
+
});
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
if (resolution?.source === 'env') {
|
|
65
|
+
emitView(view, { source: 'env' }, () => [
|
|
66
|
+
`Using ${TOKEN_ENV_VAR} environment variable (no stored account).`,
|
|
67
|
+
]);
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
if (resolution?.source === 'legacy') {
|
|
71
|
+
emitView(view, { source: 'legacy' }, () => [
|
|
72
|
+
'Using legacy single-user credentials. Run `ol auth login` to migrate to a stored account.',
|
|
73
|
+
]);
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
if (requested !== undefined) {
|
|
77
|
+
throw new CliError('ACCOUNT_NOT_FOUND', `No stored account matches "${requested}".`, ['Check the account id or display name, or run `ol auth login` to add it.']);
|
|
78
|
+
}
|
|
79
|
+
throw new CliError('NOT_AUTHENTICATED', 'Not authenticated. Run: ol auth login');
|
|
80
|
+
});
|
|
81
|
+
attachAccountRemoveCommand(account, {
|
|
82
|
+
store,
|
|
83
|
+
description: 'Remove a stored account (clears keyring + config entry)',
|
|
84
|
+
renderText: ({ account, wasDefault }) => {
|
|
85
|
+
const lines = [`${chalk.green('✓')} Removed ${account.label}`];
|
|
86
|
+
if (wasDefault) {
|
|
87
|
+
lines.push(chalk.dim('Cleared default account. Set a new one with `ol account use <id|name>`.'));
|
|
88
|
+
}
|
|
89
|
+
return lines;
|
|
90
|
+
},
|
|
91
|
+
onRemoved: ({ view }) => logClearResult(store, view.json || view.ndjson),
|
|
92
|
+
});
|
|
93
|
+
// Make bare `ol account` list. A parent action runs only when no subcommand
|
|
94
|
+
// matches, so `ol account list` still routes to the subcommand directly —
|
|
95
|
+
// this just delegates the no-subcommand case via the public API (no reliance
|
|
96
|
+
// on commander internals).
|
|
97
|
+
account.action(async () => {
|
|
98
|
+
await list.parseAsync([], { from: 'user' });
|
|
99
|
+
});
|
|
100
|
+
account.addHelpText('after', `
|
|
101
|
+
Examples:
|
|
102
|
+
ol account # list stored accounts (default subcommand)
|
|
103
|
+
ol account current # show the active account
|
|
104
|
+
ol account use "Ada Lovelace" # set the default account (id or display name)
|
|
105
|
+
ol account remove id-bob # forget an account (clears keyring + config entry)`);
|
|
106
|
+
}
|
|
107
|
+
//# sourceMappingURL=account.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"account.js","sourceRoot":"","sources":["../../src/commands/account.ts"],"names":[],"mappings":"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"}
|
package/dist/commands/auth.d.ts
CHANGED
|
@@ -1,14 +1,2 @@
|
|
|
1
|
-
import { type TokenStorageResult } from '@doist/cli-core/auth';
|
|
2
1
|
import type { Command } from 'commander';
|
|
3
|
-
/**
|
|
4
|
-
* Surface a `TokenStorageResult` from a save/clear: the human-readable
|
|
5
|
-
* confirmation goes to stdout, any keyring-fallback warning goes to stderr.
|
|
6
|
-
* Pass `isMachineOutput: true` to suppress the stdout confirmation in
|
|
7
|
-
* `--json` / `--ndjson` mode while still routing the warning to stderr.
|
|
8
|
-
*
|
|
9
|
-
* Exported for direct unit testing — the alternative (driving this via
|
|
10
|
-
* mocked cli-core login/logout hooks) would require stubbing the entire
|
|
11
|
-
* store contract just to assert two console calls.
|
|
12
|
-
*/
|
|
13
|
-
export declare function logTokenStorageResult(result: TokenStorageResult, secureStoreMessage: string, isMachineOutput?: boolean): void;
|
|
14
2
|
export declare function registerAuthCommand(program: Command): void;
|
package/dist/commands/auth.js
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
|
-
import { attachLoginCommand, attachLogoutCommand, attachStatusCommand, } from '@doist/cli-core/auth';
|
|
1
|
+
import { attachLoginCommand, attachLogoutCommand, attachStatusCommand, attachTokenViewCommand, } from '@doist/cli-core/auth';
|
|
2
2
|
import chalk from 'chalk';
|
|
3
3
|
import { apiRequest } from '../lib/api.js';
|
|
4
|
+
import { TOKEN_ENV_VAR } from '../lib/auth-constants.js';
|
|
5
|
+
import { logClearResult, logSaveResult } from '../lib/auth-output.js';
|
|
4
6
|
import { renderError, renderSuccess } from '../lib/auth-pages.js';
|
|
5
|
-
import { createOutlineAuthProvider, createOutlineTokenStore, getActiveTokenSource, } from '../lib/auth-provider.js';
|
|
7
|
+
import { createOutlineAuthProvider, createOutlineTokenStore, getActiveTokenSource, identifyAccount, prompt, resolveBaseUrl, } from '../lib/auth-provider.js';
|
|
6
8
|
import { refreshedTokenForStatus } from '../lib/auth.js';
|
|
7
9
|
import { CliError } from '../lib/errors.js';
|
|
10
|
+
import { isJsonMode } from '../lib/global-args.js';
|
|
11
|
+
import { withUserRefAware } from '../lib/user-ref-store.js';
|
|
8
12
|
const DEFAULT_OAUTH_CALLBACK_PORT = 54969;
|
|
9
13
|
function resolvePreferredCallbackPort() {
|
|
10
14
|
const raw = process.env.OUTLINE_OAUTH_CALLBACK_PORT?.trim();
|
|
@@ -16,28 +20,50 @@ function resolvePreferredCallbackPort() {
|
|
|
16
20
|
}
|
|
17
21
|
return parsed;
|
|
18
22
|
}
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
if (!isMachineOutput && result.storage === 'secure-store') {
|
|
31
|
-
console.log(chalk.dim(secureStoreMessage));
|
|
23
|
+
async function saveToken(store, token, options) {
|
|
24
|
+
if (!token) {
|
|
25
|
+
if (!process.stdin.isTTY) {
|
|
26
|
+
throw new CliError('NO_TOKEN', 'No token provided', [
|
|
27
|
+
'Pass it as an argument: ol auth token <token>',
|
|
28
|
+
'Run in an interactive terminal to be prompted for it',
|
|
29
|
+
'Set OUTLINE_API_TOKEN to authenticate without storing a token',
|
|
30
|
+
'Or use OAuth: ol auth login',
|
|
31
|
+
]);
|
|
32
|
+
}
|
|
33
|
+
token = await prompt('API token: ', { hidden: true });
|
|
32
34
|
}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
+
const trimmed = token.trim();
|
|
36
|
+
if (!trimmed)
|
|
37
|
+
throw new CliError('NO_TOKEN', 'No token provided');
|
|
38
|
+
const baseUrl = await resolveBaseUrl({ baseUrl: options.baseUrl });
|
|
39
|
+
// A freshly pasted token is verified by probing `auth.info`. Any failure
|
|
40
|
+
// (bad token, wrong instance, unreachable host) collapses to one stable
|
|
41
|
+
// error — never surface the raw API/network string.
|
|
42
|
+
let account;
|
|
43
|
+
try {
|
|
44
|
+
account = await identifyAccount(trimmed, baseUrl);
|
|
35
45
|
}
|
|
46
|
+
catch {
|
|
47
|
+
throw new CliError('AUTH_VERIFICATION_FAILED', 'Could not verify the token with Outline', [
|
|
48
|
+
'Check the token value',
|
|
49
|
+
`Check --base-url matches the instance the token came from (used: ${baseUrl})`,
|
|
50
|
+
]);
|
|
51
|
+
}
|
|
52
|
+
await store.set(account, trimmed);
|
|
53
|
+
const machine = isJsonMode();
|
|
54
|
+
if (!machine) {
|
|
55
|
+
console.log(chalk.green('✓'), `Saved token for ${account.label} (${account.teamName})`);
|
|
56
|
+
}
|
|
57
|
+
logSaveResult(store, machine);
|
|
36
58
|
}
|
|
37
59
|
export function registerAuthCommand(program) {
|
|
38
60
|
const auth = program.command('auth').description('Manage authentication');
|
|
39
61
|
const provider = createOutlineAuthProvider();
|
|
40
62
|
const store = createOutlineTokenStore();
|
|
63
|
+
// Honours a global `ol --user <ref>` placed before `auth status` / `auth
|
|
64
|
+
// logout`; login always targets the freshly authenticated account, so it
|
|
65
|
+
// keeps the raw store.
|
|
66
|
+
const refAware = withUserRefAware(store);
|
|
41
67
|
attachLoginCommand(auth, {
|
|
42
68
|
provider,
|
|
43
69
|
store,
|
|
@@ -50,10 +76,7 @@ export function registerAuthCommand(program) {
|
|
|
50
76
|
if (!isMachineOutput) {
|
|
51
77
|
console.log(chalk.green(`Authenticated to ${account.teamName} as ${account.label}`));
|
|
52
78
|
}
|
|
53
|
-
|
|
54
|
-
if (result) {
|
|
55
|
-
logTokenStorageResult(result, 'Token stored securely in the system credential manager', isMachineOutput);
|
|
56
|
-
}
|
|
79
|
+
logSaveResult(store, isMachineOutput);
|
|
57
80
|
},
|
|
58
81
|
})
|
|
59
82
|
.description('Authenticate with an Outline instance via OAuth')
|
|
@@ -64,7 +87,7 @@ export function registerAuthCommand(program) {
|
|
|
64
87
|
// populated by the time the render hooks read it.
|
|
65
88
|
let statusData = null;
|
|
66
89
|
attachStatusCommand(auth, {
|
|
67
|
-
store,
|
|
90
|
+
store: refAware,
|
|
68
91
|
description: 'Show current authentication state',
|
|
69
92
|
async fetchLive({ account, token }) {
|
|
70
93
|
try {
|
|
@@ -77,7 +100,11 @@ export function registerAuthCommand(program) {
|
|
|
77
100
|
const liveToken = await refreshedTokenForStatus(account, token);
|
|
78
101
|
const [{ data: info }, source] = await Promise.all([
|
|
79
102
|
apiRequest('auth.info', {}, { token: liveToken, baseUrl: account.baseUrl }),
|
|
80
|
-
|
|
103
|
+
// Scope the source to the selected account so `auth status
|
|
104
|
+
// --user <ref>` reports where *that* account's token lives,
|
|
105
|
+
// not the default/env source. Empty id (env/legacy snapshot)
|
|
106
|
+
// falls back to the default cascade.
|
|
107
|
+
getActiveTokenSource(account.id || undefined),
|
|
81
108
|
]);
|
|
82
109
|
statusData = { email: info.user.email, source };
|
|
83
110
|
return {
|
|
@@ -123,14 +150,22 @@ export function registerAuthCommand(program) {
|
|
|
123
150
|
},
|
|
124
151
|
});
|
|
125
152
|
attachLogoutCommand(auth, {
|
|
126
|
-
store,
|
|
153
|
+
store: refAware,
|
|
127
154
|
description: 'Clear saved authentication',
|
|
128
155
|
onCleared({ view }) {
|
|
129
|
-
|
|
130
|
-
if (!result)
|
|
131
|
-
return;
|
|
132
|
-
logTokenStorageResult(result, 'Stored token removed from the system credential manager', view.json || view.ndjson);
|
|
156
|
+
logClearResult(store, view.json || view.ndjson);
|
|
133
157
|
},
|
|
134
158
|
});
|
|
159
|
+
const tokenCmd = auth
|
|
160
|
+
.command('token [token]')
|
|
161
|
+
.description('Save an Outline API token for CLI auth (or use the `view` subcommand)')
|
|
162
|
+
.option('--base-url <url>', 'Outline base URL the token belongs to')
|
|
163
|
+
.action((token, options) => saveToken(store, token, options));
|
|
164
|
+
attachTokenViewCommand(tokenCmd, {
|
|
165
|
+
name: 'view',
|
|
166
|
+
store: refAware,
|
|
167
|
+
envVarName: TOKEN_ENV_VAR,
|
|
168
|
+
description: 'Print the stored token for the active user (or --user <ref>) to stdout for scripts',
|
|
169
|
+
});
|
|
135
170
|
}
|
|
136
171
|
//# sourceMappingURL=auth.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/commands/auth.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,kBAAkB,EAClB,mBAAmB,EACnB,mBAAmB,
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/commands/auth.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { Command } from 'commander';
|
|
3
3
|
import packageJson from '../package.json' with { type: 'json' };
|
|
4
|
+
import { registerAccountCommand } from './commands/account.js';
|
|
4
5
|
import { registerAuthCommand } from './commands/auth.js';
|
|
5
6
|
import { registerChangelogCommand } from './commands/changelog.js';
|
|
6
7
|
import { registerCollectionCommand } from './commands/collection.js';
|
|
@@ -9,7 +10,7 @@ import { registerSearchCommand } from './commands/search.js';
|
|
|
9
10
|
import { registerSkillCommand } from './commands/skill.js';
|
|
10
11
|
import { registerUpdateCommand } from './commands/update/index.js';
|
|
11
12
|
import { BaseCliError } from './lib/errors.js';
|
|
12
|
-
import { isJsonMode } from './lib/global-args.js';
|
|
13
|
+
import { applyUserSelector, isJsonMode } from './lib/global-args.js';
|
|
13
14
|
import { formatError, formatErrorJson } from './lib/output.js';
|
|
14
15
|
const program = new Command();
|
|
15
16
|
program
|
|
@@ -19,23 +20,37 @@ program
|
|
|
19
20
|
.option('--no-spinner', 'Disable loading animations')
|
|
20
21
|
.option('--accessible', 'Render output in screen-reader-friendly mode')
|
|
21
22
|
.addHelpText('after', `
|
|
23
|
+
Global options:
|
|
24
|
+
--user <id|name> Act as a specific stored account (place before the command,
|
|
25
|
+
e.g. \`ol --user scott@example.com document list\`).
|
|
26
|
+
|
|
22
27
|
Note for AI/LLM agents:
|
|
23
28
|
Use --json or --ndjson flags for unambiguous, parseable output.
|
|
24
29
|
Default JSON shows essential fields; use --full for all fields.`);
|
|
25
30
|
registerAuthCommand(program);
|
|
31
|
+
registerAccountCommand(program);
|
|
26
32
|
registerSearchCommand(program);
|
|
27
33
|
registerDocumentCommand(program);
|
|
28
34
|
registerCollectionCommand(program);
|
|
29
35
|
registerSkillCommand(program);
|
|
30
36
|
registerChangelogCommand(program);
|
|
31
37
|
registerUpdateCommand(program);
|
|
32
|
-
|
|
38
|
+
function reportError(err) {
|
|
33
39
|
if (err instanceof BaseCliError) {
|
|
34
40
|
console.error(isJsonMode() ? formatErrorJson(err) : formatError(err));
|
|
35
41
|
}
|
|
36
42
|
else {
|
|
37
|
-
console.error(err.message);
|
|
43
|
+
console.error(err instanceof Error ? err.message : String(err));
|
|
38
44
|
}
|
|
39
45
|
process.exit(1);
|
|
40
|
-
}
|
|
46
|
+
}
|
|
47
|
+
// Commander has no root `--user` option, so validate it and strip it from argv
|
|
48
|
+
// before parsing (see `applyUserSelector` for the warm-cache-then-strip order).
|
|
49
|
+
try {
|
|
50
|
+
applyUserSelector(new Set(program.commands.map((c) => c.name())));
|
|
51
|
+
}
|
|
52
|
+
catch (err) {
|
|
53
|
+
reportError(err);
|
|
54
|
+
}
|
|
55
|
+
program.parseAsync().catch(reportError);
|
|
41
56
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACnC,OAAO,WAAW,MAAM,iBAAiB,CAAC,OAAO,IAAI,EAAE,MAAM,EAAE,CAAA;AAC/D,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAA;AACxD,OAAO,EAAE,wBAAwB,EAAE,MAAM,yBAAyB,CAAA;AAClE,OAAO,EAAE,yBAAyB,EAAE,MAAM,0BAA0B,CAAA;AACpE,OAAO,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAA;AAChE,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAA;AAC5D,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAA;AAC1D,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAA;AAClE,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AAC9C,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAA;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACnC,OAAO,WAAW,MAAM,iBAAiB,CAAC,OAAO,IAAI,EAAE,MAAM,EAAE,CAAA;AAC/D,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAA;AAC9D,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAA;AACxD,OAAO,EAAE,wBAAwB,EAAE,MAAM,yBAAyB,CAAA;AAClE,OAAO,EAAE,yBAAyB,EAAE,MAAM,0BAA0B,CAAA;AACpE,OAAO,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAA;AAChE,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAA;AAC5D,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAA;AAC1D,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAA;AAClE,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AAC9C,OAAO,EAAE,iBAAiB,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAA;AACpE,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAE9D,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAA;AAE7B,OAAO;KACF,IAAI,CAAC,IAAI,CAAC;KACV,OAAO,CAAC,WAAW,CAAC,OAAO,CAAC;KAC5B,WAAW,CAAC,6CAA6C,CAAC;KAC1D,MAAM,CAAC,cAAc,EAAE,4BAA4B,CAAC;KACpD,MAAM,CAAC,cAAc,EAAE,8CAA8C,CAAC;KACtE,WAAW,CACR,OAAO,EACP;;;;;;;kEAO0D,CAC7D,CAAA;AAEL,mBAAmB,CAAC,OAAO,CAAC,CAAA;AAC5B,sBAAsB,CAAC,OAAO,CAAC,CAAA;AAC/B,qBAAqB,CAAC,OAAO,CAAC,CAAA;AAC9B,uBAAuB,CAAC,OAAO,CAAC,CAAA;AAChC,yBAAyB,CAAC,OAAO,CAAC,CAAA;AAClC,oBAAoB,CAAC,OAAO,CAAC,CAAA;AAC7B,wBAAwB,CAAC,OAAO,CAAC,CAAA;AACjC,qBAAqB,CAAC,OAAO,CAAC,CAAA;AAE9B,SAAS,WAAW,CAAC,GAAY;IAC7B,IAAI,GAAG,YAAY,YAAY,EAAE,CAAC;QAC9B,OAAO,CAAC,KAAK,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAA;IACzE,CAAC;SAAM,CAAC;QACJ,OAAO,CAAC,KAAK,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAA;IACnE,CAAC;IACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;AACnB,CAAC;AAED,+EAA+E;AAC/E,gFAAgF;AAChF,IAAI,CAAC;IACD,iBAAiB,CAAC,IAAI,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAA;AACrE,CAAC;AAAC,OAAO,GAAG,EAAE,CAAC;IACX,WAAW,CAAC,GAAG,CAAC,CAAA;AACpB,CAAC;AAED,OAAO,CAAC,UAAU,EAAE,CAAC,KAAK,CAAC,WAAW,CAAC,CAAA"}
|
package/dist/lib/api.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { fetchWithRetry } from '../transport/fetch-with-retry.js';
|
|
2
2
|
import { TOKEN_ENV_VAR } from './auth-constants.js';
|
|
3
|
-
import { getApiToken,
|
|
3
|
+
import { getApiToken, getRequestContext, proactiveRefresh, reactiveRefresh } from './auth.js';
|
|
4
4
|
import { withSpinner } from './spinner.js';
|
|
5
5
|
/**
|
|
6
6
|
* Spinner configuration mapping API paths to spinner options.
|
|
@@ -28,12 +28,13 @@ const API_SPINNER_CONFIG = {
|
|
|
28
28
|
* On the managed path, prefer the token `proactiveRefresh` resolved (rotated
|
|
29
29
|
* or current) so unrefreshable/access-only accounts stay on a single store
|
|
30
30
|
* read; only fall back to `getApiToken` when proactive refresh bows out.
|
|
31
|
+
* `handshake` pins the refresh to the `--user` account's instance.
|
|
31
32
|
*/
|
|
32
|
-
async function resolveRequestToken(managed, override) {
|
|
33
|
+
async function resolveRequestToken(managed, override, handshake) {
|
|
33
34
|
if (override)
|
|
34
35
|
return override;
|
|
35
36
|
if (managed) {
|
|
36
|
-
const refreshed = await proactiveRefresh();
|
|
37
|
+
const refreshed = await proactiveRefresh(handshake);
|
|
37
38
|
if (refreshed)
|
|
38
39
|
return refreshed;
|
|
39
40
|
}
|
|
@@ -46,11 +47,21 @@ async function rawApiRequest(path, body = {}, overrides = {}) {
|
|
|
46
47
|
// Only stored credentials can be refreshed: a caller-supplied token
|
|
47
48
|
// override or the `OUTLINE_API_TOKEN` env var is taken as-is.
|
|
48
49
|
const managed = !overrides.token && !process.env[TOKEN_ENV_VAR]?.trim();
|
|
49
|
-
//
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
50
|
+
// A caller-supplied base URL (login validate, auth status) skips account
|
|
51
|
+
// resolution — those paths pass an explicit token, so no refresh runs.
|
|
52
|
+
// Otherwise resolve the request's base URL and, for a `--user` account, the
|
|
53
|
+
// refresh handshake that keeps rotation pinned to that account's instance.
|
|
54
|
+
let resolvedBaseUrl;
|
|
55
|
+
let handshake;
|
|
56
|
+
if (overrides.baseUrl) {
|
|
57
|
+
resolvedBaseUrl = overrides.baseUrl.replace(/\/$/, '');
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
const ctx = await getRequestContext();
|
|
61
|
+
resolvedBaseUrl = ctx.baseUrl;
|
|
62
|
+
handshake = ctx.handshake;
|
|
63
|
+
}
|
|
64
|
+
const resolvedToken = await resolveRequestToken(managed, overrides.token, handshake);
|
|
54
65
|
const performRequest = (token) => fetchWithRetry({
|
|
55
66
|
url: `${resolvedBaseUrl}/api/${path}`,
|
|
56
67
|
options: {
|
|
@@ -66,7 +77,7 @@ async function rawApiRequest(path, body = {}, overrides = {}) {
|
|
|
66
77
|
// Reactive path: a 401 on a managed token triggers a forced rotation and
|
|
67
78
|
// a single retry. `reactiveRefresh` throws `NoTokenError` when the refresh
|
|
68
79
|
// token is gone, so an unrecoverable 401 surfaces the re-login hint.
|
|
69
|
-
if (res.status === 401 && managed && (await reactiveRefresh())) {
|
|
80
|
+
if (res.status === 401 && managed && (await reactiveRefresh(handshake))) {
|
|
70
81
|
res = await performRequest(await getApiToken());
|
|
71
82
|
}
|
|
72
83
|
if (!res.ok) {
|
package/dist/lib/api.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.js","sourceRoot":"","sources":["../../src/lib/api.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,kCAAkC,CAAA;AACjE,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AACnD,OAAO,EAAE,WAAW,EAAE,
|
|
1
|
+
{"version":3,"file":"api.js","sourceRoot":"","sources":["../../src/lib/api.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,kCAAkC,CAAA;AACjE,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AACnD,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,WAAW,CAAA;AAC7F,OAAO,EAAuB,WAAW,EAAE,MAAM,cAAc,CAAA;AAI/D;;;GAGG;AACH,MAAM,kBAAkB,GAAmC;IACvD,WAAW,EAAE,EAAE,IAAI,EAAE,4BAA4B,EAAE,KAAK,EAAE,MAAM,EAAE;IAClE,kBAAkB,EAAE,EAAE,IAAI,EAAE,wBAAwB,EAAE,KAAK,EAAE,MAAM,EAAE;IACrE,gBAAgB,EAAE,EAAE,IAAI,EAAE,sBAAsB,EAAE,KAAK,EAAE,MAAM,EAAE;IACjE,gBAAgB,EAAE,EAAE,IAAI,EAAE,qBAAqB,EAAE,KAAK,EAAE,MAAM,EAAE;IAChE,kBAAkB,EAAE,EAAE,IAAI,EAAE,sBAAsB,EAAE,KAAK,EAAE,OAAO,EAAE;IACpE,kBAAkB,EAAE,EAAE,IAAI,EAAE,sBAAsB,EAAE,KAAK,EAAE,QAAQ,EAAE;IACrE,kBAAkB,EAAE,EAAE,IAAI,EAAE,sBAAsB,EAAE,KAAK,EAAE,QAAQ,EAAE;IACrE,gBAAgB,EAAE,EAAE,IAAI,EAAE,oBAAoB,EAAE,KAAK,EAAE,QAAQ,EAAE;IACjE,mBAAmB,EAAE,EAAE,IAAI,EAAE,uBAAuB,EAAE,KAAK,EAAE,QAAQ,EAAE;IACvE,qBAAqB,EAAE,EAAE,IAAI,EAAE,yBAAyB,EAAE,KAAK,EAAE,QAAQ,EAAE;IAC3E,kBAAkB,EAAE,EAAE,IAAI,EAAE,wBAAwB,EAAE,KAAK,EAAE,MAAM,EAAE;IACrE,kBAAkB,EAAE,EAAE,IAAI,EAAE,uBAAuB,EAAE,KAAK,EAAE,MAAM,EAAE;IACpE,oBAAoB,EAAE,EAAE,IAAI,EAAE,wBAAwB,EAAE,KAAK,EAAE,OAAO,EAAE;IACxE,oBAAoB,EAAE,EAAE,IAAI,EAAE,wBAAwB,EAAE,KAAK,EAAE,QAAQ,EAAE;IACzE,oBAAoB,EAAE,EAAE,IAAI,EAAE,wBAAwB,EAAE,KAAK,EAAE,QAAQ,EAAE;CAC5E,CAAA;AA8BD;;;;;;GAMG;AACH,KAAK,UAAU,mBAAmB,CAC9B,OAAgB,EAChB,QAAiB,EACjB,SAA4B;IAE5B,IAAI,QAAQ;QAAE,OAAO,QAAQ,CAAA;IAC7B,IAAI,OAAO,EAAE,CAAC;QACV,MAAM,SAAS,GAAG,MAAM,gBAAgB,CAAC,SAAS,CAAC,CAAA;QACnD,IAAI,SAAS;YAAE,OAAO,SAAS,CAAA;IACnC,CAAC;IACD,OAAO,WAAW,EAAE,CAAA;AACxB,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,aAAa,CACxB,IAAY,EACZ,OAAe,EAAE,EACjB,YAAiC,EAAE;IAEnC,oEAAoE;IACpE,8DAA8D;IAC9D,MAAM,OAAO,GAAG,CAAC,SAAS,CAAC,KAAK,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,EAAE,IAAI,EAAE,CAAA;IAEvE,yEAAyE;IACzE,uEAAuE;IACvE,4EAA4E;IAC5E,2EAA2E;IAC3E,IAAI,eAAuB,CAAA;IAC3B,IAAI,SAAuC,CAAA;IAC3C,IAAI,SAAS,CAAC,OAAO,EAAE,CAAC;QACpB,eAAe,GAAG,SAAS,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAA;IAC1D,CAAC;SAAM,CAAC;QACJ,MAAM,GAAG,GAAG,MAAM,iBAAiB,EAAE,CAAA;QACrC,eAAe,GAAG,GAAG,CAAC,OAAO,CAAA;QAC7B,SAAS,GAAG,GAAG,CAAC,SAAS,CAAA;IAC7B,CAAC;IAED,MAAM,aAAa,GAAG,MAAM,mBAAmB,CAAC,OAAO,EAAE,SAAS,CAAC,KAAK,EAAE,SAAS,CAAC,CAAA;IAEpF,MAAM,cAAc,GAAG,CAAC,KAAa,EAAE,EAAE,CACrC,cAAc,CAAC;QACX,GAAG,EAAE,GAAG,eAAe,QAAQ,IAAI,EAAE;QACrC,OAAO,EAAE;YACL,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACL,cAAc,EAAE,kBAAkB;gBAClC,aAAa,EAAE,UAAU,KAAK,EAAE;aACnC;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;SAC7B;KACJ,CAAC,CAAA;IAEN,IAAI,GAAG,GAAG,MAAM,cAAc,CAAC,aAAa,CAAC,CAAA;IAE7C,yEAAyE;IACzE,2EAA2E;IAC3E,qEAAqE;IACrE,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,IAAI,OAAO,IAAI,CAAC,MAAM,eAAe,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC;QACtE,GAAG,GAAG,MAAM,cAAc,CAAC,MAAM,WAAW,EAAE,CAAC,CAAA;IACnD,CAAC;IAED,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACV,IAAI,OAAO,GAAG,cAAc,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,UAAU,EAAE,CAAA;QAC1D,IAAI,CAAC;YACD,MAAM,GAAG,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAa,CAAA;YAC1C,IAAI,GAAG,CAAC,OAAO;gBAAE,OAAO,GAAG,cAAc,GAAG,CAAC,OAAO,EAAE,CAAA;QAC1D,CAAC;QAAC,MAAM,CAAC,CAAA,CAAC;QACV,MAAM,IAAI,KAAK,CAAC,OAAO,CAAC,CAAA;IAC5B,CAAC;IAED,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAmB,CAAA;IACjD,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,UAAU,EAAE,IAAI,CAAC,UAAU,EAAE,CAAA;AAC3D,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAC5B,IAAY,EACZ,OAAe,EAAE,EACjB,YAAiC,EAAE;IAEnC,MAAM,aAAa,GAAG,kBAAkB,CAAC,IAAI,CAAC,IAAI;QAC9C,IAAI,EAAE,YAAY;QAClB,KAAK,EAAE,MAAe;KACzB,CAAA;IAED,OAAO,WAAW,CAAC,aAAa,EAAE,GAAG,EAAE,CAAC,aAAa,CAAI,IAAI,EAAE,IAAI,EAAE,SAAS,CAAC,CAAC,CAAA;AACpF,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { TokenStorageResult } from '@doist/cli-core/auth';
|
|
2
|
+
import type { OutlineTokenStore } from './auth-provider.js';
|
|
3
|
+
/**
|
|
4
|
+
* Surface a `TokenStorageResult` from a save/clear: the human-readable
|
|
5
|
+
* confirmation goes to stdout, any keyring-fallback warning goes to stderr.
|
|
6
|
+
* Pass `isMachineOutput: true` to suppress the stdout confirmation in
|
|
7
|
+
* `--json` / `--ndjson` mode while still routing the warning to stderr.
|
|
8
|
+
*/
|
|
9
|
+
export declare function logTokenStorageResult(result: TokenStorageResult, secureStoreMessage: string, isMachineOutput?: boolean): void;
|
|
10
|
+
/**
|
|
11
|
+
* Surface the result of a token save (`auth login` / `auth token`): the
|
|
12
|
+
* confirmation goes to stdout, any keyring-fallback warning to stderr. Shared so
|
|
13
|
+
* both save flows keep identical machine-output and warning behavior.
|
|
14
|
+
*/
|
|
15
|
+
export declare function logSaveResult(store: OutlineTokenStore, isMachineOutput: boolean): void;
|
|
16
|
+
/**
|
|
17
|
+
* Surface the result of a token clear (`auth logout` / `account remove`): the
|
|
18
|
+
* confirmation goes to stdout, any keyring-fallback warning to stderr. Shared so
|
|
19
|
+
* both call sites stay in lockstep.
|
|
20
|
+
*/
|
|
21
|
+
export declare function logClearResult(store: OutlineTokenStore, isMachineOutput: boolean): void;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
/**
|
|
3
|
+
* Surface a `TokenStorageResult` from a save/clear: the human-readable
|
|
4
|
+
* confirmation goes to stdout, any keyring-fallback warning goes to stderr.
|
|
5
|
+
* Pass `isMachineOutput: true` to suppress the stdout confirmation in
|
|
6
|
+
* `--json` / `--ndjson` mode while still routing the warning to stderr.
|
|
7
|
+
*/
|
|
8
|
+
export function logTokenStorageResult(result, secureStoreMessage, isMachineOutput = false) {
|
|
9
|
+
if (!isMachineOutput && result.storage === 'secure-store') {
|
|
10
|
+
console.log(chalk.dim(secureStoreMessage));
|
|
11
|
+
}
|
|
12
|
+
if (result.warning) {
|
|
13
|
+
console.error(chalk.yellow('Warning:'), result.warning);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Surface the result of a token save (`auth login` / `auth token`): the
|
|
18
|
+
* confirmation goes to stdout, any keyring-fallback warning to stderr. Shared so
|
|
19
|
+
* both save flows keep identical machine-output and warning behavior.
|
|
20
|
+
*/
|
|
21
|
+
export function logSaveResult(store, isMachineOutput) {
|
|
22
|
+
const result = store.getLastStorageResult();
|
|
23
|
+
if (!result)
|
|
24
|
+
return;
|
|
25
|
+
logTokenStorageResult(result, 'Token stored securely in the system credential manager', isMachineOutput);
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Surface the result of a token clear (`auth logout` / `account remove`): the
|
|
29
|
+
* confirmation goes to stdout, any keyring-fallback warning to stderr. Shared so
|
|
30
|
+
* both call sites stay in lockstep.
|
|
31
|
+
*/
|
|
32
|
+
export function logClearResult(store, isMachineOutput) {
|
|
33
|
+
const result = store.getLastClearResult();
|
|
34
|
+
if (!result)
|
|
35
|
+
return;
|
|
36
|
+
logTokenStorageResult(result, 'Stored token removed from the system credential manager', isMachineOutput);
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=auth-output.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth-output.js","sourceRoot":"","sources":["../../src/lib/auth-output.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,MAAM,OAAO,CAAA;AAGzB;;;;;GAKG;AACH,MAAM,UAAU,qBAAqB,CACjC,MAA0B,EAC1B,kBAA0B,EAC1B,eAAe,GAAG,KAAK;IAEvB,IAAI,CAAC,eAAe,IAAI,MAAM,CAAC,OAAO,KAAK,cAAc,EAAE,CAAC;QACxD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC,CAAA;IAC9C,CAAC;IACD,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;QACjB,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC,OAAO,CAAC,CAAA;IAC3D,CAAC;AACL,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAAC,KAAwB,EAAE,eAAwB;IAC5E,MAAM,MAAM,GAAG,KAAK,CAAC,oBAAoB,EAAE,CAAA;IAC3C,IAAI,CAAC,MAAM;QAAE,OAAM;IACnB,qBAAqB,CACjB,MAAM,EACN,wDAAwD,EACxD,eAAe,CAClB,CAAA;AACL,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAAC,KAAwB,EAAE,eAAwB;IAC7E,MAAM,MAAM,GAAG,KAAK,CAAC,kBAAkB,EAAE,CAAA;IACzC,IAAI,CAAC,MAAM;QAAE,OAAM;IACnB,qBAAqB,CACjB,MAAM,EACN,yDAAyD,EACzD,eAAe,CAClB,CAAA;AACL,CAAC"}
|