@rehearsal-db/core 0.1.0-beta.15 → 0.1.0-beta.16
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/CHANGELOG.md +34 -1
- package/dist/package.json +10 -9
- package/dist/src/baseline/privacy_contract.d.mts +147 -0
- package/dist/src/baseline/privacy_contract.mjs +2 -0
- package/dist/src/baseline/privacy_dependency_graph.d.mts +7 -0
- package/dist/src/baseline/privacy_dependency_graph.mjs +110 -0
- package/dist/src/baseline/privacy_engine.d.mts +5 -162
- package/dist/src/baseline/privacy_engine.mjs +4 -1162
- package/dist/src/baseline/privacy_key.d.mts +7 -0
- package/dist/src/baseline/privacy_key.mjs +42 -0
- package/dist/src/baseline/privacy_pipeline.d.mts +7 -0
- package/dist/src/baseline/privacy_pipeline.mjs +127 -0
- package/dist/src/baseline/privacy_policy.d.mts +6 -0
- package/dist/src/baseline/privacy_policy.mjs +237 -0
- package/dist/src/baseline/privacy_recipe_validation.d.mts +5 -0
- package/dist/src/baseline/privacy_recipe_validation.mjs +289 -0
- package/dist/src/baseline/privacy_rule_registry.d.mts +18 -0
- package/dist/src/baseline/privacy_rule_registry.mjs +143 -0
- package/dist/src/baseline/privacy_transforms.d.mts +18 -0
- package/dist/src/baseline/privacy_transforms.mjs +142 -0
- package/dist/src/baseline/privacy_validation_shared.d.mts +31 -0
- package/dist/src/baseline/privacy_validation_shared.mjs +127 -0
- package/dist/src/cli/application_command_handlers.d.mts +8 -0
- package/dist/src/cli/application_command_handlers.mjs +52 -0
- package/dist/src/cli/arguments.d.mts +0 -5
- package/dist/src/cli/arguments.mjs +0 -7
- package/dist/src/cli/basic_command_handlers.d.mts +4 -0
- package/dist/src/cli/basic_command_handlers.mjs +56 -0
- package/dist/src/cli/cli_commands.d.mts +14 -0
- package/dist/src/cli/cli_commands.mjs +32 -0
- package/dist/src/cli/command_contract.d.mts +57 -0
- package/dist/src/cli/command_contract.mjs +39 -0
- package/dist/src/cli/command_output.d.mts +12 -0
- package/dist/src/cli/command_output.mjs +20 -0
- package/dist/src/cli/command_registry.d.mts +7 -0
- package/dist/src/cli/command_registry.mjs +14 -0
- package/dist/src/cli/guided.d.mts +3 -1
- package/dist/src/cli/guided.mjs +13 -7
- package/dist/src/cli/identity_command_handlers.d.mts +8 -0
- package/dist/src/cli/identity_command_handlers.mjs +43 -0
- package/dist/src/cli/init_command.d.mts +1 -1
- package/dist/src/cli/inspection_command_handlers.d.mts +3 -0
- package/dist/src/cli/inspection_command_handlers.mjs +79 -0
- package/dist/src/cli/project_command_handlers.d.mts +11 -0
- package/dist/src/cli/project_command_handlers.mjs +92 -0
- package/dist/src/cli/project_commands.d.mts +6 -4
- package/dist/src/cli/project_commands.mjs +6 -6
- package/dist/src/cli/rehearsal.d.mts +2 -2
- package/dist/src/cli/rehearsal.mjs +51 -567
- package/dist/src/cli/runtime_action_handlers.d.mts +12 -0
- package/dist/src/cli/runtime_action_handlers.mjs +201 -0
- package/dist/src/cli/runtime_commands.d.mts +7 -3
- package/dist/src/cli/runtime_commands.mjs +10 -8
- package/dist/src/cli/source_command_handlers.d.mts +8 -0
- package/dist/src/cli/source_command_handlers.mjs +62 -0
- package/dist/src/cli/source_commands.d.mts +5 -1
- package/dist/src/cli/source_commands.mjs +3 -1
- package/dist/src/identity/claim.d.mts +5 -144
- package/dist/src/identity/claim.mjs +4 -947
- package/dist/src/identity/claim_contract.d.mts +135 -0
- package/dist/src/identity/claim_contract.mjs +6 -0
- package/dist/src/identity/claim_executor.d.mts +10 -0
- package/dist/src/identity/claim_executor.mjs +358 -0
- package/dist/src/identity/claim_identity_lookup.d.mts +17 -0
- package/dist/src/identity/claim_identity_lookup.mjs +125 -0
- package/dist/src/identity/claim_plan.d.mts +8 -0
- package/dist/src/identity/claim_plan.mjs +61 -0
- package/dist/src/identity/claim_policy.d.mts +3 -0
- package/dist/src/identity/claim_policy.mjs +377 -0
- package/dist/src/identity/claim_sql.d.mts +10 -0
- package/dist/src/identity/claim_sql.mjs +46 -0
- package/dist/src/identity/claim_verification.d.mts +13 -0
- package/dist/src/identity/claim_verification.mjs +35 -0
- package/dist/src/index.d.mts +1 -1
- package/dist/src/project/configuration.d.mts +11 -179
- package/dist/src/project/configuration.mjs +7 -956
- package/dist/src/project/configuration_contract.d.mts +125 -0
- package/dist/src/project/configuration_contract.mjs +27 -0
- package/dist/src/project/configuration_discovery.d.mts +7 -0
- package/dist/src/project/configuration_discovery.mjs +37 -0
- package/dist/src/project/configuration_normalization.d.mts +107 -0
- package/dist/src/project/configuration_normalization.mjs +302 -0
- package/dist/src/project/configuration_rendering.d.mts +14 -0
- package/dist/src/project/configuration_rendering.mjs +224 -0
- package/dist/src/project/configuration_resolution.d.mts +125 -0
- package/dist/src/project/configuration_resolution.mjs +81 -0
- package/dist/src/project/configuration_schema.d.mts +22 -0
- package/dist/src/project/configuration_schema.mjs +160 -0
- package/dist/src/project/configuration_validation.d.mts +22 -0
- package/dist/src/project/configuration_validation.mjs +136 -0
- package/dist/src/project/project_detection.d.mts +14 -0
- package/dist/src/project/project_detection.mjs +47 -0
- package/dist/src/runtime/lifecycle_engine.d.mts +63 -0
- package/dist/src/runtime/lifecycle_engine.mjs +114 -0
- package/dist/src/runtime/plan.mjs +2 -1
- package/dist/src/targets/postgresql.mjs +142 -163
- package/dist/src/targets/supabase.mjs +142 -174
- package/docs/architecture.md +118 -3
- package/docs/releasing.md +8 -3
- package/docs/typescript.md +57 -10
- package/package.json +10 -9
- package/types/configuration.d.mts +5 -164
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/** Read-only readiness, support, planning, and inspection command handlers. */
|
|
2
|
+
import { collectRehearsalSupportReport } from "../project/support_report.mjs";
|
|
3
|
+
import { inspectRehearsalBaseline, inspectRehearsalMigrations, } from "../runtime/plan.mjs";
|
|
4
|
+
import { buildRuntimeStackPlan, runRuntimeStackDoctor, topologyCandidateSummary, } from "./runtime_commands.mjs";
|
|
5
|
+
import { renderBaseline, renderCandidates, renderDoctor, renderMigrations, renderPlan, renderSupportReport, } from "./renderers.mjs";
|
|
6
|
+
import { exactCommands, renderedCommand } from "./command_contract.mjs";
|
|
7
|
+
export const createInspectionCommandHandlers = () => [
|
|
8
|
+
exactCommands("doctor", ["doctor"], async ({ guided, flags, planOptions }) => {
|
|
9
|
+
const data = await runRuntimeStackDoctor(planOptions);
|
|
10
|
+
return renderedCommand({
|
|
11
|
+
data,
|
|
12
|
+
render: (result, verbosity) => renderDoctor(result, verbosity),
|
|
13
|
+
status: data.state === "READY" ? "success" : "not_ready",
|
|
14
|
+
...(data.state !== "READY" && !guided ? { exitCode: 1 } : {}),
|
|
15
|
+
});
|
|
16
|
+
}),
|
|
17
|
+
exactCommands("support", ["support"], async ({ planOptions }) => {
|
|
18
|
+
const data = await collectRehearsalSupportReport(planOptions, {
|
|
19
|
+
runDoctor: async (options) => {
|
|
20
|
+
const report = await runRuntimeStackDoctor(options);
|
|
21
|
+
const targetAliases = new Map();
|
|
22
|
+
const aliasFor = (name) => {
|
|
23
|
+
if (!targetAliases.has(name)) {
|
|
24
|
+
targetAliases.set(name, `runtime-${targetAliases.size + 1}`);
|
|
25
|
+
}
|
|
26
|
+
return targetAliases.get(name);
|
|
27
|
+
};
|
|
28
|
+
return {
|
|
29
|
+
...report,
|
|
30
|
+
checks: report.checks.map((check) => {
|
|
31
|
+
const separator = check.id.indexOf(":");
|
|
32
|
+
if (separator === -1)
|
|
33
|
+
return check;
|
|
34
|
+
const target = check.id.slice(0, separator);
|
|
35
|
+
const alias = aliasFor(target);
|
|
36
|
+
return {
|
|
37
|
+
...check,
|
|
38
|
+
id: `${alias}:${check.id.slice(separator + 1)}`,
|
|
39
|
+
label: check.label.replace(`${target}:`, `${alias}:`),
|
|
40
|
+
};
|
|
41
|
+
}),
|
|
42
|
+
};
|
|
43
|
+
},
|
|
44
|
+
});
|
|
45
|
+
return renderedCommand({
|
|
46
|
+
data,
|
|
47
|
+
render: (result) => renderSupportReport(result),
|
|
48
|
+
});
|
|
49
|
+
}),
|
|
50
|
+
{
|
|
51
|
+
id: "explain",
|
|
52
|
+
matches: ({ command, flags }) => command === "explain" || (command === "run" && flags.dryRun),
|
|
53
|
+
handle: async ({ planOptions }) => {
|
|
54
|
+
const data = await buildRuntimeStackPlan(planOptions);
|
|
55
|
+
return renderedCommand({
|
|
56
|
+
data,
|
|
57
|
+
render: (result, verbosity) => renderPlan(result, verbosity),
|
|
58
|
+
});
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
exactCommands("inspect-baseline", ["inspect baseline"], async ({ planOptions }) => {
|
|
62
|
+
const data = await inspectRehearsalBaseline(planOptions);
|
|
63
|
+
return renderedCommand({ data, render: renderBaseline });
|
|
64
|
+
}),
|
|
65
|
+
exactCommands("inspect-migrations", ["inspect migrations"], async ({ planOptions }) => {
|
|
66
|
+
const data = await inspectRehearsalMigrations(planOptions);
|
|
67
|
+
return renderedCommand({
|
|
68
|
+
data,
|
|
69
|
+
render: (result, verbosity) => renderMigrations(result, verbosity),
|
|
70
|
+
});
|
|
71
|
+
}),
|
|
72
|
+
exactCommands("candidates", ["candidates"], async ({ planOptions }) => {
|
|
73
|
+
const { topology: _topology, ...data } = await topologyCandidateSummary(planOptions);
|
|
74
|
+
return renderedCommand({
|
|
75
|
+
data,
|
|
76
|
+
render: (result, verbosity) => renderCandidates(result, verbosity),
|
|
77
|
+
});
|
|
78
|
+
}),
|
|
79
|
+
];
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/** Project setup, baseline creation, privacy-key, and cleanup command handlers. */
|
|
2
|
+
import type { CommandDefinition } from "./command_contract.mjs";
|
|
3
|
+
import type { createProjectCommands } from "./project_commands.mjs";
|
|
4
|
+
type ProjectCommands = ReturnType<typeof createProjectCommands>;
|
|
5
|
+
export declare const createProjectCommandHandlers: ({ projectRoot, runSetup, runBaselinePreparation, runCleanup, }: {
|
|
6
|
+
projectRoot: string;
|
|
7
|
+
runSetup: ProjectCommands["runSetup"];
|
|
8
|
+
runBaselinePreparation: ProjectCommands["runBaselinePreparation"];
|
|
9
|
+
runCleanup: ProjectCommands["runCleanup"];
|
|
10
|
+
}) => readonly CommandDefinition[];
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/** Project setup, baseline creation, privacy-key, and cleanup command handlers. */
|
|
2
|
+
import { relative } from "node:path";
|
|
3
|
+
import { createSyntheticBaselineFromFiles } from "../baseline/builder.mjs";
|
|
4
|
+
import { inspectBaselineInputFiles } from "../baseline/preparation.mjs";
|
|
5
|
+
import { createPrivacyKey } from "../baseline/privacy_engine.mjs";
|
|
6
|
+
import { formatCount } from "../shared/human_output.mjs";
|
|
7
|
+
import { runRehearsalInit } from "./init_command.mjs";
|
|
8
|
+
import { loadPreparationContext } from "./source_commands.mjs";
|
|
9
|
+
import { renderBaselinePreparation, renderCleanup, renderInit, renderSetup, } from "./renderers.mjs";
|
|
10
|
+
import { exactCommands, renderedCommand } from "./command_contract.mjs";
|
|
11
|
+
export const createProjectCommandHandlers = ({ projectRoot, runSetup, runBaselinePreparation, runCleanup, }) => [
|
|
12
|
+
exactCommands("setup", ["setup"], async ({ flags, planOptions, state }) => {
|
|
13
|
+
const data = await runSetup({ flags, planOptions, session: state });
|
|
14
|
+
return renderedCommand({
|
|
15
|
+
data,
|
|
16
|
+
render: () => renderSetup(data),
|
|
17
|
+
});
|
|
18
|
+
}),
|
|
19
|
+
exactCommands("init", ["init"], async ({ flags }) => {
|
|
20
|
+
const data = await runRehearsalInit({ projectRoot, flags });
|
|
21
|
+
return renderedCommand({
|
|
22
|
+
data,
|
|
23
|
+
render: (result) => renderInit(result),
|
|
24
|
+
});
|
|
25
|
+
}),
|
|
26
|
+
exactCommands("baseline-prepare", ["baseline prepare"], async ({ flags, planOptions, state }) => {
|
|
27
|
+
const data = await runBaselinePreparation({
|
|
28
|
+
flags,
|
|
29
|
+
planOptions,
|
|
30
|
+
session: state,
|
|
31
|
+
});
|
|
32
|
+
return renderedCommand({
|
|
33
|
+
data,
|
|
34
|
+
render: (result) => renderBaselinePreparation(result, flags),
|
|
35
|
+
});
|
|
36
|
+
}),
|
|
37
|
+
exactCommands("baseline-create", ["baseline create"], async ({ flags, planOptions }) => {
|
|
38
|
+
if (!flags.recordsPath || !flags.ledgerPath) {
|
|
39
|
+
throw new Error("baseline create requires --records and --ledger input paths.");
|
|
40
|
+
}
|
|
41
|
+
const baselineInput = {
|
|
42
|
+
...planOptions,
|
|
43
|
+
recordsPath: flags.recordsPath,
|
|
44
|
+
ledgerPath: flags.ledgerPath,
|
|
45
|
+
...(flags.assetsPath === undefined
|
|
46
|
+
? {}
|
|
47
|
+
: { assetsPath: flags.assetsPath }),
|
|
48
|
+
};
|
|
49
|
+
await inspectBaselineInputFiles(baselineInput);
|
|
50
|
+
const data = await createSyntheticBaselineFromFiles(baselineInput);
|
|
51
|
+
return renderedCommand({
|
|
52
|
+
data,
|
|
53
|
+
render: (baseline) => [
|
|
54
|
+
`Activated synthetic baseline ${baseline.generationId}: ${formatCount(baseline.rowCount, "row")} across ${formatCount(baseline.tableCount, "table")}; ${formatCount(baseline.migrationCount, "migration")} through ${baseline.migrationCutoff}.`,
|
|
55
|
+
"",
|
|
56
|
+
flags.guided
|
|
57
|
+
? "Next: choose Run a rehearsal when you are ready."
|
|
58
|
+
: "Next: run rehearsal doctor to check readiness.",
|
|
59
|
+
].join("\n"),
|
|
60
|
+
});
|
|
61
|
+
}),
|
|
62
|
+
exactCommands("privacy-key", ["privacy key"], async ({ flags, planOptions }) => {
|
|
63
|
+
const { loaded } = await loadPreparationContext(planOptions);
|
|
64
|
+
if (!loaded.paths.privacyKey) {
|
|
65
|
+
throw new Error("No config.preparation.privacyKey is configured.");
|
|
66
|
+
}
|
|
67
|
+
const privacyKeyPath = loaded.paths.privacyKey;
|
|
68
|
+
const data = flags.write
|
|
69
|
+
? {
|
|
70
|
+
mode: "written",
|
|
71
|
+
path: relative(loaded.projectRoot, privacyKeyPath),
|
|
72
|
+
...(await createPrivacyKey(privacyKeyPath)),
|
|
73
|
+
}
|
|
74
|
+
: {
|
|
75
|
+
mode: "preview",
|
|
76
|
+
path: relative(loaded.projectRoot, privacyKeyPath),
|
|
77
|
+
};
|
|
78
|
+
return renderedCommand({
|
|
79
|
+
data,
|
|
80
|
+
render: (result) => result.mode === "preview"
|
|
81
|
+
? `PRIVACY KEY — PREVIEW\n\nWould create ${result.path} with owner-only permissions.\nNothing was written. Rerun with --write after reviewing the path.`
|
|
82
|
+
: `Created owner-only privacy key at ${result.path}.\nFingerprint: ${result.fingerprint}\nThe key is excluded from source control and must not be shared.`,
|
|
83
|
+
});
|
|
84
|
+
}),
|
|
85
|
+
exactCommands("cleanup", ["cleanup"], async ({ flags, planOptions, state }) => {
|
|
86
|
+
const data = await runCleanup({ flags, planOptions, session: state });
|
|
87
|
+
return renderedCommand({
|
|
88
|
+
data,
|
|
89
|
+
render: () => renderCleanup(data),
|
|
90
|
+
});
|
|
91
|
+
}),
|
|
92
|
+
];
|
|
@@ -3,6 +3,7 @@ import { summarizeBaselinePreparation } from "../baseline/preparation.mjs";
|
|
|
3
3
|
import type { RehearsalConfigPathOptions } from "../project/configuration.mjs";
|
|
4
4
|
import type { RehearsalCleanupPlan } from "../runtime/cleanup.mjs";
|
|
5
5
|
import type { RehearsalCliFlags } from "./arguments.mjs";
|
|
6
|
+
import type { CliSessionState } from "./command_contract.mjs";
|
|
6
7
|
type CleanupStackPlan = Readonly<{
|
|
7
8
|
digest: string;
|
|
8
9
|
targets: readonly Readonly<{
|
|
@@ -20,6 +21,7 @@ type RunManager = (input: {
|
|
|
20
21
|
interface ProjectCommandInput {
|
|
21
22
|
readonly flags: RehearsalCliFlags;
|
|
22
23
|
readonly planOptions: RehearsalConfigPathOptions;
|
|
24
|
+
readonly session?: CliSessionState;
|
|
23
25
|
}
|
|
24
26
|
export declare const createProjectCommands: ({ projectRoot, runManager, }: {
|
|
25
27
|
projectRoot: string;
|
|
@@ -147,11 +149,11 @@ export declare const createProjectCommands: ({ projectRoot, runManager, }: {
|
|
|
147
149
|
runtimeAdapter: string | null;
|
|
148
150
|
}>;
|
|
149
151
|
}>;
|
|
150
|
-
plan: import("../identity/
|
|
152
|
+
plan: import("../identity/claim_contract.mjs").IdentityClaimPlan;
|
|
151
153
|
}>;
|
|
152
154
|
planRuntimeStackCleanup: ({ flags, planOptions, }: ProjectCommandInput) => Promise<RehearsalCleanupPlan | CleanupStackPlan>;
|
|
153
|
-
runBaselinePreparation: ({ flags, planOptions, }: ProjectCommandInput) => Promise<ReturnType<typeof summarizeBaselinePreparation>>;
|
|
154
|
-
runCleanup: ({ flags, planOptions, }: ProjectCommandInput) => Promise<unknown>;
|
|
155
|
-
runSetup: ({ flags, planOptions, }: ProjectCommandInput) => Promise<unknown>;
|
|
155
|
+
runBaselinePreparation: ({ flags, planOptions, session, }: ProjectCommandInput) => Promise<ReturnType<typeof summarizeBaselinePreparation>>;
|
|
156
|
+
runCleanup: ({ flags, planOptions, session, }: ProjectCommandInput) => Promise<unknown>;
|
|
157
|
+
runSetup: ({ flags, planOptions, session, }: ProjectCommandInput) => Promise<unknown>;
|
|
156
158
|
}>;
|
|
157
159
|
export {};
|
|
@@ -10,14 +10,14 @@ import { runRehearsalDoctor } from "../runtime/plan.mjs";
|
|
|
10
10
|
import { loadRuntimeTopology } from "../runtime/topology.mjs";
|
|
11
11
|
const isCleanupStackPlan = (plan) => "targets" in plan;
|
|
12
12
|
export const createProjectCommands = ({ projectRoot, runManager, }) => {
|
|
13
|
-
const runSetup = async ({ flags, planOptions, }) => {
|
|
13
|
+
const runSetup = async ({ flags, planOptions, session, }) => {
|
|
14
14
|
const setupTarget = flags.target === "supabase" || flags.target === "postgresql"
|
|
15
15
|
? flags.target
|
|
16
16
|
: undefined;
|
|
17
17
|
if (flags.target !== undefined && setupTarget === undefined) {
|
|
18
18
|
throw new Error("--target must be supabase or postgresql.");
|
|
19
19
|
}
|
|
20
|
-
const plan =
|
|
20
|
+
const plan = session?.setupPlan ??
|
|
21
21
|
(await planRehearsalSetup({
|
|
22
22
|
projectRoot,
|
|
23
23
|
...(planOptions.configPath === undefined
|
|
@@ -49,11 +49,11 @@ export const createProjectCommands = ({ projectRoot, runManager, }) => {
|
|
|
49
49
|
].join("\n"),
|
|
50
50
|
};
|
|
51
51
|
};
|
|
52
|
-
const runBaselinePreparation = async ({ flags, planOptions, }) => {
|
|
52
|
+
const runBaselinePreparation = async ({ flags, planOptions, session, }) => {
|
|
53
53
|
if (!flags.recordsPath || !flags.ledgerPath) {
|
|
54
54
|
throw new Error("baseline prepare requires --records and --ledger input paths.");
|
|
55
55
|
}
|
|
56
|
-
const plan =
|
|
56
|
+
const plan = session?.preparationPlan ??
|
|
57
57
|
(await planBaselinePreparation({
|
|
58
58
|
...planOptions,
|
|
59
59
|
recordsPath: flags.recordsPath,
|
|
@@ -98,8 +98,8 @@ export const createProjectCommands = ({ projectRoot, runManager, }) => {
|
|
|
98
98
|
targets,
|
|
99
99
|
};
|
|
100
100
|
};
|
|
101
|
-
const runCleanup = async ({ flags, planOptions, }) => {
|
|
102
|
-
const plan =
|
|
101
|
+
const runCleanup = async ({ flags, planOptions, session, }) => {
|
|
102
|
+
const plan = session?.cleanupPlan ??
|
|
103
103
|
(await planRuntimeStackCleanup({ flags, planOptions }));
|
|
104
104
|
if (!flags.write)
|
|
105
105
|
return { mode: "preview", plan };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
* Purpose:
|
|
4
|
-
*
|
|
3
|
+
* Purpose: Parse one CLI request, protect project mutations, and delegate to
|
|
4
|
+
* the typed command registry shared by scripted and guided flows.
|
|
5
5
|
* Run: `npm run rehearsal -- doctor` or `npm run rehearsal -- explain`.
|
|
6
6
|
*/
|
|
7
7
|
export {};
|