@tokensrc/codex 1.14.11 → 1.14.13

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,373 @@
1
+ import { type KeyObject } from "node:crypto";
2
+ import { z } from "zod";
3
+ import { CodexV5CreateDeviceSessionResponseSchema } from "./protocol.js";
4
+ export declare const CodexV5SessionStateSchema: z.ZodObject<{
5
+ schemaVersion: z.ZodLiteral<1>;
6
+ tenantId: z.ZodString;
7
+ subject: z.ZodString;
8
+ assignmentId: z.ZodString;
9
+ managedAccountId: z.ZodString;
10
+ providerAccountId: z.ZodString;
11
+ lineageId: z.ZodString;
12
+ installationId: z.ZodString;
13
+ sessionId: z.ZodString;
14
+ authorityEpoch: z.ZodNumber;
15
+ generationVersion: z.ZodNumber;
16
+ leaseExpiresAt: z.ZodString;
17
+ releaseIdempotencyKey: z.ZodString;
18
+ status: z.ZodEnum<{
19
+ ACTIVE: "ACTIVE";
20
+ RECOVERY_REQUIRED: "RECOVERY_REQUIRED";
21
+ }>;
22
+ updatedAt: z.ZodString;
23
+ }, z.core.$strict>;
24
+ export declare const CodexV5AcquireJournalSchema: z.ZodObject<{
25
+ schemaVersion: z.ZodLiteral<1>;
26
+ tenantId: z.ZodString;
27
+ subject: z.ZodString;
28
+ assignmentId: z.ZodString;
29
+ expectedManagedAccountId: z.ZodString;
30
+ expectedProviderAccountId: z.ZodString;
31
+ expectedLineageId: z.ZodString;
32
+ installationId: z.ZodString;
33
+ clientRequestId: z.ZodString;
34
+ idempotencyKey: z.ZodString;
35
+ ackIdempotencyKey: z.ZodString;
36
+ releaseIdempotencyKey: z.ZodString;
37
+ clientKey: z.ZodObject<{
38
+ version: z.ZodLiteral<1>;
39
+ algorithm: z.ZodLiteral<"X25519-HKDF-SHA256-AES-256-GCM">;
40
+ publicKey: z.ZodString;
41
+ }, z.core.$strict>;
42
+ privateKeyPkcs8: z.ZodString;
43
+ response: z.ZodNullable<z.ZodObject<{
44
+ schemaVersion: z.ZodLiteral<5>;
45
+ session: z.ZodObject<{
46
+ id: z.ZodString;
47
+ clientRequestId: z.ZodString;
48
+ installationId: z.ZodString;
49
+ assignmentId: z.ZodString;
50
+ managedAccountId: z.ZodString;
51
+ providerAccountId: z.ZodString;
52
+ lineageId: z.ZodString;
53
+ generationVersion: z.ZodNumber;
54
+ issuedAt: z.ZodString;
55
+ leaseExpiresAt: z.ZodString;
56
+ status: z.ZodEnum<{
57
+ ACTIVE: "ACTIVE";
58
+ AWAITING_ACK: "AWAITING_ACK";
59
+ }>;
60
+ authorityEpoch: z.ZodNumber;
61
+ envelope: z.ZodObject<{
62
+ version: z.ZodLiteral<1>;
63
+ algorithm: z.ZodLiteral<"X25519-HKDF-SHA256-AES-256-GCM">;
64
+ ephemeralPublicKey: z.ZodString;
65
+ salt: z.ZodString;
66
+ nonce: z.ZodString;
67
+ ciphertext: z.ZodString;
68
+ authenticationTag: z.ZodString;
69
+ }, z.core.$strict>;
70
+ }, z.core.$strict>;
71
+ replayed: z.ZodBoolean;
72
+ }, z.core.$strict>>;
73
+ createdAt: z.ZodString;
74
+ updatedAt: z.ZodString;
75
+ }, z.core.$strict>;
76
+ export declare const CodexV5ReportJournalSchema: z.ZodObject<{
77
+ schemaVersion: z.ZodLiteral<1>;
78
+ tenantId: z.ZodString;
79
+ subject: z.ZodString;
80
+ lineageId: z.ZodString;
81
+ installationId: z.ZodString;
82
+ sessionId: z.ZodString;
83
+ authorityEpoch: z.ZodNumber;
84
+ clientRequestId: z.ZodString;
85
+ idempotencyKey: z.ZodString;
86
+ expectedGenerationVersion: z.ZodNumber;
87
+ rotationMode: z.ZodEnum<{
88
+ RETAINED: "RETAINED";
89
+ ROTATED: "ROTATED";
90
+ }>;
91
+ envelope: z.ZodObject<{
92
+ version: z.ZodLiteral<1>;
93
+ algorithm: z.ZodLiteral<"X25519-HKDF-SHA256-AES-256-GCM">;
94
+ keyId: z.ZodString;
95
+ ephemeralPublicKey: z.ZodString;
96
+ salt: z.ZodString;
97
+ nonce: z.ZodString;
98
+ ciphertext: z.ZodString;
99
+ authenticationTag: z.ZodString;
100
+ }, z.core.$strict>;
101
+ accessTokenHealth: z.ZodEnum<{
102
+ EXPIRED: "EXPIRED";
103
+ HEALTHY: "HEALTHY";
104
+ REJECTED: "REJECTED";
105
+ UNKNOWN: "UNKNOWN";
106
+ }>;
107
+ refreshTokenHealth: z.ZodEnum<{
108
+ HEALTHY: "HEALTHY";
109
+ REJECTED: "REJECTED";
110
+ UNKNOWN: "UNKNOWN";
111
+ }>;
112
+ observedAt: z.ZodString;
113
+ credentialExpiresAt: z.ZodString;
114
+ accessTokenDigest: z.ZodString;
115
+ refreshTokenDigest: z.ZodString;
116
+ idTokenDigest: z.ZodString;
117
+ createdAt: z.ZodString;
118
+ updatedAt: z.ZodString;
119
+ }, z.core.$strict>;
120
+ export type CodexV5SessionState = z.infer<typeof CodexV5SessionStateSchema>;
121
+ export type CodexV5AcquireJournal = z.infer<typeof CodexV5AcquireJournalSchema>;
122
+ export type CodexV5ReportJournal = z.infer<typeof CodexV5ReportJournalSchema>;
123
+ export declare function getOrCreateCodexInstallationId(env?: NodeJS.ProcessEnv, now?: number, newId?: () => string): Promise<string>;
124
+ export declare function readCodexV5SessionState(env?: NodeJS.ProcessEnv): Promise<{
125
+ schemaVersion: 1;
126
+ tenantId: string;
127
+ subject: string;
128
+ assignmentId: string;
129
+ managedAccountId: string;
130
+ providerAccountId: string;
131
+ lineageId: string;
132
+ installationId: string;
133
+ sessionId: string;
134
+ authorityEpoch: number;
135
+ generationVersion: number;
136
+ leaseExpiresAt: string;
137
+ releaseIdempotencyKey: string;
138
+ status: "ACTIVE" | "RECOVERY_REQUIRED";
139
+ updatedAt: string;
140
+ } | undefined>;
141
+ export declare function writeCodexV5SessionState(value: CodexV5SessionState, env?: NodeJS.ProcessEnv): Promise<{
142
+ schemaVersion: 1;
143
+ tenantId: string;
144
+ subject: string;
145
+ assignmentId: string;
146
+ managedAccountId: string;
147
+ providerAccountId: string;
148
+ lineageId: string;
149
+ installationId: string;
150
+ sessionId: string;
151
+ authorityEpoch: number;
152
+ generationVersion: number;
153
+ leaseExpiresAt: string;
154
+ releaseIdempotencyKey: string;
155
+ status: "ACTIVE" | "RECOVERY_REQUIRED";
156
+ updatedAt: string;
157
+ }>;
158
+ export declare function clearCodexV5SessionState(expectedSessionId: string, env?: NodeJS.ProcessEnv): Promise<void>;
159
+ export declare function readCodexV5AcquireJournal(env?: NodeJS.ProcessEnv): Promise<{
160
+ schemaVersion: 1;
161
+ tenantId: string;
162
+ subject: string;
163
+ assignmentId: string;
164
+ expectedManagedAccountId: string;
165
+ expectedProviderAccountId: string;
166
+ expectedLineageId: string;
167
+ installationId: string;
168
+ clientRequestId: string;
169
+ idempotencyKey: string;
170
+ ackIdempotencyKey: string;
171
+ releaseIdempotencyKey: string;
172
+ clientKey: {
173
+ version: 1;
174
+ algorithm: "X25519-HKDF-SHA256-AES-256-GCM";
175
+ publicKey: string;
176
+ };
177
+ privateKeyPkcs8: string;
178
+ response: {
179
+ schemaVersion: 5;
180
+ session: {
181
+ id: string;
182
+ clientRequestId: string;
183
+ installationId: string;
184
+ assignmentId: string;
185
+ managedAccountId: string;
186
+ providerAccountId: string;
187
+ lineageId: string;
188
+ generationVersion: number;
189
+ issuedAt: string;
190
+ leaseExpiresAt: string;
191
+ status: "ACTIVE" | "AWAITING_ACK";
192
+ authorityEpoch: number;
193
+ envelope: {
194
+ version: 1;
195
+ algorithm: "X25519-HKDF-SHA256-AES-256-GCM";
196
+ ephemeralPublicKey: string;
197
+ salt: string;
198
+ nonce: string;
199
+ ciphertext: string;
200
+ authenticationTag: string;
201
+ };
202
+ };
203
+ replayed: boolean;
204
+ } | null;
205
+ createdAt: string;
206
+ updatedAt: string;
207
+ } | undefined>;
208
+ export declare function writeCodexV5AcquireJournal(value: CodexV5AcquireJournal, env?: NodeJS.ProcessEnv): Promise<{
209
+ schemaVersion: 1;
210
+ tenantId: string;
211
+ subject: string;
212
+ assignmentId: string;
213
+ expectedManagedAccountId: string;
214
+ expectedProviderAccountId: string;
215
+ expectedLineageId: string;
216
+ installationId: string;
217
+ clientRequestId: string;
218
+ idempotencyKey: string;
219
+ ackIdempotencyKey: string;
220
+ releaseIdempotencyKey: string;
221
+ clientKey: {
222
+ version: 1;
223
+ algorithm: "X25519-HKDF-SHA256-AES-256-GCM";
224
+ publicKey: string;
225
+ };
226
+ privateKeyPkcs8: string;
227
+ response: {
228
+ schemaVersion: 5;
229
+ session: {
230
+ id: string;
231
+ clientRequestId: string;
232
+ installationId: string;
233
+ assignmentId: string;
234
+ managedAccountId: string;
235
+ providerAccountId: string;
236
+ lineageId: string;
237
+ generationVersion: number;
238
+ issuedAt: string;
239
+ leaseExpiresAt: string;
240
+ status: "ACTIVE" | "AWAITING_ACK";
241
+ authorityEpoch: number;
242
+ envelope: {
243
+ version: 1;
244
+ algorithm: "X25519-HKDF-SHA256-AES-256-GCM";
245
+ ephemeralPublicKey: string;
246
+ salt: string;
247
+ nonce: string;
248
+ ciphertext: string;
249
+ authenticationTag: string;
250
+ };
251
+ };
252
+ replayed: boolean;
253
+ } | null;
254
+ createdAt: string;
255
+ updatedAt: string;
256
+ }>;
257
+ export declare function updateCodexV5AcquireJournalResponse(expected: CodexV5AcquireJournal, response: z.infer<typeof CodexV5CreateDeviceSessionResponseSchema>, now: number, env?: NodeJS.ProcessEnv): Promise<{
258
+ schemaVersion: 1;
259
+ tenantId: string;
260
+ subject: string;
261
+ assignmentId: string;
262
+ expectedManagedAccountId: string;
263
+ expectedProviderAccountId: string;
264
+ expectedLineageId: string;
265
+ installationId: string;
266
+ clientRequestId: string;
267
+ idempotencyKey: string;
268
+ ackIdempotencyKey: string;
269
+ releaseIdempotencyKey: string;
270
+ clientKey: {
271
+ version: 1;
272
+ algorithm: "X25519-HKDF-SHA256-AES-256-GCM";
273
+ publicKey: string;
274
+ };
275
+ privateKeyPkcs8: string;
276
+ response: {
277
+ schemaVersion: 5;
278
+ session: {
279
+ id: string;
280
+ clientRequestId: string;
281
+ installationId: string;
282
+ assignmentId: string;
283
+ managedAccountId: string;
284
+ providerAccountId: string;
285
+ lineageId: string;
286
+ generationVersion: number;
287
+ issuedAt: string;
288
+ leaseExpiresAt: string;
289
+ status: "ACTIVE" | "AWAITING_ACK";
290
+ authorityEpoch: number;
291
+ envelope: {
292
+ version: 1;
293
+ algorithm: "X25519-HKDF-SHA256-AES-256-GCM";
294
+ ephemeralPublicKey: string;
295
+ salt: string;
296
+ nonce: string;
297
+ ciphertext: string;
298
+ authenticationTag: string;
299
+ };
300
+ };
301
+ replayed: boolean;
302
+ } | null;
303
+ createdAt: string;
304
+ updatedAt: string;
305
+ }>;
306
+ export declare function clearCodexV5AcquireJournal(expected: Pick<CodexV5AcquireJournal, "clientRequestId" | "idempotencyKey">, env?: NodeJS.ProcessEnv): Promise<void>;
307
+ export declare function openCodexV5AcquireJournalKey(journal: CodexV5AcquireJournal): KeyObject;
308
+ export declare function readCodexV5ReportJournal(env?: NodeJS.ProcessEnv): Promise<{
309
+ schemaVersion: 1;
310
+ tenantId: string;
311
+ subject: string;
312
+ lineageId: string;
313
+ installationId: string;
314
+ sessionId: string;
315
+ authorityEpoch: number;
316
+ clientRequestId: string;
317
+ idempotencyKey: string;
318
+ expectedGenerationVersion: number;
319
+ rotationMode: "RETAINED" | "ROTATED";
320
+ envelope: {
321
+ version: 1;
322
+ algorithm: "X25519-HKDF-SHA256-AES-256-GCM";
323
+ keyId: string;
324
+ ephemeralPublicKey: string;
325
+ salt: string;
326
+ nonce: string;
327
+ ciphertext: string;
328
+ authenticationTag: string;
329
+ };
330
+ accessTokenHealth: "EXPIRED" | "HEALTHY" | "REJECTED" | "UNKNOWN";
331
+ refreshTokenHealth: "HEALTHY" | "REJECTED" | "UNKNOWN";
332
+ observedAt: string;
333
+ credentialExpiresAt: string;
334
+ accessTokenDigest: string;
335
+ refreshTokenDigest: string;
336
+ idTokenDigest: string;
337
+ createdAt: string;
338
+ updatedAt: string;
339
+ } | undefined>;
340
+ export declare function writeCodexV5ReportJournal(value: CodexV5ReportJournal, env?: NodeJS.ProcessEnv): Promise<{
341
+ schemaVersion: 1;
342
+ tenantId: string;
343
+ subject: string;
344
+ lineageId: string;
345
+ installationId: string;
346
+ sessionId: string;
347
+ authorityEpoch: number;
348
+ clientRequestId: string;
349
+ idempotencyKey: string;
350
+ expectedGenerationVersion: number;
351
+ rotationMode: "RETAINED" | "ROTATED";
352
+ envelope: {
353
+ version: 1;
354
+ algorithm: "X25519-HKDF-SHA256-AES-256-GCM";
355
+ keyId: string;
356
+ ephemeralPublicKey: string;
357
+ salt: string;
358
+ nonce: string;
359
+ ciphertext: string;
360
+ authenticationTag: string;
361
+ };
362
+ accessTokenHealth: "EXPIRED" | "HEALTHY" | "REJECTED" | "UNKNOWN";
363
+ refreshTokenHealth: "HEALTHY" | "REJECTED" | "UNKNOWN";
364
+ observedAt: string;
365
+ credentialExpiresAt: string;
366
+ accessTokenDigest: string;
367
+ refreshTokenDigest: string;
368
+ idTokenDigest: string;
369
+ createdAt: string;
370
+ updatedAt: string;
371
+ }>;
372
+ export declare function clearCodexV5ReportJournal(expected: Pick<CodexV5ReportJournal, "clientRequestId" | "idempotencyKey">, env?: NodeJS.ProcessEnv): Promise<void>;
373
+ export declare function exportCodexV5PrivateKey(privateKey: KeyObject): string;
@@ -0,0 +1,218 @@
1
+ import { createPrivateKey, randomUUID } from "node:crypto";
2
+ import { homedir } from "node:os";
3
+ import { join } from "node:path";
4
+ import { z } from "zod";
5
+ import { CodexShortLivedDeliveryClientKeySchema, CodexV3AccessTokenHealthSchema, CodexV3CredentialEnvelopeSchema, CodexV3RefreshTokenHealthSchema, CodexV5CreateDeviceSessionResponseSchema } from "./protocol.js";
6
+ import { readJsonIfExists, removePrivateFileDurably, withPrivateFileLock, writePrivateJson } from "./private-file.js";
7
+ const Instant = z.string().datetime({ offset: true });
8
+ const Id = z.string().min(1).max(512);
9
+ const Stable = z.string().min(8).max(255);
10
+ const Digest = z.string().length(64).regex(/^[0-9a-f]{64}$/);
11
+ const InstallationId = z.string().min(16).max(200).regex(/^[A-Za-z0-9][A-Za-z0-9._:-]+$/);
12
+ const InstallationSchema = z.strictObject({
13
+ schemaVersion: z.literal(1), installationId: InstallationId, createdAt: Instant
14
+ });
15
+ export const CodexV5SessionStateSchema = z.strictObject({
16
+ schemaVersion: z.literal(1),
17
+ tenantId: Id,
18
+ subject: Id,
19
+ assignmentId: Id,
20
+ managedAccountId: Id,
21
+ providerAccountId: Id,
22
+ lineageId: Id,
23
+ installationId: InstallationId,
24
+ sessionId: Id,
25
+ authorityEpoch: z.number().int().positive(),
26
+ generationVersion: z.number().int().positive(),
27
+ leaseExpiresAt: Instant,
28
+ releaseIdempotencyKey: Stable,
29
+ status: z.enum(["ACTIVE", "RECOVERY_REQUIRED"]),
30
+ updatedAt: Instant
31
+ });
32
+ export const CodexV5AcquireJournalSchema = z.strictObject({
33
+ schemaVersion: z.literal(1),
34
+ tenantId: Id,
35
+ subject: Id,
36
+ assignmentId: Id,
37
+ expectedManagedAccountId: Id,
38
+ expectedProviderAccountId: Id,
39
+ expectedLineageId: Id,
40
+ installationId: InstallationId,
41
+ clientRequestId: Stable,
42
+ idempotencyKey: Stable,
43
+ ackIdempotencyKey: Stable,
44
+ releaseIdempotencyKey: Stable,
45
+ clientKey: CodexShortLivedDeliveryClientKeySchema,
46
+ privateKeyPkcs8: z.string().min(1).max(512).regex(/^[A-Za-z0-9_-]+$/),
47
+ response: CodexV5CreateDeviceSessionResponseSchema.nullable(),
48
+ createdAt: Instant,
49
+ updatedAt: Instant
50
+ });
51
+ export const CodexV5ReportJournalSchema = z.strictObject({
52
+ schemaVersion: z.literal(1),
53
+ tenantId: Id,
54
+ subject: Id,
55
+ lineageId: Id,
56
+ installationId: InstallationId,
57
+ sessionId: Id,
58
+ authorityEpoch: z.number().int().positive(),
59
+ clientRequestId: Stable,
60
+ idempotencyKey: Stable,
61
+ expectedGenerationVersion: z.number().int().positive(),
62
+ rotationMode: z.enum(["ROTATED", "RETAINED"]),
63
+ envelope: CodexV3CredentialEnvelopeSchema,
64
+ accessTokenHealth: CodexV3AccessTokenHealthSchema,
65
+ refreshTokenHealth: CodexV3RefreshTokenHealthSchema,
66
+ observedAt: Instant,
67
+ credentialExpiresAt: Instant,
68
+ accessTokenDigest: Digest,
69
+ refreshTokenDigest: Digest,
70
+ idTokenDigest: Digest,
71
+ createdAt: Instant,
72
+ updatedAt: Instant
73
+ });
74
+ function root(env) {
75
+ return env.CODEX_HOME?.trim() || join(homedir(), ".codex");
76
+ }
77
+ function installationPath(env) { return join(root(env), ".numa-installation.json"); }
78
+ function sessionPath(env) { return join(root(env), ".numa-device-session-v5.json"); }
79
+ function acquirePath(env) { return join(root(env), ".numa-device-acquire-v5.json"); }
80
+ function reportPath(env) { return join(root(env), ".numa-device-report-v5.json"); }
81
+ export async function getOrCreateCodexInstallationId(env = process.env, now = Date.now(), newId = randomUUID) {
82
+ const target = installationPath(env);
83
+ return withPrivateFileLock(target, async () => {
84
+ const current = await readJsonIfExists(target);
85
+ if (current !== undefined)
86
+ return InstallationSchema.parse(current).installationId;
87
+ const value = InstallationSchema.parse({ schemaVersion: 1,
88
+ installationId: `install-${newId()}`, createdAt: new Date(now).toISOString() });
89
+ await writePrivateJson(target, value);
90
+ return value.installationId;
91
+ });
92
+ }
93
+ async function readParsed(path, schema) {
94
+ const raw = await readJsonIfExists(path);
95
+ return raw === undefined ? undefined : schema.parse(raw);
96
+ }
97
+ export function readCodexV5SessionState(env = process.env) {
98
+ return readParsed(sessionPath(env), CodexV5SessionStateSchema);
99
+ }
100
+ export async function writeCodexV5SessionState(value, env = process.env) {
101
+ const target = sessionPath(env);
102
+ return withPrivateFileLock(target, async () => {
103
+ const parsed = CodexV5SessionStateSchema.parse(value);
104
+ await writePrivateJson(target, parsed);
105
+ return parsed;
106
+ });
107
+ }
108
+ export async function clearCodexV5SessionState(expectedSessionId, env = process.env) {
109
+ const target = sessionPath(env);
110
+ await withPrivateFileLock(target, async () => {
111
+ const current = await readParsed(target, CodexV5SessionStateSchema);
112
+ if (!current)
113
+ return;
114
+ if (current.sessionId !== expectedSessionId)
115
+ throw stateConflict();
116
+ await removePrivateFileDurably(target);
117
+ });
118
+ }
119
+ export function readCodexV5AcquireJournal(env = process.env) {
120
+ return readParsed(acquirePath(env), CodexV5AcquireJournalSchema);
121
+ }
122
+ export async function writeCodexV5AcquireJournal(value, env = process.env) {
123
+ const target = acquirePath(env);
124
+ return withPrivateFileLock(target, async () => {
125
+ const parsed = CodexV5AcquireJournalSchema.parse(value);
126
+ const current = await readParsed(target, CodexV5AcquireJournalSchema);
127
+ if (current && JSON.stringify(current) !== JSON.stringify(parsed))
128
+ throw stateConflict();
129
+ if (!current)
130
+ await writePrivateJson(target, parsed);
131
+ return current ?? parsed;
132
+ });
133
+ }
134
+ export async function updateCodexV5AcquireJournalResponse(expected, response, now, env = process.env) {
135
+ const target = acquirePath(env);
136
+ return withPrivateFileLock(target, async () => {
137
+ const current = await readParsed(target, CodexV5AcquireJournalSchema);
138
+ if (!current || current.clientRequestId !== expected.clientRequestId
139
+ || current.idempotencyKey !== expected.idempotencyKey)
140
+ throw stateConflict();
141
+ const updated = CodexV5AcquireJournalSchema.parse({ ...current, response,
142
+ updatedAt: new Date(now).toISOString() });
143
+ await writePrivateJson(target, updated);
144
+ return updated;
145
+ });
146
+ }
147
+ export async function clearCodexV5AcquireJournal(expected, env = process.env) {
148
+ const target = acquirePath(env);
149
+ await withPrivateFileLock(target, async () => {
150
+ const current = await readParsed(target, CodexV5AcquireJournalSchema);
151
+ if (!current)
152
+ return;
153
+ if (current.clientRequestId !== expected.clientRequestId
154
+ || current.idempotencyKey !== expected.idempotencyKey)
155
+ throw stateConflict();
156
+ await removePrivateFileDurably(target);
157
+ });
158
+ }
159
+ export function openCodexV5AcquireJournalKey(journal) {
160
+ const encoded = Buffer.from(journal.privateKeyPkcs8, "base64url");
161
+ try {
162
+ if (encoded.toString("base64url") !== journal.privateKeyPkcs8)
163
+ throw stateConflict();
164
+ const key = createPrivateKey({ key: encoded, format: "der", type: "pkcs8" });
165
+ if (key.asymmetricKeyType !== "x25519")
166
+ throw stateConflict();
167
+ return key;
168
+ }
169
+ finally {
170
+ encoded.fill(0);
171
+ }
172
+ }
173
+ export function readCodexV5ReportJournal(env = process.env) {
174
+ return readParsed(reportPath(env), CodexV5ReportJournalSchema);
175
+ }
176
+ export async function writeCodexV5ReportJournal(value, env = process.env) {
177
+ const target = reportPath(env);
178
+ return withPrivateFileLock(target, async () => {
179
+ const parsed = CodexV5ReportJournalSchema.parse(value);
180
+ const current = await readParsed(target, CodexV5ReportJournalSchema);
181
+ if (current && JSON.stringify(current) !== JSON.stringify(parsed))
182
+ throw stateConflict();
183
+ if (!current)
184
+ await writePrivateJson(target, parsed);
185
+ return current ?? parsed;
186
+ });
187
+ }
188
+ export async function clearCodexV5ReportJournal(expected, env = process.env) {
189
+ const target = reportPath(env);
190
+ await withPrivateFileLock(target, async () => {
191
+ const current = await readParsed(target, CodexV5ReportJournalSchema);
192
+ if (!current)
193
+ return;
194
+ if (current.clientRequestId !== expected.clientRequestId
195
+ || current.idempotencyKey !== expected.idempotencyKey)
196
+ throw stateConflict();
197
+ await removePrivateFileDurably(target);
198
+ });
199
+ }
200
+ export function exportCodexV5PrivateKey(privateKey) {
201
+ if (privateKey.asymmetricKeyType !== "x25519")
202
+ throw stateConflict();
203
+ const encoded = privateKey.export({ format: "der", type: "pkcs8" });
204
+ if (!Buffer.isBuffer(encoded))
205
+ throw stateConflict();
206
+ try {
207
+ return encoded.toString("base64url");
208
+ }
209
+ finally {
210
+ encoded.fill(0);
211
+ }
212
+ }
213
+ function stateConflict() {
214
+ return Object.assign(new Error("The Codex v5 device state changed unexpectedly."), {
215
+ code: "managed_codex_v5_state_conflict"
216
+ });
217
+ }
218
+ //# sourceMappingURL=multi-device-v5-state.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"multi-device-v5-state.js","sourceRoot":"","sources":["../src/multi-device-v5-state.ts"],"names":[],"mappings":"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"}
package/dist/profile.d.ts CHANGED
@@ -24,6 +24,7 @@ export interface ResolvedCodexProfile {
24
24
  rotationSync: boolean;
25
25
  managedCredentialsV3?: boolean;
26
26
  accountTokenPoolV4?: boolean;
27
+ multiDeviceCredentialSync?: boolean;
27
28
  };
