@tokensrc/codex 1.14.16 → 1.14.18

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 (66) hide show
  1. package/README.md +73 -71
  2. package/dist/client.d.ts +21 -16
  3. package/dist/client.js +198 -116
  4. package/dist/client.js.map +1 -1
  5. package/dist/command-directory.js +3 -2
  6. package/dist/command-directory.js.map +1 -1
  7. package/dist/commands.d.ts +0 -1
  8. package/dist/commands.js +479 -273
  9. package/dist/commands.js.map +1 -1
  10. package/dist/credentials.d.ts +3 -75
  11. package/dist/credentials.js +2 -338
  12. package/dist/credentials.js.map +1 -1
  13. package/dist/index.d.ts +2 -8
  14. package/dist/index.js +2 -8
  15. package/dist/index.js.map +1 -1
  16. package/dist/managed-credential-v3-envelope.d.ts +38 -14
  17. package/dist/managed-credential-v3-envelope.js +116 -25
  18. package/dist/managed-credential-v3-envelope.js.map +1 -1
  19. package/dist/managed-credential-v3-flow.d.ts +0 -17
  20. package/dist/managed-credential-v3-flow.js +107 -110
  21. package/dist/managed-credential-v3-flow.js.map +1 -1
  22. package/dist/managed-credential-v3.d.ts +0 -8
  23. package/dist/managed-credential-v3.js +0 -23
  24. package/dist/managed-credential-v3.js.map +1 -1
  25. package/dist/profile.d.ts +2 -6
  26. package/dist/profile.js +26 -23
  27. package/dist/profile.js.map +1 -1
  28. package/dist/protocol.d.ts +1284 -799
  29. package/dist/protocol.js +494 -277
  30. package/dist/protocol.js.map +1 -1
  31. package/dist/request-bound-device-v6-flow.d.ts +42 -0
  32. package/dist/request-bound-device-v6-flow.js +403 -0
  33. package/dist/request-bound-device-v6-flow.js.map +1 -0
  34. package/dist/request-bound-device-v6-state.d.ts +397 -0
  35. package/dist/request-bound-device-v6-state.js +221 -0
  36. package/dist/request-bound-device-v6-state.js.map +1 -0
  37. package/dist/selection.d.ts +5 -0
  38. package/dist/selection.js +20 -2
  39. package/dist/selection.js.map +1 -1
  40. package/dist/token-pool-v4-upload-flow.js +5 -1
  41. package/dist/token-pool-v4-upload-flow.js.map +1 -1
  42. package/package.json +2 -2
  43. package/dist/credential-supervisor.d.ts +0 -17
  44. package/dist/credential-supervisor.js +0 -84
  45. package/dist/credential-supervisor.js.map +0 -1
  46. package/dist/enrollment-envelope.d.ts +0 -18
  47. package/dist/enrollment-envelope.js +0 -112
  48. package/dist/enrollment-envelope.js.map +0 -1
  49. package/dist/enrollment-flow.d.ts +0 -27
  50. package/dist/enrollment-flow.js +0 -224
  51. package/dist/enrollment-flow.js.map +0 -1
  52. package/dist/migration-login-batch.d.ts +0 -66
  53. package/dist/migration-login-batch.js +0 -202
  54. package/dist/migration-login-batch.js.map +0 -1
  55. package/dist/retirement-flow.d.ts +0 -38
  56. package/dist/retirement-flow.js +0 -78
  57. package/dist/retirement-flow.js.map +0 -1
  58. package/dist/short-lived-delivery-flow.d.ts +0 -41
  59. package/dist/short-lived-delivery-flow.js +0 -141
  60. package/dist/short-lived-delivery-flow.js.map +0 -1
  61. package/dist/short-lived-delivery-journal.d.ts +0 -34
  62. package/dist/short-lived-delivery-journal.js +0 -137
  63. package/dist/short-lived-delivery-journal.js.map +0 -1
  64. package/dist/short-lived-delivery.d.ts +0 -26
  65. package/dist/short-lived-delivery.js +0 -139
  66. package/dist/short-lived-delivery.js.map +0 -1
package/README.md CHANGED
@@ -10,7 +10,7 @@ npx @tokensrc/codex use
10
10
  npx @tokensrc/codex run
11
11
  ```
12
12
 
13
- The standalone command tree includes `login`, `logout`, `list`, `upload`, `use`,
13
+ The standalone command tree includes `login`, `logout`, `request`, `list`, `upload`, `use`,
14
14
  `run`, `app`, `auth-agent`, `enrollment`, `admin`, `shortcut`, `status`, and `reset`. The
15
15
  `admin accounts` subtree lists tenant accounts, shows redacted credential-version
16
16
  diagnostics, records explicit subscription renewals, and requests one server-side refresh; it never receives refresh
@@ -28,6 +28,50 @@ numa codex admin assignments bind acct_xxx keycloak-subject --default
28
28
  numa codex admin assignments unbind assignment_xxx
29
29
  ```
30
30
 
31
+ When discovery advertises `requestBoundDeviceCredentials: true`, v6 replaces
32
+ direct user/account assignments with a request and per-device binding model. A
33
+ request belongs to one Keycloak subject and may contain several bindings for
34
+ that same user. Every binding owns a distinct complete ChatGPT token set and
35
+ credential lineage; Numa never copies a refresh token between installations.
36
+
37
+ ```sh
38
+ numa codex request create --reason "项目开发" --until 2026-10-01T00:00:00+08:00 --devices 2
39
+ numa codex request list
40
+ numa codex request reconcile
41
+ numa codex request bindings request_xxx
42
+
43
+ numa codex admin requests list --expiring-within 30
44
+ numa codex admin requests review request_xxx --decision APPROVE --reason "审批通过" \
45
+ --version 0 --device-limit 2 --valid-from 2026-09-01T00:00:00+08:00 \
46
+ --valid-until 2026-10-01T00:00:00+08:00
47
+ numa codex admin requests bind-device request_xxx --installation install_xxx \
48
+ --device-label "Work Mac" --platform darwin --version 1 --pool-entry pool_xxx
49
+ numa codex admin requests replacement-candidates --within 30
50
+ numa codex admin requests replace-device-token request_xxx binding_xxx \
51
+ --version 2 --reason SUBSCRIPTION_EXPIRING \
52
+ --replace-before 2026-09-25T00:00:00+08:00 --pool-entry pool_new
53
+ ```
54
+
55
+ The first v6 reconciliation reads only the safe identifiers of an already
56
+ distributed local credential. The Server atomically converts it into one
57
+ approved migration request and one `LEGACY_AUTO_MIGRATED` binding; the existing
58
+ token set changes ownership but is not duplicated. A different installation for
59
+ the same user receives `codex_device_binding_required`, its installation ID, and
60
+ administrator-contact guidance. An administrator must bind a new PoolEntry with
61
+ an independent token set before that device becomes available.
62
+
63
+ Administrator request lists are ordered by nearest expiry. `--expiring-within`
64
+ uses the Server's `expiresBefore` filter and excludes terminal requests. Under
65
+ `replacement-candidates` identifies bindings whose `accountExpiresAt` or health
66
+ requires a successor. The old binding stays active while the successor receives
67
+ an independent PoolEntry/lineage; only the device's successful install ACK makes
68
+ the successor active and retires the old token set. A temporary delivery failure
69
+ therefore keeps a healthy old token set usable and retryable. Under
70
+ v6, managed `numa codex login` can only add a complete token set to the unbound
71
+ pool; direct `--assign-to`/`--assign-to-subject` flags and legacy assignment
72
+ mutations are disabled. The full Server transaction and migration invariants are
73
+ documented in `docs/superpowers/specs/2026-08-31-request-bound-device-token-sets-design.md`.
74
+
31
75
  An account whose `subscriptionStatus` is `EXPIRED`, or whose
32
76
  `subscriptionExpiresAt` has passed, is unavailable even when a cached OpenAI
