supaschema 0.1.0-rc.1
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.
- package/.agents/skills/supaschema/SKILL.md +61 -0
- package/.claude/hooks/block-generated-migration-edits.mjs +32 -0
- package/.claude/rules/supaschema.md +22 -0
- package/.claude/settings.json +16 -0
- package/.claude/skills/supaschema/SKILL.md +61 -0
- package/.codex/hooks/supaschema-tool-gate.mjs +73 -0
- package/.codex/hooks.json +16 -0
- package/.codex/rules/supaschema.rules +22 -0
- package/AGENTS.md +40 -0
- package/LICENSE +661 -0
- package/LICENSE-COMMERCIAL.md +35 -0
- package/README.md +249 -0
- package/benchmarks/README.md +104 -0
- package/benchmarks/compare.js +489 -0
- package/benchmarks/fixtures/additive/from.sql +8 -0
- package/benchmarks/fixtures/additive/manifest.json +1 -0
- package/benchmarks/fixtures/additive/to.sql +9 -0
- package/benchmarks/fixtures/functions-policies/from.sql +24 -0
- package/benchmarks/fixtures/functions-policies/manifest.json +5 -0
- package/benchmarks/fixtures/functions-policies/to.sql +24 -0
- package/benchmarks/plot-lib.js +234 -0
- package/benchmarks/plot-svg.js +339 -0
- package/benchmarks/plot.js +154 -0
- package/benchmarks/tools/bench-all.sh +49 -0
- package/benchmarks/tools/build-project-fixture.mjs +245 -0
- package/benchmarks/tools/compare-db.mjs +101 -0
- package/benchmarks/tools/compare-fixtures.mjs +84 -0
- package/benchmarks/tools/compare-report.mjs +90 -0
- package/benchmarks/tools/compare-supabase.mjs +67 -0
- package/benchmarks/tools/registry.js +266 -0
- package/benchmarks/tools/run-workflow.mjs +77 -0
- package/bin/postinstall.mjs +26 -0
- package/bin/supaschema +2 -0
- package/config-schema.json +208 -0
- package/corpus/supabase-style/corpus.json +6 -0
- package/corpus/supabase-style/migrations/20260101000000_init.sql +28 -0
- package/corpus/supabase-style/migrations/20260102000000_noise.sql +13 -0
- package/corpus/supabase-style/migrations/20260103000000_churn.sql +4 -0
- package/corpus/supabase-style/migrations/20260104000000_triggers.sql +17 -0
- package/corpus/supabase-style/roles.sql +13 -0
- package/corpus/supabase-style/tree/functions.sql +26 -0
- package/corpus/supabase-style/tree/policies.sql +4 -0
- package/corpus/supabase-style/tree/schema.sql +4 -0
- package/corpus/supabase-style/tree/tables.sql +20 -0
- package/corpus/supabase-style/tree/triggers.sql +3 -0
- package/corpus/supabase-style/tree/types.sql +2 -0
- package/corpus/supabase-style/tree/views.sql +6 -0
- package/dist/audit.d.ts +20 -0
- package/dist/audit.d.ts.map +1 -0
- package/dist/audit.js +68 -0
- package/dist/benchmark-db.d.ts +5 -0
- package/dist/benchmark-db.d.ts.map +1 -0
- package/dist/benchmark-db.js +71 -0
- package/dist/benchmark-fixtures.d.ts +10 -0
- package/dist/benchmark-fixtures.d.ts.map +1 -0
- package/dist/benchmark-fixtures.js +201 -0
- package/dist/benchmark.d.ts +2 -0
- package/dist/benchmark.d.ts.map +1 -0
- package/dist/benchmark.js +308 -0
- package/dist/catalog-comments.d.ts +9 -0
- package/dist/catalog-comments.d.ts.map +1 -0
- package/dist/catalog-comments.js +194 -0
- package/dist/catalog-extras.d.ts +12 -0
- package/dist/catalog-extras.d.ts.map +1 -0
- package/dist/catalog-extras.js +408 -0
- package/dist/catalog-foreign.d.ts +15 -0
- package/dist/catalog-foreign.d.ts.map +1 -0
- package/dist/catalog-foreign.js +114 -0
- package/dist/catalog-tables.d.ts +9 -0
- package/dist/catalog-tables.d.ts.map +1 -0
- package/dist/catalog-tables.js +114 -0
- package/dist/catalog.d.ts +8 -0
- package/dist/catalog.d.ts.map +1 -0
- package/dist/catalog.js +351 -0
- package/dist/check-hazards.d.ts +7 -0
- package/dist/check-hazards.d.ts.map +1 -0
- package/dist/check-hazards.js +83 -0
- package/dist/check-reporters.d.ts +8 -0
- package/dist/check-reporters.d.ts.map +1 -0
- package/dist/check-reporters.js +76 -0
- package/dist/check.d.ts +3 -0
- package/dist/check.d.ts.map +1 -0
- package/dist/check.js +229 -0
- package/dist/cli-defaults.d.ts +24 -0
- package/dist/cli-defaults.d.ts.map +1 -0
- package/dist/cli-defaults.js +65 -0
- package/dist/cli-diff.d.ts +13 -0
- package/dist/cli-diff.d.ts.map +1 -0
- package/dist/cli-diff.js +348 -0
- package/dist/cli-reports.d.ts +9 -0
- package/dist/cli-reports.d.ts.map +1 -0
- package/dist/cli-reports.js +90 -0
- package/dist/cli-tools.d.ts +17 -0
- package/dist/cli-tools.d.ts.map +1 -0
- package/dist/cli-tools.js +136 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +239 -0
- package/dist/config-schema-gen.d.ts +2 -0
- package/dist/config-schema-gen.d.ts.map +1 -0
- package/dist/config-schema-gen.js +11 -0
- package/dist/config.d.ts +58 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +132 -0
- package/dist/core.d.ts +115 -0
- package/dist/core.d.ts.map +1 -0
- package/dist/core.js +1 -0
- package/dist/corpus.d.ts +26 -0
- package/dist/corpus.d.ts.map +1 -0
- package/dist/corpus.js +112 -0
- package/dist/database-url.d.ts +8 -0
- package/dist/database-url.d.ts.map +1 -0
- package/dist/database-url.js +74 -0
- package/dist/db-admin.d.ts +23 -0
- package/dist/db-admin.d.ts.map +1 -0
- package/dist/db-admin.js +147 -0
- package/dist/diagnostics.d.ts +16 -0
- package/dist/diagnostics.d.ts.map +1 -0
- package/dist/diagnostics.js +155 -0
- package/dist/diff-score.d.ts +12 -0
- package/dist/diff-score.d.ts.map +1 -0
- package/dist/diff-score.js +339 -0
- package/dist/doctor.d.ts +17 -0
- package/dist/doctor.d.ts.map +1 -0
- package/dist/doctor.js +110 -0
- package/dist/hash.d.ts +7 -0
- package/dist/hash.d.ts.map +1 -0
- package/dist/hash.js +34 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +17 -0
- package/dist/lineage.d.ts +23 -0
- package/dist/lineage.d.ts.map +1 -0
- package/dist/lineage.js +61 -0
- package/dist/migrations-status.d.ts +35 -0
- package/dist/migrations-status.d.ts.map +1 -0
- package/dist/migrations-status.js +131 -0
- package/dist/plan-order.d.ts +4 -0
- package/dist/plan-order.d.ts.map +1 -0
- package/dist/plan-order.js +178 -0
- package/dist/planner-replace.d.ts +4 -0
- package/dist/planner-replace.d.ts.map +1 -0
- package/dist/planner-replace.js +76 -0
- package/dist/planner-table.d.ts +3 -0
- package/dist/planner-table.d.ts.map +1 -0
- package/dist/planner-table.js +165 -0
- package/dist/planner.d.ts +5 -0
- package/dist/planner.d.ts.map +1 -0
- package/dist/planner.js +385 -0
- package/dist/render-guards.d.ts +12 -0
- package/dist/render-guards.d.ts.map +1 -0
- package/dist/render-guards.js +159 -0
- package/dist/render.d.ts +7 -0
- package/dist/render.d.ts.map +1 -0
- package/dist/render.js +325 -0
- package/dist/selfcheck.d.ts +11 -0
- package/dist/selfcheck.d.ts.map +1 -0
- package/dist/selfcheck.js +43 -0
- package/dist/source-normalize.d.ts +14 -0
- package/dist/source-normalize.d.ts.map +1 -0
- package/dist/source-normalize.js +420 -0
- package/dist/source.d.ts +4 -0
- package/dist/source.d.ts.map +1 -0
- package/dist/source.js +233 -0
- package/dist/sql/ast.d.ts +42 -0
- package/dist/sql/ast.d.ts.map +1 -0
- package/dist/sql/ast.js +241 -0
- package/dist/sql/canonical-nodes.d.ts +5 -0
- package/dist/sql/canonical-nodes.d.ts.map +1 -0
- package/dist/sql/canonical-nodes.js +101 -0
- package/dist/sql/extract-helpers.d.ts +18 -0
- package/dist/sql/extract-helpers.d.ts.map +1 -0
- package/dist/sql/extract-helpers.js +127 -0
- package/dist/sql/extract.d.ts +13 -0
- package/dist/sql/extract.d.ts.map +1 -0
- package/dist/sql/extract.js +323 -0
- package/dist/sql/facts.d.ts +34 -0
- package/dist/sql/facts.d.ts.map +1 -0
- package/dist/sql/facts.js +392 -0
- package/dist/sql/identifiers.d.ts +13 -0
- package/dist/sql/identifiers.d.ts.map +1 -0
- package/dist/sql/identifiers.js +83 -0
- package/dist/sql/normalize-deparse.d.ts +25 -0
- package/dist/sql/normalize-deparse.d.ts.map +1 -0
- package/dist/sql/normalize-deparse.js +96 -0
- package/dist/sql/object-hash.d.ts +5 -0
- package/dist/sql/object-hash.d.ts.map +1 -0
- package/dist/sql/object-hash.js +24 -0
- package/dist/sql/parser.d.ts +8 -0
- package/dist/sql/parser.d.ts.map +1 -0
- package/dist/sql/parser.js +89 -0
- package/dist/sql/privileges.d.ts +33 -0
- package/dist/sql/privileges.d.ts.map +1 -0
- package/dist/sql/privileges.js +379 -0
- package/dist/sql/split.d.ts +3 -0
- package/dist/sql/split.d.ts.map +1 -0
- package/dist/sql/split.js +182 -0
- package/dist/sql/statements.d.ts +17 -0
- package/dist/sql/statements.d.ts.map +1 -0
- package/dist/sql/statements.js +284 -0
- package/dist/sql/table-constraints.d.ts +15 -0
- package/dist/sql/table-constraints.d.ts.map +1 -0
- package/dist/sql/table-constraints.js +304 -0
- package/dist/sql/table-shape.d.ts +38 -0
- package/dist/sql/table-shape.d.ts.map +1 -0
- package/dist/sql/table-shape.js +287 -0
- package/dist/sync.d.ts +27 -0
- package/dist/sync.d.ts.map +1 -0
- package/dist/sync.js +86 -0
- package/dist/typegen-model.d.ts +78 -0
- package/dist/typegen-model.d.ts.map +1 -0
- package/dist/typegen-model.js +338 -0
- package/dist/typegen-views.d.ts +7 -0
- package/dist/typegen-views.d.ts.map +1 -0
- package/dist/typegen-views.js +92 -0
- package/dist/typegen-zod.d.ts +3 -0
- package/dist/typegen-zod.d.ts.map +1 -0
- package/dist/typegen-zod.js +149 -0
- package/dist/typegen.d.ts +4 -0
- package/dist/typegen.d.ts.map +1 -0
- package/dist/typegen.js +184 -0
- package/dist/validators.d.ts +3 -0
- package/dist/validators.d.ts.map +1 -0
- package/dist/validators.js +104 -0
- package/dist/verify-environment.d.ts +5 -0
- package/dist/verify-environment.d.ts.map +1 -0
- package/dist/verify-environment.js +92 -0
- package/dist/verify.d.ts +3 -0
- package/dist/verify.d.ts.map +1 -0
- package/dist/verify.js +261 -0
- package/docs/benchmarks/additive-correctness.svg +86 -0
- package/docs/benchmarks/additive-latency.svg +60 -0
- package/docs/benchmarks/functions-policies-correctness.svg +86 -0
- package/docs/benchmarks/functions-policies-latency.svg +60 -0
- package/docs/benchmarks/realistic-correctness.svg +86 -0
- package/docs/benchmarks/realistic-latency.svg +60 -0
- package/docs/benchmarks/scaling-latency.svg +106 -0
- package/docs/benchmarks/workflow-latency.svg +98 -0
- package/docs/benchmarks/xl-correctness.svg +86 -0
- package/docs/benchmarks/xl-latency.svg +60 -0
- package/docs/benchmarks/xxl-correctness.svg +86 -0
- package/docs/benchmarks/xxl-latency.svg +66 -0
- package/docs/case-study-anilize.md +51 -0
- package/docs/ci-gate.md +44 -0
- package/docs/ci.md +68 -0
- package/docs/commands.md +35 -0
- package/docs/config.md +72 -0
- package/docs/corpus.md +33 -0
- package/docs/diagnostics.md +77 -0
- package/docs/hints.md +92 -0
- package/docs/release.md +19 -0
- package/docs/support-matrix.md +57 -0
- package/examples/postgres/schemas/001_app.sql +17 -0
- package/examples/supabase/schemas/001_app.sql +13 -0
- package/examples/supabase/schemas-next/001_app.sql +21 -0
- package/examples/supabase/supaschema.config.json +15 -0
- package/package.json +99 -0
package/dist/cli.js
ADDED
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
import { readFile, writeFile } from "node:fs/promises";
|
|
2
|
+
import { resolve } from "node:path";
|
|
3
|
+
import { Command } from "commander";
|
|
4
|
+
import { checkMigrationSql } from "./check.js";
|
|
5
|
+
import { renderCheckReport } from "./check-reporters.js";
|
|
6
|
+
import { defaultTreeSource, latestMigrationFile, migrationFiles, resolveMigrationsDir, resolveSourceDefaults, } from "./cli-defaults.js";
|
|
7
|
+
import { filterModel, registerDiffCommands } from "./cli-diff.js";
|
|
8
|
+
import { registerReportCommands } from "./cli-reports.js";
|
|
9
|
+
import { registerToolCommands } from "./cli-tools.js";
|
|
10
|
+
import { defaultConfigFile, loadConfig } from "./config.js";
|
|
11
|
+
import { resolveDatabaseUrl } from "./database-url.js";
|
|
12
|
+
import { diagnosticCatalog, formatDiagnostics, hasErrors } from "./diagnostics.js";
|
|
13
|
+
import { selfCheckCatalog } from "./selfcheck.js";
|
|
14
|
+
import { extractSourceModel } from "./source.js";
|
|
15
|
+
import { verifyMigration } from "./verify.js";
|
|
16
|
+
const cliVersion = await readPackageVersion();
|
|
17
|
+
const program = new Command();
|
|
18
|
+
program
|
|
19
|
+
.name("supaschema")
|
|
20
|
+
.description("Generate deterministic, replay-safe PostgreSQL/Supabase migrations from SQL trees.")
|
|
21
|
+
.option("--config <path>", "explicit config file path (.json, .mjs, or .js)")
|
|
22
|
+
.option("--env <name>", "named environment from config.environments for the database URL")
|
|
23
|
+
.option("--quiet", "suppress diagnostic output on stderr")
|
|
24
|
+
.version(cliVersion)
|
|
25
|
+
.addHelpText("after", `
|
|
26
|
+
Exit codes:
|
|
27
|
+
0 success
|
|
28
|
+
1 runtime error (bad arguments, unreadable input, crash)
|
|
29
|
+
2 diagnostics contained at least one error
|
|
30
|
+
3 --fail-on-diff was set and the plan contained operations
|
|
31
|
+
`);
|
|
32
|
+
program
|
|
33
|
+
.command("init")
|
|
34
|
+
.description("Create supaschema.config.json in the current directory.")
|
|
35
|
+
.action(async () => {
|
|
36
|
+
const path = resolve(process.cwd(), "supaschema.config.json");
|
|
37
|
+
try {
|
|
38
|
+
await writeFile(path, defaultConfigFile, { flag: "wx" });
|
|
39
|
+
process.stdout.write(`${path}\n`);
|
|
40
|
+
}
|
|
41
|
+
catch (error) {
|
|
42
|
+
if (error instanceof Error && "code" in error && error.code === "EEXIST") {
|
|
43
|
+
process.stderr.write("supaschema.config.json already exists\n");
|
|
44
|
+
process.exitCode = 1;
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
throw error;
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
program
|
|
51
|
+
.command("inspect")
|
|
52
|
+
.option("--from <source>", "source to inspect (default: the config schema tree)")
|
|
53
|
+
.option("--schema <names>", "comma-separated schema filter")
|
|
54
|
+
.description("Extract and print a deterministic schema model.")
|
|
55
|
+
.action(async (options) => {
|
|
56
|
+
const config = await loadCliConfig();
|
|
57
|
+
const source = options.from ?? defaultTreeSource(config);
|
|
58
|
+
const model = filterModel(await extractSourceModel(source, { config }), options.schema);
|
|
59
|
+
printDiagnostics(model.diagnostics);
|
|
60
|
+
process.stdout.write(`${JSON.stringify(model, null, 2)}\n`);
|
|
61
|
+
if (hasErrors(model.diagnostics)) {
|
|
62
|
+
process.exitCode = 2;
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
registerDiffCommands(program, {
|
|
66
|
+
cliVersion,
|
|
67
|
+
loadCliConfig,
|
|
68
|
+
printDiagnostics,
|
|
69
|
+
resolveCliDatabaseUrl,
|
|
70
|
+
});
|
|
71
|
+
registerReportCommands(program, { loadCliConfig, printDiagnostics, resolveCliDatabaseUrl });
|
|
72
|
+
registerToolCommands(program, { loadCliConfig, printDiagnostics, resolveCliDatabaseUrl });
|
|
73
|
+
program
|
|
74
|
+
.command("check")
|
|
75
|
+
.argument("[migrations...]", "migration files (default: every .sql in config.migrationsDir)")
|
|
76
|
+
.option("--reporter <name>", "text | github | sarif | json", "text")
|
|
77
|
+
.description("Validate replay-safety and parser diagnostics for migration files (shell globs expand to a directory gate; `-` reads stdin; zero args checks the migrations directory).")
|
|
78
|
+
.action(async (migrationArgs, options) => {
|
|
79
|
+
const config = await loadCliConfig();
|
|
80
|
+
const migrationPaths = migrationArgs.length > 0
|
|
81
|
+
? migrationArgs
|
|
82
|
+
: await migrationFiles(resolve(process.cwd(), config.migrationsDir));
|
|
83
|
+
if (migrationPaths.length === 0) {
|
|
84
|
+
process.stderr.write(`no migrations found in ${config.migrationsDir}\n`);
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
const results = [];
|
|
88
|
+
for (const migrationPath of migrationPaths) {
|
|
89
|
+
const sql = migrationPath === "-" ? await readStdin() : await readFile(migrationPath, "utf8");
|
|
90
|
+
const diagnostics = await checkMigrationSql(sql, { config, cwd: process.cwd() });
|
|
91
|
+
results.push({ diagnostics, file: migrationPath === "-" ? "<stdin>" : migrationPath });
|
|
92
|
+
}
|
|
93
|
+
const reporter = options.reporter;
|
|
94
|
+
const report = renderCheckReport(reporter, results);
|
|
95
|
+
if (report.length > 0) {
|
|
96
|
+
process.stdout.write(report);
|
|
97
|
+
}
|
|
98
|
+
if (results.some((entry) => hasErrors(entry.diagnostics))) {
|
|
99
|
+
process.exitCode = 2;
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
if (reporter === "text") {
|
|
103
|
+
process.stdout.write(migrationPaths.length > 1 ? `ok (${migrationPaths.length} files)\n` : "ok\n");
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
program
|
|
107
|
+
.command("verify")
|
|
108
|
+
.option("--from <source>", "source model before the change (default: database, then git:HEAD)")
|
|
109
|
+
.option("--to <target>", "source model after the change (default: the config schema tree)")
|
|
110
|
+
.option("--migration <file>", "migration SQL file to apply twice (default: newest .sql in config.migrationsDir)")
|
|
111
|
+
.option("--migrations-dir <dir>", "migrations directory (default: config.migrationsDir)")
|
|
112
|
+
.option("--database-url <url>", "PostgreSQL URL whose role can create temporary databases (default: SUPASCHEMA_DATABASE_URL, then the local Supabase stack from supabase/config.toml)")
|
|
113
|
+
.option("--ensure-roles", "create missing NOLOGIN roles referenced by grants/policies on the verification server (cluster-level; never dropped)")
|
|
114
|
+
.option("--ensure-environment", "stub Supabase-provisioned surfaces (auth helpers, cron schema) in the temporary databases (default under adapter supabase-auto)")
|
|
115
|
+
.option("--keep-databases", "keep the temporary databases after the run and print their names (debugging failed verifies)")
|
|
116
|
+
.description("Apply from + migration twice and compare against target in temporary databases.")
|
|
117
|
+
.action(async (options) => {
|
|
118
|
+
const config = await loadCliConfig();
|
|
119
|
+
const databaseUrl = await resolveCliDatabaseUrl(options.databaseUrl);
|
|
120
|
+
if (!databaseUrl) {
|
|
121
|
+
process.stderr.write("no database URL: pass --database-url, --env, set SUPASCHEMA_DATABASE_URL, or run inside a project with supabase/config.toml\n");
|
|
122
|
+
process.exitCode = 1;
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
const migrationsDir = resolveMigrationsDir(options.migrationsDir, config);
|
|
126
|
+
const migrationPath = options.migration ?? (await latestMigrationFile(resolve(process.cwd(), migrationsDir)));
|
|
127
|
+
if (migrationPath === undefined) {
|
|
128
|
+
process.stderr.write(`no migration to verify: ${migrationsDir} has no .sql files\n`);
|
|
129
|
+
process.exitCode = 1;
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
const sources = await resolveSourceDefaults(options, config, () => resolveCliDatabaseUrl(options.databaseUrl));
|
|
133
|
+
if (sources.notice !== undefined) {
|
|
134
|
+
process.stderr.write(sources.notice);
|
|
135
|
+
}
|
|
136
|
+
if (options.migration === undefined) {
|
|
137
|
+
process.stderr.write(`defaults: --migration ${migrationPath} (flags override)\n`);
|
|
138
|
+
}
|
|
139
|
+
const diagnostics = await verifyMigration({
|
|
140
|
+
config,
|
|
141
|
+
databaseUrl,
|
|
142
|
+
ensureRoles: options.ensureRoles === true,
|
|
143
|
+
...(options.ensureEnvironment === true ? { ensureEnvironment: true } : {}),
|
|
144
|
+
...(options.keepDatabases === true ? { keepDatabases: true } : {}),
|
|
145
|
+
from: sources.from,
|
|
146
|
+
migrationPath,
|
|
147
|
+
to: sources.to,
|
|
148
|
+
});
|
|
149
|
+
printDiagnostics(diagnostics);
|
|
150
|
+
if (hasErrors(diagnostics)) {
|
|
151
|
+
process.exitCode = 2;
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
process.stdout.write("ok\n");
|
|
155
|
+
});
|
|
156
|
+
program
|
|
157
|
+
.command("selfcheck")
|
|
158
|
+
.option("--database-url <url>", "PostgreSQL URL to extract (default: SUPASCHEMA_DATABASE_URL, then the local Supabase stack from supabase/config.toml)")
|
|
159
|
+
.description("Re-extract the live catalog's rendered SQL and report identity normalization gaps.")
|
|
160
|
+
.action(async (options) => {
|
|
161
|
+
const databaseUrl = await resolveCliDatabaseUrl(options.databaseUrl);
|
|
162
|
+
if (!databaseUrl) {
|
|
163
|
+
process.stderr.write("no database URL: pass --database-url, --env, set SUPASCHEMA_DATABASE_URL, or run inside a project with supabase/config.toml\n");
|
|
164
|
+
process.exitCode = 1;
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
const result = await selfCheckCatalog({ databaseUrl });
|
|
168
|
+
printDiagnostics(result.diagnostics);
|
|
169
|
+
process.stdout.write(`selfcheck: ${result.checkedObjects} objects, ${result.mismatches} parity mismatches\n`);
|
|
170
|
+
if (hasErrors(result.diagnostics)) {
|
|
171
|
+
process.exitCode = 2;
|
|
172
|
+
}
|
|
173
|
+
});
|
|
174
|
+
program
|
|
175
|
+
.command("explain")
|
|
176
|
+
.argument("<code>", "diagnostic code, e.g. SUPA_PLAN_DESTRUCTIVE_HINT_REQUIRED")
|
|
177
|
+
.description("Explain a supaschema diagnostic code.")
|
|
178
|
+
.action((code) => {
|
|
179
|
+
const summary = diagnosticCatalog[code.toUpperCase()];
|
|
180
|
+
if (!summary) {
|
|
181
|
+
process.stderr.write(`unknown diagnostic code "${code}"\n`);
|
|
182
|
+
process.exitCode = 1;
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
process.stdout.write(`${code.toUpperCase()}: ${summary}\n`);
|
|
186
|
+
});
|
|
187
|
+
program.parseAsync(process.argv).catch((error) => {
|
|
188
|
+
process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`);
|
|
189
|
+
process.exitCode = 1;
|
|
190
|
+
});
|
|
191
|
+
async function loadCliConfig() {
|
|
192
|
+
const globals = program.opts();
|
|
193
|
+
return loadConfig(process.cwd(), globals.config);
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Database URL precedence: explicit flag, then the named --env entry from
|
|
197
|
+
* config.environments, then the shared resolver (SUPASCHEMA_DATABASE_URL,
|
|
198
|
+
* then supabase/config.toml discovery). Environment values support the same
|
|
199
|
+
* $ENV_NAME indirection as the flag.
|
|
200
|
+
*/
|
|
201
|
+
async function resolveCliDatabaseUrl(explicit) {
|
|
202
|
+
if (explicit) {
|
|
203
|
+
return resolveDatabaseUrl(explicit);
|
|
204
|
+
}
|
|
205
|
+
const globals = program.opts();
|
|
206
|
+
if (globals.env) {
|
|
207
|
+
const config = await loadCliConfig();
|
|
208
|
+
const entry = config.environments[globals.env];
|
|
209
|
+
if (!entry) {
|
|
210
|
+
throw new Error(`--env "${globals.env}" is not defined in config.environments (known: ${Object.keys(config.environments).join(", ") || "none"})`);
|
|
211
|
+
}
|
|
212
|
+
return resolveDatabaseUrl(entry.databaseUrl);
|
|
213
|
+
}
|
|
214
|
+
return resolveDatabaseUrl();
|
|
215
|
+
}
|
|
216
|
+
async function readStdin() {
|
|
217
|
+
const chunks = [];
|
|
218
|
+
for await (const chunk of process.stdin) {
|
|
219
|
+
chunks.push(chunk);
|
|
220
|
+
}
|
|
221
|
+
return Buffer.concat(chunks).toString("utf8");
|
|
222
|
+
}
|
|
223
|
+
function printDiagnostics(diagnostics) {
|
|
224
|
+
const globals = program.opts();
|
|
225
|
+
if (globals.quiet || diagnostics.length === 0) {
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
process.stderr.write(`${formatDiagnostics(diagnostics)}\n`);
|
|
229
|
+
}
|
|
230
|
+
async function readPackageVersion() {
|
|
231
|
+
try {
|
|
232
|
+
const raw = await readFile(new URL("../package.json", import.meta.url), "utf8");
|
|
233
|
+
const parsed = JSON.parse(raw);
|
|
234
|
+
return parsed.version ?? "0.0.0";
|
|
235
|
+
}
|
|
236
|
+
catch {
|
|
237
|
+
return "0.0.0";
|
|
238
|
+
}
|
|
239
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config-schema-gen.d.ts","sourceRoot":"","sources":["../src/config-schema-gen.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { writeFile } from "node:fs/promises";
|
|
2
|
+
import { dirname, resolve } from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
import { configJsonSchema } from "./config.js";
|
|
5
|
+
const packageRoot = resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
|
6
|
+
const schema = {
|
|
7
|
+
$schema: "https://json-schema.org/draft/2020-12/schema",
|
|
8
|
+
title: "supaschema configuration",
|
|
9
|
+
...configJsonSchema(),
|
|
10
|
+
};
|
|
11
|
+
await writeFile(resolve(packageRoot, "config-schema.json"), `${JSON.stringify(schema, null, 2)}\n`, "utf8");
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export declare const supaschemaConfigSchema: z.ZodObject<{
|
|
3
|
+
$schema: z.ZodOptional<z.ZodString>;
|
|
4
|
+
adapter: z.ZodDefault<z.ZodEnum<{
|
|
5
|
+
"supabase-auto": "supabase-auto";
|
|
6
|
+
postgres: "postgres";
|
|
7
|
+
}>>;
|
|
8
|
+
cascade: z.ZodDefault<z.ZodLiteral<"never">>;
|
|
9
|
+
destructiveChanges: z.ZodDefault<z.ZodEnum<{
|
|
10
|
+
block: "block";
|
|
11
|
+
"hint-required": "hint-required";
|
|
12
|
+
allow: "allow";
|
|
13
|
+
}>>;
|
|
14
|
+
environments: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
15
|
+
databaseUrl: z.ZodString;
|
|
16
|
+
}, z.core.$strict>>>;
|
|
17
|
+
excludedGrantRoles: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
18
|
+
hints: z.ZodDefault<z.ZodObject<{
|
|
19
|
+
destructive: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
20
|
+
renames: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
21
|
+
from: z.ZodString;
|
|
22
|
+
to: z.ZodString;
|
|
23
|
+
}, z.core.$strict>>>;
|
|
24
|
+
}, z.core.$strip>>;
|
|
25
|
+
idempotency: z.ZodDefault<z.ZodLiteral<"required">>;
|
|
26
|
+
lockTimeout: z.ZodDefault<z.ZodString>;
|
|
27
|
+
migrationsDir: z.ZodDefault<z.ZodString>;
|
|
28
|
+
typesFile: z.ZodDefault<z.ZodString>;
|
|
29
|
+
zodFile: z.ZodDefault<z.ZodString>;
|
|
30
|
+
normalize: z.ZodDefault<z.ZodEnum<{
|
|
31
|
+
off: "off";
|
|
32
|
+
deparse: "deparse";
|
|
33
|
+
}>>;
|
|
34
|
+
managedSchemas: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
35
|
+
postgresVersion: z.ZodDefault<z.ZodString>;
|
|
36
|
+
renameDetection: z.ZodDefault<z.ZodEnum<{
|
|
37
|
+
off: "off";
|
|
38
|
+
"hints-only": "hints-only";
|
|
39
|
+
}>>;
|
|
40
|
+
schemaPaths: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
41
|
+
schemas: z.ZodDefault<z.ZodObject<{
|
|
42
|
+
exclude: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
43
|
+
include: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
44
|
+
}, z.core.$strict>>;
|
|
45
|
+
statementTimeout: z.ZodDefault<z.ZodString>;
|
|
46
|
+
transactionMode: z.ZodDefault<z.ZodEnum<{
|
|
47
|
+
"per-migration": "per-migration";
|
|
48
|
+
"per-statement": "per-statement";
|
|
49
|
+
}>>;
|
|
50
|
+
validators: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
51
|
+
}, z.core.$strict>;
|
|
52
|
+
export type SupaschemaConfig = z.infer<typeof supaschemaConfigSchema>;
|
|
53
|
+
export declare const defaultConfig: SupaschemaConfig;
|
|
54
|
+
export declare function resolveConfig(config?: Partial<SupaschemaConfig>): SupaschemaConfig;
|
|
55
|
+
export declare function loadConfig(cwd?: string, explicitPath?: string): Promise<SupaschemaConfig>;
|
|
56
|
+
export declare const defaultConfigFile: string;
|
|
57
|
+
export declare function configJsonSchema(): Record<string, unknown>;
|
|
58
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AA2BxB,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAmCjC,CAAC;AAEH,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAEtE,eAAO,MAAM,aAAa,EAAE,gBAAmD,CAAC;AAEhF,wBAAgB,aAAa,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC,gBAAgB,CAAC,GAAG,gBAAgB,CAElF;AAID,wBAAsB,UAAU,CAC9B,GAAG,GAAE,MAAsB,EAC3B,YAAY,CAAC,EAAE,MAAM,GACpB,OAAO,CAAC,gBAAgB,CAAC,CAgB3B;AAsDD,eAAO,MAAM,iBAAiB,QAAiD,CAAC;AAEhF,wBAAgB,gBAAgB,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAE1D"}
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
import { isAbsolute, resolve } from "node:path";
|
|
3
|
+
import { pathToFileURL } from "node:url";
|
|
4
|
+
import { z } from "zod";
|
|
5
|
+
const hintsSchema = z
|
|
6
|
+
.object({
|
|
7
|
+
destructive: z.array(z.string()).default([]),
|
|
8
|
+
renames: z
|
|
9
|
+
.array(z.strictObject({
|
|
10
|
+
from: z.string(),
|
|
11
|
+
to: z.string(),
|
|
12
|
+
}))
|
|
13
|
+
.default([]),
|
|
14
|
+
})
|
|
15
|
+
.default({ destructive: [], renames: [] });
|
|
16
|
+
const schemaFilterSchema = z
|
|
17
|
+
.strictObject({
|
|
18
|
+
exclude: z.array(z.string()).default([]),
|
|
19
|
+
include: z.array(z.string()).default([]),
|
|
20
|
+
})
|
|
21
|
+
.default({ exclude: [], include: [] });
|
|
22
|
+
const environmentSchema = z.strictObject({
|
|
23
|
+
databaseUrl: z.string(),
|
|
24
|
+
});
|
|
25
|
+
export const supaschemaConfigSchema = z.strictObject({
|
|
26
|
+
$schema: z.string().optional(),
|
|
27
|
+
adapter: z.enum(["supabase-auto", "postgres"]).default("supabase-auto"),
|
|
28
|
+
cascade: z.literal("never").default("never"),
|
|
29
|
+
destructiveChanges: z.enum(["hint-required", "block", "allow"]).default("hint-required"),
|
|
30
|
+
environments: z.record(z.string(), environmentSchema).default({}),
|
|
31
|
+
excludedGrantRoles: z.array(z.string()).default([]),
|
|
32
|
+
hints: hintsSchema,
|
|
33
|
+
idempotency: z.literal("required").default("required"),
|
|
34
|
+
lockTimeout: z.string().default("5s"),
|
|
35
|
+
migrationsDir: z.string().default("supabase/migrations"),
|
|
36
|
+
typesFile: z.string().default("database.types.ts"),
|
|
37
|
+
zodFile: z.string().default("database.zod.ts"),
|
|
38
|
+
normalize: z.enum(["off", "deparse"]).default("deparse"),
|
|
39
|
+
managedSchemas: z
|
|
40
|
+
.array(z.string())
|
|
41
|
+
.default([
|
|
42
|
+
"auth",
|
|
43
|
+
"storage",
|
|
44
|
+
"realtime",
|
|
45
|
+
"vault",
|
|
46
|
+
"extensions",
|
|
47
|
+
"cron",
|
|
48
|
+
"net",
|
|
49
|
+
"supabase_functions",
|
|
50
|
+
"graphql",
|
|
51
|
+
"graphql_public",
|
|
52
|
+
]),
|
|
53
|
+
postgresVersion: z.string().default("15+"),
|
|
54
|
+
renameDetection: z.enum(["hints-only", "off"]).default("hints-only"),
|
|
55
|
+
schemaPaths: z.array(z.string()).default(["supabase/schemas"]),
|
|
56
|
+
schemas: schemaFilterSchema,
|
|
57
|
+
statementTimeout: z.string().default("60s"),
|
|
58
|
+
transactionMode: z.enum(["per-migration", "per-statement"]).default("per-migration"),
|
|
59
|
+
validators: z.array(z.string()).default(["internal-parser"]),
|
|
60
|
+
});
|
|
61
|
+
export const defaultConfig = supaschemaConfigSchema.parse({});
|
|
62
|
+
export function resolveConfig(config) {
|
|
63
|
+
return supaschemaConfigSchema.parse(config ?? {});
|
|
64
|
+
}
|
|
65
|
+
const moduleConfigFiles = ["supaschema.config.mjs", "supaschema.config.js"];
|
|
66
|
+
export async function loadConfig(cwd = process.cwd(), explicitPath) {
|
|
67
|
+
if (explicitPath) {
|
|
68
|
+
const path = isAbsolute(explicitPath) ? explicitPath : resolve(cwd, explicitPath);
|
|
69
|
+
return loadConfigFile(path);
|
|
70
|
+
}
|
|
71
|
+
const fromJson = await tryLoadJsonConfig(resolve(cwd, "supaschema.config.json"));
|
|
72
|
+
if (fromJson) {
|
|
73
|
+
return fromJson;
|
|
74
|
+
}
|
|
75
|
+
for (const candidate of moduleConfigFiles) {
|
|
76
|
+
const fromModule = await tryLoadModuleConfig(resolve(cwd, candidate));
|
|
77
|
+
if (fromModule) {
|
|
78
|
+
return fromModule;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return defaultConfig;
|
|
82
|
+
}
|
|
83
|
+
async function loadConfigFile(path) {
|
|
84
|
+
if (path.endsWith(".mjs") || path.endsWith(".js")) {
|
|
85
|
+
const loaded = await tryLoadModuleConfig(path);
|
|
86
|
+
if (!loaded) {
|
|
87
|
+
throw new Error(`config module not found at ${path}`);
|
|
88
|
+
}
|
|
89
|
+
return loaded;
|
|
90
|
+
}
|
|
91
|
+
const raw = await readFile(path, "utf8");
|
|
92
|
+
return resolveConfig(JSON.parse(raw));
|
|
93
|
+
}
|
|
94
|
+
async function tryLoadJsonConfig(path) {
|
|
95
|
+
try {
|
|
96
|
+
const raw = await readFile(path, "utf8");
|
|
97
|
+
return resolveConfig(JSON.parse(raw));
|
|
98
|
+
}
|
|
99
|
+
catch (error) {
|
|
100
|
+
if (isFileMissing(error)) {
|
|
101
|
+
return undefined;
|
|
102
|
+
}
|
|
103
|
+
throw error;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
async function tryLoadModuleConfig(path) {
|
|
107
|
+
try {
|
|
108
|
+
const module = (await import(pathToFileURL(path).href));
|
|
109
|
+
return resolveConfig(module.default ?? {});
|
|
110
|
+
}
|
|
111
|
+
catch (error) {
|
|
112
|
+
if (isFileMissing(error) || isModuleMissing(error)) {
|
|
113
|
+
return undefined;
|
|
114
|
+
}
|
|
115
|
+
throw error;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
function isFileMissing(error) {
|
|
119
|
+
return error instanceof Error && "code" in error && error.code === "ENOENT";
|
|
120
|
+
}
|
|
121
|
+
function isModuleMissing(error) {
|
|
122
|
+
return error instanceof Error && "code" in error && error.code === "ERR_MODULE_NOT_FOUND";
|
|
123
|
+
}
|
|
124
|
+
const scaffoldConfig = {
|
|
125
|
+
$schema: "./node_modules/supaschema/config-schema.json",
|
|
126
|
+
...defaultConfig,
|
|
127
|
+
};
|
|
128
|
+
delete scaffoldConfig.environments;
|
|
129
|
+
export const defaultConfigFile = `${JSON.stringify(scaffoldConfig, null, 2)}\n`;
|
|
130
|
+
export function configJsonSchema() {
|
|
131
|
+
return z.toJSONSchema(supaschemaConfigSchema, { io: "input" });
|
|
132
|
+
}
|
package/dist/core.d.ts
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import type { SupaschemaConfig } from "./config.js";
|
|
2
|
+
export type DiagnosticSeverity = "info" | "warning" | "error";
|
|
3
|
+
export type ObjectKind = "schema" | "extension" | "type" | "domain" | "enum" | "sequence" | "table" | "foreign-data-wrapper" | "foreign-server" | "foreign-table" | "constraint" | "index" | "function" | "procedure" | "view" | "materialized-view" | "trigger" | "rls" | "policy" | "grant" | "default-privilege" | "comment";
|
|
4
|
+
export interface ObjectRef {
|
|
5
|
+
kind: ObjectKind;
|
|
6
|
+
name: string;
|
|
7
|
+
schema?: string;
|
|
8
|
+
signature?: string;
|
|
9
|
+
table?: string;
|
|
10
|
+
}
|
|
11
|
+
export interface Diagnostic {
|
|
12
|
+
code: string;
|
|
13
|
+
severity: DiagnosticSeverity;
|
|
14
|
+
message: string;
|
|
15
|
+
ref?: ObjectRef;
|
|
16
|
+
file?: string;
|
|
17
|
+
statement?: string;
|
|
18
|
+
hint?: string;
|
|
19
|
+
/** Schemas the failing statement references, for schema-filter scoping. */
|
|
20
|
+
schemas?: string[];
|
|
21
|
+
}
|
|
22
|
+
export interface SchemaObject {
|
|
23
|
+
ref: ObjectRef;
|
|
24
|
+
key: string;
|
|
25
|
+
sql: string;
|
|
26
|
+
normalizedSql: string;
|
|
27
|
+
hash: string;
|
|
28
|
+
ordinal: number;
|
|
29
|
+
file?: string;
|
|
30
|
+
dependencies: string[];
|
|
31
|
+
metadata: Record<string, unknown>;
|
|
32
|
+
}
|
|
33
|
+
export interface TableColumn {
|
|
34
|
+
name: string;
|
|
35
|
+
definition: string;
|
|
36
|
+
type?: string;
|
|
37
|
+
notNull?: boolean;
|
|
38
|
+
hasDefault?: boolean;
|
|
39
|
+
defaultExpression?: string;
|
|
40
|
+
identity?: boolean;
|
|
41
|
+
generated?: boolean;
|
|
42
|
+
hasInlineConstraint?: boolean;
|
|
43
|
+
}
|
|
44
|
+
export interface SchemaModel {
|
|
45
|
+
source: string;
|
|
46
|
+
objects: SchemaObject[];
|
|
47
|
+
diagnostics: Diagnostic[];
|
|
48
|
+
fingerprint: string;
|
|
49
|
+
formatVersion?: number;
|
|
50
|
+
}
|
|
51
|
+
export type MigrationOperationKind = "alter" | "create" | "replace" | "drop" | "rename";
|
|
52
|
+
export interface MigrationOperation {
|
|
53
|
+
kind: MigrationOperationKind;
|
|
54
|
+
ref: ObjectRef;
|
|
55
|
+
key: string;
|
|
56
|
+
before?: SchemaObject;
|
|
57
|
+
after?: SchemaObject;
|
|
58
|
+
destructive: boolean;
|
|
59
|
+
blocked: boolean;
|
|
60
|
+
diagnostics: Diagnostic[];
|
|
61
|
+
metadata: Record<string, unknown>;
|
|
62
|
+
}
|
|
63
|
+
export interface MigrationPlan {
|
|
64
|
+
from: string;
|
|
65
|
+
to: string;
|
|
66
|
+
operations: MigrationOperation[];
|
|
67
|
+
diagnostics: Diagnostic[];
|
|
68
|
+
fingerprint: string;
|
|
69
|
+
fromFingerprint: string;
|
|
70
|
+
toFingerprint: string;
|
|
71
|
+
}
|
|
72
|
+
export interface RenameHint {
|
|
73
|
+
from: string;
|
|
74
|
+
to: string;
|
|
75
|
+
}
|
|
76
|
+
export interface SupaschemaHints {
|
|
77
|
+
destructive?: string[];
|
|
78
|
+
renames?: RenameHint[];
|
|
79
|
+
}
|
|
80
|
+
export interface ExtractOptions {
|
|
81
|
+
config?: Partial<SupaschemaConfig>;
|
|
82
|
+
cwd?: string;
|
|
83
|
+
}
|
|
84
|
+
export interface RenderOptions {
|
|
85
|
+
config?: Partial<SupaschemaConfig>;
|
|
86
|
+
includeHeader?: boolean;
|
|
87
|
+
version?: string;
|
|
88
|
+
}
|
|
89
|
+
export interface CheckOptions {
|
|
90
|
+
config?: Partial<SupaschemaConfig>;
|
|
91
|
+
cwd?: string;
|
|
92
|
+
parse?: boolean;
|
|
93
|
+
}
|
|
94
|
+
export interface VerifyMigrationOptions {
|
|
95
|
+
databaseUrl: string;
|
|
96
|
+
from: string;
|
|
97
|
+
to: string;
|
|
98
|
+
migrationPath: string;
|
|
99
|
+
cwd?: string;
|
|
100
|
+
config?: Partial<SupaschemaConfig>;
|
|
101
|
+
ensureRoles?: boolean;
|
|
102
|
+
/**
|
|
103
|
+
* Stub Supabase-provisioned surfaces (auth schema helpers, cron schema) in
|
|
104
|
+
* the temporary databases so real-world trees apply against bare
|
|
105
|
+
* PostgreSQL. Defaults to true under adapter "supabase-auto".
|
|
106
|
+
*/
|
|
107
|
+
ensureEnvironment?: boolean;
|
|
108
|
+
/**
|
|
109
|
+
* Keep the temporary databases after the run and report their names —
|
|
110
|
+
* a failed verify leaves its evidence inspectable instead of dropped.
|
|
111
|
+
*/
|
|
112
|
+
keepDatabases?: boolean;
|
|
113
|
+
}
|
|
114
|
+
export type { SupaschemaConfig } from "./config.js";
|
|
115
|
+
//# sourceMappingURL=core.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../src/core.ts"],"names":[],"mappings":"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"}
|
package/dist/core.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/corpus.d.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { Diagnostic } from "./core.js";
|
|
2
|
+
export interface CorpusOptions {
|
|
3
|
+
corpusDir: string;
|
|
4
|
+
databaseUrl: string;
|
|
5
|
+
}
|
|
6
|
+
export interface CorpusReport {
|
|
7
|
+
appliedMigrations: string[];
|
|
8
|
+
driftOperations: number;
|
|
9
|
+
idempotent: boolean;
|
|
10
|
+
reconvergenceResidual: string[];
|
|
11
|
+
stages: string[];
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* The corpus oracle: replay a migrations corpus into a disposable database
|
|
15
|
+
* (an independently-evolved, catalog-noisy state no fixture reconstruction
|
|
16
|
+
* produces), diff it against the declarative tree, apply the rendered
|
|
17
|
+
* reconciliation twice, and require the re-diff to converge to zero. Unlike
|
|
18
|
+
* verify — which compares two databases built from the same models — every
|
|
19
|
+
* comparison here crosses lanes, so symmetric modeling errors fail loudly.
|
|
20
|
+
*/
|
|
21
|
+
export declare function runCorpus(options: CorpusOptions): Promise<{
|
|
22
|
+
diagnostics: Diagnostic[];
|
|
23
|
+
report: CorpusReport;
|
|
24
|
+
}>;
|
|
25
|
+
export declare function renderCorpusReport(report: CorpusReport): string;
|
|
26
|
+
//# sourceMappingURL=corpus.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"corpus.d.ts","sourceRoot":"","sources":["../src/corpus.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,UAAU,EAAoB,MAAM,WAAW,CAAC;AAc9D,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,YAAY;IAC3B,iBAAiB,EAAE,MAAM,EAAE,CAAC;IAC5B,eAAe,EAAE,MAAM,CAAC;IACxB,UAAU,EAAE,OAAO,CAAC;IACpB,qBAAqB,EAAE,MAAM,EAAE,CAAC;IAChC,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAID;;;;;;;GAOG;AACH,wBAAsB,SAAS,CAC7B,OAAO,EAAE,aAAa,GACrB,OAAO,CAAC;IAAE,WAAW,EAAE,UAAU,EAAE,CAAC;IAAC,MAAM,EAAE,YAAY,CAAA;CAAE,CAAC,CAgH9D;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,CAM/D"}
|