@opengeni/db 3.2.0-canary.0 → 3.4.0-canary.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 (81) hide show
  1. package/dist/canonical-human-identities.js +3 -3
  2. package/dist/{chunk-SIBYBA2D.js → chunk-6DPJA36C.js} +30 -11
  3. package/dist/chunk-6DPJA36C.js.map +1 -0
  4. package/dist/{chunk-KRLPEMLH.js → chunk-C2AFP7SB.js} +184 -6
  5. package/dist/chunk-C2AFP7SB.js.map +1 -0
  6. package/dist/{chunk-AZHW7R5V.js → chunk-H7MXYG7R.js} +12 -8
  7. package/dist/chunk-H7MXYG7R.js.map +1 -0
  8. package/dist/{chunk-2PRS4J5Q.js → chunk-HY3F5Q4E.js} +3 -3
  9. package/dist/{chunk-NAB6FKFN.js → chunk-O6FTELKH.js} +3 -3
  10. package/dist/{chunk-UZNXG44K.js → chunk-PYMY3AJW.js} +324 -8
  11. package/dist/chunk-PYMY3AJW.js.map +1 -0
  12. package/dist/{chunk-6HMM2R5T.js → chunk-TRBOWUG3.js} +98 -4
  13. package/dist/chunk-TRBOWUG3.js.map +1 -0
  14. package/dist/{chunk-E6CLMKEE.js → chunk-V3TRUXFJ.js} +2 -2
  15. package/dist/{chunk-2EH4WRHL.js → chunk-ZWRIPCTR.js} +2 -2
  16. package/dist/editable-artifact-durable-export.js +2 -2
  17. package/dist/editable-artifacts.js +3 -3
  18. package/dist/governed-learning-activation.d.ts +16 -0
  19. package/dist/index.d.ts +108 -7
  20. package/dist/index.js +3605 -1417
  21. package/dist/index.js.map +1 -1
  22. package/dist/insights-model-bundle.d.ts +30 -0
  23. package/dist/insights-usage-bundle.d.ts +32 -0
  24. package/dist/insights.d.ts +10 -2
  25. package/dist/lossless-json.d.ts +1 -1
  26. package/dist/managed-user-setup.d.ts +82 -0
  27. package/dist/memory-domain.d.ts +2 -2
  28. package/dist/migrate.d.ts +3 -1
  29. package/dist/migrate.js +1 -1
  30. package/dist/new-session-drafts.d.ts +4 -4
  31. package/dist/organization-membership-lifecycle.d.ts +60 -1
  32. package/dist/pr-review.d.ts +44 -3
  33. package/dist/provision-roles.js +1 -1
  34. package/dist/runtime-posture.d.ts +12 -7
  35. package/dist/schema.d.ts +839 -101
  36. package/dist/schema.js +9 -1
  37. package/dist/session-background-commands.js +3 -3
  38. package/dist/session-tenancy.d.ts +12 -1
  39. package/dist/session-tenancy.js +3 -3
  40. package/dist/video-generation.js +3 -3
  41. package/drizzle/0348_named_signup_and_user_setup.sql +838 -0
  42. package/drizzle/0349_greenfield_session_tenancy_activation.sql +792 -0
  43. package/drizzle/0350_organization_shared_workspace_administration.sql +889 -0
  44. package/drizzle/0351_organization_user_setup_delivery.sql +978 -0
  45. package/drizzle/0352_session_variable_set_attachments.sql +1661 -0
  46. package/drizzle/0353_automatic_session_title_policy_fence.sql +476 -0
  47. package/drizzle/0354_automatic_session_title_quarantine_index.sql +9 -0
  48. package/drizzle/0355_automatic_session_title_quarantine.sql +92 -0
  49. package/drizzle/0356_set_based_insights_session_visibility.sql +237 -0
  50. package/drizzle/0357_rig_platform_base_only.sql +44 -0
  51. package/drizzle/0358_pr_review_managed_github_app.sql +108 -0
  52. package/drizzle/0359_insights_force_rls_read_capability.sql +936 -0
  53. package/drizzle/0360_organization_identity_confirmation_prompt.sql +103 -0
  54. package/drizzle/0361_remember_knowledge_memory_materialization.sql +249 -0
  55. package/package.json +6 -6
  56. package/src/database.ts +12 -8
  57. package/src/governed-learning-activation.ts +74 -2
  58. package/src/index.ts +879 -92
  59. package/src/insights-model-bundle.ts +681 -0
  60. package/src/insights-usage-bundle.ts +240 -0
  61. package/src/insights.ts +265 -152
  62. package/src/lossless-json.ts +2 -1
  63. package/src/managed-user-setup.ts +316 -0
  64. package/src/memory-domain.ts +3 -3
  65. package/src/migrate.ts +38 -14
  66. package/src/new-session-drafts.ts +22 -15
  67. package/src/organization-membership-lifecycle.ts +253 -1
  68. package/src/pr-review.ts +449 -6
  69. package/src/provision-roles.ts +92 -0
  70. package/src/runtime-posture.ts +247 -4
  71. package/src/schema.ts +210 -4
  72. package/src/session-tenancy.ts +120 -2
  73. package/dist/chunk-6HMM2R5T.js.map +0 -1
  74. package/dist/chunk-AZHW7R5V.js.map +0 -1
  75. package/dist/chunk-KRLPEMLH.js.map +0 -1
  76. package/dist/chunk-SIBYBA2D.js.map +0 -1
  77. package/dist/chunk-UZNXG44K.js.map +0 -1
  78. /package/dist/{chunk-2PRS4J5Q.js.map → chunk-HY3F5Q4E.js.map} +0 -0
  79. /package/dist/{chunk-NAB6FKFN.js.map → chunk-O6FTELKH.js.map} +0 -0
  80. /package/dist/{chunk-E6CLMKEE.js.map → chunk-V3TRUXFJ.js.map} +0 -0
  81. /package/dist/{chunk-2EH4WRHL.js.map → chunk-ZWRIPCTR.js.map} +0 -0
package/src/schema.ts CHANGED
@@ -34,6 +34,7 @@ import {
34
34
  integer,
35
35
  jsonb,
36
36
  numeric,
37
+ pgSchema,
37
38
  pgTable,
38
39
  primaryKey,
39
40
  text,
@@ -61,6 +62,8 @@ const bytea = customType<{ data: Uint8Array; driverData: Uint8Array }>({
61
62
  },
62
63
  });
63
64
 
65
+ const opengeniPrivateSchema = pgSchema("opengeni_private");
66
+
64
67
  export type ConnectorActionPolicyDecision = "allow" | "ask" | "block";
65
68
 
66
69
  export type ConnectorActionPolicySnapshotEntry = {
@@ -3786,6 +3789,10 @@ export const sessions = pgTable(
3786
3789
  // write the result through the epoch-fenced setActiveSandbox CAS. Legacy
3787
3790
  // rows may still be null/relative and are resolved at establishment.
3788
3791
  workingDir: text("working_dir"),
3792
+ // Ordered low-to-high precedence source for public/session/runtime reads.
3793
+ // session_variable_set_attachments is the FK-backed lifecycle projection;
3794
+ // the session trigger maintains it and the legacy singular alias atomically.
3795
+ variableSetIds: jsonb("variable_set_ids").$type<string[]>().notNull().default([]),
3789
3796
  variableSetId: uuid("variable_set_id").references(() => workspaceVariableSets.id, {
3790
3797
  onDelete: "set null",
3791
3798
  }),
@@ -4023,6 +4030,63 @@ export const sessions = pgTable(
4023
4030
  }),
4024
4031
  );
4025
4032
 
