@modelprofile.com/authswitch 9.1.0 → 10.0.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.
Files changed (75) hide show
  1. package/dist_ts/00_commitinfo_data.js +2 -2
  2. package/dist_ts/authority-contract.d.ts +56 -6
  3. package/dist_ts/authority-contract.js +1 -1
  4. package/dist_ts/authority-runtime-contract.d.ts +29 -0
  5. package/dist_ts/classes.authoritybroker.d.ts +36 -4
  6. package/dist_ts/classes.authoritybroker.js +71 -12
  7. package/dist_ts/classes.authoritycli.d.ts +4 -1
  8. package/dist_ts/classes.authoritycli.js +42 -7
  9. package/dist_ts/classes.authorityclient.d.ts +15 -2
  10. package/dist_ts/classes.authorityclient.js +31 -8
  11. package/dist_ts/classes.authoritydaemon.d.ts +17 -0
  12. package/dist_ts/classes.authoritydaemon.js +50 -14
  13. package/dist_ts/classes.authoritydatabase.d.ts +14 -3
  14. package/dist_ts/classes.authoritydatabase.js +25 -10
  15. package/dist_ts/classes.authorityimport.d.ts +4 -4
  16. package/dist_ts/classes.authorityimport.js +8 -7
  17. package/dist_ts/classes.authoritymodels.d.ts +11 -3
  18. package/dist_ts/classes.authoritymodels.js +43 -13
  19. package/dist_ts/classes.authoritypreuse.d.ts +8 -2
  20. package/dist_ts/classes.authoritypreuse.js +27 -17
  21. package/dist_ts/classes.authorityusage.d.ts +4 -3
  22. package/dist_ts/classes.authorityusage.js +3 -5
  23. package/dist_ts/classes.cli.js +3 -5
  24. package/dist_ts/classes.codexpreuse.d.ts +14 -3
  25. package/dist_ts/classes.codexpreuse.js +127 -44
  26. package/dist_ts/classes.codexstatus.js +44 -95
  27. package/dist_ts/classes.login.d.ts +20 -10
  28. package/dist_ts/classes.login.js +14 -13
  29. package/dist_ts/classes.openaiprovider.d.ts +53 -0
  30. package/dist_ts/classes.openaiprovider.js +340 -0
  31. package/dist_ts/classes.opencodeharness.js +3 -2
  32. package/dist_ts/classes.service.js +3 -5
  33. package/dist_ts/index.d.ts +2 -0
  34. package/dist_ts/index.js +3 -1
  35. package/dist_ts/interfaces.openai.d.ts +118 -0
  36. package/dist_ts/interfaces.openai.js +3 -0
  37. package/dist_ts/openaiauth.d.ts +76 -0
  38. package/dist_ts/openaiauth.js +371 -0
  39. package/dist_ts/openaiusage.d.ts +59 -0
  40. package/dist_ts/openaiusage.js +222 -0
  41. package/dist_ts/plugins.d.ts +1 -3
  42. package/dist_ts/plugins.js +2 -4
  43. package/dist_ts/preuse.d.ts +50 -0
  44. package/dist_ts/preuse.js +63 -4
  45. package/dist_ts/ts_migration/legacysources/shared.js +4 -3
  46. package/openai-codex-license.txt +201 -0
  47. package/package.json +6 -4
  48. package/readme.md +121 -26
  49. package/third-party-notices.md +29 -0
  50. package/ts/00_commitinfo_data.ts +1 -1
  51. package/ts/authority-contract.ts +60 -8
  52. package/ts/authority-runtime-contract.ts +30 -0
  53. package/ts/classes.authoritybroker.ts +80 -17
  54. package/ts/classes.authoritycli.ts +48 -6
  55. package/ts/classes.authorityclient.ts +32 -9
  56. package/ts/classes.authoritydaemon.ts +54 -14
  57. package/ts/classes.authoritydatabase.ts +28 -11
  58. package/ts/classes.authorityimport.ts +12 -12
  59. package/ts/classes.authoritymodels.ts +42 -14
  60. package/ts/classes.authoritypreuse.ts +30 -17
  61. package/ts/classes.authorityusage.ts +8 -9
  62. package/ts/classes.cli.ts +3 -3
  63. package/ts/classes.codexpreuse.ts +130 -40
  64. package/ts/classes.codexstatus.ts +40 -73
  65. package/ts/classes.login.ts +34 -21
  66. package/ts/classes.openaiprovider.ts +365 -0
  67. package/ts/classes.opencodeharness.ts +3 -2
  68. package/ts/classes.service.ts +3 -4
  69. package/ts/index.ts +2 -0
  70. package/ts/interfaces.openai.ts +142 -0
  71. package/ts/openaiauth.ts +422 -0
  72. package/ts/openaiusage.ts +247 -0
  73. package/ts/plugins.ts +1 -3
  74. package/ts/preuse.ts +88 -3
  75. package/ts/ts_migration/legacysources/shared.ts +4 -3
