@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
@@ -9,6 +9,7 @@ import {
9
9
  BrowserSessionCapabilities,
10
10
  InteractionError,
11
11
  PublishBrowserRevisionResponse,
12
+ UpdateBrowserIdentityRequest,
12
13
  type BrowserIdentity as BrowserIdentityValue,
13
14
  type BrowserIdentityListResponse as BrowserIdentityListResponseValue,
14
15
  type BrowserIdentityMutationResponse as BrowserIdentityMutationResponseValue,
@@ -17,6 +18,7 @@ import {
17
18
  type BrowserRevisionMaterialization as BrowserRevisionMaterializationValue,
18
19
  type InteractionError as InteractionErrorValue,
19
20
  type PublishBrowserRevisionResponse as PublishBrowserRevisionResponseValue,
21
+ type UpdateBrowserIdentityRequest as UpdateBrowserIdentityRequestValue,
20
22
  } from "@opengeni/contracts";
21
23
  import { and, asc, desc, eq, inArray, sql } from "drizzle-orm";
22
24
  import { type Database, withRlsContext } from "./database";
@@ -26,6 +28,9 @@ import {
26
28
  } from "./interaction-revisions";
27
29
  import { safeDatabaseErrorFacts } from "./persistence-errors";
28
30
  import {
31
+ commitBrowserStateUploadInTransaction,
32
+ markBrowserStateUploadsDeletePendingInTransaction,
33
+ prepareBrowserStateUploadInTransaction,
29
34
  validateBrowserStateArtifactCommitInput,
30
35
  type BrowserStateArtifactCommitInput,
31
36
  } from "./browser-state-artifacts";
@@ -37,6 +42,7 @@ type BrowserRevisionComponentRow = typeof schema.browserRevisionComponents.$infe
37
42
  type BrowserStateArtifactRow = typeof schema.browserStateArtifacts.$inferSelect;
38
43
  type BrowserSessionRow = typeof schema.browserSessions.$inferSelect;
39
44
  type InteractionOperationRow = typeof schema.interactionOperations.$inferSelect;
45
+ type InteractionResourceOperationRow = typeof schema.interactionResourceOperations.$inferSelect;
40
46
 
41
47
  const SHA256_PATTERN = /^[0-9a-f]{64}$/u;
42
48
  const MAX_COMPONENTS = 16;
@@ -57,8 +63,6 @@ export class BrowserIdentityStateError extends Error {
57
63
  readonly name = "BrowserIdentityStateError";
58
64
  }
59
65
 
60
- export type { BrowserStateArtifactCommitInput } from "./browser-state-artifacts";
61
-
62
66
  export type BrowserRevisionPublicationPreparation =
63
67
  | {
64
68
  kind: "completed";
@@ -117,6 +121,7 @@ function identityFromRow(row: BrowserIdentityRow): BrowserIdentityValue {
117
121
  workspaceId: row.workspaceId,
118
122
  name: row.name,
119
123
  status: row.status,
124
+ version: safeInteger(row.version, "BrowserIdentity version"),
120
125
  defaultRevisionId: row.defaultRevisionId,
121
126
  headGeneration: safeInteger(row.headGeneration, "BrowserIdentity head generation"),
122
127
  revisionCount: safeInteger(row.revisionCount, "BrowserIdentity revision count"),
@@ -393,6 +398,160 @@ export async function createBrowserIdentity(
393
398
  });
394
399
  }
395
400
 
401
+ export async function updateBrowserIdentity(
402
+ db: Database,
403
+ input: {
404
+ accountId: string;
405
+ workspaceId: string;
406
+ identityId: string;
407
+ actorSubjectId: string;
408
+ } & UpdateBrowserIdentityRequestValue,
409
+ ): Promise<BrowserIdentityMutationResponseValue> {
410
+ const request = UpdateBrowserIdentityRequest.parse({
411
+ operationId: input.operationId,
412
+ expectedVersion: input.expectedVersion,
413
+ ...(input.name !== undefined ? { name: input.name } : {}),
414
+ ...(input.status !== undefined ? { status: input.status } : {}),
415
+ ...(input.defaultRevisionId !== undefined
416
+ ? { defaultRevisionId: input.defaultRevisionId }
417
+ : {}),
418
+ });
419
+ const { operationId: _operationId, ...digestRequest } = request;
420
+ const requestDigest = createHash("sha256")
421
+ .update(
422
+ JSON.stringify({
423
+ version: 1,
424
+ identityId: input.identityId,
425
+ request: digestRequest,
426
+ actorSubjectId: input.actorSubjectId,
427
+ }),
428
+ )
429
+ .digest("hex");
430
+
431
+ try {
432
+ return await withRlsContext(
433
+ db,
434
+ input,
435
+ async (scopedDb) =>
436
+ await scopedDb.transaction(async (txRaw) => {
437
+ const tx = txRaw as unknown as Database;
438
+ await lockBrowserIdentityMutationOperation(tx, request.operationId);
439
+ const existing = await loadBrowserIdentityMutationOperation(
440
+ tx,
441
+ input.workspaceId,
442
+ request.operationId,
443
+ );
444
+ if (existing) {
445
+ if (
446
+ existing.resourceKind !== "browser_identity" ||
447
+ existing.resourceId !== input.identityId ||
448
+ existing.kind !== "update" ||
449
+ existing.requestDigest !== requestDigest ||
450
+ existing.actorSubjectId !== input.actorSubjectId
451
+ ) {
452
+ throw new BrowserIdentityConflictError(
453
+ "Operation id is already bound to another browser identity request",
454
+ );
455
+ }
456
+ if (existing.state !== "completed" || !existing.result || !existing.resultVersion) {
457
+ throw new BrowserIdentityStateError("Browser identity operation is not complete");
458
+ }
459
+ const response = BrowserIdentityMutationResponse.parse(existing.result);
460
+ return { ...response, replayed: true };
461
+ }
462
+
463
+ await lockBrowserIdentity(tx, input.workspaceId, input.identityId);
464
+ const current = await loadIdentity(tx, input.workspaceId, input.identityId);
465
+ if (!current) throw new BrowserIdentityNotFoundError("BrowserIdentity not found");
466
+ if (current.version !== request.expectedVersion) {
467
+ throw new BrowserIdentityConflictError("BrowserIdentity changed before this update");
468
+ }
469
+
470
+ let defaultRevisionChanged = false;
471
+ if (request.defaultRevisionId !== undefined) {
472
+ if ((request.status ?? current.status) !== "active") {
473
+ throw new BrowserIdentityStateError(
474
+ "An archived browser profile cannot select a default version",
475
+ );
476
+ }
477
+ const [revision] = await tx
478
+ .select({ id: schema.browserRevisions.id })
479
+ .from(schema.browserRevisions)
480
+ .where(
481
+ and(
482
+ eq(schema.browserRevisions.workspaceId, input.workspaceId),
483
+ eq(schema.browserRevisions.identityId, input.identityId),
484
+ eq(schema.browserRevisions.id, request.defaultRevisionId),
485
+ ),
486
+ )
487
+ .limit(1);
488
+ if (!revision) {
489
+ throw new BrowserIdentityStateError(
490
+ "Default browser version does not belong to this profile",
491
+ );
492
+ }
493
+ defaultRevisionChanged = request.defaultRevisionId !== current.defaultRevisionId;
494
+ }
495
+
496
+ const now = new Date();
497
+ const [row] = await tx
498
+ .update(schema.browserIdentities)
499
+ .set({
500
+ name: request.name ?? current.name,
501
+ status: request.status ?? current.status,
502
+ ...(defaultRevisionChanged
503
+ ? {
504
+ defaultRevisionId: request.defaultRevisionId,
505
+ headGeneration: safeInteger(
506
+ current.headGeneration + 1,
507
+ "next BrowserIdentity head generation",
508
+ ),
509
+ }
510
+ : {}),
511
+ version: safeInteger(current.version + 1, "next BrowserIdentity version"),
512
+ updatedAt: now,
513
+ })
514
+ .where(
515
+ and(
516
+ eq(schema.browserIdentities.workspaceId, input.workspaceId),
517
+ eq(schema.browserIdentities.id, input.identityId),
518
+ eq(schema.browserIdentities.version, request.expectedVersion),
519
+ ),
520
+ )
521
+ .returning();
522
+ if (!row) throw new BrowserIdentityConflictError("BrowserIdentity update lost its fence");
523
+
524
+ const response = BrowserIdentityMutationResponse.parse({
525
+ identity: identityFromRow(row),
526
+ operationId: request.operationId,
527
+ replayed: false,
528
+ });
529
+ await tx.insert(schema.interactionResourceOperations).values({
530
+ operationId: request.operationId,
531
+ accountId: input.accountId,
532
+ workspaceId: input.workspaceId,
533
+ resourceKind: "browser_identity",
534
+ resourceId: input.identityId,
535
+ kind: "update",
536
+ requestDigest,
537
+ resultVersion: row.version,
538
+ result: response,
539
+ actorSubjectId: input.actorSubjectId,
540
+ state: "completed",
541
+ settledAt: now,
542
+ });
543
+ await advanceWorkspaceInteractionRevision(tx, input.accountId, input.workspaceId);
544
+ return response;
545
+ }),
546
+ );
547
+ } catch (error) {
548
+ if (postgresConstraint(error) === "browser_identities_workspace_active_name_uq") {
549
+ throw new BrowserIdentityConflictError("An active browser profile already uses this name");
550
+ }
551
+ throw error;
552
+ }
553
+ }
554
+
396
555
  export function browserRevisionPublicationRequestDigest(input: {
397
556
  browserSessionId: string;
398
557
  identityId: string;
@@ -572,6 +731,7 @@ export async function dispatchBrowserRevisionPublication(
572
731
  expectedHeadGeneration: number;
573
732
  advanceDefault: boolean;
574
733
  actorSubjectId: string;
734
+ stateUpload?: { objectKey: string; cleanupAfter: Date };
575
735
  },
576
736
  ): Promise<BrowserRevisionPublicationDispatch> {
577
737
  const digest = browserRevisionPublicationRequestDigest(input);
@@ -634,6 +794,16 @@ export async function dispatchBrowserRevisionPublication(
634
794
  "Publication belongs to another controller generation",
635
795
  );
636
796
  }
797
+ if (input.stateUpload) {
798
+ await prepareBrowserStateUploadInTransaction(tx, {
799
+ accountId: input.accountId,
800
+ workspaceId: input.workspaceId,
801
+ operationId: input.operationId,
802
+ sourceBrowserSessionId: input.browserSessionId,
803
+ purpose: "revision_component",
804
+ ...input.stateUpload,
805
+ });
806
+ }
637
807
  return {
638
808
  kind: "dispatched",
639
809
  browserSessionId: input.browserSessionId,
@@ -642,6 +812,16 @@ export async function dispatchBrowserRevisionPublication(
642
812
  };
643
813
  }
644
814
 
815
+ if (input.stateUpload) {
816
+ await prepareBrowserStateUploadInTransaction(tx, {
817
+ accountId: input.accountId,
818
+ workspaceId: input.workspaceId,
819
+ operationId: input.operationId,
820
+ sourceBrowserSessionId: input.browserSessionId,
821
+ purpose: "revision_component",
822
+ ...input.stateUpload,
823
+ });
824
+ }
645
825
  const now = new Date();
646
826
  const [updated] = await tx
647
827
  .update(schema.interactionOperations)
@@ -781,6 +961,14 @@ export async function commitBrowserRevisionPublication(
781
961
  })
782
962
  .returning();
783
963
  if (!row) throw new Error("Browser state artifact insert was lost");
964
+ await commitBrowserStateUploadInTransaction(tx, {
965
+ workspaceId: input.workspaceId,
966
+ operationId: input.operationId,
967
+ sourceBrowserSessionId: input.browserSessionId,
968
+ purpose: "revision_component",
969
+ objectKey: artifact.objectKey,
970
+ artifactId: row.id,
971
+ });
784
972
  artifactRows.push(row);
785
973
  }
