@rehearsal-db/core 0.1.0-beta.8 → 0.1.0-rc.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (232) hide show
  1. package/CHANGELOG.md +364 -1
  2. package/COMPATIBILITY.md +30 -3
  3. package/README.md +69 -22
  4. package/dist/package.json +100 -0
  5. package/dist/scripts/install/create_root_config.d.mts +3 -0
  6. package/dist/scripts/install/create_root_config.mjs +13 -0
  7. package/dist/scripts/runtime/manage_database.d.mts +6 -0
  8. package/dist/scripts/runtime/manage_database.mjs +16 -0
  9. package/dist/src/application/interactive_task.d.mts +30 -0
  10. package/dist/src/application/interactive_task.mjs +83 -0
  11. package/dist/src/application/session.d.mts +97 -0
  12. package/dist/src/application/session.mjs +380 -0
  13. package/dist/src/baseline/artifact.d.mts +119 -0
  14. package/dist/src/baseline/artifact.mjs +522 -0
  15. package/dist/src/baseline/builder.d.mts +19 -0
  16. package/dist/src/baseline/builder.mjs +142 -0
  17. package/dist/src/baseline/input_discovery.d.mts +13 -0
  18. package/dist/src/baseline/input_discovery.mjs +149 -0
  19. package/dist/src/baseline/policy_review.d.mts +56 -0
  20. package/dist/src/baseline/policy_review.mjs +73 -0
  21. package/dist/src/baseline/preparation.d.mts +63 -0
  22. package/dist/src/baseline/preparation.mjs +295 -0
  23. package/dist/src/baseline/privacy_contract.d.mts +147 -0
  24. package/dist/src/baseline/privacy_contract.mjs +2 -0
  25. package/dist/src/baseline/privacy_dependency_graph.d.mts +7 -0
  26. package/dist/src/baseline/privacy_dependency_graph.mjs +110 -0
  27. package/dist/src/baseline/privacy_engine.d.mts +5 -0
  28. package/dist/src/baseline/privacy_engine.mjs +4 -0
  29. package/dist/src/baseline/privacy_key.d.mts +7 -0
  30. package/dist/src/baseline/privacy_key.mjs +42 -0
  31. package/dist/src/baseline/privacy_pipeline.d.mts +7 -0
  32. package/dist/src/baseline/privacy_pipeline.mjs +127 -0
  33. package/dist/src/baseline/privacy_policy.d.mts +6 -0
  34. package/dist/src/baseline/privacy_policy.mjs +237 -0
  35. package/dist/src/baseline/privacy_recipe_validation.d.mts +5 -0
  36. package/dist/src/baseline/privacy_recipe_validation.mjs +289 -0
  37. package/dist/src/baseline/privacy_rule_registry.d.mts +18 -0
  38. package/dist/src/baseline/privacy_rule_registry.mjs +143 -0
  39. package/dist/src/baseline/privacy_structured_json.d.mts +66 -0
  40. package/dist/src/baseline/privacy_structured_json.mjs +464 -0
  41. package/dist/src/baseline/privacy_transforms.d.mts +18 -0
  42. package/dist/src/baseline/privacy_transforms.mjs +142 -0
  43. package/dist/src/baseline/privacy_validation_shared.d.mts +31 -0
  44. package/dist/src/baseline/privacy_validation_shared.mjs +127 -0
  45. package/dist/src/baseline/sanitization_policy.d.mts +69 -0
  46. package/dist/src/baseline/sanitization_policy.mjs +227 -0
  47. package/dist/src/baseline/schema_snapshot.d.mts +19 -0
  48. package/dist/src/baseline/schema_snapshot.mjs +79 -0
  49. package/dist/src/cli/application_command_handlers.d.mts +8 -0
  50. package/dist/src/cli/application_command_handlers.mjs +52 -0
  51. package/dist/src/cli/arguments.d.mts +38 -0
  52. package/dist/src/cli/arguments.mjs +130 -0
  53. package/dist/src/cli/basic_command_handlers.d.mts +4 -0
  54. package/dist/src/cli/basic_command_handlers.mjs +57 -0
  55. package/dist/src/cli/cli_commands.d.mts +14 -0
  56. package/dist/src/cli/cli_commands.mjs +34 -0
  57. package/dist/src/cli/command_contract.d.mts +57 -0
  58. package/dist/src/cli/command_contract.mjs +39 -0
  59. package/dist/src/cli/command_output.d.mts +12 -0
  60. package/dist/src/cli/command_output.mjs +20 -0
  61. package/dist/src/cli/command_registry.d.mts +7 -0
  62. package/dist/src/cli/command_registry.mjs +14 -0
  63. package/dist/src/cli/guided.d.mts +53 -0
  64. package/dist/src/cli/guided.mjs +727 -0
  65. package/dist/src/cli/identity_command_handlers.d.mts +12 -0
  66. package/dist/src/cli/identity_command_handlers.mjs +239 -0
  67. package/dist/src/cli/identity_renderer.d.mts +8 -0
  68. package/dist/src/cli/identity_renderer.mjs +33 -0
  69. package/dist/src/cli/init_command.d.mts +21 -0
  70. package/dist/src/cli/init_command.mjs +90 -0
  71. package/dist/src/cli/inspection_command_handlers.d.mts +3 -0
  72. package/dist/src/cli/inspection_command_handlers.mjs +79 -0
  73. package/dist/src/cli/project_command_handlers.d.mts +11 -0
  74. package/dist/src/cli/project_command_handlers.mjs +92 -0
  75. package/dist/src/cli/project_commands.d.mts +283 -0
  76. package/dist/src/cli/project_commands.mjs +192 -0
  77. package/dist/src/cli/rehearsal.d.mts +7 -0
  78. package/dist/src/cli/rehearsal.mjs +190 -0
  79. package/dist/src/cli/renderers.d.mts +299 -0
  80. package/dist/src/cli/renderers.mjs +554 -0
  81. package/dist/src/cli/runtime_action_handlers.d.mts +12 -0
  82. package/dist/src/cli/runtime_action_handlers.mjs +201 -0
  83. package/dist/src/cli/runtime_commands.d.mts +294 -0
  84. package/dist/src/cli/runtime_commands.mjs +619 -0
  85. package/dist/src/cli/source_command_handlers.d.mts +8 -0
  86. package/dist/src/cli/source_command_handlers.mjs +62 -0
  87. package/dist/src/cli/source_commands.d.mts +436 -0
  88. package/dist/src/cli/source_commands.mjs +301 -0
  89. package/dist/src/cli/terminal.d.mts +59 -0
  90. package/dist/src/cli/terminal.mjs +230 -0
  91. package/dist/src/identity/claim.d.mts +5 -0
  92. package/dist/src/identity/claim.mjs +4 -0
  93. package/dist/src/identity/claim_contract.d.mts +135 -0
  94. package/dist/src/identity/claim_contract.mjs +6 -0
  95. package/dist/src/identity/claim_executor.d.mts +10 -0
  96. package/dist/src/identity/claim_executor.mjs +358 -0
  97. package/dist/src/identity/claim_identity_lookup.d.mts +23 -0
  98. package/dist/src/identity/claim_identity_lookup.mjs +134 -0
  99. package/dist/src/identity/claim_plan.d.mts +8 -0
  100. package/dist/src/identity/claim_plan.mjs +61 -0
  101. package/dist/src/identity/claim_policy.d.mts +3 -0
  102. package/dist/src/identity/claim_policy.mjs +377 -0
  103. package/dist/src/identity/claim_sql.d.mts +10 -0
  104. package/dist/src/identity/claim_sql.mjs +46 -0
  105. package/dist/src/identity/claim_verification.d.mts +13 -0
  106. package/dist/src/identity/claim_verification.mjs +35 -0
  107. package/dist/src/identity/connect.d.mts +30 -0
  108. package/dist/src/identity/connect.mjs +111 -0
  109. package/dist/src/identity/provider_configuration.d.mts +37 -0
  110. package/dist/src/identity/provider_configuration.mjs +132 -0
  111. package/dist/src/identity/storage.d.mts +21 -0
  112. package/dist/src/identity/storage.mjs +122 -0
  113. package/dist/src/index.d.mts +4 -0
  114. package/dist/src/index.mjs +3 -0
  115. package/dist/src/project/configuration.d.mts +13 -0
  116. package/dist/src/project/configuration.mjs +9 -0
  117. package/dist/src/project/configuration_contract.d.mts +125 -0
  118. package/dist/src/project/configuration_contract.mjs +27 -0
  119. package/dist/src/project/configuration_discovery.d.mts +7 -0
  120. package/dist/src/project/configuration_discovery.mjs +37 -0
  121. package/dist/src/project/configuration_normalization.d.mts +107 -0
  122. package/dist/src/project/configuration_normalization.mjs +302 -0
  123. package/dist/src/project/configuration_rendering.d.mts +14 -0
  124. package/dist/src/project/configuration_rendering.mjs +226 -0
  125. package/dist/src/project/configuration_resolution.d.mts +125 -0
  126. package/dist/src/project/configuration_resolution.mjs +81 -0
  127. package/dist/src/project/configuration_schema.d.mts +22 -0
  128. package/dist/src/project/configuration_schema.mjs +160 -0
  129. package/dist/src/project/configuration_validation.d.mts +22 -0
  130. package/dist/src/project/configuration_validation.mjs +136 -0
  131. package/dist/src/project/install_scaffold.d.mts +42 -0
  132. package/dist/src/project/install_scaffold.mjs +263 -0
  133. package/dist/src/project/project_detection.d.mts +14 -0
  134. package/dist/src/project/project_detection.mjs +47 -0
  135. package/dist/src/project/setup.d.mts +87 -0
  136. package/dist/src/project/setup.mjs +414 -0
  137. package/dist/src/project/support_report.d.mts +88 -0
  138. package/dist/src/project/support_report.mjs +83 -0
  139. package/dist/src/runtime/cleanup.d.mts +85 -0
  140. package/dist/src/runtime/cleanup.mjs +311 -0
  141. package/dist/src/runtime/lifecycle_engine.d.mts +63 -0
  142. package/dist/src/runtime/lifecycle_engine.mjs +114 -0
  143. package/dist/src/runtime/migration_history.d.mts +51 -0
  144. package/dist/src/runtime/migration_history.mjs +170 -0
  145. package/dist/src/runtime/plan.d.mts +134 -0
  146. package/dist/src/runtime/plan.mjs +637 -0
  147. package/dist/src/runtime/policy.d.mts +66 -0
  148. package/dist/src/runtime/policy.mjs +369 -0
  149. package/dist/src/runtime/restore.d.mts +22 -0
  150. package/dist/src/runtime/restore.mjs +276 -0
  151. package/dist/src/runtime/service_environment.d.mts +11 -0
  152. package/dist/src/runtime/service_environment.mjs +58 -0
  153. package/dist/src/runtime/topology.d.mts +51 -0
  154. package/dist/src/runtime/topology.mjs +128 -0
  155. package/dist/src/shared/diagnostics.d.mts +97 -0
  156. package/dist/src/shared/diagnostics.mjs +170 -0
  157. package/dist/src/shared/human_output.d.mts +2 -0
  158. package/{scripts/lib/rehearsal → dist/src/shared}/human_output.mjs +1 -3
  159. package/dist/src/shared/node_runtime.d.mts +14 -0
  160. package/dist/src/shared/node_runtime.mjs +25 -0
  161. package/dist/src/shared/operation_guard.d.mts +22 -0
  162. package/dist/src/shared/operation_guard.mjs +150 -0
  163. package/dist/src/shared/process_environment.d.mts +15 -0
  164. package/dist/src/shared/process_environment.mjs +50 -0
  165. package/dist/src/source/access.d.mts +165 -0
  166. package/dist/src/source/access.mjs +602 -0
  167. package/dist/src/source/asset_transfer.d.mts +27 -0
  168. package/dist/src/source/asset_transfer.mjs +202 -0
  169. package/dist/src/source/baseline.d.mts +66 -0
  170. package/dist/src/source/baseline.mjs +372 -0
  171. package/dist/src/source/external_reader.d.mts +42 -0
  172. package/dist/src/source/external_reader.mjs +278 -0
  173. package/dist/src/source/postgresql_access.d.mts +86 -0
  174. package/dist/src/source/postgresql_access.mjs +454 -0
  175. package/dist/src/source/privacy_paths.d.mts +10 -0
  176. package/dist/src/source/privacy_paths.mjs +27 -0
  177. package/dist/src/targets/driver.d.mts +2 -0
  178. package/dist/src/targets/driver.mjs +13 -0
  179. package/dist/src/targets/postgresql.d.mts +5 -0
  180. package/dist/src/targets/postgresql.mjs +620 -0
  181. package/dist/src/targets/supabase.d.mts +8 -0
  182. package/dist/src/targets/supabase.mjs +627 -0
  183. package/dist/src/targets/supabase_environment.d.mts +49 -0
  184. package/dist/src/targets/supabase_environment.mjs +162 -0
  185. package/dist/src/targets/target.d.mts +33 -0
  186. package/dist/src/targets/target.mjs +39 -0
  187. package/docs/README.md +40 -0
  188. package/docs/adapters.md +15 -6
  189. package/docs/architecture.md +183 -0
  190. package/docs/baselines.md +22 -1
  191. package/docs/commands.md +116 -16
  192. package/docs/configuration.md +314 -34
  193. package/docs/getting-started.md +77 -10
  194. package/docs/glossary.md +4 -0
  195. package/docs/index.md +48 -0
  196. package/docs/production-source.md +334 -33
  197. package/docs/releasing.md +24 -12
  198. package/docs/roadmap.md +40 -37
  199. package/docs/runtime-policies.md +264 -0
  200. package/docs/sanitization.md +592 -8
  201. package/docs/security-model.md +37 -8
  202. package/docs/stability.md +69 -0
  203. package/docs/standalone-workflow.md +130 -0
  204. package/docs/troubleshooting.md +88 -8
  205. package/docs/tutorial.md +7 -1
  206. package/docs/typescript.md +134 -0
  207. package/package.json +45 -27
  208. package/types/configuration.d.mts +5 -0
  209. package/scripts/lib/environment/local_supabase.mjs +0 -197
  210. package/scripts/lib/rehearsal/baseline_artifact.mjs +0 -565
  211. package/scripts/lib/rehearsal/baseline_builder.mjs +0 -160
  212. package/scripts/lib/rehearsal/baseline_preparation.mjs +0 -316
  213. package/scripts/lib/rehearsal/cleanup.mjs +0 -381
  214. package/scripts/lib/rehearsal/configuration.d.mts +0 -119
  215. package/scripts/lib/rehearsal/configuration.mjs +0 -847
  216. package/scripts/lib/rehearsal/diagnostics.mjs +0 -199
  217. package/scripts/lib/rehearsal/input_discovery.mjs +0 -155
  218. package/scripts/lib/rehearsal/migration_history.mjs +0 -220
  219. package/scripts/lib/rehearsal/plan.mjs +0 -685
  220. package/scripts/lib/rehearsal/policy_review.mjs +0 -92
  221. package/scripts/lib/rehearsal/process_environment.mjs +0 -64
  222. package/scripts/lib/rehearsal/runtime_restore.mjs +0 -314
  223. package/scripts/lib/rehearsal/sanitization_policy.mjs +0 -279
  224. package/scripts/lib/rehearsal/schema_snapshot.mjs +0 -113
  225. package/scripts/lib/rehearsal/service_environment.mjs +0 -82
  226. package/scripts/lib/rehearsal/setup.mjs +0 -379
  227. package/scripts/lib/rehearsal/support_report.mjs +0 -102
  228. package/scripts/lib/runtime/postgresql_runtime.mjs +0 -773
  229. package/scripts/lib/runtime/runtime_target.mjs +0 -66
  230. package/scripts/lib/runtime/supabase_runtime.mjs +0 -793
  231. package/scripts/operations/database/manage_rehearsal_database.mjs +0 -18
  232. package/scripts/operations/rehearsal/rehearsal_cli.mjs +0 -2169
