@opengeni/db 0.31.1 → 0.36.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (122) hide show
  1. package/dist/browser-auth.d.ts +209 -1
  2. package/dist/browser-downloads.d.ts +51 -0
  3. package/dist/browser-identities.d.ts +11 -2
  4. package/dist/browser-sessions.d.ts +83 -1
  5. package/dist/browser-state-artifacts.d.ts +75 -1
  6. package/dist/canonical-human-identities.d.ts +48 -0
  7. package/dist/canonical-human-identities.js +28 -0
  8. package/dist/canonical-human-identities.js.map +1 -0
  9. package/dist/capability-integrations.d.ts +8 -6
  10. package/dist/{chunk-MWDVXQOL.js → chunk-5KTIEDX7.js} +5773 -4212
  11. package/dist/chunk-5KTIEDX7.js.map +1 -0
  12. package/dist/{chunk-NBE6CHRI.js → chunk-CQZ4QSP5.js} +49 -9
  13. package/dist/chunk-CQZ4QSP5.js.map +1 -0
  14. package/dist/chunk-F32YT7MP.js +117 -0
  15. package/dist/chunk-F32YT7MP.js.map +1 -0
  16. package/dist/{chunk-ISI2TIUG.js → chunk-JC5QPLUM.js} +30 -3
  17. package/dist/chunk-JC5QPLUM.js.map +1 -0
  18. package/dist/{chunk-F5FT7BEZ.js → chunk-P3RE4D2B.js} +2 -2
  19. package/dist/chunk-TAUTWOS5.js +259 -0
  20. package/dist/chunk-TAUTWOS5.js.map +1 -0
  21. package/dist/{chunk-YHZXQ7HP.js → chunk-VKLB2ZGI.js} +446 -19
  22. package/dist/chunk-VKLB2ZGI.js.map +1 -0
  23. package/dist/database.d.ts +5 -0
  24. package/dist/editable-artifact-durable-export.js +2 -2
  25. package/dist/editable-artifacts.js +3 -3
  26. package/dist/index.d.ts +438 -29
  27. package/dist/index.js +35640 -28969
  28. package/dist/index.js.map +1 -1
  29. package/dist/insights.d.ts +23 -7
  30. package/dist/integration-bindings.d.ts +24 -24
  31. package/dist/integration-facets.d.ts +99 -0
  32. package/dist/interaction-revisions.d.ts +11 -0
  33. package/dist/interaction-schema.d.ts +698 -34
  34. package/dist/provision-roles.js +1 -1
  35. package/dist/runtime-posture.d.ts +8 -7
  36. package/dist/schema.d.ts +9464 -5412
  37. package/dist/schema.js +51 -9
  38. package/dist/session-control.d.ts +29 -3
  39. package/dist/session-tenancy.d.ts +44 -0
  40. package/dist/session-tenancy.js +16 -0
  41. package/dist/session-tenancy.js.map +1 -0
  42. package/dist/slack-task-policy-schema.d.ts +847 -0
  43. package/dist/slack-task-policy.d.ts +65 -0
  44. package/dist/task-notes-schema.d.ts +924 -0
  45. package/dist/task-notes.d.ts +85 -0
  46. package/dist/video-generation.d.ts +9 -0
  47. package/dist/video-generation.js +5 -3
  48. package/dist/xai-subscription.d.ts +326 -0
  49. package/drizzle/0212_browser_state_transfer_hardening.sql +560 -0
  50. package/drizzle/0213_browser_interaction_authority.sql +67 -0
  51. package/drizzle/0214_browser_download_saves.sql +34 -0
  52. package/drizzle/0215_browser_controller_host.sql +385 -0
  53. package/drizzle/0216_browser_auth_health_evidence.sql +137 -0
  54. package/drizzle/0217_external_browser_auth_operations.sql +22 -0
  55. package/drizzle/0218_organization_tenancy_foundation.sql +299 -0
  56. package/drizzle/0219_organization_tenancy_managed_human_provisioning.sql +317 -0
  57. package/drizzle/0219_site_auth_maintenance_sessions.sql +234 -0
  58. package/drizzle/0220_memory_slack_append_only_cascade.sql +38 -0
  59. package/drizzle/0220_session_channels.sql +54 -0
  60. package/drizzle/0221_sessions_channel_index.sql +5 -0
  61. package/drizzle/0222_session_visibility_authority_epochs.sql +158 -0
  62. package/drizzle/0222_sessions_channel_fk.sql +89 -0
  63. package/drizzle/0223_pending_tool_event_output.sql +55 -0
  64. package/drizzle/0223_sessions_channel_fk_validate.sql +118 -0
  65. package/drizzle/0224_slack_post_outcome_reconciliation.sql +123 -0
  66. package/drizzle/0225_session_visibility_fork_activation.sql +1363 -0
  67. package/drizzle/0226_personal_codex_authority_foundation.sql +365 -0
  68. package/drizzle/0227_slack_native_actions.sql +145 -0
  69. package/drizzle/0228_interaction_controller_data_plane.sql +14 -0
  70. package/drizzle/0228_slack_task_policy.sql +400 -0
  71. package/drizzle/0229_slack_inbox_file_fact.sql +10 -0
  72. package/drizzle/0230_user_scoped_variable_sets_rigs.sql +84 -0
  73. package/drizzle/0231_integration_definition_identity_cutover.sql +271 -0
  74. package/drizzle/0232_integration_facet_authority_cutover.sql +610 -0
  75. package/drizzle/0233_skill_and_integration_authority_cutover.sql +1162 -0
  76. package/drizzle/0234_xai_subscription_authority.sql +1139 -0
  77. package/drizzle/0235_canonical_human_login_bindings.sql +920 -0
  78. package/drizzle/0236_browser_identity_lifecycle.sql +39 -0
  79. package/drizzle/0236_session_visibility_slack_policy.sql +72 -0
  80. package/drizzle/0237_interaction_transition_reaper.sql +263 -0
  81. package/drizzle/0238_goal_persistence_policy.sql +471 -0
  82. package/drizzle/0238_supergrok_realtime_model.sql +29 -0
  83. package/drizzle/0239_supergrok_video_funding.sql +50 -0
  84. package/drizzle/0239_task_tree_notes.sql +990 -0
  85. package/package.json +13 -5
  86. package/src/browser-auth.ts +2600 -123
  87. package/src/browser-downloads.ts +517 -0
  88. package/src/browser-identities.ts +220 -3
  89. package/src/browser-sessions.ts +334 -45
  90. package/src/browser-state-artifacts.ts +402 -12
  91. package/src/canonical-human-identities.ts +317 -0
  92. package/src/capability-integrations.ts +121 -213
  93. package/src/database.ts +41 -1
  94. package/src/index.ts +4157 -394
  95. package/src/insights.ts +109 -28
  96. package/src/integration-bindings.ts +101 -101
  97. package/src/{integration-features.ts → integration-facets.ts} +187 -184
  98. package/src/interaction-revisions.ts +33 -3
  99. package/src/interaction-schema.ts +311 -8
  100. package/src/pack-components.ts +43 -43
  101. package/src/pack-installations.ts +0 -43
  102. package/src/plugin-packages.ts +9 -9
  103. package/src/provision-roles.ts +232 -0
  104. package/src/runtime-posture.ts +227 -14
  105. package/src/schema.ts +1188 -75
  106. package/src/session-control.ts +122 -37
  107. package/src/session-queue-commands.ts +78 -1
  108. package/src/session-tenancy.ts +188 -0
  109. package/src/session-tool-call-settlement.ts +9 -3
  110. package/src/slack-task-policy-schema.ts +130 -0
  111. package/src/slack-task-policy.ts +341 -0
  112. package/src/task-notes-schema.ts +135 -0
  113. package/src/task-notes.ts +178 -0
  114. package/src/video-generation.ts +90 -12
  115. package/src/workspace-artifacts.ts +1 -1
  116. package/src/xai-subscription.ts +1887 -0
  117. package/dist/chunk-ISI2TIUG.js.map +0 -1
  118. package/dist/chunk-MWDVXQOL.js.map +0 -1
  119. package/dist/chunk-NBE6CHRI.js.map +0 -1
  120. package/dist/chunk-YHZXQ7HP.js.map +0 -1
  121. package/dist/integration-features.d.ts +0 -99
  122. /package/dist/{chunk-F5FT7BEZ.js.map → chunk-P3RE4D2B.js.map} +0 -0
