@opengeni/db 0.27.9 → 0.27.11

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/index.js CHANGED
@@ -5,6 +5,7 @@ import {
5
5
  billingCustomers,
6
6
  capabilityCatalogItems,
7
7
  capabilityInstallations,
8
+ codexAppsSettings,
8
9
  codexCapacityWaiters,
9
10
  codexCredentialLeases,
10
11
  codexResetRedemptionAttempts,
@@ -114,7 +115,7 @@ import {
114
115
  workspaceVariableSetVariables,
115
116
  workspaceVariableSets,
116
117
  workspaces
117
- } from "./chunk-NX2JNJJP.js";
118
+ } from "./chunk-JYQPJ6Y5.js";
118
119
  import {
119
120
  migrate,
120
121
  runMigrations
@@ -134,7 +135,7 @@ import {
134
135
  inspectRuntimeDatabasePosture,
135
136
  provisionRoles,
136
137
  runtimeDatabaseReadyCheck
137
- } from "./chunk-2JFRTKTG.js";
138
+ } from "./chunk-RPHPNVWW.js";
138
139
  import "./chunk-PZ5AY32C.js";
139
140
 
140
141
  // src/index.ts
@@ -20451,11 +20452,10 @@ async function upsertCodexSubscriptionCredential(db, input) {
20451
20452
  // it when still null) so a re-connect never clobbers a rename.
20452
20453
  accountEmail: input.accountEmail ?? null,
20453
20454
  label: sql15`coalesce(${codexSubscriptionCredentials.label}, ${input.label ?? null})`,
20454
- // Ownership follows the most recent connection exactly. A
20455
- // configured/delegated/API-key reconnect is intentionally
20456
- // nonhuman and clears the prior human owner, making the row
20457
- // view-only until a direct managed-cookie human reconnects it.
20458
- connectedBySubjectId: input.connectedBySubjectId ?? null,
20455
+ // Reconnect refreshes credential material, never ownership. A row
20456
+ // without an owner may be claimed by its first direct managed human;
20457
+ // after that, disconnect is the explicit ownership-reset boundary.
20458
+ connectedBySubjectId: sql15`coalesce(${codexSubscriptionCredentials.connectedBySubjectId}, ${input.connectedBySubjectId ?? null})`,
20459
20459
  status: "active",
20460
20460
  lastError: null,
20461
20461
  version: sql15`${codexSubscriptionCredentials.version} + 1`,
@@ -20474,6 +20474,198 @@ async function upsertCodexSubscriptionCredential(db, input) {
20474
20474
  }
20475
20475
  );
20476
20476
  }
