@modelprofile.com/authswitch-signin 10.4.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.
@@ -0,0 +1,408 @@
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
+ import * as plugins from './plugins.js';
3
+ import { parseOpenAiTokenClaims, revokeOpenAiRefreshToken } from './signin.protocol.js';
4
+ import { openAiTokensOfCredential, refreshOpenAiCredential } from './signin.credential.js';
5
+ /** A grant failure. Its message is fixed and names no token. */
6
+ export class OpenAiGrantError extends Error {
7
+ code;
8
+ details;
9
+ constructor(code, details = {}) {
10
+ super(`OpenAI grant operation failed (${code}).`);
11
+ this.code = code;
12
+ this.details = details;
13
+ this.name = 'OpenAiGrantError';
14
+ }
15
+ }
16
+ /** Codex refreshes an access token that expires within five minutes (`CHATGPT_ACCESS_TOKEN_REFRESH_WINDOW_MINUTES`). */
17
+ const ACCESS_REFRESH_WINDOW_MS = 5 * 60 * 1000;
18
+ /** Codex refreshes tokens older than eight days even while the access token is valid (`TOKEN_REFRESH_INTERVAL`). */
19
+ const TOKEN_REFRESH_INTERVAL_MS = 8 * 24 * 60 * 60 * 1000;
20
+ /** One refresh request is bounded by thirty seconds; an attempt is given up thirty seconds after that. */
21
+ const REFRESH_REQUEST_TIMEOUT_MS = 30_000;
22
+ const REFRESH_ATTEMPT_LEASE_MS = 60_000;
23
+ const DEFAULT_MIN_VALIDITY_MS = 60_000;
24
+ const MAX_MIN_VALIDITY_MS = 3_600_000;
25
+ const MAX_RESOLVE_ROUNDS = 8;
26
+ const MAX_WRITE_ROUNDS = 4;
27
+ const MAX_GRANT_ID_BYTES = 512;
28
+ const isoTime = (value) => {
29
+ if (typeof value !== 'string')
30
+ return NaN;
31
+ const time = Date.parse(value);
32
+ return Number.isFinite(time) && new Date(time).toISOString() === value ? time : NaN;
33
+ };
34
+ const isCount = (value, minimum) => typeof value === 'number' && Number.isSafeInteger(value) && value >= minimum;
35
+ const requireGrantId = (grantId) => {
36
+ if (typeof grantId !== 'string' || !grantId || Buffer.byteLength(grantId, 'utf8') > MAX_GRANT_ID_BYTES) {
37
+ throw new OpenAiGrantError('invalid_argument');
38
+ }
39
+ return grantId;
40
+ };
41
+ /** The identity and expiry a credential's access token states; `null` when it states none of them usable. */
42
+ const accessFactsOf = (credential) => {
43
+ try {
44
+ openAiTokensOfCredential(credential);
45
+ const access = parseOpenAiTokenClaims(credential.accessToken);
46
+ const identity = parseOpenAiTokenClaims(credential.idToken);
47
+ const accountId = access.chatgptAccountId ?? identity.chatgptAccountId;
48
+ const userId = access.chatgptUserId ?? identity.chatgptUserId;
49
+ if (!accountId || !userId || !access.expiresAt)
50
+ return null;
51
+ if (identity.chatgptAccountId !== undefined && identity.chatgptAccountId !== accountId)
52
+ return null;
53
+ return { accountId, userId, isFedrampAccount: access.chatgptAccountIsFedramp, expiresAt: access.expiresAt };
54
+ }
55
+ catch {
56
+ return null;
57
+ }
58
+ };
59
+ /** A stored record this manager would have written; anything else is refused before it is used. */
60
+ const checkRecord = (record) => {
61
+ const valid = record !== null && typeof record === 'object'
62
+ && isCount(record.revision, 1) && isCount(record.generation, 1) && isCount(record.retryCount, 0)
63
+ && ['active', 'refresh_uncertain', 'reauth_required'].includes(record.state)
64
+ && typeof record.accountId === 'string' && record.accountId.length > 0
65
+ && typeof record.userId === 'string' && record.userId.length > 0
66
+ && typeof record.isFedrampAccount === 'boolean'
67
+ && Number.isFinite(isoTime(record.accessExpiresAt)) && Number.isFinite(isoTime(record.refreshedAt))
68
+ && (record.retryAt === null || Number.isFinite(isoTime(record.retryAt)))
69
+ && (record.state === 'refresh_uncertain'
70
+ ? record.attempt !== null && typeof record.attempt === 'object' && typeof record.attempt.id === 'string'
71
+ && record.attempt.id.length > 0 && Number.isFinite(isoTime(record.attempt.expiresAt))
72
+ : record.attempt === null)
73
+ && (record.state === 'reauth_required'
74
+ ? ['refresh_failed', 'refresh_interrupted', 'identity_changed'].includes(record.reauthReason ?? '')
75
+ : record.reauthReason === null);
76
+ if (!valid)
77
+ throw new OpenAiGrantError('invalid_record');
78
+ const facts = accessFactsOf(record.credential);
79
+ if (!facts || facts.accountId !== record.accountId || facts.userId !== record.userId
80
+ || facts.isFedrampAccount !== record.isFedrampAccount || facts.expiresAt !== record.accessExpiresAt) {
81
+ throw new OpenAiGrantError('invalid_record');
82
+ }
83
+ return record;
84
+ };
85
+ /**
86
+ * Keeps ChatGPT sign-ins usable for any number of processes that share one store: it answers current access for
87
+ * each request, refreshes the tokens when they are due or the provider rejected exactly the current generation,
88
+ * and never sends a refresh token whose outcome is unknown a second time. Within a process one refresh per grant
89
+ * runs at a time; across processes the store's compare-and-set on the revision decides, and a process that finds
90
+ * another's refresh in flight waits for its outcome. It holds no credential of its own: every call reads the
91
+ * store, and no error, status or return value carries a refresh or ID token.
92
+ */
93
+ export class OpenAiGrantManager {
94
+ store;
95
+ fetcher;
96
+ now;
97
+ waitIntervalMs;
98
+ refreshes = new Map();
99
+ constructor(options) {
100
+ if (!options || typeof options.store !== 'object' || options.store === null) {
101
+ throw new OpenAiGrantError('invalid_argument');
102
+ }
103
+ const waitIntervalMs = options.waitIntervalMs ?? 250;
104
+ if (!Number.isSafeInteger(waitIntervalMs) || waitIntervalMs < 1 || waitIntervalMs > 10_000) {
105
+ throw new OpenAiGrantError('invalid_argument');
106
+ }
107
+ this.store = options.store;
108
+ this.fetcher = options.fetch;
109
+ this.now = options.now ?? (() => Date.now());
110
+ this.waitIntervalMs = waitIntervalMs;
111
+ }
112
+ /** The record a new sign-in starts: generation one, active. */
113
+ recordOf(result, revision, generation) {
114
+ const facts = result && typeof result === 'object' ? accessFactsOf(result.credential) : null;
115
+ if (!facts)
116
+ throw new OpenAiGrantError('invalid_argument');
117
+ return {
118
+ revision, generation, state: 'active', credential: result.credential,
119
+ accountId: facts.accountId, userId: facts.userId, isFedrampAccount: facts.isFedrampAccount,
120
+ accessExpiresAt: facts.expiresAt, refreshedAt: new Date(this.now()).toISOString(),
121
+ retryAt: null, retryCount: 0, attempt: null, reauthReason: null,
122
+ };
123
+ }
124
+ statusOf(record) {
125
+ let plan = null;
126
+ try {
127
+ plan = parseOpenAiTokenClaims(record.credential.idToken).chatgptPlanType ?? null;
128
+ }
129
+ catch {
130
+ plan = null;
131
+ }
132
+ return {
133
+ revision: record.revision, generation: record.generation, state: record.state,
134
+ reauthReason: record.reauthReason, accountId: record.accountId, isFedrampAccount: record.isFedrampAccount,
135
+ plan, accessExpiresAt: record.accessExpiresAt, refreshedAt: record.refreshedAt, retryAt: record.retryAt,
136
+ };
137
+ }
138
+ async load(grantId) {
139
+ const record = await this.store.load(grantId);
140
+ return record === null ? null : checkRecord(record);
141
+ }
142
+ /** Stores the grant a device sign-in produced. Throws `OpenAiGrantError` `contended` when a grant exists under the id. */
143
+ async create(grantId, result) {
144
+ requireGrantId(grantId);
145
+ const record = this.recordOf(result, 1, 1);
146
+ if (await this.store.create(grantId, record) !== 'stored')
147
+ throw new OpenAiGrantError('contended');
148
+ return this.statusOf(record);
149
+ }
150
+ /**
151
+ * Replaces a grant with a new sign-in, over the revision the caller read: a grant that needs a new sign-in is
152
+ * repaired this way. The generation keeps rising, so a 401 of the old tokens cannot be mistaken for the new.
153
+ * The replaced tokens are not revoked.
154
+ */
155
+ async replace(grantId, expectedRevision, result) {
156
+ requireGrantId(grantId);
157
+ if (!isCount(expectedRevision, 1))
158
+ throw new OpenAiGrantError('invalid_argument');
159
+ const current = await this.load(grantId);
160
+ if (!current)
161
+ throw new OpenAiGrantError('not_found');
162
+ if (current.revision !== expectedRevision)
163
+ throw new OpenAiGrantError('contended');
164
+ const record = this.recordOf(result, current.revision + 1, current.generation + 1);
165
+ if (await this.store.compareAndSet(grantId, expectedRevision, record) !== 'stored') {
166
+ throw new OpenAiGrantError('contended');
167
+ }
168
+ return this.statusOf(record);
169
+ }
170
+ /** The grant's state without any token; `null` when there is none. */
171
+ async status(grantId) {
172
+ requireGrantId(grantId);
173
+ const record = await this.load(grantId);
174
+ return record ? this.statusOf(record) : null;
175
+ }
176
+ isDue(record, minValidityMs) {
177
+ const now = this.now();
178
+ return Date.parse(record.accessExpiresAt) <= now + Math.max(minValidityMs, ACCESS_REFRESH_WINDOW_MS)
179
+ || Date.parse(record.refreshedAt) <= now - TOKEN_REFRESH_INTERVAL_MS;
180
+ }
181
+ async wait(signal) {
182
+ if (signal?.aborted)
183
+ throw new OpenAiGrantError('aborted');
184
+ let timer;
185
+ let onAbort;
186
+ try {
187
+ await new Promise((resolve, reject) => {
188
+ timer = setTimeout(resolve, this.waitIntervalMs);
189
+ if (signal) {
190
+ onAbort = () => reject(new OpenAiGrantError('aborted'));
191
+ signal.addEventListener('abort', onAbort, { once: true });
192
+ }
193
+ });
194
+ }
195
+ finally {
196
+ if (timer)
197
+ clearTimeout(timer);
198
+ if (onAbort)
199
+ signal?.removeEventListener('abort', onAbort);
200
+ }
201
+ }
202
+ /** Waits for a promise, or rejects `aborted` as soon as the signal fires; the promise runs on regardless. */
203
+ async awaitOrAbort(task, signal) {
204
+ if (!signal)
205
+ return task;
206
+ if (signal.aborted)
207
+ throw new OpenAiGrantError('aborted');
208
+ let onAbort;
209
+ try {
210
+ await Promise.race([task, new Promise((_resolve, reject) => {
211
+ onAbort = () => reject(new OpenAiGrantError('aborted'));
212
+ signal.addEventListener('abort', onAbort, { once: true });
213
+ })]);
214
+ }
215
+ finally {
216
+ if (onAbort)
217
+ signal.removeEventListener('abort', onAbort);
218
+ }
219
+ }
220
+ /** Moves a record on over the revision it was read at; `false` when it moved meanwhile. */
221
+ async write(grantId, current, change) {
222
+ const next = { ...current, ...change, revision: current.revision + 1 };
223
+ return await this.store.compareAndSet(grantId, current.revision, next) === 'stored';
224
+ }
225
+ /**
226
+ * Current access for one provider request. The access stays valid for `minValidityMs` at least; tokens that
227
+ * are due, or whose generation the provider just rejected, are refreshed first.
228
+ * Throws `OpenAiGrantError`: `reauth_required` when only a new sign-in helps, `access_not_fresh` when the
229
+ * service could not renew the tokens yet.
230
+ */
231
+ async resolveAccess(grantId, options = {}) {
232
+ requireGrantId(grantId);
233
+ const minValidityMs = options.minValidityMs ?? DEFAULT_MIN_VALIDITY_MS;
234
+ const rejected = options.rejectedGeneration;
235
+ if (!Number.isSafeInteger(minValidityMs) || minValidityMs < 0 || minValidityMs > MAX_MIN_VALIDITY_MS
236
+ || (rejected !== undefined && !isCount(rejected, 1))) {
237
+ throw new OpenAiGrantError('invalid_argument');
238
+ }
239
+ let refreshedOnce = false;
240
+ for (let round = 0; round < MAX_RESOLVE_ROUNDS; round++) {
241
+ if (options.signal?.aborted)
242
+ throw new OpenAiGrantError('aborted');
243
+ const record = await this.load(grantId);
244
+ if (!record)
245
+ throw new OpenAiGrantError('not_found');
246
+ if (rejected !== undefined && rejected > record.generation)
247
+ throw new OpenAiGrantError('invalid_argument');
248
+ if (record.state === 'reauth_required') {
249
+ throw new OpenAiGrantError('reauth_required', { reauthReason: record.reauthReason ?? 'refresh_failed' });
250
+ }
251
+ if (record.state === 'refresh_uncertain') {
252
+ await this.settleAttempt(grantId, record, options.signal);
253
+ continue;
254
+ }
255
+ const rejectedCurrent = rejected === record.generation;
256
+ const expiresAt = Date.parse(record.accessExpiresAt);
257
+ const usable = !rejectedCurrent && expiresAt > this.now() + minValidityMs;
258
+ if (!this.isDue(record, minValidityMs) && usable) {
259
+ return {
260
+ accessToken: record.credential.accessToken, accountId: record.accountId,
261
+ isFedrampAccount: record.isFedrampAccount, expiresAt: record.accessExpiresAt, generation: record.generation,
262
+ };
263
+ }
264
+ const retryAt = record.retryAt === null ? null : Date.parse(record.retryAt);
265
+ if (refreshedOnce || (retryAt !== null && retryAt > this.now())) {
266
+ // The service was asked and could not renew the tokens yet. Access that is still good enough serves.
267
+ if (usable) {
268
+ return {
269
+ accessToken: record.credential.accessToken, accountId: record.accountId,
270
+ isFedrampAccount: record.isFedrampAccount, expiresAt: record.accessExpiresAt, generation: record.generation,
271
+ };
272
+ }
273
+ throw new OpenAiGrantError('access_not_fresh', record.retryAt === null ? {} : { retryAt: record.retryAt });
274
+ }
275
+ await this.awaitOrAbort(this.refresh(grantId, record), options.signal);
276
+ refreshedOnce = true;
277
+ }
278
+ throw new OpenAiGrantError('contended');
279
+ }
280
+ /**
281
+ * Refreshes a grant that is due (by its access expiry or its age) and answers its state; one that is not due is
282
+ * left as it is. For a periodic job, so a sign-in that no request uses stays alive.
283
+ */
284
+ async keepFresh(grantId, options = {}) {
285
+ requireGrantId(grantId);
286
+ try {
287
+ await this.resolveAccess(grantId, { signal: options.signal, minValidityMs: 0 });
288
+ }
289
+ catch (error) {
290
+ if (!(error instanceof OpenAiGrantError) || !['reauth_required', 'access_not_fresh', 'not_found'].includes(error.code)) {
291
+ throw error;
292
+ }
293
+ }
294
+ return this.status(grantId);
295
+ }
296
+ /**
297
+ * A record whose refresh may have been sent: this process waits for its own attempt; another process's attempt
298
+ * is waited for until the record moves on or the attempt's lease passes, and then the grant needs a new sign-in.
299
+ */
300
+ async settleAttempt(grantId, record, signal) {
301
+ const own = this.refreshes.get(grantId);
302
+ if (own) {
303
+ await this.awaitOrAbort(own, signal);
304
+ return;
305
+ }
306
+ let current = record;
307
+ while (current && current.revision === record.revision) {
308
+ if (!current.attempt || Date.parse(current.attempt.expiresAt) <= this.now()) {
309
+ await this.write(grantId, current, {
310
+ state: 'reauth_required', reauthReason: 'refresh_interrupted', attempt: null, retryAt: null,
311
+ });
312
+ return;
313
+ }
314
+ await this.wait(signal);
315
+ current = await this.load(grantId);
316
+ }
317
+ }
318
+ /** One refresh per grant in this process; a caller that stops waiting leaves it running to its end. */
319
+ refresh(grantId, record) {
320
+ const prior = this.refreshes.get(grantId);
321
+ if (prior)
322
+ return prior;
323
+ const task = this.performRefresh(grantId, record)
324
+ .finally(() => { if (this.refreshes.get(grantId) === task)
325
+ this.refreshes.delete(grantId); });
326
+ this.refreshes.set(grantId, task);
327
+ return task;
328
+ }
329
+ async performRefresh(grantId, initial) {
330
+ const attemptId = plugins.crypto.randomUUID();
331
+ const attempt = { id: attemptId, expiresAt: new Date(this.now() + REFRESH_ATTEMPT_LEASE_MS).toISOString() };
332
+ // The marker is stored before the refresh token is sent: a process that dies after this point leaves a
333
+ // record that can only lead to a new sign-in, never to a second use of the same refresh token.
334
+ if (!await this.write(grantId, initial, { state: 'refresh_uncertain', attempt, retryAt: null }))
335
+ return;
336
+ const marked = { ...initial, state: 'refresh_uncertain', attempt, retryAt: null,
337
+ revision: initial.revision + 1 };
338
+ const result = await refreshOpenAiCredential(initial.credential, {
339
+ fetch: this.fetcher, signal: AbortSignal.timeout(REFRESH_REQUEST_TIMEOUT_MS), now: () => new Date(this.now()),
340
+ });
341
+ const current = await this.load(grantId);
342
+ if (!current || current.revision !== marked.revision || current.attempt?.id !== attemptId)
343
+ return;
344
+ if (result.success) {
345
+ const facts = accessFactsOf(result.credential);
346
+ if (!facts || facts.accountId !== initial.accountId || facts.userId !== initial.userId) {
347
+ await this.write(grantId, current, {
348
+ state: 'reauth_required', reauthReason: 'identity_changed', attempt: null, retryAt: null,
349
+ });
350
+ return;
351
+ }
352
+ await this.write(grantId, current, {
353
+ state: 'active', credential: result.credential, generation: current.generation + 1,
354
+ isFedrampAccount: facts.isFedrampAccount, accessExpiresAt: facts.expiresAt,
355
+ refreshedAt: new Date(this.now()).toISOString(), retryAt: null, retryCount: 0, attempt: null,
356
+ reauthReason: null,
357
+ });
358
+ return;
359
+ }
360
+ if (result.requestOutcome === 'notSent') {
361
+ const backoffMs = Math.min(30_000 * 2 ** Math.min(current.retryCount, 10), 1_800_000);
362
+ const retryMs = Math.max(backoffMs, Math.min(result.retryAfterMs ?? 0, 3_600_000));
363
+ await this.write(grantId, current, {
364
+ state: 'active', attempt: null, retryAt: new Date(this.now() + retryMs).toISOString(),
365
+ retryCount: current.retryCount + 1,
366
+ });
367
+ return;
368
+ }
369
+ await this.write(grantId, current, {
370
+ state: 'reauth_required', reauthReason: 'refresh_failed', attempt: null, retryAt: null,
371
+ });
372
+ }
373
+ /**
374
+ * Removes a grant and then asks the service to revoke its refresh token. The grant is removed whatever the
375
+ * service answers; `revocation` says what it answered. `removed: false` when there was no grant.
376
+ */
377
+ async remove(grantId, options = {}) {
378
+ requireGrantId(grantId);
379
+ for (let round = 0; round < MAX_WRITE_ROUNDS; round++) {
380
+ const record = await this.store.load(grantId);
381
+ if (!record)
382
+ return { removed: false, revocation: null };
383
+ if (!isCount(record.revision, 1))
384
+ throw new OpenAiGrantError('invalid_record');
385
+ if (await this.store.remove(grantId, record.revision) !== 'removed')
386
+ continue;
387
+ let token = null;
388
+ try {
389
+ token = openAiTokensOfCredential(record.credential).refreshToken;
390
+ }
391
+ catch {
392
+ token = null;
393
+ }
394
+ if (token === null)
395
+ return { removed: true, revocation: 'failed' };
396
+ try {
397
+ await revokeOpenAiRefreshToken(token, { fetch: this.fetcher, signal: options.signal });
398
+ }
399
+ catch {
400
+ return { removed: true, revocation: 'failed' };
401
+ }
402
+ const current = record.state === 'active' && record.attempt === null;
403
+ return { removed: true, revocation: current ? 'confirmed' : 'unconfirmed' };
404
+ }
405
+ throw new OpenAiGrantError('contended');
406
+ }
407
+ }
408
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2lnbmluLmdyYW50cy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3RzX3NpZ25pbi9zaWduaW4uZ3JhbnRzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLDJKQUEySjtBQUUzSixPQUFPLEtBQUssT0FBTyxNQUFNLGNBQWMsQ0FBQztBQUN4QyxPQUFPLEVBQUUsc0JBQXNCLEVBQUUsd0JBQXdCLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQztBQUN4RixPQUFPLEVBQUUsd0JBQXdCLEVBQUUsdUJBQXVCLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQXFIM0YsZ0VBQWdFO0FBQ2hFLE1BQU0sT0FBTyxnQkFBaUIsU0FBUSxLQUFLO0lBRXZCO0lBQ0E7SUFGbEIsWUFDa0IsSUFBMkIsRUFDM0IsVUFBeUUsRUFBRTtRQUUzRixLQUFLLENBQUMsa0NBQWtDLElBQUksSUFBSSxDQUFDLENBQUM7UUFIbEMsU0FBSSxHQUFKLElBQUksQ0FBdUI7UUFDM0IsWUFBTyxHQUFQLE9BQU8sQ0FBb0U7UUFHM0YsSUFBSSxDQUFDLElBQUksR0FBRyxrQkFBa0IsQ0FBQztJQUNqQyxDQUFDO0NBQ0Y7QUFVRCx3SEFBd0g7QUFDeEgsTUFBTSx3QkFBd0IsR0FBRyxDQUFDLEdBQUcsRUFBRSxHQUFHLElBQUksQ0FBQztBQUMvQyxvSEFBb0g7QUFDcEgsTUFBTSx5QkFBeUIsR0FBRyxDQUFDLEdBQUcsRUFBRSxHQUFHLEVBQUUsR0FBRyxFQUFFLEdBQUcsSUFBSSxDQUFDO0FBQzFELDBHQUEwRztBQUMxRyxNQUFNLDBCQUEwQixHQUFHLE1BQU0sQ0FBQztBQUMxQyxNQUFNLHdCQUF3QixHQUFHLE1BQU0sQ0FBQztBQUN4QyxNQUFNLHVCQUF1QixHQUFHLE1BQU0sQ0FBQztBQUN2QyxNQUFNLG1CQUFtQixHQUFHLFNBQVMsQ0FBQztBQUN0QyxNQUFNLGtCQUFrQixHQUFHLENBQUMsQ0FBQztBQUM3QixNQUFNLGdCQUFnQixHQUFHLENBQUMsQ0FBQztBQUMzQixNQUFN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
@@ -0,0 +1,62 @@
1
+ /**
2
+ * The shapes of one ChatGPT sign-in: the credential it produces, the access that credential grants, what its
3
+ * claims say about the account, and the outcome of a refresh. Inference with an access token is FlexHarness's
4
+ * `/openai`, not this.
5
+ */
6
+ /** Whether a failed request reached the provider: `notSent` never did, `outcomeUnknown` may have. */
7
+ export type TOpenAiRequestOutcome = 'notSent' | 'outcomeUnknown';
8
+ /**
9
+ * A ChatGPT sign-in with its rotating refresh token. This exact shape is what the authority seals, so a stored
10
+ * credential keeps reading back across releases.
11
+ */
12
+ export interface IOpenAiOAuthCredential {
13
+ kind: 'chatgptOAuth';
14
+ providerId: 'openai';
15
+ accessToken: string;
16
+ refreshToken: string;
17
+ idToken: string;
18
+ /** When this credential was last refreshed; strictly increasing across refreshes. */
19
+ lastRefreshAt?: string;
20
+ }
21
+ /** Access to one ChatGPT workspace, with the workspace and residency its issuer states. */
22
+ export interface IOpenAiAccess {
23
+ accessToken: string;
24
+ accountId: string;
25
+ isFedrampAccount: boolean;
26
+ }
27
+ /** What a sign-in's claims say about its account; no token. */
28
+ export interface IOpenAiAccountSummary {
29
+ providerId: 'openai';
30
+ authKind: 'chatgptOAuth';
31
+ accountId?: string;
32
+ email?: string;
33
+ plan?: string;
34
+ }
35
+ /** What the person signing in does: open the URL and enter the code. */
36
+ export interface IOpenAiDevicePrompt {
37
+ flow: 'device';
38
+ verificationUrl: string;
39
+ userCode: string;
40
+ }
41
+ export interface IOpenAiLoginResult {
42
+ credential: IOpenAiOAuthCredential;
43
+ account: IOpenAiAccountSummary;
44
+ }
45
+ export type TOpenAiOperationErrorCode = 'ABORTED' | 'TIMEOUT';
46
+ export interface IOpenAiRefreshSuccess {
47
+ success: true;
48
+ credential: IOpenAiOAuthCredential;
49
+ account: IOpenAiAccountSummary;
50
+ }
51
+ export interface IOpenAiRefreshFailure {
52
+ success: false;
53
+ credential: IOpenAiOAuthCredential;
54
+ errorCode: TOpenAiOperationErrorCode | 'REFRESH_FAILED';
55
+ /** Never replay a rotating grant when this is `outcomeUnknown`. */
56
+ requestOutcome: TOpenAiRequestOutcome;
57
+ /** The response status, when an HTTP response was observed. */
58
+ responseStatus?: number;
59
+ /** Bounded Retry-After delay from the observed response. */
60
+ retryAfterMs?: number;
61
+ }
62
+ export type TOpenAiRefreshResult = IOpenAiRefreshSuccess | IOpenAiRefreshFailure;
@@ -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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2lnbmluLmludGVyZmFjZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90c19zaWduaW4vc2lnbmluLmludGVyZmFjZXMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsMkpBQTJKIn0=
@@ -0,0 +1,93 @@
1
+ import type { TOpenAiRequestOutcome } from './signin.interfaces.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`), for the one party that signs an account in and refreshes it: the device
5
+ * code, its poll, the authorization-code exchange, the refresh-token grant, the revocation and the claims of the
6
+ * 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
+ /** How long a device code lives: Codex polls it for fifteen minutes and tells the person it expires then. */
11
+ export declare const OPENAI_DEVICE_CODE_LIFETIME_MS: number;
12
+ export declare class OpenAiAuthError extends Error {
13
+ readonly status?: number;
14
+ readonly requestOutcome?: TOpenAiRequestOutcome;
15
+ readonly retryAfterMs?: number;
16
+ constructor(message: string, options?: {
17
+ status?: number;
18
+ requestOutcome?: TOpenAiRequestOutcome;
19
+ retryAfterMs?: number;
20
+ });
21
+ }
22
+ export interface IOpenAiAuthOptions {
23
+ fetch?: typeof fetch;
24
+ /** Aborts network requests and device-code polling. */
25
+ signal?: AbortSignal;
26
+ }
27
+ export interface IOpenAiDeviceCodePollOptions extends IOpenAiAuthOptions {
28
+ timeoutMs?: number;
29
+ sleep?: (ms: number) => Promise<void>;
30
+ }
31
+ /** What the claims of a ChatGPT token say about its account; never the token itself. */
32
+ export interface IOpenAiTokenClaims {
33
+ email?: string;
34
+ chatgptPlanType?: string;
35
+ chatgptUserId?: string;
36
+ chatgptAccountId?: string;
37
+ chatgptAccountIsFedramp: boolean;
38
+ expiresAt?: string;
39
+ }
40
+ export interface IOpenAiDeviceCode {
41
+ verificationUrl: string;
42
+ userCode: string;
43
+ deviceAuthId: string;
44
+ intervalSeconds: number;
45
+ }
46
+ export interface IOpenAiDeviceAuthorization {
47
+ authorizationCode: string;
48
+ codeChallenge: string;
49
+ codeVerifier: string;
50
+ }
51
+ /** The tokens one exchange or refresh produced, with the claims of the ID token (or access token). */
52
+ export interface IOpenAiTokenSet {
53
+ accessToken: string;
54
+ refreshToken: string;
55
+ idToken?: string;
56
+ claims: IOpenAiTokenClaims;
57
+ }
58
+ /** Reads the account claims of a ChatGPT ID or access token. Throws `OpenAiAuthError` for anything but a JWT. */
59
+ export declare const parseOpenAiTokenClaims: (token: string) => IOpenAiTokenClaims;
60
+ /** Starts a device sign-in (`POST {issuer}/api/accounts/deviceauth/usercode`). */
61
+ export declare const requestOpenAiDeviceCode: (options?: IOpenAiAuthOptions) => Promise<IOpenAiDeviceCode>;
62
+ /** What one poll of a device sign-in found: the person has not approved it yet, or has, with its authorization. */
63
+ export type TOpenAiDeviceCodePoll = {
64
+ status: 'pending';
65
+ } | {
66
+ status: 'approved';
67
+ authorization: IOpenAiDeviceAuthorization;
68
+ };
69
+ /**
70
+ * Asks once whether the person approved the sign-in (`POST {issuer}/api/accounts/deviceauth/token`): 403 and 404
71
+ * mean pending, as in Codex. `timeoutMs` bounds the one request (at most thirty seconds). The authorization it
72
+ * answers is single-use, so one sign-in is polled by one caller at a time.
73
+ */
74
+ export declare const pollOpenAiDeviceCodeOnce: (deviceCode: IOpenAiDeviceCode, options?: IOpenAiAuthOptions & {
75
+ timeoutMs?: number;
76
+ }) => Promise<TOpenAiDeviceCodePoll>;
77
+ /**
78
+ * Polls until the person approved the sign-in, at the interval the service asked for, and gives up after at most
79
+ * fifteen minutes, as Codex does.
80
+ */
81
+ export declare const pollOpenAiDeviceCode: (deviceCode: IOpenAiDeviceCode, options?: IOpenAiDeviceCodePollOptions) => Promise<IOpenAiDeviceAuthorization>;
82
+ /** Exchanges an approved device sign-in for tokens (`POST {issuer}/oauth/token`, PKCE, form-encoded). */
83
+ export declare const exchangeOpenAiDeviceAuthorization: (authorization: IOpenAiDeviceAuthorization, options?: IOpenAiAuthOptions) => Promise<IOpenAiTokenSet>;
84
+ /**
85
+ * Sends one refresh-token grant (`POST {issuer}/oauth/token`, JSON). A response without a new refresh token keeps
86
+ * the one that was sent, as Codex does.
87
+ */
88
+ export declare const refreshOpenAiTokens: (tokens: IOpenAiTokenSet, options?: IOpenAiAuthOptions) => Promise<IOpenAiTokenSet>;
89
+ /**
90
+ * Revokes a refresh token (`POST {issuer}/oauth/revoke`, JSON), as Codex does when it logs out: the grant then
91
+ * refreshes nothing anywhere. It resolves only once the service accepted the revocation.
92
+ */
93
+ export declare const revokeOpenAiRefreshToken: (refreshToken: string, options?: IOpenAiAuthOptions) => Promise<void>;