@rehearsal-db/core 0.1.0-beta.1 → 0.1.0-beta.10

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 (68) hide show
  1. package/CHANGELOG.md +244 -1
  2. package/COMPATIBILITY.md +17 -0
  3. package/README.md +139 -346
  4. package/SECURITY.md +2 -1
  5. package/SUPPORT.md +5 -0
  6. package/docs/README.md +29 -0
  7. package/docs/adapters.md +20 -6
  8. package/docs/architecture.md +58 -0
  9. package/docs/baselines.md +102 -22
  10. package/docs/commands.md +196 -33
  11. package/docs/configuration.md +258 -13
  12. package/docs/getting-started.md +106 -182
  13. package/docs/glossary.md +11 -8
  14. package/docs/production-source.md +176 -33
  15. package/docs/releasing.md +28 -38
  16. package/docs/roadmap.md +41 -0
  17. package/docs/runtime-policies.md +193 -0
  18. package/docs/sanitization.md +43 -8
  19. package/docs/security-model.md +34 -9
  20. package/docs/standalone-workflow.md +107 -0
  21. package/docs/troubleshooting.md +102 -2
  22. package/docs/tutorial.md +70 -59
  23. package/package.json +30 -22
  24. package/scripts/runtime/manage_database.mjs +18 -0
  25. package/src/README.md +17 -0
  26. package/src/application/session.mjs +435 -0
  27. package/{scripts/lib/rehearsal/baseline_artifact.mjs → src/baseline/artifact.mjs} +142 -17
  28. package/{scripts/lib/rehearsal/baseline_builder.mjs → src/baseline/builder.mjs} +19 -10
  29. package/src/baseline/input_discovery.mjs +155 -0
  30. package/src/baseline/policy_review.mjs +92 -0
  31. package/src/baseline/preparation.mjs +323 -0
  32. package/src/baseline/privacy_engine.mjs +413 -0
  33. package/{scripts/lib/rehearsal → src/baseline}/sanitization_policy.mjs +133 -3
  34. package/{scripts/lib/rehearsal → src/baseline}/schema_snapshot.mjs +1 -1
  35. package/src/cli/arguments.mjs +123 -0
  36. package/src/cli/guided.mjs +812 -0
  37. package/src/cli/rehearsal.mjs +997 -0
  38. package/src/cli/renderers.mjs +584 -0
  39. package/src/cli/runtime_commands.mjs +624 -0
  40. package/src/cli/source_commands.mjs +326 -0
  41. package/src/cli/terminal.mjs +275 -0
  42. package/src/identity/claim.mjs +975 -0
  43. package/src/identity/storage.mjs +165 -0
  44. package/{scripts/lib/rehearsal → src/project}/configuration.d.mts +72 -4
  45. package/src/project/configuration.mjs +1199 -0
  46. package/src/project/setup.mjs +379 -0
  47. package/src/project/support_report.mjs +105 -0
  48. package/src/runtime/cleanup.mjs +381 -0
  49. package/{scripts/lib/rehearsal → src/runtime}/plan.mjs +118 -20
  50. package/src/runtime/policy.mjs +438 -0
  51. package/{scripts/lib/rehearsal/runtime_restore.mjs → src/runtime/restore.mjs} +46 -27
  52. package/src/runtime/topology.mjs +177 -0
  53. package/{scripts/lib/rehearsal → src/shared}/diagnostics.mjs +10 -3
  54. package/src/shared/human_output.mjs +4 -0
  55. package/src/shared/operation_guard.mjs +162 -0
  56. package/{scripts/lib/rehearsal → src/shared}/process_environment.mjs +5 -1
  57. package/src/source/access.mjs +578 -0
  58. package/src/source/asset_transfer.mjs +177 -0
  59. package/src/source/baseline.mjs +446 -0
  60. package/src/source/postgresql_access.mjs +480 -0
  61. package/src/targets/postgresql.mjs +808 -0
  62. package/{scripts/operations/database/manage_rehearsal_database.mjs → src/targets/supabase.mjs} +66 -20
  63. package/{scripts/lib/environment/local_supabase.mjs → src/targets/supabase_environment.mjs} +60 -28
  64. package/src/targets/target.mjs +66 -0
  65. package/scripts/lib/rehearsal/configuration.mjs +0 -559
  66. package/scripts/operations/rehearsal/rehearsal_cli.mjs +0 -565
  67. /package/{scripts/lib/rehearsal → src/runtime}/migration_history.mjs +0 -0
  68. /package/{scripts/lib/rehearsal → src/runtime}/service_environment.mjs +0 -0
