@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.
- package/README.md +73 -71
- package/dist/client.d.ts +21 -16
- package/dist/client.js +198 -116
- package/dist/client.js.map +1 -1
- package/dist/command-directory.js +3 -2
- package/dist/command-directory.js.map +1 -1
- package/dist/commands.d.ts +0 -1
- package/dist/commands.js +479 -273
- package/dist/commands.js.map +1 -1
- package/dist/credentials.d.ts +3 -75
- package/dist/credentials.js +2 -338
- package/dist/credentials.js.map +1 -1
- package/dist/index.d.ts +2 -8
- package/dist/index.js +2 -8
- package/dist/index.js.map +1 -1
- package/dist/managed-credential-v3-envelope.d.ts +38 -14
- package/dist/managed-credential-v3-envelope.js +116 -25
- package/dist/managed-credential-v3-envelope.js.map +1 -1
- package/dist/managed-credential-v3-flow.d.ts +0 -17
- package/dist/managed-credential-v3-flow.js +107 -110
- package/dist/managed-credential-v3-flow.js.map +1 -1
- package/dist/managed-credential-v3.d.ts +0 -8
- package/dist/managed-credential-v3.js +0 -23
- package/dist/managed-credential-v3.js.map +1 -1
- package/dist/profile.d.ts +2 -6
- package/dist/profile.js +26 -23
- package/dist/profile.js.map +1 -1
- package/dist/protocol.d.ts +1284 -799
- package/dist/protocol.js +494 -277
- package/dist/protocol.js.map +1 -1
- package/dist/request-bound-device-v6-flow.d.ts +42 -0
- package/dist/request-bound-device-v6-flow.js +403 -0
- package/dist/request-bound-device-v6-flow.js.map +1 -0
- package/dist/request-bound-device-v6-state.d.ts +397 -0
- package/dist/request-bound-device-v6-state.js +221 -0
- package/dist/request-bound-device-v6-state.js.map +1 -0
- package/dist/selection.d.ts +5 -0
- package/dist/selection.js +20 -2
- package/dist/selection.js.map +1 -1
- package/dist/token-pool-v4-upload-flow.js +5 -1
- package/dist/token-pool-v4-upload-flow.js.map +1 -1
- package/package.json +2 -2
- package/dist/credential-supervisor.d.ts +0 -17
- package/dist/credential-supervisor.js +0 -84
- package/dist/credential-supervisor.js.map +0 -1
- package/dist/enrollment-envelope.d.ts +0 -18
- package/dist/enrollment-envelope.js +0 -112
- package/dist/enrollment-envelope.js.map +0 -1
- package/dist/enrollment-flow.d.ts +0 -27
- package/dist/enrollment-flow.js +0 -224
- package/dist/enrollment-flow.js.map +0 -1
- package/dist/migration-login-batch.d.ts +0 -66
- package/dist/migration-login-batch.js +0 -202
- package/dist/migration-login-batch.js.map +0 -1
- package/dist/retirement-flow.d.ts +0 -38
- package/dist/retirement-flow.js +0 -78
- package/dist/retirement-flow.js.map +0 -1
- package/dist/short-lived-delivery-flow.d.ts +0 -41
- package/dist/short-lived-delivery-flow.js +0 -141
- package/dist/short-lived-delivery-flow.js.map +0 -1
- package/dist/short-lived-delivery-journal.d.ts +0 -34
- package/dist/short-lived-delivery-journal.js +0 -137
- package/dist/short-lived-delivery-journal.js.map +0 -1
- package/dist/short-lived-delivery.d.ts +0 -26
- package/dist/short-lived-delivery.js +0 -139
- 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
|
-
|
|
52
|
-
|
|
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
|
|
56
|
-
numa codex
|
|
57
|
-
numa codex
|
|
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
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
`
|
|
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
|
|
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,
|
|
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
|
-
? "
|
|
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
|
|
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));
|