@doist/cli-core 0.17.0 → 0.19.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/README.md +33 -17
- package/dist/auth/errors.d.ts +1 -1
- package/dist/auth/errors.d.ts.map +1 -1
- package/dist/auth/flow.d.ts.map +1 -1
- package/dist/auth/flow.js +7 -8
- package/dist/auth/flow.js.map +1 -1
- package/dist/auth/index.d.ts +4 -2
- package/dist/auth/index.d.ts.map +1 -1
- package/dist/auth/index.js +2 -1
- package/dist/auth/index.js.map +1 -1
- package/dist/auth/keyring/internal.d.ts +50 -0
- package/dist/auth/keyring/internal.d.ts.map +1 -0
- package/dist/auth/keyring/internal.js +48 -0
- package/dist/auth/keyring/internal.js.map +1 -0
- package/dist/auth/keyring/migrate.d.ts +19 -17
- package/dist/auth/keyring/migrate.d.ts.map +1 -1
- package/dist/auth/keyring/migrate.js +111 -49
- package/dist/auth/keyring/migrate.js.map +1 -1
- package/dist/auth/keyring/record-write.d.ts +13 -1
- package/dist/auth/keyring/record-write.d.ts.map +1 -1
- package/dist/auth/keyring/record-write.js +18 -0
- package/dist/auth/keyring/record-write.js.map +1 -1
- package/dist/auth/keyring/token-store.d.ts +7 -1
- package/dist/auth/keyring/token-store.d.ts.map +1 -1
- package/dist/auth/keyring/token-store.js +63 -34
- package/dist/auth/keyring/token-store.js.map +1 -1
- package/dist/auth/persist.d.ts +9 -1
- package/dist/auth/persist.d.ts.map +1 -1
- package/dist/auth/persist.js +20 -0
- package/dist/auth/persist.js.map +1 -1
- package/dist/auth/providers/pkce.d.ts +1 -1
- package/dist/auth/providers/pkce.d.ts.map +1 -1
- package/dist/auth/providers/pkce.js +89 -7
- package/dist/auth/providers/pkce.js.map +1 -1
- package/dist/auth/refresh.d.ts +49 -0
- package/dist/auth/refresh.d.ts.map +1 -0
- package/dist/auth/refresh.js +184 -0
- package/dist/auth/refresh.js.map +1 -0
- package/dist/auth/status.d.ts +12 -4
- package/dist/auth/status.d.ts.map +1 -1
- package/dist/auth/status.js +45 -5
- package/dist/auth/status.js.map +1 -1
- package/dist/auth/types.d.ts +17 -0
- package/dist/auth/types.d.ts.map +1 -1
- package/package.json +9 -4
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
import { CliError, getErrorMessage } from '../../errors.js';
|
|
2
2
|
import { deriveChallenge, generateVerifier } from '../pkce.js';
|
|
3
|
+
// Upper bound on the refresh-token POST. Kept under the refresh helper's
|
|
4
|
+
// stale-lock threshold so a timed-out grant releases the lock before another
|
|
5
|
+
// invocation would consider it abandoned.
|
|
6
|
+
const REFRESH_TIMEOUT_MS = 10_000;
|
|
7
|
+
function expiresAtFromExpiresIn(expiresIn) {
|
|
8
|
+
return typeof expiresIn === 'number' ? Date.now() + expiresIn * 1000 : undefined;
|
|
9
|
+
}
|
|
3
10
|
/**
|
|
4
11
|
* Build an `AuthProvider` for the standard "PKCE S256, public client (no
|
|
5
12
|
* client_secret)" flow. Covers Outline (user-supplied client_id + base_url)
|
|
@@ -23,8 +30,10 @@ export function createPkceProvider(options) {
|
|
|
23
30
|
length: options.verifierLength,
|
|
24
31
|
});
|
|
25
32
|
const challenge = deriveChallenge(verifier);
|
|
26
|
-
const clientId =
|
|
27
|
-
|
|
33
|
+
const [clientId, authorizeUrl] = await Promise.all([
|
|
34
|
+
resolve(options.clientId, input.handshake, input.flags),
|
|
35
|
+
resolve(options.authorizeUrl, input.handshake, input.flags),
|
|
36
|
+
]);
|
|
28
37
|
const url = new URL(authorizeUrl);
|
|
29
38
|
url.searchParams.set('response_type', 'code');
|
|
30
39
|
url.searchParams.set('client_id', clientId);
|
|
@@ -50,7 +59,7 @@ export function createPkceProvider(options) {
|
|
|
50
59
|
// before calling exchange, so a `tokenUrl: ({ flags }) => ...`
|
|
51
60
|
// resolver sees the same flags it saw during authorize.
|
|
52
61
|
const flags = input.handshake.flags ?? {};
|
|
53
|
-
const tokenUrl = resolve(options.tokenUrl, input.handshake, flags);
|
|
62
|
+
const tokenUrl = await resolve(options.tokenUrl, input.handshake, flags);
|
|
54
63
|
const body = new URLSearchParams({
|
|
55
64
|
grant_type: 'authorization_code',
|
|
56
65
|
code: input.code,
|
|
@@ -91,17 +100,90 @@ export function createPkceProvider(options) {
|
|
|
91
100
|
return {
|
|
92
101
|
accessToken: payload.access_token,
|
|
93
102
|
refreshToken: payload.refresh_token,
|
|
94
|
-
expiresAt:
|
|
95
|
-
? Date.now() + payload.expires_in * 1000
|
|
96
|
-
: undefined,
|
|
103
|
+
expiresAt: expiresAtFromExpiresIn(payload.expires_in),
|
|
97
104
|
};
|
|
98
105
|
},
|
|
99
106
|
validateToken: options.validate,
|
|
107
|
+
async refreshToken(input) {
|
|
108
|
+
const oauth = await loadOauth4webapi();
|
|
109
|
+
// Mirror `exchangeCode`: a resolver that reads `flags` sees the
|
|
110
|
+
// same view during silent refresh as it did at authorize time.
|
|
111
|
+
const flags = input.handshake.flags ?? {};
|
|
112
|
+
const [tokenUrl, clientId] = await Promise.all([
|
|
113
|
+
resolve(options.tokenUrl, input.handshake, flags),
|
|
114
|
+
resolve(options.clientId, input.handshake, flags),
|
|
115
|
+
]);
|
|
116
|
+
const as = { issuer: tokenUrl, token_endpoint: tokenUrl };
|
|
117
|
+
const client = { client_id: clientId, token_endpoint_auth_method: 'none' };
|
|
118
|
+
// Bound the network call so a hung token endpoint can't block the
|
|
119
|
+
// CLI indefinitely (and, for refresh consumers, can't hold the
|
|
120
|
+
// refresh lock forever). Route through the consumer's injected
|
|
121
|
+
// fetch when present, so a custom transport (proxy dispatcher,
|
|
122
|
+
// decompression) applies to the refresh grant too — oauth4webapi
|
|
123
|
+
// otherwise captures the global `fetch`.
|
|
124
|
+
const requestOptions = {
|
|
125
|
+
signal: AbortSignal.timeout(REFRESH_TIMEOUT_MS),
|
|
126
|
+
...(options.fetchImpl ? { [oauth.customFetch]: options.fetchImpl } : {}),
|
|
127
|
+
};
|
|
128
|
+
try {
|
|
129
|
+
const response = await oauth.refreshTokenGrantRequest(as, client, oauth.None(), input.refreshToken, requestOptions);
|
|
130
|
+
const result = await oauth.processRefreshTokenResponse(as, client, response);
|
|
131
|
+
return {
|
|
132
|
+
accessToken: result.access_token,
|
|
133
|
+
refreshToken: result.refresh_token,
|
|
134
|
+
expiresAt: expiresAtFromExpiresIn(result.expires_in),
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
catch (error) {
|
|
138
|
+
// A ResponseBodyError carries the server's OAuth error JSON.
|
|
139
|
+
// `invalid_grant` (any status — some proxies remap 400 → 401)
|
|
140
|
+
// means the refresh token itself was rejected; re-login is the
|
|
141
|
+
// only recovery. Every other code is transient from cli-core's
|
|
142
|
+
// POV — but surface the actual `error`/`error_description` so a
|
|
143
|
+
// misconfigured server (e.g. `invalid_request: Missing
|
|
144
|
+
// client_secret`) is diagnosable rather than hidden behind
|
|
145
|
+
// oauth4webapi's generic "server responded with an error".
|
|
146
|
+
if (error instanceof oauth.ResponseBodyError) {
|
|
147
|
+
const detail = error.error_description
|
|
148
|
+
? `${error.error} (${error.error_description})`
|
|
149
|
+
: error.error;
|
|
150
|
+
if (error.error === 'invalid_grant') {
|
|
151
|
+
throw new CliError('AUTH_REFRESH_EXPIRED', `Refresh token rejected: ${detail}`, {
|
|
152
|
+
hints: ['Re-run the login command to reauthorize.'],
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
throw new CliError('AUTH_REFRESH_TRANSIENT', `Refresh request failed: ${detail}`, {
|
|
156
|
+
hints: ['Try again.'],
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
// Network failure, non-JSON body, WWWAuthenticateChallengeError, …
|
|
160
|
+
throw new CliError('AUTH_REFRESH_TRANSIENT', `Refresh request failed: ${getErrorMessage(error)}`, { hints: ['Try again.'] });
|
|
161
|
+
}
|
|
162
|
+
},
|
|
100
163
|
};
|
|
101
164
|
}
|
|
102
|
-
function resolve(resolver, handshake, flags) {
|
|
165
|
+
async function resolve(resolver, handshake, flags) {
|
|
103
166
|
return typeof resolver === 'function' ? resolver({ handshake, flags }) : resolver;
|
|
104
167
|
}
|
|
168
|
+
// Optional peer dep — only refresh consumers install it. The dynamic import
|
|
169
|
+
// (and a missing-peer failure) is memoised so it isn't repeated on every
|
|
170
|
+
// refresh, which sits on the authenticated-call path.
|
|
171
|
+
let oauthModulePromise;
|
|
172
|
+
async function loadOauth4webapi() {
|
|
173
|
+
oauthModulePromise ??= import('oauth4webapi');
|
|
174
|
+
try {
|
|
175
|
+
return await oauthModulePromise;
|
|
176
|
+
}
|
|
177
|
+
catch (error) {
|
|
178
|
+
const code = error?.code;
|
|
179
|
+
if (code === 'ERR_MODULE_NOT_FOUND' || code === 'MODULE_NOT_FOUND') {
|
|
180
|
+
throw new CliError('AUTH_REFRESH_UNAVAILABLE', 'oauth4webapi is required for refresh-token support.', { hints: ['Run `npm install oauth4webapi` in your CLI.'] });
|
|
181
|
+
}
|
|
182
|
+
// Installed but failed to initialise — surface the real cause rather
|
|
183
|
+
// than a misleading "install it" hint.
|
|
184
|
+
throw new CliError('AUTH_REFRESH_UNAVAILABLE', `Failed to load oauth4webapi: ${getErrorMessage(error)}`);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
105
187
|
async function safeReadText(response) {
|
|
106
188
|
try {
|
|
107
189
|
const text = (await response.text()).trim();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pkce.js","sourceRoot":"","sources":["../../../src/auth/providers/pkce.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"pkce.js","sourceRoot":"","sources":["../../../src/auth/providers/pkce.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { AccountRef, AuthAccount, AuthProvider, TokenBundle, TokenStore } from './types.js';
|
|
2
|
+
export type RefreshAccessTokenOptions<TAccount extends AuthAccount> = {
|
|
3
|
+
store: TokenStore<TAccount>;
|
|
4
|
+
provider: AuthProvider<TAccount>;
|
|
5
|
+
ref?: AccountRef;
|
|
6
|
+
/**
|
|
7
|
+
* Refresh proactively when the access token's expiry is within this many
|
|
8
|
+
* ms of now. Default 60_000 (60s). Ignored when `force: true`.
|
|
9
|
+
*/
|
|
10
|
+
skewMs?: number;
|
|
11
|
+
/**
|
|
12
|
+
* Reactive path: caller hit a 401 and wants a rotation regardless of
|
|
13
|
+
* expiry. Skips the skew check; still honours all the "unavailable"
|
|
14
|
+
* gates (no refresh token, no provider hook, no `activeBundle`/`setBundle`).
|
|
15
|
+
*/
|
|
16
|
+
force?: boolean;
|
|
17
|
+
/**
|
|
18
|
+
* Path to the O_EXCL concurrency lock file. Required — cli-core does not
|
|
19
|
+
* interpret `~` or know where the consumer's config lives. Recommended:
|
|
20
|
+
* `${getConfigPath(serviceName)}.refresh.lock`.
|
|
21
|
+
*/
|
|
22
|
+
lockPath: string;
|
|
23
|
+
/**
|
|
24
|
+
* Forwarded to `provider.refreshToken` as its `handshake`, so consumers
|
|
25
|
+
* can pass runtime context the provider's resolvers need (e.g. a
|
|
26
|
+
* `--env`-derived base URL / client id). Defaults to `{}`.
|
|
27
|
+
*/
|
|
28
|
+
handshake?: Record<string, unknown>;
|
|
29
|
+
};
|
|
30
|
+
export type RefreshAccessTokenResult<TAccount extends AuthAccount> = {
|
|
31
|
+
rotated: boolean;
|
|
32
|
+
bundle: TokenBundle;
|
|
33
|
+
account: TAccount;
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* Rotate the access token using the stored refresh token. Proactive when
|
|
37
|
+
* `accessTokenExpiresAt` is within `skewMs` of now; reactive when `force:
|
|
38
|
+
* true`. Uses an `O_EXCL` file lock at `lockPath` so concurrent CLI
|
|
39
|
+
* invocations don't issue parallel refresh-token grants — one POSTs, the
|
|
40
|
+
* others re-read the rotated bundle from the store.
|
|
41
|
+
*
|
|
42
|
+
* Throws `AUTH_REFRESH_UNAVAILABLE` when refresh isn't possible in the
|
|
43
|
+
* current setup: store doesn't implement `activeBundle` + `setBundle`,
|
|
44
|
+
* provider doesn't implement `refreshToken`, no credential, or no refresh
|
|
45
|
+
* token. Server-side rejections surface as `AUTH_REFRESH_EXPIRED` (re-login
|
|
46
|
+
* required) or `AUTH_REFRESH_TRANSIENT` (retryable).
|
|
47
|
+
*/
|
|
48
|
+
export declare function refreshAccessToken<TAccount extends AuthAccount>(options: RefreshAccessTokenOptions<TAccount>): Promise<RefreshAccessTokenResult<TAccount>>;
|
|
49
|
+
//# sourceMappingURL=refresh.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"refresh.d.ts","sourceRoot":"","sources":["../../src/auth/refresh.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,YAAY,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAEhG,MAAM,MAAM,yBAAyB,CAAC,QAAQ,SAAS,WAAW,IAAI;IAClE,KAAK,EAAE,UAAU,CAAC,QAAQ,CAAC,CAAA;IAC3B,QAAQ,EAAE,YAAY,CAAC,QAAQ,CAAC,CAAA;IAChC,GAAG,CAAC,EAAE,UAAU,CAAA;IAChB;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAA;IACf;;;;OAIG;IACH,KAAK,CAAC,EAAE,OAAO,CAAA;IACf;;;;OAIG;IACH,QAAQ,EAAE,MAAM,CAAA;IAChB;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CACtC,CAAA;AAED,MAAM,MAAM,wBAAwB,CAAC,QAAQ,SAAS,WAAW,IAAI;IACjE,OAAO,EAAE,OAAO,CAAA;IAChB,MAAM,EAAE,WAAW,CAAA;IACnB,OAAO,EAAE,QAAQ,CAAA;CACpB,CAAA;AAUD;;;;;;;;;;;;GAYG;AACH,wBAAsB,kBAAkB,CAAC,QAAQ,SAAS,WAAW,EACjE,OAAO,EAAE,yBAAyB,CAAC,QAAQ,CAAC,GAC7C,OAAO,CAAC,wBAAwB,CAAC,QAAQ,CAAC,CAAC,CA4F7C"}
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { open, readFile, stat, unlink } from 'node:fs/promises';
|
|
3
|
+
import { setTimeout as sleep } from 'node:timers/promises';
|
|
4
|
+
import { CliError, getErrorMessage } from '../errors.js';
|
|
5
|
+
import { bundleFromExchange, persistBundle } from './persist.js';
|
|
6
|
+
const DEFAULT_SKEW_MS = 60_000;
|
|
7
|
+
const LOCK_WAIT_TIMEOUT_MS = 2_000;
|
|
8
|
+
const LOCK_POLL_INTERVAL_MS = 50;
|
|
9
|
+
// A lock older than this was almost certainly left by a crashed holder — the
|
|
10
|
+
// refresh POST is bounded by a provider-side timeout well under this — so it's
|
|
11
|
+
// safe to steal rather than block every future refresh forever.
|
|
12
|
+
const LOCK_STALE_MS = 15_000;
|
|
13
|
+
/**
|
|
14
|
+
* Rotate the access token using the stored refresh token. Proactive when
|
|
15
|
+
* `accessTokenExpiresAt` is within `skewMs` of now; reactive when `force:
|
|
16
|
+
* true`. Uses an `O_EXCL` file lock at `lockPath` so concurrent CLI
|
|
17
|
+
* invocations don't issue parallel refresh-token grants — one POSTs, the
|
|
18
|
+
* others re-read the rotated bundle from the store.
|
|
19
|
+
*
|
|
20
|
+
* Throws `AUTH_REFRESH_UNAVAILABLE` when refresh isn't possible in the
|
|
21
|
+
* current setup: store doesn't implement `activeBundle` + `setBundle`,
|
|
22
|
+
* provider doesn't implement `refreshToken`, no credential, or no refresh
|
|
23
|
+
* token. Server-side rejections surface as `AUTH_REFRESH_EXPIRED` (re-login
|
|
24
|
+
* required) or `AUTH_REFRESH_TRANSIENT` (retryable).
|
|
25
|
+
*/
|
|
26
|
+
export async function refreshAccessToken(options) {
|
|
27
|
+
const { store, provider, ref, force, lockPath } = options;
|
|
28
|
+
const skewMs = options.skewMs ?? DEFAULT_SKEW_MS;
|
|
29
|
+
const handshake = options.handshake ?? {};
|
|
30
|
+
// Refresh must both read the full bundle and persist the rotated one. A
|
|
31
|
+
// store missing either capability can't participate — fail loudly rather
|
|
32
|
+
// than silently dropping the rotated refresh token via a `set()` fallback.
|
|
33
|
+
if (!store.activeBundle || !store.setBundle) {
|
|
34
|
+
throw new CliError('AUTH_REFRESH_UNAVAILABLE', 'TokenStore must implement activeBundle + setBundle for refresh.', { hints: ['Re-run the login command to reauthorize.'] });
|
|
35
|
+
}
|
|
36
|
+
if (!provider.refreshToken) {
|
|
37
|
+
throw new CliError('AUTH_REFRESH_UNAVAILABLE', 'Auth provider does not implement refreshToken.');
|
|
38
|
+
}
|
|
39
|
+
const activeBundle = store.activeBundle.bind(store);
|
|
40
|
+
const refreshGrant = provider.refreshToken.bind(provider);
|
|
41
|
+
const snapshot = await activeBundle(ref);
|
|
42
|
+
if (!snapshot) {
|
|
43
|
+
throw new CliError('AUTH_REFRESH_UNAVAILABLE', 'No stored credential to refresh.', {
|
|
44
|
+
hints: ['Re-run the login command to reauthorize.'],
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
if (!force && !needsRefresh(snapshot.bundle, skewMs)) {
|
|
48
|
+
return { rotated: false, bundle: snapshot.bundle, account: snapshot.account };
|
|
49
|
+
}
|
|
50
|
+
if (!snapshot.bundle.refreshToken) {
|
|
51
|
+
throw new CliError('AUTH_REFRESH_UNAVAILABLE', 'Stored credential has no refresh token.', {
|
|
52
|
+
hints: ['Re-run the login command to reauthorize.'],
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
const lockToken = await acquireLock(lockPath);
|
|
56
|
+
if (!lockToken) {
|
|
57
|
+
// Holder didn't release in time. It may have rotated then crashed
|
|
58
|
+
// before unlinking — re-read once and adopt the rotated bundle if so.
|
|
59
|
+
const fresh = await activeBundle(ref);
|
|
60
|
+
if (fresh && hasRotated(snapshot.bundle, fresh.bundle)) {
|
|
61
|
+
return { rotated: true, bundle: fresh.bundle, account: fresh.account };
|
|
62
|
+
}
|
|
63
|
+
throw new CliError('AUTH_REFRESH_TRANSIENT', 'Timed out waiting for a concurrent refresh to complete.', { hints: ['Try again.'] });
|
|
64
|
+
}
|
|
65
|
+
try {
|
|
66
|
+
// Re-read under the lock (covers a clean acquire too): a concurrent
|
|
67
|
+
// holder may have rotated between our snapshot read and acquiring the
|
|
68
|
+
// lock, so adopt their bundle rather than POST a now-stale refresh
|
|
69
|
+
// token. A throw here releases the lock via `finally`.
|
|
70
|
+
const current = await activeBundle(ref);
|
|
71
|
+
if (!current) {
|
|
72
|
+
// A concurrent `logout`/`clear` removed the credential after our
|
|
73
|
+
// first read — do not POST + persist it back into existence.
|
|
74
|
+
throw new CliError('AUTH_REFRESH_UNAVAILABLE', 'Credential was removed during refresh.', {
|
|
75
|
+
hints: ['Re-run the login command to reauthorize.'],
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
if (hasRotated(snapshot.bundle, current.bundle)) {
|
|
79
|
+
return { rotated: true, bundle: current.bundle, account: current.account };
|
|
80
|
+
}
|
|
81
|
+
const refreshToken = current.bundle.refreshToken;
|
|
82
|
+
if (!refreshToken) {
|
|
83
|
+
throw new CliError('AUTH_REFRESH_UNAVAILABLE', 'Stored credential has no refresh token.', { hints: ['Re-run the login command to reauthorize.'] });
|
|
84
|
+
}
|
|
85
|
+
const exchange = await refreshGrant({ refreshToken, handshake });
|
|
86
|
+
const account = exchange.account ?? current.account;
|
|
87
|
+
const bundle = bundleFromExchange(exchange, current.bundle);
|
|
88
|
+
await persistBundle({ store, account, bundle });
|
|
89
|
+
return { rotated: true, bundle, account };
|
|
90
|
+
}
|
|
91
|
+
finally {
|
|
92
|
+
await releaseLock(lockPath, lockToken);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
function needsRefresh(bundle, skewMs) {
|
|
96
|
+
// No expiry tracked → can't proactively refresh; defer to reactive 401.
|
|
97
|
+
if (bundle.accessTokenExpiresAt === undefined)
|
|
98
|
+
return false;
|
|
99
|
+
return bundle.accessTokenExpiresAt - Date.now() < skewMs;
|
|
100
|
+
}
|
|
101
|
+
function hasRotated(before, after) {
|
|
102
|
+
return (after.accessToken !== before.accessToken ||
|
|
103
|
+
after.accessTokenExpiresAt !== before.accessTokenExpiresAt ||
|
|
104
|
+
after.refreshToken !== before.refreshToken ||
|
|
105
|
+
after.refreshTokenExpiresAt !== before.refreshTokenExpiresAt);
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Acquire the lock, returning a unique ownership token (or `null` on
|
|
109
|
+
* contention timeout). The token is written into the lock file so
|
|
110
|
+
* `releaseLock` only unlinks a lock it still owns — a holder whose stale
|
|
111
|
+
* lock was stolen mid-flight won't delete the new holder's lock.
|
|
112
|
+
*/
|
|
113
|
+
async function acquireLock(lockPath) {
|
|
114
|
+
const token = randomUUID();
|
|
115
|
+
if (await tryAcquire(lockPath, token))
|
|
116
|
+
return token;
|
|
117
|
+
const deadline = Date.now() + LOCK_WAIT_TIMEOUT_MS;
|
|
118
|
+
while (Date.now() < deadline) {
|
|
119
|
+
await sleep(LOCK_POLL_INTERVAL_MS);
|
|
120
|
+
if (await tryAcquire(lockPath, token))
|
|
121
|
+
return token;
|
|
122
|
+
}
|
|
123
|
+
return null;
|
|
124
|
+
}
|
|
125
|
+
// Write the lock with O_EXCL. On EEXIST, steal it if it's stale (older than
|
|
126
|
+
// LOCK_STALE_MS — assumes the provider bounds its HTTP, which the built-in
|
|
127
|
+
// PKCE provider does); otherwise report contention.
|
|
128
|
+
async function tryAcquire(lockPath, token) {
|
|
129
|
+
if (await tryWriteLock(lockPath, token))
|
|
130
|
+
return true;
|
|
131
|
+
if (await lockIsStale(lockPath)) {
|
|
132
|
+
await forceUnlink(lockPath);
|
|
133
|
+
return tryWriteLock(lockPath, token);
|
|
134
|
+
}
|
|
135
|
+
return false;
|
|
136
|
+
}
|
|
137
|
+
async function lockIsStale(lockPath) {
|
|
138
|
+
try {
|
|
139
|
+
const { mtimeMs } = await stat(lockPath);
|
|
140
|
+
return Date.now() - mtimeMs > LOCK_STALE_MS;
|
|
141
|
+
}
|
|
142
|
+
catch {
|
|
143
|
+
return false;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
async function tryWriteLock(lockPath, token) {
|
|
147
|
+
let handle;
|
|
148
|
+
try {
|
|
149
|
+
handle = await open(lockPath, 'wx');
|
|
150
|
+
}
|
|
151
|
+
catch (error) {
|
|
152
|
+
const code = error.code;
|
|
153
|
+
if (code === 'EEXIST')
|
|
154
|
+
return false;
|
|
155
|
+
throw new CliError('AUTH_REFRESH_TRANSIENT', `Failed to acquire refresh lock: ${getErrorMessage(error)}`, { hints: ['Try again.'] });
|
|
156
|
+
}
|
|
157
|
+
try {
|
|
158
|
+
await handle.writeFile(token);
|
|
159
|
+
}
|
|
160
|
+
finally {
|
|
161
|
+
await handle.close();
|
|
162
|
+
}
|
|
163
|
+
return true;
|
|
164
|
+
}
|
|
165
|
+
async function releaseLock(lockPath, token) {
|
|
166
|
+
try {
|
|
167
|
+
const owner = (await readFile(lockPath, 'utf8')).trim();
|
|
168
|
+
if (owner === token)
|
|
169
|
+
await unlink(lockPath);
|
|
170
|
+
}
|
|
171
|
+
catch {
|
|
172
|
+
// best-effort: a missing/unreadable lock (manual cleanup, crash, a
|
|
173
|
+
// steal by another holder) must not surface as a refresh failure.
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
async function forceUnlink(lockPath) {
|
|
177
|
+
try {
|
|
178
|
+
await unlink(lockPath);
|
|
179
|
+
}
|
|
180
|
+
catch {
|
|
181
|
+
// already gone
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
//# sourceMappingURL=refresh.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"refresh.js","sourceRoot":"","sources":["../../src/auth/refresh.ts"],"names":[],"mappings":"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"}
|
package/dist/auth/status.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Command } from 'commander';
|
|
2
2
|
import type { ViewOptions } from '../options.js';
|
|
3
|
-
import type { AuthAccount, TokenStore } from './types.js';
|
|
3
|
+
import type { AuthAccount, TokenBundle, TokenStore } from './types.js';
|
|
4
4
|
export type AttachStatusContext<TAccount extends AuthAccount> = {
|
|
5
5
|
account: TAccount;
|
|
6
6
|
/** `--json` / `--ndjson` flag values, both present (defaulted to `false`). */
|
|
@@ -20,6 +20,12 @@ export type AttachStatusCommandOptions<TAccount extends AuthAccount = AuthAccoun
|
|
|
20
20
|
fetchLive?(ctx: {
|
|
21
21
|
account: TAccount;
|
|
22
22
|
token: string;
|
|
23
|
+
/**
|
|
24
|
+
* Full bundle when the store implements `activeBundle` — lets a
|
|
25
|
+
* consumer render expiry without a second read. Absent when the
|
|
26
|
+
* store only exposes `active()` (no refresh-side metadata available).
|
|
27
|
+
*/
|
|
28
|
+
bundle?: TokenBundle;
|
|
23
29
|
/** `--json` / `--ndjson` flag values, both present (defaulted to `false`). */
|
|
24
30
|
view: Required<ViewOptions>;
|
|
25
31
|
flags: Record<string, unknown>;
|
|
@@ -49,9 +55,11 @@ export type AttachStatusCommandOptions<TAccount extends AuthAccount = AuthAccoun
|
|
|
49
55
|
}): void | Promise<void>;
|
|
50
56
|
};
|
|
51
57
|
/**
|
|
52
|
-
* Attach `status` as a subcommand of `parent`. Reads
|
|
53
|
-
*
|
|
54
|
-
*
|
|
58
|
+
* Attach `status` as a subcommand of `parent`. Reads the active credential
|
|
59
|
+
* (preferring `store.activeBundle` when `fetchLive` is set, so the token and
|
|
60
|
+
* bundle come from one read), optionally confirms via `fetchLive`, then
|
|
61
|
+
* dispatches to `renderText` (human) or `renderJson` (machine). Returns the
|
|
62
|
+
* new `Command` so the consumer can chain.
|
|
55
63
|
*/
|
|
56
64
|
export declare function attachStatusCommand<TAccount extends AuthAccount = AuthAccount>(parent: Command, options: AttachStatusCommandOptions<TAccount>): Command;
|
|
57
65
|
//# sourceMappingURL=status.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../src/auth/status.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAGxC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAChD,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;
|
|
1
|
+
{"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../src/auth/status.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAGxC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAChD,OAAO,KAAK,EAAc,WAAW,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAqDlF,MAAM,MAAM,mBAAmB,CAAC,QAAQ,SAAS,WAAW,IAAI;IAC5D,OAAO,EAAE,QAAQ,CAAA;IACjB,8EAA8E;IAC9E,IAAI,EAAE,QAAQ,CAAC,WAAW,CAAC,CAAA;IAC3B,oHAAoH;IACpH,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CACjC,CAAA;AAED,MAAM,MAAM,0BAA0B,CAAC,QAAQ,SAAS,WAAW,GAAG,WAAW,IAAI;IACjF,KAAK,EAAE,UAAU,CAAC,QAAQ,CAAC,CAAA;IAC3B,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB;;;;;OAKG;IACH,SAAS,CAAC,CAAC,GAAG,EAAE;QACZ,OAAO,EAAE,QAAQ,CAAA;QACjB,KAAK,EAAE,MAAM,CAAA;QACb;;;;WAIG;QACH,MAAM,CAAC,EAAE,WAAW,CAAA;QACpB,8EAA8E;QAC9E,IAAI,EAAE,QAAQ,CAAC,WAAW,CAAC,CAAA;QAC3B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KACjC,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAA;IACrB;;;OAGG;IACH,UAAU,CAAC,GAAG,EAAE,mBAAmB,CAAC,QAAQ,CAAC,GAAG,MAAM,GAAG,SAAS,MAAM,EAAE,CAAA;IAC1E;;;;OAIG;IACH,UAAU,CAAC,CAAC,GAAG,EAAE;QAAE,OAAO,EAAE,QAAQ,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,GAAG,OAAO,CAAA;IAChF;;;OAGG;IACH,kBAAkB,CAAC,CAAC,GAAG,EAAE;QACrB,8EAA8E;QAC9E,IAAI,EAAE,QAAQ,CAAC,WAAW,CAAC,CAAA;QAC3B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KACjC,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;CAC3B,CAAA;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,SAAS,WAAW,GAAG,WAAW,EAC1E,MAAM,EAAE,OAAO,EACf,OAAO,EAAE,0BAA0B,CAAC,QAAQ,CAAC,GAC9C,OAAO,CA4CT"}
|
package/dist/auth/status.js
CHANGED
|
@@ -1,10 +1,49 @@
|
|
|
1
1
|
import { CliError } from '../errors.js';
|
|
2
2
|
import { formatJson, formatNdjson } from '../json.js';
|
|
3
|
-
import { attachUserFlag, extractUserRef, requireSnapshotForRef } from './user-flag.js';
|
|
3
|
+
import { accountNotFoundError, attachUserFlag, extractUserRef, requireSnapshotForRef, } from './user-flag.js';
|
|
4
4
|
/**
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
5
|
+
* Resolve the auth snapshot for `status`. When the consumer supplies
|
|
6
|
+
* `fetchLive` (and the store implements `activeBundle`), read the bundle once
|
|
7
|
+
* and derive both the access token and the bundle from it — avoiding a second
|
|
8
|
+
* keyring round-trip on the hot path. Otherwise fall back to the narrow
|
|
9
|
+
* `active()` read. A bundle-read fault (e.g. a refresh-slot error) also falls
|
|
10
|
+
* back to `active()` so it can't break status, which is the user's first port
|
|
11
|
+
* of call when something is wrong. An explicit-ref miss throws
|
|
12
|
+
* `ACCOUNT_NOT_FOUND`, matching `requireSnapshotForRef`.
|
|
13
|
+
*/
|
|
14
|
+
async function resolveStatusSnapshot(store, ref, wantsBundle) {
|
|
15
|
+
if (wantsBundle && store.activeBundle) {
|
|
16
|
+
try {
|
|
17
|
+
const snap = await store.activeBundle(ref);
|
|
18
|
+
if (snap) {
|
|
19
|
+
return {
|
|
20
|
+
token: snap.bundle.accessToken,
|
|
21
|
+
account: snap.account,
|
|
22
|
+
bundle: snap.bundle,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
if (ref !== undefined)
|
|
26
|
+
throw accountNotFoundError(ref);
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
catch (error) {
|
|
30
|
+
// Only a typed read failure falls through to the access-only
|
|
31
|
+
// `active()` read (e.g. a refresh-slot fault that `active()`
|
|
32
|
+
// doesn't hit). Anything else — `ACCOUNT_NOT_FOUND`, or an
|
|
33
|
+
// unexpected store bug — propagates rather than being masked.
|
|
34
|
+
if (!(error instanceof CliError) || error.code !== 'AUTH_STORE_READ_FAILED')
|
|
35
|
+
throw error;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
const snapshot = await requireSnapshotForRef(store, ref);
|
|
39
|
+
return snapshot ? { token: snapshot.token, account: snapshot.account } : null;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Attach `status` as a subcommand of `parent`. Reads the active credential
|
|
43
|
+
* (preferring `store.activeBundle` when `fetchLive` is set, so the token and
|
|
44
|
+
* bundle come from one read), optionally confirms via `fetchLive`, then
|
|
45
|
+
* dispatches to `renderText` (human) or `renderJson` (machine). Returns the
|
|
46
|
+
* new `Command` so the consumer can chain.
|
|
8
47
|
*/
|
|
9
48
|
export function attachStatusCommand(parent, options) {
|
|
10
49
|
const command = parent
|
|
@@ -19,7 +58,7 @@ export function attachStatusCommand(parent, options) {
|
|
|
19
58
|
ndjson: Boolean(ndjson),
|
|
20
59
|
};
|
|
21
60
|
const ref = extractUserRef(cmd);
|
|
22
|
-
const snapshot = await
|
|
61
|
+
const snapshot = await resolveStatusSnapshot(options.store, ref, Boolean(options.fetchLive));
|
|
23
62
|
if (!snapshot) {
|
|
24
63
|
if (options.onNotAuthenticated) {
|
|
25
64
|
await options.onNotAuthenticated({ view, flags });
|
|
@@ -31,6 +70,7 @@ export function attachStatusCommand(parent, options) {
|
|
|
31
70
|
? await options.fetchLive({
|
|
32
71
|
account: snapshot.account,
|
|
33
72
|
token: snapshot.token,
|
|
73
|
+
...(snapshot.bundle ? { bundle: snapshot.bundle } : {}),
|
|
34
74
|
view,
|
|
35
75
|
flags,
|
|
36
76
|
})
|
package/dist/auth/status.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"status.js","sourceRoot":"","sources":["../../src/auth/status.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAA;AACvC,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAGrD,OAAO,
|
|
1
|
+
{"version":3,"file":"status.js","sourceRoot":"","sources":["../../src/auth/status.ts"],"names":[],"mappings":"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"}
|
package/dist/auth/types.d.ts
CHANGED
|
@@ -79,6 +79,11 @@ export type TokenBundle = {
|
|
|
79
79
|
accessTokenExpiresAt?: number;
|
|
80
80
|
refreshTokenExpiresAt?: number;
|
|
81
81
|
};
|
|
82
|
+
/** Read-side snapshot returned by `activeBundle`. Mirrors `setBundle`'s write side. */
|
|
83
|
+
export type ActiveBundleSnapshot<TAccount extends AuthAccount = AuthAccount> = {
|
|
84
|
+
account: TAccount;
|
|
85
|
+
bundle: TokenBundle;
|
|
86
|
+
};
|
|
82
87
|
/** Opaque account selector. Stores own the matching rule (id, email, label, …). */
|
|
83
88
|
export type AccountRef = string;
|
|
84
89
|
/**
|
|
@@ -112,6 +117,18 @@ export type TokenStore<TAccount extends AuthAccount = AuthAccount> = {
|
|
|
112
117
|
setBundle?(account: TAccount, bundle: TokenBundle, options?: {
|
|
113
118
|
promoteDefault?: boolean;
|
|
114
119
|
}): Promise<void>;
|
|
120
|
+
/**
|
|
121
|
+
* Full-bundle read for refresh-capable consumers. Returns the matching
|
|
122
|
+
* account + bundle, or `null` on miss. Optional on the contract — the
|
|
123
|
+
* silent-refresh helper throws `AUTH_REFRESH_UNAVAILABLE` when a custom
|
|
124
|
+
* store doesn't implement it. `KeyringTokenStore` overrides this as
|
|
125
|
+
* required so cli-core helpers can call it without a non-null assertion.
|
|
126
|
+
*
|
|
127
|
+
* Stores MAY throw `CliError('AUTH_STORE_READ_FAILED', …)` on the same
|
|
128
|
+
* conditions as `active()` (e.g. keyring offline while a matching
|
|
129
|
+
* record exists).
|
|
130
|
+
*/
|
|
131
|
+
activeBundle?(ref?: AccountRef): Promise<ActiveBundleSnapshot<TAccount> | null>;
|
|
115
132
|
/** Remove a stored credential. No-op when `ref` doesn't match. */
|
|
116
133
|
clear(ref?: AccountRef): Promise<void>;
|
|
117
134
|
/** Every stored account with a default marker. */
|
package/dist/auth/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/auth/types.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/auth/types.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@doist/cli-core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.19.0",
|
|
4
4
|
"description": "Shared core utilities for Doist CLI projects",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -66,15 +66,16 @@
|
|
|
66
66
|
"@semantic-release/changelog": "6.0.3",
|
|
67
67
|
"@semantic-release/exec": "7.1.0",
|
|
68
68
|
"@semantic-release/git": "10.0.1",
|
|
69
|
-
"@types/node": "25.
|
|
69
|
+
"@types/node": "25.8.0",
|
|
70
70
|
"commander": "14.0.3",
|
|
71
71
|
"conventional-changelog-conventionalcommits": "9.3.1",
|
|
72
72
|
"lefthook": "2.1.6",
|
|
73
73
|
"marked": "18.0.3",
|
|
74
74
|
"marked-terminal-renderer": "2.2.0",
|
|
75
|
+
"oauth4webapi": "3.8.6",
|
|
75
76
|
"open": "11.0.0",
|
|
76
|
-
"oxfmt": "0.
|
|
77
|
-
"oxlint": "1.
|
|
77
|
+
"oxfmt": "0.50.0",
|
|
78
|
+
"oxlint": "1.65.0",
|
|
78
79
|
"semantic-release": "25.0.3",
|
|
79
80
|
"typescript": "6.0.3",
|
|
80
81
|
"vitest": "4.1.6"
|
|
@@ -90,6 +91,7 @@
|
|
|
90
91
|
"commander": ">=14",
|
|
91
92
|
"marked": ">=18",
|
|
92
93
|
"marked-terminal-renderer": ">=2",
|
|
94
|
+
"oauth4webapi": ">=3",
|
|
93
95
|
"open": ">=10",
|
|
94
96
|
"vitest": ">=4.1"
|
|
95
97
|
},
|
|
@@ -103,6 +105,9 @@
|
|
|
103
105
|
"marked-terminal-renderer": {
|
|
104
106
|
"optional": true
|
|
105
107
|
},
|
|
108
|
+
"oauth4webapi": {
|
|
109
|
+
"optional": true
|
|
110
|
+
},
|
|
106
111
|
"open": {
|
|
107
112
|
"optional": true
|
|
108
113
|
},
|