33
77
  access token has a later JWT expiry. Renewal requires a strictly later,
@@ -48,80 +92,38 @@ delivery-eligible and credential/device-session endpoints reject it with
48
92
  `codex_account_expired`; after renewal it becomes eligible only when its
49
93
  credential lineage is otherwise healthy.
50
94
 
51
- Tenant administrators complete a server-created account discovery or assignment
52
- enrollment with one isolated official Codex login:
95
+ Credential expiry is independent from subscription expiry. The legacy Server
96
+ error `client_credential_expired` is normalized to
97
+ `codex_account_needs_reauth`, never `codex_account_expired`. On an explicit 409
98
+ reauthentication decision, the client removes only the exact rejected delivery
99
+ recovery journal. Network failures, 5xx responses, and unknown mutation
100
+ outcomes retain that journal for idempotent recovery.
101
+
102
+ For an active subscription with `credentialStatus=NEEDS_REAUTH`, an
103
+ administrator replaces the credential with a fresh isolated official login,
104
+ targeted to the affected Numa username or exact directory email:
53
105
 
54
106
  ```sh
55
- numa codex enrollment status intent_xxx
56
- numa codex enrollment login intent_xxx
57
- numa codex enrollment login intent_xxx --device-auth
58
- numa codex enrollment login-batch migration_plan_xxx --dry-run
59
- numa codex enrollment login-batch migration_plan_xxx
60
- numa codex enrollment cancel intent_xxx
61
- numa codex retirement acknowledge retirement_xxx
107
+ numa codex admin accounts credential-versions acct_xxx --json
108
+ numa codex admin assignments list --json
109
+ numa codex login --assign-to affected-user
62
110
  ```
63
111
 
64
- `enrollment login` refuses to start until the service advertises encrypted
65
- candidate ingress. It claims the intent, maintains its heartbeat, runs the
66
- official login in a temporary `CODEX_HOME`, and uploads only an authenticated
67
- X25519/AES-GCM refresh-token envelope bound to the tenant, intent, revision, and
68
- idempotency key. Provider account identity and access/ID tokens are not accepted
69
- by the upload contract, and the temporary login directory is removed afterward.
70
- Transport failures and HTTP 5xx responses replay the exact same encrypted body,
71
- intent revision, and idempotency key a bounded number of times. A Server-confirmed
72
- `TEMPORARILY_UNAVAILABLE` result is different: while the same isolated login still
73
- holds the credential, Numa may follow the returned revision and create the next
74
- idempotent candidate attempt. If the final upload result remains uncertain, Numa
75
- reads only intent metadata and refuses a new login or upload key until the Server
76
- reports a terminal result.
77
-
78
- `enrollment login-batch` is available only when discovery advertises
79
- `migrationPlans: true` and the Bearer principal has the tenant-admin role. It
80
- pages the Server-owned queue, executes `LOGIN`/`AWAITING_CLI` targets one at a
81
- time, and reloads the plan after every target. A response-lost `CLAIMED` or
82
- `LOGIN_IN_PROGRESS` target is resumed only after the Server proves that the
83
- current Bearer is the same claimant; another claimant is never taken over.
84
- Other `VIEW_ENROLLMENT`, completed, paused, and cancelled work is reported
85
- without starting another official login.
86
- `--dry-run` emits the same redacted ordering without generating credentials. The
87
- advertised verified minimum of two parallel lineages is evidence, not a maximum;
88
- the CLI still obeys `sequentialRequired: true` and never creates a local RT pool.
89
-
90
- When the discovered profile advertises `delivery: true`, `use`, `run`, `app`,
91
- and `auth-agent` resolve the caller's schema-v2 credential Assignment; they fail
92
- closed instead of falling back to the schema-v1 account list. The Server remains
93
- the only owner and refresh executor for the real OpenAI refresh token. Before an
94
- issue request, Numa writes a mode-`0600` private recovery journal containing the
95
- client delivery key and issue idempotency key. A lost response or crash in the
96
- `INSTALLING` phase therefore replays the same request instead of creating another
97
- delivery. Numa decrypts only access/ID tokens, installs them under a local file
98
- lock with an atomic `fsync` + rename, and writes a random, upstream-unusable
99
- placeholder in the `auth.json` refresh-token field. It then ACKs the installed
100
- lineage generation and securely removes the private issue journal. The remaining
101
- lineage and ACK recovery metadata contains no credential material.
102
- Schema-v2 install, reset, and retirement also delete any old full
103
- `auth.json.numa-backup` instead of retaining or restoring a legacy real refresh
104
- token. Once delivery has been observed, profile caching treats it as sticky and
105
- will not downgrade to schema v1 during a discovery failure.
106
-
107
- When either `delivery` or `migrationPlans` is enabled, the legacy RT-pool
108
- mutations (`upload`, administrator refresh, assignment bind/unbind, and
109
- `auth-agent --restore`) fail with
110
- `schema_v2_legacy_management_disabled`; they never silently call schema-v1.
111
-
112
- `run` and `app` automatically supervise delivery while their official Codex child
113
- process remains alive. They request renewal only inside the Server's final
114
- 60-second safety window, stop supervision on child exit, and terminate the child
115
- with a visible error if renewal fails. `auth-agent` remains available as an
116
- explicit foreground diagnostic. Schema-v1 short-lived delivery remains available
117
- only for tenants whose discovered profile has not enabled the v2 capability.
118
-
119
- `retirement acknowledge` only removes the exact locally managed
120
- Assignment/lineage/generation recorded by Numa. It writes a Secret-free local
121
- tombstone before deleting `auth.json`. Before deletion it reads the Server
122
- retirement, verifies the Assignment and exact disclosed lineage/version target,
123
- then uses the current revision to append evidence. The ACK is not device identity and
124
- does not bypass the natural expiry of any other disclosed short-lived token.
112
+ The affected user then runs `numa codex list --json` and `numa codex run` to
113
+ verify a new lineage. Do not renew the subscription unless its own status or
114
+ timestamp has expired. Do not copy or share `auth.json`; official Codex login
115
+ credentials are collected only inside the isolated login flow.
116
+
117
+ If the official login succeeds but upload returns
118
+ `codex_token_pool_healthy_lineage_exists`, do not repeat the login. The Server
119
+ must first reconcile the stale lineage to `NEEDS_REAUTH`; a lineage that just
120
+ failed delivery with `client_credential_expired` cannot validly block its own
121
+ replacement as healthy.
122
+
123
+ When the discovered profile advertises `requestBoundDeviceCredentials: true`,
124
+ the legacy direct-assignment mutations (`upload`, administrator refresh,
125
+ assignment bind/unbind, and `auth-agent --restore`) fail with
126
+ `schema_v2_legacy_management_disabled`; they never silently fall back.
125
127
 
126
128
  The client connects to
127
129
  `X-Tenant-Id: numa-realm`. With `--server` and `--tenant-id` it resolves RFC 9728
