@rehearsal-db/core 0.1.0-beta.14 → 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.
Files changed (236) hide show
  1. package/CHANGELOG.md +51 -1
  2. package/README.md +1 -0
  3. package/dist/package.json +101 -0
  4. package/dist/scripts/install/create_root_config.d.mts +3 -0
  5. package/dist/scripts/install/create_root_config.mjs +13 -0
  6. package/dist/scripts/runtime/manage_database.d.mts +6 -0
  7. package/{scripts → dist/scripts}/runtime/manage_database.mjs +6 -8
  8. package/dist/src/application/session.d.mts +96 -0
  9. package/dist/src/application/session.mjs +380 -0
  10. package/dist/src/baseline/artifact.d.mts +119 -0
  11. package/dist/src/baseline/artifact.mjs +522 -0
  12. package/dist/src/baseline/builder.d.mts +19 -0
  13. package/dist/src/baseline/builder.mjs +142 -0
  14. package/dist/src/baseline/input_discovery.d.mts +13 -0
  15. package/dist/src/baseline/input_discovery.mjs +149 -0
  16. package/dist/src/baseline/policy_review.d.mts +56 -0
  17. package/dist/src/baseline/policy_review.mjs +73 -0
  18. package/dist/src/baseline/preparation.d.mts +63 -0
  19. package/dist/src/baseline/preparation.mjs +295 -0
  20. package/dist/src/baseline/privacy_contract.d.mts +147 -0
  21. package/dist/src/baseline/privacy_contract.mjs +2 -0
  22. package/dist/src/baseline/privacy_dependency_graph.d.mts +7 -0
  23. package/dist/src/baseline/privacy_dependency_graph.mjs +110 -0
  24. package/dist/src/baseline/privacy_engine.d.mts +5 -0
  25. package/dist/src/baseline/privacy_engine.mjs +4 -0
  26. package/dist/src/baseline/privacy_key.d.mts +7 -0
  27. package/dist/src/baseline/privacy_key.mjs +42 -0
  28. package/dist/src/baseline/privacy_pipeline.d.mts +7 -0
  29. package/dist/src/baseline/privacy_pipeline.mjs +127 -0
  30. package/dist/src/baseline/privacy_policy.d.mts +6 -0
  31. package/dist/src/baseline/privacy_policy.mjs +237 -0
  32. package/dist/src/baseline/privacy_recipe_validation.d.mts +5 -0
  33. package/dist/src/baseline/privacy_recipe_validation.mjs +289 -0
  34. package/dist/src/baseline/privacy_rule_registry.d.mts +18 -0
  35. package/dist/src/baseline/privacy_rule_registry.mjs +143 -0
  36. package/dist/src/baseline/privacy_structured_json.d.mts +66 -0
  37. package/dist/src/baseline/privacy_structured_json.mjs +464 -0
  38. package/dist/src/baseline/privacy_transforms.d.mts +18 -0
  39. package/dist/src/baseline/privacy_transforms.mjs +142 -0
  40. package/dist/src/baseline/privacy_validation_shared.d.mts +31 -0
  41. package/dist/src/baseline/privacy_validation_shared.mjs +127 -0
  42. package/dist/src/baseline/sanitization_policy.d.mts +69 -0
  43. package/dist/src/baseline/sanitization_policy.mjs +227 -0
  44. package/dist/src/baseline/schema_snapshot.d.mts +19 -0
  45. package/dist/src/baseline/schema_snapshot.mjs +79 -0
  46. package/dist/src/cli/application_command_handlers.d.mts +8 -0
  47. package/dist/src/cli/application_command_handlers.mjs +52 -0
  48. package/dist/src/cli/arguments.d.mts +38 -0
  49. package/dist/src/cli/arguments.mjs +128 -0
  50. package/dist/src/cli/basic_command_handlers.d.mts +4 -0
  51. package/dist/src/cli/basic_command_handlers.mjs +56 -0
  52. package/dist/src/cli/cli_commands.d.mts +14 -0
  53. package/dist/src/cli/cli_commands.mjs +32 -0
  54. package/dist/src/cli/command_contract.d.mts +57 -0
  55. package/dist/src/cli/command_contract.mjs +39 -0
  56. package/dist/src/cli/command_output.d.mts +12 -0
  57. package/dist/src/cli/command_output.mjs +20 -0
  58. package/dist/src/cli/command_registry.d.mts +7 -0
  59. package/dist/src/cli/command_registry.mjs +14 -0
  60. package/dist/src/cli/guided.d.mts +53 -0
  61. package/dist/src/cli/guided.mjs +719 -0
  62. package/dist/src/cli/identity_command_handlers.d.mts +8 -0
  63. package/dist/src/cli/identity_command_handlers.mjs +43 -0
  64. package/dist/src/cli/init_command.d.mts +21 -0
  65. package/dist/src/cli/init_command.mjs +90 -0
  66. package/dist/src/cli/inspection_command_handlers.d.mts +3 -0
  67. package/dist/src/cli/inspection_command_handlers.mjs +79 -0
  68. package/dist/src/cli/project_command_handlers.d.mts +11 -0
  69. package/dist/src/cli/project_command_handlers.mjs +92 -0
  70. package/dist/src/cli/project_commands.d.mts +159 -0
  71. package/dist/src/cli/project_commands.mjs +183 -0
  72. package/dist/src/cli/rehearsal.d.mts +7 -0
  73. package/dist/src/cli/rehearsal.mjs +190 -0
  74. package/dist/src/cli/renderers.d.mts +299 -0
  75. package/dist/src/cli/renderers.mjs +554 -0
  76. package/dist/src/cli/runtime_action_handlers.d.mts +12 -0
  77. package/dist/src/cli/runtime_action_handlers.mjs +201 -0
  78. package/dist/src/cli/runtime_commands.d.mts +269 -0
  79. package/dist/src/cli/runtime_commands.mjs +601 -0
  80. package/dist/src/cli/source_command_handlers.d.mts +8 -0
  81. package/dist/src/cli/source_command_handlers.mjs +62 -0
  82. package/dist/src/cli/source_commands.d.mts +436 -0
  83. package/dist/src/cli/source_commands.mjs +301 -0
  84. package/dist/src/cli/terminal.d.mts +59 -0
  85. package/dist/src/cli/terminal.mjs +230 -0
  86. package/dist/src/identity/claim.d.mts +5 -0
  87. package/dist/src/identity/claim.mjs +4 -0
  88. package/dist/src/identity/claim_contract.d.mts +135 -0
  89. package/dist/src/identity/claim_contract.mjs +6 -0
  90. package/dist/src/identity/claim_executor.d.mts +10 -0
  91. package/dist/src/identity/claim_executor.mjs +358 -0
  92. package/dist/src/identity/claim_identity_lookup.d.mts +17 -0
  93. package/dist/src/identity/claim_identity_lookup.mjs +125 -0
  94. package/dist/src/identity/claim_plan.d.mts +8 -0
  95. package/dist/src/identity/claim_plan.mjs +61 -0
  96. package/dist/src/identity/claim_policy.d.mts +3 -0
  97. package/dist/src/identity/claim_policy.mjs +377 -0
  98. package/dist/src/identity/claim_sql.d.mts +10 -0
  99. package/dist/src/identity/claim_sql.mjs +46 -0
  100. package/dist/src/identity/claim_verification.d.mts +13 -0
  101. package/dist/src/identity/claim_verification.mjs +35 -0
  102. package/dist/src/identity/provider_configuration.d.mts +37 -0
  103. package/dist/src/identity/provider_configuration.mjs +132 -0
  104. package/dist/src/identity/storage.d.mts +21 -0
  105. package/dist/src/identity/storage.mjs +122 -0
  106. package/dist/src/index.d.mts +4 -0
  107. package/dist/src/index.mjs +3 -0
  108. package/dist/src/project/configuration.d.mts +13 -0
  109. package/dist/src/project/configuration.mjs +9 -0
  110. package/dist/src/project/configuration_contract.d.mts +125 -0
  111. package/dist/src/project/configuration_contract.mjs +27 -0
  112. package/dist/src/project/configuration_discovery.d.mts +7 -0
  113. package/dist/src/project/configuration_discovery.mjs +37 -0
  114. package/dist/src/project/configuration_normalization.d.mts +107 -0
  115. package/dist/src/project/configuration_normalization.mjs +302 -0
  116. package/dist/src/project/configuration_rendering.d.mts +14 -0
  117. package/dist/src/project/configuration_rendering.mjs +224 -0
  118. package/dist/src/project/configuration_resolution.d.mts +125 -0
  119. package/dist/src/project/configuration_resolution.mjs +81 -0
  120. package/dist/src/project/configuration_schema.d.mts +22 -0
  121. package/dist/src/project/configuration_schema.mjs +160 -0
  122. package/dist/src/project/configuration_validation.d.mts +22 -0
  123. package/dist/src/project/configuration_validation.mjs +136 -0
  124. package/dist/src/project/install_scaffold.d.mts +42 -0
  125. package/dist/src/project/install_scaffold.mjs +263 -0
  126. package/dist/src/project/project_detection.d.mts +14 -0
  127. package/dist/src/project/project_detection.mjs +47 -0
  128. package/dist/src/project/setup.d.mts +87 -0
  129. package/dist/src/project/setup.mjs +414 -0
  130. package/dist/src/project/support_report.d.mts +88 -0
  131. package/dist/src/project/support_report.mjs +83 -0
  132. package/dist/src/runtime/cleanup.d.mts +85 -0
  133. package/dist/src/runtime/cleanup.mjs +311 -0
  134. package/dist/src/runtime/lifecycle_engine.d.mts +63 -0
  135. package/dist/src/runtime/lifecycle_engine.mjs +114 -0
  136. package/dist/src/runtime/migration_history.d.mts +51 -0
  137. package/dist/src/runtime/migration_history.mjs +170 -0
  138. package/dist/src/runtime/plan.d.mts +134 -0
  139. package/dist/src/runtime/plan.mjs +637 -0
  140. package/dist/src/runtime/policy.d.mts +66 -0
  141. package/dist/src/runtime/policy.mjs +369 -0
  142. package/dist/src/runtime/restore.d.mts +22 -0
  143. package/dist/src/runtime/restore.mjs +276 -0
  144. package/dist/src/runtime/service_environment.d.mts +11 -0
  145. package/dist/src/runtime/service_environment.mjs +58 -0
  146. package/dist/src/runtime/topology.d.mts +51 -0
  147. package/dist/src/runtime/topology.mjs +128 -0
  148. package/dist/src/shared/diagnostics.d.mts +97 -0
  149. package/dist/src/shared/diagnostics.mjs +170 -0
  150. package/dist/src/shared/human_output.d.mts +2 -0
  151. package/{src → dist/src}/shared/human_output.mjs +1 -3
  152. package/dist/src/shared/node_runtime.d.mts +14 -0
  153. package/dist/src/shared/node_runtime.mjs +25 -0
  154. package/dist/src/shared/operation_guard.d.mts +22 -0
  155. package/dist/src/shared/operation_guard.mjs +150 -0
  156. package/dist/src/shared/process_environment.d.mts +15 -0
  157. package/dist/src/shared/process_environment.mjs +50 -0
  158. package/dist/src/source/access.d.mts +165 -0
  159. package/dist/src/source/access.mjs +602 -0
  160. package/dist/src/source/asset_transfer.d.mts +27 -0
  161. package/dist/src/source/asset_transfer.mjs +202 -0
  162. package/dist/src/source/baseline.d.mts +66 -0
  163. package/dist/src/source/baseline.mjs +372 -0
  164. package/dist/src/source/external_reader.d.mts +42 -0
  165. package/dist/src/source/external_reader.mjs +278 -0
  166. package/dist/src/source/postgresql_access.d.mts +86 -0
  167. package/dist/src/source/postgresql_access.mjs +454 -0
  168. package/dist/src/source/privacy_paths.d.mts +10 -0
  169. package/dist/src/source/privacy_paths.mjs +27 -0
  170. package/dist/src/targets/driver.d.mts +2 -0
  171. package/dist/src/targets/driver.mjs +13 -0
  172. package/dist/src/targets/postgresql.d.mts +5 -0
  173. package/dist/src/targets/postgresql.mjs +620 -0
  174. package/dist/src/targets/supabase.d.mts +8 -0
  175. package/dist/src/targets/supabase.mjs +627 -0
  176. package/dist/src/targets/supabase_environment.d.mts +49 -0
  177. package/dist/src/targets/supabase_environment.mjs +162 -0
  178. package/dist/src/targets/target.d.mts +33 -0
  179. package/dist/src/targets/target.mjs +39 -0
  180. package/docs/README.md +1 -0
  181. package/docs/architecture.md +133 -10
  182. package/docs/configuration.md +9 -3
  183. package/docs/index.md +1 -0
  184. package/docs/releasing.md +8 -3
  185. package/docs/typescript.md +134 -0
  186. package/package.json +36 -29
  187. package/types/configuration.d.mts +5 -0
  188. package/scripts/install/create_root_config.mjs +0 -19
  189. package/src/README.md +0 -17
  190. package/src/application/session.mjs +0 -435
  191. package/src/baseline/artifact.mjs +0 -684
  192. package/src/baseline/builder.mjs +0 -164
  193. package/src/baseline/input_discovery.mjs +0 -155
  194. package/src/baseline/policy_review.mjs +0 -92
  195. package/src/baseline/preparation.mjs +0 -323
  196. package/src/baseline/privacy_engine.mjs +0 -1399
  197. package/src/baseline/privacy_structured_json.mjs +0 -554
  198. package/src/baseline/sanitization_policy.mjs +0 -299
  199. package/src/baseline/schema_snapshot.mjs +0 -113
  200. package/src/cli/arguments.mjs +0 -126
  201. package/src/cli/guided.mjs +0 -814
  202. package/src/cli/init_command.mjs +0 -94
  203. package/src/cli/rehearsal.mjs +0 -972
  204. package/src/cli/renderers.mjs +0 -638
  205. package/src/cli/runtime_commands.mjs +0 -707
  206. package/src/cli/source_commands.mjs +0 -355
  207. package/src/cli/terminal.mjs +0 -275
  208. package/src/identity/claim.mjs +0 -1165
  209. package/src/identity/provider_configuration.mjs +0 -177
  210. package/src/identity/storage.mjs +0 -165
  211. package/src/project/configuration.d.mts +0 -164
  212. package/src/project/configuration.mjs +0 -1337
  213. package/src/project/install_scaffold.mjs +0 -325
  214. package/src/project/setup.mjs +0 -474
  215. package/src/project/support_report.mjs +0 -105
  216. package/src/runtime/cleanup.mjs +0 -381
  217. package/src/runtime/migration_history.mjs +0 -220
  218. package/src/runtime/plan.mjs +0 -722
  219. package/src/runtime/policy.mjs +0 -438
  220. package/src/runtime/restore.mjs +0 -337
  221. package/src/runtime/service_environment.mjs +0 -82
  222. package/src/runtime/topology.mjs +0 -177
  223. package/src/shared/diagnostics.mjs +0 -207
  224. package/src/shared/node_runtime.mjs +0 -31
  225. package/src/shared/operation_guard.mjs +0 -162
  226. package/src/shared/process_environment.mjs +0 -68
  227. package/src/source/access.mjs +0 -798
  228. package/src/source/asset_transfer.mjs +0 -259
  229. package/src/source/baseline.mjs +0 -482
  230. package/src/source/external_reader.mjs +0 -368
  231. package/src/source/postgresql_access.mjs +0 -638
  232. package/src/source/privacy_paths.mjs +0 -38
  233. package/src/targets/postgresql.mjs +0 -808
  234. package/src/targets/supabase.mjs +0 -840
  235. package/src/targets/supabase_environment.mjs +0 -229
  236. package/src/targets/target.mjs +0 -66
