@doist/twist-cli 2.39.0 → 2.40.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 +6 -0
- package/dist/commands/auth/helpers.d.ts +1 -1
- package/dist/commands/auth/helpers.d.ts.map +1 -1
- package/dist/commands/auth/helpers.js.map +1 -1
- package/dist/commands/auth/store-wrap.d.ts +1 -1
- package/dist/commands/auth/store-wrap.d.ts.map +1 -1
- package/dist/commands/auth/store-wrap.js +18 -1
- package/dist/commands/auth/store-wrap.js.map +1 -1
- package/dist/commands/auth/token.d.ts.map +1 -1
- package/dist/commands/auth/token.js +19 -10
- package/dist/commands/auth/token.js.map +1 -1
- package/dist/lib/auth-constants.d.ts +9 -0
- package/dist/lib/auth-constants.d.ts.map +1 -0
- package/dist/lib/auth-constants.js +9 -0
- package/dist/lib/auth-constants.js.map +1 -0
- package/dist/lib/auth-provider.d.ts +26 -7
- package/dist/lib/auth-provider.d.ts.map +1 -1
- package/dist/lib/auth-provider.js +151 -108
- package/dist/lib/auth-provider.js.map +1 -1
- package/dist/lib/auth.d.ts +13 -12
- package/dist/lib/auth.d.ts.map +1 -1
- package/dist/lib/auth.js +46 -238
- package/dist/lib/auth.js.map +1 -1
- package/dist/lib/config.d.ts +21 -1
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +62 -3
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/migrate-auth.d.ts +14 -0
- package/dist/lib/migrate-auth.d.ts.map +1 -0
- package/dist/lib/migrate-auth.js +61 -0
- package/dist/lib/migrate-auth.js.map +1 -0
- package/dist/lib/twist-account.d.ts +22 -0
- package/dist/lib/twist-account.d.ts.map +1 -0
- package/dist/lib/twist-account.js +23 -0
- package/dist/lib/twist-account.js.map +1 -0
- package/dist/lib/user-records.d.ts +15 -0
- package/dist/lib/user-records.d.ts.map +1 -0
- package/dist/lib/user-records.js +84 -0
- package/dist/lib/user-records.js.map +1 -0
- package/dist/postinstall.js +4 -0
- package/dist/postinstall.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
## [2.40.0](https://github.com/Doist/twist-cli/compare/v2.39.0...v2.40.0) (2026-05-17)
|
|
2
|
+
|
|
3
|
+
### Features
|
|
4
|
+
|
|
5
|
+
- **auth:** schema v2 + multi-account migration foundation ([#232](https://github.com/Doist/twist-cli/issues/232)) ([8ca3382](https://github.com/Doist/twist-cli/commit/8ca3382378506ddb27cdcb521103d06bd567a3fb))
|
|
6
|
+
|
|
1
7
|
## [2.39.0](https://github.com/Doist/twist-cli/compare/v2.38.0...v2.39.0) (2026-05-16)
|
|
2
8
|
|
|
3
9
|
### Features
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { TokenStorageResult } from '
|
|
1
|
+
import type { TokenStorageResult } from '@doist/cli-core/auth';
|
|
2
2
|
/**
|
|
3
3
|
* Surface a `TokenStorageResult` from a save/clear operation: the
|
|
4
4
|
* human-readable confirmation goes to stdout, any keyring-fallback warning
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../../src/commands/auth/helpers.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../../src/commands/auth/helpers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAA;AAG9D;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CACjC,MAAM,EAAE,kBAAkB,EAC1B,kBAAkB,EAAE,MAAM,EAC1B,eAAe,UAAQ,GACxB,IAAI,CAON"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"helpers.js","sourceRoot":"","sources":["../../../src/commands/auth/helpers.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"helpers.js","sourceRoot":"","sources":["../../../src/commands/auth/helpers.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB;;;;;;GAMG;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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import type { AccountRef } from '@doist/cli-core/auth';
|
|
2
|
-
import type
|
|
2
|
+
import { type TwistTokenStore } from '../../lib/auth-provider.js';
|
|
3
3
|
export declare function withUserRefAware(store: TwistTokenStore, requestedRef: AccountRef | undefined): TwistTokenStore;
|
|
4
4
|
//# sourceMappingURL=store-wrap.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store-wrap.d.ts","sourceRoot":"","sources":["../../../src/commands/auth/store-wrap.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAA;AACtD,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"store-wrap.d.ts","sourceRoot":"","sources":["../../../src/commands/auth/store-wrap.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAA;AACtD,OAAO,EAAqB,KAAK,eAAe,EAAE,MAAM,4BAA4B,CAAA;AAapF,wBAAgB,gBAAgB,CAC5B,KAAK,EAAE,eAAe,EACtB,YAAY,EAAE,UAAU,GAAG,SAAS,GACrC,eAAe,CAgBjB"}
|
|
@@ -1,10 +1,27 @@
|
|
|
1
|
+
import { matchTwistAccount } from '../../lib/auth-provider.js';
|
|
2
|
+
import { CliError } from '../../lib/errors.js';
|
|
1
3
|
// Bridge the global `tw --user <ref>` (stripped by `src/index.ts`) into
|
|
2
4
|
// cli-core's attachers, which only see per-command `--user`. Explicit ref
|
|
3
5
|
// passed by commander wins over the captured global ref.
|
|
6
|
+
//
|
|
7
|
+
// `active()` passes the substituted ref straight through — cli-core's
|
|
8
|
+
// `KeyringTokenStore.active` returns `null` on a miss, which the attachers
|
|
9
|
+
// surface via `onNotAuthenticated` (status / token view). `clear()` does the
|
|
10
|
+
// extra existence check first, because cli-core's `KeyringTokenStore.clear`
|
|
11
|
+
// is a silent no-op on a non-matching ref and would otherwise let
|
|
12
|
+
// `tw --user <wrong> auth logout` print `✓ Logged out`.
|
|
4
13
|
export function withUserRefAware(store, requestedRef) {
|
|
5
14
|
return Object.assign(Object.create(store), {
|
|
6
15
|
active: (ref) => store.active(ref ?? requestedRef),
|
|
7
|
-
clear: (ref) =>
|
|
16
|
+
clear: async (ref) => {
|
|
17
|
+
if (ref === undefined && requestedRef !== undefined) {
|
|
18
|
+
const records = await store.list();
|
|
19
|
+
if (!records.some(({ account }) => matchTwistAccount(account, requestedRef))) {
|
|
20
|
+
throw new CliError('ACCOUNT_NOT_FOUND', `No stored account matches "${requestedRef}".`);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
await store.clear(ref ?? requestedRef);
|
|
24
|
+
},
|
|
8
25
|
});
|
|
9
26
|
}
|
|
10
27
|
//# sourceMappingURL=store-wrap.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store-wrap.js","sourceRoot":"","sources":["../../../src/commands/auth/store-wrap.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"store-wrap.js","sourceRoot":"","sources":["../../../src/commands/auth/store-wrap.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAwB,MAAM,4BAA4B,CAAA;AACpF,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAA;AAE9C,wEAAwE;AACxE,0EAA0E;AAC1E,yDAAyD;AACzD,EAAE;AACF,sEAAsE;AACtE,2EAA2E;AAC3E,6EAA6E;AAC7E,4EAA4E;AAC5E,kEAAkE;AAClE,wDAAwD;AACxD,MAAM,UAAU,gBAAgB,CAC5B,KAAsB,EACtB,YAAoC;IAEpC,OAAO,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAoB,EAAE;QAC1D,MAAM,EAAE,CAAC,GAAgB,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,IAAI,YAAY,CAAC;QAC/D,KAAK,EAAE,KAAK,EAAE,GAAgB,EAAE,EAAE;YAC9B,IAAI,GAAG,KAAK,SAAS,IAAI,YAAY,KAAK,SAAS,EAAE,CAAC;gBAClD,MAAM,OAAO,GAAG,MAAM,KAAK,CAAC,IAAI,EAAE,CAAA;gBAClC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,iBAAiB,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC,EAAE,CAAC;oBAC3E,MAAM,IAAI,QAAQ,CACd,mBAAmB,EACnB,8BAA8B,YAAY,IAAI,CACjD,CAAA;gBACL,CAAC;YACL,CAAC;YACD,MAAM,KAAK,CAAC,KAAK,CAAC,GAAG,IAAI,YAAY,CAAC,CAAA;QAC1C,CAAC;KACJ,CAAC,CAAA;AACN,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"token.d.ts","sourceRoot":"","sources":["../../../src/commands/auth/token.ts"],"names":[],"mappings":"AA6BA,wBAAsB,cAAc,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"token.d.ts","sourceRoot":"","sources":["../../../src/commands/auth/token.ts"],"names":[],"mappings":"AA6BA,wBAAsB,cAAc,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA6BlE"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createInterface } from 'node:readline';
|
|
2
2
|
import chalk from 'chalk';
|
|
3
|
-
import {
|
|
3
|
+
import { createTwistTokenStore } from '../../lib/auth-provider.js';
|
|
4
4
|
import { CliError } from '../../lib/errors.js';
|
|
5
5
|
import { isNonInteractive } from '../../lib/global-args.js';
|
|
6
6
|
import { logTokenStorageResult } from './helpers.js';
|
|
@@ -30,16 +30,25 @@ export async function loginWithToken(token) {
|
|
|
30
30
|
throw new CliError('NO_TOKEN', 'Cannot prompt for token in non-interactive mode. Set the TWIST_API_TOKEN environment variable instead.');
|
|
31
31
|
}
|
|
32
32
|
token = await promptHiddenInput('API token: ');
|
|
33
|
-
if (!token.trim()) {
|
|
34
|
-
throw new CliError('NO_TOKEN', 'No token provided', [
|
|
35
|
-
'Run: tw auth token (interactive prompt)',
|
|
36
|
-
'Or set TWIST_API_TOKEN environment variable',
|
|
37
|
-
'Or use OAuth: tw auth login',
|
|
38
|
-
]);
|
|
39
|
-
}
|
|
40
33
|
}
|
|
41
|
-
const
|
|
34
|
+
const trimmed = token.trim();
|
|
35
|
+
if (!trimmed) {
|
|
36
|
+
throw new CliError('NO_TOKEN', 'No token provided', [
|
|
37
|
+
'Run: tw auth token (interactive prompt)',
|
|
38
|
+
'Or set TWIST_API_TOKEN environment variable',
|
|
39
|
+
'Or use OAuth: tw auth login',
|
|
40
|
+
]);
|
|
41
|
+
}
|
|
42
|
+
// Manual token entry has no identity (no API call to resolve the user).
|
|
43
|
+
// Persist the empty-id account; `UserRecordStore.upsert` writes
|
|
44
|
+
// `authUserId: undefined` for it and the synthesised record is what later
|
|
45
|
+
// `active()` / `list()` reads will return.
|
|
46
|
+
const store = createTwistTokenStore();
|
|
47
|
+
await store.set({ id: '', label: '', authMode: 'unknown', authScope: '' }, trimmed);
|
|
42
48
|
console.log(chalk.green('✓'), 'API token saved successfully!');
|
|
43
|
-
|
|
49
|
+
const result = store.getLastStorageResult();
|
|
50
|
+
if (result) {
|
|
51
|
+
logTokenStorageResult(result, 'Token stored securely in the system credential manager');
|
|
52
|
+
}
|
|
44
53
|
}
|
|
45
54
|
//# sourceMappingURL=token.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"token.js","sourceRoot":"","sources":["../../../src/commands/auth/token.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AAC/C,OAAO,KAAK,MAAM,OAAO,CAAA;AACzB,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"token.js","sourceRoot":"","sources":["../../../src/commands/auth/token.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AAC/C,OAAO,KAAK,MAAM,OAAO,CAAA;AACzB,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAA;AAClE,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAA;AAC9C,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAA;AAC3D,OAAO,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAA;AAEpD,SAAS,iBAAiB,CAAC,MAAc;IACrC,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC3B,MAAM,EAAE,GAAG,eAAe,CAAC;YACvB,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,MAAM,EAAE,OAAO,CAAC,MAAM;SACzB,CAAC,CAAA;QACF,kFAAkF;QAClF,MAAM,SAAS,GAAI,EAAU,CAAC,cAAc,CAE3C;QAAC,EAAU,CAAC,cAAc,GAAG,CAAC,GAAW,EAAE,EAAE;YAC1C,IAAI,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;gBACvB,SAAS,CAAC,IAAI,CAAC,EAAE,EAAE,MAAM,CAAC,CAAA;YAC9B,CAAC;QACL,CAAC,CAAA;QACD,EAAE,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,MAAM,EAAE,EAAE;YAC3B,EAAE,CAAC,KAAK,EAAE,CAAA;YACV,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;YAC1B,OAAO,CAAC,MAAM,CAAC,CAAA;QACnB,CAAC,CAAC,CAAA;IACN,CAAC,CAAC,CAAA;AACN,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,KAAc;IAC/C,IAAI,CAAC,KAAK,EAAE,CAAC;QACT,IAAI,gBAAgB,EAAE,EAAE,CAAC;YACrB,MAAM,IAAI,QAAQ,CACd,UAAU,EACV,wGAAwG,CAC3G,CAAA;QACL,CAAC;QACD,KAAK,GAAG,MAAM,iBAAiB,CAAC,aAAa,CAAC,CAAA;IAClD,CAAC;IACD,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,EAAE,CAAA;IAC5B,IAAI,CAAC,OAAO,EAAE,CAAC;QACX,MAAM,IAAI,QAAQ,CAAC,UAAU,EAAE,mBAAmB,EAAE;YAChD,yCAAyC;YACzC,6CAA6C;YAC7C,6BAA6B;SAChC,CAAC,CAAA;IACN,CAAC;IACD,wEAAwE;IACxE,gEAAgE;IAChE,0EAA0E;IAC1E,2CAA2C;IAC3C,MAAM,KAAK,GAAG,qBAAqB,EAAE,CAAA;IACrC,MAAM,KAAK,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE,EAAE,EAAE,EAAE,OAAO,CAAC,CAAA;IACnF,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,+BAA+B,CAAC,CAAA;IAC9D,MAAM,MAAM,GAAG,KAAK,CAAC,oBAAoB,EAAE,CAAA;IAC3C,IAAI,MAAM,EAAE,CAAC;QACT,qBAAqB,CAAC,MAAM,EAAE,wDAAwD,CAAC,CAAA;IAC3F,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/** OS keyring `service` identifier for every twist-cli secret. */
|
|
2
|
+
export declare const SECURE_STORE_SERVICE = "twist-cli";
|
|
3
|
+
/**
|
|
4
|
+
* Legacy single-user keyring slot. `migrateLegacyAuth` deletes it after a
|
|
5
|
+
* successful migration; the runtime token store reads it as a last resort
|
|
6
|
+
* when migration can't complete (e.g. offline `identifyAccount`).
|
|
7
|
+
*/
|
|
8
|
+
export declare const LEGACY_KEYRING_ACCOUNT = "api-token";
|
|
9
|
+
//# sourceMappingURL=auth-constants.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth-constants.d.ts","sourceRoot":"","sources":["../../src/lib/auth-constants.ts"],"names":[],"mappings":"AAAA,kEAAkE;AAClE,eAAO,MAAM,oBAAoB,cAAc,CAAA;AAE/C;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,cAAc,CAAA"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/** OS keyring `service` identifier for every twist-cli secret. */
|
|
2
|
+
export const SECURE_STORE_SERVICE = 'twist-cli';
|
|
3
|
+
/**
|
|
4
|
+
* Legacy single-user keyring slot. `migrateLegacyAuth` deletes it after a
|
|
5
|
+
* successful migration; the runtime token store reads it as a last resort
|
|
6
|
+
* when migration can't complete (e.g. offline `identifyAccount`).
|
|
7
|
+
*/
|
|
8
|
+
export const LEGACY_KEYRING_ACCOUNT = 'api-token';
|
|
9
|
+
//# sourceMappingURL=auth-constants.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth-constants.js","sourceRoot":"","sources":["../../src/lib/auth-constants.ts"],"names":[],"mappings":"AAAA,kEAAkE;AAClE,MAAM,CAAC,MAAM,oBAAoB,GAAG,WAAW,CAAA;AAE/C;;;;GAIG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,WAAW,CAAA"}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { type AuthAccount, type AuthProvider, type
|
|
2
|
-
import { type
|
|
3
|
-
import type { AuthMode } from './config.js';
|
|
1
|
+
import { type AccountRef, type AuthAccount, type AuthProvider, type KeyringTokenStore } from '@doist/cli-core/auth';
|
|
2
|
+
import { type AuthMode } from './config.js';
|
|
4
3
|
export declare const AUTHORIZATION_URL = "https://twist.com/oauth/authorize";
|
|
5
4
|
export declare const TOKEN_URL = "https://twist.com/oauth/access_token";
|
|
6
5
|
export declare const REGISTRATION_URL = "https://twist.com/oauth/register";
|
|
@@ -19,10 +18,30 @@ export type TwistAccount = AuthAccount & {
|
|
|
19
18
|
authMode: AuthMode;
|
|
20
19
|
authScope: string;
|
|
21
20
|
};
|
|
21
|
+
export type TwistTokenStore = KeyringTokenStore<TwistAccount>;
|
|
22
22
|
export declare function createTwistAuthProvider(): AuthProvider<TwistAccount>;
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
23
|
+
/**
|
|
24
|
+
* Accepts `42`, `id:42`, and case-insensitive labels — `parseRef` normalises
|
|
25
|
+
* the numeric forms. Broader than cli-core's default strict-equality matcher.
|
|
26
|
+
*/
|
|
27
|
+
export declare function matchTwistAccount(account: TwistAccount, ref: AccountRef): boolean;
|
|
28
|
+
/**
|
|
29
|
+
* `TWIST_API_TOKEN` short-circuits `active()` only when no explicit ref is
|
|
30
|
+
* supplied — cli-core's `KeyringTokenStore` doesn't know about the env var,
|
|
31
|
+
* and an explicit ref means the caller targets a specific stored account.
|
|
32
|
+
*
|
|
33
|
+
* `ensureMigrated()` runs on every stored-state op so `--ignore-scripts`
|
|
34
|
+
* installs still migrate on first command. When migration isn't conclusive:
|
|
35
|
+
* - `active()` falls back to the legacy snapshot, honouring `ref` so it
|
|
36
|
+
* can't resolve to a different account than the caller asked for.
|
|
37
|
+
* - `set()` / `clear()` discharge legacy state on disk first so v2 writes
|
|
38
|
+
* aren't shadowed by a stale v1 token on the next read.
|
|
39
|
+
*/
|
|
27
40
|
export declare function createTwistTokenStore(): TwistTokenStore;
|
|
41
|
+
/**
|
|
42
|
+
* Where the currently-active token lives. Returns `'config-file'` whenever
|
|
43
|
+
* a plaintext token is on disk — including the legacy `config.token` slot —
|
|
44
|
+
* so doctor/config-view reports the security-relevant state accurately.
|
|
45
|
+
*/
|
|
46
|
+
export declare function getActiveTokenSource(): Promise<'env' | 'secure-store' | 'config-file'>;
|
|
28
47
|
//# sourceMappingURL=auth-provider.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth-provider.d.ts","sourceRoot":"","sources":["../../src/lib/auth-provider.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"auth-provider.d.ts","sourceRoot":"","sources":["../../src/lib/auth-provider.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,KAAK,UAAU,EACf,KAAK,WAAW,EAChB,KAAK,YAAY,EAKjB,KAAK,iBAAiB,EAEzB,MAAM,sBAAsB,CAAA;AAG7B,OAAO,EAAE,KAAK,QAAQ,EAA0C,MAAM,aAAa,CAAA;AAOnF,eAAO,MAAM,iBAAiB,sCAAsC,CAAA;AACpE,eAAO,MAAM,SAAS,yCAAyC,CAAA;AAC/D,eAAO,MAAM,gBAAgB,qCAAqC,CAAA;AAKlE,eAAO,MAAM,iBAAiB,UAkB7B,CAAA;AAED,eAAO,MAAM,gBAAgB,UAW5B,CAAA;AAID;;;;;;GAMG;AACH,MAAM,MAAM,YAAY,GAAG,WAAW,GAAG;IACrC,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,QAAQ,CAAA;IAClB,SAAS,EAAE,MAAM,CAAA;CACpB,CAAA;AAED,MAAM,MAAM,eAAe,GAAG,iBAAiB,CAAC,YAAY,CAAC,CAAA;AAsE7D,wBAAgB,uBAAuB,IAAI,YAAY,CAAC,YAAY,CAAC,CAsHpE;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,YAAY,EAAE,GAAG,EAAE,UAAU,GAAG,OAAO,CAKjF;AA8ED;;;;;;;;;;;GAWG;AACH,wBAAgB,qBAAqB,IAAI,eAAe,CAkDvD;AAED;;;;GAIG;AACH,wBAAsB,oBAAoB,IAAI,OAAO,CAAC,KAAK,GAAG,cAAc,GAAG,aAAa,CAAC,CAQ5F"}
|
|
@@ -1,8 +1,12 @@
|
|
|
1
|
-
import { deriveChallenge, generateVerifier,
|
|
1
|
+
import { createKeyringTokenStore, createSecureStore, deriveChallenge, generateVerifier, } from '@doist/cli-core/auth';
|
|
2
2
|
import { createWrappedTwistClient } from './api.js';
|
|
3
|
-
import {
|
|
3
|
+
import { LEGACY_KEYRING_ACCOUNT, SECURE_STORE_SERVICE } from './auth-constants.js';
|
|
4
|
+
import { getConfig, getConfigPath, updateConfig } from './config.js';
|
|
4
5
|
import { CliError } from './errors.js';
|
|
6
|
+
import { runMigrateLegacyAuth } from './migrate-auth.js';
|
|
5
7
|
import { parseRef } from './refs.js';
|
|
8
|
+
import { makeTwistAccount, toTwistAccount } from './twist-account.js';
|
|
9
|
+
import { createTwistUserRecordStore, getDefaultUserRecord } from './user-records.js';
|
|
6
10
|
export const AUTHORIZATION_URL = 'https://twist.com/oauth/authorize';
|
|
7
11
|
export const TOKEN_URL = 'https://twist.com/oauth/access_token';
|
|
8
12
|
export const REGISTRATION_URL = 'https://twist.com/oauth/register';
|
|
@@ -170,129 +174,168 @@ export function createTwistAuthProvider() {
|
|
|
170
174
|
const hs = asHandshake(handshake);
|
|
171
175
|
const client = createWrappedTwistClient(token);
|
|
172
176
|
const user = await client.users.getSessionUser();
|
|
173
|
-
return {
|
|
174
|
-
id: String(user.id),
|
|
175
|
-
label: user.name,
|
|
176
|
-
authMode: hs.authMode ?? 'unknown',
|
|
177
|
-
authScope: hs.authScope ?? '',
|
|
178
|
-
};
|
|
177
|
+
return toTwistAccount(user, { authMode: hs.authMode, authScope: hs.authScope });
|
|
179
178
|
},
|
|
180
179
|
};
|
|
181
180
|
}
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
181
|
+
/**
|
|
182
|
+
* Accepts `42`, `id:42`, and case-insensitive labels — `parseRef` normalises
|
|
183
|
+
* the numeric forms. Broader than cli-core's default strict-equality matcher.
|
|
184
|
+
*/
|
|
185
|
+
export function matchTwistAccount(account, ref) {
|
|
186
|
+
const parsed = parseRef(ref);
|
|
187
|
+
if (parsed.type === 'id')
|
|
188
|
+
return Number(account.id) === parsed.id;
|
|
189
|
+
if (parsed.type === 'name')
|
|
190
|
+
return account.label.toLowerCase() === parsed.name.toLowerCase();
|
|
191
|
+
return false;
|
|
192
|
+
}
|
|
193
|
+
const TOKEN_ENV_VAR = 'TWIST_API_TOKEN';
|
|
194
|
+
/** True when the v2 store is the authoritative source. */
|
|
195
|
+
function migrationIsConclusive(result) {
|
|
196
|
+
return (result.status === 'migrated' ||
|
|
197
|
+
result.status === 'already-migrated' ||
|
|
198
|
+
result.status === 'no-legacy-state');
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Synthesise a snapshot from v1 state still on disk (legacy keyring slot,
|
|
202
|
+
* then plaintext `config.token`). Fallback for when migration can't complete.
|
|
203
|
+
* Token-only users with no `authUserId` get `account.id = ''`.
|
|
204
|
+
*/
|
|
205
|
+
async function readLegacyTokenSnapshot() {
|
|
206
|
+
const fromKeyring = await createSecureStore({
|
|
207
|
+
serviceName: SECURE_STORE_SERVICE,
|
|
208
|
+
account: LEGACY_KEYRING_ACCOUNT,
|
|
209
|
+
})
|
|
210
|
+
.getSecret()
|
|
211
|
+
.catch(() => null);
|
|
212
|
+
const config = await getConfig();
|
|
213
|
+
const token = fromKeyring || config.token?.trim() || null;
|
|
214
|
+
if (!token)
|
|
215
|
+
return null;
|
|
216
|
+
return {
|
|
217
|
+
token,
|
|
218
|
+
account: makeTwistAccount({
|
|
219
|
+
id: config.authUserId !== undefined ? String(config.authUserId) : '',
|
|
220
|
+
label: config.authUserName ?? '',
|
|
221
|
+
authMode: config.authMode,
|
|
222
|
+
authScope: config.authScope,
|
|
223
|
+
}),
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Clear the legacy keyring slot + v1 flat config fields. Runs before a
|
|
228
|
+
* write/clear when migration is inconclusive so v2 writes aren't shadowed
|
|
229
|
+
* by a stale legacy token. Best-effort — failures leave legacy in place.
|
|
230
|
+
*/
|
|
231
|
+
async function dischargeLegacyState() {
|
|
232
|
+
await Promise.allSettled([
|
|
233
|
+
createSecureStore({
|
|
234
|
+
serviceName: SECURE_STORE_SERVICE,
|
|
235
|
+
account: LEGACY_KEYRING_ACCOUNT,
|
|
236
|
+
}).deleteSecret(),
|
|
237
|
+
updateConfig({
|
|
238
|
+
token: undefined,
|
|
239
|
+
authMode: undefined,
|
|
240
|
+
authScope: undefined,
|
|
241
|
+
authUserId: undefined,
|
|
242
|
+
authUserName: undefined,
|
|
243
|
+
pendingSecureStoreClear: undefined,
|
|
244
|
+
}),
|
|
245
|
+
]);
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* Memoised one-shot migration trigger. Resolves with `null` on rejection
|
|
249
|
+
* so the CLI never fails to start because of a migration error — the
|
|
250
|
+
* legacy snapshot fallback below handles that case. Tests reset the memo
|
|
251
|
+
* with `vi.resetModules()` + a dynamic re-import.
|
|
252
|
+
*/
|
|
253
|
+
let migrationPromise;
|
|
254
|
+
function ensureMigrated() {
|
|
255
|
+
if (!migrationPromise) {
|
|
256
|
+
migrationPromise = runMigrateLegacyAuth({ silent: true }).catch(() => null);
|
|
233
257
|
}
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
258
|
+
return migrationPromise;
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* `TWIST_API_TOKEN` short-circuits `active()` only when no explicit ref is
|
|
262
|
+
* supplied — cli-core's `KeyringTokenStore` doesn't know about the env var,
|
|
263
|
+
* and an explicit ref means the caller targets a specific stored account.
|
|
264
|
+
*
|
|
265
|
+
* `ensureMigrated()` runs on every stored-state op so `--ignore-scripts`
|
|
266
|
+
* installs still migrate on first command. When migration isn't conclusive:
|
|
267
|
+
* - `active()` falls back to the legacy snapshot, honouring `ref` so it
|
|
268
|
+
* can't resolve to a different account than the caller asked for.
|
|
269
|
+
* - `set()` / `clear()` discharge legacy state on disk first so v2 writes
|
|
270
|
+
* aren't shadowed by a stale v1 token on the next read.
|
|
271
|
+
*/
|
|
272
|
+
export function createTwistTokenStore() {
|
|
273
|
+
const inner = createKeyringTokenStore({
|
|
274
|
+
serviceName: SECURE_STORE_SERVICE,
|
|
275
|
+
userRecords: createTwistUserRecordStore(),
|
|
276
|
+
recordsLocation: getConfigPath(),
|
|
277
|
+
matchAccount: matchTwistAccount,
|
|
278
|
+
});
|
|
279
|
+
async function maybeDischargeLegacy() {
|
|
280
|
+
const result = await ensureMigrated();
|
|
281
|
+
if (result === null || !migrationIsConclusive(result)) {
|
|
282
|
+
await dischargeLegacyState();
|
|
245
283
|
}
|
|
246
|
-
return snapshot;
|
|
247
284
|
}
|
|
248
|
-
return {
|
|
285
|
+
return Object.assign(Object.create(inner), {
|
|
249
286
|
async active(ref) {
|
|
250
|
-
// No-ref legacy path — tolerate missing keyring / no token and
|
|
251
|
-
// return null so downstream callers (status's `fetchLive`,
|
|
252
|
-
// login's pre-flight, etc.) keep falling through to their own
|
|
253
|
-
// `NoTokenError` envelope rather than seeing a raw keyring
|
|
254
|
-
// error. Returning a snapshot whenever a token resolves — even
|
|
255
|
-
// when the persisted identity is empty (env var, manual
|
|
256
|
-
// `tw auth token`, pre-upgrade config) — also avoids a second
|
|
257
|
-
// credential read downstream.
|
|
258
287
|
if (ref === undefined) {
|
|
259
|
-
|
|
288
|
+
const envToken = process.env[TOKEN_ENV_VAR];
|
|
289
|
+
if (envToken) {
|
|
290
|
+
return {
|
|
291
|
+
token: envToken,
|
|
292
|
+
account: { id: '', label: '', authMode: 'unknown', authScope: '' },
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
const result = await ensureMigrated();
|
|
297
|
+
if (result === null || !migrationIsConclusive(result)) {
|
|
298
|
+
const legacy = await readLegacyTokenSnapshot();
|
|
299
|
+
if (legacy && (ref === undefined || matchTwistAccount(legacy.account, ref))) {
|
|
300
|
+
return legacy;
|
|
301
|
+
}
|
|
260
302
|
}
|
|
261
|
-
return
|
|
303
|
+
return inner.active(ref);
|
|
262
304
|
},
|
|
263
305
|
async set(account, token) {
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
authMode: account.authMode,
|
|
267
|
-
authScope: account.authScope,
|
|
268
|
-
authUserId: Number.isFinite(userId) ? userId : undefined,
|
|
269
|
-
authUserName: account.label,
|
|
270
|
-
});
|
|
306
|
+
await maybeDischargeLegacy();
|
|
307
|
+
return inner.set(account, token);
|
|
271
308
|
},
|
|
272
309
|
async clear(ref) {
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
// ✓ Logged out — the upstream `attachLogoutCommand` treats any
|
|
276
|
-
// non-throwing `clear()` as success.
|
|
277
|
-
if (ref !== undefined) {
|
|
278
|
-
await resolveByRef(ref);
|
|
279
|
-
}
|
|
280
|
-
lastClearResult = await clearApiToken();
|
|
310
|
+
await maybeDischargeLegacy();
|
|
311
|
+
return inner.clear(ref);
|
|
281
312
|
},
|
|
282
313
|
async list() {
|
|
283
|
-
|
|
284
|
-
return
|
|
314
|
+
await ensureMigrated();
|
|
315
|
+
return inner.list();
|
|
285
316
|
},
|
|
286
317
|
async setDefault(ref) {
|
|
287
|
-
await
|
|
288
|
-
|
|
289
|
-
},
|
|
290
|
-
getLastStorageResult() {
|
|
291
|
-
return lastStorageResult;
|
|
318
|
+
await ensureMigrated();
|
|
319
|
+
return inner.setDefault(ref);
|
|
292
320
|
},
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
321
|
+
});
|
|
322
|
+
}
|
|
323
|
+
/**
|
|
324
|
+
* Where the currently-active token lives. Returns `'config-file'` whenever
|
|
325
|
+
* a plaintext token is on disk — including the legacy `config.token` slot —
|
|
326
|
+
* so doctor/config-view reports the security-relevant state accurately.
|
|
327
|
+
*/
|
|
328
|
+
export async function getActiveTokenSource() {
|
|
329
|
+
if (process.env[TOKEN_ENV_VAR])
|
|
330
|
+
return 'env';
|
|
331
|
+
const config = await getConfig();
|
|
332
|
+
const record = getDefaultUserRecord(config);
|
|
333
|
+
if (record?.fallbackToken)
|
|
334
|
+
return 'config-file';
|
|
335
|
+
if (record)
|
|
336
|
+
return 'secure-store';
|
|
337
|
+
if (config.token?.trim())
|
|
338
|
+
return 'config-file';
|
|
339
|
+
return 'secure-store';
|
|
297
340
|
}
|
|
298
341
|
//# sourceMappingURL=auth-provider.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth-provider.js","sourceRoot":"","sources":["../../src/lib/auth-provider.ts"],"names":[],"mappings":"AAAA,OAAO,EAIH,eAAe,EACf,gBAAgB,
|
|
1
|
+
{"version":3,"file":"auth-provider.js","sourceRoot":"","sources":["../../src/lib/auth-provider.ts"],"names":[],"mappings":"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"}
|
package/dist/lib/auth.d.ts
CHANGED
|
@@ -1,21 +1,14 @@
|
|
|
1
|
+
import { SecureStoreUnavailableError } from '@doist/cli-core/auth';
|
|
1
2
|
import { type AuthMode } from './config.js';
|
|
2
3
|
import { CliError } from './errors.js';
|
|
3
|
-
export
|
|
4
|
-
export declare class NoTokenError extends CliError {
|
|
5
|
-
constructor();
|
|
6
|
-
}
|
|
4
|
+
export { SecureStoreUnavailableError };
|
|
7
5
|
export declare const TOKEN_ENV_VAR = "TWIST_API_TOKEN";
|
|
6
|
+
export declare const SECURE_STORE_DESCRIPTION = "system credential manager";
|
|
8
7
|
export type TokenStorageLocation = 'secure-store' | 'config-file';
|
|
9
8
|
export type TokenStorageResult = {
|
|
10
9
|
storage: TokenStorageLocation;
|
|
11
10
|
warning?: string;
|
|
12
11
|
};
|
|
13
|
-
export type SaveApiTokenOptions = {
|
|
14
|
-
authMode?: AuthMode;
|
|
15
|
-
authScope?: string;
|
|
16
|
-
authUserId?: number;
|
|
17
|
-
authUserName?: string;
|
|
18
|
-
};
|
|
19
12
|
export type AuthMetadata = {
|
|
20
13
|
authMode: AuthMode;
|
|
21
14
|
authScope?: string;
|
|
@@ -34,9 +27,17 @@ export type AuthProbeResult = {
|
|
|
34
27
|
token: string;
|
|
35
28
|
metadata: AuthProbeMetadata;
|
|
36
29
|
};
|
|
30
|
+
export declare class NoTokenError extends CliError {
|
|
31
|
+
constructor();
|
|
32
|
+
}
|
|
33
|
+
/** Read the active token. The store wraps env-var precedence internally. */
|
|
37
34
|
export declare function getApiToken(): Promise<string>;
|
|
35
|
+
/** Token + metadata in one round-trip for `tw config view` / `tw doctor`. */
|
|
38
36
|
export declare function probeApiToken(): Promise<AuthProbeResult>;
|
|
37
|
+
/**
|
|
38
|
+
* Auth metadata for `tw auth status` and `ensureWriteAllowed`. Falls back
|
|
39
|
+
* to v1 flat fields when no v2 record exists so a legacy `read-only` token
|
|
40
|
+
* isn't reported as `'unknown'` — that would skip the local READ_ONLY guard.
|
|
41
|
+
*/
|
|
39
42
|
export declare function getAuthMetadata(): Promise<AuthMetadata>;
|
|
40
|
-
export declare function saveApiToken(token: string, options?: SaveApiTokenOptions): Promise<TokenStorageResult>;
|
|
41
|
-
export declare function clearApiToken(): Promise<TokenStorageResult>;
|
|
42
43
|
//# sourceMappingURL=auth.d.ts.map
|