package/dist/client.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import type { CodexAuthController } from "./oidc.js";
2
- import { type CodexAdminAccountListResponse, type CodexAdminAccountRenewalInput, type CodexAdminAccountRenewalResponse, type CodexAdminAssignmentDeleteResponse, type CodexAdminAssignmentListResponse, type CodexAdminAssignmentMutationResponse, type CodexAccountListResponse, type CodexAssignmentRetirementLocalDeleteAckInput, type CodexAssignmentRetirementLocalDeleteAckResponse, type CodexAssignmentRetirementPreflightResponse, type CodexCredentialVersionListResponse, type CodexEnrollmentHeartbeatInput, type CodexEnrollmentCandidateInput, type CodexEnrollmentCandidateResponse, type CodexEnrollmentIntentResponse, type CodexEnrollmentMutationInput, type CodexImportResult, type CodexLoginCredentialsResponse, type CodexManualRefreshResponse, type CodexMigrationLoginQueueResponse, type CodexShortLivedDeliveryAckInput, type CodexShortLivedDeliveryAckResponse, type CodexShortLivedDeliveryRequest, type CodexShortLivedDeliveryResponse, type CodexUserCredentialAssignmentListResponse, type CodexUploadBatch, type CodexV3CredentialAssignmentListResponse, type CodexV3EnrollmentConfiguration, type CodexV3EnrollmentInput, type CodexV3EnrollmentResponse, type CodexV3FullCredentialDeliveryAckInput, type CodexV3FullCredentialDeliveryAckResponse, type CodexV3FullCredentialDeliveryRequest, type CodexV3FullCredentialDeliveryResponse, type CodexV3GenerationReportInput, type CodexV3GenerationReportResponse, type CodexV4AccessObservationInput, type CodexV4AccessObservationResponse, type CodexV5AcknowledgeDeviceSessionInput, type CodexV5AcknowledgeDeviceSessionResponse, type CodexV5CreateDeviceSessionInput, type CodexV5CreateDeviceSessionResponse, type CodexV5GenerationReportInput, type CodexV5GenerationReportResponse, type CodexV5HeartbeatDeviceSessionInput, type CodexV5HeartbeatDeviceSessionResponse, type CodexV5ReleaseDeviceSessionInput, type CodexV5ReleaseDeviceSessionResponse, type CodexTokenPoolV4AssignmentTarget, type CodexTokenPoolV4DirectoryResolveResponse, type CodexTokenPoolV4EnrollmentConfiguration, type CodexTokenPoolV4UploadInput, type CodexTokenPoolV4UploadResponse } from "./protocol.js";
2
+ import { type CodexAdminAccountListResponse, type CodexAdminAccountRenewalInput, type CodexAdminAccountRenewalResponse, type CodexAdminAssignmentDeleteResponse, type CodexAdminAssignmentListResponse, type CodexAdminAssignmentMutationResponse, type CodexAccountListResponse, type CodexCredentialVersionListResponse, type CodexImportResult, type CodexLoginCredentialsResponse, type CodexManualRefreshResponse, type CodexUploadBatch, type CodexV3CredentialAssignmentListResponse, type CodexV3EnrollmentConfiguration, type CodexV3EnrollmentInput, type CodexV3EnrollmentResponse, type CodexV3FullCredentialDeliveryAckInput, type CodexV3FullCredentialDeliveryAckResponse, type CodexV3FullCredentialDeliveryRequest, type CodexV3FullCredentialDeliveryResponse, type CodexV3GenerationReportInput, type CodexV3GenerationReportResponse, type CodexV4AccessObservationInput, type CodexV4AccessObservationResponse, type CodexV5AcknowledgeDeviceSessionInput, type CodexV5AcknowledgeDeviceSessionResponse, type CodexV5CreateDeviceSessionInput, type CodexV5CreateDeviceSessionResponse, type CodexV5GenerationReportInput, type CodexV5GenerationReportResponse, type CodexV5HeartbeatDeviceSessionInput, type CodexV5HeartbeatDeviceSessionResponse, type CodexV5ReleaseDeviceSessionInput, type CodexV5ReleaseDeviceSessionResponse, type CodexV6AccountRequestListResponse, type CodexV6AdminAccountRequestListQuery, type CodexV6AccountRequestResponse, type CodexV6CancelAccountRequestInput, type CodexV6AdminReviewAccountRequestInput, type CodexV6AdminReplacementCandidateListResponse, type CodexV6AdminReplacementCandidateQuery, type CodexV6AcknowledgeFullCredentialDeliveryInput, type CodexV6AcknowledgeFullCredentialDeliveryResponse, type CodexV6AdminCreateDeviceBindingInput, type CodexV6AdminCreateDeviceBindingResponse, type CodexV6AdminReplaceDeviceTokenInput, type CodexV6AdminReplaceDeviceTokenResponse, type CodexV6CreateAccountRequestInput, type CodexV6DeviceBindingListResponse, type CodexV6FullCredentialDeliveryInput, type CodexV6FullCredentialDeliveryResponse, type CodexV6GenerationReportInput, type CodexV6GenerationReportResponse, type CodexV6ReconcileDeviceAccessInput, type CodexV6ReconcileDeviceAccessResponse, type CodexTokenPoolV4AssignmentTarget, type CodexTokenPoolV4DirectoryResolveResponse, type CodexTokenPoolV4EnrollmentConfiguration, type CodexTokenPoolV4UploadInput, type CodexTokenPoolV4UploadResponse } from "./protocol.js";
3
3
  import type { ResolvedCodexConfig } from "./types.js";
4
4
  export declare function normalizeCodexServiceUrl(rawUrl: string, allowInsecureHttp?: boolean): string;