@@ -16,11 +16,11 @@ import { pathToFileURL } from "node:url";
16
16
  import {
17
17
  resolveActiveBaselinePaths,
18
18
  verifyActiveBaseline,
19
- } from "../../lib/rehearsal/baseline_artifact.mjs";
19
+ } from "../baseline/artifact.mjs";
20
20
  import {
21
21
  createCleanProcessEnvironment,
22
22
  assertLoopbackUrl,
23
- } from "../../lib/rehearsal/process_environment.mjs";
23
+ } from "../shared/process_environment.mjs";
24
24
  import {
25
25
  localCommandSucceeds,
26
26
  readLocalSupabaseEnvironment,
@@ -28,30 +28,42 @@ import {
28
28
  runLocalCommand,
29
29
  startLocalSupabase,
30
30
  stopLocalSupabase,
31
- } from "../../lib/environment/local_supabase.mjs";
31
+ } from "./supabase_environment.mjs";
32
32
  import {
33
33
  buildRestoreSqlPrefix,
34
34
  buildRestoreSqlSuffix,
35
35
  createCandidateMigrationReceipt,
36
36
  encodeBaselineRecordForCopy,
37
37
  summarizeRestoreError,
38
- } from "../../lib/rehearsal/runtime_restore.mjs";
38
+ } from "../runtime/restore.mjs";
39
39
  import {
40
40
  buildMigrationLedgerInventory,
41
41
  compareSourceToReplay,
42
42
  createMigrationReplayReceipt,
43
43
  readMigrationFileInventory,
44
- } from "../../lib/rehearsal/migration_history.mjs";
45
- import { loadRehearsalConfig } from "../../lib/rehearsal/configuration.mjs";
46
- import { readRehearsalServiceEnvironment } from "../../lib/rehearsal/service_environment.mjs";
44
+ } from "../runtime/migration_history.mjs";
45
+ import { loadRehearsalConfig } from "../project/configuration.mjs";
46
+ import { readRehearsalServiceEnvironment } from "../runtime/service_environment.mjs";
47
+ import { readBoundRuntimeSanitizationPolicy } from "../baseline/sanitization_policy.mjs";
47
48
  import {
48
49
  captureLocalPublicSchema,
49
50
  compareProductionSchemaDumps,
50
- } from "../../lib/rehearsal/schema_snapshot.mjs";
51
+ } from "../baseline/schema_snapshot.mjs";
52
+ import { formatCount } from "../shared/human_output.mjs";
53
+ import { parseRuntimeInvocation } from "./target.mjs";
54
+ import {
55
+ buildRuntimeFinalizationSql,
56
+ buildRuntimePostSchemaSql,
57
+ buildRuntimePrerequisiteSql,
58
+ buildRuntimeVerificationSql,
59
+ validateRuntimePolicy,
60
+ } from "../runtime/policy.mjs";
51
61
 
52
62
  const repositoryRoot = process.cwd();
63
+ const invocation = parseRuntimeInvocation();
53
64
  const loadedConfiguration = await loadRehearsalConfig({
54
65
  projectRoot: repositoryRoot,
66
+ configPath: invocation.configPath,
55
67
  });
56
68
  const { config, paths: configuredPaths } = loadedConfiguration;
57
69
  const artifactRoot = configuredPaths.artifactDirectory;
@@ -73,8 +85,13 @@ const projectId = config.runtime.projectId;
73
85
  const runtimeAdapter = configuredPaths.runtimeAdapter
74
86
  ? await import(pathToFileURL(configuredPaths.runtimeAdapter).href)
75
87
  : null;
88
+ const runtimePolicy = configuredPaths.runtimePolicy
89
+ ? validateRuntimePolicy(
90
+ JSON.parse(await readFile(configuredPaths.runtimePolicy, "utf8")),
91
+ )
92
+ : null;
76
93
  const environmentKeyPattern = /^[A-Z][A-Z0-9_]*$/u;
77
- const action = process.argv[2] ?? "status";
94
+ const action = invocation.action;
78
95
 
