@doist/cli-core 0.18.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 +6 -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 +25 -0
- package/dist/auth/keyring/internal.d.ts.map +1 -1
- package/dist/auth/keyring/internal.js +24 -7
- package/dist/auth/keyring/internal.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 +59 -20
- 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 +1 @@
|
|
|
1
|
-
{"version":3,"file":"token-store.js","sourceRoot":"","sources":["../../../src/auth/keyring/token-store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAA;
|
|
1
|
+
{"version":3,"file":"token-store.js","sourceRoot":"","sources":["../../../src/auth/keyring/token-store.ts"],"names":[],"mappings":"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"}
|
package/dist/auth/persist.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AuthAccount, TokenBundle, TokenStore } from './types.js';
|
|
1
|
+
import type { AuthAccount, ExchangeResult, TokenBundle, TokenStore } from './types.js';
|
|
2
2
|
export type PersistBundleOptions<TAccount extends AuthAccount> = {
|
|
3
3
|
store: TokenStore<TAccount>;
|
|
4
4
|
account: TAccount;
|
|
@@ -19,5 +19,13 @@ export type PersistBundleOptions<TAccount extends AuthAccount> = {
|
|
|
19
19
|
* silent-refresh-safe selection (no re-pinning on background rotation)
|
|
20
20
|
* MUST implement `setBundle`.
|
|
21
21
|
*/
|
|
22
|
+
/**
|
|
23
|
+
* Build a `TokenBundle` from an `ExchangeResult`. `prev` carries the previous
|
|
24
|
+
* refresh token + its expiry forward when the server didn't reissue one (most
|
|
25
|
+
* don't on a refresh-grant). When the server DID return a new refresh token,
|
|
26
|
+
* its expiry is whatever the server gave (or unknown) — never the old token's,
|
|
27
|
+
* which would attach stale expiry metadata to a different credential.
|
|
28
|
+
*/
|
|
29
|
+
export declare function bundleFromExchange<TAccount extends AuthAccount>(exchange: ExchangeResult<TAccount>, prev?: TokenBundle): TokenBundle;
|
|
22
30
|
export declare function persistBundle<TAccount extends AuthAccount>(options: PersistBundleOptions<TAccount>): Promise<void>;
|
|
23
31
|
//# sourceMappingURL=persist.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"persist.d.ts","sourceRoot":"","sources":["../../src/auth/persist.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;
|
|
1
|
+
{"version":3,"file":"persist.d.ts","sourceRoot":"","sources":["../../src/auth/persist.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,cAAc,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAEtF,MAAM,MAAM,oBAAoB,CAAC,QAAQ,SAAS,WAAW,IAAI;IAC7D,KAAK,EAAE,UAAU,CAAC,QAAQ,CAAC,CAAA;IAC3B,OAAO,EAAE,QAAQ,CAAA;IACjB,MAAM,EAAE,WAAW,CAAA;IACnB,yEAAyE;IACzE,cAAc,CAAC,EAAE,OAAO,CAAA;CAC3B,CAAA;AAED;;;;;;;;;;;;GAYG;AACH;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,SAAS,WAAW,EAC3D,QAAQ,EAAE,cAAc,CAAC,QAAQ,CAAC,EAClC,IAAI,CAAC,EAAE,WAAW,GACnB,WAAW,CAYb;AAED,wBAAsB,aAAa,CAAC,QAAQ,SAAS,WAAW,EAC5D,OAAO,EAAE,oBAAoB,CAAC,QAAQ,CAAC,GACxC,OAAO,CAAC,IAAI,CAAC,CAqBf"}
|
package/dist/auth/persist.js
CHANGED
|
@@ -12,6 +12,26 @@ import { CliError, getErrorMessage } from '../errors.js';
|
|
|
12
12
|
* silent-refresh-safe selection (no re-pinning on background rotation)
|
|
13
13
|
* MUST implement `setBundle`.
|
|
14
14
|
*/
|
|
15
|
+
/**
|
|
16
|
+
* Build a `TokenBundle` from an `ExchangeResult`. `prev` carries the previous
|
|
17
|
+
* refresh token + its expiry forward when the server didn't reissue one (most
|
|
18
|
+
* don't on a refresh-grant). When the server DID return a new refresh token,
|
|
19
|
+
* its expiry is whatever the server gave (or unknown) — never the old token's,
|
|
20
|
+
* which would attach stale expiry metadata to a different credential.
|
|
21
|
+
*/
|
|
22
|
+
export function bundleFromExchange(exchange, prev) {
|
|
23
|
+
const rotatedRefresh = exchange.refreshToken !== undefined;
|
|
24
|
+
const refreshToken = exchange.refreshToken ?? prev?.refreshToken;
|
|
25
|
+
const refreshTokenExpiresAt = rotatedRefresh
|
|
26
|
+
? exchange.refreshTokenExpiresAt
|
|
27
|
+
: (exchange.refreshTokenExpiresAt ?? prev?.refreshTokenExpiresAt);
|
|
28
|
+
return {
|
|
29
|
+
accessToken: exchange.accessToken,
|
|
30
|
+
...(refreshToken !== undefined ? { refreshToken } : {}),
|
|
31
|
+
...(exchange.expiresAt !== undefined ? { accessTokenExpiresAt: exchange.expiresAt } : {}),
|
|
32
|
+
...(refreshTokenExpiresAt !== undefined ? { refreshTokenExpiresAt } : {}),
|
|
33
|
+
};
|
|
34
|
+
}
|
|
15
35
|
export async function persistBundle(options) {
|
|
16
36
|
const { store, account, bundle, promoteDefault } = options;
|
|
17
37
|
try {
|
package/dist/auth/persist.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"persist.js","sourceRoot":"","sources":["../../src/auth/persist.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AAWxD;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAC/B,OAAuC;IAEvC,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,GAAG,OAAO,CAAA;IAC1D,IAAI,CAAC;QACD,IAAI,KAAK,CAAC,SAAS,EAAE,CAAC;YAClB,6DAA6D;YAC7D,4DAA4D;YAC5D,IAAI,cAAc,KAAK,SAAS,EAAE,CAAC;gBAC/B,MAAM,KAAK,CAAC,SAAS,CAAC,OAAO,EAAE,MAAM,CAAC,CAAA;YAC1C,CAAC;iBAAM,CAAC;gBACJ,MAAM,KAAK,CAAC,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,cAAc,EAAE,CAAC,CAAA;YAC9D,CAAC;QACL,CAAC;aAAM,CAAC;YACJ,MAAM,KAAK,CAAC,GAAG,CAAC,OAAO,EAAE,MAAM,CAAC,WAAW,CAAC,CAAA;QAChD,CAAC;IACL,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACb,IAAI,KAAK,YAAY,QAAQ;YAAE,MAAM,KAAK,CAAA;QAC1C,MAAM,IAAI,QAAQ,CACd,yBAAyB,EACzB,4BAA4B,eAAe,CAAC,KAAK,CAAC,EAAE,CACvD,CAAA;IACL,CAAC;AACL,CAAC"}
|
|
1
|
+
{"version":3,"file":"persist.js","sourceRoot":"","sources":["../../src/auth/persist.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AAWxD;;;;;;;;;;;;GAYG;AACH;;;;;;GAMG;AACH,MAAM,UAAU,kBAAkB,CAC9B,QAAkC,EAClC,IAAkB;IAElB,MAAM,cAAc,GAAG,QAAQ,CAAC,YAAY,KAAK,SAAS,CAAA;IAC1D,MAAM,YAAY,GAAG,QAAQ,CAAC,YAAY,IAAI,IAAI,EAAE,YAAY,CAAA;IAChE,MAAM,qBAAqB,GAAG,cAAc;QACxC,CAAC,CAAC,QAAQ,CAAC,qBAAqB;QAChC,CAAC,CAAC,CAAC,QAAQ,CAAC,qBAAqB,IAAI,IAAI,EAAE,qBAAqB,CAAC,CAAA;IACrE,OAAO;QACH,WAAW,EAAE,QAAQ,CAAC,WAAW;QACjC,GAAG,CAAC,YAAY,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACvD,GAAG,CAAC,QAAQ,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,oBAAoB,EAAE,QAAQ,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACzF,GAAG,CAAC,qBAAqB,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,qBAAqB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC5E,CAAA;AACL,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,aAAa,CAC/B,OAAuC;IAEvC,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,GAAG,OAAO,CAAA;IAC1D,IAAI,CAAC;QACD,IAAI,KAAK,CAAC,SAAS,EAAE,CAAC;YAClB,6DAA6D;YAC7D,4DAA4D;YAC5D,IAAI,cAAc,KAAK,SAAS,EAAE,CAAC;gBAC/B,MAAM,KAAK,CAAC,SAAS,CAAC,OAAO,EAAE,MAAM,CAAC,CAAA;YAC1C,CAAC;iBAAM,CAAC;gBACJ,MAAM,KAAK,CAAC,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,cAAc,EAAE,CAAC,CAAA;YAC9D,CAAC;QACL,CAAC;aAAM,CAAC;YACJ,MAAM,KAAK,CAAC,GAAG,CAAC,OAAO,EAAE,MAAM,CAAC,WAAW,CAAC,CAAA;QAChD,CAAC;IACL,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACb,IAAI,KAAK,YAAY,QAAQ;YAAE,MAAM,KAAK,CAAA;QAC1C,MAAM,IAAI,QAAQ,CACd,yBAAyB,EACzB,4BAA4B,eAAe,CAAC,KAAK,CAAC,EAAE,CACvD,CAAA;IACL,CAAC;AACL,CAAC"}
|
|
@@ -7,7 +7,7 @@ import type { AuthAccount, AuthProvider, ValidateInput } from '../types.js';
|
|
|
7
7
|
export type PkceLazyString = string | ((ctx: {
|
|
8
8
|
handshake: Record<string, unknown>;
|
|
9
9
|
flags: Record<string, unknown>;
|
|
10
|
-
}) => string);
|
|
10
|
+
}) => string | Promise<string>);
|
|
11
11
|
export type PkceProviderOptions<TAccount extends AuthAccount = AuthAccount> = {
|
|
12
12
|
/** OAuth 2.0 authorize endpoint. Function form supports per-flow base URLs (Outline self-hosted). */
|
|
13
13
|
authorizeUrl: PkceLazyString;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pkce.d.ts","sourceRoot":"","sources":["../../../src/auth/providers/pkce.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"pkce.d.ts","sourceRoot":"","sources":["../../../src/auth/providers/pkce.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACR,WAAW,EACX,YAAY,EAMZ,aAAa,EAChB,MAAM,aAAa,CAAA;AAWpB;;;;GAIG;AACH,MAAM,MAAM,cAAc,GACpB,MAAM,GACN,CAAC,CAAC,GAAG,EAAE;IACH,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAClC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CACjC,KAAK,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAA;AAErC,MAAM,MAAM,mBAAmB,CAAC,QAAQ,SAAS,WAAW,GAAG,WAAW,IAAI;IAC1E,qGAAqG;IACrG,YAAY,EAAE,cAAc,CAAA;IAC5B,2EAA2E;IAC3E,QAAQ,EAAE,cAAc,CAAA;IACxB,mFAAmF;IACnF,QAAQ,EAAE,cAAc,CAAA;IACxB,iGAAiG;IACjG,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,kBAAkB;IAClB,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,0FAA0F;IAC1F,QAAQ,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAA;IACrD,6CAA6C;IAC7C,SAAS,CAAC,EAAE,OAAO,KAAK,CAAA;CAC3B,CAAA;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,SAAS,WAAW,EAC3D,OAAO,EAAE,mBAAmB,CAAC,QAAQ,CAAC,GACvC,YAAY,CAAC,QAAQ,CAAC,CAsLxB"}
|
|
@@ -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":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AACxC,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAA;AAC/D,OAAO,EAAE,UAAU,IAAI,KAAK,EAAE,MAAM,sBAAsB,CAAA;AAC1D,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AACxD,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AAsChE,MAAM,eAAe,GAAG,MAAM,CAAA;AAC9B,MAAM,oBAAoB,GAAG,KAAK,CAAA;AAClC,MAAM,qBAAqB,GAAG,EAAE,CAAA;AAChC,6EAA6E;AAC7E,+EAA+E;AAC/E,gEAAgE;AAChE,MAAM,aAAa,GAAG,MAAM,CAAA;AAE5B;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACpC,OAA4C;IAE5C,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAA;IACzD,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,eAAe,CAAA;IAChD,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,EAAE,CAAA;IAEzC,wEAAwE;IACxE,yEAAyE;IACzE,2EAA2E;IAC3E,IAAI,CAAC,KAAK,CAAC,YAAY,IAAI,CAAC,KAAK,CAAC,SAAS,EAAE,CAAC;QAC1C,MAAM,IAAI,QAAQ,CACd,0BAA0B,EAC1B,iEAAiE,EACjE,EAAE,KAAK,EAAE,CAAC,0CAA0C,CAAC,EAAE,CAC1D,CAAA;IACL,CAAC;IACD,IAAI,CAAC,QAAQ,CAAC,YAAY,EAAE,CAAC;QACzB,MAAM,IAAI,QAAQ,CACd,0BAA0B,EAC1B,gDAAgD,CACnD,CAAA;IACL,CAAC;IACD,MAAM,YAAY,GAAG,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;IACnD,MAAM,YAAY,GAAG,QAAQ,CAAC,YAAY,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;IAEzD,MAAM,QAAQ,GAAG,MAAM,YAAY,CAAC,GAAG,CAAC,CAAA;IACxC,IAAI,CAAC,QAAQ,EAAE,CAAC;QACZ,MAAM,IAAI,QAAQ,CAAC,0BAA0B,EAAE,kCAAkC,EAAE;YAC/E,KAAK,EAAE,CAAC,0CAA0C,CAAC;SACtD,CAAC,CAAA;IACN,CAAC;IAED,IAAI,CAAC,KAAK,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC;QACnD,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,EAAE,OAAO,EAAE,QAAQ,CAAC,OAAO,EAAE,CAAA;IACjF,CAAC;IAED,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,YAAY,EAAE,CAAC;QAChC,MAAM,IAAI,QAAQ,CAAC,0BAA0B,EAAE,yCAAyC,EAAE;YACtF,KAAK,EAAE,CAAC,0CAA0C,CAAC;SACtD,CAAC,CAAA;IACN,CAAC;IAED,MAAM,SAAS,GAAG,MAAM,WAAW,CAAC,QAAQ,CAAC,CAAA;IAC7C,IAAI,CAAC,SAAS,EAAE,CAAC;QACb,kEAAkE;QAClE,sEAAsE;QACtE,MAAM,KAAK,GAAG,MAAM,YAAY,CAAC,GAAG,CAAC,CAAA;QACrC,IAAI,KAAK,IAAI,UAAU,CAAC,QAAQ,CAAC,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC;YACrD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,CAAA;QAC1E,CAAC;QACD,MAAM,IAAI,QAAQ,CACd,wBAAwB,EACxB,yDAAyD,EACzD,EAAE,KAAK,EAAE,CAAC,YAAY,CAAC,EAAE,CAC5B,CAAA;IACL,CAAC;IAED,IAAI,CAAC;QACD,oEAAoE;QACpE,sEAAsE;QACtE,mEAAmE;QACnE,uDAAuD;QACvD,MAAM,OAAO,GAAG,MAAM,YAAY,CAAC,GAAG,CAAC,CAAA;QACvC,IAAI,CAAC,OAAO,EAAE,CAAC;YACX,iEAAiE;YACjE,6DAA6D;YAC7D,MAAM,IAAI,QAAQ,CACd,0BAA0B,EAC1B,wCAAwC,EACxC;gBACI,KAAK,EAAE,CAAC,0CAA0C,CAAC;aACtD,CACJ,CAAA;QACL,CAAC;QACD,IAAI,UAAU,CAAC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;YAC9C,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,CAAA;QAC9E,CAAC;QACD,MAAM,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,YAAY,CAAA;QAChD,IAAI,CAAC,YAAY,EAAE,CAAC;YAChB,MAAM,IAAI,QAAQ,CACd,0BAA0B,EAC1B,yCAAyC,EACzC,EAAE,KAAK,EAAE,CAAC,0CAA0C,CAAC,EAAE,CAC1D,CAAA;QACL,CAAC;QACD,MAAM,QAAQ,GAAG,MAAM,YAAY,CAAC,EAAE,YAAY,EAAE,SAAS,EAAE,CAAC,CAAA;QAChE,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,IAAI,OAAO,CAAC,OAAO,CAAA;QACnD,MAAM,MAAM,GAAG,kBAAkB,CAAC,QAAQ,EAAE,OAAO,CAAC,MAAM,CAAC,CAAA;QAC3D,MAAM,aAAa,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAA;QAC/C,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,CAAA;IAC7C,CAAC;YAAS,CAAC;QACP,MAAM,WAAW,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAA;IAC1C,CAAC;AACL,CAAC;AAED,SAAS,YAAY,CAAC,MAAmB,EAAE,MAAc;IACrD,wEAAwE;IACxE,IAAI,MAAM,CAAC,oBAAoB,KAAK,SAAS;QAAE,OAAO,KAAK,CAAA;IAC3D,OAAO,MAAM,CAAC,oBAAoB,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,MAAM,CAAA;AAC5D,CAAC;AAED,SAAS,UAAU,CAAC,MAAmB,EAAE,KAAkB;IACvD,OAAO,CACH,KAAK,CAAC,WAAW,KAAK,MAAM,CAAC,WAAW;QACxC,KAAK,CAAC,oBAAoB,KAAK,MAAM,CAAC,oBAAoB;QAC1D,KAAK,CAAC,YAAY,KAAK,MAAM,CAAC,YAAY;QAC1C,KAAK,CAAC,qBAAqB,KAAK,MAAM,CAAC,qBAAqB,CAC/D,CAAA;AACL,CAAC;AAED;;;;;GAKG;AACH,KAAK,UAAU,WAAW,CAAC,QAAgB;IACvC,MAAM,KAAK,GAAG,UAAU,EAAE,CAAA;IAC1B,IAAI,MAAM,UAAU,CAAC,QAAQ,EAAE,KAAK,CAAC;QAAE,OAAO,KAAK,CAAA;IACnD,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,oBAAoB,CAAA;IAClD,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ,EAAE,CAAC;QAC3B,MAAM,KAAK,CAAC,qBAAqB,CAAC,CAAA;QAClC,IAAI,MAAM,UAAU,CAAC,QAAQ,EAAE,KAAK,CAAC;YAAE,OAAO,KAAK,CAAA;IACvD,CAAC;IACD,OAAO,IAAI,CAAA;AACf,CAAC;AAED,4EAA4E;AAC5E,2EAA2E;AAC3E,oDAAoD;AACpD,KAAK,UAAU,UAAU,CAAC,QAAgB,EAAE,KAAa;IACrD,IAAI,MAAM,YAAY,CAAC,QAAQ,EAAE,KAAK,CAAC;QAAE,OAAO,IAAI,CAAA;IACpD,IAAI,MAAM,WAAW,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC9B,MAAM,WAAW,CAAC,QAAQ,CAAC,CAAA;QAC3B,OAAO,YAAY,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAA;IACxC,CAAC;IACD,OAAO,KAAK,CAAA;AAChB,CAAC;AAED,KAAK,UAAU,WAAW,CAAC,QAAgB;IACvC,IAAI,CAAC;QACD,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,CAAA;QACxC,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,OAAO,GAAG,aAAa,CAAA;IAC/C,CAAC;IAAC,MAAM,CAAC;QACL,OAAO,KAAK,CAAA;IAChB,CAAC;AACL,CAAC;AAED,KAAK,UAAU,YAAY,CAAC,QAAgB,EAAE,KAAa;IACvD,IAAI,MAAM,CAAA;IACV,IAAI,CAAC;QACD,MAAM,GAAG,MAAM,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAA;IACvC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACb,MAAM,IAAI,GAAI,KAA+B,CAAC,IAAI,CAAA;QAClD,IAAI,IAAI,KAAK,QAAQ;YAAE,OAAO,KAAK,CAAA;QACnC,MAAM,IAAI,QAAQ,CACd,wBAAwB,EACxB,mCAAmC,eAAe,CAAC,KAAK,CAAC,EAAE,EAC3D,EAAE,KAAK,EAAE,CAAC,YAAY,CAAC,EAAE,CAC5B,CAAA;IACL,CAAC;IACD,IAAI,CAAC;QACD,MAAM,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,CAAA;IACjC,CAAC;YAAS,CAAC;QACP,MAAM,MAAM,CAAC,KAAK,EAAE,CAAA;IACxB,CAAC;IACD,OAAO,IAAI,CAAA;AACf,CAAC;AAED,KAAK,UAAU,WAAW,CAAC,QAAgB,EAAE,KAAa;IACtD,IAAI,CAAC;QACD,MAAM,KAAK,GAAG,CAAC,MAAM,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,EAAE,CAAA;QACvD,IAAI,KAAK,KAAK,KAAK;YAAE,MAAM,MAAM,CAAC,QAAQ,CAAC,CAAA;IAC/C,CAAC;IAAC,MAAM,CAAC;QACL,mEAAmE;QACnE,kEAAkE;IACtE,CAAC;AACL,CAAC;AAED,KAAK,UAAU,WAAW,CAAC,QAAgB;IACvC,IAAI,CAAC;QACD,MAAM,MAAM,CAAC,QAAQ,CAAC,CAAA;IAC1B,CAAC;IAAC,MAAM,CAAC;QACL,eAAe;IACnB,CAAC;AACL,CAAC"}
|
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"}
|