5
5
  export declare class CodexServiceClient {
@@ -12,7 +12,6 @@ export declare class CodexServiceClient {
12
12
  getCurrentActorSubject(): Promise<string>;
13
13
  private request;
14
14
  listAccounts(): Promise<CodexAccountListResponse>;
15
- listCredentialAssignments(): Promise<CodexUserCredentialAssignmentListResponse>;
16
15
  getV3EnrollmentConfiguration(): Promise<CodexV3EnrollmentConfiguration>;
17
16
  getTokenPoolV4EnrollmentConfiguration(): Promise<CodexTokenPoolV4EnrollmentConfiguration>;
18
17
  resolveTokenPoolV4DirectoryUser(principal: string): Promise<CodexTokenPoolV4DirectoryResolveResponse>;
@@ -36,12 +35,28 @@ export declare class CodexServiceClient {
36
35
  heartbeatV5DeviceSession(sessionId: string, input: CodexV5HeartbeatDeviceSessionInput): Promise<CodexV5HeartbeatDeviceSessionResponse>;
37
36
  releaseV5DeviceSession(sessionId: string, input: CodexV5ReleaseDeviceSessionInput, idempotencyKey: string): Promise<CodexV5ReleaseDeviceSessionResponse>;
38
37
  reportV5Generation(lineageId: string, input: CodexV5GenerationReportInput, idempotencyKey: string): Promise<CodexV5GenerationReportResponse>;
38
+ listV6AccountRequests(): Promise<CodexV6AccountRequestListResponse>;
39
+ getV6AccountRequest(requestId: string): Promise<CodexV6AccountRequestResponse>;
40
+ createV6AccountRequest(input: CodexV6CreateAccountRequestInput, idempotencyKey: string): Promise<CodexV6AccountRequestResponse>;
41
+ cancelV6AccountRequest(requestId: string, input: CodexV6CancelAccountRequestInput, idempotencyKey: string): Promise<CodexV6AccountRequestResponse>;
42
+ listV6AdminAccountRequests(query?: CodexV6AdminAccountRequestListQuery): Promise<CodexV6AccountRequestListResponse>;
43
+ getV6AdminAccountRequest(requestId: string): Promise<CodexV6AccountRequestResponse>;
44
+ listV6AdminReplacementCandidates(query: CodexV6AdminReplacementCandidateQuery): Promise<CodexV6AdminReplacementCandidateListResponse>;
45
+ reviewV6AdminAccountRequest(requestId: string, input: CodexV6AdminReviewAccountRequestInput, idempotencyKey: string): Promise<CodexV6AccountRequestResponse>;
46
+ listV6DeviceBindings(requestId: string): Promise<CodexV6DeviceBindingListResponse>;
47
+ reconcileV6DeviceAccess(input: CodexV6ReconcileDeviceAccessInput, idempotencyKey: string): Promise<CodexV6ReconcileDeviceAccessResponse>;
48
+ createV6AdminDeviceBinding(requestId: string, input: CodexV6AdminCreateDeviceBindingInput, idempotencyKey: string): Promise<CodexV6AdminCreateDeviceBindingResponse>;
49
+ replaceV6AdminDeviceToken(requestId: string, bindingId: string, input: CodexV6AdminReplaceDeviceTokenInput, idempotencyKey: string): Promise<CodexV6AdminReplaceDeviceTokenResponse>;
50
+ listV6AdminDeviceBindings(requestId: string): Promise<CodexV6DeviceBindingListResponse>;
51
+ createV6FullCredentialDelivery(bindingId: string, input: CodexV6FullCredentialDeliveryInput, idempotencyKey: string): Promise<CodexV6FullCredentialDeliveryResponse>;
52
+ resolveV6FullCredentialDelivery(bindingId: string, clientRequestId: string, installationId: string): Promise<CodexV6FullCredentialDeliveryResponse>;
53
+ private requireV6FullDelivery;
54
+ acknowledgeV6FullCredentialDelivery(deliveryId: string, input: CodexV6AcknowledgeFullCredentialDeliveryInput, idempotencyKey: string): Promise<CodexV6AcknowledgeFullCredentialDeliveryResponse>;
55
+ reportV6Generation(bindingId: string, input: CodexV6GenerationReportInput, idempotencyKey: string): Promise<CodexV6GenerationReportResponse>;
56
+ resolveV6GenerationReport(bindingId: string, expected: Pick<CodexV6GenerationReportInput, "clientRequestId" | "bindingId" | "installationId" | "expectedGenerationVersion" | "rotationMode" | "accessTokenHealth" | "refreshTokenHealth" | "observedAt">): Promise<CodexV6GenerationReportResponse>;
57
+ private requireV6Report;
39
58
  observeV4AccessToken(lineageId: string, input: CodexV4AccessObservationInput): Promise<CodexV4AccessObservationResponse>;
40
59
  private requireV3Report;
41
- createShortLivedCredentialDelivery(assignmentId: string, input: CodexShortLivedDeliveryRequest, idempotencyKey: string): Promise<CodexShortLivedDeliveryResponse>;
42
- acknowledgeShortLivedCredentialDelivery(deliveryId: string, input: CodexShortLivedDeliveryAckInput, idempotencyKey: string): Promise<CodexShortLivedDeliveryAckResponse>;
43
- acknowledgeAssignmentRetirementLocalDelete(retirementId: string, input: CodexAssignmentRetirementLocalDeleteAckInput, idempotencyKey: string): Promise<CodexAssignmentRetirementLocalDeleteAckResponse>;
44
- getAssignmentRetirement(retirementId: string): Promise<CodexAssignmentRetirementPreflightResponse>;
45
60
  getLoginCredentials(accountId: string): Promise<CodexLoginCredentialsResponse>;
46
61
  uploadAccounts(payload: CodexUploadBatch): Promise<CodexImportResult>;
47
62
  listAdminAccounts(): Promise<CodexAdminAccountListResponse>;
@@ -55,15 +70,5 @@ export declare class CodexServiceClient {
55
70
  isDefault: boolean;
56
71
  }): Promise<CodexAdminAssignmentMutationResponse>;
57
72
  unbindAdminAssignment(assignmentId: string): Promise<CodexAdminAssignmentDeleteResponse>;
58
- getEnrollmentIntent(intentId: string): Promise<CodexEnrollmentIntentResponse>;
59
- listMigrationLoginQueue(planId: string, query?: {
60
- page?: number;
61
- pageSize?: number;
62
- }): Promise<CodexMigrationLoginQueueResponse>;
63
- claimEnrollmentIntent(intentId: string, input: CodexEnrollmentMutationInput): Promise<CodexEnrollmentIntentResponse>;
64
- heartbeatEnrollmentIntent(intentId: string, input: CodexEnrollmentHeartbeatInput): Promise<CodexEnrollmentIntentResponse>;
65
- cancelEnrollmentIntent(intentId: string, input: CodexEnrollmentMutationInput): Promise<CodexEnrollmentIntentResponse>;
66
- uploadEnrollmentCandidate(intentId: string, input: CodexEnrollmentCandidateInput, idempotencyKey: string): Promise<CodexEnrollmentCandidateResponse>;
67
- private mutateEnrollmentIntent;
68
73
  }
69
74
  export declare function codexImportRequestTimeoutMs(baseTimeoutMs: number, accountCount: number): number;
package/dist/client.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { CodexAuthError, CodexLoginRequiredError, CodexServiceError } from "./errors.js";
2
- import { CODEX_ACCOUNTS_IMPORT_PATH, CODEX_ACCOUNTS_LIST_PATH, CodexAssignmentRetirementLocalDeleteAckInputSchema, CodexAssignmentRetirementLocalDeleteAckResponseSchema, CodexAssignmentRetirementPreflightResponseSchema, CODEX_ADMIN_ACCOUNTS_PATH, CODEX_ADMIN_ASSIGNMENTS_PATH, CODEX_CREDENTIAL_ASSIGNMENTS_PATH, CodexAdminAssignmentDeleteResponseSchema, CodexAdminAssignmentListResponseSchema, CodexAdminAssignmentMutationResponseSchema, CodexAdminAccountListResponseSchema, CodexAdminAccountRenewalInputSchema, CodexAdminAccountRenewalResponseSchema, CodexAccountListResponseSchema, CodexCredentialVersionListResponseSchema, CodexEnrollmentHeartbeatInputSchema, CodexEnrollmentCandidateInputSchema, CodexEnrollmentCandidateResponseSchema, CodexEnrollmentIntentResponseSchema, CodexEnrollmentMutationInputSchema, CodexImportResultSchema, CodexLoginCredentialsResponseSchema, CodexManualRefreshResponseSchema, CodexMigrationLoginQueueResponseSchema, CodexShortLivedDeliveryAckInputSchema, CodexShortLivedDeliveryAckResponseSchema, CodexShortLivedDeliveryRequestSchema, CodexShortLivedDeliveryResponseSchema, CodexUserCredentialAssignmentListResponseSchema, CODEX_V3_CREDENTIAL_ASSIGNMENTS_PATH, CODEX_V3_ENROLLMENT_CONFIGURATION_PATH, CODEX_V3_ENROLLMENTS_PATH, CodexV3CredentialAssignmentListResponseSchema, CodexV3EnrollmentConfigurationSchema, CodexV3EnrollmentInputSchema, CodexV3EnrollmentResponseSchema, CodexV3FullCredentialDeliveryAckInputSchema, CodexV3FullCredentialDeliveryAckResponseSchema, CodexV3FullCredentialDeliveryRequestSchema, CodexV3FullCredentialDeliveryResponseSchema, CodexV3GenerationReportInputSchema, CodexV3GenerationReportResponseSchema, CodexV4AccessObservationInputSchema, CodexV4AccessObservationResponseSchema, CodexV5AcknowledgeDeviceSessionInputSchema, CodexV5AcknowledgeDeviceSessionResponseSchema, CodexV5CreateDeviceSessionInputSchema, CodexV5CreateDeviceSessionResponseSchema, CodexV5GenerationReportInputSchema, CodexV5GenerationReportResponseSchema, CodexV5HeartbeatDeviceSessionInputSchema, CodexV5HeartbeatDeviceSessionResponseSchema, CodexV5ReleaseDeviceSessionInputSchema, CodexV5ReleaseDeviceSessionResponseSchema, CODEX_TOKEN_POOL_V4_ENROLLMENT_CONFIGURATION_PATH, CODEX_TOKEN_POOL_V4_UPLOADS_PATH, CodexTokenPoolV4DirectoryResolveResponseSchema, CodexTokenPoolV4EnrollmentConfigurationSchema, CodexTokenPoolV4IdempotencyKeySchema, CodexTokenPoolV4UploadInputSchema, CodexTokenPoolV4UploadResponseSchema, codexAccountLoginCredentialsPath, codexAssignmentRetirementLocalDeleteAckPath, codexAssignmentRetirementPath, codexAdminAssignmentPath, codexAdminCredentialVersionsPath, codexAdminEnrollmentIntentActionPath, codexAdminEnrollmentIntentPath, codexAdminMigrationLoginQueuePath, codexAdminRenewPath, codexAdminRefreshPath, codexAssignmentShortLivedDeliveriesPath, codexShortLivedDeliveryAckPath, codexV3AssignmentFullCredentialDeliveriesPath, codexV3AssignmentFullCredentialDeliveryResolvePath, codexV3EnrollmentResolvePath, codexV3FullCredentialDeliveryAckPath, codexV3LineageGenerationReportResolvePath, codexV3LineageGenerationReportsPath, codexV4LineageAccessObservationPath, codexV5AssignmentDeviceSessionResolvePath, codexV5AssignmentDeviceSessionsPath, codexV5DeviceSessionActionPath, codexV5LineageGenerationReportsPath, codexTokenPoolV4DirectoryResolvePath, codexTokenPoolV4UploadResolvePath } from "./protocol.js";
2
+ import { CODEX_ACCOUNTS_IMPORT_PATH, CODEX_ACCOUNTS_LIST_PATH, CODEX_ADMIN_ACCOUNTS_PATH, CODEX_ADMIN_ASSIGNMENTS_PATH, CodexAdminAssignmentDeleteResponseSchema, CodexAdminAssignmentListResponseSchema, CodexAdminAssignmentMutationResponseSchema, CodexAdminAccountListResponseSchema, CodexAdminAccountRenewalInputSchema, CodexAdminAccountRenewalResponseSchema, CodexAccountListResponseSchema, CodexCredentialVersionListResponseSchema, CodexEnrollmentMutationInputSchema, CodexImportResultSchema, CodexLoginCredentialsResponseSchema, CodexManualRefreshResponseSchema, CODEX_V3_CREDENTIAL_ASSIGNMENTS_PATH, CODEX_V3_ENROLLMENT_CONFIGURATION_PATH, CODEX_V3_ENROLLMENTS_PATH, CodexV3CredentialAssignmentListResponseSchema, CodexV3EnrollmentConfigurationSchema, CodexV3EnrollmentInputSchema, CodexV3EnrollmentResponseSchema, CodexV3FullCredentialDeliveryAckInputSchema, CodexV3FullCredentialDeliveryAckResponseSchema, CodexV3FullCredentialDeliveryRequestSchema, CodexV3FullCredentialDeliveryResponseSchema, CodexV3GenerationReportInputSchema, CodexV3GenerationReportResponseSchema, CodexV4AccessObservationInputSchema, CodexV4AccessObservationResponseSchema, CodexV5AcknowledgeDeviceSessionInputSchema, CodexV5AcknowledgeDeviceSessionResponseSchema, CodexV5CreateDeviceSessionInputSchema, CodexV5CreateDeviceSessionResponseSchema, CodexV5GenerationReportInputSchema, CodexV5GenerationReportResponseSchema, CodexV5HeartbeatDeviceSessionInputSchema, CodexV5HeartbeatDeviceSessionResponseSchema, CodexV5ReleaseDeviceSessionInputSchema, CodexV5ReleaseDeviceSessionResponseSchema, CODEX_V6_ACCOUNT_REQUESTS_PATH, CODEX_V6_DEVICE_ACCESS_RECONCILIATIONS_PATH, CodexV6AccountRequestListResponseSchema, CodexV6AccountRequestResponseSchema, CodexV6CancelAccountRequestInputSchema, CodexV6AdminReviewAccountRequestInputSchema, CodexV6AdminReplacementCandidateListResponseSchema, CodexV6AcknowledgeFullCredentialDeliveryInputSchema, CodexV6AcknowledgeFullCredentialDeliveryResponseSchema, CodexV6AdminCreateDeviceBindingInputSchema, CodexV6AdminCreateDeviceBindingResponseSchema, CodexV6AdminReplaceDeviceTokenInputSchema, CodexV6AdminReplaceDeviceTokenResponseSchema, CodexV6CreateAccountRequestInputSchema, CodexV6DeviceBindingListResponseSchema, CodexV6FullCredentialDeliveryInputSchema, CodexV6FullCredentialDeliveryResponseSchema, CodexV6GenerationReportInputSchema, CodexV6GenerationReportResponseSchema, CodexV6ReconcileDeviceAccessInputSchema, CodexV6ReconcileDeviceAccessResponseSchema, CODEX_TOKEN_POOL_V4_ENROLLMENT_CONFIGURATION_PATH, CODEX_TOKEN_POOL_V4_UPLOADS_PATH, CodexTokenPoolV4DirectoryResolveResponseSchema, CodexTokenPoolV4EnrollmentConfigurationSchema, CodexTokenPoolV4IdempotencyKeySchema, CodexTokenPoolV4UploadInputSchema, CodexTokenPoolV4UploadResponseSchema, codexAccountLoginCredentialsPath, codexAdminAssignmentPath, codexAdminCredentialVersionsPath, codexAdminRenewPath, codexAdminRefreshPath, codexV3AssignmentFullCredentialDeliveriesPath, codexV3AssignmentFullCredentialDeliveryResolvePath, codexV3EnrollmentResolvePath, codexV3FullCredentialDeliveryAckPath, codexV3LineageGenerationReportResolvePath, codexV3LineageGenerationReportsPath, codexV4LineageAccessObservationPath, codexV5AssignmentDeviceSessionResolvePath, codexV5AssignmentDeviceSessionsPath, codexV5DeviceSessionActionPath, codexV5LineageGenerationReportsPath, codexV6AccountRequestDeviceBindingsPath, codexV6AccountRequestActionPath, codexV6AccountRequestPath, codexV6AdminAccountRequestDeviceBindingsPath, codexV6AdminAccountRequestPath, codexV6AdminAccountRequestsPath, codexV6AdminAccountRequestReviewPath, codexV6AdminDeviceBindingReplacementPath, codexV6AdminReplacementCandidatesPath, codexV6BindingGenerationReportResolvePath, codexV6BindingGenerationReportsPath, codexV6DeviceBindingFullCredentialDeliveriesPath, codexV6DeviceBindingFullCredentialDeliveryResolvePath, codexV6FullCredentialDeliveryAckPath, codexTokenPoolV4DirectoryResolvePath, codexTokenPoolV4UploadResolvePath } from "./protocol.js";
3
3
  export function normalizeCodexServiceUrl(rawUrl, allowInsecureHttp = false) {
4
4
  const url = new URL(rawUrl);
5
5
  const loopback = ["127.0.0.1", "localhost", "::1", "[::1]"].includes(url.hostname);
@@ -104,7 +104,7 @@ export class CodexServiceClient {
104
104
  ? serviceCode
105
105
  : undefined;
106
106
  const normalizedServiceCode = safeServiceCode === "client_credential_expired"
107
- ? "codex_account_expired"
107
+ ? "codex_account_needs_reauth"
108
108
  : safeServiceCode;
109
109
  const code = normalizedServiceCode
110
110
  ?? (response.status === 401 || response.status === 403
@@ -113,7 +113,7 @@ export class CodexServiceClient {
113
113
  throw new CodexServiceError(normalizedServiceCode === "codex_account_expired"
114
114
  ? "ChatGPT account subscription has expired and must be renewed by an administrator."
115
115
  : normalizedServiceCode === "codex_account_needs_reauth"
116
- ? "ChatGPT account credentials are invalid and must be re-imported by an administrator."
116
+ ? "ChatGPT account credentials are invalid and must be replaced through a fresh managed Codex login."
117
117
  : `Codex account service request failed (HTTP ${response.status}): ${detail}`, code, response.status);
118
118
  }
119
119
  return body;
@@ -125,13 +125,6 @@ export class CodexServiceClient {
125
125
  }
126
126
  return parsed.data;
127
127
  }
128
- async listCredentialAssignments() {
129
- const parsed = CodexUserCredentialAssignmentListResponseSchema.safeParse(await this.request(CODEX_CREDENTIAL_ASSIGNMENTS_PATH));
130
- if (!parsed.success) {
131
- throw new CodexServiceError("Invalid Codex credential assignment list response.", "invalid_codex_service_response");
132
- }
133
- return parsed.data;
134
- }
135
128
  async getV3EnrollmentConfiguration() {
136
129
  const parsed = CodexV3EnrollmentConfigurationSchema.safeParse(await this.request(CODEX_V3_ENROLLMENT_CONFIGURATION_PATH));
137
130
  if (!parsed.success) {
@@ -316,6 +309,201 @@ export class CodexServiceClient {
316
309
  }
317
310
  return parsed.data;
318
311
  }
312
+ async listV6AccountRequests() {
313
+ const subject = await this.getCurrentActorSubject();
314
+ const parsed = CodexV6AccountRequestListResponseSchema.safeParse(await this.request(CODEX_V6_ACCOUNT_REQUESTS_PATH));
315
+ if (!parsed.success || parsed.data.items.some((item) => item.userSubject !== subject)) {
316
+ throw new CodexServiceError("Invalid Codex v6 account-request list response.", "invalid_codex_service_response");
317
+ }
318
+ return parsed.data;
319
+ }
320
+ async getV6AccountRequest(requestId) {
321
+ const subject = await this.getCurrentActorSubject();
322
+ const parsed = CodexV6AccountRequestResponseSchema.safeParse(await this.request(codexV6AccountRequestPath(requestId)));
323
+ if (!parsed.success || parsed.data.request.id !== requestId
324
+ || parsed.data.request.userSubject !== subject) {
325
+ throw new CodexServiceError("Invalid or mismatched Codex v6 account-request response.", "invalid_codex_service_response");
326
+ }
327
+ return parsed.data;
328
+ }
329
+ async createV6AccountRequest(input, idempotencyKey) {
330
+ const subject = await this.getCurrentActorSubject();
331
+ const body = CodexV6CreateAccountRequestInputSchema.parse(input);
332
+ const key = CodexTokenPoolV4IdempotencyKeySchema.parse(idempotencyKey);
333
+ const parsed = CodexV6AccountRequestResponseSchema.safeParse(await this.request(CODEX_V6_ACCOUNT_REQUESTS_PATH, { method: "POST", body, headers: { "Idempotency-Key": key } }));
334
+ if (!parsed.success || parsed.data.request.userSubject !== subject) {
335
+ throw new CodexServiceError("Invalid Codex v6 account-request response.", "invalid_codex_service_response");
336
+ }
337
+ return parsed.data;
338
+ }
339
+ async cancelV6AccountRequest(requestId, input, idempotencyKey) {
340
+ const subject = await this.getCurrentActorSubject();
341
+ const body = CodexV6CancelAccountRequestInputSchema.parse(input);
342
+ const key = CodexTokenPoolV4IdempotencyKeySchema.parse(idempotencyKey);
343
+ const parsed = CodexV6AccountRequestResponseSchema.safeParse(await this.request(codexV6AccountRequestActionPath(requestId, "cancel"), { method: "POST", body, headers: { "Idempotency-Key": key } }));
344
+ if (!parsed.success || parsed.data.request.id !== requestId
345
+ || parsed.data.request.status !== "CANCELLED"
346
+ || parsed.data.request.userSubject !== subject) {
347
+ throw new CodexServiceError("Invalid or mismatched Codex v6 request-cancellation response.", "invalid_codex_service_response");
348
+ }
349
+ return parsed.data;
350
+ }
351
+ async listV6AdminAccountRequests(query = {}) {
352
+ const parsed = CodexV6AccountRequestListResponseSchema.safeParse(await this.request(codexV6AdminAccountRequestsPath(query)));
353
+ if (!parsed.success) {
354
+ throw new CodexServiceError("Invalid Codex v6 administrator request-list response.", "invalid_codex_service_response");
355
+ }
356
+ return parsed.data;
357
+ }
358
+ async getV6AdminAccountRequest(requestId) {
359
+ const parsed = CodexV6AccountRequestResponseSchema.safeParse(await this.request(codexV6AdminAccountRequestPath(requestId)));
360
+ if (!parsed.success || parsed.data.request.id !== requestId) {
361
+ throw new CodexServiceError("Invalid or mismatched Codex v6 administrator request response.", "invalid_codex_service_response");
362
+ }
363
+ return parsed.data;
364
+ }
365
+ async listV6AdminReplacementCandidates(query) {
366
+ const parsed = CodexV6AdminReplacementCandidateListResponseSchema.safeParse(await this.request(codexV6AdminReplacementCandidatesPath(query)));
367
+ if (!parsed.success) {
368
+ throw new CodexServiceError("Invalid Codex v6 replacement-candidate list response.", "invalid_codex_service_response");
369
+ }
370
+ return parsed.data;
371
+ }
372
+ async reviewV6AdminAccountRequest(requestId, input, idempotencyKey) {
373
+ const body = CodexV6AdminReviewAccountRequestInputSchema.parse(input);
374
+ const key = CodexTokenPoolV4IdempotencyKeySchema.parse(idempotencyKey);
375
+ const parsed = CodexV6AccountRequestResponseSchema.safeParse(await this.request(codexV6AdminAccountRequestReviewPath(requestId), { method: "POST", body, headers: { "Idempotency-Key": key } }));
376
+ const expectedStatus = body.decision === "APPROVE" ? "APPROVED" : "REJECTED";
377
+ if (!parsed.success || parsed.data.request.id !== requestId
378
+ || parsed.data.request.status !== expectedStatus) {
379
+ throw new CodexServiceError("Invalid or mismatched Codex v6 request-review response.", "invalid_codex_service_response");
380
+ }
381
+ return parsed.data;
382
+ }
383
+ async listV6DeviceBindings(requestId) {
384
+ const subject = await this.getCurrentActorSubject();
385
+ const parsed = CodexV6DeviceBindingListResponseSchema.safeParse(await this.request(codexV6AccountRequestDeviceBindingsPath(requestId)));
386
+ if (!parsed.success || parsed.data.items.some((item) => item.requestId !== requestId
387
+ || item.userSubject !== subject)) {
388
+ throw new CodexServiceError("Invalid or mismatched Codex v6 device-binding list response.", "invalid_codex_service_response");
389
+ }
390
+ return parsed.data;
391
+ }
392
+ async reconcileV6DeviceAccess(input, idempotencyKey) {
393
+ const subject = await this.getCurrentActorSubject();
394
+ const body = CodexV6ReconcileDeviceAccessInputSchema.parse(input);
395
+ const key = CodexTokenPoolV4IdempotencyKeySchema.parse(idempotencyKey);
396
+ const parsed = CodexV6ReconcileDeviceAccessResponseSchema.safeParse(await this.request(CODEX_V6_DEVICE_ACCESS_RECONCILIATIONS_PATH, { method: "POST", body, headers: { "Idempotency-Key": key } }));
397
+ if (!parsed.success
398
+ || parsed.data.binding?.installationId !== undefined
399
+ && parsed.data.binding.installationId !== body.device.installationId
400
+ || parsed.data.replacementBinding?.installationId !== undefined
401
+ && parsed.data.replacementBinding.installationId !== body.device.installationId
402
+ || parsed.data.request !== null && parsed.data.binding !== null
403
+ && parsed.data.binding.requestId !== parsed.data.request.id
404
+ || parsed.data.request !== null && parsed.data.request.userSubject !== subject
405
+ || parsed.data.binding !== null && parsed.data.binding.userSubject !== subject
406
+ || parsed.data.replacementBinding !== null
407
+ && parsed.data.replacementBinding.userSubject !== subject) {
408
+ throw new CodexServiceError("Invalid or mismatched Codex v6 device-access reconciliation.", "invalid_codex_service_response");
409
+ }
410
+ return parsed.data;
411
+ }
412
+ async createV6AdminDeviceBinding(requestId, input, idempotencyKey) {
413
+ const body = CodexV6AdminCreateDeviceBindingInputSchema.parse(input);
414
+ const key = CodexTokenPoolV4IdempotencyKeySchema.parse(idempotencyKey);
415
+ const parsed = CodexV6AdminCreateDeviceBindingResponseSchema.safeParse(await this.request(codexV6AdminAccountRequestDeviceBindingsPath(requestId), { method: "POST", body, headers: { "Idempotency-Key": key } }));
416
+ if (!parsed.success || parsed.data.request.id !== requestId
417
+ || parsed.data.binding.requestId !== requestId
418
+ || parsed.data.binding.installationId !== body.device.installationId) {
419
+ throw new CodexServiceError("Invalid or mismatched Codex v6 device-binding response.", "invalid_codex_service_response");
420
+ }
421
+ return parsed.data;
422
+ }
423
+ async replaceV6AdminDeviceToken(requestId, bindingId, input, idempotencyKey) {
424
+ const body = CodexV6AdminReplaceDeviceTokenInputSchema.parse(input);
425
+ const key = CodexTokenPoolV4IdempotencyKeySchema.parse(idempotencyKey);
426
+ const parsed = CodexV6AdminReplaceDeviceTokenResponseSchema.safeParse(await this.request(codexV6AdminDeviceBindingReplacementPath(requestId, bindingId), { method: "POST", body, headers: { "Idempotency-Key": key } }));
427
+ if (!parsed.success || parsed.data.request.id !== requestId
428
+ || parsed.data.currentBinding.id !== bindingId
429
+ || parsed.data.currentBinding.requestId !== requestId
430
+ || parsed.data.replacementBinding.requestId !== requestId) {
431
+ throw new CodexServiceError("Invalid or mismatched Codex v6 replacement response.", "invalid_codex_service_response");
432
+ }
433
+ return parsed.data;
434
+ }
435
+ async listV6AdminDeviceBindings(requestId) {
436
+ const parsed = CodexV6DeviceBindingListResponseSchema.safeParse(await this.request(codexV6AdminAccountRequestDeviceBindingsPath(requestId)));
437
+ if (!parsed.success || parsed.data.items.some((item) => item.requestId !== requestId)) {
438
+ throw new CodexServiceError("Invalid or mismatched Codex v6 administrator device-binding list response.", "invalid_codex_service_response");
439
+ }
440
+ return parsed.data;
441
+ }
442
+ async createV6FullCredentialDelivery(bindingId, input, idempotencyKey) {
443
+ const body = CodexV6FullCredentialDeliveryInputSchema.parse(input);
444
+ const key = CodexTokenPoolV4IdempotencyKeySchema.parse(idempotencyKey);
445
+ const parsed = CodexV6FullCredentialDeliveryResponseSchema.safeParse(await this.request(codexV6DeviceBindingFullCredentialDeliveriesPath(bindingId), { method: "POST", body, headers: { "Idempotency-Key": key }, timeoutMs: 45_000 }));
446
+ return this.requireV6FullDelivery(parsed, bindingId, body.clientRequestId, body.installationId);
447
+ }
448
+ async resolveV6FullCredentialDelivery(bindingId, clientRequestId, installationId) {
449
+ const requestId = CodexV6FullCredentialDeliveryInputSchema.shape.clientRequestId
450
+ .parse(clientRequestId);
451
+ const installation = CodexV6FullCredentialDeliveryInputSchema.shape.installationId
452
+ .parse(installationId);
453
+ const parsed = CodexV6FullCredentialDeliveryResponseSchema.safeParse(await this.request(codexV6DeviceBindingFullCredentialDeliveryResolvePath(bindingId, requestId)));
454
+ return this.requireV6FullDelivery(parsed, bindingId, requestId, installation);
455
+ }
456
+ requireV6FullDelivery(parsed, bindingId, clientRequestId, installationId) {
457
+ if (!parsed.success || parsed.data.delivery.bindingId !== bindingId
458
+ || parsed.data.delivery.clientRequestId !== clientRequestId
459
+ || parsed.data.delivery.installationId !== installationId) {
460
+ throw new CodexServiceError("Invalid or mismatched Codex v6 full-delivery response.", "invalid_codex_service_response");
461
+ }
462
+ return parsed.data;
463
+ }
464
+ async acknowledgeV6FullCredentialDelivery(deliveryId, input, idempotencyKey) {
465
+ const body = CodexV6AcknowledgeFullCredentialDeliveryInputSchema.parse(input);
466
+ const key = CodexTokenPoolV4IdempotencyKeySchema.parse(idempotencyKey);
467
+ const parsed = CodexV6AcknowledgeFullCredentialDeliveryResponseSchema.safeParse(await this.request(codexV6FullCredentialDeliveryAckPath(deliveryId), { method: "POST", body, headers: { "Idempotency-Key": key } }));
468
+ if (!parsed.success || parsed.data.delivery.id !== deliveryId
469
+ || parsed.data.delivery.installationId !== body.installationId
470
+ || parsed.data.delivery.credentialLineageId !== body.credentialLineageId
471
+ || parsed.data.delivery.generationVersion !== body.generationVersion) {
472
+ throw new CodexServiceError("Invalid or mismatched Codex v6 delivery ACK response.", "invalid_codex_service_response");
473
+ }
474
+ return parsed.data;
475
+ }
476
+ async reportV6Generation(bindingId, input, idempotencyKey) {
477
+ const body = CodexV6GenerationReportInputSchema.parse(input);
478
+ if (body.bindingId !== bindingId) {
479
+ throw new CodexServiceError("Codex v6 generation report targets another binding.", "invalid_codex_request", 400);
480
+ }
481
+ const key = CodexTokenPoolV4IdempotencyKeySchema.parse(idempotencyKey);
482
+ const parsed = CodexV6GenerationReportResponseSchema.safeParse(await this.request(codexV6BindingGenerationReportsPath(bindingId), { method: "POST", body, headers: { "Idempotency-Key": key }, timeoutMs: 45_000 }));
483
+ return this.requireV6Report(parsed, bindingId, body);
484
+ }
485
+ async resolveV6GenerationReport(bindingId, expected) {
486
+ if (expected.bindingId !== bindingId) {
487
+ throw new CodexServiceError("Codex v6 generation report targets another binding.", "invalid_codex_request", 400);
488
+ }
489
+ const clientRequestId = CodexV6GenerationReportInputSchema.shape.clientRequestId
490
+ .parse(expected.clientRequestId);
491
+ const parsed = CodexV6GenerationReportResponseSchema.safeParse(await this.request(codexV6BindingGenerationReportResolvePath(bindingId, clientRequestId)));
492
+ return this.requireV6Report(parsed, bindingId, { ...expected, clientRequestId });
493
+ }
494
+ requireV6Report(parsed, bindingId, expected) {
495
+ if (!parsed.success || parsed.data.report.bindingId !== bindingId
496
+ || parsed.data.report.clientRequestId !== expected.clientRequestId
497
+ || parsed.data.report.installationId !== expected.installationId
498
+ || parsed.data.report.previousGenerationVersion !== expected.expectedGenerationVersion
499
+ || parsed.data.report.rotationMode !== expected.rotationMode
500
+ || parsed.data.report.accessTokenHealth !== expected.accessTokenHealth
501
+ || parsed.data.report.refreshTokenHealth !== expected.refreshTokenHealth
502
+ || parsed.data.report.observedAt !== expected.observedAt) {
503
+ throw new CodexServiceError("Invalid or mismatched Codex v6 generation report response.", "invalid_codex_service_response");
504
+ }
505
+ return parsed.data;
506
+ }
319
507
  async observeV4AccessToken(lineageId, input) {
320
508
  const body = CodexV4AccessObservationInputSchema.parse(input);
321
509
  const parsed = CodexV4AccessObservationResponseSchema.safeParse(await this.request(codexV4LineageAccessObservationPath(lineageId), { method: "PUT", body, timeoutMs: Math.min(this.config.connection.requestTimeoutMs, 2_000) }));
@@ -340,55 +528,6 @@ export class CodexServiceClient {
340
528
  }
341
529
  return parsed.data;
342
530
  }
343
- async createShortLivedCredentialDelivery(assignmentId, input, idempotencyKey) {
344
- const body = CodexShortLivedDeliveryRequestSchema.parse(input);
345
- const idempotency = CodexEnrollmentMutationInputSchema.shape.idempotencyKey.parse(idempotencyKey);
346
- const parsed = CodexShortLivedDeliveryResponseSchema.safeParse(await this.request(codexAssignmentShortLivedDeliveriesPath(assignmentId), {
347
- method: "POST",
348
- body,
349
- headers: { "Idempotency-Key": idempotency },
350
- timeoutMs: Math.max(this.config.connection.requestTimeoutMs, 45_000)
351
- }));
352
- if (!parsed.success || parsed.data.delivery.assignmentId !== assignmentId) {
353
- throw new CodexServiceError("Invalid or mismatched Codex short-lived credential delivery response.", "invalid_codex_service_response");
354
- }
355
- return parsed.data;
356
- }
357
- async acknowledgeShortLivedCredentialDelivery(deliveryId, input, idempotencyKey) {
358
- const body = CodexShortLivedDeliveryAckInputSchema.parse(input);
359
- const idempotency = CodexEnrollmentMutationInputSchema.shape.idempotencyKey.parse(idempotencyKey);
360
- const parsed = CodexShortLivedDeliveryAckResponseSchema.safeParse(await this.request(codexShortLivedDeliveryAckPath(deliveryId), {
361
- method: "POST",
362
- body,
363
- headers: { "Idempotency-Key": idempotency }
364
- }));
365
- if (!parsed.success || parsed.data.delivery.id !== deliveryId
366
- || parsed.data.delivery.lineageId !== input.lineageId
367
- || parsed.data.delivery.generationVersion !== input.generationVersion) {
368
- throw new CodexServiceError("Invalid or mismatched Codex short-lived credential ACK response.", "invalid_codex_service_response");
369
- }
370
- return parsed.data;
371
- }
372
- async acknowledgeAssignmentRetirementLocalDelete(retirementId, input, idempotencyKey) {
373
- const body = CodexAssignmentRetirementLocalDeleteAckInputSchema.parse(input);
374
- const idempotency = CodexEnrollmentMutationInputSchema.shape.idempotencyKey.parse(idempotencyKey);
375
- const parsed = CodexAssignmentRetirementLocalDeleteAckResponseSchema.safeParse(await this.request(codexAssignmentRetirementLocalDeleteAckPath(retirementId), {
376
- method: "POST",
377
- body,
378
- headers: { "Idempotency-Key": idempotency }
379
- }));
380
- if (!parsed.success || parsed.data.retirement.id !== retirementId) {
381
- throw new CodexServiceError("Invalid or mismatched Codex assignment retirement response.", "invalid_codex_service_response");
382
- }
383
- return parsed.data;
384
- }
385
- async getAssignmentRetirement(retirementId) {
386
- const parsed = CodexAssignmentRetirementPreflightResponseSchema.safeParse(await this.request(codexAssignmentRetirementPath(retirementId)));
387
- if (!parsed.success || parsed.data.retirement.id !== retirementId) {
388
- throw new CodexServiceError("Invalid or mismatched Codex assignment retirement preflight response.", "invalid_codex_service_response");
389
- }
390
- return parsed.data;
391
- }
392
531
  async getLoginCredentials(accountId) {
393
532
  const parsed = CodexLoginCredentialsResponseSchema.safeParse(await this.request(codexAccountLoginCredentialsPath(accountId)));
394
533
  if (!parsed.success || parsed.data.account.id !== accountId) {
@@ -480,63 +619,6 @@ export class CodexServiceClient {
480
619
  }
481
620
  return parsed.data;
482
621
  }
483
- async getEnrollmentIntent(intentId) {
484
- const parsed = CodexEnrollmentIntentResponseSchema.safeParse(await this.request(codexAdminEnrollmentIntentPath(intentId)));
485
- if (!parsed.success || parsed.data.intent.id !== intentId) {
486
- throw new CodexServiceError("Invalid or mismatched Codex enrollment intent response.", "invalid_codex_service_response");
487
- }
488
- return parsed.data;
489
- }
490
- async listMigrationLoginQueue(planId, query = {}) {
491
- const page = query.page ?? 1;
492
- const pageSize = query.pageSize ?? 100;
493
- if (!Number.isInteger(page) || page < 1 || page > 1_000_000
494
- || !Number.isInteger(pageSize) || pageSize < 1 || pageSize > 100) {
495
- throw new CodexServiceError("Invalid migration login queue page.", "invalid_configuration");
496
- }
497
- const parsed = CodexMigrationLoginQueueResponseSchema.safeParse(await this.request(codexAdminMigrationLoginQueuePath(planId, { page, pageSize })));
498
- if (!parsed.success || parsed.data.plan.id !== planId
499
- || parsed.data.page !== page || parsed.data.pageSize !== pageSize) {
500
- throw new CodexServiceError("Invalid or mismatched Codex migration login queue response.", "invalid_codex_service_response");
501
- }
502
- return parsed.data;
503
- }
504
- async claimEnrollmentIntent(intentId, input) {
505
- const body = CodexEnrollmentMutationInputSchema.parse(input);
506
- return this.mutateEnrollmentIntent(intentId, "claim", body);
507
- }
508
- async heartbeatEnrollmentIntent(intentId, input) {
509
- const body = CodexEnrollmentHeartbeatInputSchema.parse(input);
510
- return this.mutateEnrollmentIntent(intentId, "heartbeat", body);
511
- }
512
- async cancelEnrollmentIntent(intentId, input) {
513
- const body = CodexEnrollmentMutationInputSchema.parse(input);
514
- return this.mutateEnrollmentIntent(intentId, "cancel", body);
515
- }
516
- async uploadEnrollmentCandidate(intentId, input, idempotencyKey) {
517
- const body = CodexEnrollmentCandidateInputSchema.parse(input);
518
- const idempotency = CodexEnrollmentMutationInputSchema.shape.idempotencyKey.parse(idempotencyKey);
519
- const parsed = CodexEnrollmentCandidateResponseSchema.safeParse(await this.request(codexAdminEnrollmentIntentActionPath(intentId, "candidate"), {
520
- method: "POST",
521
- body,
522
- headers: { "Idempotency-Key": idempotency },
523
- timeoutMs: Math.max(this.config.connection.requestTimeoutMs, 45_000)
524
- }));
525
- if (!parsed.success || parsed.data.intent.id !== intentId) {
526
- throw new CodexServiceError("Invalid or mismatched Codex enrollment candidate response.", "invalid_codex_service_response");
527
- }
528
- return parsed.data;
529
- }
530
- async mutateEnrollmentIntent(intentId, action, body) {
531
- const parsed = CodexEnrollmentIntentResponseSchema.safeParse(await this.request(codexAdminEnrollmentIntentActionPath(intentId, action), {
532
- method: "POST",
533
- body
534
- }));
535
- if (!parsed.success || parsed.data.intent.id !== intentId) {
536
- throw new CodexServiceError("Invalid or mismatched Codex enrollment intent response.", "invalid_codex_service_response");
537
- }
538
- return parsed.data;
539
- }
540
622
  }
541
623
  export function codexImportRequestTimeoutMs(baseTimeoutMs, accountCount) {
542
624
  const validationWaves = Math.max(1, Math.ceil(accountCount / 8));