@opengeni/db 0.7.3 → 0.10.7
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/dist/{chunk-YFQ7SGE4.js → chunk-BMFDXFPA.js} +23 -1
- package/dist/chunk-BMFDXFPA.js.map +1 -0
- package/dist/chunk-KW526IJA.js +127 -0
- package/dist/chunk-KW526IJA.js.map +1 -0
- package/dist/{chunk-B22X3IEZ.js → chunk-P6PKXY5W.js} +604 -32
- package/dist/chunk-P6PKXY5W.js.map +1 -0
- package/dist/index.d.ts +4 -3
- package/dist/index.js +7408 -2276
- package/dist/index.js.map +1 -1
- package/dist/migrate.d.ts +29 -4
- package/dist/migrate.js +3 -1
- package/dist/provision-roles.d.ts +1122 -73
- package/dist/provision-roles.js +1 -1
- package/dist/{schema-BN5mB9xZ.d.ts → schema-CqkzrBRS.d.ts} +6967 -4457
- package/dist/schema.d.ts +1 -1
- package/dist/schema.js +19 -1
- package/drizzle/0053_codex_credential_leases.sql +2 -2
- package/drizzle/0057_durable_queue_control.sql +1 -1
- package/drizzle/0061_session_workflow_wake_outbox.sql +1 -1
- package/drizzle/0062_session_list_snapshot_reaper.sql +1 -1
- package/drizzle/0063_session_control_mega_foundation.sql +1 -1
- package/drizzle/0064_rotation_strategy_sharded_backfill.sql +15 -0
- package/drizzle/0065_codex_subscription_overview.sql +168 -0
- package/drizzle/0065_session_attempt_quiescence.sql +26 -0
- package/drizzle/0065_session_tool_policy.sql +38 -0
- package/drizzle/0066_session_interruption_attempt_lookup.sql +4 -0
- package/drizzle/0067_session_event_payload_bounds.sql +209 -0
- package/drizzle/0068_workspace_control_event_bounds.sql +134 -0
- package/drizzle/0069_session_event_history_backfill.sql +32 -0
- package/drizzle/0070_session_event_type_sequence_lookup.sql +4 -0
- package/drizzle/0071_session_event_monitoring_tail.sql +10 -0
- package/drizzle/0072_sessions_workspace_created_id_idx.sql +4 -0
- package/drizzle/0073_sessions_workspace_updated_id_idx.sql +4 -0
- package/drizzle/0074_session_activity_revisions.sql +72 -0
- package/drizzle/0075_sessions_workspace_activity_revision_idx.sql +4 -0
- package/drizzle/0076_session_workflow_wake_acl.sql +13 -0
- package/drizzle/0077_session_attempt_latest_lookup.sql +4 -0
- package/drizzle/0094_quarantine_credential_bearing_catalog_urls.sql +51 -0
- package/drizzle/0095_github_existing_installations.sql +84 -0
- package/drizzle/0096_session_turn_initiators.sql +97 -0
- package/drizzle/0097_host_export_outbox.sql +1220 -0
- package/drizzle/0098_usage_events_workspace_session_idx.sql +4 -0
- package/drizzle/0099_session_human_input_attempt_owner_index.sql +6 -0
- package/drizzle/0100_session_human_input_requests.sql +89 -0
- package/drizzle/0101_session_mcp_connection_refs.sql +30 -0
- package/drizzle/0102_session_command_receipt_service_actor.sql +16 -0
- package/drizzle/0103_host_export_root_session.sql +166 -0
- package/drizzle/0104_host_export_root_session_backfill.sql +27 -0
- package/drizzle/0105_session_turn_instructions.sql +9 -0
- package/drizzle/0106_session_attempt_mcp_approval_policies.sql +29 -0
- package/drizzle/0107_host_export_lineage_contract.sql +381 -0
- package/drizzle/0108_fence_invalidated_warming_epochs.sql +76 -0
- package/package.json +5 -4
- package/src/codex-token-resolver.ts +175 -14
- package/src/connection-token-resolver.ts +428 -119
- package/src/event-payload-sanitizer.ts +88 -20
- package/src/index.ts +7208 -1273
- package/src/memory-domain.ts +1 -1
- package/src/migrate.ts +86 -23
- package/src/persistence-errors.ts +252 -0
- package/src/provision-roles.ts +42 -0
- package/src/schema.ts +658 -34
- package/src/session-control.ts +520 -38
- package/src/session-queue-commands.ts +385 -61
- package/src/session-tool-call-settlement.ts +58 -7
- package/src/turn-initiator.ts +155 -0
- package/dist/chunk-7LDU7F5P.js +0 -80
- package/dist/chunk-7LDU7F5P.js.map +0 -1
- package/dist/chunk-B22X3IEZ.js.map +0 -1
- package/dist/chunk-YFQ7SGE4.js.map +0 -1
|
@@ -26,6 +26,10 @@ import {
|
|
|
26
26
|
CodexReloginRequired,
|
|
27
27
|
type CodexTokenSnapshot,
|
|
28
28
|
type CodexUsagePayload,
|
|
29
|
+
type CodexFetch,
|
|
30
|
+
type CodexRateLimitResetCreditsDetails,
|
|
31
|
+
type ResetCreditFetchFailureReason,
|
|
32
|
+
fetchCodexRateLimitResetCredits,
|
|
29
33
|
fetchCodexUsage,
|
|
30
34
|
normalizeCodexUsage,
|
|
31
35
|
refreshCodexToken,
|
|
@@ -49,6 +53,92 @@ import {
|
|
|
49
53
|
// connected credential. Concurrent calls for the SAME credential still coalesce,
|
|
50
54
|
// so the one-time refresh token is never double-spent.
|
|
51
55
|
const inflight = new Map<string, Promise<CodexTokenSnapshot>>();
|
|
56
|
+
const CODEX_TOKEN_REFRESH_TIMEOUT_MS = 6_000;
|
|
57
|
+
|
|
58
|
+
export type CodexTokenDeadlineClock = {
|
|
59
|
+
setTimeout: (callback: () => void, delayMs: number) => ReturnType<typeof globalThis.setTimeout>;
|
|
60
|
+
clearTimeout: (handle: ReturnType<typeof globalThis.setTimeout>) => void;
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
export type CodexTokenDeadlineOptions = {
|
|
64
|
+
timeoutMs?: number | undefined;
|
|
65
|
+
signal?: AbortSignal | undefined;
|
|
66
|
+
clock?: CodexTokenDeadlineClock | undefined;
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
const systemCodexTokenDeadlineClock: CodexTokenDeadlineClock = {
|
|
70
|
+
setTimeout: (callback, delayMs) => globalThis.setTimeout(callback, delayMs),
|
|
71
|
+
clearTimeout: (handle) => globalThis.clearTimeout(handle),
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Bound a refresh promise without abandoning its rejection handler when the
|
|
76
|
+
* deadline or cancellation wins. The provider promise is observed exactly
|
|
77
|
+
* once, while the observer itself always fulfills, so a late provider failure
|
|
78
|
+
* cannot become an unhandled rejection or replace the authoritative outcome.
|
|
79
|
+
*/
|
|
80
|
+
export async function withCodexTokenDeadline<T>(
|
|
81
|
+
operation: Promise<T>,
|
|
82
|
+
options: CodexTokenDeadlineOptions = {},
|
|
83
|
+
): Promise<T> {
|
|
84
|
+
const timeoutMs = options.timeoutMs ?? CODEX_TOKEN_REFRESH_TIMEOUT_MS;
|
|
85
|
+
if (!Number.isFinite(timeoutMs) || timeoutMs <= 0) {
|
|
86
|
+
throw new Error("Codex token refresh timeout must be positive");
|
|
87
|
+
}
|
|
88
|
+
const clock = options.clock ?? systemCodexTokenDeadlineClock;
|
|
89
|
+
const signal = options.signal;
|
|
90
|
+
|
|
91
|
+
return await new Promise<T>((resolve, reject) => {
|
|
92
|
+
let settled = false;
|
|
93
|
+
let timeout: ReturnType<typeof globalThis.setTimeout> | undefined;
|
|
94
|
+
|
|
95
|
+
const cleanup = (): void => {
|
|
96
|
+
if (timeout !== undefined) {
|
|
97
|
+
clock.clearTimeout(timeout);
|
|
98
|
+
timeout = undefined;
|
|
99
|
+
}
|
|
100
|
+
signal?.removeEventListener("abort", onAbort);
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
const settle = (
|
|
104
|
+
outcome: { kind: "resolve"; value: T } | { kind: "reject"; error: unknown },
|
|
105
|
+
) => {
|
|
106
|
+
if (settled) return;
|
|
107
|
+
settled = true;
|
|
108
|
+
cleanup();
|
|
109
|
+
if (outcome.kind === "resolve") {
|
|
110
|
+
resolve(outcome.value);
|
|
111
|
+
} else {
|
|
112
|
+
reject(outcome.error);
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
const onAbort = (): void => {
|
|
117
|
+
settle({
|
|
118
|
+
kind: "reject",
|
|
119
|
+
error: signal?.reason ?? new Error("Codex token refresh cancelled"),
|
|
120
|
+
});
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
if (signal?.aborted) {
|
|
124
|
+
onAbort();
|
|
125
|
+
} else {
|
|
126
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
127
|
+
timeout = clock.setTimeout(
|
|
128
|
+
() => settle({ kind: "reject", error: new Error("Codex token refresh timed out") }),
|
|
129
|
+
timeoutMs,
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Do not use Promise.race here. Its derived promise can obscure which
|
|
134
|
+
// branch owns settlement, while this fulfillment-only observer makes the
|
|
135
|
+
// losing provider branch explicitly consumed after timeout/cancellation.
|
|
136
|
+
void Promise.resolve(operation).then(
|
|
137
|
+
(value) => settle({ kind: "resolve", value }),
|
|
138
|
+
(error) => settle({ kind: "reject", error }),
|
|
139
|
+
);
|
|
140
|
+
});
|
|
141
|
+
}
|
|
52
142
|
|
|
53
143
|
// Dependencies are injectable so the lifecycle logic (single-flight, staleness,
|
|
54
144
|
// needs_relogin transition) is unit-testable without a database. Production uses
|
|
@@ -96,7 +186,10 @@ export function buildCodexTokenResolver(
|
|
|
96
186
|
cred: CodexCredentialForRun,
|
|
97
187
|
): Promise<CodexTokenSnapshot> => {
|
|
98
188
|
try {
|
|
99
|
-
|
|
189
|
+
// Bound even injected/custom refresh implementations that ignore abort
|
|
190
|
+
// signals. The provider client has its own AbortController timeout; this
|
|
191
|
+
// outer fence ensures the DB advisory transaction cannot be held forever.
|
|
192
|
+
const next = await withCodexTokenDeadline(deps.refresh(cred.tokens.refreshToken));
|
|
100
193
|
const tokens = {
|
|
101
194
|
access_token: next.accessToken ?? cred.tokens.accessToken,
|
|
102
195
|
refresh_token: next.refreshToken ?? cred.tokens.refreshToken,
|
|
@@ -219,6 +312,7 @@ function errorUsagePayload(reason?: "needs_relogin"): CodexUsagePayload {
|
|
|
219
312
|
weekly: null,
|
|
220
313
|
limitReached: false,
|
|
221
314
|
fetchedAt: new Date().toISOString(),
|
|
315
|
+
rateLimitResetCredits: null,
|
|
222
316
|
...(reason ? { reason } : {}),
|
|
223
317
|
};
|
|
224
318
|
}
|
|
@@ -242,6 +336,7 @@ export async function fetchCodexUsageForAccount(
|
|
|
242
336
|
settings: Settings,
|
|
243
337
|
workspaceId: string,
|
|
244
338
|
credentialId: string,
|
|
339
|
+
fetchImpl: CodexFetch = fetch,
|
|
245
340
|
): Promise<CodexUsagePayload> {
|
|
246
341
|
const resolver = buildCodexTokenResolver(db, settings, workspaceId, credentialId);
|
|
247
342
|
let token: CodexTokenSnapshot;
|
|
@@ -253,12 +348,15 @@ export async function fetchCodexUsageForAccount(
|
|
|
253
348
|
|
|
254
349
|
let normalized: CodexUsagePayload;
|
|
255
350
|
try {
|
|
256
|
-
const usage = await fetchCodexUsage(
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
351
|
+
const usage = await fetchCodexUsage(
|
|
352
|
+
{
|
|
353
|
+
accessToken: token.accessToken,
|
|
354
|
+
chatgptAccountId: token.chatgptAccountId,
|
|
355
|
+
isFedramp: token.isFedramp,
|
|
356
|
+
clientVersion: CODEX_CLIENT_VERSION,
|
|
357
|
+
},
|
|
358
|
+
fetchImpl,
|
|
359
|
+
);
|
|
262
360
|
normalized = normalizeCodexUsage(usage.status, usage.payload);
|
|
263
361
|
} catch {
|
|
264
362
|
// A network throw on the /wham/usage read must surface as an error PAYLOAD
|
|
@@ -266,17 +364,80 @@ export async function fetchCodexUsageForAccount(
|
|
|
266
364
|
return errorUsagePayload();
|
|
267
365
|
}
|
|
268
366
|
|
|
269
|
-
|
|
367
|
+
const parsedQuota =
|
|
368
|
+
normalized.status !== "error" && (normalized.fiveHour != null || normalized.weekly != null);
|
|
369
|
+
if (parsedQuota || normalized.rateLimitResetCredits) {
|
|
370
|
+
const checkedAt = new Date();
|
|
371
|
+
// Quota windows and reset-summary freshness are independent. A malformed
|
|
372
|
+
// usage body can still carry a syntactically valid count; that count may be
|
|
373
|
+
// cached without erasing or falsely refreshing the last valid quota truth.
|
|
270
374
|
// Cache-write is best-effort: a disconnect under us (false) or a transient
|
|
271
|
-
// write error must NOT sink the freshly-read
|
|
375
|
+
// write error must NOT sink the freshly-read result we are about to return.
|
|
272
376
|
await recordCodexAccountUsage(db, workspaceId, credentialId, {
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
377
|
+
...(parsedQuota
|
|
378
|
+
? {
|
|
379
|
+
primaryUsedPercent: normalized.fiveHour?.percent ?? null,
|
|
380
|
+
primaryResetAt: normalized.fiveHour?.resetAt
|
|
381
|
+
? new Date(normalized.fiveHour.resetAt)
|
|
382
|
+
: null,
|
|
383
|
+
secondaryUsedPercent: normalized.weekly?.percent ?? null,
|
|
384
|
+
secondaryResetAt: normalized.weekly?.resetAt
|
|
385
|
+
? new Date(normalized.weekly.resetAt)
|
|
386
|
+
: null,
|
|
387
|
+
checkedAt,
|
|
388
|
+
}
|
|
389
|
+
: {}),
|
|
390
|
+
...(normalized.rateLimitResetCredits
|
|
391
|
+
? {
|
|
392
|
+
resetCreditAvailableCount: normalized.rateLimitResetCredits.availableCount,
|
|
393
|
+
resetCreditsCheckedAt: checkedAt,
|
|
394
|
+
}
|
|
395
|
+
: {}),
|
|
278
396
|
}).catch(() => undefined);
|
|
279
397
|
}
|
|
280
398
|
|
|
281
399
|
return normalized;
|
|
282
400
|
}
|
|
401
|
+
|
|
402
|
+
export type CodexRateLimitResetCreditsAccountResult =
|
|
403
|
+
| { ok: true; status: number; details: CodexRateLimitResetCreditsDetails }
|
|
404
|
+
| {
|
|
405
|
+
ok: false;
|
|
406
|
+
status: number;
|
|
407
|
+
reason: ResetCreditFetchFailureReason | "needs_relogin";
|
|
408
|
+
};
|
|
409
|
+
|
|
410
|
+
/**
|
|
411
|
+
* Fresh detailed reset-credit inventory for one exact workspace credential.
|
|
412
|
+
* The token is refreshed through the same resolver as usage and never escapes
|
|
413
|
+
* this server-side function. Detailed rows are returned to the route only and
|
|
414
|
+
* are never persisted as redemption authority.
|
|
415
|
+
*/
|
|
416
|
+
export async function fetchCodexRateLimitResetCreditsForAccount(
|
|
417
|
+
db: Database,
|
|
418
|
+
settings: Settings,
|
|
419
|
+
workspaceId: string,
|
|
420
|
+
credentialId: string,
|
|
421
|
+
fetchImpl: CodexFetch = fetch,
|
|
422
|
+
): Promise<CodexRateLimitResetCreditsAccountResult> {
|
|
423
|
+
const resolver = buildCodexTokenResolver(db, settings, workspaceId, credentialId);
|
|
424
|
+
let token: CodexTokenSnapshot;
|
|
425
|
+
try {
|
|
426
|
+
token = await resolver.getToken();
|
|
427
|
+
} catch (error) {
|
|
428
|
+
return {
|
|
429
|
+
ok: false,
|
|
430
|
+
status: 0,
|
|
431
|
+
reason: error instanceof CodexReloginRequired ? "needs_relogin" : "network_error",
|
|
432
|
+
};
|
|
433
|
+
}
|
|
434
|
+
return await fetchCodexRateLimitResetCredits(
|
|
435
|
+
{
|
|
436
|
+
accessToken: token.accessToken,
|
|
437
|
+
chatgptAccountId: token.chatgptAccountId,
|
|
438
|
+
isFedramp: token.isFedramp,
|
|
439
|
+
clientVersion: CODEX_CLIENT_VERSION,
|
|
440
|
+
},
|
|
441
|
+
fetchImpl,
|
|
442
|
+
);
|
|
443
|
+
}
|