4033
+ export const sessionVariableSetAttachments = pgTable(
4034
+ "session_variable_set_attachments",
4035
+ {
4036
+ id: uuid("id").primaryKey().defaultRandom(),
4037
+ accountId: uuid("account_id")
4038
+ .notNull()
4039
+ .references(() => managedAccounts.id, { onDelete: "cascade" }),
4040
+ workspaceId: uuid("workspace_id").notNull(),
4041
+ sessionId: uuid("session_id").notNull(),
4042
+ variableSetId: uuid("variable_set_id")
4043
+ .notNull()
4044
+ .references(() => workspaceVariableSets.id, { onDelete: "cascade" }),
4045
+ position: integer("position").notNull(),
4046
+ sessionStatus: text("session_status").notNull(),
4047
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
4048
+ },
4049
+ (table) => ({
4050
+ workspaceAccount: foreignKey({
4051
+ name: "session_variable_set_attachments_workspace_account_fk",
4052
+ columns: [table.workspaceId, table.accountId],
4053
+ foreignColumns: [workspaces.id, workspaces.accountId],
4054
+ }).onDelete("cascade"),
4055
+ session: foreignKey({
4056
+ name: "session_variable_set_attachments_session_fk",
4057
+ columns: [table.workspaceId, table.sessionId],
4058
+ foreignColumns: [sessions.workspaceId, sessions.id],
4059
+ }).onDelete("cascade"),
4060
+ sessionPosition: uniqueIndex("session_variable_set_attachments_session_position_uq").on(
4061
+ table.workspaceId,
4062
+ table.sessionId,
4063
+ table.position,
4064
+ ),
4065
+ sessionVariableSet: uniqueIndex("session_variable_set_attachments_session_set_uq").on(
4066
+ table.workspaceId,
4067
+ table.sessionId,
4068
+ table.variableSetId,
4069
+ ),
4070
+ variableSetSessions: index("session_variable_set_attachments_set_sessions_idx").on(
4071
+ table.variableSetId,
4072
+ table.sessionStatus,
4073
+ table.workspaceId,
4074
+ table.sessionId,
4075
+ ),
4076
+ positionValid: check(
4077
+ "session_variable_set_attachments_position_check",
4078
+ sql`${table.position} >= 0 and ${table.position} < 25`,
4079
+ ),
4080
+ statusValid: check(
4081
+ "session_variable_set_attachments_status_check",
4082
+ sql`${table.sessionStatus} in (
4083
+ 'queued', 'running', 'idle', 'requires_action', 'recovering',
4084
+ 'waiting_capacity', 'failed', 'cancelled'
4085
+ )`,
4086
+ ),
4087
+ }),
4088
+ );
4089
+
4026
4090
  export const organizationUserResourceGrants = pgTable(
4027
4091
  "organization_user_resource_grants",
4028
4092
  {
@@ -5997,7 +6061,7 @@ export const turnPersonalResourceAttachmentReceipts = pgTable(
5997
6061
  sql`${table.sessionAuthorityEpoch} > 0
5998
6062
  and octet_length(${table.initiatingHumanSubjectId}) between 1 and 512
5999
6063
  and ${table.membershipAuthorizationRevision} > 0
6000
- and ${table.resourceCount} between 1 and 28
6064
+ and ${table.resourceCount} between 1 and 52
6001
6065
  and ${table.grantMode} in ('once', 'session', 'always')
6002
6066
  and ${table.sessionVisibility} in ('user_private', 'workspace_shared')
6003
6067
  and ${table.sharedOutputWarningVersion} = 1
@@ -6063,7 +6127,7 @@ export const turnPersonalResourceSnapshots = pgTable(
6063
6127
  sql`${table.membershipAuthorizationRevision} > 0
6064
6128
  and ${table.authorityGeneration} > 0
6065
6129
  and ${table.grantGeneration} > 0
6066
- and cardinality(${table.selectionSources}) between 1 and 26`,
6130
+ and cardinality(${table.selectionSources}) between 1 and 50`,
6067
6131
  ),
6068
6132
  grantShape: check(
6069
6133
  "turn_personal_resource_snapshots_grant_chk",
@@ -7823,6 +7887,50 @@ export const sessionEvents = pgTable(
7823
7887
  }),
7824
7888
  );
7825
7889
 
7890
+ /**
7891
+ * Durable fanout obligation for the migration-owned automatic-title
7892
+ * quarantine event. The deployment-wide workflow-wake dispatcher publishes
7893
+ * these exact committed events and marks them delivered; duplicate publication
7894
+ * after a process crash is safe because consumers sequence-fence every event.
7895
+ */
7896
+ export const automaticSessionTitleFanoutOutboxV1 = opengeniPrivateSchema.table(
7897
+ "automatic_session_title_fanout_outbox_v1",
7898
+ {
7899
+ id: uuid("id").primaryKey().defaultRandom(),
7900
+ accountId: uuid("account_id").notNull(),
7901
+ workspaceId: uuid("workspace_id").notNull(),
7902
+ sessionId: uuid("session_id").notNull(),
7903
+ eventId: uuid("event_id").notNull(),
7904
+ attempts: integer("attempts").notNull().default(0),
7905
+ lastError: text("last_error"),
7906
+ deliveredAt: timestamp("delivered_at", { withTimezone: true }),
7907
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
7908
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
7909
+ },
7910
+ (table) => ({
7911
+ attemptsValid: check("automatic_title_fanout_attempts_chk", sql`${table.attempts} >= 0`),
7912
+ workspaceAccount: foreignKey({
7913
+ name: "automatic_title_fanout_workspace_account_fk",
7914
+ columns: [table.workspaceId, table.accountId],
7915
+ foreignColumns: [workspaces.id, workspaces.accountId],
7916
+ }).onDelete("cascade"),
7917
+ workspaceSession: foreignKey({
7918
+ name: "automatic_title_fanout_workspace_session_fk",
7919
+ columns: [table.workspaceId, table.sessionId],
7920
+ foreignColumns: [sessions.workspaceId, sessions.id],
7921
+ }).onDelete("cascade"),
7922
+ workspaceEvent: foreignKey({
7923
+ name: "automatic_title_fanout_workspace_event_fk",
7924
+ columns: [table.workspaceId, table.eventId],
7925
+ foreignColumns: [sessionEvents.workspaceId, sessionEvents.id],
7926
+ }).onDelete("cascade"),
7927
+ event: uniqueIndex("automatic_title_fanout_event_uq").on(table.eventId),
7928
+ pending: index("automatic_title_fanout_pending_idx")
7929
+ .on(table.createdAt, table.id)
7930
+ .where(sql`${table.deliveredAt} is null`),
7931
+ }),
7932
+ );
7933
+
7826
7934
  export const agentRunStates = pgTable("agent_run_states", {
7827
7935
  id: uuid("id").primaryKey().defaultRandom(),
7828
7936
  accountId: uuid("account_id")
@@ -10329,6 +10437,14 @@ export const prReviewAppRegistrations = pgTable(
10329
10437
  provider: text("provider").notNull(),
10330
10438
  providerBaseUrl: text("provider_base_url").notNull(),
10331
10439
  appId: text("app_id"),
10440
+ installationId: text("installation_id"),
10441
+ providerAccountLogin: text("provider_account_login"),
10442
+ providerAccountType: text("provider_account_type"),
10443
+ githubActorId: text("github_actor_id"),
10444
+ authorityKind: text("authority_kind"),
10445
+ authorityCheckedAt: timestamp("authority_checked_at", { withTimezone: true }),
10446
+ authorityExpiresAt: timestamp("authority_expires_at", { withTimezone: true }),
10447
+ authorityNonce: text("authority_nonce"),
10332
10448
  credentialKind: text("credential_kind").notNull(),
10333
10449
  credentialEncrypted: text("credential_encrypted"),
10334
10450
  accessTokenExpiresAt: timestamp("access_token_expires_at", { withTimezone: true }),
@@ -10356,6 +10472,12 @@ export const prReviewAppRegistrations = pgTable(
10356
10472
  table.workspaceId,
10357
10473
  table.status,
10358
10474
  ),
10475
+ managedGithubInstallation: uniqueIndex("pr_review_managed_github_workspace_installation_uq")
10476
+ .on(table.workspaceId, table.installationId)
10477
+ .where(sql`${table.credentialKind} = 'managed_github_app'`),
10478
+ managedGithubAuthorityNonce: uniqueIndex("pr_review_managed_github_authority_nonce_uq")
10479
+ .on(table.authorityNonce)
10480
+ .where(sql`${table.authorityNonce} is not null`),
10359
10481
  providerCheck: check(
10360
10482
  "pr_review_app_registrations_provider_chk",
10361
10483
  sql`${table.provider} in ('github', 'gitlab', 'azure_devops')`,
@@ -10363,9 +10485,11 @@ export const prReviewAppRegistrations = pgTable(
10363
10485
  credentialCheck: check(
10364
10486
  "pr_review_app_registrations_credential_chk",
10365
10487
  sql`(
10366
- (${table.provider} = 'github' and ${table.credentialKind} = 'github_app' and ${table.credentialEncrypted} is not null and ${table.appId} is not null)
10488
+ (${table.provider} = 'github' and ${table.credentialKind} = 'github_app' and ${table.credentialEncrypted} is not null and ${table.appId} is not null and ${table.installationId} is null)
10489
+ or
10490
+ (${table.provider} = 'github' and ${table.credentialKind} = 'managed_github_app' and ${table.credentialEncrypted} is null and ${table.appId} is not null and ${table.installationId} is not null and ${table.providerAccountType} in ('User', 'Organization') and ${table.githubActorId} ~ '^[1-9][0-9]*$' and ${table.authorityKind} in ('personal_owner', 'organization_owner') and ${table.authorityCheckedAt} is not null and ${table.authorityExpiresAt} is not null and ${table.authorityExpiresAt} > ${table.authorityCheckedAt} and octet_length(${table.authorityNonce}) between 16 and 256)
10367
10491
  or
10368
- (${table.provider} in ('gitlab', 'azure_devops') and ${table.credentialKind} = 'provider_token' and ${table.credentialEncrypted} is not null)
10492
+ (${table.provider} in ('gitlab', 'azure_devops') and ${table.credentialKind} = 'provider_token' and ${table.credentialEncrypted} is not null and ${table.installationId} is null)
10369
10493
  )`,
10370
10494
  ),
10371
10495
  webhookAuthCheck: check(
@@ -10455,6 +10579,86 @@ export const prReviewRepositoryBindings = pgTable(
10455
10579
  }),
10456
10580
  );
10457
10581
 
10582
+ /** Append-only successful OAuth-state consumption receipts. The latest receipt
10583
+ * is also projected on the registration, but this ledger owns durable replay
10584
+ * rejection across later reconnects. */
10585
+ export const prReviewManagedGithubAuthorityNonces = pgTable(
10586
+ "pr_review_managed_github_authority_nonces",
10587
+ {
10588
+ authorityNonce: text("authority_nonce").primaryKey(),
10589
+ accountId: uuid("account_id")
10590
+ .notNull()
10591
+ .references(() => managedAccounts.id, { onDelete: "cascade" }),
10592
+ workspaceId: uuid("workspace_id")
10593
+ .notNull()
10594
+ .references(() => workspaces.id, { onDelete: "cascade" }),
10595
+ installationId: text("installation_id").notNull(),
10596
+ authorityExpiresAt: timestamp("authority_expires_at", { withTimezone: true }).notNull(),
10597
+ consumedAt: timestamp("consumed_at", { withTimezone: true }).notNull().defaultNow(),
10598
+ },
10599
+ (table) => ({
10600
+ identityCheck: check(
10601
+ "pr_review_managed_github_authority_nonces_identity_chk",
10602
+ sql`octet_length(${table.authorityNonce}) between 16 and 256
10603
+ and ${table.installationId} ~ '^[1-9][0-9]*$'
10604
+ and ${table.authorityExpiresAt} > ${table.consumedAt}`,
10605
+ ),
10606
+ workspaceAccount: foreignKey({
10607
+ columns: [table.workspaceId, table.accountId],
10608
+ foreignColumns: [workspaces.id, workspaces.accountId],
10609
+ name: "pr_review_managed_github_authority_nonces_workspace_account_fk",
10610
+ }).onDelete("cascade"),
10611
+ }),
10612
+ );
10613
+
10614
+ /** Credential-free routing for the deployment-owned PR-review GitHub App.
10615
+ * Signature verification happens before provider ids reach this table. */
10616
+ export const prReviewManagedGithubRoutes = pgTable(
10617
+ "pr_review_managed_github_routes",
10618
+ {
10619
+ bindingId: uuid("binding_id")
10620
+ .primaryKey()
10621
+ .references(() => prReviewRepositoryBindings.id, { onDelete: "cascade" }),
10622
+ accountId: uuid("account_id")
10623
+ .notNull()
10624
+ .references(() => managedAccounts.id, { onDelete: "cascade" }),
10625
+ workspaceId: uuid("workspace_id")
10626
+ .notNull()
10627
+ .references(() => workspaces.id, { onDelete: "cascade" }),
10628
+ registrationId: uuid("registration_id").notNull(),
10629
+ sourceId: uuid("source_id").notNull(),
10630
+ installationId: text("installation_id").notNull(),
10631
+ providerRepositoryId: text("provider_repository_id").notNull(),
10632
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
10633
+ },
10634
+ (table) => ({
10635
+ routeIdentity: uniqueIndex("pr_review_managed_github_route_identity_uq").on(
10636
+ table.installationId,
10637
+ table.providerRepositoryId,
10638
+ ),
10639
+ identityCheck: check(
10640
+ "pr_review_managed_github_routes_identity_chk",
10641
+ sql`${table.installationId} ~ '^[1-9][0-9]*$'
10642
+ and ${table.providerRepositoryId} ~ '^[1-9][0-9]*$'`,
10643
+ ),
10644
+ workspaceAccount: foreignKey({
10645
+ columns: [table.workspaceId, table.accountId],
10646
+ foreignColumns: [workspaces.id, workspaces.accountId],
10647
+ name: "pr_review_managed_github_routes_workspace_account_fk",
10648
+ }).onDelete("cascade"),
10649
+ registration: foreignKey({
10650
+ columns: [table.workspaceId, table.registrationId],
10651
+ foreignColumns: [prReviewAppRegistrations.workspaceId, prReviewAppRegistrations.id],
10652
+ name: "pr_review_managed_github_routes_registration_fk",
10653
+ }).onDelete("cascade"),
10654
+ source: foreignKey({
10655
+ columns: [table.workspaceId, table.sourceId],
10656
+ foreignColumns: [automationSources.workspaceId, automationSources.id],
10657
+ name: "pr_review_managed_github_routes_source_fk",
10658
+ }).onDelete("cascade"),
10659
+ }),
10660
+ );
10661
+
10458
10662
  export const usageEvents = pgTable(
10459
10663
  "usage_events",
10460
10664
  {
@@ -12189,6 +12393,8 @@ export const rigVersions = pgTable(
12189
12393
  .notNull()
12190
12394
  .references(() => rigs.id, { onDelete: "cascade" }),
12191
12395
  version: integer("version").notNull(),
12396
+ // Legacy audit field only. Migration 0356 rejects new non-null values;
12397
+ // runtime always uses the deployment platform sandbox image.
12192
12398
  image: text("image"),
12193
12399
  setupScript: text("setup_script"),
12194
12400
  // Self-declared health checks: [{ name, command }].
@@ -121,6 +121,17 @@ export type ForkSessionContentInput = {
121
121
  destinationVisibility: SessionTenancyVisibility;
122
122
  workspaceSharedAcknowledged: boolean;
123
123
  operationKey: string;
124
+ runtimeRequest?: ForkSessionRuntimeRequest;
125
+ runtimeConfiguration?: ForkSessionRuntimeConfiguration;
126
+ };
127
+
128
+ export type ForkSessionRuntimeRequest = {
129
+ variableSetIds: string[];
130
+ rigId: string | null;
131
+ };
132
+
133
+ export type ForkSessionRuntimeConfiguration = ForkSessionRuntimeRequest & {
134
+ rigVersionId: string | null;
124
135
  };
125
136
 
126
137
  export type ForkSessionContentResult = {
@@ -133,6 +144,8 @@ export type ForkSessionContentResult = {
133
144
  authorityEpoch: number;
134
145
  copiedHistoryItemCount: number;
135
146
  replay: boolean;
147
+ runtimeEventId: string | null;
148
+ runtimeEventSequence: number | null;
136
149
  };
137
150
 
138
151
  export async function sessionTenancyProductActivated(
@@ -332,8 +345,23 @@ export function canonicalSessionForkHash(
332
345
  | "destinationWorkspaceId"
333
346
  | "destinationVisibility"
334
347
  | "workspaceSharedAcknowledged"
348
+ | "runtimeRequest"
335
349
  >,
336
350
  ): string {
351
+ if (input.runtimeRequest) {
352
+ return createHash("sha256")
353
+ .update(
354
+ JSON.stringify({
355
+ version: 3,
356
+ sourceSessionId: input.sourceSessionId,
357
+ destinationWorkspaceId: input.destinationWorkspaceId,
358
+ destinationVisibility: input.destinationVisibility,
359
+ workspaceSharedAcknowledged: input.workspaceSharedAcknowledged,
360
+ runtime: input.runtimeRequest,
361
+ }),
362
+ )
363
+ .digest("hex");
364
+ }
337
365
  const legacyCompatiblePrivateRequest =
338
366
  input.destinationVisibility === "user_private" && !input.workspaceSharedAcknowledged;
339
367
  return createHash("sha256")
@@ -358,6 +386,12 @@ export function canonicalSessionForkHash(
358
386
  .digest("hex");
359
387
  }
360
388
 
389
+ function canonicalForkRuntimeConfigurationDigest(input: ForkSessionRuntimeRequest): string {
390
+ return createHash("sha256")
391
+ .update(JSON.stringify({ version: 1, ...input }))
392
+ .digest("hex");
393
+ }
394
+
361
395
  export async function transitionSessionVisibility(
362
396
  db: Database,
363
397
  input: TransitionSessionVisibilityInput,
@@ -437,6 +471,17 @@ export async function forkSessionContent(
437
471
  if (input.destinationWorkspaceId !== input.sourceWorkspaceId) {
438
472
  throw new Error("The first session fork contract is same-workspace only");
439
473
  }
474
+ if (Boolean(input.runtimeRequest) !== Boolean(input.runtimeConfiguration)) {
475
+ throw new Error("A fresh session fork runtime request requires its resolved configuration");
476
+ }
477
+ if (
478
+ input.runtimeRequest &&
479
+ (input.runtimeRequest.rigId !== input.runtimeConfiguration?.rigId ||
480
+ JSON.stringify(input.runtimeRequest.variableSetIds) !==
481
+ JSON.stringify(input.runtimeConfiguration?.variableSetIds))
482
+ ) {
483
+ throw new Error("Resolved session fork runtime configuration does not match its request");
484
+ }
440
485
  const { accountId } = await rlsContextForWorkspace(db, input.sourceWorkspaceId);
441
486
  await assertSessionTenancyProductActivated(db, input.sourceWorkspaceId);
442
487
  const requestHash = canonicalSessionForkHash(input);
@@ -446,6 +491,43 @@ export async function forkSessionContent(
446
491
  input.sourceWorkspaceId,
447
492
  input.actorSubjectId,
448
493
  async (scopedDb) => {
494
+ if (input.runtimeRequest && input.runtimeConfiguration) {
495
+ const runtimeDigest = canonicalForkRuntimeConfigurationDigest(input.runtimeRequest);
496
+ const rows = await rawRows<ForkSessionContentResult>(
497
+ scopedDb,
498
+ sql`select
499
+ operation_id as "operationId",
500
+ event_id as "eventId",
501
+ event_sequence as "eventSequence",
502
+ session_id as "sessionId",
503
+ workspace_id as "workspaceId",
504
+ visibility,
505
+ authority_epoch as "authorityEpoch",
506
+ copied_history_item_count as "copiedHistoryItemCount",
507
+ replay,
508
+ runtime_event_id as "runtimeEventId",
509
+ runtime_event_sequence as "runtimeEventSequence"
510
+ from fork_session_content_with_runtime(
511
+ ${accountId}::uuid,
512
+ ${input.sourceWorkspaceId}::uuid,
513
+ ${input.sourceSessionId}::uuid,
514
+ ${input.actorSubjectId},
515
+ ${input.destinationWorkspaceId}::uuid,
516
+ ${input.destinationVisibility},
517
+ ${input.workspaceSharedAcknowledged},
518
+ ${input.operationKey},
519
+ ${requestHash},
520
+ ${SESSION_TENANCY_ACTIVATION_VERSION},
521
+ ${JSON.stringify(input.runtimeConfiguration.variableSetIds)}::jsonb,
522
+ ${input.runtimeConfiguration.rigId}::uuid,
523
+ ${input.runtimeConfiguration.rigVersionId}::uuid,
524
+ ${runtimeDigest}
525
+ )`,
526
+ );
527
+ const result = rows[0];
528
+ if (!result) throw new Error("Session fork returned no result");
529
+ return result;
530
+ }
449
531
  const rows = await rawRows<ForkSessionContentResult>(
450
532
  scopedDb,
451
533
  sql`select
@@ -457,7 +539,9 @@ export async function forkSessionContent(
457
539
  visibility,
458
540
  authority_epoch as "authorityEpoch",
459
541
  copied_history_item_count as "copiedHistoryItemCount",
460
- replay
542
+ replay,
543
+ null::uuid as "runtimeEventId",
544
+ null::integer as "runtimeEventSequence"
461
545
  from fork_session_content(
462
546
  ${accountId}::uuid,
463
547
  ${input.sourceWorkspaceId}::uuid,
@@ -515,6 +599,38 @@ export async function replayAppliedSessionFork(
515
599
  input.sourceWorkspaceId,
516
600
  input.actorSubjectId,
517
601
  async (scopedDb) => {
602
+ if (input.runtimeRequest) {
603
+ const runtimeDigest = canonicalForkRuntimeConfigurationDigest(input.runtimeRequest);
604
+ const rows = await rawRows<ForkSessionContentResult>(
605
+ scopedDb,
606
+ sql`select
607
+ operation_id as "operationId",
608
+ event_id as "eventId",
609
+ event_sequence as "eventSequence",
610
+ session_id as "sessionId",
611
+ workspace_id as "workspaceId",
612
+ visibility,
613
+ authority_epoch as "authorityEpoch",
614
+ copied_history_item_count as "copiedHistoryItemCount",
615
+ replay,
616
+ runtime_event_id as "runtimeEventId",
617
+ runtime_event_sequence as "runtimeEventSequence"
618
+ from replay_applied_session_fork_with_runtime(
619
+ ${accountId}::uuid,
620
+ ${input.sourceWorkspaceId}::uuid,
621
+ ${input.sourceSessionId}::uuid,
622
+ ${input.actorSubjectId},
623
+ ${input.destinationWorkspaceId}::uuid,
624
+ ${input.destinationVisibility},
625
+ ${input.workspaceSharedAcknowledged},
626
+ ${input.operationKey},
627
+ ${requestHash},
628
+ ${SESSION_TENANCY_ACTIVATION_VERSION},
629
+ ${runtimeDigest}
630
+ )`,
631
+ );
632
+ return rows[0] ?? null;
633
+ }
518
634
  const rows = await rawRows<ForkSessionContentResult>(
519
635
  scopedDb,
520
636
  sql`select
@@ -526,7 +642,9 @@ export async function replayAppliedSessionFork(
526
642
  visibility,
527
643
  authority_epoch as "authorityEpoch",
528
644
  copied_history_item_count as "copiedHistoryItemCount",
529
- replay
645
+ replay,
646
+ null::uuid as "runtimeEventId",
647
+ null::integer as "runtimeEventSequence"
530
648
  from replay_applied_session_fork(
531
649
  ${accountId}::uuid,
532
650
  ${input.sourceWorkspaceId}::uuid,
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/session-tenancy.ts"],"sourcesContent":["import { createHash } from \"node:crypto\";\nimport { sql } from \"drizzle-orm\";\nimport {\n SessionTenancyBlocker as SessionTenancyBlockerSchema,\n type SessionTenancyBlocker,\n} from \"@opengeni/contracts\";\nimport {\n rawRows,\n type Database,\n rlsContextForWorkspace,\n withWorkspaceRls,\n withWorkspaceSubjectRls,\n withWorkspaceSubjectSessionActivityRls,\n} from \"./database\";\nimport { nestedPostgresSqlState } from \"./persistence-errors\";\n\nconst SESSION_TENANCY_ACTIVATION_VERSION = 1;\n\nexport class SessionTenancyConflictError extends Error {\n readonly name = \"SessionTenancyConflictError\";\n constructor(\n readonly reason: \"not_quiescent\" | \"authority_epoch\" | \"operation_reuse\",\n readonly blocker: SessionTenancyBlocker | null = null,\n options?: ErrorOptions,\n ) {\n super(\n reason === \"not_quiescent\"\n ? \"Session must be fully quiescent before its tenancy can change\"\n : reason === \"authority_epoch\"\n ? \"Session authority changed before the operation committed\"\n : \"Session tenancy operation key was reused with different input\",\n options,\n );\n }\n}\n\nexport class SessionTenancyNotActivatedError extends Error {\n readonly name = \"SessionTenancyNotActivatedError\";\n constructor(options?: ErrorOptions) {\n super(\"Session tenancy product surface is not activated for this organization\", options);\n }\n}\n\nexport class SessionTenancyAccessError extends Error {\n readonly name = \"SessionTenancyAccessError\";\n constructor(options?: ErrorOptions) {\n super(\"Session tenancy target is unavailable\", options);\n }\n}\n\nexport class SessionTenancyInvalidRequestError extends Error {\n readonly name = \"SessionTenancyInvalidRequestError\";\n constructor(options?: ErrorOptions) {\n super(\"Session tenancy request is invalid\", options);\n }\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return Boolean(value && typeof value === \"object\");\n}\n\n/** Extract only the fixed quiescence DETAIL vocabulary, never arbitrary driver detail. */\nexport function nestedSessionTenancyBlocker(error: unknown): SessionTenancyBlocker | null {\n const queue: unknown[] = [error];\n const seen = new Set<unknown>();\n while (queue.length > 0 && seen.size < 64) {\n const current = queue.shift();\n if (!isRecord(current) || seen.has(current)) continue;\n seen.add(current);\n for (const key of [\"detail\", \"detailMessage\"] as const) {\n const parsed = SessionTenancyBlockerSchema.safeParse(current[key]);\n if (parsed.success) return parsed.data;\n }\n for (const key of [\"cause\", \"original\", \"driverError\", \"error\", \"errors\"] as const) {\n const nested = current[key];\n if (Array.isArray(nested)) queue.push(...nested);\n else if (nested !== undefined) queue.push(nested);\n }\n }\n return null;\n}\n\nexport type SessionTenancyVisibility = \"user_private\" | \"workspace_shared\";\n\nexport type PrivateSessionCreatePolicy = {\n personalWorkspace: boolean;\n platformAvailable: boolean;\n organizationEnabled: boolean;\n};\n\nexport type TransitionSessionVisibilityInput = {\n workspaceId: string;\n sessionId: string;\n actorSubjectId: string;\n targetVisibility: SessionTenancyVisibility;\n expectedAuthorityEpoch: number;\n operationKey: string;\n};\n\nexport type TransitionSessionVisibilityResult = {\n operationId: string;\n eventId: string | null;\n eventSequence: number | null;\n visibility: SessionTenancyVisibility;\n authorityEpoch: number;\n ownerOrganizationMembershipId: string | null;\n changed: boolean;\n replay: boolean;\n interruptedAttemptCount: number;\n cancelledTurnCount: number;\n cancelledUpdateCount: number;\n pausedGoalCount: number;\n revokedGrantCount: number;\n};\n\nexport type ForkSessionContentInput = {\n sourceWorkspaceId: string;\n sourceSessionId: string;\n actorSubjectId: string;\n destinationWorkspaceId: string;\n destinationVisibility: SessionTenancyVisibility;\n workspaceSharedAcknowledged: boolean;\n operationKey: string;\n};\n\nexport type ForkSessionContentResult = {\n operationId: string;\n eventId: string;\n eventSequence: number;\n sessionId: string;\n workspaceId: string;\n visibility: SessionTenancyVisibility;\n authorityEpoch: number;\n copiedHistoryItemCount: number;\n replay: boolean;\n};\n\nexport async function sessionTenancyProductActivated(\n db: Database,\n workspaceId: string,\n): Promise<boolean> {\n const { accountId } = await rlsContextForWorkspace(db, workspaceId);\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const rows = await rawRows<{ activated: boolean }>(\n scopedDb,\n sql`select session_tenancy_product_activated(\n ${accountId}::uuid,\n ${SESSION_TENANCY_ACTIVATION_VERSION}\n ) as activated`,\n );\n return rows[0]?.activated === true;\n });\n}\n\nexport async function getPrivateSessionCreatePolicy(\n db: Database,\n input: { workspaceId: string; actorSubjectId: string },\n): Promise<PrivateSessionCreatePolicy> {\n const { accountId } = await rlsContextForWorkspace(db, input.workspaceId);\n return await withWorkspaceSubjectRls(\n db,\n input.workspaceId,\n input.actorSubjectId,\n async (scopedDb) => {\n const rows = await rawRows<{\n personalWorkspace: boolean;\n platformAvailable: boolean;\n organizationEnabled: boolean;\n }>(\n scopedDb,\n sql`select\n personal_workspace as \"personalWorkspace\",\n platform_available as \"platformAvailable\",\n organization_enabled as \"organizationEnabled\"\n from get_private_session_create_policy(\n ${accountId}::uuid,\n ${input.workspaceId}::uuid,\n ${input.actorSubjectId}\n )`,\n );\n const policy = rows[0];\n if (!policy) throw new SessionTenancyAccessError();\n return policy;\n },\n );\n}\n\n/** Open the exact transaction-local trigger capability used by atomic private create. */\nexport async function openPrivateSessionCreateCapability(\n db: Database,\n input: { accountId: string; workspaceId: string; sessionId: string; actorSubjectId: string },\n): Promise<{ capabilityId: string; ownerMembershipId: string }> {\n let rows: Array<{ capabilityId: string; ownerMembershipId: string }>;\n try {\n rows = await rawRows<{ capabilityId: string; ownerMembershipId: string }>(\n db,\n sql`select\n capability_id as \"capabilityId\",\n owner_membership_id as \"ownerMembershipId\"\n from open_private_session_create_capability(\n ${input.accountId}::uuid,\n ${input.workspaceId}::uuid,\n ${input.sessionId}::uuid,\n ${input.actorSubjectId}\n )`,\n );\n } catch (error) {\n // The definer raises 55000 only when the organization owner/admin setting\n // does not permit a new private session in this shared workspace; every\n // authority failure remains 42501 and propagates unchanged.\n if (nestedPostgresSqlState(error) === \"55000\") {\n throw new SessionTenancyNotActivatedError({ cause: error });\n }\n throw error;\n }\n const capabilityId = rows[0]?.capabilityId;\n const ownerMembershipId = rows[0]?.ownerMembershipId;\n if (!capabilityId || !ownerMembershipId) {\n throw new Error(\"Private session create capability was not returned\");\n }\n return { capabilityId, ownerMembershipId };\n}\n\n/** Open the exact transaction-local capability for one private child insert. */\nexport async function openPrivateChildSessionCreateCapability(\n db: Database,\n input: {\n accountId: string;\n workspaceId: string;\n sessionId: string;\n parentSessionId: string;\n actorTurnId: string;\n actorAttemptId: string;\n actorExecutionGeneration: number;\n },\n): Promise<{ capabilityId: string; ownerMembershipId: string; ownerSubjectId: string }> {\n const rows = await rawRows<{\n capabilityId: string;\n ownerMembershipId: string;\n ownerSubjectId: string;\n }>(\n db,\n sql`select\n capability_id as \"capabilityId\",\n owner_membership_id as \"ownerMembershipId\",\n owner_subject_id as \"ownerSubjectId\"\n from open_private_child_session_create_capability(\n ${input.accountId}::uuid,\n ${input.workspaceId}::uuid,\n ${input.sessionId}::uuid,\n ${input.parentSessionId}::uuid,\n ${input.actorTurnId}::uuid,\n ${input.actorAttemptId}::uuid,\n ${input.actorExecutionGeneration}::integer\n )`,\n );\n const capabilityId = rows[0]?.capabilityId;\n const ownerMembershipId = rows[0]?.ownerMembershipId;\n const ownerSubjectId = rows[0]?.ownerSubjectId;\n if (!capabilityId || !ownerMembershipId || !ownerSubjectId) {\n throw new Error(\"Private child session create capability was not returned\");\n }\n return { capabilityId, ownerMembershipId, ownerSubjectId };\n}\n\nexport async function closePrivateSessionCreateCapability(\n db: Database,\n capabilityId: string,\n): Promise<void> {\n await db.execute(sql`select close_private_session_create_capability(${capabilityId}::uuid)`);\n}\n\nasync function assertSessionTenancyProductActivated(\n db: Database,\n workspaceId: string,\n): Promise<void> {\n if (!(await sessionTenancyProductActivated(db, workspaceId))) {\n throw new SessionTenancyNotActivatedError();\n }\n}\n\nfunction mapSessionTenancyPersistenceError(\n error: unknown,\n options: { authorityEpochConflict: boolean },\n): never {\n const state = nestedPostgresSqlState(error);\n if (state === \"55P03\") {\n throw new SessionTenancyConflictError(\"not_quiescent\", nestedSessionTenancyBlocker(error), {\n cause: error,\n });\n }\n if (state === \"40001\" && options.authorityEpochConflict) {\n throw new SessionTenancyConflictError(\"authority_epoch\", null, { cause: error });\n }\n if (state === \"23505\") {\n throw new SessionTenancyConflictError(\"operation_reuse\", null, { cause: error });\n }\n if (state === \"55000\") {\n throw new SessionTenancyNotActivatedError({ cause: error });\n }\n if (state === \"42501\" || state === \"P0002\") {\n throw new SessionTenancyAccessError({ cause: error });\n }\n if (state === \"22023\") {\n throw new SessionTenancyInvalidRequestError({ cause: error });\n }\n throw error;\n}\n\nexport function canonicalSessionVisibilityTransitionHash(\n input: Pick<\n TransitionSessionVisibilityInput,\n \"sessionId\" | \"targetVisibility\" | \"expectedAuthorityEpoch\"\n >,\n): string {\n return createHash(\"sha256\")\n .update(\n JSON.stringify({\n version: 1,\n sessionId: input.sessionId,\n targetVisibility: input.targetVisibility,\n expectedAuthorityEpoch: input.expectedAuthorityEpoch,\n }),\n )\n .digest(\"hex\");\n}\n\nexport function canonicalSessionForkHash(\n input: Pick<\n ForkSessionContentInput,\n | \"sourceSessionId\"\n | \"destinationWorkspaceId\"\n | \"destinationVisibility\"\n | \"workspaceSharedAcknowledged\"\n >,\n): string {\n const legacyCompatiblePrivateRequest =\n input.destinationVisibility === \"user_private\" && !input.workspaceSharedAcknowledged;\n return createHash(\"sha256\")\n .update(\n JSON.stringify(\n legacyCompatiblePrivateRequest\n ? {\n version: 1,\n sourceSessionId: input.sourceSessionId,\n destinationWorkspaceId: input.destinationWorkspaceId,\n destinationVisibility: input.destinationVisibility,\n }\n : {\n version: 2,\n sourceSessionId: input.sourceSessionId,\n destinationWorkspaceId: input.destinationWorkspaceId,\n destinationVisibility: input.destinationVisibility,\n workspaceSharedAcknowledged: input.workspaceSharedAcknowledged,\n },\n ),\n )\n .digest(\"hex\");\n}\n\nexport async function transitionSessionVisibility(\n db: Database,\n input: TransitionSessionVisibilityInput,\n): Promise<TransitionSessionVisibilityResult> {\n if (!Number.isSafeInteger(input.expectedAuthorityEpoch) || input.expectedAuthorityEpoch < 1) {\n throw new Error(\"expectedAuthorityEpoch must be a positive safe integer\");\n }\n if (!input.operationKey.trim()) throw new Error(\"operationKey must not be empty\");\n const requestHash = canonicalSessionVisibilityTransitionHash(input);\n const { accountId } = await rlsContextForWorkspace(db, input.workspaceId);\n await assertSessionTenancyProductActivated(db, input.workspaceId);\n try {\n return await withWorkspaceSubjectSessionActivityRls(\n db,\n input.workspaceId,\n input.actorSubjectId,\n async (scopedDb) => {\n const rows = await rawRows<{\n operationId: string;\n eventId: string | null;\n eventSequence: number | null;\n visibility: SessionTenancyVisibility;\n authorityEpoch: number;\n ownerOrganizationMembershipId: string | null;\n changed: boolean;\n replay: boolean;\n interruptedAttemptCount: number;\n cancelledTurnCount: number;\n cancelledUpdateCount: number;\n pausedGoalCount: number;\n revokedGrantCount: number;\n }>(\n scopedDb,\n sql`select\n operation_id as \"operationId\",\n event_id as \"eventId\",\n event_sequence as \"eventSequence\",\n visibility,\n authority_epoch as \"authorityEpoch\",\n owner_organization_membership_id as \"ownerOrganizationMembershipId\",\n changed,\n replay,\n interrupted_attempt_count as \"interruptedAttemptCount\",\n cancelled_turn_count as \"cancelledTurnCount\",\n cancelled_update_count as \"cancelledUpdateCount\",\n paused_goal_count as \"pausedGoalCount\",\n revoked_grant_count as \"revokedGrantCount\"\n from transition_session_visibility(\n ${accountId}::uuid,\n ${input.workspaceId}::uuid,\n ${input.sessionId}::uuid,\n ${input.actorSubjectId},\n ${input.targetVisibility},\n ${input.expectedAuthorityEpoch},\n ${input.operationKey},\n ${requestHash},\n ${SESSION_TENANCY_ACTIVATION_VERSION}\n )`,\n );\n const result = rows[0];\n if (!result) throw new Error(\"Session visibility transition returned no result\");\n return result;\n },\n undefined,\n \"none\",\n );\n } catch (error) {\n mapSessionTenancyPersistenceError(error, { authorityEpochConflict: true });\n }\n}\n\nexport async function forkSessionContent(\n db: Database,\n input: ForkSessionContentInput,\n): Promise<ForkSessionContentResult> {\n if (!input.operationKey.trim()) throw new Error(\"operationKey must not be empty\");\n if (input.destinationWorkspaceId !== input.sourceWorkspaceId) {\n throw new Error(\"The first session fork contract is same-workspace only\");\n }\n const { accountId } = await rlsContextForWorkspace(db, input.sourceWorkspaceId);\n await assertSessionTenancyProductActivated(db, input.sourceWorkspaceId);\n const requestHash = canonicalSessionForkHash(input);\n try {\n return await withWorkspaceSubjectRls(\n db,\n input.sourceWorkspaceId,\n input.actorSubjectId,\n async (scopedDb) => {\n const rows = await rawRows<ForkSessionContentResult>(\n scopedDb,\n sql`select\n operation_id as \"operationId\",\n event_id as \"eventId\",\n event_sequence as \"eventSequence\",\n session_id as \"sessionId\",\n workspace_id as \"workspaceId\",\n visibility,\n authority_epoch as \"authorityEpoch\",\n copied_history_item_count as \"copiedHistoryItemCount\",\n replay\n from fork_session_content(\n ${accountId}::uuid,\n ${input.sourceWorkspaceId}::uuid,\n ${input.sourceSessionId}::uuid,\n ${input.actorSubjectId},\n ${input.destinationWorkspaceId}::uuid,\n ${input.destinationVisibility},\n ${input.workspaceSharedAcknowledged},\n ${input.operationKey},\n ${requestHash},\n ${SESSION_TENANCY_ACTIVATION_VERSION}\n )`,\n );\n const result = rows[0];\n if (!result) throw new Error(\"Session fork returned no result\");\n return result;\n },\n undefined,\n \"none\",\n );\n } catch (error) {\n // A private destination inside a shared workspace carries the same\n // organization owner/admin product decision the create path enforces\n // (migration 0323), and the fork routine raises the same 55000. Surface it\n // as the not-activated product state rather than an opaque database error.\n if (nestedPostgresSqlState(error) === \"55000\") {\n throw new SessionTenancyNotActivatedError({ cause: error });\n }\n mapSessionTenancyPersistenceError(error, { authorityEpochConflict: false });\n }\n}\n\n/**\n * Recover one exact committed fork before mutable source-session authorization.\n *\n * The database capability requires the authenticated actor's active workspace\n * authority and matches the complete actor/workspace/source/key/request-hash\n * tuple. A fresh key returns null; changed intent raises the ordinary tenancy\n * idempotency conflict. This is receipt recovery, not session discovery.\n */\nexport async function replayAppliedSessionFork(\n db: Database,\n input: ForkSessionContentInput,\n): Promise<ForkSessionContentResult | null> {\n if (!input.operationKey.trim()) throw new Error(\"operationKey must not be empty\");\n if (input.destinationWorkspaceId !== input.sourceWorkspaceId) {\n throw new Error(\"The first session fork contract is same-workspace only\");\n }\n const { accountId } = await rlsContextForWorkspace(db, input.sourceWorkspaceId);\n await assertSessionTenancyProductActivated(db, input.sourceWorkspaceId);\n const requestHash = canonicalSessionForkHash(input);\n try {\n return await withWorkspaceSubjectRls(\n db,\n input.sourceWorkspaceId,\n input.actorSubjectId,\n async (scopedDb) => {\n const rows = await rawRows<ForkSessionContentResult>(\n scopedDb,\n sql`select\n operation_id as \"operationId\",\n event_id as \"eventId\",\n event_sequence as \"eventSequence\",\n session_id as \"sessionId\",\n workspace_id as \"workspaceId\",\n visibility,\n authority_epoch as \"authorityEpoch\",\n copied_history_item_count as \"copiedHistoryItemCount\",\n replay\n from replay_applied_session_fork(\n ${accountId}::uuid,\n ${input.sourceWorkspaceId}::uuid,\n ${input.sourceSessionId}::uuid,\n ${input.actorSubjectId},\n ${input.destinationWorkspaceId}::uuid,\n ${input.destinationVisibility},\n ${input.workspaceSharedAcknowledged},\n ${input.operationKey},\n ${requestHash},\n ${SESSION_TENANCY_ACTIVATION_VERSION}\n )`,\n );\n return rows[0] ?? null;\n },\n );\n } catch (error) {\n mapSessionTenancyPersistenceError(error, { authorityEpochConflict: false });\n }\n}\n"],"mappings":";;;;;;;;;;AAAA,SAAS,kBAAkB;AAC3B,SAAS,WAAW;AACpB;AAAA,EACE,yBAAyB;AAAA,OAEpB;AAWP,IAAM,qCAAqC;AAEpC,IAAM,8BAAN,cAA0C,MAAM;AAAA,EAErD,YACW,QACA,UAAwC,MACjD,SACA;AACA;AAAA,MACE,WAAW,kBACP,kEACA,WAAW,oBACT,6DACA;AAAA,MACN;AAAA,IACF;AAXS;AACA;AAAA,EAWX;AAAA,EAdS,OAAO;AAelB;AAEO,IAAM,kCAAN,cAA8C,MAAM;AAAA,EAChD,OAAO;AAAA,EAChB,YAAY,SAAwB;AAClC,UAAM,0EAA0E,OAAO;AAAA,EACzF;AACF;AAEO,IAAM,4BAAN,cAAwC,MAAM;AAAA,EAC1C,OAAO;AAAA,EAChB,YAAY,SAAwB;AAClC,UAAM,yCAAyC,OAAO;AAAA,EACxD;AACF;AAEO,IAAM,oCAAN,cAAgD,MAAM;AAAA,EAClD,OAAO;AAAA,EAChB,YAAY,SAAwB;AAClC,UAAM,sCAAsC,OAAO;AAAA,EACrD;AACF;AAEA,SAAS,SAAS,OAAkD;AAClE,SAAO,QAAQ,SAAS,OAAO,UAAU,QAAQ;AACnD;AAGO,SAAS,4BAA4B,OAA8C;AACxF,QAAM,QAAmB,CAAC,KAAK;AAC/B,QAAM,OAAO,oBAAI,IAAa;AAC9B,SAAO,MAAM,SAAS,KAAK,KAAK,OAAO,IAAI;AACzC,UAAM,UAAU,MAAM,MAAM;AAC5B,QAAI,CAAC,SAAS,OAAO,KAAK,KAAK,IAAI,OAAO,EAAG;AAC7C,SAAK,IAAI,OAAO;AAChB,eAAW,OAAO,CAAC,UAAU,eAAe,GAAY;AACtD,YAAM,SAAS,4BAA4B,UAAU,QAAQ,GAAG,CAAC;AACjE,UAAI,OAAO,QAAS,QAAO,OAAO;AAAA,IACpC;AACA,eAAW,OAAO,CAAC,SAAS,YAAY,eAAe,SAAS,QAAQ,GAAY;AAClF,YAAM,SAAS,QAAQ,GAAG;AAC1B,UAAI,MAAM,QAAQ,MAAM,EAAG,OAAM,KAAK,GAAG,MAAM;AAAA,eACtC,WAAW,OAAW,OAAM,KAAK,MAAM;AAAA,IAClD;AAAA,EACF;AACA,SAAO;AACT;AAyDA,eAAsB,+BACpB,IACA,aACkB;AAClB,QAAM,EAAE,UAAU,IAAI,MAAM,uBAAuB,IAAI,WAAW;AAClE,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AACjE,UAAM,OAAO,MAAM;AAAA,MACjB;AAAA,MACA;AAAA,UACI,SAAS;AAAA,UACT,kCAAkC;AAAA;AAAA,IAExC;AACA,WAAO,KAAK,CAAC,GAAG,cAAc;AAAA,EAChC,CAAC;AACH;AAEA,eAAsB,8BACpB,IACA,OACqC;AACrC,QAAM,EAAE,UAAU,IAAI,MAAM,uBAAuB,IAAI,MAAM,WAAW;AACxE,SAAO,MAAM;AAAA,IACX;AAAA,IACA,MAAM;AAAA,IACN,MAAM;AAAA,IACN,OAAO,aAAa;AAClB,YAAM,OAAO,MAAM;AAAA,QAKjB;AAAA,QACA;AAAA;AAAA;AAAA;AAAA;AAAA,YAKI,SAAS;AAAA,YACT,MAAM,WAAW;AAAA,YACjB,MAAM,cAAc;AAAA;AAAA,MAE1B;AACA,YAAM,SAAS,KAAK,CAAC;AACrB,UAAI,CAAC,OAAQ,OAAM,IAAI,0BAA0B;AACjD,aAAO;AAAA,IACT;AAAA,EACF;AACF;AAGA,eAAsB,mCACpB,IACA,OAC8D;AAC9D,MAAI;AACJ,MAAI;AACF,WAAO,MAAM;AAAA,MACX;AAAA,MACA;AAAA;AAAA;AAAA;AAAA,UAII,MAAM,SAAS;AAAA,UACf,MAAM,WAAW;AAAA,UACjB,MAAM,SAAS;AAAA,UACf,MAAM,cAAc;AAAA;AAAA,IAE1B;AAAA,EACF,SAAS,OAAO;AAId,QAAI,uBAAuB,KAAK,MAAM,SAAS;AAC7C,YAAM,IAAI,gCAAgC,EAAE,OAAO,MAAM,CAAC;AAAA,IAC5D;AACA,UAAM;AAAA,EACR;AACA,QAAM,eAAe,KAAK,CAAC,GAAG;AAC9B,QAAM,oBAAoB,KAAK,CAAC,GAAG;AACnC,MAAI,CAAC,gBAAgB,CAAC,mBAAmB;AACvC,UAAM,IAAI,MAAM,oDAAoD;AAAA,EACtE;AACA,SAAO,EAAE,cAAc,kBAAkB;AAC3C;AAGA,eAAsB,wCACpB,IACA,OASsF;AACtF,QAAM,OAAO,MAAM;AAAA,IAKjB;AAAA,IACA;AAAA;AAAA;AAAA;AAAA;AAAA,QAKI,MAAM,SAAS;AAAA,QACf,MAAM,WAAW;AAAA,QACjB,MAAM,SAAS;AAAA,QACf,MAAM,eAAe;AAAA,QACrB,MAAM,WAAW;AAAA,QACjB,MAAM,cAAc;AAAA,QACpB,MAAM,wBAAwB;AAAA;AAAA,EAEpC;AACA,QAAM,eAAe,KAAK,CAAC,GAAG;AAC9B,QAAM,oBAAoB,KAAK,CAAC,GAAG;AACnC,QAAM,iBAAiB,KAAK,CAAC,GAAG;AAChC,MAAI,CAAC,gBAAgB,CAAC,qBAAqB,CAAC,gBAAgB;AAC1D,UAAM,IAAI,MAAM,0DAA0D;AAAA,EAC5E;AACA,SAAO,EAAE,cAAc,mBAAmB,eAAe;AAC3D;AAEA,eAAsB,oCACpB,IACA,cACe;AACf,QAAM,GAAG,QAAQ,qDAAqD,YAAY,SAAS;AAC7F;AAEA,eAAe,qCACb,IACA,aACe;AACf,MAAI,CAAE,MAAM,+BAA+B,IAAI,WAAW,GAAI;AAC5D,UAAM,IAAI,gCAAgC;AAAA,EAC5C;AACF;AAEA,SAAS,kCACP,OACA,SACO;AACP,QAAM,QAAQ,uBAAuB,KAAK;AAC1C,MAAI,UAAU,SAAS;AACrB,UAAM,IAAI,4BAA4B,iBAAiB,4BAA4B,KAAK,GAAG;AAAA,MACzF,OAAO;AAAA,IACT,CAAC;AAAA,EACH;AACA,MAAI,UAAU,WAAW,QAAQ,wBAAwB;AACvD,UAAM,IAAI,4BAA4B,mBAAmB,MAAM,EAAE,OAAO,MAAM,CAAC;AAAA,EACjF;AACA,MAAI,UAAU,SAAS;AACrB,UAAM,IAAI,4BAA4B,mBAAmB,MAAM,EAAE,OAAO,MAAM,CAAC;AAAA,EACjF;AACA,MAAI,UAAU,SAAS;AACrB,UAAM,IAAI,gCAAgC,EAAE,OAAO,MAAM,CAAC;AAAA,EAC5D;AACA,MAAI,UAAU,WAAW,UAAU,SAAS;AAC1C,UAAM,IAAI,0BAA0B,EAAE,OAAO,MAAM,CAAC;AAAA,EACtD;AACA,MAAI,UAAU,SAAS;AACrB,UAAM,IAAI,kCAAkC,EAAE,OAAO,MAAM,CAAC;AAAA,EAC9D;AACA,QAAM;AACR;AAEO,SAAS,yCACd,OAIQ;AACR,SAAO,WAAW,QAAQ,EACvB;AAAA,IACC,KAAK,UAAU;AAAA,MACb,SAAS;AAAA,MACT,WAAW,MAAM;AAAA,MACjB,kBAAkB,MAAM;AAAA,MACxB,wBAAwB,MAAM;AAAA,IAChC,CAAC;AAAA,EACH,EACC,OAAO,KAAK;AACjB;AAEO,SAAS,yBACd,OAOQ;AACR,QAAM,iCACJ,MAAM,0BAA0B,kBAAkB,CAAC,MAAM;AAC3D,SAAO,WAAW,QAAQ,EACvB;AAAA,IACC,KAAK;AAAA,MACH,iCACI;AAAA,QACE,SAAS;AAAA,QACT,iBAAiB,MAAM;AAAA,QACvB,wBAAwB,MAAM;AAAA,QAC9B,uBAAuB,MAAM;AAAA,MAC/B,IACA;AAAA,QACE,SAAS;AAAA,QACT,iBAAiB,MAAM;AAAA,QACvB,wBAAwB,MAAM;AAAA,QAC9B,uBAAuB,MAAM;AAAA,QAC7B,6BAA6B,MAAM;AAAA,MACrC;AAAA,IACN;AAAA,EACF,EACC,OAAO,KAAK;AACjB;AAEA,eAAsB,4BACpB,IACA,OAC4C;AAC5C,MAAI,CAAC,OAAO,cAAc,MAAM,sBAAsB,KAAK,MAAM,yBAAyB,GAAG;AAC3F,UAAM,IAAI,MAAM,wDAAwD;AAAA,EAC1E;AACA,MAAI,CAAC,MAAM,aAAa,KAAK,EAAG,OAAM,IAAI,MAAM,gCAAgC;AAChF,QAAM,cAAc,yCAAyC,KAAK;AAClE,QAAM,EAAE,UAAU,IAAI,MAAM,uBAAuB,IAAI,MAAM,WAAW;AACxE,QAAM,qCAAqC,IAAI,MAAM,WAAW;AAChE,MAAI;AACF,WAAO,MAAM;AAAA,MACX;AAAA,MACA,MAAM;AAAA,MACN,MAAM;AAAA,MACN,OAAO,aAAa;AAClB,cAAM,OAAO,MAAM;AAAA,UAejB;AAAA,UACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,YAeE,SAAS;AAAA,YACT,MAAM,WAAW;AAAA,YACjB,MAAM,SAAS;AAAA,YACf,MAAM,cAAc;AAAA,YACpB,MAAM,gBAAgB;AAAA,YACtB,MAAM,sBAAsB;AAAA,YAC5B,MAAM,YAAY;AAAA,YAClB,WAAW;AAAA,YACX,kCAAkC;AAAA;AAAA,QAEtC;AACA,cAAM,SAAS,KAAK,CAAC;AACrB,YAAI,CAAC,OAAQ,OAAM,IAAI,MAAM,kDAAkD;AAC/E,eAAO;AAAA,MACT;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF,SAAS,OAAO;AACd,sCAAkC,OAAO,EAAE,wBAAwB,KAAK,CAAC;AAAA,EAC3E;AACF;AAEA,eAAsB,mBACpB,IACA,OACmC;AACnC,MAAI,CAAC,MAAM,aAAa,KAAK,EAAG,OAAM,IAAI,MAAM,gCAAgC;AAChF,MAAI,MAAM,2BAA2B,MAAM,mBAAmB;AAC5D,UAAM,IAAI,MAAM,wDAAwD;AAAA,EAC1E;AACA,QAAM,EAAE,UAAU,IAAI,MAAM,uBAAuB,IAAI,MAAM,iBAAiB;AAC9E,QAAM,qCAAqC,IAAI,MAAM,iBAAiB;AACtE,QAAM,cAAc,yBAAyB,KAAK;AAClD,MAAI;AACF,WAAO,MAAM;AAAA,MACX;AAAA,MACA,MAAM;AAAA,MACN,MAAM;AAAA,MACN,OAAO,aAAa;AAClB,cAAM,OAAO,MAAM;AAAA,UACjB;AAAA,UACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,YAWE,SAAS;AAAA,YACT,MAAM,iBAAiB;AAAA,YACvB,MAAM,eAAe;AAAA,YACrB,MAAM,cAAc;AAAA,YACpB,MAAM,sBAAsB;AAAA,YAC5B,MAAM,qBAAqB;AAAA,YAC3B,MAAM,2BAA2B;AAAA,YACjC,MAAM,YAAY;AAAA,YAClB,WAAW;AAAA,YACX,kCAAkC;AAAA;AAAA,QAEtC;AACA,cAAM,SAAS,KAAK,CAAC;AACrB,YAAI,CAAC,OAAQ,OAAM,IAAI,MAAM,iCAAiC;AAC9D,eAAO;AAAA,MACT;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF,SAAS,OAAO;AAKd,QAAI,uBAAuB,KAAK,MAAM,SAAS;AAC7C,YAAM,IAAI,gCAAgC,EAAE,OAAO,MAAM,CAAC;AAAA,IAC5D;AACA,sCAAkC,OAAO,EAAE,wBAAwB,MAAM,CAAC;AAAA,EAC5E;AACF;AAUA,eAAsB,yBACpB,IACA,OAC0C;AAC1C,MAAI,CAAC,MAAM,aAAa,KAAK,EAAG,OAAM,IAAI,MAAM,gCAAgC;AAChF,MAAI,MAAM,2BAA2B,MAAM,mBAAmB;AAC5D,UAAM,IAAI,MAAM,wDAAwD;AAAA,EAC1E;AACA,QAAM,EAAE,UAAU,IAAI,MAAM,uBAAuB,IAAI,MAAM,iBAAiB;AAC9E,QAAM,qCAAqC,IAAI,MAAM,iBAAiB;AACtE,QAAM,cAAc,yBAAyB,KAAK;AAClD,MAAI;AACF,WAAO,MAAM;AAAA,MACX;AAAA,MACA,MAAM;AAAA,MACN,MAAM;AAAA,MACN,OAAO,aAAa;AAClB,cAAM,OAAO,MAAM;AAAA,UACjB;AAAA,UACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,YAWE,SAAS;AAAA,YACT,MAAM,iBAAiB;AAAA,YACvB,MAAM,eAAe;AAAA,YACrB,MAAM,cAAc;AAAA,YACpB,MAAM,sBAAsB;AAAA,YAC5B,MAAM,qBAAqB;AAAA,YAC3B,MAAM,2BAA2B;AAAA,YACjC,MAAM,YAAY;AAAA,YAClB,WAAW;AAAA,YACX,kCAAkC;AAAA;AAAA,QAEtC;AACA,eAAO,KAAK,CAAC,KAAK;AAAA,MACpB;AAAA,IACF;AAAA,EACF,SAAS,OAAO;AACd,sCAAkC,OAAO,EAAE,wBAAwB,MAAM,CAAC;AAAA,EAC5E;AACF;","names":[]}