@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
@@ -0,0 +1,317 @@
1
+ import { createHash } from "node:crypto";
2
+ import {
3
+ CanonicalHumanIdentityMutationResponse,
4
+ CanonicalHumanIdentityProjection,
5
+ type CanonicalHumanIdentityMutationOutcome,
6
+ type CanonicalHumanIdentityMutationResponse as CanonicalHumanIdentityMutationResponseType,
7
+ type CanonicalHumanIdentityProjection as CanonicalHumanIdentityProjectionType,
8
+ } from "@opengeni/contracts/canonical-human-identities";
9
+ import { sql } from "drizzle-orm";
10
+ import type { Database } from "./database";
11
+ import { rawRows } from "./database";
12
+ import { nestedPostgresSqlState } from "./persistence-errors";
13
+
14
+ export type CanonicalHumanSessionAuthority = {
15
+ identityId: string;
16
+ identityRevision: number;
17
+ authRevision: number;
18
+ identityStatus: "active" | "recovery_required" | "disputed" | "disabled";
19
+ };
20
+
21
+ export class CanonicalHumanIdentityConflictError extends Error {
22
+ readonly name = "CanonicalHumanIdentityConflictError";
23
+ readonly code = "CANONICAL_HUMAN_IDENTITY_CONFLICT";
24
+
25
+ constructor() {
26
+ super("The canonical human identity changed in another request");
27
+ }
28
+ }
29
+
30
+ export class CanonicalHumanIdentityOperationReuseError extends Error {
31
+ readonly name = "CanonicalHumanIdentityOperationReuseError";
32
+ readonly code = "CANONICAL_HUMAN_IDENTITY_OPERATION_REUSED";
33
+
34
+ constructor() {
35
+ super("The canonical human identity operation id was already used for another request");
36
+ }
37
+ }
38
+
39
+ export class CanonicalHumanIdentityNotFoundError extends Error {
40
+ readonly name = "CanonicalHumanIdentityNotFoundError";
41
+
42
+ constructor(message = "Canonical human identity was not found") {
43
+ super(message);
44
+ }
45
+ }
46
+
47
+ export class CanonicalHumanIdentityAuthorityError extends Error {
48
+ readonly name = "CanonicalHumanIdentityAuthorityError";
49
+ }
50
+
51
+ function deterministicOperationId(seed: string): string {
52
+ const bytes = createHash("sha256").update(seed, "utf8").digest().subarray(0, 16);
53
+ bytes[6] = (bytes[6]! & 0x0f) | 0x50;
54
+ bytes[8] = (bytes[8]! & 0x3f) | 0x80;
55
+ const hex = bytes.toString("hex");
56
+ return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
57
+ }
58
+
59
+ function projectionValue(value: unknown): unknown {
60
+ if (typeof value === "string") return JSON.parse(value);
61
+ return value;
62
+ }
63
+
64
+ function mapSqlError(error: unknown): never {
65
+ const state = nestedPostgresSqlState(error);
66
+ if (state === "40001") throw new CanonicalHumanIdentityConflictError();
67
+ if (state === "23505") throw new CanonicalHumanIdentityOperationReuseError();
68
+ if (state === "P0002") throw new CanonicalHumanIdentityNotFoundError();
69
+ if (state === "42501") {
70
+ throw new CanonicalHumanIdentityAuthorityError(
71
+ error instanceof Error ? error.message : "Canonical human identity authority denied",
72
+ );
73
+ }
74
+ throw error;
75
+ }
76
+
77
+ export async function ensureCanonicalHumanIdentity(
78
+ db: Database,
79
+ input: { authUserId: string; displayName: string },
80
+ ): Promise<CanonicalHumanSessionAuthority> {
81
+ try {
82
+ const [row] = await rawRows<{
83
+ identityId: string;
84
+ identityRevision: number | string;
85
+ authRevision: number | string;
86
+ identityStatus: CanonicalHumanSessionAuthority["identityStatus"];
87
+ }>(
88
+ db,
89
+ sql`
90
+ select
91
+ identity_id as "identityId",
92
+ identity_revision as "identityRevision",
93
+ auth_revision as "authRevision",
94
+ identity_status as "identityStatus"
95
+ from ensure_canonical_human_identity(${input.authUserId}, ${input.displayName})
96
+ `,
97
+ );
98
+ if (!row) throw new CanonicalHumanIdentityNotFoundError();
99
+ return {
100
+ identityId: row.identityId,
101
+ identityRevision: Number(row.identityRevision),
102
+ authRevision: Number(row.authRevision),
103
+ identityStatus: row.identityStatus,
104
+ };
105
+ } catch (error) {
106
+ mapSqlError(error);
107
+ }
108
+ }
109
+
110
+ export async function ensureCanonicalHumanIdentityForAuthUser(
111
+ db: Database,
112
+ authUserId: string,
113
+ ): Promise<CanonicalHumanSessionAuthority> {
114
+ const [user] = await rawRows<{ displayName: string }>(
115
+ db,
116
+ sql`
117
+ select coalesce(nullif(btrim(name), ''), email) as "displayName"
118
+ from auth_users
119
+ where id = ${authUserId}
120
+ limit 1
121
+ `,
122
+ );
123
+ if (!user) throw new CanonicalHumanIdentityNotFoundError("Authentication user was not found");
124
+ return await ensureCanonicalHumanIdentity(db, {
125
+ authUserId,
126
+ displayName: user.displayName,
127
+ });
128
+ }
129
+
130
+ export async function synchronizeCanonicalHumanLoginBindings(
131
+ db: Database,
132
+ authUserId: string,
133
+ ): Promise<CanonicalHumanSessionAuthority> {
134
+ let authority = await ensureCanonicalHumanIdentityForAuthUser(db, authUserId);
135
+ const accounts = await rawRows<{
136
+ id: string;
137
+ providerId: string;
138
+ providerAccountId: string;
139
+ }>(
140
+ db,
141
+ sql`
142
+ select
143
+ id,
144
+ lower(provider_id) as "providerId",
145
+ account_id as "providerAccountId"
146
+ from auth_identities
147
+ where user_id = ${authUserId}
148
+ order by created_at, id
149
+ `,
150
+ );
151
+
152
+ for (const account of accounts) {
153
+ for (let attempt = 0; attempt < 4; attempt += 1) {
154
+ const projection = await getCanonicalHumanIdentityProjection(db, authUserId);
155
+ if (projection.activeIdentity.status !== "active") {
156
+ return {
157
+ identityId: projection.activeIdentity.id,
158
+ identityRevision: projection.activeIdentity.identityRevision,
159
+ authRevision: projection.activeIdentity.authRevision,
160
+ identityStatus: projection.activeIdentity.status,
161
+ };
162
+ }
163
+ const existing = projection.loginBindings.find(
164
+ (binding) =>
165
+ binding.providerId === account.providerId &&
166
+ binding.providerAccountId === account.providerAccountId,
167
+ );
168
+ if (existing?.status === "active") {
169
+ authority = {
170
+ identityId: projection.activeIdentity.id,
171
+ identityRevision: projection.activeIdentity.identityRevision,
172
+ authRevision: projection.activeIdentity.authRevision,
173
+ identityStatus: projection.activeIdentity.status,
174
+ };
175
+ break;
176
+ }
177
+ try {
178
+ const result = await applyCanonicalHumanIdentityOperation(db, {
179
+ operationId: deterministicOperationId(
180
+ `canonical-human-account-link\n${account.id}\n${projection.activeIdentity.identityRevision}`,
181
+ ),
182
+ authUserId,
183
+ expectedIdentityRevision: projection.activeIdentity.identityRevision,
184
+ operationType: "link",
185
+ providerId: account.providerId,
186
+ providerAccountId: account.providerAccountId,
187
+ reason: "Synchronize verified authentication account",
188
+ });
189
+ authority = {
190
+ identityId: result.identity.activeIdentity.id,
191
+ identityRevision: result.identity.activeIdentity.identityRevision,
192
+ authRevision: result.identity.activeIdentity.authRevision,
193
+ identityStatus: result.identity.activeIdentity.status,
194
+ };
195
+ break;
196
+ } catch (error) {
197
+ if (error instanceof CanonicalHumanIdentityConflictError && attempt < 3) continue;
198
+ if (error instanceof CanonicalHumanIdentityAuthorityError) {
199
+ const currentProjection = await getCanonicalHumanIdentityProjection(db, authUserId);
200
+ if (currentProjection.activeIdentity.status !== "active") {
201
+ return {
202
+ identityId: currentProjection.activeIdentity.id,
203
+ identityRevision: currentProjection.activeIdentity.identityRevision,
204
+ authRevision: currentProjection.activeIdentity.authRevision,
205
+ identityStatus: currentProjection.activeIdentity.status,
206
+ };
207
+ }
208
+ }
209
+ throw error;
210
+ }
211
+ }
212
+ }
213
+ return authority;
214
+ }
215
+
216
+ export async function validateCanonicalHumanSession(
217
+ db: Database,
218
+ input: { authSessionId: string; authUserId: string; allowRecovery?: boolean },
219
+ ): Promise<boolean> {
220
+ try {
221
+ const [row] = await rawRows<{ valid: boolean }>(
222
+ db,
223
+ sql`
224
+ select validate_canonical_human_session(
225
+ ${input.authSessionId},
226
+ ${input.authUserId},
227
+ ${input.allowRecovery ?? false}
228
+ ) as valid
229
+ `,
230
+ );
231
+ return row?.valid === true;
232
+ } catch (error) {
233
+ mapSqlError(error);
234
+ }
235
+ }
236
+
237
+ export async function getCanonicalHumanIdentityProjection(
238
+ db: Database,
239
+ authUserId: string,
240
+ ): Promise<CanonicalHumanIdentityProjectionType> {
241
+ try {
242
+ const [row] = await rawRows<{ projection: unknown }>(
243
+ db,
244
+ sql`
245
+ select get_canonical_human_identity_projection(${authUserId}) as projection
246
+ `,
247
+ );
248
+ if (row?.projection === null || row?.projection === undefined) {
249
+ throw new CanonicalHumanIdentityNotFoundError();
250
+ }
251
+ return CanonicalHumanIdentityProjection.parse(projectionValue(row.projection));
252
+ } catch (error) {
253
+ if (error instanceof CanonicalHumanIdentityNotFoundError) throw error;
254
+ mapSqlError(error);
255
+ }
256
+ }
257
+
258
+ export type ApplyCanonicalHumanIdentityOperationInput = {
259
+ operationId: string;
260
+ authUserId: string;
261
+ expectedIdentityRevision: number;
262
+ operationType: "link" | "unlink" | "begin_recovery" | "recover";
263
+ bindingId?: string | null;
264
+ providerId?: string | null;
265
+ providerAccountId?: string | null;
266
+ reason: string;
267
+ };
268
+
269
+ export async function applyCanonicalHumanIdentityOperation(
270
+ db: Database,
271
+ input: ApplyCanonicalHumanIdentityOperationInput,
272
+ ): Promise<CanonicalHumanIdentityMutationResponseType> {
273
+ try {
274
+ const [row] = await rawRows<{
275
+ outcome: CanonicalHumanIdentityMutationOutcome;
276
+ identityId: string;
277
+ identityRevision: number | string;
278
+ authRevision: number | string;
279
+ }>(
280
+ db,
281
+ sql`
282
+ select
283
+ outcome,
284
+ identity_id as "identityId",
285
+ identity_revision as "identityRevision",
286
+ auth_revision as "authRevision"
287
+ from apply_canonical_human_identity_operation(
288
+ ${input.operationId},
289
+ ${input.authUserId},
290
+ ${input.expectedIdentityRevision},
291
+ ${input.operationType},
292
+ ${input.bindingId ?? null},
293
+ ${input.providerId ?? null},
294
+ ${input.providerAccountId ?? null},
295
+ ${input.reason}
296
+ )
297
+ `,
298
+ );
299
+ if (!row) throw new CanonicalHumanIdentityNotFoundError();
300
+ const identity = await getCanonicalHumanIdentityProjection(db, input.authUserId);
301
+ return CanonicalHumanIdentityMutationResponse.parse({
302
+ outcome: row.outcome,
303
+ operationId: input.operationId,
304
+ identity,
305
+ });
306
+ } catch (error) {
307
+ if (
308
+ error instanceof CanonicalHumanIdentityConflictError ||
309
+ error instanceof CanonicalHumanIdentityOperationReuseError ||
310
+ error instanceof CanonicalHumanIdentityNotFoundError ||
311
+ error instanceof CanonicalHumanIdentityAuthorityError
312
+ ) {
313
+ throw error;
314
+ }
315
+ mapSqlError(error);
316
+ }
317
+ }