@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,302 @@
1
+ /**
2
+ * Purpose: Load and strictly validate the versioned, project-owned Rehearsal
3
+ * configuration contract. Do not run directly; this module is reusable script
4
+ * infrastructure.
5
+ */
6
+ import { REHEARSAL_CONFIG_VERSION, REHEARSAL_DEFAULTS, } from "./configuration_contract.mjs";
7
+ import { validateConfigurationSchema } from "./configuration_schema.mjs";
8
+ import { assertBoolean, assertCommand, assertDatabaseIdentifier, assertEnvironmentKey, assertEnvironmentReference, assertHttpStatus, assertIdentifier, assertKnownKeys, assertLoopbackUrl, assertNonEmptyString, assertPlainObject, assertPort, assertPostgresImage, assertPositiveInteger, assertRelativePath, assertStringArray, } from "./configuration_validation.mjs";
9
+ const LOOPBACK_HOSTS = new Set(REHEARSAL_DEFAULTS.safety.allowedHosts);
10
+ const SUPPORTED_SUPABASE_OAUTH_PROVIDERS = new Set(["github", "google"]);
11
+ const normalizeApplicationEnvironmentMappings = (value = {}) => {
12
+ const mappings = assertPlainObject(value, "config.application.environmentVariables");
13
+ return Object.freeze(Object.fromEntries(Object.entries(mappings).map(([key, reference]) => {
14
+ const path = `config.application.environmentVariables.${key}`;
15
+ assertEnvironmentKey(key, path);
16
+ return [key, assertEnvironmentReference(reference, path)];
17
+ })));
18
+ };
19
+ export const normalizeRehearsalConfig = (input) => {
20
+ const { root, project, runtime, runtimeTarget, supabase, postgresql, baseline, containerRuntime, cleanup, preparation, dependentTargets, application, readiness, httpProofs, safety, verification, authentication, } = validateConfigurationSchema(input);
21
+ const projectName = assertIdentifier(project.name, "config.project.name");
22
+ const normalizedDependentTargets = dependentTargets.map((target, index) => {
23
+ const path = `config.dependentTargets[${index}]`;
24
+ const name = assertIdentifier(target.name, `${path}.name`);
25
+ return Object.freeze({
26
+ name,
27
+ configPath: assertRelativePath(target.configPath, `${path}.configPath`),
28
+ prepareCommand: target.prepareCommand === undefined
29
+ ? null
30
+ : assertCommand(target.prepareCommand, `${path}.prepareCommand`),
31
+ });
32
+ });
33
+ if (new Set(normalizedDependentTargets.map((target) => target.name)).size !==
34
+ normalizedDependentTargets.length) {
35
+ throw new Error("config.dependentTargets names must be unique.");
36
+ }
37
+ if (httpProofs.length > 0 &&
38
+ (!httpProofs.some((proof) => proof.kind === "positive") ||
39
+ !httpProofs.some((proof) => proof.kind === "negative"))) {
40
+ throw new Error("config.application.httpProofs must include at least one positive and one negative check.");
41
+ }
42
+ const allowedHosts = assertStringArray(safety.allowedHosts ?? REHEARSAL_DEFAULTS.safety.allowedHosts, "config.safety.allowedHosts");
43
+ if (allowedHosts.some((host) => !LOOPBACK_HOSTS.has(host))) {
44
+ throw new Error("config.safety.allowedHosts may contain loopback hosts only in configuration version 1.");
45
+ }
46
+ if ((safety.hostedAccess ?? "disabled") !== "disabled") {
47
+ throw new Error("config.safety.hostedAccess must remain disabled in configuration version 1.");
48
+ }
49
+ if ((safety.outboundNetwork ?? "deny") !== "deny") {
50
+ throw new Error("config.safety.outboundNetwork must remain deny in configuration version 1.");
51
+ }
52
+ const ports = {
53
+ ...(runtimeTarget === "supabase"
54
+ ? { api: assertPort(runtime.apiPort, "config.runtime.apiPort") }
55
+ : {}),
56
+ database: assertPort(runtime.databasePort, "config.runtime.databasePort"),
57
+ ...(runtimeTarget === "supabase"
58
+ ? { studio: assertPort(runtime.studioPort, "config.runtime.studioPort") }
59
+ : {}),
60
+ };
61
+ if (new Set(Object.values(ports)).size !== Object.values(ports).length) {
62
+ throw new Error("Rehearsal runtime ports must be unique.");
63
+ }
64
+ const commands = verification.commands ?? [];
65
+ if (!Array.isArray(commands)) {
66
+ throw new Error("config.verification.commands must be an array.");
67
+ }
68
+ let normalizedAuthentication = null;
69
+ if (authentication) {
70
+ if (!supabase) {
71
+ throw new Error("config.supabase.authentication requires the Supabase runtime target.");
72
+ }
73
+ if (authentication.enableLocalSignup !== true) {
74
+ throw new Error("config.supabase.authentication.enableLocalSignup must be true to create the disposable local identity used by an OAuth sign-in.");
75
+ }
76
+ if (supabase.serviceEnvironmentFile !== undefined ||
77
+ supabase.serviceEnvironmentVariables !== undefined) {
78
+ throw new Error("config.supabase.authentication cannot be combined with the legacy serviceEnvironmentFile or serviceEnvironmentVariables fields.");
79
+ }
80
+ if (safety.authenticationProviders !== undefined) {
81
+ throw new Error("config.safety.authenticationProviders is derived from config.supabase.authentication and must be omitted.");
82
+ }
83
+ if (!Array.isArray(authentication.providers) ||
84
+ authentication.providers.length === 0) {
85
+ throw new Error("config.supabase.authentication.providers must be a non-empty array.");
86
+ }
87
+ const providers = authentication.providers.map((entry, index) => {
88
+ const path = `config.supabase.authentication.providers[${index}]`;
89
+ const value = entry;
90
+ const reviewedName = assertNonEmptyString(value.name, `${path}.name`);
91
+ if (!SUPPORTED_SUPABASE_OAUTH_PROVIDERS.has(reviewedName)) {
92
+ throw new Error(`${path}.name must be one of: ${[...SUPPORTED_SUPABASE_OAUTH_PROVIDERS].join(", ")}.`);
93
+ }
94
+ const name = reviewedName;
95
+ const environmentVariable = (key) => {
96
+ return assertEnvironmentKey(value[key], `${path}.${key}`);
97
+ };
98
+ const optionalBoolean = (key) => {
99
+ if (value[key] === undefined)
100
+ return false;
101
+ if (typeof value[key] !== "boolean") {
102
+ throw new Error(`${path}.${key} must be a boolean.`);
103
+ }
104
+ return value[key];
105
+ };
106
+ return Object.freeze({
107
+ name,
108
+ clientIdEnvironmentVariable: environmentVariable("clientIdEnvironmentVariable"),
109
+ clientSecretEnvironmentVariable: environmentVariable("clientSecretEnvironmentVariable"),
110
+ skipNonceCheck: optionalBoolean("skipNonceCheck"),
111
+ emailOptional: optionalBoolean("emailOptional"),
112
+ });
113
+ });
114
+ if (new Set(providers.map(({ name }) => name)).size !==
115
+ providers.length) {
116
+ throw new Error("config.supabase.authentication.providers must not contain duplicate providers.");
117
+ }
118
+ const credentialVariables = providers.flatMap((provider) => [
119
+ provider.clientIdEnvironmentVariable,
120
+ provider.clientSecretEnvironmentVariable,
121
+ ]);
122
+ if (new Set(credentialVariables).size !== credentialVariables.length) {
123
+ throw new Error("config.supabase.authentication provider environment variables must be unique.");
124
+ }
125
+ normalizedAuthentication = Object.freeze({
126
+ enableLocalSignup: true,
127
+ environmentFile: assertRelativePath(authentication.environmentFile, "config.supabase.authentication.environmentFile"),
128
+ providers: Object.freeze(providers),
129
+ });
130
+ }
131
+ const serviceEnvironmentVariables = normalizedAuthentication
132
+ ? normalizedAuthentication.providers.flatMap((provider) => [
133
+ provider.clientIdEnvironmentVariable,
134
+ provider.clientSecretEnvironmentVariable,
135
+ ])
136
+ : (supabase?.serviceEnvironmentVariables ?? []);
137
+ if (!Array.isArray(serviceEnvironmentVariables)) {
138
+ throw new Error("config.supabase.serviceEnvironmentVariables must be an array.");
139
+ }
140
+ const normalizedServiceEnvironmentVariables = serviceEnvironmentVariables.map((value, index) => assertNonEmptyString(value, `config.supabase.serviceEnvironmentVariables[${index}]`));
141
+ if (new Set(normalizedServiceEnvironmentVariables).size !==
142
+ normalizedServiceEnvironmentVariables.length) {
143
+ throw new Error("config.supabase.serviceEnvironmentVariables must not contain duplicates.");
144
+ }
145
+ if (Boolean(normalizedAuthentication?.environmentFile ??
146
+ supabase?.serviceEnvironmentFile) !== Boolean(normalizedServiceEnvironmentVariables.length)) {
147
+ throw new Error("config.supabase.serviceEnvironmentFile and serviceEnvironmentVariables must be configured together.");
148
+ }
149
+ const authenticationProviders = normalizedAuthentication
150
+ ? normalizedAuthentication.providers.map(({ name }) => name)
151
+ : safety.authenticationProviders
152
+ ? assertStringArray(safety.authenticationProviders, "config.safety.authenticationProviders")
153
+ : [];
154
+ if (runtimeTarget === "postgresql" && authenticationProviders.length > 0) {
155
+ throw new Error("config.safety.authenticationProviders is available only for the Supabase target.");
156
+ }
157
+ return Object.freeze({
158
+ schemaVersion: REHEARSAL_CONFIG_VERSION,
159
+ project: Object.freeze({ name: projectName }),
160
+ supabase: supabase
161
+ ? Object.freeze({
162
+ workdir: assertRelativePath(supabase.workdir, "config.supabase.workdir"),
163
+ migrationDirectory: assertRelativePath(supabase.migrationDirectory, "config.supabase.migrationDirectory"),
164
+ rehearsalConfig: assertRelativePath(supabase.rehearsalConfig, "config.supabase.rehearsalConfig"),
165
+ runtimeWorkdir: assertRelativePath(supabase.runtimeWorkdir, "config.supabase.runtimeWorkdir"),
166
+ authentication: normalizedAuthentication,
167
+ serviceEnvironmentFile: normalizedAuthentication
168
+ ? normalizedAuthentication.environmentFile
169
+ : supabase.serviceEnvironmentFile
170
+ ? assertRelativePath(supabase.serviceEnvironmentFile, "config.supabase.serviceEnvironmentFile")
171
+ : null,
172
+ serviceEnvironmentVariables: Object.freeze(normalizedServiceEnvironmentVariables),
173
+ })
174
+ : null,
175
+ postgresql: postgresql
176
+ ? Object.freeze({
177
+ migrationDirectory: assertRelativePath(postgresql.migrationDirectory, "config.postgresql.migrationDirectory"),
178
+ runtimeWorkdir: assertRelativePath(postgresql.runtimeWorkdir ?? ".rehearsal/runtime", "config.postgresql.runtimeWorkdir"),
179
+ image: assertPostgresImage(postgresql.image ?? "postgres:17-alpine", "config.postgresql.image"),
180
+ database: assertDatabaseIdentifier(postgresql.database ?? "postgres", "config.postgresql.database"),
181
+ user: assertDatabaseIdentifier(postgresql.user ?? "postgres", "config.postgresql.user"),
182
+ })
183
+ : null,
184
+ baseline: Object.freeze({
185
+ artifactDirectory: assertRelativePath(baseline.artifactDirectory ??
186
+ REHEARSAL_DEFAULTS.baseline.artifactDirectory, "config.baseline.artifactDirectory"),
187
+ sanitizationPolicy: assertRelativePath(baseline.sanitizationPolicy, "config.baseline.sanitizationPolicy"),
188
+ }),
189
+ containerRuntime: Object.freeze({
190
+ autoStartColima: assertBoolean(containerRuntime.autoStartColima ??
191
+ REHEARSAL_DEFAULTS.containerRuntime.autoStartColima, "config.containerRuntime.autoStartColima"),
192
+ }),
193
+ cleanup: Object.freeze({
194
+ retainBaselineGenerations: assertPositiveInteger(cleanup.retainBaselineGenerations ??
195
+ REHEARSAL_DEFAULTS.cleanup.retainBaselineGenerations, "config.cleanup.retainBaselineGenerations"),
196
+ }),
197
+ preparation: preparation
198
+ ? Object.freeze({
199
+ sourcePolicy: assertRelativePath(preparation.sourcePolicy, "config.preparation.sourcePolicy"),
200
+ privacyKey: assertRelativePath(preparation.privacyKey, "config.preparation.privacyKey"),
201
+ batchRows: assertPositiveInteger(preparation.batchRows ?? 500, "config.preparation.batchRows"),
202
+ maximumRows: assertPositiveInteger(preparation.maximumRows ?? 1_000_000, "config.preparation.maximumRows"),
203
+ maximumBytes: assertPositiveInteger(preparation.maximumBytes ?? 2 * 1024 * 1024 * 1024, "config.preparation.maximumBytes"),
204
+ diskHeadroomBytes: assertPositiveInteger(preparation.diskHeadroomBytes ?? 64 * 1024 * 1024, "config.preparation.diskHeadroomBytes"),
205
+ })
206
+ : null,
207
+ runtimePolicy: root.runtimePolicy === undefined
208
+ ? null
209
+ : assertRelativePath(root.runtimePolicy, "config.runtimePolicy"),
210
+ identityPolicy: root.identityPolicy === undefined
211
+ ? null
212
+ : assertRelativePath(root.identityPolicy, "config.identityPolicy"),
213
+ dependentTargets: Object.freeze(normalizedDependentTargets),
214
+ application: Object.freeze({
215
+ startCommand: assertCommand(application.startCommand, "config.application.startCommand"),
216
+ proofCommand: assertCommand(application.proofCommand, "config.application.proofCommand"),
217
+ environmentFile: assertRelativePath(application.environmentFile ?? ".rehearsal/runtime.env", "config.application.environmentFile"),
218
+ environmentVariables: normalizeApplicationEnvironmentMappings(application.environmentVariables),
219
+ readiness: readiness
220
+ ? Object.freeze({
221
+ url: assertLoopbackUrl(readiness.url, "config.application.readiness.url", allowedHosts, LOOPBACK_HOSTS),
222
+ expectedStatus: assertHttpStatus(readiness.expectedStatus, "config.application.readiness.expectedStatus"),
223
+ timeoutSeconds: assertPositiveInteger(readiness.timeoutSeconds ?? 30, "config.application.readiness.timeoutSeconds"),
224
+ })
225
+ : null,
226
+ httpProofs: Object.freeze(httpProofs.map((proof, index) => {
227
+ const path = `config.application.httpProofs[${index}]`;
228
+ const value = assertPlainObject(proof, path);
229
+ assertKnownKeys(value, ["name", "kind", "url", "method", "expectedStatus", "json"], path);
230
+ if (typeof value.kind !== "string" ||
231
+ !["positive", "negative"].includes(value.kind)) {
232
+ throw new Error(`${path}.kind must be positive or negative.`);
233
+ }
234
+ const expectedStatus = assertHttpStatus(value.expectedStatus, `${path}.expectedStatus`);
235
+ const method = assertNonEmptyString(value.method ?? "GET", `${path}.method`).toUpperCase();
236
+ if (!["GET", "HEAD"].includes(method)) {
237
+ throw new Error(`${path}.method must be GET or HEAD.`);
238
+ }
239
+ let json = null;
240
+ if (value.json !== undefined) {
241
+ const assertion = assertPlainObject(value.json, `${path}.json`);
242
+ assertKnownKeys(assertion, ["path", "equals", "notEquals", "minimumItems"], `${path}.json`);
243
+ if (!Array.isArray(assertion.path) ||
244
+ assertion.path.length === 0 ||
245
+ assertion.path.some((segment) => typeof segment !== "string" || !segment)) {
246
+ throw new Error(`${path}.json.path must be a non-empty string array.`);
247
+ }
248
+ const assertionCount = [
249
+ Object.hasOwn(assertion, "equals"),
250
+ Object.hasOwn(assertion, "notEquals"),
251
+ assertion.minimumItems !== undefined,
252
+ ].filter(Boolean).length;
253
+ if (assertionCount !== 1) {
254
+ throw new Error(`${path}.json must declare exactly one assertion.`);
255
+ }
256
+ json = Object.freeze({
257
+ path: Object.freeze([...assertion.path]),
258
+ ...(Object.hasOwn(assertion, "equals")
259
+ ? { equals: assertion.equals }
260
+ : {}),
261
+ ...(Object.hasOwn(assertion, "notEquals")
262
+ ? { notEquals: assertion.notEquals }
263
+ : {}),
264
+ ...(assertion.minimumItems !== undefined
265
+ ? {
266
+ minimumItems: assertPositiveInteger(assertion.minimumItems, `${path}.json.minimumItems`),
267
+ }
268
+ : {}),
269
+ });
270
+ }
271
+ return Object.freeze({
272
+ name: assertNonEmptyString(value.name, `${path}.name`),
273
+ kind: value.kind,
274
+ url: assertLoopbackUrl(value.url, `${path}.url`, allowedHosts, LOOPBACK_HOSTS),
275
+ method,
276
+ expectedStatus,
277
+ json,
278
+ });
279
+ })),
280
+ runtimeAdapter: application.runtimeAdapter === undefined
281
+ ? null
282
+ : assertRelativePath(application.runtimeAdapter, "config.application.runtimeAdapter"),
283
+ }),
284
+ runtime: Object.freeze({
285
+ target: runtimeTarget,
286
+ applicationUrl: assertLoopbackUrl(runtime.applicationUrl ?? REHEARSAL_DEFAULTS.runtime.applicationUrl, "config.runtime.applicationUrl", allowedHosts, LOOPBACK_HOSTS),
287
+ projectId: assertNonEmptyString(runtime.projectId ?? REHEARSAL_DEFAULTS.runtime.projectId, "config.runtime.projectId"),
288
+ ports: Object.freeze(ports),
289
+ }),
290
+ safety: Object.freeze({
291
+ allowedHosts: Object.freeze(allowedHosts),
292
+ blockedEnvironmentVariables: Object.freeze(assertStringArray(safety.blockedEnvironmentVariables ??
293
+ REHEARSAL_DEFAULTS.safety.blockedEnvironmentVariables, "config.safety.blockedEnvironmentVariables")),
294
+ authenticationProviders: Object.freeze(authenticationProviders),
295
+ hostedAccess: "disabled",
296
+ outboundNetwork: "deny",
297
+ }),
298
+ verification: Object.freeze({
299
+ commands: Object.freeze(commands.map((command, index) => assertCommand(command, `config.verification.commands[${index}]`))),
300
+ }),
301
+ });
302
+ };
@@ -0,0 +1,14 @@
1
+ /** Render reviewed starter configurations without reading or writing a project. */
2
+ import type { DetectedProject } from "./project_detection.mjs";
3
+ export declare const renderDetectedConfig: (detected: DetectedProject, { applicationUrl, ports, }?: {
4
+ applicationUrl?: string;
5
+ ports?: {
6
+ api: number;
7
+ database: number;
8
+ studio: number;
9
+ };
10
+ }) => string;
11
+ export declare const renderDetectedPostgresqlConfig: (detected: DetectedProject, { applicationUrl, databasePort }?: {
12
+ applicationUrl?: string | undefined;
13
+ databasePort?: number | undefined;
14
+ }) => string;
@@ -0,0 +1,224 @@
1
+ /** Render reviewed starter configurations without reading or writing a project. */
2
+ export const renderDetectedConfig = (detected, { applicationUrl = "http://localhost:5175", ports = { api: 58321, database: 58322, studio: 58323 }, } = {}) => `// @ts-check
3
+ /**
4
+ * Rehearsal configuration for ${detected.projectName}.
5
+ * Generated from this project by \`npx rehearsal\` and safe to commit.
6
+ * Review the CHECK comments. Keep passwords, tokens, and production URLs out of this file.
7
+ * Docs: https://github.com/Ddupasquier/rehearsal-db/blob/main/docs/configuration.md
8
+ */
9
+ import { defineRehearsalConfig } from "@rehearsal-db/core";
10
+
11
+ export default defineRehearsalConfig({
12
+ // Configuration format. Rehearsal will explain if an upgrade is ever needed.
13
+ schemaVersion: 1,
14
+ // Stable local name used in Rehearsal labels and reports.
15
+ project: { name: ${JSON.stringify(detected.projectName)} },
16
+
17
+ // Project files Rehearsal reads. Every path stays inside this repository.
18
+ supabase: {
19
+ workdir: ".",
20
+ migrationDirectory: "supabase/migrations",
21
+ rehearsalConfig: "infrastructure/rehearsal/supabase/config.toml",
22
+ runtimeWorkdir: ".rehearsal/runtime",
23
+
24
+ // Optional local OAuth connection. Secrets stay in the ignored owner-only file.
25
+ // Register http://127.0.0.1:${ports.api}/auth/v1/callback with the provider.
26
+ // authentication: {
27
+ // enableLocalSignup: true,
28
+ // environmentFile: ".env.rehearsal-service.local",
29
+ // providers: [
30
+ // {
31
+ // name: "google",
32
+ // clientIdEnvironmentVariable: "REHEARSAL_GOOGLE_CLIENT_ID",
33
+ // clientSecretEnvironmentVariable: "REHEARSAL_GOOGLE_CLIENT_SECRET",
34
+ // skipNonceCheck: false,
35
+ // emailOptional: false,
36
+ // },
37
+ // ],
38
+ // },
39
+ },
40
+
41
+ // Immutable local baseline files. Rehearsal never reads production on your behalf.
42
+ baseline: {
43
+ artifactDirectory: ".rehearsal",
44
+ sanitizationPolicy: "infrastructure/rehearsal/sanitization-policy.json",
45
+ },
46
+
47
+ // Optional source refresh. Enable only after reviewing docs/standalone-workflow.md.
48
+ // Credentials are read from the environment named by source-access-policy.json.
49
+ // preparation: {
50
+ // sourcePolicy: "infrastructure/rehearsal/source-access-policy.json",
51
+ // privacyKey: ".rehearsal/secrets/privacy.key",
52
+ // batchRows: 500,
53
+ // maximumRows: 1000000,
54
+ // maximumBytes: 2147483648,
55
+ // diskHeadroomBytes: 67108864,
56
+ // },
57
+ // Optional reviewed schemas/extensions/triggers/local-only rows.
58
+ // runtimePolicy: "infrastructure/rehearsal/runtime-policy.json",
59
+ // Optional copied-account association. The JSON stores only reviewed matcher hashes;
60
+ // raw emails/subjects and provider credentials stay in ignored environment files.
61
+ // identityPolicy: "infrastructure/rehearsal/identity-policy.json",
62
+
63
+ // Reuse any running Docker-compatible engine; start Colima only when needed.
64
+ containerRuntime: {
65
+ autoStartColima: true,
66
+ },
67
+
68
+ // Keep this many baseline generations, always including the active one.
69
+ cleanup: {
70
+ retainBaselineGenerations: 2,
71
+ },
72
+
73
+ // Optional: manage another isolated database as part of the same rehearsal.
74
+ // Give that database its own complete config, ports, project ID, and .rehearsal folder.
75
+ // dependentTargets: [
76
+ // {
77
+ // name: "publication-api",
78
+ // configPath: "rehearsal.publication.config.mjs",
79
+ // prepareCommand: "npm run rehearsal:prepare-publication",
80
+ // },
81
+ // ],
82
+
83
+ application: {
84
+ // CHECK: commands detected from package.json. Change them if they are not correct.
85
+ startCommand: ${JSON.stringify(detected.applicationCommand)},
86
+ proofCommand: ${JSON.stringify(detected.verificationCommand)},
87
+ environmentFile: ".rehearsal/runtime.env",
88
+ // Map generated local runtime values directly into the normal app command.
89
+ // environmentVariables: { DATABASE_URL: "primary:DATABASE_URL" },
90
+ // Required by \`rehearsal open\`; use a route that responds only when the app is ready.
91
+ readiness: { url: ${JSON.stringify(applicationUrl)}, expectedStatus: 200, timeoutSeconds: 30 },
92
+ // Add at least one real positive and one negative before enabling HTTP proofs.
93
+ // httpProofs: [],
94
+ // Optional project-specific restore hook:
95
+ // runtimeAdapter: "infrastructure/rehearsal/runtime-adapter.mjs",
96
+ },
97
+
98
+ // Disposable local runtime identity, URL, and dedicated ports.
99
+ runtime: {
100
+ target: "supabase",
101
+ applicationUrl: ${JSON.stringify(applicationUrl)},
102
+ projectId: "${detected.projectName}-rehearsal",
103
+ apiPort: ${ports.api},
104
+ databasePort: ${ports.database},
105
+ studioPort: ${ports.studio},
106
+ },
107
+
108
+ // Only local runtime URLs are accepted; common hosted credentials are quarantined.
109
+ safety: {
110
+ allowedHosts: ["127.0.0.1", "::1", "localhost"],
111
+ blockedEnvironmentVariables: [
112
+ "SUPABASE_ACCESS_TOKEN",
113
+ "SUPABASE_DB_PASSWORD",
114
+ "SUPABASE_PROJECT_ID",
115
+ ],
116
+ hostedAccess: "disabled",
117
+ outboundNetwork: "deny",
118
+ },
119
+ });
120
+ `.replaceAll("\t", " ");
121
+ export const renderDetectedPostgresqlConfig = (detected, { applicationUrl = "http://localhost:5175", databasePort = 58322 } = {}) => `// @ts-check
122
+ /**
123
+ * Rehearsal configuration for ${detected.projectName}.
124
+ * Generated from this project by \`npx rehearsal\` and safe to commit.
125
+ * Review the CHECK comments. Keep passwords, tokens, and production URLs out of this file.
126
+ * Docs: https://github.com/Ddupasquier/rehearsal-db/blob/main/docs/configuration.md
127
+ */
128
+ import { defineRehearsalConfig } from "@rehearsal-db/core";
129
+
130
+ export default defineRehearsalConfig({
131
+ // Configuration format. Rehearsal will explain if an upgrade is ever needed.
132
+ schemaVersion: 1,
133
+ // Stable local name used in Rehearsal labels and reports.
134
+ project: { name: ${JSON.stringify(detected.projectName)} },
135
+
136
+ // Disposable PostgreSQL settings. The image must already exist locally.
137
+ postgresql: {
138
+ migrationDirectory: ${JSON.stringify(detected.postgresqlMigrationDirectory)},
139
+ runtimeWorkdir: ".rehearsal/runtime",
140
+ image: "postgres:17-alpine",
141
+ database: "postgres",
142
+ user: "postgres",
143
+ },
144
+
145
+ // Immutable local baseline files. Rehearsal never reads production on your behalf.
146
+ baseline: {
147
+ artifactDirectory: ".rehearsal",
148
+ sanitizationPolicy: "infrastructure/rehearsal/sanitization-policy.json",
149
+ },
150
+
151
+ // Optional source refresh. Enable only after reviewing docs/standalone-workflow.md.
152
+ // Credentials are read from the environment named by source-access-policy.json.
153
+ // preparation: {
154
+ // sourcePolicy: "infrastructure/rehearsal/source-access-policy.json",
155
+ // privacyKey: ".rehearsal/secrets/privacy.key",
156
+ // batchRows: 500,
157
+ // maximumRows: 1000000,
158
+ // maximumBytes: 2147483648,
159
+ // diskHeadroomBytes: 67108864,
160
+ // },
161
+ // Optional reviewed schemas/extensions/triggers/local-only rows.
162
+ // runtimePolicy: "infrastructure/rehearsal/runtime-policy.json",
163
+ // Optional copied-account association. The JSON stores only reviewed matcher hashes;
164
+ // raw emails/subjects and provider credentials stay in ignored environment files.
165
+ // identityPolicy: "infrastructure/rehearsal/identity-policy.json",
166
+
167
+ // Reuse any running Docker-compatible engine; start Colima only when needed.
168
+ containerRuntime: {
169
+ autoStartColima: true,
170
+ },
171
+
172
+ // Keep this many baseline generations, always including the active one.
173
+ cleanup: {
174
+ retainBaselineGenerations: 2,
175
+ },
176
+
177
+ // Optional: manage another isolated database as part of the same rehearsal.
178
+ // Give that database its own complete config, ports, project ID, and .rehearsal folder.
179
+ // dependentTargets: [
180
+ // {
181
+ // name: "publication-api",
182
+ // configPath: "rehearsal.publication.config.mjs",
183
+ // prepareCommand: "npm run rehearsal:prepare-publication",
184
+ // },
185
+ // ],
186
+
187
+ application: {
188
+ // CHECK: commands detected from package.json. Change them if they are not correct.
189
+ startCommand: ${JSON.stringify(detected.applicationCommand)},
190
+ proofCommand: ${JSON.stringify(detected.verificationCommand)},
191
+ environmentFile: ".rehearsal/runtime.env",
192
+ // Map generated local runtime values directly into the normal app command.
193
+ // environmentVariables: { DATABASE_URL: "primary:DATABASE_URL" },
194
+ // Required by \`rehearsal open\`; use a route that responds only when the app is ready.
195
+ readiness: { url: ${JSON.stringify(applicationUrl)}, expectedStatus: 200, timeoutSeconds: 30 },
196
+ // Add at least one real positive and one negative before enabling HTTP proofs.
197
+ // httpProofs: [],
198
+ // Optional project-specific restore hook:
199
+ // runtimeAdapter: "infrastructure/rehearsal/runtime-adapter.mjs",
200
+ },
201
+
202
+ // Disposable local runtime identity, URL, and dedicated database port.
203
+ runtime: {
204
+ target: "postgresql",
205
+ applicationUrl: ${JSON.stringify(applicationUrl)},
206
+ projectId: "${detected.projectName}-rehearsal",
207
+ databasePort: ${databasePort},
208
+ },
209
+
210
+ // Only local runtime URLs are accepted; common hosted credentials are quarantined.
211
+ safety: {
212
+ allowedHosts: ["127.0.0.1", "::1", "localhost"],
213
+ blockedEnvironmentVariables: [
214
+ "DATABASE_URL",
215
+ "PGHOST",
216
+ "PGPASSWORD",
217
+ "PGPORT",
218
+ "PGUSER",
219
+ ],
220
+ hostedAccess: "disabled",
221
+ outboundNetwork: "deny",
222
+ },
223
+ });
224
+ `.replaceAll("\t", " ");
@@ -0,0 +1,125 @@
1
+ /** Load a discovered config and resolve every owned path from the project root. */
2
+ import { type RehearsalConfigPathOptions } from "./configuration_discovery.mjs";
3
+ import { normalizeRehearsalConfig } from "./configuration_normalization.mjs";
4
+ export type NormalizedRehearsalConfig = ReturnType<typeof normalizeRehearsalConfig>;
5
+ export declare const loadRehearsalConfig: ({ projectRoot, configPath, }?: RehearsalConfigPathOptions) => Promise<Readonly<{
6
+ config: Readonly<{
7
+ schemaVersion: 1;
8
+ project: Readonly<{
9
+ name: string;
10
+ }>;
11
+ supabase: Readonly<{
12
+ workdir: string;
13
+ migrationDirectory: string;
14
+ rehearsalConfig: string;
15
+ runtimeWorkdir: string;
16
+ authentication: Readonly<{
17
+ enableLocalSignup: true;
18
+ environmentFile: string;
19
+ providers: readonly Readonly<{
20
+ name: "github" | "google";
21
+ clientIdEnvironmentVariable: string;
22
+ clientSecretEnvironmentVariable: string;
23
+ skipNonceCheck: boolean;
24
+ emailOptional: boolean;
25
+ }>[];
26
+ }> | null;
27
+ serviceEnvironmentFile: string | null;
28
+ serviceEnvironmentVariables: readonly string[];
29
+ }> | null;
30
+ postgresql: Readonly<{
31
+ migrationDirectory: string;
32
+ runtimeWorkdir: string;
33
+ image: string;
34
+ database: string;
35
+ user: string;
36
+ }> | null;
37
+ baseline: Readonly<{
38
+ artifactDirectory: string;
39
+ sanitizationPolicy: string;
40
+ }>;
41
+ containerRuntime: Readonly<{
42
+ autoStartColima: boolean;
43
+ }>;
44
+ cleanup: Readonly<{
45
+ retainBaselineGenerations: number;
46
+ }>;
47
+ preparation: Readonly<{
48
+ sourcePolicy: string;
49
+ privacyKey: string;
50
+ batchRows: number;
51
+ maximumRows: number;
52
+ maximumBytes: number;
53
+ diskHeadroomBytes: number;
54
+ }> | null;
55
+ runtimePolicy: string | null;
56
+ identityPolicy: string | null;
57
+ dependentTargets: readonly Readonly<{
58
+ name: string;
59
+ configPath: string;
60
+ prepareCommand: string | null;
61
+ }>[];
62
+ application: Readonly<{
63
+ startCommand: string;
64
+ proofCommand: string;
65
+ environmentFile: string;
66
+ environmentVariables: Readonly<Record<string, string>>;
67
+ readiness: Readonly<{
68
+ url: string;
69
+ expectedStatus: number;
70
+ timeoutSeconds: number;
71
+ }> | null;
72
+ httpProofs: readonly Readonly<{
73
+ name: string;
74
+ kind: "positive" | "negative";
75
+ url: string;
76
+ method: string;
77
+ expectedStatus: number;
78
+ json: Readonly<{
79
+ path: readonly string[];
80
+ equals?: unknown;
81
+ notEquals?: unknown;
82
+ minimumItems?: number;
83
+ }> | null;
84
+ }>[];
85
+ runtimeAdapter: string | null;
86
+ }>;
87
+ runtime: Readonly<{
88
+ target: "postgresql" | "supabase";
89
+ applicationUrl: string;
90
+ projectId: string;
91
+ ports: Readonly<{
92
+ api?: number;
93
+ database: number;
94
+ studio?: number;
95
+ }>;
96
+ }>;
97
+ safety: Readonly<{
98
+ allowedHosts: readonly string[];
99
+ blockedEnvironmentVariables: readonly string[];
100
+ authenticationProviders: readonly string[];
101
+ hostedAccess: "disabled";
102
+ outboundNetwork: "deny";
103
+ }>;
104
+ verification: Readonly<{
105
+ commands: readonly string[];
106
+ }>;
107
+ }>;
108
+ configPath: string;
109
+ projectRoot: string;
110
+ paths: Readonly<{
111
+ artifactDirectory: string;
112
+ applicationEnvironment: string;
113
+ migrationDirectory: string;
114
+ rehearsalConfig: string | null;
115
+ runtimeWorkdir: string;
116
+ serviceEnvironment: string | null;
117
+ sanitizationPolicy: string;
118
+ sourcePolicy: string | null;
119
+ privacyKey: string | null;
120
+ runtimePolicy: string | null;
121
+ identityPolicy: string | null;
122
+ supabaseWorkdir: string | null;
123
+ runtimeAdapter: string | null;
124
+ }>;
125
+ }>>;