786
974
 
@@ -832,6 +1020,7 @@ export async function commitBrowserRevisionPublication(
832
1020
  .update(schema.browserIdentities)
833
1021
  .set({
834
1022
  revisionCount: ordinal,
1023
+ version: safeInteger(identity.version + 1, "next BrowserIdentity version"),
835
1024
  ...(defaultAdvanced
836
1025
  ? { defaultRevisionId: revisionId, headGeneration: resultHeadGeneration }
837
1026
  : {}),
@@ -980,6 +1169,7 @@ export async function failBrowserRevisionPublication(
980
1169
  )
981
1170
  .returning({ operationId: schema.interactionOperations.operationId });
982
1171
  if (!settled) throw new Error("BrowserRevision publication failure settlement was lost");
1172
+ await markBrowserStateUploadsDeletePendingInTransaction(tx, input);
983
1173
  }),
984
1174
  );
985
1175
  }
@@ -1041,7 +1231,7 @@ async function loadBrowserRevisionArtifactAuthority(
1041
1231
  revision,
1042
1232
  artifacts: components.map((component) => {
1043
1233
  const artifact = byArtifact.get(component.artifactId);
1044
- if (!artifact || artifact.state !== "available") {
1234
+ if (!artifact || artifact.state !== "available" || artifact.encryptedDataKey === null) {
1045
1235
  throw new BrowserIdentityStateError("BrowserRevision artifact is unavailable");
1046
1236
  }
1047
1237
  return {
@@ -1147,6 +1337,33 @@ async function lockBrowserIdentity(db: Database, workspaceId: string, identityId
1147
1337
  `);
1148
1338
  }
1149
1339
 
1340
+ async function lockBrowserIdentityMutationOperation(
1341
+ db: Database,
1342
+ operationId: string,
1343
+ ): Promise<void> {
1344
+ await db.execute(
1345
+ sql`select pg_advisory_xact_lock(hashtextextended(${`interaction-resource:${operationId}`}, 0))`,
1346
+ );
1347
+ }
1348
+
1349
+ async function loadBrowserIdentityMutationOperation(
1350
+ db: Database,
1351
+ workspaceId: string,
1352
+ operationId: string,
1353
+ ): Promise<InteractionResourceOperationRow | null> {
1354
+ const [row] = await db
1355
+ .select()
1356
+ .from(schema.interactionResourceOperations)
1357
+ .where(
1358
+ and(
1359
+ eq(schema.interactionResourceOperations.workspaceId, workspaceId),
1360
+ eq(schema.interactionResourceOperations.operationId, operationId),
1361
+ ),
1362
+ )
1363
+ .limit(1);
1364
+ return row ?? null;
1365
+ }
1366
+
1150
1367
  async function lockBrowserSession(db: Database, workspaceId: string, browserSessionId: string) {
1151
1368
  await db.execute(sql`
1152
1369
  select id from browser_sessions