20477
+ async function getCodexAppsSettings(db, workspaceId) {
20478
+ return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {
20479
+ const [row] = await scopedDb.select({
20480
+ credentialId: codexAppsSettings.credentialId,
20481
+ version: codexAppsSettings.version,
20482
+ designatedAt: codexAppsSettings.designatedAt
20483
+ }).from(codexAppsSettings).where(eq18(codexAppsSettings.workspaceId, workspaceId)).limit(1);
20484
+ return row ?? { credentialId: null, version: 0, designatedAt: null };
20485
+ });
20486
+ }
20487
+ function canManageCodexApps(permissions) {
20488
+ return Array.isArray(permissions) && (permissions.includes("connections:write") || permissions.includes("workspace:admin"));
20489
+ }
20490
+ var CodexAppsAuthorizationRevokedError = class extends Error {
20491
+ constructor() {
20492
+ super("Codex Apps authorization is no longer active");
20493
+ this.name = "CodexAppsAuthorizationRevokedError";
20494
+ }
20495
+ };
20496
+ async function getCodexAppsCredentialAuthorizationForRun(db, workspaceId) {
20497
+ return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {
20498
+ const [row] = await scopedDb.select({
20499
+ credentialId: codexAppsSettings.credentialId,
20500
+ ownerSubjectId: codexSubscriptionCredentials.connectedBySubjectId
20501
+ }).from(codexAppsSettings).innerJoin(
20502
+ codexSubscriptionCredentials,
20503
+ and17(
20504
+ eq18(codexSubscriptionCredentials.id, codexAppsSettings.credentialId),
20505
+ eq18(codexSubscriptionCredentials.accountId, codexAppsSettings.accountId),
20506
+ eq18(codexSubscriptionCredentials.workspaceId, workspaceId),
20507
+ eq18(codexSubscriptionCredentials.status, "active")
20508
+ )
20509
+ ).where(eq18(codexAppsSettings.workspaceId, workspaceId)).limit(1);
20510
+ return row?.credentialId && row.ownerSubjectId ? { credentialId: row.credentialId, ownerSubjectId: row.ownerSubjectId } : null;
20511
+ });
20512
+ }
20513
+ async function withCodexAppsRequestAuthorization(db, input, use) {
20514
+ return await withWorkspaceRls(db, input.workspaceId, async (scopedDb) => {
20515
+ await scopedDb.execute(
20516
+ sql15`select pg_advisory_xact_lock(hashtextextended(${`codex-apps-settings:${input.workspaceId}`}, 0))`
20517
+ );
20518
+ const [designation] = await scopedDb.select({ credentialId: codexAppsSettings.credentialId }).from(codexAppsSettings).where(eq18(codexAppsSettings.workspaceId, input.workspaceId)).for("share").limit(1);
20519
+ if (designation?.credentialId !== input.credentialId) {
20520
+ throw new CodexAppsAuthorizationRevokedError();
20521
+ }
20522
+ const [credential] = await scopedDb.select({
20523
+ ownerSubjectId: codexSubscriptionCredentials.connectedBySubjectId,
20524
+ status: codexSubscriptionCredentials.status
20525
+ }).from(codexSubscriptionCredentials).where(
20526
+ and17(
20527
+ eq18(codexSubscriptionCredentials.workspaceId, input.workspaceId),
20528
+ eq18(codexSubscriptionCredentials.id, input.credentialId)
20529
+ )
20530
+ ).for("share").limit(1);
20531
+ if (!credential?.ownerSubjectId || credential.status !== "active") {
20532
+ throw new CodexAppsAuthorizationRevokedError();
20533
+ }
20534
+ const [membership] = await scopedDb.select({ permissions: workspaceMemberships.permissions }).from(workspaceMemberships).where(
20535
+ and17(
20536
+ eq18(workspaceMemberships.workspaceId, input.workspaceId),
20537
+ eq18(workspaceMemberships.subjectId, credential.ownerSubjectId)
20538
+ )
20539
+ ).for("share").limit(1);
20540
+ if (!canManageCodexApps(membership?.permissions)) {
20541
+ throw new CodexAppsAuthorizationRevokedError();
20542
+ }
20543
+ return await use();
20544
+ });
20545
+ }
20546
+ async function designateCodexAppsCredential(db, input) {
20547
+ return await withRlsContext(
20548
+ db,
20549
+ { accountId: input.accountId, workspaceId: input.workspaceId },
20550
+ async (scopedDb) => {
20551
+ await scopedDb.execute(
20552
+ sql15`select pg_advisory_xact_lock(hashtextextended(${`codex-apps-settings:${input.workspaceId}`}, 0))`
20553
+ );
20554
+ const [currentRow] = await scopedDb.select().from(codexAppsSettings).where(eq18(codexAppsSettings.workspaceId, input.workspaceId)).for("update").limit(1);
20555
+ const current = currentRow ? {
20556
+ credentialId: currentRow.credentialId,
20557
+ version: currentRow.version,
20558
+ designatedAt: currentRow.designatedAt
20559
+ } : { credentialId: null, version: 0, designatedAt: null };
20560
+ if (current.version !== input.expectedVersion) return { kind: "conflict", ...current };
20561
+ if (current.credentialId !== null) return { kind: "already_designated", ...current };
20562
+ const [credential] = await scopedDb.select({
20563
+ connectedBySubjectId: codexSubscriptionCredentials.connectedBySubjectId,
20564
+ status: codexSubscriptionCredentials.status
20565
+ }).from(codexSubscriptionCredentials).where(
20566
+ and17(
20567
+ eq18(codexSubscriptionCredentials.accountId, input.accountId),
20568
+ eq18(codexSubscriptionCredentials.workspaceId, input.workspaceId),
20569
+ eq18(codexSubscriptionCredentials.id, input.credentialId)
20570
+ )
20571
+ ).for("update").limit(1);
20572
+ if (!credential) return { kind: "not_found" };
20573
+ if (credential.connectedBySubjectId !== input.subjectId) return { kind: "not_owner" };
20574
+ if (credential.status !== "active") return { kind: "unavailable" };
20575
+ const [membership] = await scopedDb.select({ permissions: workspaceMemberships.permissions }).from(workspaceMemberships).where(
20576
+ and17(
20577
+ eq18(workspaceMemberships.accountId, input.accountId),
20578
+ eq18(workspaceMemberships.workspaceId, input.workspaceId),
20579
+ eq18(workspaceMemberships.subjectId, input.subjectId)
20580
+ )
20581
+ ).for("update").limit(1);
20582
+ if (!canManageCodexApps(membership?.permissions)) return { kind: "forbidden" };
20583
+ const now = /* @__PURE__ */ new Date();
20584
+ const version = current.version + 1;
20585
+ const [updated] = await scopedDb.insert(codexAppsSettings).values({
20586
+ accountId: input.accountId,
20587
+ workspaceId: input.workspaceId,
20588
+ credentialId: input.credentialId,
20589
+ version,
20590
+ designatedAt: now,
20591
+ updatedAt: now
20592
+ }).onConflictDoUpdate({
20593
+ target: codexAppsSettings.workspaceId,
20594
+ set: {
20595
+ credentialId: input.credentialId,
20596
+ version,
20597
+ designatedAt: now,
20598
+ updatedAt: now
20599
+ }
20600
+ }).returning({
20601
+ credentialId: codexAppsSettings.credentialId,
20602
+ version: codexAppsSettings.version,
20603
+ designatedAt: codexAppsSettings.designatedAt
20604
+ });
20605
+ if (!updated?.credentialId || !updated.designatedAt) {
20606
+ throw new Error("Codex Apps designation was not persisted");
20607
+ }
20608
+ await scopedDb.insert(auditEvents).values({
20609
+ accountId: input.accountId,
20610
+ workspaceId: input.workspaceId,
20611
+ subjectId: input.subjectId,
20612
+ action: "codex_apps.designated",
20613
+ targetType: "codex_subscription_credential",
20614
+ targetId: input.credentialId,
20615
+ metadata: { version }
20616
+ });
20617
+ return { kind: "updated", ...updated };
20618
+ }
20619
+ );
20620
+ }
20621
+ async function clearCodexAppsCredential(db, input) {
20622
+ return await withRlsContext(
20623
+ db,
20624
+ { accountId: input.accountId, workspaceId: input.workspaceId },
20625
+ async (scopedDb) => {
20626
+ await scopedDb.execute(
20627
+ sql15`select pg_advisory_xact_lock(hashtextextended(${`codex-apps-settings:${input.workspaceId}`}, 0))`
20628
+ );
20629
+ const [row] = await scopedDb.select().from(codexAppsSettings).where(eq18(codexAppsSettings.workspaceId, input.workspaceId)).for("update").limit(1);
20630
+ const current = row ? { credentialId: row.credentialId, version: row.version, designatedAt: row.designatedAt } : { credentialId: null, version: 0, designatedAt: null };
20631
+ const [membership] = await scopedDb.select({ permissions: workspaceMemberships.permissions }).from(workspaceMemberships).where(
20632
+ and17(
20633
+ eq18(workspaceMemberships.accountId, input.accountId),
20634
+ eq18(workspaceMemberships.workspaceId, input.workspaceId),
20635
+ eq18(workspaceMemberships.subjectId, input.subjectId)
20636
+ )
20637
+ ).for("update").limit(1);
20638
+ if (!canManageCodexApps(membership?.permissions)) {
20639
+ return { kind: "forbidden", ...current };
20640
+ }
20641
+ if (current.version !== input.expectedVersion) return { kind: "conflict", ...current };
20642
+ if (current.credentialId === null) return { kind: "unchanged", ...current };
20643
+ const now = /* @__PURE__ */ new Date();
20644
+ const version = current.version + 1;
20645
+ const [updated] = await scopedDb.update(codexAppsSettings).set({
20646
+ credentialId: null,
20647
+ version,
20648
+ designatedAt: null,
20649
+ updatedAt: now
20650
+ }).where(eq18(codexAppsSettings.workspaceId, input.workspaceId)).returning({
20651
+ credentialId: codexAppsSettings.credentialId,
20652
+ version: codexAppsSettings.version,
20653
+ designatedAt: codexAppsSettings.designatedAt
20654
+ });
20655
+ if (!updated) throw new Error("Codex Apps designation clear was not persisted");
20656
+ await scopedDb.insert(auditEvents).values({
20657
+ accountId: input.accountId,
20658
+ workspaceId: input.workspaceId,
20659
+ subjectId: input.subjectId,
20660
+ action: "codex_apps.cleared",
20661
+ targetType: "codex_subscription_credential",
20662
+ targetId: current.credentialId,
20663
+ metadata: { version }
20664
+ });
20665
+ return { kind: "updated", ...updated };
20666
+ }
20667
+ );
20668
+ }
20477
20669
  async function loadCodexCredentialForRun(db, settings, workspaceId, credentialId) {
20478
20670
  const key = environmentsEncryptionKeyBytes(settings);
20479
20671
  if (!key) {
@@ -20708,8 +20900,6 @@ function mapCodexLeaseCandidate(row, activeCredentialId) {
20708
20900
  secondaryResetAt: codexMetadataDate(row.secondary_reset_at),
20709
20901
  usageCheckedAt: codexMetadataDate(row.usage_checked_at),
20710
20902
  exhaustedUntil: codexMetadataDate(row.exhausted_until),
20711
- connectorNamespaces: row.connector_namespaces,
20712
- connectorsCheckedAt: codexMetadataDate(row.connectors_checked_at),
20713
20903
  selectionCount: Number(row.selection_count),
20714
20904
  lastSelectedAt: codexMetadataDate(row.last_selected_at),
20715
20905
  activeLeaseCount: Number(row.active_lease_count)
@@ -20750,8 +20940,6 @@ async function listCodexLeaseCandidatesInTransaction(tx, input) {
20750
20940
  c.secondary_reset_at,
20751
20941
  c.usage_checked_at,
20752
20942
  c.exhausted_until,
20753
- c.connector_namespaces,
20754
- c.connectors_checked_at,
20755
20943
  c.selection_count,
20756
20944
  c.last_selected_at,
20757
20945
  count(l.id) filter (
@@ -20809,18 +20997,6 @@ async function acquireCodexCredentialLease(db, input, select) {
20809
20997
  throw new Error(`Session turn not found for Codex lease: ${input.turnId}`);
20810
20998
  }
20811
20999
  const policyScope = input.resolvePolicyScope?.(turns[0].metadata ?? {}) ?? null;
20812
- const continuationRows = input.continuationCredentialId ? await tx.execute(
20813
- sql15`
20814
- select frozen_codex_credential_id
20815
- from agent_run_states
20816
- where account_id = ${input.accountId}
20817
- and workspace_id = ${input.workspaceId}
20818
- and turn_id = ${input.turnId}
20819
- order by state_version desc
20820
- limit 1
20821
- `
20822
- ) : [];
20823
- const validatedContinuationCredentialId = continuationRows[0]?.frozen_codex_credential_id === input.continuationCredentialId ? input.continuationCredentialId : null;
20824
21000
  const activeCredentialId = settingsRow.active_credential_id;
20825
21001
  const rotationEnabled = settingsRow.rotation_enabled;
20826
21002
  const leaseRotationEnabled = settingsRow.rotation_enabled && settingsRow.lease_rotation_enabled;
@@ -20847,7 +21023,7 @@ async function acquireCodexCredentialLease(db, input, select) {
20847
21023
  activeCredentialId,
20848
21024
  excludeTurnId: input.turnId
20849
21025
  });
20850
- const sameTurnCredentialId = existingCredentialId ?? validatedContinuationCredentialId;
21026
+ const sameTurnCredentialId = existingCredentialId;
20851
21027
  const selectionContext = (accounts2, unavailableDiagnostics2) => ({
20852
21028
  accounts: accounts2,
20853
21029
  activeCredentialId,
@@ -20903,7 +21079,7 @@ async function acquireCodexCredentialLease(db, input, select) {
20903
21079
  if (!selectedAccount) {
20904
21080
  throw new Error("Codex lease selector returned a credential outside the workspace pool");
20905
21081
  }
20906
- if (!selectedAccount.allocatorEnabled && selectedAccount.id !== existingCredentialId && selectedAccount.id !== validatedContinuationCredentialId) {
21082
+ if (!selectedAccount.allocatorEnabled && selectedAccount.id !== existingCredentialId) {
20907
21083
  throw new Error("Codex lease selector returned a credential disabled for new allocations");
20908
21084
  }
20909
21085
  const advanceActivePointer = input.advanceActivePointer && selected.advanceActivePointer !== false;
@@ -21816,10 +21992,7 @@ async function listCodexAccountStatuses(db, workspaceId) {
21816
21992
  secondaryUsedPercent: codexSubscriptionCredentials.secondaryUsedPercent,
21817
21993
  secondaryResetAt: codexSubscriptionCredentials.secondaryResetAt,
21818
21994
  usageCheckedAt: codexSubscriptionCredentials.usageCheckedAt,
21819
- exhaustedUntil: codexSubscriptionCredentials.exhaustedUntil,
21820
- // P4 connector-set cache — metadata-only, rides along on this read.
21821
- connectorNamespaces: codexSubscriptionCredentials.connectorNamespaces,
21822
- connectorsCheckedAt: codexSubscriptionCredentials.connectorsCheckedAt
21995
+ exhaustedUntil: codexSubscriptionCredentials.exhaustedUntil
21823
21996
  }).from(codexSubscriptionCredentials).where(eq18(codexSubscriptionCredentials.workspaceId, workspaceId)).orderBy(
21824
21997
  asc8(codexSubscriptionCredentials.createdAt),
21825
21998
  asc8(codexSubscriptionCredentials.id)
@@ -21834,7 +22007,6 @@ async function listCodexAccountStatuses(db, workspaceId) {
21834
22007
  secondaryResetAt: codexMetadataDate(row.secondaryResetAt),
21835
22008
  usageCheckedAt: codexMetadataDate(row.usageCheckedAt),
21836
22009
  exhaustedUntil: codexMetadataDate(row.exhaustedUntil),
21837
- connectorsCheckedAt: codexMetadataDate(row.connectorsCheckedAt),
21838
22010
  isActive: row.id === activeId
21839
22011
  }));
21840
22012
  });
@@ -22552,23 +22724,6 @@ async function countConsecutiveReactiveRotations(db, workspaceId, sessionId) {
22552
22724
  return Number(rotated);
22553
22725
  });
22554
22726
  }
22555
- async function recordCodexAccountConnectors(db, workspaceId, credentialId, namespaces) {
22556
- return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {
22557
- const updated = await scopedDb.update(codexSubscriptionCredentials).set({
22558
- connectorNamespaces: namespaces,
22559
- connectorsCheckedAt: /* @__PURE__ */ new Date()
22560
- // NB: no `version` bump and no `updatedAt` touch — connector set is non-credential
22561
- // metadata and must NOT race the (id, version) refresh CAS (same discipline as
22562
- // recordCodexAccountUsage / setCodexCredentialExhausted).
22563
- }).where(
22564
- and17(
22565
- eq18(codexSubscriptionCredentials.id, credentialId),
22566
- eq18(codexSubscriptionCredentials.workspaceId, workspaceId)
22567
- )
22568
- ).returning({ id: codexSubscriptionCredentials.id });
22569
- return updated.length > 0;
22570
- });
22571
- }
22572
22727
  var CODEX_ROTATION_STRATEGIES = [
22573
22728
  "most_remaining",
22574
22729
  "round_robin",
@@ -22667,14 +22822,21 @@ async function recordSessionActiveCodexCredential(db, workspaceId, sessionId, cr
22667
22822
  await scopedDb.update(sessions).set({ codexLastCredentialId: credentialId, updatedAt: /* @__PURE__ */ new Date() }).where(and17(eq18(sessions.workspaceId, workspaceId), eq18(sessions.id, sessionId)));
22668
22823
  });
22669
22824
  }
