@opengeni/db 1.0.2 → 1.2.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 (86) hide show
  1. package/dist/artifact-catalog.d.ts +12 -0
  2. package/dist/canonical-human-identities.js +3 -3
  3. package/dist/capability-reconciliation.js +2 -2
  4. package/dist/{chunk-KH3TYDGY.js → chunk-3GAR5UN3.js} +2 -2
  5. package/dist/{chunk-UEQQ2WWU.js → chunk-3TGYFFZR.js} +3 -26
  6. package/dist/chunk-3TGYFFZR.js.map +1 -0
  7. package/dist/{chunk-F3YMVRF4.js → chunk-6EIEGHPK.js} +4 -4
  8. package/dist/{chunk-OQZOGCLG.js → chunk-CONWNUSL.js} +2 -2
  9. package/dist/{chunk-7S53WLPI.js → chunk-CYP72JTQ.js} +11 -4
  10. package/dist/{chunk-7S53WLPI.js.map → chunk-CYP72JTQ.js.map} +1 -1
  11. package/dist/{chunk-LDTQGYD2.js → chunk-FWQNHNOU.js} +54 -2
  12. package/dist/chunk-FWQNHNOU.js.map +1 -0
  13. package/dist/{chunk-KEDWSSNP.js → chunk-GDN5TSZP.js} +2 -2
  14. package/dist/{chunk-PQGTWFRF.js → chunk-JICUP7ZR.js} +2 -2
  15. package/dist/{chunk-NLSG7GGA.js → chunk-JLVWBIEM.js} +3 -3
  16. package/dist/{chunk-Y77PVZZD.js → chunk-LXPFNG4L.js} +2 -2
  17. package/dist/{chunk-56MYWKQV.js → chunk-O2Y5E5M3.js} +68 -32
  18. package/dist/chunk-O2Y5E5M3.js.map +1 -0
  19. package/dist/{chunk-7POTLB24.js → chunk-QFJNEXFL.js} +2 -2
  20. package/dist/{chunk-MACELCXG.js → chunk-UCIMHNII.js} +101 -21
  21. package/dist/chunk-UCIMHNII.js.map +1 -0
  22. package/dist/{chunk-OMHBVHX7.js → chunk-VDPCIFKL.js} +5 -5
  23. package/dist/{chunk-N5QCKHYL.js → chunk-YOYILDLY.js} +87 -19
  24. package/dist/chunk-YOYILDLY.js.map +1 -0
  25. package/dist/connect-attempts.js +3 -3
  26. package/dist/credit-balances.d.ts +18 -0
  27. package/dist/credit-promotion-policy.d.ts +10 -0
  28. package/dist/editable-artifact-durable-export.js +2 -2
  29. package/dist/editable-artifacts.js +3 -3
  30. package/dist/index.d.ts +35 -10
  31. package/dist/index.js +2432 -2255
  32. package/dist/index.js.map +1 -1
  33. package/dist/managed-auth-session-sets.js +3 -3
  34. package/dist/managed-user-setup.d.ts +1 -0
  35. package/dist/mcp-operations.js +2 -2
  36. package/dist/organization-integration-policy.js +3 -3
  37. package/dist/organization-membership-lifecycle.d.ts +1 -0
  38. package/dist/persistence-errors.d.ts +9 -6
  39. package/dist/provision-roles.js +1 -1
  40. package/dist/retained-provider-commands.js +6 -6
  41. package/dist/runtime-posture.d.ts +7 -6
  42. package/dist/schema.d.ts +214 -2
  43. package/dist/schema.js +5 -1
  44. package/dist/session-background-commands.js +4 -4
  45. package/dist/session-command-output.js +5 -5
  46. package/dist/session-event-slices.js +3 -3
  47. package/dist/session-mcp-credential-rotation.js +5 -5
  48. package/dist/session-tenancy.d.ts +6 -1
  49. package/dist/session-tenancy.js +3 -5
  50. package/dist/video-generation.js +3 -3
  51. package/dist/workspace-tool-defaults.js +4 -4
  52. package/drizzle/0610_artifact_catalog_pins.sql +165 -0
  53. package/drizzle/0611_universal_session_tenancy_activation.sql +166 -0
  54. package/drizzle/0612_scheduled_model_unavailable_refusal.sql +21 -0
  55. package/drizzle/0613_model_scoped_promotional_credits.sql +238 -0
  56. package/drizzle/0614_quiescence_command_containment.sql +7 -0
  57. package/drizzle/0615_credit_promotion_policy_validation.sql +63 -0
  58. package/package.json +7 -7
  59. package/src/artifact-catalog.ts +31 -5
  60. package/src/credit-balances.ts +109 -0
  61. package/src/credit-promotion-policy.ts +12 -0
  62. package/src/database.ts +81 -42
  63. package/src/index.ts +295 -79
  64. package/src/managed-user-setup.ts +8 -0
  65. package/src/organization-membership-lifecycle.ts +8 -0
  66. package/src/persistence-errors.ts +17 -6
  67. package/src/provision-roles.ts +25 -0
  68. package/src/runtime-posture-cli.ts +0 -2
  69. package/src/runtime-posture.ts +86 -27
  70. package/src/schema.ts +57 -1
  71. package/src/session-tenancy.ts +9 -31
  72. package/src/video-generation.ts +2 -7
  73. package/dist/chunk-56MYWKQV.js.map +0 -1
  74. package/dist/chunk-LDTQGYD2.js.map +0 -1
  75. package/dist/chunk-MACELCXG.js.map +0 -1
  76. package/dist/chunk-N5QCKHYL.js.map +0 -1
  77. package/dist/chunk-UEQQ2WWU.js.map +0 -1
  78. /package/dist/{chunk-KH3TYDGY.js.map → chunk-3GAR5UN3.js.map} +0 -0
  79. /package/dist/{chunk-F3YMVRF4.js.map → chunk-6EIEGHPK.js.map} +0 -0
  80. /package/dist/{chunk-OQZOGCLG.js.map → chunk-CONWNUSL.js.map} +0 -0
  81. /package/dist/{chunk-KEDWSSNP.js.map → chunk-GDN5TSZP.js.map} +0 -0
  82. /package/dist/{chunk-PQGTWFRF.js.map → chunk-JICUP7ZR.js.map} +0 -0
  83. /package/dist/{chunk-NLSG7GGA.js.map → chunk-JLVWBIEM.js.map} +0 -0
  84. /package/dist/{chunk-Y77PVZZD.js.map → chunk-LXPFNG4L.js.map} +0 -0
  85. /package/dist/{chunk-7POTLB24.js.map → chunk-QFJNEXFL.js.map} +0 -0
  86. /package/dist/{chunk-OMHBVHX7.js.map → chunk-VDPCIFKL.js.map} +0 -0