@@ -1,5 +1,5 @@
1
1
  import { eq, sql } from "drizzle-orm";
2
- import { rawRows, type Database } from "./database";
2
+ import { rawRows, type Database, withRlsContext } from "./database";
3
3
  import * as schema from "./schema";
4
4
 
5
5
  export async function advanceWorkspaceInteractionRevision(
@@ -31,10 +31,40 @@ export async function readWorkspaceInteractionRevision(
31
31
  db: Database,
32
32
  workspaceId: string,
33
33
  ): Promise<number> {
34
+ return (await readWorkspaceInteractionRevisionState(db, workspaceId)).revision;
35
+ }
36
+
37
+ export type WorkspaceInteractionRevisionState = {
38
+ revision: number;
39
+ updatedAt: Date | null;
40
+ };
41
+
42
+ /** Read the latest cursor while already inside the workspace RLS boundary. */
43
+ export async function readWorkspaceInteractionRevisionState(
44
+ db: Database,
45
+ workspaceId: string,
46
+ ): Promise<WorkspaceInteractionRevisionState> {
34
47
  const [row] = await db
35
- .select({ revision: schema.workspaceInteractionRevisions.revision })
48
+ .select({
49
+ revision: schema.workspaceInteractionRevisions.revision,
50
+ updatedAt: schema.workspaceInteractionRevisions.updatedAt,
51
+ })
36
52
  .from(schema.workspaceInteractionRevisions)
37
53
  .where(eq(schema.workspaceInteractionRevisions.workspaceId, workspaceId))
38
54
  .limit(1);
39
- return row?.revision ?? 0;
55
+ return row
56
+ ? { revision: row.revision, updatedAt: row.updatedAt }
57
+ : { revision: 0, updatedAt: null };
58
+ }
59
+
60
+ /** Standalone tenant-scoped cursor read used by the workspace SSE projection. */
61
+ export async function getWorkspaceInteractionRevisionState(
62
+ db: Database,
63
+ input: { accountId: string; workspaceId: string },
64
+ ): Promise<WorkspaceInteractionRevisionState> {
65
+ return await withRlsContext(
66
+ db,
67
+ input,
68
+ async (scopedDb) => await readWorkspaceInteractionRevisionState(scopedDb, input.workspaceId),
69
+ );
40
70
  }
@@ -87,6 +87,7 @@ export const browserIdentities = pgTable(
87
87
  status: text("status", { enum: ["active", "archived"] })
88
88
  .notNull()
89
89
  .default("active"),
90
+ version: bigint("version", { mode: "number" }).notNull().default(1),
90
91
  defaultRevisionId: uuid("default_revision_id"),
91
92
  headGeneration: bigint("head_generation", { mode: "number" }).notNull().default(0),
92
93
  revisionCount: bigint("revision_count", { mode: "number" }).notNull().default(0),
@@ -118,9 +119,9 @@ export const browserIdentities = pgTable(
118
119
  sql`octet_length(${table.name}) between 1 and 200
119
120
  and ${table.name} = btrim(${table.name})
120
121
  and octet_length(${table.createdBySubjectId}) between 1 and 1024
122
+ and ${table.version} > 0
121
123
  and ${table.headGeneration} >= 0
122
124
  and ${table.revisionCount} >= 0
123
- and ${table.headGeneration} <= ${table.revisionCount}
124
125
  and (
125
126
  (${table.headGeneration} = 0 and ${table.defaultRevisionId} is null)
126
127
  or (${table.headGeneration} > 0 and ${table.defaultRevisionId} is not null)
@@ -216,13 +217,17 @@ export const browserStateArtifacts = pgTable(
216
217
  contentDigest: text("content_digest").notNull(),
217
218
  manifestDigest: text("manifest_digest").notNull(),
218
219
  objectKey: text("object_key").notNull(),
219
- encryptedDataKey: text("encrypted_data_key").notNull(),
220
+ encryptedDataKey: text("encrypted_data_key"),
220
221
  sizeBytes: bigint("size_bytes", { mode: "number" }).notNull(),
221
222
  materialization: jsonb("materialization").$type<BrowserRevisionMaterialization>().notNull(),
222
- state: text("state", { enum: ["available", "delete_pending", "deleted"] })
223
+ state: text("state", {
224
+ enum: ["available", "delete_pending", "deleting", "deleted"],
225
+ })
223
226
  .notNull()
224
227
  .default("available"),
225
228
  retainedUntil: timestamp("retained_until", { withTimezone: true }),
229
+ deleteClaimId: uuid("delete_claim_id"),
230
+ deleteClaimedAt: timestamp("delete_claimed_at", { withTimezone: true }),
226
231
  createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
227
232
  deletedAt: timestamp("deleted_at", { withTimezone: true }),
228
233
  },
@@ -231,6 +236,12 @@ export const browserStateArtifacts = pgTable(
231
236
  table.workspaceId,
232
237
  table.id,
233
238
  ),
239
+ commitAuthority: uniqueIndex("browser_state_artifacts_commit_authority_uq").on(
240
+ table.workspaceId,
241
+ table.id,
242
+ table.purpose,
243
+ table.sourceBrowserSessionId,
244
+ ),
234
245
  objectKey: uniqueIndex("browser_state_artifacts_object_key_uq").on(table.objectKey),
235
246
  source: index("browser_state_artifacts_source_idx").on(
236
247
  table.workspaceId,
@@ -240,6 +251,7 @@ export const browserStateArtifacts = pgTable(
240
251
  gc: index("browser_state_artifacts_gc_idx").on(
241
252
  table.state,
242
253
  table.retainedUntil,
254
+ table.deleteClaimedAt,
243
255
  table.createdAt,
244
256
  ),
245
257
  valuesValid: check(
@@ -251,7 +263,10 @@ export const browserStateArtifacts = pgTable(
251
263
  and ${table.manifestDigest} ~ '^[0-9a-f]{64}$'
252
264
  and octet_length(${table.objectKey}) between 1 and 2048
253
265
  and ${table.objectKey} ~ ('^workspaces/' || ${table.workspaceId}::text || '/browser-state/[A-Za-z0-9._=-]+(/[A-Za-z0-9._=-]+)*$')
254
- and octet_length(${table.encryptedDataKey}) between 16 and 8192
266
+ and (
267
+ ${table.encryptedDataKey} is null
268
+ or octet_length(${table.encryptedDataKey}) between 16 and 8192
269
+ )
255
270
  and ${table.sizeBytes} > 0
256
271
  and jsonb_typeof(${table.materialization}) = 'object'
257
272
  and octet_length(${table.materialization}::text) between 2 and 65536
@@ -261,13 +276,136 @@ export const browserStateArtifacts = pgTable(
261
276
  ${table.state} = 'available'
262
277
  and ${table.retainedUntil} is null
263
278
  and ${table.deletedAt} is null
279
+ and ${table.deleteClaimId} is null
280
+ and ${table.deleteClaimedAt} is null
281
+ and ${table.encryptedDataKey} is not null
264
282
  )
265
283
  )`,
266
284
  ),
267
285
  lifecycleValid: check(
268
286
  "browser_state_artifacts_lifecycle_check",
269
- sql`(${table.state} = 'deleted' and ${table.deletedAt} is not null)
270
- or (${table.state} <> 'deleted' and ${table.deletedAt} is null)`,
287
+ sql`(
288
+ ${table.state} = 'available'
289
+ and ${table.retainedUntil} is null
290
+ and ${table.deleteClaimId} is null
291
+ and ${table.deleteClaimedAt} is null
292
+ and ${table.deletedAt} is null
293
+ and ${table.encryptedDataKey} is not null
294
+ ) or (
295
+ ${table.state} = 'delete_pending'
296
+ and ${table.retainedUntil} is not null
297
+ and ${table.deleteClaimId} is null
298
+ and ${table.deleteClaimedAt} is null
299
+ and ${table.deletedAt} is null
300
+ and ${table.encryptedDataKey} is not null
301
+ ) or (
302
+ ${table.state} = 'deleting'
303
+ and ${table.retainedUntil} is not null
304
+ and ${table.deleteClaimId} is not null
305
+ and ${table.deleteClaimedAt} is not null
306
+ and ${table.deletedAt} is null
307
+ and ${table.encryptedDataKey} is not null
308
+ ) or (
309
+ ${table.state} = 'deleted'
310
+ and ${table.retainedUntil} is not null
311
+ and ${table.deleteClaimId} is null
312
+ and ${table.deleteClaimedAt} is null
313
+ and ${table.deletedAt} is not null
314
+ and ${table.encryptedDataKey} is null
315
+ )`,
316
+ ),
317
+ }),
318
+ );
319
+
320
+ /** Pre-publication object authority. This row exists before a controller can
321
+ * upload bytes, then becomes either a committed artifact root or reclaimable
322
+ * cleanup authority. It never carries encryption keys or signed URLs. */
323
+ export const browserStateUploads = pgTable(
324
+ "browser_state_uploads",
325
+ {
326
+ id: uuid("id").primaryKey(),
327
+ accountId: uuid("account_id").notNull(),
328
+ workspaceId: uuid("workspace_id").notNull(),
329
+ operationId: uuid("operation_id").notNull(),
330
+ sourceBrowserSessionId: uuid("source_browser_session_id").notNull(),
331
+ purpose: text("purpose", {
332
+ enum: ["revision_component", "private_checkpoint"],
333
+ }).notNull(),
334
+ objectKey: text("object_key").notNull(),
335
+ state: text("state", {
336
+ enum: ["prepared", "delete_pending", "deleting", "committed", "deleted"],
337
+ })
338
+ .notNull()
339
+ .default("prepared"),
340
+ cleanupAfter: timestamp("cleanup_after", { withTimezone: true }),
341
+ committedArtifactId: uuid("committed_artifact_id"),
342
+ deleteClaimId: uuid("delete_claim_id"),
343
+ deleteClaimedAt: timestamp("delete_claimed_at", { withTimezone: true }),
344
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
345
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
346
+ deletedAt: timestamp("deleted_at", { withTimezone: true }),
347
+ },
348
+ (table) => ({
349
+ workspaceUpload: uniqueIndex("browser_state_uploads_workspace_id_uq").on(
350
+ table.workspaceId,
351
+ table.id,
352
+ ),
353
+ operationObject: uniqueIndex("browser_state_uploads_operation_object_uq").on(
354
+ table.workspaceId,
355
+ table.operationId,
356
+ table.objectKey,
357
+ ),
358
+ objectKey: uniqueIndex("browser_state_uploads_object_key_uq").on(table.objectKey),
359
+ gc: index("browser_state_uploads_gc_idx").on(
360
+ table.state,
361
+ table.cleanupAfter,
362
+ table.deleteClaimedAt,
363
+ table.createdAt,
364
+ ),
365
+ valuesValid: check(
366
+ "browser_state_uploads_values_check",
367
+ sql`octet_length(${table.objectKey}) between 1 and 2048
368
+ and ${table.objectKey} ~ ('^workspaces/' || ${table.workspaceId}::text || '/browser-state/[A-Za-z0-9._=-]+(/[A-Za-z0-9._=-]+)*$')
369
+ and ${table.updatedAt} >= ${table.createdAt}`,
370
+ ),
371
+ lifecycleValid: check(
372
+ "browser_state_uploads_lifecycle_check",
373
+ sql`(
374
+ ${table.state} = 'prepared'
375
+ and ${table.cleanupAfter} is not null
376
+ and ${table.committedArtifactId} is null
377
+ and ${table.deleteClaimId} is null
378
+ and ${table.deleteClaimedAt} is null
379
+ and ${table.deletedAt} is null
380
+ ) or (
381
+ ${table.state} = 'delete_pending'
382
+ and ${table.cleanupAfter} is not null
383
+ and ${table.committedArtifactId} is null
384
+ and ${table.deleteClaimId} is null
385
+ and ${table.deleteClaimedAt} is null
386
+ and ${table.deletedAt} is null
387
+ ) or (
388
+ ${table.state} = 'deleting'
389
+ and ${table.cleanupAfter} is not null
390
+ and ${table.committedArtifactId} is null
391
+ and ${table.deleteClaimId} is not null
392
+ and ${table.deleteClaimedAt} is not null
393
+ and ${table.deletedAt} is null
394
+ ) or (
395
+ ${table.state} = 'committed'
396
+ and ${table.cleanupAfter} is null
397
+ and ${table.committedArtifactId} is not null
398
+ and ${table.deleteClaimId} is null
399
+ and ${table.deleteClaimedAt} is null
400
+ and ${table.deletedAt} is null
401
+ ) or (
402
+ ${table.state} = 'deleted'
403
+ and ${table.cleanupAfter} is not null
404
+ and ${table.committedArtifactId} is null
405
+ and ${table.deleteClaimId} is null
406
+ and ${table.deleteClaimedAt} is null
407
+ and ${table.deletedAt} is not null
408
+ )`,
271
409
  ),
272
410
  }),
273
411
  );