22670
- async function disconnectCodexAccount(db, workspaceId, credentialId) {
22825
+ async function disconnectCodexAccount(db, workspaceId, credentialId, actorSubjectId = null) {
22671
22826
  return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {
22672
22827
  await scopedDb.execute(sql15`
22673
22828
  select id from codex_rotation_settings
22674
22829
  where workspace_id = ${workspaceId}
22675
22830
  for update
22676
22831
  `);
22677
- const [credential] = await scopedDb.select({ id: codexSubscriptionCredentials.id }).from(codexSubscriptionCredentials).where(
22832
+ await scopedDb.execute(
22833
+ sql15`select pg_advisory_xact_lock(hashtextextended(${`codex-apps-settings:${workspaceId}`}, 0))`
22834
+ );
22835
+ const [appsSettings] = await scopedDb.select().from(codexAppsSettings).where(eq18(codexAppsSettings.workspaceId, workspaceId)).for("update").limit(1);
22836
+ const [credential] = await scopedDb.select({
22837
+ id: codexSubscriptionCredentials.id,
22838
+ accountId: codexSubscriptionCredentials.accountId
22839
+ }).from(codexSubscriptionCredentials).where(
22678
22840
  and17(
22679
22841
  eq18(codexSubscriptionCredentials.id, credentialId),
22680
22842
  eq18(codexSubscriptionCredentials.workspaceId, workspaceId)
@@ -22704,6 +22866,24 @@ async function disconnectCodexAccount(db, workspaceId, credentialId) {
22704
22866
  blockedByUnresolvedRedemption: true
22705
22867
  };
22706
22868
  }
22869
+ if (appsSettings?.credentialId === credentialId) {
22870
+ const version = appsSettings.version + 1;
22871
+ await scopedDb.update(codexAppsSettings).set({
22872
+ credentialId: null,
22873
+ version,
22874
+ designatedAt: null,
22875
+ updatedAt: /* @__PURE__ */ new Date()
22876
+ }).where(eq18(codexAppsSettings.id, appsSettings.id));
22877
+ await scopedDb.insert(auditEvents).values({
22878
+ accountId: credential.accountId,
22879
+ workspaceId,
22880
+ subjectId: actorSubjectId,
22881
+ action: "codex_apps.cleared_on_disconnect",
22882
+ targetType: "codex_subscription_credential",
22883
+ targetId: credentialId,
22884
+ metadata: { version }
22885
+ });
22886
+ }
22707
22887
  const removedRows = await scopedDb.delete(codexSubscriptionCredentials).where(
22708
22888
  and17(
22709
22889
  eq18(codexSubscriptionCredentials.id, credentialId),
@@ -22735,9 +22915,16 @@ async function disconnectCodexAccount(db, workspaceId, credentialId) {
22735
22915
  };
22736
22916
  });
22737
22917
  }
22738
- async function disconnectAllCodexAccounts(db, workspaceId) {
22918
+ async function disconnectAllCodexAccounts(db, workspaceId, actorSubjectId = null) {
22739
22919
  return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {
22740
- const credentials = await scopedDb.select({ id: codexSubscriptionCredentials.id }).from(codexSubscriptionCredentials).where(eq18(codexSubscriptionCredentials.workspaceId, workspaceId)).orderBy(asc8(codexSubscriptionCredentials.id)).for("update");
22920
+ await scopedDb.execute(
22921
+ sql15`select pg_advisory_xact_lock(hashtextextended(${`codex-apps-settings:${workspaceId}`}, 0))`
22922
+ );
22923
+ const [appsSettings] = await scopedDb.select().from(codexAppsSettings).where(eq18(codexAppsSettings.workspaceId, workspaceId)).for("update").limit(1);
22924
+ const credentials = await scopedDb.select({
22925
+ id: codexSubscriptionCredentials.id,
22926
+ accountId: codexSubscriptionCredentials.accountId
22927
+ }).from(codexSubscriptionCredentials).where(eq18(codexSubscriptionCredentials.workspaceId, workspaceId)).orderBy(asc8(codexSubscriptionCredentials.id)).for("update");
22741
22928
  if (credentials.length === 0) return { removed: 0, blockedCredentialIds: [] };
22742
22929
  const blocked = await scopedDb.selectDistinct({
22743
22930
  credentialId: codexResetRedemptionAttempts.credentialId
@@ -22753,6 +22940,24 @@ async function disconnectAllCodexAccounts(db, workspaceId) {
22753
22940
  blockedCredentialIds: blocked.map((row) => row.credentialId).sort()
22754
22941
  };
22755
22942
  }
22943
+ if (appsSettings?.credentialId) {
22944
+ const version = appsSettings.version + 1;
22945
+ await scopedDb.update(codexAppsSettings).set({
22946
+ credentialId: null,
22947
+ version,
22948
+ designatedAt: null,
22949
+ updatedAt: /* @__PURE__ */ new Date()
22950
+ }).where(eq18(codexAppsSettings.id, appsSettings.id));
22951
+ await scopedDb.insert(auditEvents).values({
22952
+ accountId: credentials[0].accountId,
22953
+ workspaceId,
22954
+ subjectId: actorSubjectId,
22955
+ action: "codex_apps.cleared_on_disconnect",
22956
+ targetType: "codex_subscription_credential",
22957
+ targetId: appsSettings.credentialId,
22958
+ metadata: { version }
22959
+ });
22960
+ }
22756
22961
  const rows = await scopedDb.delete(codexSubscriptionCredentials).where(eq18(codexSubscriptionCredentials.workspaceId, workspaceId)).returning({ id: codexSubscriptionCredentials.id });
22757
22962
  return { removed: rows.length, blockedCredentialIds: [] };
22758
22963
  });
@@ -23707,6 +23912,13 @@ async function lockSessionCreateIdempotencyKey(tx, workspaceId, createIdempotenc
23707
23912
  sql15`select pg_advisory_xact_lock(hashtext(${`session-create:${workspaceId}:${createIdempotencyKey}`}))`
23708
23913
  );
23709
23914
  }
23915
+ async function lockAgentSessionCreate(tx, input) {
23916
+ const actorSessionId = input.createdByActor?.sessionId;
23917
+ if (!actorSessionId) return;
23918
+ await tx.execute(
23919
+ sql15`select pg_advisory_xact_lock(hashtextextended(${`agent-session-create:${input.workspaceId}:${actorSessionId}`}, 0))`
23920
+ );
23921
+ }
23710
23922
  async function existingSpawnDenialForKey(tx, workspaceId, createIdempotencyKey) {
23711
23923
  const [existing] = await tx.select().from(sessionSpawnDenials).where(
23712
23924
  and17(
@@ -23780,6 +23992,7 @@ async function createSessionInTransaction(tx, input, id) {
23780
23992
  };
23781
23993
  }
23782
23994
  }
23995
+ await lockAgentSessionCreate(tx, input);
23783
23996
  const decision = await resolveSessionDepthDecision(tx, input, id, workspace, deploymentPolicy);
23784
23997
  if (decision.denied) {
23785
23998
  return {
@@ -25754,7 +25967,6 @@ async function getLatestRunState(db, workspaceId, sessionId) {
25754
25967
  turnId: row.turnId ?? null,
25755
25968
  serializedRunState: row.serializedRunState,
25756
25969
  pendingApprovals: row.pendingApprovals,
25757
- frozenCodexCredentialId: row.frozenCodexCredentialId ?? null,
25758
25970
  providerArtifactInvalidatedAt: row.providerArtifactInvalidatedAt ?? null
25759
25971
  } : null;
25760
25972
  });
@@ -26255,7 +26467,6 @@ async function appendSessionHistoryItems(db, input) {
26255
26467
  workspaceId: input.workspaceId,
26256
26468
  sessionId: input.sessionId,
26257
26469
  turnId: input.turnId,
26258
- producerCodexCredentialId: input.producerCodexCredentialId ?? null,
26259
26470
  position: entry.position,
26260
26471
  // This is the canonical model-memory boundary. The pending-call
26261
26472
  // ledger and audit event may retain their separate raw/preview
@@ -26497,9 +26708,9 @@ async function getSessionHistoryItems(db, workspaceId, sessionId) {
26497
26708
  async function getActiveSessionHistoryItems(db, workspaceId, sessionId) {
26498
26709
  return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {
26499
26710
  const rows = await scopedDb.select({
26711
+ id: sessionHistoryItems.id,
26500
26712
  position: sessionHistoryItems.position,
26501
26713
  item: sessionHistoryItems.item,
26502
- producerCodexCredentialId: sessionHistoryItems.producerCodexCredentialId,
26503
26714
  providerArtifactInvalidatedAt: sessionHistoryItems.providerArtifactInvalidatedAt
26504
26715
  }).from(sessionHistoryItems).where(
26505
26716
  and17(
@@ -26633,8 +26844,7 @@ async function applyContextCompaction(db, input) {
26633
26844
  turnId: null,
26634
26845
  position: supersededFrom + index,
26635
26846
  item: sanitizeModelPayload(item),
26636
- active: true,
26637
- ...input.producerCodexCredentialId ? { producerCodexCredentialId: input.producerCodexCredentialId } : {}
26847
+ active: true
26638
26848
  }))
26639
26849
  );
26640
26850
  }
@@ -26646,8 +26856,7 @@ async function applyContextCompaction(db, input) {
26646
26856
  turnId: input.turnId,
26647
26857
  position: summaryPosition,
26648
26858
  item: sanitizeModelPayload(input.summaryItem),
26649
- active: true,
26650
- ...input.producerCodexCredentialId ? { producerCodexCredentialId: input.producerCodexCredentialId } : {}
26859
+ active: true
26651
26860
  });
26652
26861
  const insertedEvents = input.eventPayload ? await tx.insert(sessionEvents).values({
26653
26862
  accountId: input.accountId,
@@ -33784,8 +33993,7 @@ async function saveRunState(db, input) {
33784
33993
  turnId: input.turnId,
33785
33994
  stateVersion: Number(maxVersion) + 1,
33786
33995
  serializedRunState: input.serializedRunState,
33787
- pendingApprovals: input.pendingApprovals,
33788
- frozenCodexCredentialId: input.frozenCodexCredentialId ?? null
33996
+ pendingApprovals: input.pendingApprovals
33789
33997
  });
33790
33998
  return true;
33791
33999
  });
@@ -35621,8 +35829,7 @@ async function claimSessionWorkForAttempt(db, workspaceId, input) {
35621
35829
  sessionId,
35622
35830
  turnId,
35623
35831
  position: Number(position),
35624
- item: sanitizeModelPayload(delivered2.historyItem),
35625
- producerCodexCredentialId: null
35832
+ item: sanitizeModelPayload(delivered2.historyItem)
35626
35833
  });
35627
35834
  };
35628
35835
  const workspaceControl = await lockWorkspaceInferenceControl(
@@ -36408,8 +36615,7 @@ async function claimSessionWorkForAttempt(db, workspaceId, input) {
36408
36615
  item: durableUserHistoryItem(
36409
36616
  row.prompt,
36410
36617
  Array.isArray(row.resources) ? row.resources : []
36411
- ),
36412
- producerCodexCredentialId: null
36618
+ )
36413
36619
  });
36414
36620
  const providerDelegatedTurn = isSessionRealtimeDelegationTurnMetadata(row.metadata);
36415
36621
  const delivered = providerDelegatedTurn ? {
@@ -37625,8 +37831,7 @@ async function applySessionTurnSettlement(db, workspaceId, input, hooks = {}) {
37625
37831
  turnId: input.turnId,
37626
37832
  stateVersion: Number(maxVersion) + 1,
37627
37833
  serializedRunState: input.runState.serializedRunState,
37628
- pendingApprovals: input.runState.pendingApprovals,
37629
- frozenCodexCredentialId: input.runState.frozenCodexCredentialId ?? null
37834
+ pendingApprovals: input.runState.pendingApprovals
37630
37835
  });
37631
37836
  if (humanInputRequests.length > 0) {
37632
37837
  for (const request of humanInputRequests) {
@@ -38426,7 +38631,8 @@ async function requestSessionTurnRecovery(db, workspaceId, input) {
38426
38631
  }
38427
38632
  let providerArtifactsInvalidated = 0;
38428
38633
  if (input.providerArtifactInvalidation) {
38429
- const invalidatedHistory = await tx.update(sessionHistoryItems).set({
38634
+ const historyItemIds = [...new Set(input.providerArtifactInvalidation.historyItemIds)];
38635
+ const invalidatedHistory = historyItemIds.length > 0 ? await tx.update(sessionHistoryItems).set({
38430
38636
  providerArtifactInvalidatedAt: now,
38431
38637
  providerArtifactInvalidationReason: input.providerArtifactInvalidation.reason,
38432
38638
  providerArtifactInvalidatedByAttemptId: input.attemptId
@@ -38436,35 +38642,37 @@ async function requestSessionTurnRecovery(db, workspaceId, input) {
38436
38642
  eq18(sessionHistoryItems.workspaceId, workspaceId),
38437
38643
  eq18(sessionHistoryItems.sessionId, input.sessionId),
38438
38644
  eq18(sessionHistoryItems.active, true),
38439
- eq18(
38440
- sessionHistoryItems.producerCodexCredentialId,
38441
- input.providerArtifactInvalidation.codexCredentialId
38442
- ),
38645
+ inArray11(sessionHistoryItems.id, historyItemIds),
38443
38646
  isNull6(sessionHistoryItems.providerArtifactInvalidatedAt),
38444
- sql15`${sessionHistoryItems.item} ->> 'type' in ('reasoning', 'compaction')`
38647
+ sql15`${sessionHistoryItems.item} ->> 'type' in ('reasoning', 'compaction')`,
38648
+ sql15`(
38649
+ nullif(${sessionHistoryItems.item} ->> 'encrypted_content', '') is not null
38650
+ or nullif(${sessionHistoryItems.item} ->> 'encryptedContent', '') is not null
38651
+ or nullif(${sessionHistoryItems.item} -> 'providerData' ->> 'encrypted_content', '') is not null
38652
+ or nullif(${sessionHistoryItems.item} -> 'providerData' ->> 'encryptedContent', '') is not null
38653
+ )`
38445
38654
  )
38446
- ).returning({ id: sessionHistoryItems.id });
38447
- const [latestRunState] = await tx.select({ id: agentRunStates.id }).from(agentRunStates).where(
38448
- and17(
38449
- eq18(agentRunStates.accountId, session.accountId),
38450
- eq18(agentRunStates.workspaceId, workspaceId),
38451
- eq18(agentRunStates.sessionId, input.sessionId),
38452
- eq18(agentRunStates.turnId, input.turnId),
38453
- eq18(
38454
- agentRunStates.frozenCodexCredentialId,
38455
- input.providerArtifactInvalidation.codexCredentialId
38456
- ),
38457
- isNull6(agentRunStates.providerArtifactInvalidatedAt)
38458
- )
38459
- ).orderBy(desc8(agentRunStates.stateVersion)).limit(1);
38460
- const invalidatedRunState = latestRunState ? await tx.update(agentRunStates).set({
38655
+ ).returning({ id: sessionHistoryItems.id }) : [];
38656
+ const invalidatedRunState = input.providerArtifactInvalidation.runStateId ? await tx.update(agentRunStates).set({
38461
38657
  providerArtifactInvalidatedAt: now,
38462
38658
  providerArtifactInvalidationReason: input.providerArtifactInvalidation.reason,
38463
38659
  providerArtifactInvalidatedByAttemptId: input.attemptId
38464
38660
  }).where(
38465
38661
  and17(
38466
- eq18(agentRunStates.id, latestRunState.id),
38467
- isNull6(agentRunStates.providerArtifactInvalidatedAt)
38662
+ eq18(agentRunStates.accountId, session.accountId),
38663
+ eq18(agentRunStates.workspaceId, workspaceId),
38664
+ eq18(agentRunStates.sessionId, input.sessionId),
38665
+ eq18(agentRunStates.turnId, input.turnId),
38666
+ eq18(agentRunStates.id, input.providerArtifactInvalidation.runStateId),
38667
+ isNull6(agentRunStates.providerArtifactInvalidatedAt),
38668
+ sql15`${agentRunStates.stateVersion} = (
38669
+ select max(latest.state_version)
38670
+ from agent_run_states latest
38671
+ where latest.account_id = ${session.accountId}
38672
+ and latest.workspace_id = ${workspaceId}
38673
+ and latest.session_id = ${input.sessionId}
38674
+ and latest.turn_id = ${input.turnId}
38675
+ )`
38468
38676
  )
38469
38677
  ).returning({ id: agentRunStates.id }) : [];
38470
38678
  providerArtifactsInvalidated = invalidatedHistory.length + invalidatedRunState.length;
@@ -41040,6 +41248,7 @@ export {
41040
41248
  CODEX_CREDENTIAL_LEASE_TTL_MS,
41041
41249
  CODEX_RESET_REDEMPTION_OUTCOMES,
41042
41250
  CODEX_ROTATION_STRATEGIES,
41251
+ CodexAppsAuthorizationRevokedError,
41043
41252
  ConnectionDisconnectGenerationError,
41044
41253
  ConnectionDisconnectIdempotencyError,
41045
41254
  ConnectionRefreshHttpError,
@@ -41244,6 +41453,7 @@ export {
41244
41453
  claimSlackInteractionProgressDelivery,
41245
41454
  claimTerminalRetainedProcesses,
41246
41455
  claimWorkspaceArchiveCapture,
41456
+ clearCodexAppsCredential,
41247
41457
  clearDurablePendingSessionToolCalls,
41248
41458
  clearEnrollmentWentOffline,
41249
41459
  clearPendingSessionToolspaceCall,
@@ -41350,6 +41560,7 @@ export {
41350
41560
  deleteWorkspaceEnvironmentVariable,
41351
41561
  deleteWorkspacePack,
41352
41562
  denyDeviceEnrollmentRequest,
41563
+ designateCodexAppsCredential,
41353
41564
  diffWorkspaceInstructionPolicyContent,
41354
41565
  diffWorkspaceInstructionPolicyRevisions,
41355
41566
  disableCapabilityInstallation,
@@ -41400,6 +41611,8 @@ export {
41400
41611
  getBillingCustomer,
41401
41612
  getCapabilityCatalogItem,
41402
41613
  getCapabilityInstallation,
41614
+ getCodexAppsCredentialAuthorizationForRun,
41615
+ getCodexAppsSettings,
41403
41616
  getCodexCapacityWaitForSession,
41404
41617
  getCodexCredentialStatus,
41405
41618
  getCodexResetRedemptionAttempt,
@@ -41671,7 +41884,6 @@ export {
41671
41884
  reconcileColdLostLeaseInstanceBlockers,
41672
41885
  reconcileSessionAttemptQuiescence,
41673
41886
  recordAuditEvent,
41674
- recordCodexAccountConnectors,
41675
41887
  recordCodexAccountUsage,
41676
41888
  recordCodexAccountUsageWithWakeTargets,
41677
41889
  recordCodexTokenRefresh,
@@ -41872,6 +42084,7 @@ export {
41872
42084
  verifyRetainedProcessMutationSettlement,
41873
42085
  verifyWorkspaceMutationSettlement,
41874
42086
  withAccountRls,
42087
+ withCodexAppsRequestAuthorization,
41875
42088
  withCodexCapacityMutation,
41876
42089
  withCodexCredentialRefreshLock,
41877
42090
  withCodexTokenDeadline,