@doist/outline-cli 1.7.0 → 1.9.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 +25 -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 +46 -7
- package/dist/lib/api.js.map +1 -1
- package/dist/lib/auth-output.d.ts +15 -0
- package/dist/lib/auth-output.js +27 -0
- package/dist/lib/auth-output.js.map +1 -0
- package/dist/lib/auth-provider.d.ts +26 -18
- package/dist/lib/auth-provider.js +131 -107
- package/dist/lib/auth-provider.js.map +1 -1
- package/dist/lib/auth.d.ts +50 -6
- package/dist/lib/auth.js +134 -11
- package/dist/lib/auth.js.map +1 -1
- package/dist/lib/config.d.ts +7 -0
- package/dist/lib/config.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 +18 -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 +46 -9
- 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 +3 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
## [1.9.0](https://github.com/Doist/outline-cli/compare/v1.8.0...v1.9.0) (2026-05-24)
|
|
2
|
+
|
|
3
|
+
### Features
|
|
4
|
+
|
|
5
|
+
* **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)
|
|
6
|
+
|
|
7
|
+
## [1.8.0](https://github.com/Doist/outline-cli/compare/v1.7.0...v1.8.0) (2026-05-21)
|
|
8
|
+
|
|
9
|
+
### Features
|
|
10
|
+
|
|
11
|
+
* **auth:** silent OAuth token refresh ([#75](https://github.com/Doist/outline-cli/issues/75)) ([83996d5](https://github.com/Doist/outline-cli/commit/83996d56810e28e608d91a981fd3b313dcdeb4d3))
|
|
12
|
+
|
|
1
13
|
## [1.7.0](https://github.com/Doist/outline-cli/compare/v1.6.0...v1.7.0) (2026-05-17)
|
|
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":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAA;AAC1C,OAAO,EACH,wBAAwB,EACxB,0BAA0B,EAC1B,uBAAuB,GAC1B,MAAM,sBAAsB,CAAA;AAC7B,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAA;AACxD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AACtD,OAAO,EACH,uBAAuB,EAEvB,0BAA0B,GAC7B,MAAM,yBAAyB,CAAA;AAChC,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAA;AAC3C,OAAO,EAAE,mBAAmB,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAA;AAEzE,sEAAsE;AACtE,SAAS,WAAW,CAAC,OAAuB,EAAE,SAAkB;IAC5D,MAAM,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAA;IAC3F,OAAO,GAAG,OAAO,CAAC,KAAK,IAAI,KAAK,CAAC,GAAG,CAAC,OAAO,OAAO,CAAC,EAAE,GAAG,CAAC,GAAG,MAAM,EAAE,CAAA;AACzE,CAAC;AAED,0FAA0F;AAC1F,SAAS,cAAc,CAAC,OAAuB,EAAE,SAAkB;IAC/D,OAAO;QACH,EAAE,EAAE,OAAO,CAAC,EAAE;QACd,KAAK,EAAE,OAAO,CAAC,KAAK;QACpB,QAAQ,EAAE,OAAO,CAAC,QAAQ;QAC1B,OAAO,EAAE,OAAO,CAAC,OAAO;QACxB,SAAS;KACZ,CAAA;AACL,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,OAAgB;IACnD,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,WAAW,CAAC,4BAA4B,CAAC,CAAA;IACpF,MAAM,KAAK,GAAG,uBAAuB,EAAE,CAAA;IAEvC,MAAM,IAAI,GAAG,wBAAwB,CAAiB,OAAO,EAAE;QAC3D,KAAK;QACL,WAAW,EAAE,8BAA8B;QAC3C,UAAU,EAAE,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE;YACzB,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACxB,OAAO,qDAAqD,CAAA;YAChE,CAAC;YACD,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC,WAAW,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC,CAAA;QACpF,CAAC;QACD,UAAU,EAAE,CAAC,EAAE,OAAO,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC,cAAc,CAAC,OAAO,EAAE,SAAS,CAAC;KAC7E,CAAC,CAAA;IAEF,uBAAuB,CAAiB,OAAO,EAAE;QAC7C,KAAK;QACL,WAAW,EAAE,sEAAsE;KACtF,CAAC,CAAA;IAEF,6EAA6E;IAC7E,6EAA6E;IAC7E,+EAA+E;IAC/E,OAAO;SACF,OAAO,CAAC,SAAS,CAAC;SAClB,WAAW,CAAC,gEAAgE,CAAC;SAC7E,MAAM,CAAC,QAAQ,EAAE,mCAAmC,CAAC;SACrD,MAAM,CAAC,UAAU,EAAE,qCAAqC,CAAC;SACzD,MAAM,CAAC,KAAK,EAAE,OAA6C,EAAE,EAAE;QAC5D,MAAM,IAAI,GAAG,EAAE,IAAI,EAAE,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAA;QAC7E,MAAM,SAAS,GAAG,mBAAmB,EAAE,CAAA;QACvC,MAAM,UAAU,GAAG,MAAM,0BAA0B,CAAC,SAAS,CAAC,CAAA;QAC9D,IAAI,UAAU,EAAE,MAAM,KAAK,QAAQ,EAAE,CAAC;YAClC,MAAM,EAAE,OAAO,EAAE,GAAG,EAAE,SAAS,EAAE,GAAG,UAAU,CAAA;YAC9C,QAAQ,CACJ,IAAI,EACJ,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,cAAc,CAAC,GAAG,EAAE,SAAS,CAAC,EAAE,EAC7D,GAAG,EAAE;gBACD,MAAM,KAAK,GAAG,CAAC,WAAW,CAAC,GAAG,EAAE,SAAS,CAAC,EAAE,eAAe,GAAG,CAAC,OAAO,EAAE,CAAC,CAAA;gBACzE,IAAI,GAAG,CAAC,QAAQ;oBAAE,KAAK,CAAC,IAAI,CAAC,WAAW,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAA;gBACvD,OAAO,KAAK,CAAA;YAChB,CAAC,CACJ,CAAA;YACD,OAAM;QACV,CAAC;QACD,IAAI,UAAU,EAAE,MAAM,KAAK,KAAK,EAAE,CAAC;YAC/B,QAAQ,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,GAAG,EAAE,CAAC;gBACpC,SAAS,aAAa,4CAA4C;aACrE,CAAC,CAAA;YACF,OAAM;QACV,CAAC;QACD,IAAI,UAAU,EAAE,MAAM,KAAK,QAAQ,EAAE,CAAC;YAClC,QAAQ,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,GAAG,EAAE,CAAC;gBACvC,2FAA2F;aAC9F,CAAC,CAAA;YACF,OAAM;QACV,CAAC;QACD,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;YAC1B,MAAM,IAAI,QAAQ,CACd,mBAAmB,EACnB,8BAA8B,SAAS,IAAI,EAC3C,CAAC,yEAAyE,CAAC,CAC9E,CAAA;QACL,CAAC;QACD,MAAM,IAAI,QAAQ,CAAC,mBAAmB,EAAE,uCAAuC,CAAC,CAAA;IACpF,CAAC,CAAC,CAAA;IAEN,0BAA0B,CAAiB,OAAO,EAAE;QAChD,KAAK;QACL,WAAW,EAAE,yDAAyD;QACtE,UAAU,EAAE,CAAC,EAAE,OAAO,EAAE,UAAU,EAAE,EAAE,EAAE;YACpC,MAAM,KAAK,GAAG,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,YAAY,OAAO,CAAC,KAAK,EAAE,CAAC,CAAA;YAC9D,IAAI,UAAU,EAAE,CAAC;gBACb,KAAK,CAAC,IAAI,CACN,KAAK,CAAC,GAAG,CACL,yEAAyE,CAC5E,CACJ,CAAA;YACL,CAAC;YACD,OAAO,KAAK,CAAA;QAChB,CAAC;QACD,SAAS,EAAE,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,cAAc,CAAC,KAAK,EAAE,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,MAAM,CAAC;KAC3E,CAAC,CAAA;IAEF,4EAA4E;IAC5E,0EAA0E;IAC1E,6EAA6E;IAC7E,2BAA2B;IAC3B,OAAO,CAAC,MAAM,CAAC,KAAK,IAAI,EAAE;QACtB,MAAM,IAAI,CAAC,UAAU,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAA;IAC/C,CAAC,CAAC,CAAA;IAEF,OAAO,CAAC,WAAW,CACf,OAAO,EACP;;;;;qFAK6E,CAChF,CAAA;AACL,CAAC"}
|
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,9 +1,12 @@
|
|
|
1
|
-
import { attachLoginCommand, attachLogoutCommand, attachStatusCommand
|
|
1
|
+
import { attachLoginCommand, attachLogoutCommand, attachStatusCommand } from '@doist/cli-core/auth';
|
|
2
2
|
import chalk from 'chalk';
|
|
3
3
|
import { apiRequest } from '../lib/api.js';
|
|
4
|
+
import { logClearResult, logTokenStorageResult } from '../lib/auth-output.js';
|
|
4
5
|
import { renderError, renderSuccess } from '../lib/auth-pages.js';
|
|
5
6
|
import { createOutlineAuthProvider, createOutlineTokenStore, getActiveTokenSource, } from '../lib/auth-provider.js';
|
|
7
|
+
import { refreshedTokenForStatus } from '../lib/auth.js';
|
|
6
8
|
import { CliError } from '../lib/errors.js';
|
|
9
|
+
import { withUserRefAware } from '../lib/user-ref-store.js';
|
|
7
10
|
const DEFAULT_OAUTH_CALLBACK_PORT = 54969;
|
|
8
11
|
function resolvePreferredCallbackPort() {
|
|
9
12
|
const raw = process.env.OUTLINE_OAUTH_CALLBACK_PORT?.trim();
|
|
@@ -15,28 +18,14 @@ function resolvePreferredCallbackPort() {
|
|
|
15
18
|
}
|
|
16
19
|
return parsed;
|
|
17
20
|
}
|
|
18
|
-
/**
|
|
19
|
-
* Surface a `TokenStorageResult` from a save/clear: the human-readable
|
|
20
|
-
* confirmation goes to stdout, any keyring-fallback warning goes to stderr.
|
|
21
|
-
* Pass `isMachineOutput: true` to suppress the stdout confirmation in
|
|
22
|
-
* `--json` / `--ndjson` mode while still routing the warning to stderr.
|
|
23
|
-
*
|
|
24
|
-
* Exported for direct unit testing — the alternative (driving this via
|
|
25
|
-
* mocked cli-core login/logout hooks) would require stubbing the entire
|
|
26
|
-
* store contract just to assert two console calls.
|
|
27
|
-
*/
|
|
28
|
-
export function logTokenStorageResult(result, secureStoreMessage, isMachineOutput = false) {
|
|
29
|
-
if (!isMachineOutput && result.storage === 'secure-store') {
|
|
30
|
-
console.log(chalk.dim(secureStoreMessage));
|
|
31
|
-
}
|
|
32
|
-
if (result.warning) {
|
|
33
|
-
console.error(chalk.yellow('Warning:'), result.warning);
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
21
|
export function registerAuthCommand(program) {
|
|
37
22
|
const auth = program.command('auth').description('Manage authentication');
|
|
38
23
|
const provider = createOutlineAuthProvider();
|
|
39
24
|
const store = createOutlineTokenStore();
|
|
25
|
+
// Honours a global `ol --user <ref>` placed before `auth status` / `auth
|
|
26
|
+
// logout`; login always targets the freshly authenticated account, so it
|
|
27
|
+
// keeps the raw store.
|
|
28
|
+
const refAware = withUserRefAware(store);
|
|
40
29
|
attachLoginCommand(auth, {
|
|
41
30
|
provider,
|
|
42
31
|
store,
|
|
@@ -63,13 +52,24 @@ export function registerAuthCommand(program) {
|
|
|
63
52
|
// populated by the time the render hooks read it.
|
|
64
53
|
let statusData = null;
|
|
65
54
|
attachStatusCommand(auth, {
|
|
66
|
-
store,
|
|
55
|
+
store: refAware,
|
|
67
56
|
description: 'Show current authentication state',
|
|
68
|
-
async fetchLive({
|
|
57
|
+
async fetchLive({ account, token }) {
|
|
69
58
|
try {
|
|
59
|
+
// Refresh the *selected* account before the check (scoped via
|
|
60
|
+
// its id + base URL/client id), then probe with the rotated
|
|
61
|
+
// token. Outline access tokens last ~an hour; without this
|
|
62
|
+
// `auth status` can't self-heal even though normal commands
|
|
63
|
+
// do. Passing the resolved token keeps the check tied to the
|
|
64
|
+
// requested account rather than the default.
|
|
65
|
+
const liveToken = await refreshedTokenForStatus(account, token);
|
|
70
66
|
const [{ data: info }, source] = await Promise.all([
|
|
71
|
-
apiRequest('auth.info', {}, { token, baseUrl: account.baseUrl }),
|
|
72
|
-
|
|
67
|
+
apiRequest('auth.info', {}, { token: liveToken, baseUrl: account.baseUrl }),
|
|
68
|
+
// Scope the source to the selected account so `auth status
|
|
69
|
+
// --user <ref>` reports where *that* account's token lives,
|
|
70
|
+
// not the default/env source. Empty id (env/legacy snapshot)
|
|
71
|
+
// falls back to the default cascade.
|
|
72
|
+
getActiveTokenSource(account.id || undefined),
|
|
73
73
|
]);
|
|
74
74
|
statusData = { email: info.user.email, source };
|
|
75
75
|
return {
|
|
@@ -115,13 +115,10 @@ export function registerAuthCommand(program) {
|
|
|
115
115
|
},
|
|
116
116
|
});
|
|
117
117
|
attachLogoutCommand(auth, {
|
|
118
|
-
store,
|
|
118
|
+
store: refAware,
|
|
119
119
|
description: 'Clear saved authentication',
|
|
120
120
|
onCleared({ view }) {
|
|
121
|
-
|
|
122
|
-
if (!result)
|
|
123
|
-
return;
|
|
124
|
-
logTokenStorageResult(result, 'Stored token removed from the system credential manager', view.json || view.ndjson);
|
|
121
|
+
logClearResult(store, view.json || view.ndjson);
|
|
125
122
|
},
|
|
126
123
|
});
|
|
127
124
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/commands/auth.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
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,5 +1,6 @@
|
|
|
1
1
|
import { fetchWithRetry } from '../transport/fetch-with-retry.js';
|
|
2
|
-
import {
|
|
2
|
+
import { TOKEN_ENV_VAR } from './auth-constants.js';
|
|
3
|
+
import { getApiToken, getRequestContext, proactiveRefresh, reactiveRefresh } from './auth.js';
|
|
3
4
|
import { withSpinner } from './spinner.js';
|
|
4
5
|
/**
|
|
5
6
|
* Spinner configuration mapping API paths to spinner options.
|
|
@@ -22,25 +23,63 @@ const API_SPINNER_CONFIG = {
|
|
|
22
23
|
'collections.update': { text: 'Updating collection...', color: 'yellow' },
|
|
23
24
|
'collections.delete': { text: 'Deleting collection...', color: 'yellow' },
|
|
24
25
|
};
|
|
26
|
+
/**
|
|
27
|
+
* Resolve the token for a request. A caller-supplied override is used as-is.
|
|
28
|
+
* On the managed path, prefer the token `proactiveRefresh` resolved (rotated
|
|
29
|
+
* or current) so unrefreshable/access-only accounts stay on a single store
|
|
30
|
+
* read; only fall back to `getApiToken` when proactive refresh bows out.
|
|
31
|
+
* `handshake` pins the refresh to the `--user` account's instance.
|
|
32
|
+
*/
|
|
33
|
+
async function resolveRequestToken(managed, override, handshake) {
|
|
34
|
+
if (override)
|
|
35
|
+
return override;
|
|
36
|
+
if (managed) {
|
|
37
|
+
const refreshed = await proactiveRefresh(handshake);
|
|
38
|
+
if (refreshed)
|
|
39
|
+
return refreshed;
|
|
40
|
+
}
|
|
41
|
+
return getApiToken();
|
|
42
|
+
}
|
|
25
43
|
/**
|
|
26
44
|
* Core API request function without spinner wrapping.
|
|
27
45
|
*/
|
|
28
46
|
async function rawApiRequest(path, body = {}, overrides = {}) {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
47
|
+
// Only stored credentials can be refreshed: a caller-supplied token
|
|
48
|
+
// override or the `OUTLINE_API_TOKEN` env var is taken as-is.
|
|
49
|
+
const managed = !overrides.token && !process.env[TOKEN_ENV_VAR]?.trim();
|
|
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);
|
|
65
|
+
const performRequest = (token) => fetchWithRetry({
|
|
34
66
|
url: `${resolvedBaseUrl}/api/${path}`,
|
|
35
67
|
options: {
|
|
36
68
|
method: 'POST',
|
|
37
69
|
headers: {
|
|
38
70
|
'Content-Type': 'application/json',
|
|
39
|
-
Authorization: `Bearer ${
|
|
71
|
+
Authorization: `Bearer ${token}`,
|
|
40
72
|
},
|
|
41
73
|
body: JSON.stringify(body),
|
|
42
74
|
},
|
|
43
75
|
});
|
|
76
|
+
let res = await performRequest(resolvedToken);
|
|
77
|
+
// Reactive path: a 401 on a managed token triggers a forced rotation and
|
|
78
|
+
// a single retry. `reactiveRefresh` throws `NoTokenError` when the refresh
|
|
79
|
+
// token is gone, so an unrecoverable 401 surfaces the re-login hint.
|
|
80
|
+
if (res.status === 401 && managed && (await reactiveRefresh(handshake))) {
|
|
81
|
+
res = await performRequest(await getApiToken());
|
|
82
|
+
}
|
|
44
83
|
if (!res.ok) {
|
|
45
84
|
let message = `API error: ${res.status} ${res.statusText}`;
|
|
46
85
|
try {
|
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,WAAW,EAAE,
|
|
1
|
+
{"version":3,"file":"api.js","sourceRoot":"","sources":["../../src/lib/api.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
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 clear (`auth logout` / `account remove`): the
|
|
12
|
+
* confirmation goes to stdout, any keyring-fallback warning to stderr. Shared so
|
|
13
|
+
* both call sites stay in lockstep.
|
|
14
|
+
*/
|
|
15
|
+
export declare function logClearResult(store: OutlineTokenStore, isMachineOutput: boolean): void;
|
|
@@ -0,0 +1,27 @@
|
|
|
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 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 function logClearResult(store, isMachineOutput) {
|
|
22
|
+
const result = store.getLastClearResult();
|
|
23
|
+
if (!result)
|
|
24
|
+
return;
|
|
25
|
+
logTokenStorageResult(result, 'Stored token removed from the system credential manager', isMachineOutput);
|
|
26
|
+
}
|
|
27
|
+
//# 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,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"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { type AccountRef, type AuthProvider, type KeyringTokenStore } from '@doist/cli-core/auth';
|
|
2
2
|
import { type OutlineAccount } from './outline-account.js';
|
|
3
3
|
export type { OutlineAccount } from './outline-account.js';
|
|
4
|
+
export { matchOutlineAccount } from './outline-account.js';
|
|
4
5
|
export type AuthInfoResponse = {
|
|
5
6
|
user: {
|
|
6
7
|
id: string;
|
|
@@ -14,12 +15,6 @@ export type AuthInfoResponse = {
|
|
|
14
15
|
};
|
|
15
16
|
export type OutlineTokenStore = KeyringTokenStore<OutlineAccount>;
|
|
16
17
|
export declare function createOutlineAuthProvider(): AuthProvider<OutlineAccount>;
|
|
17
|
-
/**
|
|
18
|
-
* Accepts the Outline user UUID or display name. Id matches are
|
|
19
|
-
* case-sensitive (UUIDs are canonical); label matches are
|
|
20
|
-
* case-insensitive so users can pass the name they see in `auth status`.
|
|
21
|
-
*/
|
|
22
|
-
export declare function matchOutlineAccount(account: OutlineAccount, ref: AccountRef): boolean;
|
|
23
18
|
/**
|
|
24
19
|
* True when the v2 store is empty but a legacy v1 token snapshot is still
|
|
25
20
|
* the only thing keeping the CLI authenticated — typically because
|
|
@@ -29,26 +24,39 @@ export declare function matchOutlineAccount(account: OutlineAccount, ref: Accoun
|
|
|
29
24
|
* v1 keyring slot to read from). Useful for downstream diagnostics.
|
|
30
25
|
*/
|
|
31
26
|
export declare function isLegacyAuthActive(): Promise<boolean>;
|
|
27
|
+
/** Where `ol account current` resolves the active credential from. */
|
|
28
|
+
export type ActiveAccountSource = {
|
|
29
|
+
source: 'stored';
|
|
30
|
+
account: OutlineAccount;
|
|
31
|
+
isDefault: boolean;
|
|
32
|
+
} | {
|
|
33
|
+
source: 'env';
|
|
34
|
+
} | {
|
|
35
|
+
source: 'legacy';
|
|
36
|
+
} | null;
|
|
32
37
|
/**
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
* account.
|
|
38
|
+
* Authoritatively classify the active credential without re-deriving the
|
|
39
|
+
* cascade from membership heuristics. Mirrors `active()`'s precedence — env
|
|
40
|
+
* (only when no explicit ref) → stored v2 → legacy snapshot — but reports
|
|
41
|
+
* *which* branch matched, so `ol account current` can render the right shape.
|
|
37
42
|
*
|
|
38
|
-
*
|
|
39
|
-
* legacy
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
* the cleanup failure (v2 wins in `active()` regardless); `clear()`
|
|
43
|
-
* propagates it so a failed logout fails loudly instead of leaving the
|
|
44
|
-
* user authenticated via the legacy fallback.
|
|
43
|
+
* The v2 lookup uses the bare keyring store (no legacy fallback) and matches by
|
|
44
|
+
* `ref`, so a renamed legacy snapshot sharing a UUID with a v2 record can't be
|
|
45
|
+
* misreported as `stored`: a `--user <old-name>` that the v2 record no longer
|
|
46
|
+
* matches falls through to the legacy branch.
|
|
45
47
|
*/
|
|
48
|
+
export declare function resolveActiveAccountSource(ref?: AccountRef): Promise<ActiveAccountSource>;
|
|
46
49
|
export declare function createOutlineTokenStore(): OutlineTokenStore;
|
|
47
50
|
/**
|
|
48
51
|
* Where the currently-active token lives. Mirrors `active()`'s resolution
|
|
49
52
|
* order — env → v2 record → legacy plaintext — so the answer can never
|
|
50
53
|
* contradict the token the runtime is actually using.
|
|
51
54
|
*
|
|
55
|
+
* Pass `ref` to report the source of a specific `--user` account (used by
|
|
56
|
+
* `auth status --user <ref>`): a ref selects the matching record and skips the
|
|
57
|
+
* env short-circuit, so the source reflects the account being shown rather
|
|
58
|
+
* than an ambient env token. Without a ref the default/env cascade applies.
|
|
59
|
+
*
|
|
52
60
|
* The precedence cascade is intentionally duplicated with `active()`:
|
|
53
61
|
* the only true dedupe options either (a) add an extra config read on
|
|
54
62
|
* every `apiRequest` call (regressing the request hot path) or (b)
|
|
@@ -56,4 +64,4 @@ export declare function createOutlineTokenStore(): OutlineTokenStore;
|
|
|
56
64
|
* invites is guarded by the `getActiveTokenSource` regression test that
|
|
57
65
|
* asserts v2-record presence wins over a lingering v1 `api_token`.
|
|
58
66
|
*/
|
|
59
|
-
export declare function getActiveTokenSource(): Promise<'env' | 'secure-store' | 'config-file'>;
|
|
67
|
+
export declare function getActiveTokenSource(ref?: AccountRef): Promise<'env' | 'secure-store' | 'config-file'>;
|