@@ -432,6 +570,9 @@ export const browserSessions = pgTable(
432
570
  deviceId: uuid("device_id"),
433
571
  externalProviderId: text("external_provider_id"),
434
572
  externalPlacementId: text("external_placement_id"),
573
+ /** Sandbox group hosting browserd when the logical browser itself lives
574
+ * on a remote provider. This is deliberately separate from placement. */
575
+ controllerHostSandboxGroupId: uuid("controller_host_sandbox_group_id"),
435
576
  controllerId: text("controller_id"),
436
577
  controllerGeneration: text("controller_generation"),
437
578
  placementInstanceId: text("placement_instance_id"),
@@ -446,6 +587,13 @@ export const browserSessions = pgTable(
446
587
  baseRevisionId: uuid("base_revision_id"),
447
588
  linkedComputerSessionId: uuid("linked_computer_session_id"),
448
589
  networkRouteId: uuid("network_route_id"),
590
+ networkRouteVersion: bigint("network_route_version", { mode: "number" }),
591
+ networkRouteConfiguration: jsonb("network_route_configuration"),
592
+ networkRouteConsistency: jsonb("network_route_consistency"),
593
+ networkRouteCredentialVersion: bigint("network_route_credential_version", {
594
+ mode: "number",
595
+ }),
596
+ networkRouteAuthorityDigest: text("network_route_authority_digest"),
449
597
  privateCheckpointArtifactId: uuid("private_checkpoint_artifact_id"),
450
598
  capabilities: jsonb("capabilities").$type<BrowserSessionCapabilities>().notNull(),
451
599
  createOperationId: uuid("create_operation_id").notNull(),
@@ -478,6 +626,16 @@ export const browserSessions = pgTable(
478
626
  table.sandboxGroupId,
479
627
  table.lifecycle,
480
628
  ),
629
+ controllerHostSandboxGroup: index("browser_sessions_controller_host_sandbox_group_idx").on(
630
+ table.workspaceId,
631
+ table.controllerHostSandboxGroupId,
632
+ table.lifecycle,
633
+ ),
634
+ networkRoute: index("browser_sessions_workspace_network_route_idx").on(
635
+ table.workspaceId,
636
+ table.networkRouteId,
637
+ table.lifecycle,
638
+ ),
481
639
  valuesValid: check(
482
640
  "browser_sessions_values_check",
483
641
  sql`octet_length(${table.name}) between 1 and 200
@@ -485,6 +643,27 @@ export const browserSessions = pgTable(
485
643
  and octet_length(${table.createdBySubjectId}) between 1 and 1024
486
644
  and ${table.tokenGeneration} > 0
487
645
  and octet_length(${table.capabilities}::text) between 2 and 65536
646
+ and (
647
+ (${table.networkRouteId} is null
648
+ and ${table.networkRouteVersion} is null
649
+ and ${table.networkRouteConfiguration} is null
650
+ and ${table.networkRouteConsistency} is null
651
+ and ${table.networkRouteCredentialVersion} is null
652
+ and ${table.networkRouteAuthorityDigest} is null)
653
+ or
654
+ (${table.networkRouteId} is not null
655
+ and ${table.networkRouteVersion} > 0
656
+ and jsonb_typeof(${table.networkRouteConfiguration}) = 'object'
657
+ and octet_length(${table.networkRouteConfiguration}::text) between 2 and 65536
658
+ and jsonb_typeof(${table.networkRouteConsistency}) = 'object'
659
+ and octet_length(${table.networkRouteConsistency}::text) between 2 and 65536
660
+ and (${table.networkRouteCredentialVersion} is null or ${table.networkRouteCredentialVersion} > 0)
661
+ and (${table.networkRouteAuthorityDigest} is not null or ${table.networkRouteCredentialVersion} is null)
662
+ and (${table.networkRouteAuthorityDigest} is null or (
663
+ octet_length(${table.networkRouteAuthorityDigest}) between 16 and 256
664
+ and ${table.networkRouteAuthorityDigest} ~ '^[A-Za-z0-9._~-]+$'
665
+ )))
666
+ )
488
667
  and (${table.engineVersion} is null or octet_length(${table.engineVersion}) between 1 and 256)
489
668
  and (${table.failureCode} is null or octet_length(${table.failureCode}) between 1 and 512)`,
490
669
  ),
@@ -539,6 +718,19 @@ export const browserSessions = pgTable(
539
718
  and ${table.controllerHeartbeatAt} is not null
540
719
  )`,
541
720
  ),
721
+ controllerHostValid: check(
722
+ "browser_sessions_controller_host_check",
723
+ sql`(
724
+ ${table.placementKind} = 'sandbox_group'
725
+ and ${table.controllerHostSandboxGroupId} = ${table.sandboxGroupId}
726
+ ) or (
727
+ ${table.placementKind} = 'external_provider'
728
+ and ${table.controllerHostSandboxGroupId} is not null
729
+ ) or (
730
+ ${table.placementKind} in ('connected_machine', 'attached_device')
731
+ and ${table.controllerHostSandboxGroupId} is null
732
+ )`,
733
+ ),
542
734
  identityRevisionValid: check(
543
735
  "browser_sessions_identity_revision_check",
544
736
  sql`${table.baseRevisionId} is null or ${table.identityId} is not null`,
@@ -873,6 +1065,15 @@ export const siteAuthConnections = pgTable(
873
1065
  .default("unknown"),
874
1066
  lastVerifiedAt: timestamp("last_verified_at", { withTimezone: true }),
875
1067
  lastVerifiedUrl: text("last_verified_url"),
1068
+ lastCheckedAt: timestamp("last_checked_at", { withTimezone: true }),
1069
+ nextCheckAt: timestamp("next_check_at", { withTimezone: true }),
1070
+ maintenanceOperationId: uuid("maintenance_operation_id"),
1071
+ maintenanceAction: text("maintenance_action", { enum: ["health_check", "repair"] }),
1072
+ maintenanceDueAt: timestamp("maintenance_due_at", { withTimezone: true }),
1073
+ maintenanceClaimedAt: timestamp("maintenance_claimed_at", { withTimezone: true }),
1074
+ maintenanceSessionId: uuid("maintenance_session_id"),
1075
+ maintenanceStartedAt: timestamp("maintenance_started_at", { withTimezone: true }),
1076
+ healthSequence: bigint("health_sequence", { mode: "number" }).notNull().default(0),
876
1077
  repairCode: text("repair_code"),
877
1078
  version: bigint("version", { mode: "number" }).notNull().default(1),
878
1079
  createOperationId: uuid("create_operation_id").notNull(),
@@ -899,6 +1100,11 @@ export const siteAuthConnections = pgTable(
899
1100
  table.updatedAt,
900
1101
  table.id,
901
1102
  ),
1103
+ maintenance: index("site_auth_connections_health_maintenance_idx").on(
1104
+ table.nextCheckAt,
1105
+ table.maintenanceClaimedAt,
1106
+ table.id,
1107
+ ),
902
1108
  valuesValid: check(
903
1109
  "site_auth_connections_values_check",
904
1110
  sql`octet_length(${table.name}) between 1 and 200
@@ -943,6 +1149,50 @@ export const siteAuthConnections = pgTable(
943
1149
  and ${table.repairCode} is not null
944
1150
  )`,
945
1151
  ),
1152
+ healthValid: check(
1153
+ "site_auth_connections_health_check",
1154
+ sql`(
1155
+ (
1156
+ ${table.healthSequence} = 0
1157
+ and ${table.lastCheckedAt} is null
1158
+ ) or (
1159
+ ${table.healthSequence} > 0
1160
+ and ${table.lastCheckedAt} is not null
1161
+ )
1162
+ ) and (
1163
+ (
1164
+ ${table.status} = 'active'
1165
+ and ${table.healthPolicy}->>'mode' = 'maintained'
1166
+ and ${table.nextCheckAt} is not null
1167
+ ) or (
1168
+ not (${table.status} = 'active' and ${table.healthPolicy}->>'mode' = 'maintained')
1169
+ and ${table.nextCheckAt} is null
1170
+ )
1171
+ )`,
1172
+ ),
1173
+ maintenanceValid: check(
1174
+ "site_auth_connections_maintenance_check",
1175
+ sql`(
1176
+ ${table.maintenanceOperationId} is null
1177
+ and ${table.maintenanceAction} is null
1178
+ and ${table.maintenanceDueAt} is null
1179
+ and ${table.maintenanceClaimedAt} is null
1180
+ and ${table.maintenanceSessionId} is null
1181
+ and ${table.maintenanceStartedAt} is null
1182
+ ) or (
1183
+ ${table.status} = 'active'
1184
+ and ${table.healthPolicy}->>'mode' = 'maintained'
1185
+ and ${table.maintenanceOperationId} is not null
1186
+ and ${table.maintenanceAction} in ('health_check', 'repair')
1187
+ and ${table.maintenanceDueAt} is not null
1188
+ and ${table.maintenanceClaimedAt} is not null
1189
+ and ${table.maintenanceSessionId} is not null
1190
+ and (
1191
+ ${table.maintenanceStartedAt} is null
1192
+ or ${table.maintenanceStartedAt} >= ${table.maintenanceDueAt}
1193
+ )
1194
+ )`,
1195
+ ),
946
1196
  }),
947
1197
  );
948
1198
 
@@ -958,6 +1208,13 @@ export const authRuns = pgTable(
958
1208
  controllerGeneration: text("controller_generation").notNull(),
959
1209
  targetGeneration: text("target_generation").notNull(),
960
1210
  documentGeneration: text("document_generation"),
1211
+ purpose: text("purpose", { enum: ["authenticate", "health_check", "repair"] })
1212
+ .notNull()
1213
+ .default("authenticate"),
1214
+ healthSequence: bigint("health_sequence", { mode: "number" })
1215
+ .notNull()
1216
+ .default(sql`nextval('auth_runs_health_sequence_seq'::regclass)`),
1217
+ maintenanceOperationId: uuid("maintenance_operation_id"),
961
1218
  methodId: text("method_id"),
962
1219
  authorityId: text("authority_id"),
963
1220
  state: text("state", {
@@ -1006,6 +1263,9 @@ export const authRuns = pgTable(
1006
1263
  table.siteAuthConnectionId,
1007
1264
  table.createdAt,
1008
1265
  ),
1266
+ maintenanceOperation: uniqueIndex("auth_runs_workspace_maintenance_operation_uq")
1267
+ .on(table.workspaceId, table.maintenanceOperationId)
1268
+ .where(sql`${table.maintenanceOperationId} is not null`),
1009
1269
  valuesValid: check(
1010
1270
  "auth_runs_values_check",
1011
1271
  sql`octet_length(${table.targetId}) between 1 and 512
@@ -1027,6 +1287,16 @@ export const authRuns = pgTable(
1027
1287
  and ${table.version} > 0
1028
1288
  and octet_length(${table.createdBySubjectId}) between 1 and 1024`,
1029
1289
  ),
1290
+ healthEvidenceValid: check(
1291
+ "auth_runs_health_evidence_check",
1292
+ sql`${table.purpose} in ('authenticate', 'health_check', 'repair')
1293
+ and ${table.healthSequence} > 0`,
1294
+ ),
1295
+ maintenanceValid: check(
1296
+ "auth_runs_maintenance_check",
1297
+ sql`${table.maintenanceOperationId} is null
1298
+ or ${table.purpose} in ('health_check', 'repair')`,
1299
+ ),
1030
1300
  lifecycleValid: check(
1031
1301
  "auth_runs_lifecycle_check",
1032
1302
  sql`(
@@ -1088,6 +1358,7 @@ export const interactionInterventions = pgTable(
1088
1358
  originatingTurnId: uuid("originating_turn_id"),
1089
1359
  originatingAttemptId: uuid("originating_attempt_id"),
1090
1360
  originatingToolOperationId: uuid("originating_tool_operation_id"),
1361
+ originatingToolCallId: text("originating_tool_call_id"),
1091
1362
  responseActorSubjectId: text("response_actor_subject_id"),
1092
1363
  version: bigint("version", { mode: "number" }).notNull().default(1),
1093
1364
  operationId: uuid("operation_id").notNull(),
@@ -1105,6 +1376,14 @@ export const interactionInterventions = pgTable(
1105
1376
  table.workspaceId,
1106
1377
  table.operationId,
1107
1378
  ),
1379
+ originatingToolCall: uniqueIndex("interaction_interventions_originating_tool_call_uq")
1380
+ .on(
1381
+ table.workspaceId,
1382
+ table.originatingSessionId,
1383
+ table.originatingTurnId,
1384
+ table.originatingToolCallId,
1385
+ )
1386
+ .where(sql`${table.originatingToolCallId} is not null`),
1108
1387
  openResource: index("interaction_interventions_open_resource_idx").on(
1109
1388
  table.workspaceId,
1110
1389
  table.resourceKind,
@@ -1128,6 +1407,10 @@ export const interactionInterventions = pgTable(
1128
1407
  and ${table.reason} = btrim(${table.reason})
1129
1408
  and (${table.originatingAttemptId} is null or ${table.originatingTurnId} is not null)
1130
1409
  and (${table.originatingToolOperationId} is null or ${table.originatingAttemptId} is not null)
1410
+ and (${table.originatingToolCallId} is null or (
1411
+ ${table.originatingAttemptId} is not null
1412
+ and octet_length(${table.originatingToolCallId}) between 1 and 1024
1413
+ ))
1131
1414
  and (${table.responseActorSubjectId} is null or octet_length(${table.responseActorSubjectId}) between 1 and 1024)
1132
1415
  and ${table.version} > 0`,
1133
1416
  ),
@@ -1152,13 +1435,31 @@ export const interactionResourceOperations = pgTable(
1152
1435
  accountId: uuid("account_id").notNull(),
1153
1436
  workspaceId: uuid("workspace_id").notNull(),
1154
1437
  resourceKind: text("resource_kind", {
1155
- enum: ["network_route", "site_auth_connection", "auth_run", "intervention"],
1438
+ enum: [
1439
+ "browser_identity",
1440
+ "network_route",
1441
+ "site_auth_connection",
1442
+ "auth_run",
1443
+ "intervention",
1444
+ "browser_download",
1445
+ ],
1156
1446
  }).notNull(),
1157
1447
  resourceId: uuid("resource_id").notNull(),
1158
1448
  kind: text("kind", {
1159
- enum: ["create", "update", "start", "report", "protected_fill", "verify", "resolve"],
1449
+ enum: [
1450
+ "create",
1451
+ "update",
1452
+ "start",
1453
+ "report",
1454
+ "protected_fill",
1455
+ "external_auth",
1456
+ "verify",
1457
+ "resolve",
1458
+ "save",
1459
+ ],
1160
1460
  }).notNull(),
1161
1461
  requestDigest: text("request_digest").notNull(),
1462
+ metadata: jsonb("metadata").$type<Record<string, unknown>>().notNull().default({}),
1162
1463
  state: text("state", {
1163
1464
  enum: ["prepared", "dispatched", "completed", "failed", "outcome_unknown"],
1164
1465
  })
@@ -1185,6 +1486,8 @@ export const interactionResourceOperations = pgTable(
1185
1486
  valuesValid: check(
1186
1487
  "interaction_resource_operations_values_check",
1187
1488
  sql`${table.requestDigest} ~ '^[0-9a-f]{64}$'
1489
+ and jsonb_typeof(${table.metadata}) = 'object'
1490
+ and octet_length(${table.metadata}::text) between 2 and 65536
1188
1491
  and (${table.resultVersion} is null or ${table.resultVersion} > 0)
1189
1492
  and (${table.result} is null or (
1190
1493
  jsonb_typeof(${table.result}) = 'object'