@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
@@ -1,11 +1,13 @@
1
1
  import {
2
2
  CreateOrganizationResponse,
3
+ ListOrganizationAdministrationMembersResponse,
3
4
  ListOrganizationInvitationsResponse,
4
5
  ListOrganizationInvitationsPageResponse,
5
6
  ListOrganizationMembersResponse,
6
7
  ListSelfOrganizationMembershipsResponse,
7
8
  OrganizationInvitation,
8
9
  OrganizationAdministrationOverview,
10
+ OrganizationWorkspaceAccess,
9
11
  OrganizationPrivateSessionSettings,
10
12
  OrganizationMember,
11
13
  OrganizationRetentionDeletionClaim,
@@ -15,7 +17,9 @@ import {
15
17
  OrganizationRetentionDeletionResult,
16
18
  OrganizationRetentionPolicy,
17
19
  OrganizationSummary,
20
+ RevokeOrganizationWorkspaceMemberResponse,
18
21
  type CreateOrganizationResponse as CreateOrganizationResponseType,
22
+ type OrganizationAdministrationMember as OrganizationAdministrationMemberType,
19
23
  type OrganizationAdministrationOverview as OrganizationAdministrationOverviewType,
20
24
  type OrganizationInvitation as OrganizationInvitationType,
21
25
  type OrganizationMember as OrganizationMemberType,
@@ -28,6 +32,9 @@ import {
28
32
  type OrganizationRetentionDeletionResult as OrganizationRetentionDeletionResultType,
29
33
  type OrganizationRetentionPolicy as OrganizationRetentionPolicyType,
30
34
  type OrganizationSummary as OrganizationSummaryType,
35
+ type OrganizationWorkspaceAccess as OrganizationWorkspaceAccessType,
36
+ type PutOrganizationWorkspaceMemberRequest,
37
+ type RevokeOrganizationWorkspaceMemberResponse as RevokeOrganizationWorkspaceMemberResponseType,
31
38
  type UpdateOrganizationMemberRequest,
32
39
  } from "@opengeni/contracts";
33
40
  import { and, eq, sql } from "drizzle-orm";
@@ -317,6 +324,7 @@ export async function removeWorkspaceMember(
317
324
  actorSubjectId: string;
318
325
  targetSubjectId: string;
319
326
  requireOrganizationSharedWorkspaceAdministration?: boolean;
327
+ operationId?: string;
320
328
  },
321
329
  ): Promise<boolean> {
322
330
  const command = {
@@ -325,7 +333,7 @@ export async function removeWorkspaceMember(
325
333
  workspaceId: input.workspaceId,
326
334
  actorSubjectId: input.actorSubjectId,
327
335
  targetSubjectId: input.targetSubjectId,
328
- operationId: crypto.randomUUID(),
336
+ operationId: input.operationId ?? crypto.randomUUID(),
329
337
  };
330
338
  return await db.transaction(async (tx) => {
331
339
  const txDb = tx as unknown as Database;
@@ -409,6 +417,201 @@ export async function removeWorkspaceMember(
409
417
  });
410
418
  }
411
419
 
420
+ type OrganizationWorkspaceCommandResult = {
421
+ workspaceId: string;
422
+ organizationMembershipId?: string;
423
+ workspaceMembershipId?: string;
424
+ updatedAt: string;
425
+ replay: boolean;
426
+ };
427
+
428
+ async function runOrganizationWorkspaceCommand(
429
+ db: Database,
430
+ command: Record<string, unknown> & {
431
+ organizationId: string;
432
+ actorSubjectId: string;
433
+ },
434
+ ): Promise<OrganizationWorkspaceCommandResult> {
435
+ return await withRlsContext(
436
+ db,
437
+ { accountId: command.organizationId, workspaceId: null },
438
+ async (scopedDb) => {
439
+ await setSubjectRlsContext(scopedDb, command.actorSubjectId);
440
+ const [row] = await rawRows<{ result: OrganizationWorkspaceCommandResult }>(
441
+ scopedDb,
442
+ sql`select organization_workspace_command(${JSON.stringify(command)}::jsonb) as result`,
443
+ );
444
+ if (!row) throw new Error("Organization workspace command returned no result");
445
+ return row.result;
446
+ },
447
+ );
448
+ }
449
+
450
+ export async function createOrganizationWorkspace(
451
+ db: Database,
452
+ input: {
453
+ organizationId: string;
454
+ actorSubjectId: string;
455
+ name: string;
456
+ operationId: string;
457
+ },
458
+ ): Promise<OrganizationWorkspaceAccessType> {
459
+ const command = await runOrganizationWorkspaceCommand(db, { action: "create", ...input });
460
+ const overview = await getOrganizationAdministrationOverview(db, input);
461
+ const workspace = overview.workspaces.find((candidate) => candidate.id === command.workspaceId);
462
+ if (!workspace) throw new Error("Created organization workspace is missing from its overview");
463
+ return OrganizationWorkspaceAccess.parse(workspace);
464
+ }
465
+
466
+ export async function updateOrganizationWorkspace(
467
+ db: Database,
468
+ input: {
469
+ organizationId: string;
470
+ actorSubjectId: string;
471
+ workspaceId: string;
472
+ name: string;
473
+ expectedUpdatedAt: string;
474
+ operationId: string;
475
+ },
476
+ ): Promise<OrganizationWorkspaceAccessType> {
477
+ await runOrganizationWorkspaceCommand(db, { action: "rename", ...input });
478
+ const overview = await getOrganizationAdministrationOverview(db, input);
479
+ const workspace = overview.workspaces.find((candidate) => candidate.id === input.workspaceId);
480
+ if (!workspace) throw new Error("Renamed organization workspace is missing from its overview");
481
+ return OrganizationWorkspaceAccess.parse(workspace);
482
+ }
483
+
484
+ export async function putOrganizationWorkspaceMember(
485
+ db: Database,
486
+ input: {
487
+ organizationId: string;
488
+ actorSubjectId: string;
489
+ workspaceId: string;
490
+ targetOrganizationMembershipId: string;
491
+ access: PutOrganizationWorkspaceMemberRequest;
492
+ },
493
+ ) {
494
+ const result = await runOrganizationWorkspaceCommand(db, {
495
+ action: "grant",
496
+ organizationId: input.organizationId,
497
+ actorSubjectId: input.actorSubjectId,
498
+ workspaceId: input.workspaceId,
499
+ targetOrganizationMembershipId: input.targetOrganizationMembershipId,
500
+ ...input.access,
501
+ });
502
+ const overview = await getOrganizationAdministrationOverview(db, input);
503
+ const member = overview.workspaces
504
+ .find((candidate) => candidate.id === input.workspaceId)
505
+ ?.members.find((candidate) => candidate.membershipId === result.workspaceMembershipId);
506
+ if (!member) throw new Error("Organization workspace member is missing from its overview");
507
+ return member;
508
+ }
509
+
510
+ /**
511
+ * Revoke one managed human's shared-workspace access. The existing fenced
512
+ * prepare/settle/removal protocol remains the teardown authority. This outer
513
+ * transaction enters the canonical organization -> session-tenancy ->
514
+ * personal-state prefix before any row lock, then adds caller-owned
515
+ * idempotency, CAS, and immutable organization audit evidence.
516
+ */
517
+ export async function revokeOrganizationWorkspaceMember(
518
+ db: Database,
519
+ input: {
520
+ organizationId: string;
521
+ actorSubjectId: string;
522
+ workspaceId: string;
523
+ targetOrganizationMembershipId: string;
524
+ expectedUpdatedAt: string;
525
+ operationId: string;
526
+ },
527
+ ): Promise<RevokeOrganizationWorkspaceMemberResponseType> {
528
+ return await db.transaction(async (tx) => {
529
+ const txDb = tx as unknown as Database;
530
+ await txDb.execute(
531
+ sql`select pg_advisory_xact_lock(hashtextextended(
532
+ ${`organization-membership:${input.organizationId}`}, 0
533
+ ))`,
534
+ );
535
+ const targetSubjectId = await withRlsContext(
536
+ txDb,
537
+ { accountId: input.organizationId, workspaceId: null },
538
+ async (scopedDb) => {
539
+ await setSubjectRlsContext(scopedDb, input.actorSubjectId);
540
+ const [row] = await rawRows<{ subject_id: string }>(
541
+ scopedDb,
542
+ sql`select resolve_organization_workspace_removal_subject(
543
+ ${input.organizationId}::uuid,
544
+ ${input.actorSubjectId},
545
+ ${input.targetOrganizationMembershipId}::uuid
546
+ ) as subject_id`,
547
+ );
548
+ if (!row?.subject_id) throw new Error("Organization member subject resolution failed");
549
+ return row.subject_id;
550
+ },
551
+ );
552
+ await txDb.execute(
553
+ sql`select pg_advisory_xact_lock_shared(hashtextextended(
554
+ ${`session-tenancy:${input.workspaceId}`}, 0
555
+ ))`,
556
+ );
557
+ await txDb.execute(
558
+ sql`select pg_advisory_xact_lock(hashtextextended(
559
+ ${`session-personal-state:${input.workspaceId}:${targetSubjectId}`}, 0
560
+ ))`,
561
+ );
562
+ const command = { action: "revoke", ...input, targetSubjectId };
563
+ const prepared = await withRlsContext(
564
+ txDb,
565
+ { accountId: input.organizationId, workspaceId: null },
566
+ async (scopedDb) => {
567
+ await setSubjectRlsContext(scopedDb, input.actorSubjectId);
568
+ const [row] = await rawRows<{ result: Record<string, unknown> }>(
569
+ scopedDb,
570
+ sql`select prepare_organization_workspace_member_removal(
571
+ ${JSON.stringify(command)}::jsonb
572
+ ) as result`,
573
+ );
574
+ if (!row) throw new Error("Organization workspace removal preparation returned no result");
575
+ return row.result;
576
+ },
577
+ );
578
+ if (prepared.replay === true) {
579
+ return RevokeOrganizationWorkspaceMemberResponse.parse(prepared);
580
+ }
581
+ const workspaceMembershipId = String(prepared.workspaceMembershipId ?? "");
582
+ const actorMembershipId = String(prepared.actorMembershipId ?? "");
583
+ if (!uuidPattern.test(workspaceMembershipId) || !uuidPattern.test(actorMembershipId)) {
584
+ throw new Error("Organization workspace removal preparation returned invalid evidence");
585
+ }
586
+ const removed = await removeWorkspaceMember(txDb, {
587
+ accountId: input.organizationId,
588
+ workspaceId: input.workspaceId,
589
+ actorSubjectId: input.actorSubjectId,
590
+ targetSubjectId,
591
+ requireOrganizationSharedWorkspaceAdministration: true,
592
+ operationId: input.operationId,
593
+ });
594
+ if (!removed) throw new Error("Organization workspace removal lost its locked membership");
595
+ return await withRlsContext(
596
+ txDb,
597
+ { accountId: input.organizationId, workspaceId: null },
598
+ async (scopedDb) => {
599
+ await setSubjectRlsContext(scopedDb, input.actorSubjectId);
600
+ const [row] = await rawRows<{ result: unknown }>(
601
+ scopedDb,
602
+ sql`select record_organization_workspace_member_removal(
603
+ ${JSON.stringify(command)}::jsonb,
604
+ ${workspaceMembershipId}::uuid,
605
+ ${actorMembershipId}::uuid
606
+ ) as result`,
607
+ );
608
+ if (!row) throw new Error("Organization workspace removal audit returned no result");
609
+ return RevokeOrganizationWorkspaceMemberResponse.parse(row.result);
610
+ },
611
+ );
612
+ });
613
+ }
614
+
412
615
  export async function assertActiveManagedHumanOrganizationMembership(
413
616
  db: Database,
414
617
  input: { accountId: string; subjectId: string },
@@ -530,6 +733,29 @@ export async function listOrganizationMembers(
530
733
  );
531
734
  }
532
735
 
736
+ export async function listOrganizationAdministrationMembers(
737
+ db: Database,
738
+ input: { organizationId: string; actorSubjectId: string },
739
+ ): Promise<OrganizationAdministrationMemberType[]> {
740
+ return await withRlsContext(
741
+ db,
742
+ { accountId: input.organizationId, workspaceId: null },
743
+ async (scopedDb) => {
744
+ await setSubjectRlsContext(scopedDb, input.actorSubjectId);
745
+ const [row] = await rawRows<{ result: unknown }>(
746
+ scopedDb,
747
+ sql`select list_organization_administration_members(
748
+ ${input.organizationId}::uuid,
749
+ ${input.actorSubjectId}
750
+ ) as result`,
751
+ );
752
+ return ListOrganizationAdministrationMembersResponse.parse({
753
+ members: row?.result ?? [],
754
+ }).members;
755
+ },
756
+ );
757
+ }
758
+
533
759
  export async function getOrganizationAdministrationOverview(
534
760
  db: Database,
535
761
  input: { organizationId: string; actorSubjectId: string },
@@ -671,6 +897,32 @@ export async function listOrganizationInvitations(
671
897
  );
672
898
  }
673
899
 
900
+ export async function getOrganizationInvitationForAdministration(
901
+ db: Database,
902
+ input: {
903
+ organizationId: string;
904
+ actorSubjectId: string;
905
+ invitationId: string;
906
+ },
907
+ ): Promise<OrganizationInvitationType> {
908
+ return await withRlsContext(
909
+ db,
910
+ { accountId: input.organizationId, workspaceId: null },
911
+ async (scopedDb) => {
912
+ await setSubjectRlsContext(scopedDb, input.actorSubjectId);
913
+ const [row] = await rawRows<{ result: unknown }>(
914
+ scopedDb,
915
+ sql`select get_organization_invitation_for_administration(
916
+ ${input.organizationId}::uuid,
917
+ ${input.actorSubjectId},
918
+ ${input.invitationId}::uuid
919
+ ) as result`,
920
+ );
921
+ return OrganizationInvitation.parse(row?.result);
922
+ },
923
+ );
924
+ }
925
+
674
926
  export async function createOrganizationInvitation(
675
927
  db: Database,
676
928
  input: CommandBase & {