@@ -0,0 +1,81 @@
1
+ /** Load a discovered config and resolve every owned path from the project root. */
2
+ import { basename, isAbsolute, join, relative, resolve } from "node:path";
3
+ import { pathToFileURL } from "node:url";
4
+ import { findRehearsalConfigPath, } from "./configuration_discovery.mjs";
5
+ import { normalizeRehearsalConfig } from "./configuration_normalization.mjs";
6
+ import { assertIdentifier } from "./configuration_validation.mjs";
7
+ export const loadRehearsalConfig = async ({ projectRoot = process.cwd(), configPath, } = {}) => {
8
+ const root = resolve(projectRoot);
9
+ const path = await findRehearsalConfigPath({
10
+ projectRoot: root,
11
+ ...(configPath === undefined ? {} : { configPath }),
12
+ });
13
+ const module = await import(`${pathToFileURL(path).href}?loaded=${Date.now()}`);
14
+ const config = normalizeRehearsalConfig(module.default);
15
+ const resolveOwnedPath = (value) => {
16
+ const resolved = resolve(root, value);
17
+ if (relative(root, resolved).startsWith("..")) {
18
+ throw new Error(`A Rehearsal path escaped the project root: ${value}.`);
19
+ }
20
+ return resolved;
21
+ };
22
+ const paths = Object.freeze({
23
+ artifactDirectory: resolveOwnedPath(config.baseline.artifactDirectory),
24
+ applicationEnvironment: resolveOwnedPath(config.application.environmentFile),
25
+ migrationDirectory: resolveOwnedPath((config.supabase ?? config.postgresql).migrationDirectory),
26
+ rehearsalConfig: config.supabase
27
+ ? resolveOwnedPath(config.supabase.rehearsalConfig)
28
+ : null,
29
+ runtimeWorkdir: resolveOwnedPath((config.supabase ?? config.postgresql).runtimeWorkdir),
30
+ serviceEnvironment: config.supabase?.serviceEnvironmentFile
31
+ ? resolveOwnedPath(config.supabase.serviceEnvironmentFile)
32
+ : null,
33
+ sanitizationPolicy: resolveOwnedPath(config.baseline.sanitizationPolicy),
34
+ sourcePolicy: config.preparation
35
+ ? resolveOwnedPath(config.preparation.sourcePolicy)
36
+ : null,
37
+ privacyKey: config.preparation
38
+ ? resolveOwnedPath(config.preparation.privacyKey)
39
+ : null,
40
+ runtimePolicy: config.runtimePolicy
41
+ ? resolveOwnedPath(config.runtimePolicy)
42
+ : null,
43
+ identityPolicy: config.identityPolicy
44
+ ? resolveOwnedPath(config.identityPolicy)
45
+ : null,
46
+ supabaseWorkdir: config.supabase
47
+ ? resolveOwnedPath(config.supabase.workdir)
48
+ : null,
49
+ runtimeAdapter: config.application.runtimeAdapter
50
+ ? resolveOwnedPath(config.application.runtimeAdapter)
51
+ : null,
52
+ });
53
+ if (basename(paths.artifactDirectory) !== ".rehearsal") {
54
+ throw new Error('config.baseline.artifactDirectory must resolve to a directory named ".rehearsal" so destructive reset and cleanup operations have an explicit safety boundary.');
55
+ }
56
+ const requiredRuntimeWorkdir = join(paths.artifactDirectory, "runtime");
57
+ if (paths.runtimeWorkdir !== requiredRuntimeWorkdir) {
58
+ throw new Error(`config.${config.runtime.target}.runtimeWorkdir must resolve to the runtime directory inside config.baseline.artifactDirectory.`);
59
+ }
60
+ const environmentRelativePath = relative(paths.artifactDirectory, paths.applicationEnvironment);
61
+ if (!environmentRelativePath ||
62
+ environmentRelativePath.startsWith("..") ||
63
+ isAbsolute(environmentRelativePath)) {
64
+ throw new Error("config.application.environmentFile must resolve to a file inside config.baseline.artifactDirectory.");
65
+ }
66
+ if (paths.privacyKey) {
67
+ const privacyKeyRelativePath = relative(paths.artifactDirectory, paths.privacyKey);
68
+ if (!privacyKeyRelativePath ||
69
+ privacyKeyRelativePath.startsWith("..") ||
70
+ isAbsolute(privacyKeyRelativePath)) {
71
+ throw new Error("config.preparation.privacyKey must resolve to a secret file inside config.baseline.artifactDirectory.");
72
+ }
73
+ }
74
+ assertIdentifier(config.runtime.projectId, "config.runtime.projectId");
75
+ return Object.freeze({
76
+ config,
77
+ configPath: path,
78
+ projectRoot: root,
79
+ paths,
80
+ });
81
+ };
@@ -0,0 +1,22 @@
1
+ /** Validate the raw object shape and known keys before applying defaults. */
2
+ import { type PlainObject } from "./configuration_validation.mjs";
3
+ export interface ValidatedConfigurationSchema {
4
+ root: PlainObject;
5
+ project: PlainObject;
6
+ runtime: PlainObject;
7
+ runtimeTarget: "supabase" | "postgresql";
8
+ supabase: PlainObject | null;
9
+ postgresql: PlainObject | null;
10
+ baseline: PlainObject;
11
+ containerRuntime: PlainObject;
12
+ cleanup: PlainObject;
13
+ preparation: PlainObject | null;
14
+ dependentTargets: PlainObject[];
15
+ application: PlainObject;
16
+ readiness: PlainObject | null;
17
+ httpProofs: PlainObject[];
18
+ safety: PlainObject;
19
+ verification: PlainObject;
20
+ authentication: PlainObject | null;
21
+ }
22
+ export declare const validateConfigurationSchema: (input: unknown) => ValidatedConfigurationSchema;
@@ -0,0 +1,160 @@
1
+ /** Validate the raw object shape and known keys before applying defaults. */
2
+ import { resolveRuntimeTarget } from "../targets/target.mjs";
3
+ import { REHEARSAL_CONFIG_VERSION } from "./configuration_contract.mjs";
4
+ import { assertKnownKeys, assertPlainObject, } from "./configuration_validation.mjs";
5
+ const assertObjectArray = (value, path) => {
6
+ if (!Array.isArray(value))
7
+ throw new Error(`${path} must be an array.`);
8
+ return value.map((entry, index) => assertPlainObject(entry, `${path}[${index}]`));
9
+ };
10
+ export const validateConfigurationSchema = (input) => {
11
+ const root = assertPlainObject(input, "config");
12
+ assertKnownKeys(root, [
13
+ "schemaVersion",
14
+ "project",
15
+ "supabase",
16
+ "postgresql",
17
+ "baseline",
18
+ "containerRuntime",
19
+ "cleanup",
20
+ "preparation",
21
+ "runtimePolicy",
22
+ "identityPolicy",
23
+ "dependentTargets",
24
+ "application",
25
+ "runtime",
26
+ "safety",
27
+ "verification",
28
+ ], "config");
29
+ if (root.schemaVersion !== REHEARSAL_CONFIG_VERSION) {
30
+ throw new Error(`Unsupported Rehearsal configuration version: ${String(root.schemaVersion)}. Expected ${REHEARSAL_CONFIG_VERSION}.`);
31
+ }
32
+ const project = assertPlainObject(root.project, "config.project");
33
+ assertKnownKeys(project, ["name"], "config.project");
34
+ const runtime = assertPlainObject(root.runtime ?? {}, "config.runtime");
35
+ assertKnownKeys(runtime, [
36
+ "target",
37
+ "applicationUrl",
38
+ "projectId",
39
+ "apiPort",
40
+ "databasePort",
41
+ "studioPort",
42
+ ], "config.runtime");
43
+ const runtimeTarget = resolveRuntimeTarget(runtime.target).id;
44
+ const supabase = runtimeTarget === "supabase"
45
+ ? assertPlainObject(root.supabase, "config.supabase")
46
+ : null;
47
+ const postgresql = runtimeTarget === "postgresql"
48
+ ? assertPlainObject(root.postgresql, "config.postgresql")
49
+ : null;
50
+ if (runtimeTarget === "supabase" && root.postgresql !== undefined) {
51
+ throw new Error("config.postgresql is not allowed when config.runtime.target is supabase.");
52
+ }
53
+ if (runtimeTarget === "postgresql" && root.supabase !== undefined) {
54
+ throw new Error("config.supabase is not allowed when config.runtime.target is postgresql.");
55
+ }
56
+ if (supabase) {
57
+ assertKnownKeys(supabase, [
58
+ "workdir",
59
+ "migrationDirectory",
60
+ "rehearsalConfig",
61
+ "runtimeWorkdir",
62
+ "authentication",
63
+ "serviceEnvironmentFile",
64
+ "serviceEnvironmentVariables",
65
+ ], "config.supabase");
66
+ }
67
+ if (postgresql) {
68
+ assertKnownKeys(postgresql, ["migrationDirectory", "runtimeWorkdir", "image", "database", "user"], "config.postgresql");
69
+ }
70
+ const baseline = assertPlainObject(root.baseline, "config.baseline");
71
+ assertKnownKeys(baseline, ["artifactDirectory", "sanitizationPolicy"], "config.baseline");
72
+ const containerRuntime = assertPlainObject(root.containerRuntime ?? {}, "config.containerRuntime");
73
+ assertKnownKeys(containerRuntime, ["autoStartColima"], "config.containerRuntime");
74
+ const cleanup = assertPlainObject(root.cleanup ?? {}, "config.cleanup");
75
+ assertKnownKeys(cleanup, ["retainBaselineGenerations"], "config.cleanup");
76
+ const preparation = root.preparation === undefined
77
+ ? null
78
+ : assertPlainObject(root.preparation, "config.preparation");
79
+ if (preparation) {
80
+ assertKnownKeys(preparation, [
81
+ "sourcePolicy",
82
+ "privacyKey",
83
+ "batchRows",
84
+ "maximumRows",
85
+ "maximumBytes",
86
+ "diskHeadroomBytes",
87
+ ], "config.preparation");
88
+ }
89
+ const dependentTargets = assertObjectArray(root.dependentTargets ?? [], "config.dependentTargets");
90
+ dependentTargets.forEach((target, index) => assertKnownKeys(target, ["name", "configPath", "prepareCommand"], `config.dependentTargets[${index}]`));
91
+ const application = assertPlainObject(root.application, "config.application");
92
+ assertKnownKeys(application, [
93
+ "startCommand",
94
+ "proofCommand",
95
+ "environmentFile",
96
+ "environmentVariables",
97
+ "readiness",
98
+ "httpProofs",
99
+ "runtimeAdapter",
100
+ ], "config.application");
101
+ const readiness = application.readiness === undefined
102
+ ? null
103
+ : assertPlainObject(application.readiness, "config.application.readiness");
104
+ if (readiness) {
105
+ assertKnownKeys(readiness, ["url", "expectedStatus", "timeoutSeconds"], "config.application.readiness");
106
+ }
107
+ const httpProofs = assertObjectArray(application.httpProofs ?? [], "config.application.httpProofs");
108
+ httpProofs.forEach((proof, index) => {
109
+ const path = `config.application.httpProofs[${index}]`;
110
+ assertKnownKeys(proof, ["name", "kind", "url", "method", "expectedStatus", "json"], path);
111
+ if (proof.json !== undefined) {
112
+ assertKnownKeys(assertPlainObject(proof.json, `${path}.json`), ["path", "equals", "notEquals", "minimumItems"], `${path}.json`);
113
+ }
114
+ });
115
+ const safety = assertPlainObject(root.safety ?? {}, "config.safety");
116
+ assertKnownKeys(safety, [
117
+ "allowedHosts",
118
+ "blockedEnvironmentVariables",
119
+ "authenticationProviders",
120
+ "hostedAccess",
121
+ "outboundNetwork",
122
+ ], "config.safety");
123
+ const verification = assertPlainObject(root.verification ?? {}, "config.verification");
124
+ assertKnownKeys(verification, ["commands"], "config.verification");
125
+ const authentication = supabase?.authentication === undefined
126
+ ? null
127
+ : assertPlainObject(supabase.authentication, "config.supabase.authentication");
128
+ if (authentication) {
129
+ assertKnownKeys(authentication, ["enableLocalSignup", "environmentFile", "providers"], "config.supabase.authentication");
130
+ if (Array.isArray(authentication.providers)) {
131
+ const providers = assertObjectArray(authentication.providers, "config.supabase.authentication.providers");
132
+ providers.forEach((provider, index) => assertKnownKeys(provider, [
133
+ "name",
134
+ "clientIdEnvironmentVariable",
135
+ "clientSecretEnvironmentVariable",
136
+ "skipNonceCheck",
137
+ "emailOptional",
138
+ ], `config.supabase.authentication.providers[${index}]`));
139
+ }
140
+ }
141
+ return {
142
+ root,
143
+ project,
144
+ runtime,
145
+ runtimeTarget,
146
+ supabase,
147
+ postgresql,
148
+ baseline,
149
+ containerRuntime,
150
+ cleanup,
151
+ preparation,
152
+ dependentTargets,
153
+ application,
154
+ readiness,
155
+ httpProofs,
156
+ safety,
157
+ verification,
158
+ authentication,
159
+ };
160
+ };
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Purpose: Provide the reusable, side-effect-free validators used by the
3
+ * Rehearsal configuration schema and normalizer.
4
+ */
5
+ export type PlainObject = Record<string, unknown>;
6
+ export declare const isPlainObject: (value: unknown) => value is PlainObject;
7
+ export declare const assertPlainObject: (value: unknown, path: string) => PlainObject;
8
+ export declare const assertKnownKeys: (value: PlainObject, keys: readonly string[], path: string) => void;
9
+ export declare const assertNonEmptyString: (value: unknown, path: string) => string;
10
+ export declare const assertRelativePath: (value: unknown, path: string) => string;
11
+ export declare const assertCommand: (value: unknown, path: string) => string;
12
+ export declare const assertIdentifier: (value: unknown, path: string) => string;
13
+ export declare const assertDatabaseIdentifier: (value: unknown, path: string) => string;
14
+ export declare const assertPostgresImage: (value: unknown, path: string) => string;
15
+ export declare const assertEnvironmentKey: (value: unknown, path: string) => string;
16
+ export declare const assertEnvironmentReference: (value: unknown, path: string) => string;
17
+ export declare const assertPort: (value: unknown, path: string) => number;
18
+ export declare const assertBoolean: (value: unknown, path: string) => boolean;
19
+ export declare const assertPositiveInteger: (value: unknown, path: string) => number;
20
+ export declare const assertHttpStatus: (value: unknown, path: string) => number;
21
+ export declare const assertStringArray: (value: unknown, path: string) => string[];
22
+ export declare const assertLoopbackUrl: (value: unknown, path: string, allowedHosts: readonly string[], supportedHosts: ReadonlySet<string>) => string;
@@ -0,0 +1,136 @@
1
+ /**
2
+ * Purpose: Provide the reusable, side-effect-free validators used by the
3
+ * Rehearsal configuration schema and normalizer.
4
+ */
5
+ import { isAbsolute } from "node:path";
6
+ const SAFE_COMMAND_PATTERN = /^[^\n\r\0]+$/u;
7
+ const IDENTIFIER_PATTERN = /^[a-z0-9][a-z0-9-]{1,62}$/u;
8
+ const DATABASE_IDENTIFIER_PATTERN = /^[a-z][a-z0-9_]{0,62}$/u;
9
+ const POSTGRES_IMAGE_PATTERN = /^postgres:\d+(?:\.\d+)?-alpine$/u;
10
+ const ENVIRONMENT_KEY_PATTERN = /^[A-Z][A-Z0-9_]*$/u;
11
+ const ENVIRONMENT_REFERENCE_PATTERN = /^[a-z0-9][a-z0-9-]*:[A-Z][A-Z0-9_]*$/u;
12
+ export const isPlainObject = (value) => value !== null &&
13
+ typeof value === "object" &&
14
+ !Array.isArray(value) &&
15
+ Object.getPrototypeOf(value) === Object.prototype;
16
+ export const assertPlainObject = (value, path) => {
17
+ if (!isPlainObject(value))
18
+ throw new Error(`${path} must be an object.`);
19
+ return value;
20
+ };
21
+ export const assertKnownKeys = (value, keys, path) => {
22
+ for (const key of Object.keys(value)) {
23
+ if (!keys.includes(key)) {
24
+ throw new Error(`Unknown Rehearsal configuration property: ${path}.${key}.`);
25
+ }
26
+ }
27
+ };
28
+ export const assertNonEmptyString = (value, path) => {
29
+ if (typeof value !== "string" || !value.trim()) {
30
+ throw new Error(`${path} must be a non-empty string.`);
31
+ }
32
+ return value.trim();
33
+ };
34
+ export const assertRelativePath = (value, path) => {
35
+ const normalized = assertNonEmptyString(value, path);
36
+ if (isAbsolute(normalized) || normalized.split(/[\\/]/u).includes("..")) {
37
+ throw new Error(`${path} must stay inside the project root.`);
38
+ }
39
+ return normalized;
40
+ };
41
+ export const assertCommand = (value, path) => {
42
+ const command = assertNonEmptyString(value, path);
43
+ if (!SAFE_COMMAND_PATTERN.test(command)) {
44
+ throw new Error(`${path} contains an unsafe control character.`);
45
+ }
46
+ return command;
47
+ };
48
+ export const assertIdentifier = (value, path) => {
49
+ const identifier = assertNonEmptyString(value, path);
50
+ if (!IDENTIFIER_PATTERN.test(identifier)) {
51
+ throw new Error(`${path} must contain only lowercase letters, digits, and hyphens.`);
52
+ }
53
+ return identifier;
54
+ };
55
+ export const assertDatabaseIdentifier = (value, path) => {
56
+ const identifier = assertNonEmptyString(value, path);
57
+ if (!DATABASE_IDENTIFIER_PATTERN.test(identifier)) {
58
+ throw new Error(`${path} must be a safe lowercase PostgreSQL identifier.`);
59
+ }
60
+ return identifier;
61
+ };
62
+ export const assertPostgresImage = (value, path) => {
63
+ const image = assertNonEmptyString(value, path);
64
+ if (!POSTGRES_IMAGE_PATTERN.test(image)) {
65
+ throw new Error(`${path} must name an official versioned Alpine PostgreSQL image, such as postgres:17-alpine.`);
66
+ }
67
+ return image;
68
+ };
69
+ export const assertEnvironmentKey = (value, path) => {
70
+ const key = assertNonEmptyString(value, path);
71
+ if (!ENVIRONMENT_KEY_PATTERN.test(key)) {
72
+ throw new Error(`${path} must be a safe environment variable name.`);
73
+ }
74
+ return key;
75
+ };
76
+ export const assertEnvironmentReference = (value, path) => {
77
+ if (typeof value !== "string" || !ENVIRONMENT_REFERENCE_PATTERN.test(value)) {
78
+ throw new Error(`${path} must reference target:VARIABLE, such as primary:DATABASE_URL.`);
79
+ }
80
+ return value;
81
+ };
82
+ export const assertPort = (value, path) => {
83
+ if (typeof value !== "number" ||
84
+ !Number.isSafeInteger(value) ||
85
+ value < 1024 ||
86
+ value > 65_535) {
87
+ throw new Error(`${path} must be a non-privileged TCP port.`);
88
+ }
89
+ return value;
90
+ };
91
+ export const assertBoolean = (value, path) => {
92
+ if (typeof value !== "boolean") {
93
+ throw new Error(`${path} must be true or false.`);
94
+ }
95
+ return value;
96
+ };
97
+ export const assertPositiveInteger = (value, path) => {
98
+ if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 1) {
99
+ throw new Error(`${path} must be a positive integer.`);
100
+ }
101
+ return value;
102
+ };
103
+ export const assertHttpStatus = (value, path) => {
104
+ if (typeof value !== "number" ||
105
+ !Number.isSafeInteger(value) ||
106
+ value < 100 ||
107
+ value > 599) {
108
+ throw new Error(`${path} must be an HTTP status.`);
109
+ }
110
+ return value;
111
+ };
112
+ export const assertStringArray = (value, path) => {
113
+ if (!Array.isArray(value) ||
114
+ value.length === 0 ||
115
+ value.some((entry) => typeof entry !== "string" || !entry.trim())) {
116
+ throw new Error(`${path} must be a non-empty string array.`);
117
+ }
118
+ return [...new Set(value.map((entry) => entry.trim()))];
119
+ };
120
+ export const assertLoopbackUrl = (value, path, allowedHosts, supportedHosts) => {
121
+ let parsed;
122
+ try {
123
+ parsed = new URL(assertNonEmptyString(value, path));
124
+ }
125
+ catch {
126
+ throw new Error(`${path} must be a valid loopback URL.`);
127
+ }
128
+ if (!allowedHosts.includes(parsed.hostname) ||
129
+ !supportedHosts.has(parsed.hostname)) {
130
+ throw new Error(`${path} must use an explicitly allowed loopback host.`);
131
+ }
132
+ if (!["http:", "https:"].includes(parsed.protocol)) {
133
+ throw new Error(`${path} must use HTTP or HTTPS.`);
134
+ }
135
+ return parsed.toString().replace(/\/$/u, "");
136
+ };
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Purpose: Resolve an npm consumer root conservatively and create the same
3
+ * project-owned scaffolding used by the guided setup command.
4
+ */
5
+ export type ConsumerRootResolution = {
6
+ status: "skipped";
7
+ reason: string;
8
+ } | {
9
+ status: "resolved";
10
+ projectRoot: string;
11
+ };
12
+ export interface ResolveConsumerRootOptions {
13
+ packageRoot?: string;
14
+ initCwd?: string;
15
+ localPrefix?: string;
16
+ globalInstall?: boolean | string;
17
+ workspace?: string;
18
+ }
19
+ export interface InstalledScaffoldOptions {
20
+ packageRoot?: string;
21
+ environment?: NodeJS.ProcessEnv;
22
+ isPortAvailable?: (port: number) => boolean | Promise<boolean>;
23
+ }
24
+ export interface InstalledScaffoldFile {
25
+ path: string;
26
+ action: string;
27
+ }
28
+ export type InstalledScaffoldResult = {
29
+ status: "skipped";
30
+ reason: string;
31
+ } | {
32
+ status: "ready";
33
+ projectRoot: string;
34
+ target: string;
35
+ files: InstalledScaffoldFile[];
36
+ configurationPath: string;
37
+ configurationAction: string;
38
+ rootConfigGenerationSkipped: boolean;
39
+ };
40
+ export declare const renderInstalledRehearsalScaffold: (result: InstalledScaffoldResult) => string;
41
+ export declare const resolveRehearsalConsumerRoot: ({ packageRoot, initCwd, localPrefix, globalInstall, workspace, }?: ResolveConsumerRootOptions) => Promise<ConsumerRootResolution>;
42
+ export declare const createInstalledRehearsalScaffold: ({ packageRoot, environment, isPortAvailable, }?: InstalledScaffoldOptions) => Promise<InstalledScaffoldResult>;