@@ -0,0 +1,118 @@
1
+ /**
2
+ * The ChatGPT account types authswitch owns: the sign-in it runs, the credential it holds and refreshes, and the
3
+ * credential-free readings it takes. Inference with an access token is FlexHarness's `/openai`, not this.
4
+ */
5
+ /** Whether a failed request reached the provider: `notSent` never did, `outcomeUnknown` may have. */
6
+ export type TOpenAiRequestOutcome = 'notSent' | 'outcomeUnknown';
7
+ /**
8
+ * A ChatGPT sign-in with its rotating refresh token. This exact shape is what the authority seals, so a stored
9
+ * credential keeps reading back across releases.
10
+ */
11
+ export interface IOpenAiOAuthCredential {
12
+ kind: 'chatgptOAuth';
13
+ providerId: 'openai';
14
+ accessToken: string;
15
+ refreshToken: string;
16
+ idToken: string;
17
+ /** When this credential was last refreshed; strictly increasing across refreshes. */
18
+ lastRefreshAt?: string;
19
+ }
20
+ /** Access to one ChatGPT workspace, with the workspace and residency its issuer states. */
21
+ export interface IOpenAiAccess {
22
+ accessToken: string;
23
+ accountId: string;
24
+ isFedrampAccount: boolean;
25
+ }
26
+ /** What a sign-in's claims say about its account; no token. */
27
+ export interface IOpenAiAccountSummary {
28
+ providerId: 'openai';
29
+ authKind: 'chatgptOAuth';
30
+ accountId?: string;
31
+ email?: string;
32
+ plan?: string;
33
+ }
34
+ export interface IOpenAiProviderDescriptor {
35
+ providerId: 'openai';
36
+ displayName: string;
37
+ loginFlows: readonly ['device'];
38
+ }
39
+ /** What the person signing in does: open the URL and enter the code. */
40
+ export interface IOpenAiDevicePrompt {
41
+ flow: 'device';
42
+ verificationUrl: string;
43
+ userCode: string;
44
+ }
45
+ export interface IOpenAiLoginResult {
46
+ credential: IOpenAiOAuthCredential;
47
+ account: IOpenAiAccountSummary;
48
+ }
49
+ export type TOpenAiLoginCancelStatus = 'canceled' | 'notFound';
50
+ /** One device sign-in in flight. `completion` settles once the person approved it, or it failed or was cancelled. */
51
+ export interface IOpenAiLoginHandle {
52
+ readonly prompt: IOpenAiDevicePrompt;
53
+ readonly completion: Promise<IOpenAiLoginResult>;
54
+ cancel(): Promise<TOpenAiLoginCancelStatus>;
55
+ close(): Promise<void>;
56
+ }
57
+ export interface IOpenAiOperationOptions {
58
+ signal?: AbortSignal;
59
+ timeoutMs?: number;
60
+ }
61
+ export interface IOpenAiLoginOptions extends IOpenAiOperationOptions {
62
+ flow: 'device';
63
+ }
64
+ export type TOpenAiOperationErrorCode = 'ABORTED' | 'TIMEOUT';
65
+ export interface IOpenAiRefreshSuccess {
66
+ success: true;
67
+ credential: IOpenAiOAuthCredential;
68
+ account: IOpenAiAccountSummary;
69
+ }
70
+ export interface IOpenAiRefreshFailure {
71
+ success: false;
72
+ credential: IOpenAiOAuthCredential;
73
+ errorCode: TOpenAiOperationErrorCode | 'REFRESH_FAILED';
74
+ /** Never replay a rotating grant when this is `outcomeUnknown`. */
75
+ requestOutcome: TOpenAiRequestOutcome;
76
+ /** The response status, when an HTTP response was observed. */
77
+ responseStatus?: number;
78
+ /** Bounded Retry-After delay from the observed response. */
79
+ retryAfterMs?: number;
80
+ }
81
+ export type TOpenAiRefreshResult = IOpenAiRefreshSuccess | IOpenAiRefreshFailure;
82
+ export interface IOpenAiRateLimitWindow {
83
+ usedPercent: number;
84
+ limitWindowSeconds: number;
85
+ resetAfterSeconds: number;
86
+ /** Unix timestamp in seconds. */
87
+ resetsAt: number;
88
+ }
89
+ export interface IOpenAiRateLimitDetails {
90
+ allowed: boolean;
91
+ limitReached: boolean;
92
+ primaryWindow?: IOpenAiRateLimitWindow;
93
+ secondaryWindow?: IOpenAiRateLimitWindow;
94
+ }
95
+ export interface IOpenAiAdditionalRateLimit {
96
+ limitName: string;
97
+ meteredFeature: string;
98
+ rateLimit?: IOpenAiRateLimitDetails;
99
+ }
100
+ /** An account's usage limits as `wham/usage` reports them, credential-free; the authority stores this shape. */
101
+ export interface IOpenAiAccountRateLimits {
102
+ providerId: 'openai';
103
+ plan: string;
104
+ observedAt: string;
105
+ rateLimit?: IOpenAiRateLimitDetails;
106
+ additionalRateLimits: IOpenAiAdditionalRateLimit[];
107
+ rateLimitReachedType?: string;
108
+ rateLimitResetCreditsAvailableCount?: number;
109
+ }
110
+ export interface IOpenAiAccountRateLimitsSuccess {
111
+ success: true;
112
+ rateLimits: IOpenAiAccountRateLimits;
113
+ }
114
+ export interface IOpenAiAccountRateLimitsFailure {
115
+ success: false;
116
+ errorCode: TOpenAiOperationErrorCode | 'CREDENTIAL_REFRESH_REQUIRED' | 'ACCOUNT_RATE_LIMITS_FAILED';
117
+ }
118
+ export type TOpenAiAccountRateLimitsResult = IOpenAiAccountRateLimitsSuccess | IOpenAiAccountRateLimitsFailure;
@@ -0,0 +1,3 @@
1
+ // OpenAI protocol portions are adapted in TypeScript from OpenAI Codex (Apache-2.0) and modified by Task Venture Capital GmbH; see third-party-notices.md.
2
+ export {};
3
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW50ZXJmYWNlcy5vcGVuYWkuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9pbnRlcmZhY2VzLm9wZW5haS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSwySkFBMkoifQ==
@@ -0,0 +1,76 @@
1
+ import type { TOpenAiRequestOutcome } from './interfaces.openai.js';
2
+ /**
3
+ * The ChatGPT sign-in protocol Codex uses (`codex-rs/login`: `device_code_auth.rs`, `auth/manager.rs`,
4
+ * `auth/revoke.rs`, `oauth/client.rs`), which the authority runs as the one party that signs in and refreshes:
5
+ * the device code, its poll, the authorization-code exchange, the refresh-token grant, the revocation and the
6
+ * claims of the tokens. Every failure is a fixed message: no response body, token or header crosses an error.
7
+ */
8
+ export declare const OPENAI_AUTH_ISSUER = "https://auth.openai.com";
9
+ export declare const OPENAI_AUTH_CLIENT_ID = "app_EMoamEEZ73f0CkXaXp7hrann";
10
+ export declare class OpenAiAuthError extends Error {
11
+ readonly status?: number;
12
+ readonly requestOutcome?: TOpenAiRequestOutcome;
13
+ readonly retryAfterMs?: number;
14
+ constructor(message: string, options?: {
15
+ status?: number;
16
+ requestOutcome?: TOpenAiRequestOutcome;
17
+ retryAfterMs?: number;
18
+ });
19
+ }
20
+ export interface IOpenAiAuthOptions {
21
+ fetch?: typeof fetch;
22
+ /** Aborts network requests and device-code polling. */
23
+ signal?: AbortSignal;
24
+ }
25
+ export interface IOpenAiDeviceCodePollOptions extends IOpenAiAuthOptions {
26
+ timeoutMs?: number;
27
+ sleep?: (ms: number) => Promise<void>;
28
+ }
29
+ /** What the claims of a ChatGPT token say about its account; never the token itself. */
30
+ export interface IOpenAiTokenClaims {
31
+ email?: string;
32
+ chatgptPlanType?: string;
33
+ chatgptUserId?: string;
34
+ chatgptAccountId?: string;
35
+ chatgptAccountIsFedramp: boolean;
36
+ expiresAt?: string;
37
+ }
38
+ export interface IOpenAiDeviceCode {
39
+ verificationUrl: string;
40
+ userCode: string;
41
+ deviceAuthId: string;
42
+ intervalSeconds: number;
43
+ }
44
+ export interface IOpenAiDeviceAuthorization {
45
+ authorizationCode: string;
46
+ codeChallenge: string;
47
+ codeVerifier: string;
48
+ }
49
+ /** The tokens one exchange or refresh produced, with the claims of the ID token (or access token). */
50
+ export interface IOpenAiTokenSet {
51
+ accessToken: string;
52
+ refreshToken: string;
53
+ idToken?: string;
54
+ claims: IOpenAiTokenClaims;
55
+ }
56
+ /** Reads the account claims of a ChatGPT ID or access token. Throws `OpenAiAuthError` for anything but a JWT. */
57
+ export declare const parseOpenAiTokenClaims: (token: string) => IOpenAiTokenClaims;
58
+ /** Starts a device sign-in (`POST {issuer}/api/accounts/deviceauth/usercode`). */
59
+ export declare const requestOpenAiDeviceCode: (options?: IOpenAiAuthOptions) => Promise<IOpenAiDeviceCode>;
60
+ /**
61
+ * Polls until the person approved the sign-in (`POST {issuer}/api/accounts/deviceauth/token`): 403 and 404 mean
62
+ * pending, as in Codex, and the poll gives up after at most fifteen minutes.
63
+ */
64
+ export declare const pollOpenAiDeviceCode: (deviceCode: IOpenAiDeviceCode, options?: IOpenAiDeviceCodePollOptions) => Promise<IOpenAiDeviceAuthorization>;
65
+ /** Exchanges an approved device sign-in for tokens (`POST {issuer}/oauth/token`, PKCE, form-encoded). */
66
+ export declare const exchangeOpenAiDeviceAuthorization: (authorization: IOpenAiDeviceAuthorization, options?: IOpenAiAuthOptions) => Promise<IOpenAiTokenSet>;
67
+ /**
68
+ * Sends one refresh-token grant (`POST {issuer}/oauth/token`, JSON). A response without a new refresh token keeps
69
+ * the one that was sent, as Codex does.
70
+ */
71
+ export declare const refreshOpenAiTokens: (tokens: IOpenAiTokenSet, options?: IOpenAiAuthOptions) => Promise<IOpenAiTokenSet>;
72
+ /**
73
+ * Revokes a refresh token (`POST {issuer}/oauth/revoke`, JSON), as Codex does when it logs out: the grant then
74
+ * refreshes nothing anywhere. It resolves only once the service accepted the revocation.
75
+ */
76
+ export declare const revokeOpenAiRefreshToken: (refreshToken: string, options?: IOpenAiAuthOptions) => Promise<void>;
@@ -0,0 +1,371 @@
1
+ // OpenAI protocol portions are adapted in TypeScript from OpenAI Codex (Apache-2.0) and modified by Task Venture Capital GmbH; see third-party-notices.md.
2
+ /**
3
+ * The ChatGPT sign-in protocol Codex uses (`codex-rs/login`: `device_code_auth.rs`, `auth/manager.rs`,
4
+ * `auth/revoke.rs`, `oauth/client.rs`), which the authority runs as the one party that signs in and refreshes:
5
+ * the device code, its poll, the authorization-code exchange, the refresh-token grant, the revocation and the
6
+ * claims of the tokens. Every failure is a fixed message: no response body, token or header crosses an error.
7
+ */
8
+ export const OPENAI_AUTH_ISSUER = 'https://auth.openai.com';
9
+ export const OPENAI_AUTH_CLIENT_ID = 'app_EMoamEEZ73f0CkXaXp7hrann';
10
+ const DEVICE_CODE_TIMEOUT_MS = 15 * 60 * 1000;
11
+ /** Codex's `REVOKE_HTTP_TIMEOUT`. */
12
+ const REVOKE_TIMEOUT_MS = 10_000;
13
+ const MAX_RESPONSE_BYTES = 64 * 1024;
14
+ const MAX_TOKEN_BYTES = 16 * 1024;
15
+ const MAX_AUTHORIZATION_CODE_BYTES = 8 * 1024;
16
+ const MAX_IDENTIFIER_BYTES = 1024;
17
+ const REQUEST_TIMEOUT_MS = 30_000;
18
+ const textEncoder = new TextEncoder();
19
+ const textDecoder = new TextDecoder();
20
+ const utf8ByteLength = (valueArg) => textEncoder.encode(valueArg).byteLength;
21
+ export class OpenAiAuthError extends Error {
22
+ status;
23
+ requestOutcome;
24
+ retryAfterMs;
25
+ constructor(message, options = {}) {
26
+ super(message);
27
+ this.name = 'OpenAiAuthError';
28
+ this.status = options.status;
29
+ this.requestOutcome = options.requestOutcome;
30
+ this.retryAfterMs = options.retryAfterMs;
31
+ }
32
+ }
33
+ const getFetch = (options) => {
34
+ const fetchFunction = options.fetch ?? globalThis.fetch;
35
+ if (!fetchFunction)
36
+ throw new OpenAiAuthError('fetch is not available for OpenAI authentication.');
37
+ return fetchFunction;
38
+ };
39
+ const throwIfAborted = (options) => {
40
+ if (options.signal?.aborted)
41
+ throw new OpenAiAuthError('OpenAI authentication was aborted.');
42
+ };
43
+ const asString = (value, name, maximumBytes = MAX_IDENTIFIER_BYTES) => {
44
+ if (typeof value !== 'string' || value.length === 0) {
45
+ throw new OpenAiAuthError(`OpenAI auth response is missing ${name}.`);
46
+ }
47
+ if (utf8ByteLength(value) > maximumBytes)
48
+ throw new OpenAiAuthError(`OpenAI auth response contains an invalid ${name}.`);
49
+ return value;
50
+ };
51
+ const asOptionalString = (value, maximumBytes = MAX_IDENTIFIER_BYTES) => {
52
+ if (typeof value !== 'string' || value.length === 0)
53
+ return undefined;
54
+ if (utf8ByteLength(value) > maximumBytes)
55
+ throw new OpenAiAuthError('OpenAI auth response contains an oversized string.');
56
+ return value;
57
+ };
58
+ /** Codex reads the interval as a string (`deserialize_interval`); both a number and a numeric string are taken. */
59
+ const asIntervalSeconds = (value) => {
60
+ const interval = typeof value === 'number' ? value : Number.parseInt(String(value ?? ''), 10);
61
+ if (!Number.isFinite(interval) || interval <= 0 || interval > 300) {
62
+ throw new OpenAiAuthError('OpenAI device-code response has an invalid interval.');
63
+ }
64
+ return interval;
65
+ };
66
+ const readResponseText = async (response, options) => {
67
+ const contentLength = response.headers.get('content-length');
68
+ if (contentLength !== null && (!/^\d+$/.test(contentLength) || Number(contentLength) > MAX_RESPONSE_BYTES)) {
69
+ await response.body?.cancel().catch(() => undefined);
70
+ throw new OpenAiAuthError('OpenAI auth response exceeded its size limit.', { status: response.status });
71
+ }
72
+ if (!response.body)
73
+ return '';
74
+ const reader = response.body.getReader();
75
+ const chunks = [];
76
+ let byteLength = 0;
77
+ let completed = false;
78
+ const onAbort = () => { void reader.cancel().catch(() => undefined); };
79
+ options.signal?.addEventListener('abort', onAbort, { once: true });
80
+ if (options.signal?.aborted)
81
+ onAbort();
82
+ try {
83
+ while (true) {
84
+ throwIfAborted(options);
85
+ const { done, value } = await reader.read();
86
+ throwIfAborted(options);
87
+ if (done)
88
+ break;
89
+ byteLength += value.byteLength;
90
+ if (byteLength > MAX_RESPONSE_BYTES) {
91
+ await reader.cancel().catch(() => undefined);
92
+ throw new OpenAiAuthError('OpenAI auth response exceeded its size limit.', { status: response.status });
93
+ }
94
+ chunks.push(value);
95
+ }
96
+ completed = true;
97
+ }
98
+ finally {
99
+ options.signal?.removeEventListener('abort', onAbort);
100
+ if (!completed)
101
+ void reader.cancel().catch(() => undefined);
102
+ reader.releaseLock();
103
+ }
104
+ const bytes = new Uint8Array(byteLength);
105
+ let offset = 0;
106
+ for (const chunk of chunks) {
107
+ bytes.set(chunk, offset);
108
+ offset += chunk.byteLength;
109
+ }
110
+ return textDecoder.decode(bytes);
111
+ };
112
+ const readJson = async (response, context, options) => {
113
+ const body = await readResponseText(response, options);
114
+ if (!response.ok)
115
+ throw new OpenAiAuthError(`${context} failed with status ${response.status}.`, { status: response.status });
116
+ try {
117
+ return body ? JSON.parse(body) : {};
118
+ }
119
+ catch {
120
+ throw new OpenAiAuthError(`${context} returned invalid JSON.`, { status: response.status });
121
+ }
122
+ };
123
+ const parseRetryAfterMs = (header) => {
124
+ if (!header || header.length > 128)
125
+ return undefined;
126
+ const maximumDelayMs = 24 * 60 * 60 * 1000;
127
+ if (/^\d{1,10}$/.test(header))
128
+ return Math.min(Number(header) * 1000, maximumDelayMs);
129
+ const retryAt = Date.parse(header);
130
+ if (!Number.isFinite(retryAt))
131
+ return undefined;
132
+ return Math.min(Math.max(0, retryAt - Date.now()), maximumDelayMs);
133
+ };
134
+ /**
135
+ * One bounded request. Its failure says whether the request was handed to fetch at all: a refresh whose outcome
136
+ * is `outcomeUnknown` may have rotated the grant and is never sent again.
137
+ */
138
+ const runFetch = async (url, init, options, handle, timeoutMs = REQUEST_TIMEOUT_MS) => {
139
+ if (options.signal?.aborted) {
140
+ throw new OpenAiAuthError('OpenAI authentication was aborted.', { requestOutcome: 'notSent' });
141
+ }
142
+ const controller = new AbortController();
143
+ let response;
144
+ let requestStarted = false;
145
+ const onExternalAbort = () => controller.abort();
146
+ const onRequestAbort = () => { void response?.body?.cancel().catch(() => undefined); };
147
+ options.signal?.addEventListener('abort', onExternalAbort, { once: true });
148
+ let rejectOnAbort;
149
+ const aborted = new Promise((_resolve, reject) => {
150
+ rejectOnAbort = () => reject(new Error('OpenAI authentication request aborted.'));
151
+ controller.signal.addEventListener('abort', rejectOnAbort, { once: true });
152
+ });
153
+ controller.signal.addEventListener('abort', onRequestAbort, { once: true });
154
+ if (options.signal?.aborted)
155
+ controller.abort();
156
+ const timer = setTimeout(() => controller.abort(), Math.min(timeoutMs, REQUEST_TIMEOUT_MS));
157
+ const requestOptions = { ...options, signal: controller.signal };
158
+ try {
159
+ return await Promise.race([
160
+ (async () => {
161
+ const fetchImplementation = getFetch(options);
162
+ requestStarted = true;
163
+ response = await fetchImplementation(url, { ...init, redirect: 'error', signal: controller.signal });
164
+ if (controller.signal.aborted)
165
+ await response.body?.cancel().catch(() => undefined);
166
+ throwIfAborted(requestOptions);
167
+ return handle(response, requestOptions);
168
+ })(),
169
+ aborted,
170
+ ]);
171
+ }
172
+ catch (error) {
173
+ const requestOutcome = requestStarted ? 'outcomeUnknown' : 'notSent';
174
+ const retryAfterMs = response ? parseRetryAfterMs(response.headers.get('retry-after')) : undefined;
175
+ const status = error instanceof OpenAiAuthError && error.status !== undefined ? error.status : response?.status;
176
+ throw new OpenAiAuthError(error instanceof OpenAiAuthError ? error.message
177
+ : options.signal?.aborted ? 'OpenAI authentication was aborted.' : 'OpenAI authentication request failed.', {
178
+ requestOutcome,
179
+ ...(status !== undefined ? { status } : {}),
180
+ ...(retryAfterMs !== undefined ? { retryAfterMs } : {}),
181
+ });
182
+ }
183
+ finally {
184
+ clearTimeout(timer);
185
+ options.signal?.removeEventListener('abort', onExternalAbort);
186
+ controller.signal.removeEventListener('abort', rejectOnAbort);
187
+ controller.signal.removeEventListener('abort', onRequestAbort);
188
+ }
189
+ };
190
+ const postJson = (url, body, options) => runFetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body) }, options, (response, requestOptions) => readJson(response, `POST ${url}`, requestOptions));
191
+ const postForm = (url, body, options) => runFetch(url, { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: body.toString() }, options, (response, requestOptions) => readJson(response, `POST ${url}`, requestOptions));
192
+ const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms));
193
+ const sleepWithAbort = async (milliseconds, options) => {
194
+ throwIfAborted(options);
195
+ const signal = options.signal;
196
+ if (!signal) {
197
+ await (options.sleep ?? sleep)(milliseconds);
198
+ return;
199
+ }
200
+ let abortListener;
201
+ let timer;
202
+ try {
203
+ await Promise.race([
204
+ options.sleep ? options.sleep(milliseconds) : new Promise(resolve => { timer = setTimeout(resolve, milliseconds); }),
205
+ new Promise((_resolve, reject) => {
206
+ abortListener = () => reject(new OpenAiAuthError('OpenAI authentication was aborted.'));
207
+ signal.addEventListener('abort', abortListener, { once: true });
208
+ if (signal.aborted)
209
+ abortListener();
210
+ }),
211
+ ]);
212
+ }
213
+ finally {
214
+ if (timer)
215
+ clearTimeout(timer);
216
+ if (abortListener)
217
+ signal.removeEventListener('abort', abortListener);
218
+ }
219
+ };
220
+ const parseJwtPayload = (jwt) => {
221
+ const parts = jwt.split('.');
222
+ if (parts.length !== 3 || !parts[1])
223
+ throw new OpenAiAuthError('OpenAI auth returned an invalid token.');
224
+ try {
225
+ const base64 = parts[1].replace(/-/g, '+').replace(/_/g, '/');
226
+ const binary = atob(base64.padEnd(Math.ceil(base64.length / 4) * 4, '='));
227
+ const value = JSON.parse(textDecoder.decode(Uint8Array.from(binary, character => character.charCodeAt(0))));
228
+ if (value === null || typeof value !== 'object' || Array.isArray(value))
229
+ throw new Error();
230
+ return value;
231
+ }
232
+ catch {
233
+ throw new OpenAiAuthError('OpenAI token claims could not be parsed.');
234
+ }
235
+ };
236
+ const claimRecord = (value) => value !== null && typeof value === 'object' && !Array.isArray(value) ? value : undefined;
237
+ /** Reads the account claims of a ChatGPT ID or access token. Throws `OpenAiAuthError` for anything but a JWT. */
238
+ export const parseOpenAiTokenClaims = (token) => {
239
+ const claims = parseJwtPayload(token);
240
+ const profile = claimRecord(claims['https://api.openai.com/profile']);
241
+ const auth = claimRecord(claims['https://api.openai.com/auth']);
242
+ const expiresAtSeconds = typeof claims.exp === 'number' ? claims.exp : undefined;
243
+ return {
244
+ email: asOptionalString(claims.email) ?? asOptionalString(profile?.email),
245
+ chatgptPlanType: asOptionalString(auth?.chatgpt_plan_type),
246
+ chatgptUserId: asOptionalString(auth?.chatgpt_user_id) ?? asOptionalString(auth?.user_id),
247
+ chatgptAccountId: asOptionalString(auth?.chatgpt_account_id),
248
+ chatgptAccountIsFedramp: auth?.chatgpt_account_is_fedramp === true,
249
+ expiresAt: expiresAtSeconds !== undefined ? new Date(expiresAtSeconds * 1000).toISOString() : undefined,
250
+ };
251
+ };
252
+ const createTokenSet = (response, existing) => {
253
+ const accessToken = asOptionalString(response.access_token, MAX_TOKEN_BYTES) ?? existing?.accessToken;
254
+ const refreshToken = asOptionalString(response.refresh_token, MAX_TOKEN_BYTES) ?? existing?.refreshToken;
255
+ const idToken = asOptionalString(response.id_token, MAX_TOKEN_BYTES) ?? existing?.idToken;
256
+ if (!accessToken)
257
+ throw new OpenAiAuthError('OpenAI auth response is missing access_token.');
258
+ if (!refreshToken)
259
+ throw new OpenAiAuthError('OpenAI auth response is missing refresh_token.');
260
+ let claims;
261
+ try {
262
+ claims = parseOpenAiTokenClaims(idToken ?? accessToken);
263
+ }
264
+ catch {
265
+ throw new OpenAiAuthError('OpenAI auth returned an invalid token.');
266
+ }
267
+ return { accessToken, refreshToken, ...(idToken ? { idToken } : {}), claims };
268
+ };
269
+ /** Starts a device sign-in (`POST {issuer}/api/accounts/deviceauth/usercode`). */
270
+ export const requestOpenAiDeviceCode = async (options = {}) => {
271
+ const response = await postJson(`${OPENAI_AUTH_ISSUER}/api/accounts/deviceauth/usercode`, { client_id: OPENAI_AUTH_CLIENT_ID }, options);
272
+ return {
273
+ verificationUrl: `${OPENAI_AUTH_ISSUER}/codex/device`,
274
+ userCode: asString(response.user_code ?? response.usercode, 'user_code'),
275
+ deviceAuthId: asString(response.device_auth_id, 'device_auth_id'),
276
+ intervalSeconds: asIntervalSeconds(response.interval),
277
+ };
278
+ };
279
+ /**
280
+ * Polls until the person approved the sign-in (`POST {issuer}/api/accounts/deviceauth/token`): 403 and 404 mean
281
+ * pending, as in Codex, and the poll gives up after at most fifteen minutes.
282
+ */
283
+ export const pollOpenAiDeviceCode = async (deviceCode, options = {}) => {
284
+ const pollUrl = `${OPENAI_AUTH_ISSUER}/api/accounts/deviceauth/token`;
285
+ const timeoutMs = options.timeoutMs ?? DEVICE_CODE_TIMEOUT_MS;
286
+ if (!Number.isSafeInteger(timeoutMs) || timeoutMs < 1 || timeoutMs > DEVICE_CODE_TIMEOUT_MS) {
287
+ throw new OpenAiAuthError('OpenAI device-code timeout is invalid.');
288
+ }
289
+ if (utf8ByteLength(deviceCode.deviceAuthId) > MAX_IDENTIFIER_BYTES
290
+ || utf8ByteLength(deviceCode.userCode) > MAX_IDENTIFIER_BYTES
291
+ || !Number.isSafeInteger(deviceCode.intervalSeconds) || deviceCode.intervalSeconds < 1
292
+ || deviceCode.intervalSeconds > 300) {
293
+ throw new OpenAiAuthError('OpenAI device-code input is invalid.');
294
+ }
295
+ const startedAt = Date.now();
296
+ while (Date.now() - startedAt < timeoutMs) {
297
+ const remainingBeforeRequest = timeoutMs - (Date.now() - startedAt);
298
+ const pollResult = await runFetch(pollUrl, {
299
+ method: 'POST',
300
+ headers: { 'Content-Type': 'application/json' },
301
+ body: JSON.stringify({ device_auth_id: deviceCode.deviceAuthId, user_code: deviceCode.userCode }),
302
+ }, options, async (response, requestOptions) => {
303
+ if (response.ok) {
304
+ return { status: 'complete',
305
+ body: await readJson(response, `POST ${pollUrl}`, requestOptions) };
306
+ }
307
+ await readResponseText(response, requestOptions);
308
+ if (response.status !== 403 && response.status !== 404) {
309
+ throw new OpenAiAuthError(`OpenAI device-code polling failed with status ${response.status}.`, { status: response.status });
310
+ }
311
+ return { status: 'pending' };
312
+ }, Math.max(remainingBeforeRequest, 1));
313
+ if (pollResult.status === 'complete') {
314
+ return {
315
+ authorizationCode: asString(pollResult.body.authorization_code, 'authorization_code', MAX_AUTHORIZATION_CODE_BYTES),
316
+ codeChallenge: asString(pollResult.body.code_challenge, 'code_challenge'),
317
+ codeVerifier: asString(pollResult.body.code_verifier, 'code_verifier'),
318
+ };
319
+ }
320
+ const remaining = timeoutMs - (Date.now() - startedAt);
321
+ await sleepWithAbort(Math.min(deviceCode.intervalSeconds * 1000, Math.max(remaining, 0)), options);
322
+ }
323
+ throw new OpenAiAuthError('OpenAI device-code login timed out.');
324
+ };
325
+ /** Exchanges an approved device sign-in for tokens (`POST {issuer}/oauth/token`, PKCE, form-encoded). */
326
+ export const exchangeOpenAiDeviceAuthorization = async (authorization, options = {}) => {
327
+ const response = await postForm(`${OPENAI_AUTH_ISSUER}/oauth/token`, new URLSearchParams({
328
+ grant_type: 'authorization_code',
329
+ code: authorization.authorizationCode,
330
+ redirect_uri: `${OPENAI_AUTH_ISSUER}/deviceauth/callback`,
331
+ client_id: OPENAI_AUTH_CLIENT_ID,
332
+ code_verifier: authorization.codeVerifier,
333
+ }), options);
334
+ return createTokenSet(response);
335
+ };
336
+ /**
337
+ * Sends one refresh-token grant (`POST {issuer}/oauth/token`, JSON). A response without a new refresh token keeps
338
+ * the one that was sent, as Codex does.
339
+ */
340
+ export const refreshOpenAiTokens = async (tokens, options = {}) => {
341
+ const response = await postJson(`${OPENAI_AUTH_ISSUER}/oauth/token`, {
342
+ client_id: OPENAI_AUTH_CLIENT_ID,
343
+ grant_type: 'refresh_token',
344
+ refresh_token: tokens.refreshToken,
345
+ }, options);
346
+ return createTokenSet({
347
+ id_token: response.id_token ?? tokens.idToken,
348
+ access_token: response.access_token ?? tokens.accessToken,
349
+ refresh_token: response.refresh_token ?? tokens.refreshToken,
350
+ }, tokens);
351
+ };
352
+ /**
353
+ * Revokes a refresh token (`POST {issuer}/oauth/revoke`, JSON), as Codex does when it logs out: the grant then
354
+ * refreshes nothing anywhere. It resolves only once the service accepted the revocation.
355
+ */
356
+ export const revokeOpenAiRefreshToken = async (refreshToken, options = {}) => {
357
+ if (typeof refreshToken !== 'string' || !refreshToken || utf8ByteLength(refreshToken) > MAX_TOKEN_BYTES) {
358
+ throw new OpenAiAuthError('OpenAI revocation input is invalid.', { requestOutcome: 'notSent' });
359
+ }
360
+ const url = `${OPENAI_AUTH_ISSUER}/oauth/revoke`;
361
+ await runFetch(url, {
362
+ method: 'POST',
363
+ headers: { 'Content-Type': 'application/json' },
364
+ body: JSON.stringify({ token: refreshToken, token_type_hint: 'refresh_token', client_id: OPENAI_AUTH_CLIENT_ID }),
365
+ }, options, async (response, requestOptions) => {
366
+ await readResponseText(response, requestOptions);
367
+ if (!response.ok)
368
+ throw new OpenAiAuthError(`POST ${url} failed with status ${response.status}.`, { status: response.status });
369
+ }, REVOKE_TIMEOUT_MS);
370
+ };
371
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoib3BlbmFpYXV0aC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3RzL29wZW5haWF1dGgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsMkpBQTJKO0FBSTNKOzs7OztHQUtHO0FBRUgsTUFBTSxDQUFDLE1BQU0sa0JBQWtCLEdBQUcseUJBQXlCLENBQUM7QUFDNUQsTUFBTSxDQUFDLE1BQU0scUJBQXFCLEdBQUcsOEJBQThCLENBQUM7QUFFcEUsTUFBTSxzQkFBc0IsR0FBRyxFQUFFLEdBQUcsRUFBRSxHQUFHLElBQUksQ0FBQztBQUM5QyxxQ0FBcUM7QUFDckMsTUFBTSxpQkFBaUIsR0FBRyxNQUFNLENBQUM7QUFDakMsTUFBTSxrQkFBa0IsR0FBRyxFQUFFLEdBQUcsSUFBSSxDQUFDO0FBQ3JDLE1BQU0sZUFBZSxHQUFHLEVBQUUsR0FBRyxJQUFJLENBQUM7QUFDbEMsTUFBTSw0QkFBNEIsR0FBRyxDQUFDLEdBQUcsSUFBSSxDQUFDO0FBQzlDLE1BQU0sb0JBQW9CLEdBQUcsSUFBSSxDQUFDO0FBQ2xDLE1BQU0sa0JBQWtCLEdBQUcsTUFBTSxDQUFDO0FBQ2xDLE1BQU0sV0FBVyxHQUFHLElBQUksV0FBVyxFQUFFLENBQUM7QUFDdEMsTUFBTSxXQUFXLEdBQUcsSUFBSSxXQUFXLEVBQUUsQ0FBQztBQUN0QyxNQUFNLGNBQWMsR0FBRyxDQUFDLFFBQWdCLEVBQVUsRUFBRSxDQUFDLFdBQVcsQ0FBQyxNQUFNLENBQUMsUUFBUSxDQUFDLENBQUMsVUFBVSxDQUFDO0FBRTdGLE1BQU0sT0FBTyxlQUFnQixTQUFRLEtBQUs7SUFDeEIsTUFBTSxDQUFVO0lBQ2hCLGNBQWMsQ0FBeUI7SUFDdkMsWUFBWSxDQUFVO0lBRXRDLFlBQVksT0FBZSxFQUFFLFVBQ0QsRUFBRTtRQUM1QixLQUFLLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDZixJQUFJLENBQUMsSUFBSSxHQUFHLGlCQUFpQixDQUFDO1FBQzlCLElBQUksQ0FBQyxNQUFNLEdBQUcsT0FB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