79
96
  const readServiceEnvironment = () =>
80
97
  readRehearsalServiceEnvironment({
@@ -329,6 +346,12 @@ const writeRuntimeEnvironment = async ({
329
346
  const variables = {
330
347
  REHEARSAL_RUNTIME_ENVIRONMENT: "rehearsal",
331
348
  REHEARSAL_BASELINE_ID: baseline.generationId,
349
+ DATABASE_URL: environment.databaseUrl,
350
+ PGHOST: environment.databaseHost,
351
+ PGPORT: environment.databasePort,
352
+ PGDATABASE: environment.databaseName,
353
+ PGUSER: environment.databaseUser,
354
+ PGPASSWORD: environment.databasePassword,
332
355
  SUPABASE_URL: environment.apiUrl,
333
356
  SUPABASE_PUBLISHABLE_KEY: environment.publishableKey,
334
357
  SUPABASE_SERVICE_ROLE_KEY: environment.serviceRoleKey,
@@ -370,7 +393,13 @@ const runDatabaseSql = (sql) => {
370
393
 
371
394
  const restoreProductionSchema = async ({ baseline, paths }) => {
372
395
  const receipt = baseline.files?.["production-schema.sql"];
373
- if (baseline.formatVersion === 1 && receipt === undefined) return null;
396
+ if (baseline.formatVersion === 1 && receipt === undefined) {
397
+ if (runtimePolicy) {
398
+ runDatabaseSql(buildRuntimePrerequisiteSql(runtimePolicy));
399
+ runDatabaseSql(buildRuntimePostSchemaSql(runtimePolicy));
400
+ }
401
+ return null;
402
+ }
374
403
  if (
375
404
  baseline.formatVersion !== 2 ||
376
405
  !/^[a-f0-9]{64}$/u.test(receipt?.sha256 ?? "") ||
@@ -381,7 +410,12 @@ const restoreProductionSchema = async ({ baseline, paths }) => {
381
410
  );
382
411
  }
383
412
  const schemaSql = await readFile(paths.schemaPath, "utf8");
384
- runDatabaseSql("drop schema if exists public cascade;");
413
+ runDatabaseSql(`drop schema if exists public cascade;
414
+ create schema public authorization pg_database_owner;
415
+ grant usage on schema public to public;`);
416
+ if (runtimePolicy) {
417
+ runDatabaseSql(buildRuntimePrerequisiteSql(runtimePolicy));
418
+ }
385
419
  if (runtimeAdapter?.prepareSchema) {
386
420
  const preparation = runtimeAdapter.prepareSchema({
387
421
  runSql: runDatabaseSql,
@@ -393,6 +427,9 @@ const restoreProductionSchema = async ({ baseline, paths }) => {
393
427
  }
394
428
  }
395
429
  runDatabaseSql(schemaSql);
430
+ if (runtimePolicy) {
431
+ runDatabaseSql(buildRuntimePostSchemaSql(runtimePolicy));
432
+ }
396
433
  const restoredSchema = await captureLocalPublicSchema({
397
434
  repositoryRoot,
398
435
  artifactRoot,
@@ -443,11 +480,15 @@ const configureProjectRuntime = ({ environment, baseline }) => {
443
480
  };
444
481
 
445
482
  const readActive = async () => {
446
- const [baseline, paths, manifest] = await Promise.all([
483
+ const [baseline, paths, policyBytes] = await Promise.all([
447
484
  verifyActiveBaseline({ artifactRoot }),
448
485
  resolveActiveBaselinePaths({ artifactRoot }),
449
- readFile(manifestPath, "utf8").then(JSON.parse),
486
+ readFile(manifestPath),
450
487
  ]);
488
+ const manifest = readBoundRuntimeSanitizationPolicy({
489
+ bytes: policyBytes,
490
+ expectedSha256: baseline.sanitizationPolicySha256,
491
+ });
451
492
  return { baseline, paths, manifest };
452
493
  };
453
494
 
@@ -462,6 +503,7 @@ const resetRuntime = async () => {
462
503
  workdir: runtimeWorkdir,
463
504
  exclude: ["edge-runtime", "logflare", "vector", "realtime"],
464
505
  environment: serviceEnvironment,
506
+ autoStartColima: config.containerRuntime.autoStartColima,
465
507
  });
466
508
  const structuralSchemaSha256 = await restoreProductionSchema(active);
467
509
  await restoreBaselineRows(active);
@@ -470,6 +512,10 @@ const resetRuntime = async () => {
470
512
  paths: active.paths,
471
513
  environment,
472
514
  });
515
+ if (runtimePolicy && runtimePolicy.localRows.length > 0) {
516
+ runDatabaseSql(buildRuntimeFinalizationSql(runtimePolicy));
517
+ console.log("Applied reviewed local-only recipes.");
518
+ }
473
519
  const projectRuntime = configureProjectRuntime({
474
520
  environment,
475
521
  baseline: active.baseline,
@@ -496,7 +542,7 @@ const resetRuntime = async () => {
496
542
  { mode: 0o600 },
497
543
  );
498
544
  console.log(
499
- `Restored Rehearsal baseline ${active.baseline.generationId}: ${active.baseline.rowCount} rows across ${Object.keys(active.baseline.tableCounts).length} tables.`,
545
+ `Restored Rehearsal baseline ${active.baseline.generationId}: ${formatCount(active.baseline.rowCount, "row")} across ${formatCount(Object.keys(active.baseline.tableCounts).length, "table")}.`,
500
546
  );
501
547
  console.log(projectRuntime.message);
502
548
  return environment;
@@ -526,6 +572,7 @@ const startRuntime = async () => {
526
572
  workdir: runtimeWorkdir,
527
573
  exclude: ["edge-runtime", "logflare", "vector", "realtime"],
528
574
  environment: serviceEnvironment,
575
+ autoStartColima: config.containerRuntime.autoStartColima,
529
576
  });
530
577
  const projectRuntime = configureProjectRuntime({ environment, baseline });
531
578
  await writeRuntimeEnvironment({
@@ -605,6 +652,7 @@ const verifyRuntime = async () => {
605
652
  currentFiles: candidateReceipt.currentFiles,
606
653
  });
607
654
  let projectVerification;
655
+ if (runtimePolicy) runDatabaseSql(buildRuntimeVerificationSql(runtimePolicy));
608
656
  if (runtimeAdapter?.verifyRuntime) {
609
657
  projectVerification = runtimeAdapter.verifyRuntime({
610
658
  baseline,
@@ -621,7 +669,7 @@ const verifyRuntime = async () => {
621
669
  }
622
670
  }
623
671
  console.log(
624
- `Verified Rehearsal runtime ${baseline.generationId}: immutable baseline and migration history are valid with ${migrationComparison.candidates.length} applied candidate migrations. Runtime rows may differ from the baseline until the next reset.`,
672
+ `Verified Rehearsal runtime ${baseline.generationId}: immutable baseline and migration history are valid with ${formatCount(migrationComparison.candidates.length, "applied candidate migration")}. Runtime rows may differ from the baseline until the next reset.`,
625
673
  );
626
674
  if (projectVerification) console.log(projectVerification.message);
627
675
  return { baseline, candidateReceipt, migrationComparison };
@@ -652,11 +700,9 @@ const migrateRuntime = async () => {
652
700
  return receipt;
653
701
  }
654
702
  console.log(
655
- `Candidate migrations (${receipt.candidateSha256}): ${receipt.candidates.map((candidate) => candidate.filename).join(", ")}`,
703
+ `${receipt.candidates.length === 1 ? "Candidate migration" : "Candidate migrations"} (${receipt.candidateSha256}): ${receipt.candidates.map((candidate) => candidate.filename).join(", ")}`,
656
704
  );
657
- const confirmation = process.argv
658
- .find((argument) => argument.startsWith("--confirm-candidates="))
659
- ?.slice("--confirm-candidates=".length);
705
+ const confirmation = invocation.confirmation;
660
706
  if (confirmation !== receipt.candidateSha256) {
661
707
  throw new Error(
662
708
  "Candidate migration confirmation is missing or does not match the exact SHA-256.",
@@ -707,7 +753,7 @@ const migrateRuntime = async () => {
707
753
  { mode: 0o600 },
708
754
  );
709
755
  console.log(
710
- `Applied ${receipt.candidates.length} confirmed candidate migrations to the disposable Rehearsal runtime.`,
756
+ `Applied ${formatCount(receipt.candidates.length, "confirmed candidate migration")} to the disposable Rehearsal runtime.`,
711
757
  );
712
758
  return receipt;
713
759
  } catch (error) {
@@ -4,7 +4,7 @@
4
4
  */
5
5
 
6
6
  import { spawnSync } from "node:child_process";
7
- import { createCleanProcessEnvironment } from "../rehearsal/process_environment.mjs";
7
+ import { createCleanProcessEnvironment } from "../shared/process_environment.mjs";
8
8
 
9
9
  export const parseSupabaseStatusEnvironment = (output) => {
10
10
  const values = {};
@@ -18,6 +18,56 @@ export const parseSupabaseStatusEnvironment = (output) => {
18
18
  return values;
19
19
  };
20
20
 
21
+ export const parseLocalSupabaseEnvironment = (output) => {
22
+ const values = parseSupabaseStatusEnvironment(output);
23
+ const localEnvironment = {
24
+ apiUrl: values.API_URL,
25
+ databaseUrl: values.DB_URL,
26
+ publishableKey: values.PUBLISHABLE_KEY ?? values.ANON_KEY,
27
+ serviceRoleKey: values.SERVICE_ROLE_KEY ?? values.SECRET_KEY,
28
+ studioUrl: values.STUDIO_URL,
29
+ };
30
+ for (const [label, value] of [
31
+ ["API URL", localEnvironment.apiUrl],
32
+ ["database URL", localEnvironment.databaseUrl],
33
+ ["publishable key", localEnvironment.publishableKey],
34
+ ["service-role key", localEnvironment.serviceRoleKey],
35
+ ]) {
36
+ if (!value) throw new Error(`Local Supabase status omitted its ${label}.`);
37
+ }
38
+ const api = new URL(localEnvironment.apiUrl);
39
+ const database = new URL(localEnvironment.databaseUrl);
40
+ const loopbackHosts = ["127.0.0.1", "::1", "localhost"];
41
+ if (
42
+ !loopbackHosts.includes(api.hostname) ||
43
+ !loopbackHosts.includes(database.hostname) ||
44
+ !["postgres:", "postgresql:"].includes(database.protocol)
45
+ ) {
46
+ throw new Error("Refusing to use a non-local Supabase status target.");
47
+ }
48
+ const databaseName = decodeURIComponent(
49
+ database.pathname.replace(/^\//u, ""),
50
+ );
51
+ if (
52
+ !database.port ||
53
+ !databaseName ||
54
+ !database.username ||
55
+ !database.password
56
+ ) {
57
+ throw new Error(
58
+ "Local Supabase status returned an incomplete database URL.",
59
+ );
60
+ }
61
+ return {
62
+ ...localEnvironment,
63
+ databaseHost: database.hostname,
64
+ databasePort: database.port,
65
+ databaseName,
66
+ databaseUser: decodeURIComponent(database.username),
67
+ databasePassword: decodeURIComponent(database.password),
68
+ };
69
+ };
70
+
21
71
  export const runLocalCommand = (
22
72
  command,
23
73
  args,
@@ -62,14 +112,13 @@ export const localCommandSucceeds = (
62
112
  stdio: "ignore",
63
113
  }).status === 0;
64
114
 
65
- export const ensureLocalContainerRuntime = ({ cwd = process.cwd() } = {}) => {
115
+ export const ensureLocalContainerRuntime = ({
116
+ cwd = process.cwd(),
117
+ autoStartColima = true,
118
+ } = {}) => {
66
119
  if (localCommandSucceeds("docker", ["info"], { cwd })) return;
67
- if (localCommandSucceeds("colima", ["version"], { cwd })) {
68
- runLocalCommand(
69
- "colima",
70
- ["start", "--cpu", "4", "--memory", "4", "--disk", "40"],
71
- { cwd },
72
- );
120
+ if (autoStartColima && localCommandSucceeds("colima", ["version"], { cwd })) {
121
+ runLocalCommand("colima", ["start"], { cwd });
73
122
  }
74
123
  if (!localCommandSucceeds("docker", ["info"], { cwd })) {
75
124
  throw new Error(
@@ -91,25 +140,7 @@ export const readLocalSupabaseEnvironment = ({
91
140
  withWorkdir(["status", "-o", "env"], workdir),
92
141
  { capture: true, cwd, environment },
93
142
  );
94
- const values = parseSupabaseStatusEnvironment(output);
95
- const localEnvironment = {
96
- apiUrl: values.API_URL,
97
- publishableKey: values.PUBLISHABLE_KEY ?? values.ANON_KEY,
98
- serviceRoleKey: values.SERVICE_ROLE_KEY ?? values.SECRET_KEY,
99
- studioUrl: values.STUDIO_URL,
100
- };
101
- for (const [label, value] of [
102
- ["API URL", localEnvironment.apiUrl],
103
- ["publishable key", localEnvironment.publishableKey],
104
- ["service-role key", localEnvironment.serviceRoleKey],
105
- ]) {
106
- if (!value) throw new Error(`Local Supabase status omitted its ${label}.`);
107
- }
108
- const hostname = new URL(localEnvironment.apiUrl).hostname;
109
- if (!["127.0.0.1", "::1", "localhost"].includes(hostname)) {
110
- throw new Error("Refusing to use a non-loopback Supabase status target.");
111
- }
112
- return localEnvironment;
143
+ return parseLocalSupabaseEnvironment(output);
113
144
  };
114
145
 
115
146
  export const startLocalSupabase = ({
@@ -118,8 +149,9 @@ export const startLocalSupabase = ({
118
149
  exclude = [],
119
150
  environment = {},
120
151
  applyMigrations = true,
152
+ autoStartColima = true,
121
153
  } = {}) => {
122
- ensureLocalContainerRuntime({ cwd });
154
+ ensureLocalContainerRuntime({ cwd, autoStartColima });
123
155
  const startArguments = withWorkdir(
124
156
  ["start", ...(exclude.length ? ["--exclude", exclude.join(",")] : [])],
125
157
  workdir,
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Purpose: Define the small, closed set of database runtimes Rehearsal can select.
3
+ * Runtime implementations stay behind this boundary so the shared CLI does not
4
+ * need target-specific branches.
5
+ */
6
+
7
+ const TARGETS = Object.freeze({
8
+ supabase: Object.freeze({
9
+ id: "supabase",
10
+ label: "Supabase",
11
+ }),
12
+ postgresql: Object.freeze({
13
+ id: "postgresql",
14
+ label: "PostgreSQL",
15
+ }),
16
+ });
17
+
18
+ export const REHEARSAL_RUNTIME_TARGETS = Object.freeze(Object.keys(TARGETS));
19
+
20
+ export const parseRuntimeInvocation = (arguments_ = process.argv.slice(2)) => {
21
+ const action = arguments_.find((argument) => !argument.startsWith("--"));
22
+ const valueAfter = (prefix) =>
23
+ arguments_
24
+ .find((argument) => argument.startsWith(prefix))
25
+ ?.slice(prefix.length);
26
+ return Object.freeze({
27
+ action: action ?? "status",
28
+ configPath: valueAfter("--config="),
29
+ confirmation: valueAfter("--confirm-candidates="),
30
+ });
31
+ };
32
+
33
+ export const buildRuntimeManagerArguments = ({
34
+ managerPath,
35
+ action,
36
+ configPath,
37
+ confirmation,
38
+ }) => [
39
+ managerPath,
40
+ action,
41
+ ...(configPath ? [`--config=${configPath}`] : []),
42
+ ...(confirmation ? [`--confirm-candidates=${confirmation}`] : []),
43
+ ];
44
+
45
+ export const resolveRuntimeTarget = (value = "supabase") => {
46
+ if (typeof value !== "string" || !Object.hasOwn(TARGETS, value)) {
47
+ throw new Error(
48
+ `Unsupported Rehearsal runtime target: ${String(value)}. Supported targets: ${REHEARSAL_RUNTIME_TARGETS.join(", ")}.`,
49
+ );
50
+ }
51
+ return TARGETS[value];
52
+ };
53
+
54
+ export const runRuntimeTarget = async (target) => {
55
+ const resolved = resolveRuntimeTarget(target);
56
+ switch (resolved.id) {
57
+ case "supabase":
58
+ await import("./supabase.mjs");
59
+ return;
60
+ case "postgresql":
61
+ await import("./postgresql.mjs");
62
+ return;
63
+ default:
64
+ throw new Error(`No runtime driver is installed for ${resolved.id}.`);
65
+ }
66
+ };