@@ -0,0 +1,100 @@
1
+ {
2
+ "name": "@rehearsal-db/core",
3
+ "version": "0.1.0-rc.1",
4
+ "private": false,
5
+ "description": "Safely rehearse PostgreSQL and Supabase migrations against sanitized, production-shaped data.",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/Ddupasquier/rehearsal-db.git"
9
+ },
10
+ "bugs": {
11
+ "url": "https://github.com/Ddupasquier/rehearsal-db/issues"
12
+ },
13
+ "homepage": "https://ddupasquier.github.io/rehearsal-db/",
14
+ "publishConfig": {
15
+ "access": "public",
16
+ "provenance": true
17
+ },
18
+ "type": "module",
19
+ "engines": {
20
+ "node": "^22.0.0 || ^24.0.0 || ^26.0.0"
21
+ },
22
+ "bin": {
23
+ "rehearsal": "dist/src/cli/rehearsal.mjs"
24
+ },
25
+ "exports": {
26
+ ".": {
27
+ "types": "./types/configuration.d.mts",
28
+ "import": "./dist/src/index.mjs"
29
+ },
30
+ "./baseline": "./dist/src/baseline/artifact.mjs",
31
+ "./baseline-builder": "./dist/src/baseline/builder.mjs",
32
+ "./diagnostics": "./dist/src/shared/diagnostics.mjs",
33
+ "./migrations": "./dist/src/runtime/migration_history.mjs",
34
+ "./process-environment": "./dist/src/shared/process_environment.mjs",
35
+ "./privacy": "./dist/src/baseline/privacy_engine.mjs",
36
+ "./schema": "./dist/src/baseline/schema_snapshot.mjs",
37
+ "./service-environment": "./dist/src/runtime/service_environment.mjs",
38
+ "./source-access": "./dist/src/source/access.mjs"
39
+ },
40
+ "files": [
41
+ "dist",
42
+ "types",
43
+ "docs/*.md",
44
+ "README.md",
45
+ "BENCHMARKS.md",
46
+ "CHANGELOG.md",
47
+ "SECURITY.md",
48
+ "COMPATIBILITY.md",
49
+ "SUPPORT.md",
50
+ "LICENSE"
51
+ ],
52
+ "scripts": {
53
+ "postinstall": "node dist/scripts/install/create_root_config.mjs",
54
+ "prepack": "npm run build",
55
+ "build": "node scripts/build/clean.mjs && tsc --project tsconfig.build.json",
56
+ "docs:build": "node scripts/docs/build.mjs",
57
+ "docs:preview": "node scripts/docs/serve.mjs",
58
+ "test": "npm run build && vitest run",
59
+ "test:unit": "npm run build && vitest run tests/unit",
60
+ "test:integration": "npm run build && vitest run tests/integration tests/contracts",
61
+ "test:docs": "npm run build && vitest run tests/contracts/documentationCommands.test.mjs",
62
+ "test:fixture": "npm run build && node scripts/verification/run_scenario.mjs supabase",
63
+ "test:fixture:postgresql": "npm run build && node scripts/verification/run_scenario.mjs postgresql",
64
+ "test:fixture:dependent": "npm run build && node scripts/verification/run_scenario.mjs dependent-target",
65
+ "test:fixture:onboarding": "npm run build && node scripts/verification/run_scenario.mjs onboarding",
66
+ "test:fixture:typescript": "npm run build && node scripts/verification/run_scenario.mjs typescript",
67
+ "test:fixture:standalone": "npm run build && node scripts/verification/run_scenario.mjs standalone",
68
+ "test:fixture:privacy": "npm run build && node scripts/verification/run_scenario.mjs privacy",
69
+ "release:verify": "node scripts/verification/release_gate.mjs",
70
+ "check": "npm run check:syntax && npm run typecheck && npm run test && npm run docs:build && npm run format:check && npm run package:audit",
71
+ "check:syntax": "find scripts tests -type f -name '*.mjs' -exec node --check {} +",
72
+ "typecheck": "npm run build && tsc --project tsconfig.json",
73
+ "format": "prettier --write .",
74
+ "format:check": "prettier --check .",
75
+ "package:audit": "node scripts/verification/audit_package.mjs"
76
+ },
77
+ "keywords": [
78
+ "postgresql",
79
+ "supabase",
80
+ "migration",
81
+ "testing",
82
+ "database"
83
+ ],
84
+ "license": "MIT",
85
+ "dependencies": {
86
+ "@clack/prompts": "^1.8.1",
87
+ "pg": "^8.23.1"
88
+ },
89
+ "devDependencies": {
90
+ "@fontsource-variable/dm-sans": "^5.3.0",
91
+ "@fontsource-variable/fraunces": "^5.3.0",
92
+ "@lydell/node-pty": "^1.2.0-beta.15",
93
+ "@types/node": "22.20.5",
94
+ "@types/pg": "^8.23.1",
95
+ "marked": "^18.0.14",
96
+ "prettier": "^3.9.6",
97
+ "typescript": "7.0.2",
98
+ "vitest": "^5.0.2"
99
+ }
100
+ }
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ /** Create safe project-root Rehearsal scaffolding during a local install. */
3
+ export {};
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env node
2
+ /** Create safe project-root Rehearsal scaffolding during a local install. */
3
+ import { fileURLToPath } from "node:url";
4
+ import { createInstalledRehearsalScaffold, renderInstalledRehearsalScaffold, } from "../../src/project/install_scaffold.mjs";
5
+ const packageRoot = fileURLToPath(new URL("../../..", import.meta.url));
6
+ try {
7
+ const result = await createInstalledRehearsalScaffold({ packageRoot });
8
+ console.log(renderInstalledRehearsalScaffold(result));
9
+ }
10
+ catch (error) {
11
+ const message = error instanceof Error ? error.message : String(error);
12
+ console.warn(`Rehearsal could not safely create project files during installation: ${message}\nNext: run npx rehearsal from the application directory.`);
13
+ }
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Purpose: Select the configured database runtime and forward the requested
4
+ * lifecycle action to its isolated driver.
5
+ */
6
+ export {};
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Purpose: Select the configured database runtime and forward the requested
4
+ * lifecycle action to its isolated driver.
5
+ */
6
+ import { loadRehearsalConfig } from "../../src/project/configuration.mjs";
7
+ import { parseRuntimeInvocation } from "../../src/targets/target.mjs";
8
+ import { runRuntimeTarget } from "../../src/targets/driver.mjs";
9
+ const invocation = parseRuntimeInvocation();
10
+ const { config } = await loadRehearsalConfig({
11
+ projectRoot: process.cwd(),
12
+ ...(invocation.configPath === undefined
13
+ ? {}
14
+ : { configPath: invocation.configPath }),
15
+ });
16
+ await runRuntimeTarget(config.runtime.target);
@@ -0,0 +1,30 @@
1
+ /** Run identity discovery while an owned local application remains available. */
2
+ import type { EventEmitter } from "node:events";
3
+ import { type ApplicationDiagnostics, type ApplicationSession, type ApplicationSessionSignal } from "./session.mjs";
4
+ type SignalTarget = Pick<EventEmitter, "prependListener" | "removeListener">;
5
+ interface SessionInput {
6
+ readonly isTTY?: boolean;
7
+ prependListener(event: "data", listener: (chunk: Buffer | string) => void): unknown;
8
+ removeListener(event: "data", listener: (chunk: Buffer | string) => void): unknown;
9
+ }
10
+ /**
11
+ * A terminal interruption aborts the task and retires the owned process group.
12
+ * A completed task leaves the session running so its caller can deliberately
13
+ * stop, reuse, or hand it back to the persistent application holder.
14
+ */
15
+ export declare const runApplicationSessionTask: <Value>({ session, task, signalTarget, input, onReady, }: {
16
+ session: ApplicationSession;
17
+ task: (signal: AbortSignal) => Promise<Value>;
18
+ signalTarget?: SignalTarget;
19
+ input?: SessionInput;
20
+ onReady?: (ready: ApplicationSession["ready"]) => void;
21
+ }) => Promise<Readonly<{
22
+ completed: true;
23
+ value: Value;
24
+ diagnostics: ApplicationDiagnostics;
25
+ }> | Readonly<{
26
+ completed: false;
27
+ signal: ApplicationSessionSignal;
28
+ diagnostics: ApplicationDiagnostics;
29
+ }>>;
30
+ export {};
@@ -0,0 +1,83 @@
1
+ /** Run identity discovery while an owned local application remains available. */
2
+ import { summarizeProjectCommandFailure, } from "./session.mjs";
3
+ const SESSION_SIGNALS = ["SIGINT", "SIGTERM", "SIGHUP", "SIGTSTP"];
4
+ /**
5
+ * A terminal interruption aborts the task and retires the owned process group.
6
+ * A completed task leaves the session running so its caller can deliberately
7
+ * stop, reuse, or hand it back to the persistent application holder.
8
+ */
9
+ export const runApplicationSessionTask = async ({ session, task, signalTarget = process, input = process.stdin, onReady = () => undefined, }) => {
10
+ if (!session ||
11
+ typeof session.wait !== "function" ||
12
+ typeof session.stop !== "function") {
13
+ throw new Error("A started application session is required.");
14
+ }
15
+ let finishInterruption = () => undefined;
16
+ const interruption = new Promise((resolve) => {
17
+ finishInterruption = resolve;
18
+ });
19
+ const handlers = new Map(SESSION_SIGNALS.map((signal) => [
20
+ signal,
21
+ () => finishInterruption({ kind: "interrupted", signal }),
22
+ ]));
23
+ for (const [signal, handler] of handlers) {
24
+ signalTarget.prependListener(signal, handler);
25
+ }
26
+ const onInput = (chunk) => {
27
+ const bytes = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
28
+ if (bytes.includes(0x03)) {
29
+ finishInterruption({ kind: "interrupted", signal: "SIGINT" });
30
+ }
31
+ else if (bytes.includes(0x1a)) {
32
+ finishInterruption({ kind: "interrupted", signal: "SIGTSTP" });
33
+ }
34
+ };
35
+ if (input?.isTTY)
36
+ input.prependListener("data", onInput);
37
+ const abortController = new AbortController();
38
+ try {
39
+ onReady(session.ready);
40
+ const outcome = await Promise.race([
41
+ interruption,
42
+ task(abortController.signal).then((value) => ({
43
+ kind: "completed",
44
+ value,
45
+ })),
46
+ session.wait().then((exit) => ({ kind: "exited", ...exit })),
47
+ ]);
48
+ if (outcome.kind === "exited") {
49
+ throw new Error(`Application exited before identity connection finished (${summarizeProjectCommandFailure({
50
+ status: outcome.status,
51
+ signal: outcome.signal,
52
+ stdoutByteCount: session.diagnostics().stdoutBytes,
53
+ stderrByteCount: session.diagnostics().stderrBytes,
54
+ })}).`);
55
+ }
56
+ if (outcome.kind === "interrupted") {
57
+ abortController.abort(new Error(`Identity connection was interrupted by ${outcome.signal}.`));
58
+ await session.stop();
59
+ return Object.freeze({
60
+ completed: false,
61
+ signal: outcome.signal,
62
+ diagnostics: session.diagnostics(),
63
+ });
64
+ }
65
+ return Object.freeze({
66
+ completed: true,
67
+ value: outcome.value,
68
+ diagnostics: session.diagnostics(),
69
+ });
70
+ }
71
+ catch (error) {
72
+ abortController.abort(error);
73
+ await session.stop();
74
+ throw error;
75
+ }
76
+ finally {
77
+ for (const [signal, handler] of handlers) {
78
+ signalTarget.removeListener(signal, handler);
79
+ }
80
+ if (input?.isTTY)
81
+ input.removeListener("data", onInput);
82
+ }
83
+ };
@@ -0,0 +1,97 @@
1
+ /** Launch ordinary application commands against verified local runtime files. */
2
+ import { spawn } from "node:child_process";
3
+ import type { EventEmitter } from "node:events";
4
+ declare const SESSION_SIGNALS: string[];
5
+ type SessionSignal = (typeof SESSION_SIGNALS)[number];
6
+ export type ApplicationSessionSignal = SessionSignal;
7
+ export interface ApplicationReadiness {
8
+ readonly url: string;
9
+ readonly expectedStatus?: number;
10
+ readonly timeoutSeconds?: number;
11
+ }
12
+ export interface ApplicationSession {
13
+ readonly pid: number | undefined;
14
+ readonly ready: Readonly<{
15
+ url: string;
16
+ status: number;
17
+ }>;
18
+ readonly stop: () => Promise<void>;
19
+ readonly wait: () => Promise<ChildExit>;
20
+ readonly diagnostics: () => ApplicationDiagnostics;
21
+ }
22
+ export interface ApplicationDiagnostics {
23
+ readonly stdoutBytes: number;
24
+ readonly stderrBytes: number;
25
+ }
26
+ interface ChildExit {
27
+ readonly status: number | null;
28
+ readonly signal: NodeJS.Signals | null;
29
+ }
30
+ interface SessionInput {
31
+ readonly isTTY?: boolean;
32
+ prependListener(event: "data", listener: (chunk: Buffer | string) => void): unknown;
33
+ removeListener(event: "data", listener: (chunk: Buffer | string) => void): unknown;
34
+ }
35
+ interface EnvironmentInput {
36
+ readonly files: Readonly<Record<string, string>> & {
37
+ readonly primary: string;
38
+ };
39
+ readonly mappings: Readonly<Record<string, string>>;
40
+ }
41
+ interface HttpJsonAssertion {
42
+ readonly path: readonly string[];
43
+ readonly equals?: unknown;
44
+ readonly notEquals?: unknown;
45
+ readonly minimumItems?: number;
46
+ }
47
+ export interface HttpProofCheck {
48
+ readonly name: string;
49
+ readonly kind: "positive" | "negative";
50
+ readonly url: string;
51
+ readonly method?: string;
52
+ readonly expectedStatus: number;
53
+ readonly timeoutMs?: number;
54
+ readonly json?: HttpJsonAssertion | null;
55
+ }
56
+ type SignalTarget = Pick<EventEmitter, "prependListener" | "removeListener">;
57
+ export declare const buildApplicationEnvironment: ({ files, mappings, }: EnvironmentInput) => Promise<Record<string, string>>;
58
+ export declare const summarizeProjectCommandFailure: ({ error, status, signal, stdout, stderr, stdoutByteCount, stderrByteCount, }: {
59
+ error?: NodeJS.ErrnoException;
60
+ status: number | null;
61
+ signal: NodeJS.Signals | null;
62
+ stdout?: string;
63
+ stderr?: string;
64
+ stdoutByteCount?: number;
65
+ stderrByteCount?: number;
66
+ }) => string;
67
+ export declare const startApplicationSession: ({ command, cwd, files, mappings, readiness, inheritedEnvironment, spawnImplementation, fetchImplementation, signalTarget, }: EnvironmentInput & {
68
+ command: string;
69
+ cwd: string;
70
+ readiness: ApplicationReadiness;
71
+ inheritedEnvironment?: NodeJS.ProcessEnv;
72
+ spawnImplementation?: typeof spawn;
73
+ fetchImplementation?: typeof fetch;
74
+ signalTarget?: SignalTarget;
75
+ }) => Promise<ApplicationSession>;
76
+ /**
77
+ * Keep a ready application session attached until the user interrupts it.
78
+ * The child process group is always stopped before this function returns.
79
+ */
80
+ export declare const holdApplicationSession: ({ session, signalTarget, input, onReady, }: {
81
+ session: ApplicationSession;
82
+ signalTarget?: SignalTarget;
83
+ input?: SessionInput;
84
+ onReady?: (ready: ApplicationSession["ready"]) => void;
85
+ }) => Promise<Readonly<{
86
+ signal: SessionSignal;
87
+ diagnostics: ApplicationDiagnostics;
88
+ }>>;
89
+ export declare const runHttpProofs: ({ checks, fetchImplementation, }: {
90
+ checks: readonly HttpProofCheck[];
91
+ fetchImplementation?: typeof fetch;
92
+ }) => Promise<readonly Readonly<{
93
+ name: string;
94
+ kind: "positive" | "negative";
95
+ status: number;
96
+ }>[]>;
97
+ export {};