28
29
  stale: boolean;
29
30
  }
@@ -39,3 +40,4 @@ export interface ResolveCodexProfileOptions {
39
40
  export declare function resolveCodexProfile(options: ResolveCodexProfileOptions): Promise<ResolvedCodexProfile>;
40
41
  export declare function profileManagedCredentialsV3Enabled(value: unknown): boolean;
41
42
  export declare function profileAccountTokenPoolV4Enabled(value: unknown): boolean;
43
+ export declare function profileMultiDeviceCredentialSyncEnabled(value: unknown): boolean;
package/dist/profile.js CHANGED
@@ -27,7 +27,8 @@ const ServiceSchema = z.object({
27
27
  migrationPlans: z.boolean().optional(),
28
28
  rotationSync: z.boolean(),
29
29
  managedCredentialsV3: z.boolean().optional(),
30
- accountTokenPoolV4: z.boolean().optional()
30
+ accountTokenPoolV4: z.boolean().optional(),
31
+ multiDeviceCredentialSync: z.boolean().optional()
31
32
  }).passthrough().optional()
32
33
  }).passthrough().optional()
33
34
  });
@@ -108,6 +109,8 @@ export async function resolveCodexProfile(options) {
108
109
  || cachedProfile?.success === true && profileManagedCredentialsV3Enabled(cachedProfile.data);
109
110
  const accountTokenPoolV4Required = cached?.observedAccountTokenPoolV4 === true
110
111
  || cachedProfile?.success === true && profileAccountTokenPoolV4Enabled(cachedProfile.data);
112
+ const multiDeviceCredentialSyncRequired = cached?.observedMultiDeviceCredentialSync === true
113
+ || cachedProfile?.success === true && profileMultiDeviceCredentialSyncEnabled(cachedProfile.data);
111
114
  const cacheMaxAgeMs = cachedProfile?.success
112
115
  ? (cachedProfile.data.cache?.maxAgeSeconds ?? 300) * 1_000
113
116
  : 0;
@@ -156,6 +159,9 @@ export async function resolveCodexProfile(options) {
156
159
  if (accountTokenPoolV4Required && !profileAccountTokenPoolV4Enabled(next.data)) {
157
160
  throw new CodexError("Client configuration attempted to disable the previously observed v4 account token pool.", "profile_capability_downgrade");
158
161
  }
162
+ if (multiDeviceCredentialSyncRequired && !profileMultiDeviceCredentialSyncEnabled(next.data)) {
163
+ throw new CodexError("Client configuration attempted to disable previously observed multi-device credential fencing.", "profile_capability_downgrade");
164
+ }
159
165
  const previous = cached ? ProfileSchema.safeParse(cached.profile) : undefined;
160
166
  if (previous?.success && next.data.profileId === previous.data.profileId
161
167
  && next.data.revision < previous.data.revision) {
@@ -174,6 +180,9 @@ export async function resolveCodexProfile(options) {
174
180
  ...((accountTokenPoolV4Required || profileAccountTokenPoolV4Enabled(raw))
175
181
  ? { observedAccountTokenPoolV4: true }
176
182
  : {}),
183
+ ...((multiDeviceCredentialSyncRequired || profileMultiDeviceCredentialSyncEnabled(raw))
184
+ ? { observedMultiDeviceCredentialSync: true }
185
+ : {}),
177
186
  profile: raw
178
187
  };
179
188
  }
@@ -202,6 +211,9 @@ export async function resolveCodexProfile(options) {
202
211
  if (accountTokenPoolV4Required && !profileAccountTokenPoolV4Enabled(profile.data)) {
203
212
  throw new CodexError("A cached profile cannot disable the previously observed v4 account token pool.", "profile_capability_downgrade");
204
213
  }
214
+ if (multiDeviceCredentialSyncRequired && !profileMultiDeviceCredentialSyncEnabled(profile.data)) {
215
+ throw new CodexError("A cached profile cannot disable previously observed multi-device credential fencing.", "profile_capability_downgrade");
216
+ }
205
217
  const minimumVersion = profile.data.minimumClientVersions?.tokensrcCodex;
206
218
  if (minimumVersion && compareVersions(PACKAGE_VERSION, minimumVersion) < 0) {
207
219
  throw new CodexError(`@tokensrc/codex ${minimumVersion} or newer is required by this profile.`, "client_upgrade_required");
@@ -277,6 +289,17 @@ export function profileAccountTokenPoolV4Enabled(value) {
277
289
  return parsed.success
278
290
  && parsed.data.services.codex?.capabilities?.userBoundRefreshTokens?.accountTokenPoolV4 === true;
279
291
  }
292
+ export function profileMultiDeviceCredentialSyncEnabled(value) {
293
+ if (value && typeof value === "object"
294
+ && value
295
+ .userBoundRefreshTokens?.multiDeviceCredentialSync === true) {
296
+ return true;
297
+ }
298
+ const parsed = ProfileSchema.safeParse(value);
299
+ return parsed.success
300
+ && parsed.data.services.codex?.capabilities?.userBoundRefreshTokens
301
+ ?.multiDeviceCredentialSync === true;
302
+ }
280
303
  function defaultProfileDirectory() {
281
304
  const configured = process.env.TOKENSRC_CODEX_CONFIG_DIR?.trim();
282
305
  if (configured)