package/src/database.ts CHANGED
@@ -6,6 +6,8 @@ import { drizzle } from "drizzle-orm/postgres-js";
6
6
  import postgres from "postgres";
7
7
 
8
8
  import {
9
+ DatabaseTransactionError,
10
+ isDatabasePersistenceFailure,
9
11
  runIdempotentPersistenceTransaction,
10
12
  type IdempotentPersistenceTransactionOptions,
11
13
  } from "./persistence-errors";
@@ -521,6 +523,39 @@ async function restoreRlsContextSettings(
521
523
  }
522
524
  }
523
525
 
526
+ /** Attribute only failures outside the application callback to our transaction
527
+ * driver. BEGIN/COMMIT/ROLLBACK can throw raw postgres.js errors, unlike ORM
528
+ * queries. This supplies provenance, never transaction retry permission. */
529
+ async function withDatabaseTransactionProvenance<T>(
530
+ db: Database,
531
+ fn: (db: Database) => Promise<T>,
532
+ transactionConfig?: PgTransactionConfig,
533
+ ): Promise<T> {
534
+ let entered = false;
535
+ let callbackFailure: { error: unknown } | undefined;
536
+ try {
537
+ return await db.transaction(async (tx) => {
538
+ entered = true;
539
+ try {
540
+ return await fn(tx as unknown as Database);
541
+ } catch (error) {
542
+ callbackFailure = { error };
543
+ throw error;
544
+ }
545
+ }, transactionConfig);
546
+ } catch (error) {
547
+ // A provider/tool rejection propagated by a successful rollback is still
548
+ // the provider/tool's error, even if it has a connection-looking code.
549
+ if (callbackFailure && callbackFailure.error === error) throw error;
550
+ if (!isDatabasePersistenceFailure(error)) throw error;
551
+ throw new DatabaseTransactionError(
552
+ entered ? "settlement" : "admission",
553
+ error,
554
+ callbackFailure?.error,
555
+ );
556
+ }
557
+ }
558
+
524
559
  export async function withRlsContext<T>(
525
560
  db: Database,
526
561
  context: RlsContext,
@@ -535,49 +570,53 @@ export async function withRlsContext<T>(
535
570
  restoreParentScope ? "savepoint_admission" : "transaction_admission",
536
571
  );
537
572
  try {
538
- return await db.transaction(async (tx) => {
539
- admission("completed");
540
- const setup = startDatabaseTiming("rls_setup");
541
- const scoped = tx as unknown as Database;
542
- let parentScope: RlsContextSettings | null;
543
- try {
544
- parentScope = restoreParentScope ? await readRlsContextSettings(scoped) : null;
545
- await setRlsContext(scoped, context);
546
- if (context.workspaceId && sessionTenancyFence === "shared") {
547
- await scoped.execute(
548
- sql`select pg_advisory_xact_lock_shared(hashtextextended(${`session-tenancy:${context.workspaceId}`}, 0))`,
549
- );
573
+ return await withDatabaseTransactionProvenance(
574
+ db,
575
+ async (tx) => {
576
+ admission("completed");
577
+ const setup = startDatabaseTiming("rls_setup");
578
+ const scoped = tx as unknown as Database;
579
+ let parentScope: RlsContextSettings | null;
580
+ try {
581
+ parentScope = restoreParentScope ? await readRlsContextSettings(scoped) : null;
582
+ await setRlsContext(scoped, context);
583
+ if (context.workspaceId && sessionTenancyFence === "shared") {
584
+ await scoped.execute(
585
+ sql`select pg_advisory_xact_lock_shared(hashtextextended(${`session-tenancy:${context.workspaceId}`}, 0))`,
586
+ );
587
+ }
588
+ // Defense-in-depth: read the LOCAL GUC back on THIS backend BEFORE running
589
+ // the scoped query. The set_config and this read share one db.transaction,
590
+ // which a transaction pooler pins to a single backend — so a mismatch here
591
+ // means the context was genuinely lost (a torn transaction / pooler backend
592
+ // swap), not normal operation. Without this guard such an event runs the
593
+ // scoped read with an empty account_id and returns zero RLS-visible rows,
594
+ // manufacturing a phantom "no active subscription" from a credential that is
595
+ // in fact active. Convert that silent false into a loud, root-cause-bearing
596
+ // error so the caller can retry rather than permanently mis-decide.
597
+ await assertRlsContextApplied(scoped, context);
598
+ setup("completed");
599
+ } catch (error) {
600
+ setup("failed");
601
+ throw error;
550
602
  }
551
- // Defense-in-depth: read the LOCAL GUC back on THIS backend BEFORE running
552
- // the scoped query. The set_config and this read share one db.transaction,
553
- // which a transaction pooler pins to a single backend — so a mismatch here
554
- // means the context was genuinely lost (a torn transaction / pooler backend
555
- // swap), not normal operation. Without this guard such an event runs the
556
- // scoped read with an empty account_id and returns zero RLS-visible rows,
557
- // manufacturing a phantom "no active subscription" from a credential that is
558
- // in fact active. Convert that silent false into a loud, root-cause-bearing
559
- // error so the caller can retry rather than permanently mis-decide.
560
- await assertRlsContextApplied(scoped, context);
561
- setup("completed");
562
- } catch (error) {
563
- setup("failed");
564
- throw error;
565
- }
566
- const callback = startDatabaseTiming("scoped_callback");
567
- let value: T;
568
- try {
569
- value = await fn(scoped);
570
- callback("completed");
571
- } catch (error) {
572
- callback("failed");
573
- throw error;
574
- }
575
- // A nested transaction is a savepoint, and SET LOCAL survives successful
576
- // savepoint release. Restore the parent tenant and actor proof together;
577
- // writer/protocol capabilities intentionally remain transaction-wide.
578
- if (parentScope) await restoreRlsContextSettings(scoped, parentScope);
579
- return value;
580
- }, transactionConfig);
603
+ const callback = startDatabaseTiming("scoped_callback");
604
+ let value: T;
605
+ try {
606
+ value = await fn(scoped);
607
+ callback("completed");
608
+ } catch (error) {
609
+ callback("failed");
610
+ throw error;
611
+ }
612
+ // A nested transaction is a savepoint, and SET LOCAL survives successful
613
+ // savepoint release. Restore the parent tenant and actor proof together;
614
+ // writer/protocol capabilities intentionally remain transaction-wide.
615
+ if (parentScope) await restoreRlsContextSettings(scoped, parentScope);
616
+ return value;
617
+ },
618
+ transactionConfig,
619
+ );
581
620
  } catch (error) {
582
621
  // No-op after callback entry; only admission failures are counted here.
583
622
  admission("failed");