@empire-builder-kit/nx 1.0.0-rc.37 → 1.0.0-rc.39

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 (637) hide show
  1. package/README.md +18 -0
  2. package/executors.json +5 -0
  3. package/generators.json +10 -0
  4. package/package.json +20 -3
  5. package/src/aws-authority/index.d.ts +1 -0
  6. package/src/aws-authority/index.js +1 -0
  7. package/src/aws-authority/lambda-policy-ordering.d.ts +38 -0
  8. package/src/aws-authority/lambda-policy-ordering.js +56 -0
  9. package/src/aws-authority/stage-authority.d.ts +11 -3
  10. package/src/aws-authority/stage-authority.js +615 -29
  11. package/src/blueprints/external-sandbox.js +21 -9
  12. package/src/blueprints/manifest.d.ts +1 -1
  13. package/src/blueprints/resolver.js +28 -15
  14. package/src/cli/bootstrap.d.ts +1 -1
  15. package/src/cli/deploy-runtime.d.ts +6 -0
  16. package/src/cli/deploy-runtime.js +58 -0
  17. package/src/cli/dev-command.d.ts +16 -4
  18. package/src/cli/dev-command.js +63 -0
  19. package/src/cli/main.d.ts +7 -1
  20. package/src/cli/main.js +128 -20
  21. package/src/cli/output.d.ts +1 -1
  22. package/src/developer-agent/context.js +41 -9
  23. package/src/developer-agent/generator-planning.js +16 -2
  24. package/src/developer-agent/git-inspection.d.ts +6 -2
  25. package/src/developer-agent/git-inspection.js +78 -6
  26. package/src/developer-agent/model.d.ts +4 -2
  27. package/src/developer-agent/operation-registry.d.ts +5 -0
  28. package/src/developer-agent/operation-registry.js +179 -23
  29. package/src/developer-agent/preview-changes.d.ts +2 -0
  30. package/src/developer-agent/preview-changes.js +14 -2
  31. package/src/developer-agent/preview-source.js +3 -0
  32. package/src/developer-agent/validation.js +20 -8
  33. package/src/developer-agent/workspace-inspection.js +37 -3
  34. package/src/executors/deployment-plan/deployment-plan.d.ts +2 -0
  35. package/src/executors/deployment-plan/deployment-plan.js +51 -4
  36. package/src/executors/dev-doctor/dev-doctor.js +13 -6
  37. package/src/executors/dev-task-cleanup/dev-task-cleanup.d.ts +23 -0
  38. package/src/executors/dev-task-cleanup/dev-task-cleanup.js +145 -0
  39. package/src/executors/dev-task-cleanup/schema.json +9 -0
  40. package/src/executors/dev-task-cleanup/task-stack-absence.d.ts +27 -0
  41. package/src/executors/dev-task-cleanup/task-stack-absence.js +281 -0
  42. package/src/executors/dev-task-cleanup/task-stack-checkpoint.d.ts +12 -0
  43. package/src/executors/dev-task-cleanup/task-stack-checkpoint.js +92 -0
  44. package/src/executors/fleet/fleet.js +1 -1
  45. package/src/executors/foundation-remove-preflight/foundation-remove-preflight.js +28 -1
  46. package/src/executors/local-deploy/local-deploy.d.ts +8 -1
  47. package/src/executors/local-deploy/local-deploy.js +97 -24
  48. package/src/executors/local-deploy/schema.json +8 -0
  49. package/src/executors/router-waf-rehearsal/router-waf-rehearsal.js +30 -18
  50. package/src/executors/sst-lifecycle/governed-native-operation.d.ts +2 -0
  51. package/src/executors/sst-lifecycle/governed-native-operation.js +9 -0
  52. package/src/executors/sst-lifecycle/run-sst-command.d.ts +5 -0
  53. package/src/executors/sst-lifecycle/run-sst-command.js +220 -32
  54. package/src/executors/sst-lifecycle/sst-environment-source.d.ts +8 -0
  55. package/src/executors/sst-lifecycle/sst-environment-source.js +54 -0
  56. package/src/executors/sst-lifecycle/task-unlock.d.ts +15 -0
  57. package/src/executors/sst-lifecycle/task-unlock.js +126 -0
  58. package/src/foundation/capability-plan.d.ts +43 -0
  59. package/src/foundation/capability-plan.js +168 -0
  60. package/src/foundation/discovery.d.ts +14 -11
  61. package/src/foundation/discovery.js +32 -6
  62. package/src/foundation/index.d.ts +1 -0
  63. package/src/foundation/index.js +1 -0
  64. package/src/foundation/local-database-contract.d.ts +20 -0
  65. package/src/foundation/local-database-contract.js +262 -13
  66. package/src/foundation/local-private-smoke-access.d.ts +20 -0
  67. package/src/foundation/local-private-smoke-access.js +197 -0
  68. package/src/foundation/preflight.js +37 -18
  69. package/src/foundation/private-smoke-access.js +10 -2
  70. package/src/foundation/private-smoke-admission.d.ts +3 -1
  71. package/src/foundation/private-smoke-admission.js +29 -8
  72. package/src/foundation/private-smoke-control-plane.js +17 -6
  73. package/src/foundation/provision-database-bindings.d.ts +5 -0
  74. package/src/foundation/provision-database-bindings.js +41 -8
  75. package/src/foundation/provision-logical-database.js +13 -8
  76. package/src/foundation/requirements.d.ts +3 -3
  77. package/src/foundation/requirements.js +24 -12
  78. package/src/foundation/router-waf.d.ts +1 -0
  79. package/src/foundation/router-waf.js +14 -1
  80. package/src/generators/blueprint/blueprint.d.ts +5 -0
  81. package/src/generators/blueprint/blueprint.js +102 -0
  82. package/src/generators/blueprint/files.d.ts +6 -0
  83. package/src/generators/blueprint/files.js +217 -0
  84. package/src/generators/blueprint/schema.d.ts +4 -0
  85. package/src/generators/blueprint/schema.json +18 -0
  86. package/src/generators/formatting.js +24 -1
  87. package/src/generators/logging-registry.d.ts +2 -0
  88. package/src/generators/logging-registry.js +22 -0
  89. package/src/generators/preset/workspace-files-adopter-skills.d.ts +7 -0
  90. package/src/generators/preset/workspace-files-adopter-skills.js +301 -0
  91. package/src/generators/preset/workspace-files-ci-install.d.ts +2 -0
  92. package/src/generators/preset/workspace-files-ci-install.js +196 -0
  93. package/src/generators/preset/workspace-files-developer-agent.js +40 -13
  94. package/src/generators/preset/workspace-files-performance-load.js +8 -0
  95. package/src/generators/preset/workspace-files-stage-authority.js +40 -1
  96. package/src/generators/preset/workspace-files-thin-deploy.js +66 -34
  97. package/src/generators/preset/workspace-files-thin-docs.js +64 -18
  98. package/src/generators/preset/workspace-files.d.ts +4 -0
  99. package/src/generators/preset/workspace-files.js +159 -91
  100. package/src/generators/repository-policy/repository-policy.js +37 -0
  101. package/src/generators/slice/built-in-plan-api-contract-files.js +42 -7
  102. package/src/generators/slice/built-in-plan-api-files.d.ts +1 -1
  103. package/src/generators/slice/built-in-plan-api-files.js +47 -389
  104. package/src/generators/slice/built-in-plan-async-work-files.js +19 -1912
  105. package/src/generators/slice/built-in-plan-authorization-files.js +92 -329
  106. package/src/generators/slice/built-in-plan-authorization-infrastructure-files.js +36 -2
  107. package/src/generators/slice/built-in-plan-authorization-storage.d.ts +3 -0
  108. package/src/generators/slice/built-in-plan-authorization-storage.js +119 -0
  109. package/src/generators/slice/built-in-plan-background-work-files.d.ts +1 -1
  110. package/src/generators/slice/built-in-plan-background-work-files.js +15 -5
  111. package/src/generators/slice/built-in-plan-data-deletion-files.js +2 -830
  112. package/src/generators/slice/built-in-plan-data-files.d.ts +1 -1
  113. package/src/generators/slice/built-in-plan-data-files.js +61 -1164
  114. package/src/generators/slice/built-in-plan-data-lifecycle-files.js +53 -28
  115. package/src/generators/slice/built-in-plan-data-lifecycle-runtime-files.js +18 -2
  116. package/src/generators/slice/built-in-plan-data-retention-job-files.js +7 -2446
  117. package/src/generators/slice/built-in-plan-data-retention-launcher-files.js +30 -6
  118. package/src/generators/slice/built-in-plan-data-rights-files.js +6 -4482
  119. package/src/generators/slice/built-in-plan-database-lifecycle-files.js +4 -15
  120. package/src/generators/slice/built-in-plan-foundation-files.d.ts +2 -1
  121. package/src/generators/slice/built-in-plan-foundation-files.js +34 -10
  122. package/src/generators/slice/built-in-plan-frontend-files.js +2 -2
  123. package/src/generators/slice/built-in-plan-infrastructure-files.d.ts +1 -1
  124. package/src/generators/slice/built-in-plan-infrastructure-files.js +180 -522
  125. package/src/generators/slice/built-in-plan-key-value-cleanup.d.ts +4 -0
  126. package/src/generators/slice/built-in-plan-key-value-cleanup.js +100 -0
  127. package/src/generators/slice/built-in-plan-key-value-consumer.d.ts +4 -0
  128. package/src/generators/slice/built-in-plan-key-value-consumer.js +151 -0
  129. package/src/generators/slice/built-in-plan-key-value-deletion.d.ts +2 -0
  130. package/src/generators/slice/built-in-plan-key-value-deletion.js +377 -0
  131. package/src/generators/slice/built-in-plan-key-value-delivery.d.ts +2 -0
  132. package/src/generators/slice/built-in-plan-key-value-delivery.js +120 -0
  133. package/src/generators/slice/built-in-plan-key-value-export.d.ts +2 -0
  134. package/src/generators/slice/built-in-plan-key-value-export.js +595 -0
  135. package/src/generators/slice/built-in-plan-key-value-files.d.ts +2 -0
  136. package/src/generators/slice/built-in-plan-key-value-files.js +31 -0
  137. package/src/generators/slice/built-in-plan-key-value-holds.d.ts +2 -0
  138. package/src/generators/slice/built-in-plan-key-value-holds.js +189 -0
  139. package/src/generators/slice/built-in-plan-key-value-infrastructure.d.ts +2 -0
  140. package/src/generators/slice/built-in-plan-key-value-infrastructure.js +102 -0
  141. package/src/generators/slice/built-in-plan-key-value-performance.d.ts +5 -0
  142. package/src/generators/slice/built-in-plan-key-value-performance.js +530 -0
  143. package/src/generators/slice/built-in-plan-key-value-provider.d.ts +4 -0
  144. package/src/generators/slice/built-in-plan-key-value-provider.js +366 -0
  145. package/src/generators/slice/built-in-plan-key-value-records.d.ts +3 -0
  146. package/src/generators/slice/built-in-plan-key-value-records.js +232 -0
  147. package/src/generators/slice/built-in-plan-key-value-retention-infrastructure.d.ts +2 -0
  148. package/src/generators/slice/built-in-plan-key-value-retention-infrastructure.js +103 -0
  149. package/src/generators/slice/built-in-plan-key-value-retention-job-files.d.ts +2 -0
  150. package/src/generators/slice/built-in-plan-key-value-retention-job-files.js +160 -0
  151. package/src/generators/slice/built-in-plan-key-value-retention-maintenance.d.ts +2 -0
  152. package/src/generators/slice/built-in-plan-key-value-retention-maintenance.js +329 -0
  153. package/src/generators/slice/built-in-plan-key-value-retention-worker.d.ts +2 -0
  154. package/src/generators/slice/built-in-plan-key-value-retention-worker.js +477 -0
  155. package/src/generators/slice/built-in-plan-key-value-retention.d.ts +2 -0
  156. package/src/generators/slice/built-in-plan-key-value-retention.js +184 -0
  157. package/src/generators/slice/built-in-plan-metadata-files.d.ts +1 -1
  158. package/src/generators/slice/built-in-plan-metadata-files.js +140 -28
  159. package/src/generators/slice/built-in-plan-native-runtime-authority-files.d.ts +1 -1
  160. package/src/generators/slice/built-in-plan-native-runtime-authority-files.js +36 -19
  161. package/src/generators/slice/built-in-plan-operations-files.d.ts +1 -1
  162. package/src/generators/slice/built-in-plan-operations-files.js +89 -50
  163. package/src/generators/slice/built-in-plan-performance-files.js +84 -1010
  164. package/src/generators/slice/built-in-plan-project-files.js +116 -67
  165. package/src/generators/slice/built-in-plan-release-files.d.ts +1 -1
  166. package/src/generators/slice/built-in-plan-release-files.js +64 -15
  167. package/src/generators/slice/built-in-plan-reliability-files.js +54 -28
  168. package/src/generators/slice/built-in-plan-shared.d.ts +4 -2
  169. package/src/generators/slice/built-in-plan-shared.js +41 -19
  170. package/src/generators/slice/built-in-plan-sql-events.d.ts +2 -0
  171. package/src/generators/slice/built-in-plan-sql-events.js +257 -0
  172. package/src/generators/slice/built-in-plan-testing-files.d.ts +1 -1
  173. package/src/generators/slice/built-in-plan-testing-files.js +184 -132
  174. package/src/generators/slice/built-in-plan-testing-persistence-files.d.ts +2 -0
  175. package/src/generators/slice/built-in-plan-testing-persistence-files.js +178 -0
  176. package/src/generators/slice/built-in-plan-thin-release-files.d.ts +1 -1
  177. package/src/generators/slice/built-in-plan-thin-release-files.js +35 -2
  178. package/src/generators/slice/built-in-plan-verification-files.js +70 -0
  179. package/src/generators/slice/built-in-plan-web-files.d.ts +1 -1
  180. package/src/generators/slice/built-in-plan-web-files.js +206 -14
  181. package/src/generators/slice/built-in-plan-workload-role-files.d.ts +1 -1
  182. package/src/generators/slice/built-in-plan-workload-role-files.js +113 -274
  183. package/src/generators/slice/built-in-plan.d.ts +9 -1
  184. package/src/generators/slice/built-in-plan.js +49 -21
  185. package/src/generators/slice/data-policy-review-seed.d.ts +2 -0
  186. package/src/generators/slice/data-policy-review-seed.js +22 -0
  187. package/src/generators/slice/deployed-smoke-readiness.d.ts +2 -0
  188. package/src/generators/slice/deployed-smoke-readiness.js +214 -0
  189. package/src/generators/slice/local-source-identity.d.ts +2 -0
  190. package/src/generators/slice/local-source-identity.js +31 -0
  191. package/src/generators/slice/persistence-contract.d.ts +14 -0
  192. package/src/generators/slice/persistence-contract.js +32 -0
  193. package/src/generators/slice/slice.js +29 -24
  194. package/src/generators/sql/schema.d.ts +7 -0
  195. package/src/generators/sql/schema.json +38 -0
  196. package/src/generators/sql/sql.d.ts +6 -0
  197. package/src/generators/sql/sql.js +53 -0
  198. package/src/generators/upgrade/sql-seeded-reconciliation.d.ts +2 -0
  199. package/src/generators/upgrade/sql-seeded-reconciliation.js +170 -0
  200. package/src/generators/upgrade/upgrade.d.ts +2 -0
  201. package/src/generators/upgrade/upgrade.js +136 -9
  202. package/src/generators/workload/workload.js +51 -2
  203. package/src/local-dev/browser-verification.d.ts +37 -0
  204. package/src/local-dev/browser-verification.js +281 -0
  205. package/src/local-dev/contracts.d.ts +10 -1
  206. package/src/local-dev/contracts.js +114 -13
  207. package/src/local-dev/dev-command-core.js +24 -5
  208. package/src/local-dev/docker-credential-health.d.ts +14 -0
  209. package/src/local-dev/docker-credential-health.js +94 -0
  210. package/src/local-dev/environment-inspector.d.ts +7 -0
  211. package/src/local-dev/environment-inspector.js +42 -15
  212. package/src/local-dev/environment-state.js +2 -2
  213. package/src/local-dev/errors.d.ts +1 -1
  214. package/src/local-dev/errors.js +2 -0
  215. package/src/local-dev/fleet-client.js +2 -2
  216. package/src/local-dev/fleet-configuration.js +57 -25
  217. package/src/local-dev/fleet-inventory.js +46 -18
  218. package/src/local-dev/fleet-ipc.d.ts +7 -0
  219. package/src/local-dev/fleet-ipc.js +14 -2
  220. package/src/local-dev/fleet-launcher.d.ts +6 -0
  221. package/src/local-dev/fleet-launcher.js +14 -2
  222. package/src/local-dev/fleet-logs.js +50 -22
  223. package/src/local-dev/fleet-process.d.ts +20 -1
  224. package/src/local-dev/fleet-process.js +197 -41
  225. package/src/local-dev/fleet-runner-evidence.d.ts +5 -0
  226. package/src/local-dev/fleet-runner-evidence.js +56 -0
  227. package/src/local-dev/fleet-runtime.js +268 -229
  228. package/src/local-dev/fleet-session.d.ts +2 -0
  229. package/src/local-dev/fleet-session.js +28 -11
  230. package/src/local-dev/fleet-slice-runner-daemon.js +4 -0
  231. package/src/local-dev/fleet-state.d.ts +5 -2
  232. package/src/local-dev/fleet-state.js +25 -4
  233. package/src/local-dev/fleet-supervisor.d.ts +3 -0
  234. package/src/local-dev/fleet-supervisor.js +66 -11
  235. package/src/local-dev/fleet-web-start.d.ts +12 -0
  236. package/src/local-dev/fleet-web-start.js +48 -0
  237. package/src/local-dev/identity.js +3 -14
  238. package/src/local-dev/index.d.ts +1 -0
  239. package/src/local-dev/index.js +1 -0
  240. package/src/local-dev/native-completion.d.ts +9 -0
  241. package/src/local-dev/native-completion.js +130 -0
  242. package/src/local-dev/nx-workspace.d.ts +4 -2
  243. package/src/local-dev/nx-workspace.js +11 -6
  244. package/src/local-dev/personal-stage.d.ts +4 -5
  245. package/src/local-dev/personal-stage.js +6 -54
  246. package/src/local-dev/port-claims.d.ts +13 -0
  247. package/src/local-dev/port-claims.js +46 -0
  248. package/src/local-dev/ports.d.ts +14 -2
  249. package/src/local-dev/ports.js +78 -3
  250. package/src/local-dev/private-state.d.ts +6 -0
  251. package/src/local-dev/private-state.js +126 -34
  252. package/src/local-dev/process-group.d.ts +4 -0
  253. package/src/local-dev/process-group.js +29 -0
  254. package/src/local-dev/process-identity.d.ts +8 -0
  255. package/src/local-dev/process-identity.js +31 -1
  256. package/src/local-dev/proxy.js +11 -12
  257. package/src/local-dev/runtime-paths.js +1 -1
  258. package/src/local-dev/slice-claim.js +1 -1
  259. package/src/local-dev/slice-runner.d.ts +15 -6
  260. package/src/local-dev/slice-runner.js +189 -54
  261. package/src/local-dev/task-attachment.d.ts +17 -0
  262. package/src/local-dev/task-attachment.js +73 -0
  263. package/src/local-dev/task-authority.d.ts +10 -0
  264. package/src/local-dev/task-authority.js +27 -0
  265. package/src/local-dev/task-identity.d.ts +33 -0
  266. package/src/local-dev/task-identity.js +418 -0
  267. package/src/local-dev/task-native-writer.d.ts +18 -0
  268. package/src/local-dev/task-native-writer.js +329 -0
  269. package/src/local-dev/tls.js +3 -1
  270. package/src/local-dev/web-launch.d.ts +9 -0
  271. package/src/local-dev/web-launch.js +130 -0
  272. package/src/ownership/composition.d.ts +2 -1
  273. package/src/ownership/composition.js +1 -0
  274. package/src/performance/scenario.d.ts +22 -0
  275. package/src/performance/scenario.js +100 -92
  276. package/src/repository-policy/deployment-plan.d.ts +2 -2
  277. package/src/repository-policy/deployment-plan.js +2 -1
  278. package/src/repository-policy/policy.js +38 -3
  279. package/src/schemas/blueprint-v1.json +5 -4
  280. package/src/schemas/foundation-requirement-v1.json +5 -4
  281. package/src/schemas/testing-evidence-result-v1.json +1 -1
  282. package/src/secrets/operator.d.ts +3 -1
  283. package/src/secrets/operator.js +22 -3
  284. package/src/sst-environment-source-format.d.ts +3 -0
  285. package/src/sst-environment-source-format.js +20 -0
  286. package/src/supply-chain/blueprint-trust-git.js +13 -3
  287. package/src/supply-chain/build-output.js +15 -0
  288. package/src/supply-chain/generated-blueprint-trust-command.js +18 -1
  289. package/src/testing-evidence/fixture-scope.d.ts +2 -1
  290. package/src/testing-evidence/fixture-scope.js +4 -2
  291. package/src/testing-evidence/result.d.ts +2 -1
  292. package/src/testing-evidence/result.js +18 -4
  293. package/src/workload-roles/standard-slice.js +2 -3
  294. package/src/api-contract/baseline-update.js.map +0 -1
  295. package/src/api-contract/compatibility.js.map +0 -1
  296. package/src/api-contract/contract-graph.js.map +0 -1
  297. package/src/api-contract/evidence.js.map +0 -1
  298. package/src/api-contract/index.js.map +0 -1
  299. package/src/api-contract/model.fixtures.d.ts +0 -2
  300. package/src/api-contract/model.fixtures.js +0 -81
  301. package/src/api-contract/model.fixtures.js.map +0 -1
  302. package/src/api-contract/model.js.map +0 -1
  303. package/src/api-contract/rollout.js.map +0 -1
  304. package/src/authorization/compatibility.js.map +0 -1
  305. package/src/authorization/index.js.map +0 -1
  306. package/src/aws/child-environment.js.map +0 -1
  307. package/src/aws/identity.js.map +0 -1
  308. package/src/aws-authority/index.js.map +0 -1
  309. package/src/aws-authority/stage-authority.js.map +0 -1
  310. package/src/blueprints/execution.js.map +0 -1
  311. package/src/blueprints/external-sandbox.js.map +0 -1
  312. package/src/blueprints/index.js.map +0 -1
  313. package/src/blueprints/inputs.js.map +0 -1
  314. package/src/blueprints/manifest.js.map +0 -1
  315. package/src/blueprints/resolver.js.map +0 -1
  316. package/src/blueprints/transitions.js.map +0 -1
  317. package/src/cli/agent-command.js.map +0 -1
  318. package/src/cli/agent-runtime.js.map +0 -1
  319. package/src/cli/blueprint-authority.js.map +0 -1
  320. package/src/cli/blueprint-command.js.map +0 -1
  321. package/src/cli/bootstrap.js.map +0 -1
  322. package/src/cli/dev-command.js.map +0 -1
  323. package/src/cli/main.js.map +0 -1
  324. package/src/cli/output.js.map +0 -1
  325. package/src/cli/personal-secret-runtime.js.map +0 -1
  326. package/src/cli/secret-terminal.js.map +0 -1
  327. package/src/container-images.js.map +0 -1
  328. package/src/data-lifecycle/index.js.map +0 -1
  329. package/src/data-lifecycle/model.fixtures.d.ts +0 -2
  330. package/src/data-lifecycle/model.fixtures.js +0 -244
  331. package/src/data-lifecycle/model.fixtures.js.map +0 -1
  332. package/src/data-lifecycle/model.js.map +0 -1
  333. package/src/data-lifecycle/sensitive-artifacts.js.map +0 -1
  334. package/src/data-lifecycle/validation.js.map +0 -1
  335. package/src/database-retirement/contract.js.map +0 -1
  336. package/src/database-retirement/index.js.map +0 -1
  337. package/src/deterministic-order.js.map +0 -1
  338. package/src/developer-agent/context.js.map +0 -1
  339. package/src/developer-agent/generator-planning.js.map +0 -1
  340. package/src/developer-agent/generator-preview.js.map +0 -1
  341. package/src/developer-agent/git-inspection.js.map +0 -1
  342. package/src/developer-agent/handoff.js.map +0 -1
  343. package/src/developer-agent/index.js.map +0 -1
  344. package/src/developer-agent/model.js.map +0 -1
  345. package/src/developer-agent/operation-registry.js.map +0 -1
  346. package/src/developer-agent/ordering.js.map +0 -1
  347. package/src/developer-agent/planning.js.map +0 -1
  348. package/src/developer-agent/preview-changes.js.map +0 -1
  349. package/src/developer-agent/preview-source.js.map +0 -1
  350. package/src/developer-agent/validation.js.map +0 -1
  351. package/src/developer-agent/workspace-inspection.js.map +0 -1
  352. package/src/developer-agent/workspace-path.js.map +0 -1
  353. package/src/executors/blueprint-trust/blueprint-trust.js.map +0 -1
  354. package/src/executors/blueprint-verification/blueprint-verification.js.map +0 -1
  355. package/src/executors/deploy/deploy.js.map +0 -1
  356. package/src/executors/deployment-plan/deployment-plan.js.map +0 -1
  357. package/src/executors/dev/dev.js.map +0 -1
  358. package/src/executors/dev-doctor/dev-doctor.js.map +0 -1
  359. package/src/executors/dev-setup/dev-setup.js.map +0 -1
  360. package/src/executors/developer-context/developer-context.js.map +0 -1
  361. package/src/executors/fleet/fleet.js.map +0 -1
  362. package/src/executors/foundation-preflight/foundation-preflight.js.map +0 -1
  363. package/src/executors/foundation-profile-preflight/foundation-profile-preflight.js.map +0 -1
  364. package/src/executors/foundation-profile-preflight/production-database-safeguard.js.map +0 -1
  365. package/src/executors/foundation-remove-preflight/foundation-remove-preflight.js.map +0 -1
  366. package/src/executors/github-bootstrap/github-bootstrap.js.map +0 -1
  367. package/src/executors/infrastructure-plan/infrastructure-plan.js.map +0 -1
  368. package/src/executors/local-deploy/federated-credential-transport.js.map +0 -1
  369. package/src/executors/local-deploy/fixtures/local-deploy-state-machine.mjs +0 -53
  370. package/src/executors/local-deploy/local-approval.js.map +0 -1
  371. package/src/executors/local-deploy/local-deploy.js.map +0 -1
  372. package/src/executors/refresh/refresh.js.map +0 -1
  373. package/src/executors/remove/remove.js.map +0 -1
  374. package/src/executors/router-waf-rehearsal/router-waf-rehearsal.js.map +0 -1
  375. package/src/executors/secret-guardrails/secret-guardrails.js.map +0 -1
  376. package/src/executors/secret-initialize/secret-initialize.js.map +0 -1
  377. package/src/executors/secret-metadata/secret-metadata.js.map +0 -1
  378. package/src/executors/sst-lifecycle/generated-secret-retirement.js.map +0 -1
  379. package/src/executors/sst-lifecycle/governed-native-operation.js.map +0 -1
  380. package/src/executors/sst-lifecycle/logging-preflight.js.map +0 -1
  381. package/src/executors/sst-lifecycle/run-sst-command.js.map +0 -1
  382. package/src/executors/sst-lifecycle/secret-preflight.js.map +0 -1
  383. package/src/executors/sst-lifecycle/sst-environment-source.js.map +0 -1
  384. package/src/executors/unlock/unlock.js.map +0 -1
  385. package/src/executors/work-markers/work-markers.js.map +0 -1
  386. package/src/foundation/discovery.js.map +0 -1
  387. package/src/foundation/index.js.map +0 -1
  388. package/src/foundation/local-database-contract.js.map +0 -1
  389. package/src/foundation/logging-preflight.js.map +0 -1
  390. package/src/foundation/logging.js.map +0 -1
  391. package/src/foundation/partial-state.js.map +0 -1
  392. package/src/foundation/preflight.js.map +0 -1
  393. package/src/foundation/private-smoke-access.js.map +0 -1
  394. package/src/foundation/private-smoke-admission.js.map +0 -1
  395. package/src/foundation/private-smoke-control-plane.js.map +0 -1
  396. package/src/foundation/provision-database-bindings.js.map +0 -1
  397. package/src/foundation/provision-logical-database.js.map +0 -1
  398. package/src/foundation/requirements.js.map +0 -1
  399. package/src/foundation/router-origin-proof.js.map +0 -1
  400. package/src/foundation/router-waf-rate-rehearsal.js.map +0 -1
  401. package/src/foundation/router-waf.js.map +0 -1
  402. package/src/foundation/stages.js.map +0 -1
  403. package/src/frontend-security/index.js.map +0 -1
  404. package/src/frontend-security/security-headers.js.map +0 -1
  405. package/src/generators/feature-registry.js.map +0 -1
  406. package/src/generators/formatting.js.map +0 -1
  407. package/src/generators/function/function.js.map +0 -1
  408. package/src/generators/job/job.js.map +0 -1
  409. package/src/generators/logging-registry.js.map +0 -1
  410. package/src/generators/post-generation-install.js.map +0 -1
  411. package/src/generators/preset/dependency-overrides.js.map +0 -1
  412. package/src/generators/preset/generator.js.map +0 -1
  413. package/src/generators/preset/tool-versions.js.map +0 -1
  414. package/src/generators/preset/workspace-files-ci-acceptance.js.map +0 -1
  415. package/src/generators/preset/workspace-files-developer-agent.js.map +0 -1
  416. package/src/generators/preset/workspace-files-ecr-inspector.js.map +0 -1
  417. package/src/generators/preset/workspace-files-foundation-workload-roles.js.map +0 -1
  418. package/src/generators/preset/workspace-files-performance-cost.js.map +0 -1
  419. package/src/generators/preset/workspace-files-performance-load.js.map +0 -1
  420. package/src/generators/preset/workspace-files-stage-authority.js.map +0 -1
  421. package/src/generators/preset/workspace-files-thin-deploy.js.map +0 -1
  422. package/src/generators/preset/workspace-files-thin-docs.js.map +0 -1
  423. package/src/generators/preset/workspace-files-thin-release.js.map +0 -1
  424. package/src/generators/preset/workspace-files-workload-role-baseline.js.map +0 -1
  425. package/src/generators/preset/workspace-files.js.map +0 -1
  426. package/src/generators/repository-policy/repository-policy.js.map +0 -1
  427. package/src/generators/repository-policy/tree-policy.js.map +0 -1
  428. package/src/generators/service/service.js.map +0 -1
  429. package/src/generators/slice/built-in-plan-api-contract-files.js.map +0 -1
  430. package/src/generators/slice/built-in-plan-api-files.js.map +0 -1
  431. package/src/generators/slice/built-in-plan-async-work-files.js.map +0 -1
  432. package/src/generators/slice/built-in-plan-authorization-files.js.map +0 -1
  433. package/src/generators/slice/built-in-plan-authorization-infrastructure-files.js.map +0 -1
  434. package/src/generators/slice/built-in-plan-background-work-files.js.map +0 -1
  435. package/src/generators/slice/built-in-plan-data-deletion-files.js.map +0 -1
  436. package/src/generators/slice/built-in-plan-data-export-infrastructure-files.js.map +0 -1
  437. package/src/generators/slice/built-in-plan-data-files.js.map +0 -1
  438. package/src/generators/slice/built-in-plan-data-lifecycle-files.js.map +0 -1
  439. package/src/generators/slice/built-in-plan-data-lifecycle-runtime-files.js.map +0 -1
  440. package/src/generators/slice/built-in-plan-data-retention-job-files.js.map +0 -1
  441. package/src/generators/slice/built-in-plan-data-retention-launcher-files.js.map +0 -1
  442. package/src/generators/slice/built-in-plan-data-rights-files.js.map +0 -1
  443. package/src/generators/slice/built-in-plan-database-lifecycle-files.js.map +0 -1
  444. package/src/generators/slice/built-in-plan-database-retirement-rehearsal-files.js.map +0 -1
  445. package/src/generators/slice/built-in-plan-foundation-files.js.map +0 -1
  446. package/src/generators/slice/built-in-plan-frontend-files.js.map +0 -1
  447. package/src/generators/slice/built-in-plan-infrastructure-files.js.map +0 -1
  448. package/src/generators/slice/built-in-plan-infrastructure-safety-files.js.map +0 -1
  449. package/src/generators/slice/built-in-plan-metadata-files.js.map +0 -1
  450. package/src/generators/slice/built-in-plan-native-runtime-authority-files.js.map +0 -1
  451. package/src/generators/slice/built-in-plan-operations-files.js.map +0 -1
  452. package/src/generators/slice/built-in-plan-performance-files.js.map +0 -1
  453. package/src/generators/slice/built-in-plan-project-files.js.map +0 -1
  454. package/src/generators/slice/built-in-plan-release-files.js.map +0 -1
  455. package/src/generators/slice/built-in-plan-reliability-files.js.map +0 -1
  456. package/src/generators/slice/built-in-plan-secret-runtime-files.js.map +0 -1
  457. package/src/generators/slice/built-in-plan-shared.js.map +0 -1
  458. package/src/generators/slice/built-in-plan-testing-files.js.map +0 -1
  459. package/src/generators/slice/built-in-plan-thin-release-files.js.map +0 -1
  460. package/src/generators/slice/built-in-plan-verification-files.js.map +0 -1
  461. package/src/generators/slice/built-in-plan-web-files.js.map +0 -1
  462. package/src/generators/slice/built-in-plan-workload-role-files.js.map +0 -1
  463. package/src/generators/slice/built-in-plan.js.map +0 -1
  464. package/src/generators/slice/slice.js.map +0 -1
  465. package/src/generators/upgrade/upgrade.js.map +0 -1
  466. package/src/generators/workload/frozen-container.js.map +0 -1
  467. package/src/generators/workload/performance-registration.js.map +0 -1
  468. package/src/generators/workload/reliability-registration.js.map +0 -1
  469. package/src/generators/workload/service-performance-files.js.map +0 -1
  470. package/src/generators/workload/workload.js.map +0 -1
  471. package/src/git-policy/action-pins.js.map +0 -1
  472. package/src/git-policy/github-bootstrap.js.map +0 -1
  473. package/src/git-policy/index.js.map +0 -1
  474. package/src/git-policy/routing.js.map +0 -1
  475. package/src/index.js.map +0 -1
  476. package/src/infrastructure-change/convergence.js.map +0 -1
  477. package/src/infrastructure-change/drift.js.map +0 -1
  478. package/src/infrastructure-change/index.js.map +0 -1
  479. package/src/infrastructure-change/local-capability.js.map +0 -1
  480. package/src/infrastructure-change/model.js.map +0 -1
  481. package/src/infrastructure-change/normalize.js.map +0 -1
  482. package/src/infrastructure-change/plan.js.map +0 -1
  483. package/src/infrastructure-change/risk.js.map +0 -1
  484. package/src/infrastructure-change/summary.js.map +0 -1
  485. package/src/local-dev/context-discovery.js.map +0 -1
  486. package/src/local-dev/contract-validation.js.map +0 -1
  487. package/src/local-dev/contracts.js.map +0 -1
  488. package/src/local-dev/control-contract.js.map +0 -1
  489. package/src/local-dev/dev-command-core.js.map +0 -1
  490. package/src/local-dev/effects.js.map +0 -1
  491. package/src/local-dev/environment-inspector.js.map +0 -1
  492. package/src/local-dev/environment-state.js.map +0 -1
  493. package/src/local-dev/errors.js.map +0 -1
  494. package/src/local-dev/fleet-client.js.map +0 -1
  495. package/src/local-dev/fleet-configuration.js.map +0 -1
  496. package/src/local-dev/fleet-inventory.js.map +0 -1
  497. package/src/local-dev/fleet-ipc.js.map +0 -1
  498. package/src/local-dev/fleet-launcher.js.map +0 -1
  499. package/src/local-dev/fleet-lock.js.map +0 -1
  500. package/src/local-dev/fleet-logs.js.map +0 -1
  501. package/src/local-dev/fleet-process.js.map +0 -1
  502. package/src/local-dev/fleet-runtime.js.map +0 -1
  503. package/src/local-dev/fleet-session.js.map +0 -1
  504. package/src/local-dev/fleet-slice-runner-daemon.js.map +0 -1
  505. package/src/local-dev/fleet-startup.js.map +0 -1
  506. package/src/local-dev/fleet-state.js.map +0 -1
  507. package/src/local-dev/fleet-supervisor-daemon.js.map +0 -1
  508. package/src/local-dev/fleet-supervisor.js.map +0 -1
  509. package/src/local-dev/gateway-daemon.js.map +0 -1
  510. package/src/local-dev/gateway.js.map +0 -1
  511. package/src/local-dev/identity.js.map +0 -1
  512. package/src/local-dev/index.js.map +0 -1
  513. package/src/local-dev/local-context.js.map +0 -1
  514. package/src/local-dev/nx-workspace.js.map +0 -1
  515. package/src/local-dev/personal-secret-ledger.js.map +0 -1
  516. package/src/local-dev/personal-stage.js.map +0 -1
  517. package/src/local-dev/portless.js.map +0 -1
  518. package/src/local-dev/ports.js.map +0 -1
  519. package/src/local-dev/private-state.js.map +0 -1
  520. package/src/local-dev/process-identity.js.map +0 -1
  521. package/src/local-dev/proxy.js.map +0 -1
  522. package/src/local-dev/runtime-paths.js.map +0 -1
  523. package/src/local-dev/secret-slice-claim.js.map +0 -1
  524. package/src/local-dev/slice-claim.js.map +0 -1
  525. package/src/local-dev/slice-runner.js.map +0 -1
  526. package/src/local-dev/tls.js.map +0 -1
  527. package/src/ownership/composition.js.map +0 -1
  528. package/src/ownership/foundation-record.js.map +0 -1
  529. package/src/ownership/hash.js.map +0 -1
  530. package/src/ownership/index.js.map +0 -1
  531. package/src/ownership/json-ownership.js.map +0 -1
  532. package/src/ownership/record.js.map +0 -1
  533. package/src/ownership/workspace-record.js.map +0 -1
  534. package/src/performance/cost-collection.js.map +0 -1
  535. package/src/performance/cost-controls.js.map +0 -1
  536. package/src/performance/evidence.js.map +0 -1
  537. package/src/performance/index.js.map +0 -1
  538. package/src/performance/load-safety.js.map +0 -1
  539. package/src/performance/model.js.map +0 -1
  540. package/src/performance/pr-artifact-budget.js.map +0 -1
  541. package/src/performance/runner.js.map +0 -1
  542. package/src/performance/scenario-endpoint.js.map +0 -1
  543. package/src/performance/scenario.js.map +0 -1
  544. package/src/performance/test-fixtures.d.ts +0 -7
  545. package/src/performance/test-fixtures.js +0 -167
  546. package/src/performance/test-fixtures.js.map +0 -1
  547. package/src/performance/unit-cost.js.map +0 -1
  548. package/src/release/index.js.map +0 -1
  549. package/src/release/lifecycle.js.map +0 -1
  550. package/src/release/manifest.js.map +0 -1
  551. package/src/release/rollout.js.map +0 -1
  552. package/src/release/source-authority.js.map +0 -1
  553. package/src/repository-policy/aurora-preflight.js.map +0 -1
  554. package/src/repository-policy/capacity-migration.js.map +0 -1
  555. package/src/repository-policy/deployment-plan.js.map +0 -1
  556. package/src/repository-policy/foundation-profile.js.map +0 -1
  557. package/src/repository-policy/index.js.map +0 -1
  558. package/src/repository-policy/policy.js.map +0 -1
  559. package/src/secrets/adapters.js.map +0 -1
  560. package/src/secrets/aws-control-plane.js.map +0 -1
  561. package/src/secrets/declaration-verification.js.map +0 -1
  562. package/src/secrets/generated-aws-control-plane.js.map +0 -1
  563. package/src/secrets/guardrails.js.map +0 -1
  564. package/src/secrets/index.js.map +0 -1
  565. package/src/secrets/metadata.js.map +0 -1
  566. package/src/secrets/model.js.map +0 -1
  567. package/src/secrets/operator.js.map +0 -1
  568. package/src/secrets/permissions.js.map +0 -1
  569. package/src/secrets/personal-command.js.map +0 -1
  570. package/src/secrets/personal-ledger.js.map +0 -1
  571. package/src/secrets/registry.js.map +0 -1
  572. package/src/secrets/verification.js.map +0 -1
  573. package/src/secrets/workload-access.js.map +0 -1
  574. package/src/sst-environment-source-format.js.map +0 -1
  575. package/src/supply-chain/action-pins.js.map +0 -1
  576. package/src/supply-chain/blueprint-trust-git.js.map +0 -1
  577. package/src/supply-chain/blueprint-trust-process.js.map +0 -1
  578. package/src/supply-chain/blueprint-trust.js.map +0 -1
  579. package/src/supply-chain/blueprint-verification-authority.js.map +0 -1
  580. package/src/supply-chain/blueprint-verification-execution.js.map +0 -1
  581. package/src/supply-chain/build-output-bounds.js.map +0 -1
  582. package/src/supply-chain/build-output.js.map +0 -1
  583. package/src/supply-chain/common.js.map +0 -1
  584. package/src/supply-chain/container-artifact-contract.js.map +0 -1
  585. package/src/supply-chain/container-release.js.map +0 -1
  586. package/src/supply-chain/ecr-applicability.js.map +0 -1
  587. package/src/supply-chain/ecr-scanning.js.map +0 -1
  588. package/src/supply-chain/ecs-deployed-image.js.map +0 -1
  589. package/src/supply-chain/errors.js.map +0 -1
  590. package/src/supply-chain/generated-blueprint-trust-command.js.map +0 -1
  591. package/src/supply-chain/generated-command.js.map +0 -1
  592. package/src/supply-chain/generated-container-release-command.js.map +0 -1
  593. package/src/supply-chain/generated-ecr-collector-command.js.map +0 -1
  594. package/src/supply-chain/generated-files.js.map +0 -1
  595. package/src/supply-chain/generated-scanner-command.js.map +0 -1
  596. package/src/supply-chain/index.js.map +0 -1
  597. package/src/supply-chain/inventory.js.map +0 -1
  598. package/src/supply-chain/license-expression.js.map +0 -1
  599. package/src/supply-chain/pnpm-toolchain-authority.js.map +0 -1
  600. package/src/supply-chain/policy.js.map +0 -1
  601. package/src/supply-chain/publication.js.map +0 -1
  602. package/src/supply-chain/sbom.js.map +0 -1
  603. package/src/supply-chain/scanner.js.map +0 -1
  604. package/src/supply-chain/vendored-source.js.map +0 -1
  605. package/src/testing-evidence/fixture-scope.js.map +0 -1
  606. package/src/testing-evidence/index.js.map +0 -1
  607. package/src/testing-evidence/quarantine.js.map +0 -1
  608. package/src/testing-evidence/result.js.map +0 -1
  609. package/src/testing-evidence/runner-adapter.js.map +0 -1
  610. package/src/testing-evidence/sensitive-artifacts.js.map +0 -1
  611. package/src/validation.js.map +0 -1
  612. package/src/work-markers/index.js.map +0 -1
  613. package/src/work-markers/work-markers.js.map +0 -1
  614. package/src/workload-roles/account-baseline.js.map +0 -1
  615. package/src/workload-roles/authority.js.map +0 -1
  616. package/src/workload-roles/aws-adapter.js.map +0 -1
  617. package/src/workload-roles/aws-internal-handler.js.map +0 -1
  618. package/src/workload-roles/aws-s3-state.js.map +0 -1
  619. package/src/workload-roles/aws-sdk-control-plane.js.map +0 -1
  620. package/src/workload-roles/boundary.js.map +0 -1
  621. package/src/workload-roles/convergence.js.map +0 -1
  622. package/src/workload-roles/effective-policy.js.map +0 -1
  623. package/src/workload-roles/handler.js.map +0 -1
  624. package/src/workload-roles/history.js.map +0 -1
  625. package/src/workload-roles/index.js.map +0 -1
  626. package/src/workload-roles/injection.js.map +0 -1
  627. package/src/workload-roles/manifest.js.map +0 -1
  628. package/src/workload-roles/provisioner.js.map +0 -1
  629. package/src/workload-roles/registration.js.map +0 -1
  630. package/src/workload-roles/stage-boundary.js.map +0 -1
  631. package/src/workload-roles/standard-slice.js.map +0 -1
  632. package/src/workspace-deployment/affected-lifecycle.js.map +0 -1
  633. package/src/workspace-deployment/identity.js.map +0 -1
  634. package/src/workspace-deployment/index.js.map +0 -1
  635. package/src/workspace-deployment/migration-evidence.js.map +0 -1
  636. package/src/workspace-deployment/migration.js.map +0 -1
  637. package/src/workspace-deployment/ownership.js.map +0 -1
@@ -0,0 +1,595 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.renderKeyValueExportFiles = renderKeyValueExportFiles;
4
+ const built_in_plan_shared_js_1 = require("./built-in-plan-shared.js");
5
+ /** Native export authority, publication and cleanup; no SQL compatibility adapter. */
6
+ function renderKeyValueExportFiles(name, pascalName) {
7
+ const prefix = (0, built_in_plan_shared_js_1.lowerCamelIdentifier)(pascalName);
8
+ return {
9
+ 'data/record-export.ts': `import {
10
+ assertAuthorizationAllowed, beginApprovalExecution, completeApprovalExecution,
11
+ createApprovalRequest, decideApprovalRequest, digestApprovalRequest, expireApprovalRequest,
12
+ type ApprovalRequest, type AuthorizationPrincipal,
13
+ } from '@empire-builder-kit/runtime/authorization';
14
+ import { createDataLifecycleExportRequest, transitionDataLifecycleExport,
15
+ type DataLifecycleExportRequestV1 } from '@empire-builder-kit/runtime/data-lifecycle';
16
+ import type { KeyValueChange } from '@empire-builder-kit/runtime/key-value';
17
+ import { compareUtf16 } from '@empire-builder-kit/runtime/deterministic-order';
18
+ import { ${prefix}AuthorizationPolicy } from '../authorization/policy.js';
19
+ import { approvalReference, productRecordReference } from './pseudonymous-reference.js';
20
+ import { canonicalDataRightsNow, DATA_RIGHTS_POLICY_VERSION, dataRightsArtifactReference,
21
+ dataRightsAuditChange, dataRightsSubjectReference, plusDataRightsHours,
22
+ requireDirectAdmin, requireDirectHuman, requireExportCleanupAuthority } from './data-rights-shared.js';
23
+ import { loadActiveRecordHolds } from './record-holds.js';
24
+ import { readProductRecord } from './records.js';
25
+ import { dataStore } from './key-value.js';
26
+ import { readExportObject, exportPayloadDigest, putEncryptedExport,
27
+ runExportObjectCleanupAttempt, type ExportObjectVersion } from './record-export-objects.js';
28
+ export { putEncryptedExport, runExportObjectCleanupAttempt, type ExportObjectCleanupResult,
29
+ type ExportObjectVersion, type RecordExportObjectStore } from './record-export-objects.js';
30
+
31
+ const ACTION = '${name}:record-export';
32
+ const COPY = 'primary-database'; // Logical policy location; its physical store is DynamoDB.
33
+ const POLICY = ${prefix}AuthorizationPolicy.version;
34
+ const MAXIMUM_OUTSTANDING = 20;
35
+ const MAXIMUM_REQUESTS_PER_DAY = 5;
36
+ const MAXIMUM_PENDING_REPORTS = 1_000;
37
+ const TENANT = 'application';
38
+ const COLLECTION = 'record-exports';
39
+ interface Command { correlationId: string; now?: string; principal: AuthorizationPrincipal; recordId: string }
40
+ interface Execution extends Command { approvalRequestId: string }
41
+ interface Workflow {
42
+ kind: 'record-export'; schemaVersion: 1;
43
+ approval: ApprovalRequest<typeof ACTION>; lifecycle: DataLifecycleExportRequestV1;
44
+ recordRef: string; subjectRef: string; objectKey: string;
45
+ cleanupState: 'requested' | 'gathering' | 'ready' | 'deletion-in-progress' | 'failed' | 'completed';
46
+ uploadStartedAt: string | null; expiresAt: string | null; cleanupDeadlineAt: string | null;
47
+ recordVersion: number | null; payloadDigest: string | null;
48
+ artifactRef: string | null; currentVersionId: string | null;
49
+ versions: ExportObjectVersion[];
50
+ }
51
+ type Loaded = { workflow: Workflow; version: number };
52
+ const exportCommand = (recordId: string) => ({ format: 'application/json', recordRef: productRecordReference(recordId) });
53
+ export function recordExportObjectKey(id: string): string {
54
+ if (!/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/i.test(id))
55
+ throw new Error('Export object key requires an approval UUID.');
56
+ return 'confidential-exports/' + id + '/record.json';
57
+ }
58
+ export const recordExportExpiresAt = (now: string) => plusDataRightsHours(canonicalDataRightsNow(now), 21);
59
+ export const recordExportCleanupDeadlineAt = (now: string) => plusDataRightsHours(canonicalDataRightsNow(now), 24);
60
+ export function recordExportSchedule(now: string, persisted: {
61
+ uploadStartedAt?: string | null; expiresAt?: string | null; cleanupDeadlineAt?: string | null;
62
+ } = {}) {
63
+ const supplied = [persisted.uploadStartedAt, persisted.expiresAt, persisted.cleanupDeadlineAt].some(value => value != null);
64
+ if (supplied && [persisted.uploadStartedAt, persisted.expiresAt, persisted.cleanupDeadlineAt].some(value => typeof value !== 'string'))
65
+ throw new Error('Persisted confidential-export cleanup schedule is incomplete.');
66
+ const uploadStartedAt = canonicalDataRightsNow(persisted.uploadStartedAt ?? now);
67
+ const expiresAt = recordExportExpiresAt(uploadStartedAt);
68
+ const cleanupDeadlineAt = recordExportCleanupDeadlineAt(uploadStartedAt);
69
+ if (supplied && (persisted.expiresAt !== expiresAt || persisted.cleanupDeadlineAt !== cleanupDeadlineAt))
70
+ throw new Error('Persisted confidential-export cleanup schedule is inconsistent.');
71
+ return { uploadStartedAt, expiresAt, cleanupDeadlineAt };
72
+ }
73
+ function workflowChange(workflow: Workflow, version: number): KeyValueChange {
74
+ // Runtime retry explicitly clears these optional fields with undefined. Project only
75
+ // those documented omissions; all other non-JSON values still fail native validation.
76
+ const lifecycle = { ...workflow.lifecycle };
77
+ if (lifecycle.failurePhase === undefined) delete lifecycle.failurePhase;
78
+ if (lifecycle.outcomeCode === undefined) delete lifecycle.outcomeCode;
79
+ return { action: 'put', collection: COLLECTION, id: workflow.approval.id, expectedVersion: version, value: { ...workflow, lifecycle } };
80
+ }
81
+ function audit(input: Omit<Execution, 'recordId'> & { recordId?: string; recordReference?: string }, now: string,
82
+ purposeCode: string, outcome: 'succeeded' | 'held' | 'rejected' | 'retry-required' = 'succeeded') {
83
+ return dataRightsAuditChange({ action: 'export', approvalRequestId: input.approvalRequestId,
84
+ correlationId: input.correlationId, now, outcome, principal: input.principal, purposeCode,
85
+ ...(input.recordId ? { recordId: input.recordId } : { resourceReference: input.recordReference }),
86
+ summary: 'A bounded confidential-export workflow transition was committed.' });
87
+ }
88
+ async function commit(changes: KeyValueChange[]) { await dataStore().commit({ tenantId: TENANT, changes }); }
89
+ async function capacity() {
90
+ const row = await dataStore().get(TENANT, 'export-capacity', 'outstanding');
91
+ const ids = row ? (row.value as { ids?: unknown } | null)?.ids : [];
92
+ if (!Array.isArray(ids) || ids.length > MAXIMUM_OUTSTANDING || new Set(ids).size !== ids.length)
93
+ throw new Error('The bounded confidential-export inventory is invalid.');
94
+ for (const id of ids) recordExportObjectKey(id);
95
+ return { ids: ids as string[], version: row?.version ?? 0 };
96
+ }
97
+ function capacityChange(value: Awaited<ReturnType<typeof capacity>>, ids: string[]): KeyValueChange {
98
+ return { action: 'put', collection: 'export-capacity', id: 'outstanding', expectedVersion: value.version, value: { ids: [...ids].sort() } };
99
+ }
100
+ async function load(id: string): Promise<Loaded> {
101
+ const objectKey = recordExportObjectKey(id);
102
+ const row = await dataStore().get(TENANT, COLLECTION, id);
103
+ const workflow = row?.value as Workflow | undefined;
104
+ if (!row || !workflow || workflow.kind !== 'record-export' || workflow.schemaVersion !== 1 ||
105
+ workflow.approval?.id !== id || workflow.approval.action !== ACTION || workflow.approval.slice !== '${name}' ||
106
+ workflow.approval.schemaVersion !== 1 || workflow.approval.policyVersion !== POLICY ||
107
+ workflow.approval.resource?.type !== 'record' || workflow.approval.resource.id !== workflow.recordRef ||
108
+ workflow.objectKey !== objectKey || workflow.subjectRef !== dataRightsSubjectReference(workflow.approval.author.actorId) ||
109
+ workflow.lifecycle?.kind !== 'data-export' || workflow.lifecycle.version !== 1 ||
110
+ workflow.lifecycle.requestRef !== approvalReference(id) || workflow.lifecycle.scopeRef !== workflow.recordRef ||
111
+ workflow.lifecycle.categoryId !== 'product-record' || workflow.lifecycle.policyVersion !== DATA_RIGHTS_POLICY_VERSION ||
112
+ workflow.lifecycle.approvalRequirement !== 'required' || workflow.lifecycle.sourceCopies?.length !== 1 ||
113
+ workflow.lifecycle.sourceCopies[0]?.copyId !== COPY || !Array.isArray(workflow.versions) || workflow.versions.length > 100)
114
+ throw new Error('The exact export workflow was not found or is invalid.');
115
+ if (!['requested', 'gathering', 'ready', 'deletion-in-progress', 'failed', 'completed'].includes(workflow.cleanupState))
116
+ throw new Error('The export cleanup state is invalid.');
117
+ if (workflow.cleanupState !== 'requested' && workflow.cleanupState !== 'completed' &&
118
+ (typeof workflow.uploadStartedAt !== 'string' || typeof workflow.expiresAt !== 'string' || typeof workflow.cleanupDeadlineAt !== 'string' ||
119
+ !Number.isSafeInteger(workflow.recordVersion) || workflow.recordVersion! < 1 || !/^[a-f0-9]{64}$/.test(workflow.payloadDigest ?? '')))
120
+ throw new Error('The prepared export schedule or source binding is invalid.');
121
+ if (workflow.uploadStartedAt !== null) recordExportSchedule(workflow.uploadStartedAt, workflow);
122
+ if (workflow.versions.some(value => value.key !== objectKey || typeof value.versionId !== 'string' || !value.versionId || value.versionId.length > 1_024))
123
+ throw new Error('The export version inventory is invalid.');
124
+ return { workflow, version: row.version };
125
+ }
126
+ function assertTarget(workflow: Workflow, input: Execution, author = true) {
127
+ if (workflow.recordRef !== productRecordReference(input.recordId) ||
128
+ workflow.approval.requestDigest !== digestApprovalRequest({ action: ACTION, command: exportCommand(input.recordId),
129
+ resource: { id: workflow.recordRef, type: 'record' } }) ||
130
+ (author && workflow.approval.author.actorId !== input.principal.actor.id))
131
+ throw new Error('The export workflow was not found.');
132
+ }
133
+ async function ownedRecord(input: Command) {
134
+ const row = await dataStore().get(TENANT, 'records', input.recordId);
135
+ if (!row) throw new Error('The export target was not found.');
136
+ const record = readProductRecord(row.value, input.recordId);
137
+ if (record.ownerId !== input.principal.actor.id) throw new Error('The export target was not found.');
138
+ return { record, check: { action: 'check', collection: 'records', id: input.recordId, expectedVersion: row.version } as KeyValueChange };
139
+ }
140
+ const bodyFor = (record: ReturnType<typeof readProductRecord>) => JSON.stringify({ id: record.id, name: record.name, runScope: record.runScope });
141
+
142
+ export async function requestAuthorizedRecordExport(input: Command) {
143
+ requireDirectHuman(input.principal);
144
+ const now = canonicalDataRightsNow(input.now);
145
+ const record = await ownedRecord(input);
146
+ const inventory = await capacity();
147
+ if (inventory.ids.length >= MAXIMUM_OUTSTANDING) throw new Error('Confidential-export capacity is full; complete due cleanup before retrying.');
148
+ const subjectRef = dataRightsSubjectReference(input.principal.actor.id);
149
+ const rate = await dataStore().get(TENANT, 'export-rate', subjectRef);
150
+ const prior = rate ? (rate.value as { requestedAt?: unknown } | null)?.requestedAt : [];
151
+ if (!Array.isArray(prior) || prior.length > MAXIMUM_REQUESTS_PER_DAY) throw new Error('The export rate inventory is invalid.');
152
+ const requestedAt = prior.map(value => canonicalDataRightsNow(value)).filter(value => Date.parse(value) > Date.parse(now) - 86_400_000);
153
+ if (requestedAt.some(value => value > now) || requestedAt.length >= MAXIMUM_REQUESTS_PER_DAY)
154
+ throw new Error('The subject export request rate limit was reached.');
155
+ const recordRef = productRecordReference(input.recordId);
156
+ const approval = createApprovalRequest({ action: ACTION, author: input.principal, command: exportCommand(input.recordId),
157
+ expiresAt: plusDataRightsHours(now, 1), now, policyVersion: POLICY, resource: { id: recordRef, type: 'record' }, slice: '${name}' });
158
+ const lifecycle = createDataLifecycleExportRequest({ approvalRequirement: 'required', categoryId: 'product-record', createdAt: now,
159
+ policyVersion: DATA_RIGHTS_POLICY_VERSION, requestRef: approvalReference(approval.id), scopeRef: recordRef, sourceCopyIds: [COPY] });
160
+ const workflow: Workflow = { kind: 'record-export', schemaVersion: 1, approval, lifecycle, recordRef, subjectRef,
161
+ objectKey: recordExportObjectKey(approval.id), cleanupState: 'requested', uploadStartedAt: null, expiresAt: null,
162
+ cleanupDeadlineAt: null, recordVersion: null, payloadDigest: null, artifactRef: null, currentVersionId: null, versions: [] };
163
+ await commit([record.check, workflowChange(workflow, 0), capacityChange(inventory, [...inventory.ids, approval.id]),
164
+ { action: 'put', collection: 'export-rate', id: subjectRef, expectedVersion: rate?.version ?? 0, value: { requestedAt: [...requestedAt, now] } },
165
+ audit({ ...input, approvalRequestId: approval.id }, now, 'export-request')]);
166
+ return { approvalRequestId: approval.id, expiresAt: approval.expiresAt, requestDigest: approval.requestDigest, status: 'pending' as const };
167
+ }
168
+ export async function decideRecordExport(input: Execution & {
169
+ expectedRequestDigest: string; outcome: 'approved' | 'rejected'; reasonReference: string;
170
+ }) {
171
+ requireDirectAdmin(input.principal);
172
+ const now = canonicalDataRightsNow(input.now);
173
+ const { workflow, version } = await load(input.approvalRequestId);
174
+ assertTarget(workflow, input, false);
175
+ const result = decideApprovalRequest(workflow.approval, { approver: input.principal, expectedRequestDigest: input.expectedRequestDigest,
176
+ now, outcome: input.outcome, reasonReference: input.reasonReference, requiredPolicyVersion: POLICY });
177
+ assertAuthorizationAllowed(result.decision);
178
+ workflow.approval = result.request;
179
+ const changes: KeyValueChange[] = [];
180
+ if (input.outcome === 'rejected') {
181
+ if (workflow.cleanupState !== 'requested' || workflow.uploadStartedAt !== null) throw new Error('The requested export changed.');
182
+ workflow.lifecycle = transitionDataLifecycleExport(workflow.lifecycle, { at: now, reasonCode: 'approval-rejected', type: 'reject' });
183
+ workflow.cleanupState = 'completed';
184
+ const inventory = await capacity();
185
+ if (!inventory.ids.includes(input.approvalRequestId)) throw new Error('Export capacity binding is missing.');
186
+ changes.push(capacityChange(inventory, inventory.ids.filter(id => id !== input.approvalRequestId)));
187
+ }
188
+ await commit([...changes, workflowChange(workflow, version), audit(input, now, 'export-decision', input.outcome === 'approved' ? 'succeeded' : 'rejected')]);
189
+ return { status: result.request.status };
190
+ }
191
+
192
+ export async function executeApprovedRecordExport(input: Execution): Promise<{ status: 'held' } | { artifactRef: string; expiresAt: string; status: 'ready' }> {
193
+ requireDirectHuman(input.principal);
194
+ const now = canonicalDataRightsNow(input.now);
195
+ let { workflow, version } = await load(input.approvalRequestId);
196
+ assertTarget(workflow, input);
197
+ if (workflow.cleanupState === 'ready') {
198
+ const schedule = recordExportSchedule(now, workflow);
199
+ if (workflow.approval.status !== 'executed' || workflow.lifecycle.status !== 'ready' ||
200
+ workflow.lifecycle.artifact?.artifactRef !== workflow.artifactRef || workflow.lifecycle.artifact?.expiresAt !== schedule.expiresAt ||
201
+ !workflow.artifactRef || !workflow.currentVersionId || Date.parse(schedule.expiresAt) <= Date.parse(now))
202
+ throw new Error('The export artifact is not ready or has expired.');
203
+ return { artifactRef: workflow.artifactRef, expiresAt: schedule.expiresAt, status: 'ready' };
204
+ }
205
+ const record = await ownedRecord(input);
206
+ const holds = await loadActiveRecordHolds(input.recordId, now, 'export');
207
+ const body = bodyFor(record.record);
208
+ if (workflow.cleanupState === 'requested') {
209
+ workflow.lifecycle = transitionDataLifecycleExport(workflow.lifecycle, { approvalRef: approvalReference(input.approvalRequestId),
210
+ at: now, authorityRef: dataRightsSubjectReference(input.principal.actor.id), holds: holds.holds, type: 'verify' });
211
+ if (workflow.lifecycle.status === 'held') {
212
+ await commit([record.check, holds.check, workflowChange(workflow, version), audit(input, now, 'export-execution', 'held')]);
213
+ return { status: 'held' };
214
+ }
215
+ const begun = beginApprovalExecution(workflow.approval, { action: ACTION, command: exportCommand(input.recordId),
216
+ executionId: 'export:' + input.approvalRequestId, now, requiredPolicyVersion: POLICY,
217
+ resource: { id: workflow.recordRef, type: 'record' } });
218
+ assertAuthorizationAllowed(begun.decision);
219
+ workflow.approval = begun.request;
220
+ workflow.lifecycle = transitionDataLifecycleExport(workflow.lifecycle, { at: now, type: 'start-gathering' });
221
+ workflow.lifecycle = transitionDataLifecycleExport(workflow.lifecycle, { at: now, copyId: COPY, type: 'start-copy' });
222
+ Object.assign(workflow, recordExportSchedule(now), { cleanupState: 'gathering', recordVersion: record.check.expectedVersion, payloadDigest: exportPayloadDigest(body) });
223
+ // Durable authority and deadline precede all S3 activity. No plaintext copy is persisted here.
224
+ await commit([record.check, holds.check, workflowChange(workflow, version)]);
225
+ ({ workflow, version } = await load(input.approvalRequestId));
226
+ }
227
+ if (workflow.cleanupState !== 'gathering' || workflow.lifecycle.status !== 'gathering' || workflow.approval.status !== 'executing' ||
228
+ workflow.approval.execution?.executionId !== 'export:' + input.approvalRequestId || holds.evaluation.blocked ||
229
+ workflow.recordVersion !== record.check.expectedVersion || workflow.payloadDigest !== exportPayloadDigest(body))
230
+ throw new Error('The executing export authority, record or hold changed.');
231
+ const schedule = recordExportSchedule(now, workflow);
232
+ if (Date.parse(schedule.expiresAt) <= Date.parse(now)) throw new Error('The confidential export expired before publication.');
233
+ const versionId = await putEncryptedExport(workflow.objectKey, body);
234
+ const finishedAt = canonicalDataRightsNow(input.now);
235
+ if (Date.parse(schedule.expiresAt) <= Date.parse(finishedAt)) throw new Error('The confidential export expired before publication.');
236
+ const artifactRef = dataRightsArtifactReference(input.approvalRequestId + ':' + versionId);
237
+ workflow.lifecycle = transitionDataLifecycleExport(workflow.lifecycle, { at: finishedAt, copyId: COPY, outcomeCode: 'gathered', type: 'complete-copy' });
238
+ workflow.lifecycle = transitionDataLifecycleExport(workflow.lifecycle, { artifactRef, at: finishedAt,
239
+ encryption: 'approved-profile', expiresAt: schedule.expiresAt, type: 'publish' });
240
+ const completed = completeApprovalExecution(workflow.approval, { executionId: 'export:' + input.approvalRequestId, now: finishedAt, requiredPolicyVersion: POLICY });
241
+ assertAuthorizationAllowed(completed.decision);
242
+ Object.assign(workflow, { approval: completed.request, artifactRef, currentVersionId: versionId, cleanupState: 'ready',
243
+ versions: [{ key: workflow.objectKey, versionId, isDeleteMarker: false }] });
244
+ // A concurrent hold, owner edit, cleanup or publication wins by CAS. An unaccepted encrypted
245
+ // object remains covered by the durable gathering row and exact-key cleanup inventory.
246
+ await commit([record.check, holds.check, workflowChange(workflow, version), audit(input, finishedAt, 'export-execution')]);
247
+ return { artifactRef, expiresAt: schedule.expiresAt, status: 'ready' };
248
+ }
249
+
250
+ export async function deliverReadyRecordExport(input: Execution) {
251
+ requireDirectHuman(input.principal);
252
+ const now = canonicalDataRightsNow(input.now);
253
+ const { workflow, version } = await load(input.approvalRequestId);
254
+ assertTarget(workflow, input);
255
+ const schedule = recordExportSchedule(now, workflow);
256
+ if (workflow.cleanupState !== 'ready' || workflow.approval.status !== 'executed' || workflow.lifecycle.status !== 'ready' ||
257
+ workflow.lifecycle.artifact?.status !== 'available' || workflow.lifecycle.artifact?.artifactRef !== workflow.artifactRef ||
258
+ workflow.lifecycle.artifact.expiresAt !== schedule.expiresAt || !workflow.currentVersionId || !workflow.artifactRef || !workflow.payloadDigest ||
259
+ Date.parse(schedule.expiresAt) <= Date.parse(now)) throw new Error('The export artifact is not ready or has expired.');
260
+ const record = await ownedRecord(input);
261
+ const holds = await loadActiveRecordHolds(input.recordId, now, 'export');
262
+ if (holds.evaluation.blocked) throw new Error('An active record hold blocks export delivery.');
263
+ const delivered = await readExportObject(workflow.objectKey, workflow.currentVersionId, workflow.payloadDigest, input.recordId);
264
+ const deliveredAt = canonicalDataRightsNow(input.now);
265
+ if (Date.parse(schedule.expiresAt) <= Date.parse(deliveredAt)) throw new Error('The export artifact has expired.');
266
+ await commit([record.check, holds.check, { action: 'check', collection: COLLECTION, id: input.approvalRequestId, expectedVersion: version },
267
+ audit(input, deliveredAt, 'export-download')]);
268
+ return { artifactRef: workflow.artifactRef, deliveredAt, expiresAt: schedule.expiresAt, record: delivered };
269
+ }
270
+
271
+ interface DeadlineReport { id: string; deadlineAt: string }
272
+ async function reports() {
273
+ const row = await dataStore().get(TENANT, 'export-cleanup-reports', 'pending');
274
+ const pending = row ? (row.value as { pending?: DeadlineReport[] } | null)?.pending : [];
275
+ if (!Array.isArray(pending) || pending.length > MAXIMUM_PENDING_REPORTS || new Set(pending.map(value => value.id)).size !== pending.length)
276
+ throw new Error('The export cleanup report inventory is invalid.');
277
+ for (const report of pending) { recordExportObjectKey(report.id); canonicalDataRightsNow(report.deadlineAt); }
278
+ return { pending, version: row?.version ?? 0 };
279
+ }
280
+ function reportsChange(current: Awaited<ReturnType<typeof reports>>, pending: DeadlineReport[]): KeyValueChange {
281
+ return { action: 'put', collection: 'export-cleanup-reports', id: 'pending', expectedVersion: current.version, value: { pending } };
282
+ }
283
+ async function deadlineChange(workflow: Workflow, observedAt: string): Promise<KeyValueChange[]> {
284
+ if (workflow.uploadStartedAt === null || workflow.lifecycle.status === 'completed') return [];
285
+ const schedule = recordExportSchedule(observedAt, workflow);
286
+ if (schedule.cleanupDeadlineAt > observedAt) return [];
287
+ const current = await reports();
288
+ const prior = current.pending.find(value => value.id === workflow.approval.id);
289
+ if (prior && prior.deadlineAt !== schedule.cleanupDeadlineAt) throw new Error('The cleanup deadline report changed.');
290
+ // Saturated observability must not prevent deletion. The bounded active inventory is
291
+ // rescanned next time; cleanup itself still reports the observed deadline breach.
292
+ if (prior || current.pending.length >= MAXIMUM_PENDING_REPORTS) return [];
293
+ return [reportsChange(current, [...current.pending, { id: workflow.approval.id, deadlineAt: schedule.cleanupDeadlineAt }])];
294
+ }
295
+ export async function reportExportCleanupDeadlineBreaches(input: { correlationId: string; pageSize?: number; report(value: number): boolean }) {
296
+ const pageSize = input.pageSize ?? 100;
297
+ if (!Number.isSafeInteger(pageSize) || pageSize < 1 || pageSize > 100) throw new Error('Export cleanup report page size must be from 1 through 100.');
298
+ const current = await reports();
299
+ const selected = current.pending.slice(0, pageSize);
300
+ if (!input.report(selected.length)) throw new Error('Confidential export cleanup deadline metric delivery failed.');
301
+ // Metric failure keeps every report; transaction failure permits at-least-once reporting.
302
+ if (selected.length) await commit([reportsChange(current, current.pending.slice(selected.length))]);
303
+ return { continuationRequired: current.pending.length > pageSize, reported: selected.length };
304
+ }
305
+ type CleanupInput = Omit<Execution, 'recordId'> & { recordId?: string; recordReference?: string };
306
+ export async function cleanupExpiredRecordExport(input: CleanupInput): Promise<{ deletedVersions: number; status: 'completed' | 'retry-required' }> {
307
+ requireExportCleanupAuthority(input.principal);
308
+ if ((input.recordId === undefined) === (input.recordReference === undefined)) throw new Error('Export cleanup requires exactly one record identifier or reference.');
309
+ const expected = input.recordReference ?? productRecordReference(input.recordId!);
310
+ const now = canonicalDataRightsNow(input.now);
311
+ let { workflow, version } = await load(input.approvalRequestId);
312
+ if (workflow.recordRef !== expected) throw new Error('The export artifact was not found.');
313
+ if (workflow.cleanupState === 'completed') return { deletedVersions: 0, status: 'completed' };
314
+ if (workflow.cleanupState === 'requested') {
315
+ const expired = expireApprovalRequest(workflow.approval, now);
316
+ if (expired.status !== 'expired') throw new Error('The export request is not due for cleanup.');
317
+ workflow.approval = expired;
318
+ workflow.lifecycle = transitionDataLifecycleExport(workflow.lifecycle, { at: now, reasonCode: 'approval-expired', type: 'reject' });
319
+ workflow.cleanupState = 'completed';
320
+ const inventory = await capacity();
321
+ if (!inventory.ids.includes(input.approvalRequestId)) throw new Error('Export capacity binding is missing.');
322
+ await commit([workflowChange(workflow, version), capacityChange(inventory, inventory.ids.filter(id => id !== input.approvalRequestId)), audit(input, now, 'export-expiry')]);
323
+ return { deletedVersions: 0, status: 'completed' };
324
+ }
325
+ const schedule = recordExportSchedule(now, workflow);
326
+ if (schedule.expiresAt > now) throw new Error('The export artifact is not due for cleanup.');
327
+ const deadline = await deadlineChange(workflow, now);
328
+ if (workflow.lifecycle.status === 'ready') {
329
+ workflow.lifecycle = transitionDataLifecycleExport(workflow.lifecycle, { at: now, type: 'expire' });
330
+ workflow.lifecycle = transitionDataLifecycleExport(workflow.lifecycle, { at: now, type: 'start-artifact-deletion' });
331
+ } else if (workflow.lifecycle.status === 'gathering') {
332
+ workflow.lifecycle = transitionDataLifecycleExport(workflow.lifecycle, { at: now, type: 'start-unpublished-artifact-deletion' });
333
+ } else if (workflow.lifecycle.status === 'failed') {
334
+ workflow.lifecycle = transitionDataLifecycleExport(workflow.lifecycle, { at: now, type: 'retry' });
335
+ }
336
+ if (!['artifact-deletion-in-progress', 'unpublished-artifact-deletion-in-progress'].includes(workflow.lifecycle.status))
337
+ throw new Error('The export cleanup attempt changed.');
338
+ workflow.cleanupState = 'deletion-in-progress';
339
+ await commit([workflowChange(workflow, version), ...deadline]);
340
+ ({ workflow, version } = await load(input.approvalRequestId));
341
+ return runExportObjectCleanupAttempt({ objectKey: workflow.objectKey, trackedVersions: workflow.versions,
342
+ async recordDiscovered(discovered) {
343
+ const next = await load(input.approvalRequestId);
344
+ if (next.workflow.cleanupState !== 'deletion-in-progress') throw new Error('The export cleanup attempt changed.');
345
+ const merged = new Map([...next.workflow.versions, ...discovered].map(value => [value.versionId, value]));
346
+ if (merged.size > 100) throw new Error('The exact export version inventory exceeded its bound.');
347
+ next.workflow.versions = [...merged.values()];
348
+ await commit([workflowChange(next.workflow, next.version)]);
349
+ },
350
+ async finalize({ attemptedVersions, failedVersionIds }) {
351
+ const next = await load(input.approvalRequestId);
352
+ if (next.workflow.cleanupState === 'completed') return { deletedVersions: 0, status: 'completed' as const };
353
+ if (next.workflow.cleanupState !== 'deletion-in-progress') throw new Error('The export cleanup attempt changed.');
354
+ // The scan's input.now is a selection snapshot, not the completion clock.
355
+ const finishedAt = canonicalDataRightsNow();
356
+ const pending = await deadlineChange(next.workflow, finishedAt);
357
+ const failed = new Set(failedVersionIds);
358
+ const unpublished = next.workflow.lifecycle.artifact === undefined;
359
+ next.workflow.lifecycle = transitionDataLifecycleExport(next.workflow.lifecycle, failed.size
360
+ ? { at: finishedAt, errorCode: 'object-version-delete-failed', type: 'fail-artifact-deletion' }
361
+ : { at: finishedAt, outcomeCode: attemptedVersions.length ? 'deleted' : 'not-found', type: 'complete-artifact-deletion' });
362
+ if (!failed.size && unpublished) {
363
+ const completed = completeApprovalExecution(next.workflow.approval, { executionId: 'export:' + input.approvalRequestId, now: finishedAt, requiredPolicyVersion: POLICY });
364
+ assertAuthorizationAllowed(completed.decision); next.workflow.approval = completed.request;
365
+ }
366
+ next.workflow.cleanupState = failed.size ? 'failed' : 'completed';
367
+ next.workflow.versions = attemptedVersions.filter(value => failed.has(value.versionId));
368
+ const changes: KeyValueChange[] = [...pending];
369
+ if (!failed.size) {
370
+ const inventory = await capacity();
371
+ if (!inventory.ids.includes(input.approvalRequestId)) throw new Error('Export capacity binding is missing.');
372
+ changes.push(capacityChange(inventory, inventory.ids.filter(id => id !== input.approvalRequestId)));
373
+ }
374
+ await commit([...changes, workflowChange(next.workflow, next.version), audit(input, finishedAt, 'export-expiry', failed.size ? 'retry-required' : 'succeeded')]);
375
+ return { deletedVersions: attemptedVersions.length - failed.size, status: failed.size ? 'retry-required' as const : 'completed' as const };
376
+ },
377
+ });
378
+ }
379
+
380
+ export async function cleanupDueRecordExports(input: { correlationId: string; limit?: number; maximumBatches?: number;
381
+ now?: string; principal: AuthorizationPrincipal; shouldContinue?: () => boolean;
382
+ }, dependencies: { cleanupExpiredRecordExport?: typeof cleanupExpiredRecordExport } = {}) {
383
+ requireExportCleanupAuthority(input.principal);
384
+ const now = canonicalDataRightsNow(input.now);
385
+ const limit = input.limit ?? 25;
386
+ const maximumBatches = input.maximumBatches ?? 100;
387
+ if (!Number.isSafeInteger(limit) || limit < 1 || limit > 100 || !Number.isSafeInteger(maximumBatches) || maximumBatches < 1 || maximumBatches > 100)
388
+ throw new Error('Export cleanup batch size and count must be from 1 through 100.');
389
+ const inventory = await capacity();
390
+ const active = await Promise.all(inventory.ids.map(load));
391
+ const due = (workflow: Workflow) => workflow.cleanupState === 'requested' ? workflow.approval.expiresAt <= now : workflow.expiresAt !== null && workflow.expiresAt <= now;
392
+ let deadlineBreached = false;
393
+ for (const { workflow } of active) {
394
+ if (workflow.cleanupState === 'completed') throw new Error('Completed export remains in the active inventory.');
395
+ const changes = await deadlineChange(workflow, now);
396
+ if (changes.length) await commit(changes);
397
+ if (workflow.cleanupDeadlineAt !== null && workflow.cleanupDeadlineAt <= now) deadlineBreached = true;
398
+ }
399
+ const candidates = active.filter(({ workflow }) => due(workflow)).sort((a, b) =>
400
+ compareUtf16(a.workflow.expiresAt ?? a.workflow.approval.expiresAt, b.workflow.expiresAt ?? b.workflow.approval.expiresAt) || compareUtf16(a.workflow.approval.id, b.workflow.approval.id));
401
+ let processed = 0; let completed = 0; let retryRequired = 0; let batches = 0;
402
+ for (let offset = 0; offset < candidates.length && batches < maximumBatches && (input.shouldContinue?.() ?? true); offset += limit) {
403
+ batches += 1;
404
+ for (const { workflow } of candidates.slice(offset, offset + limit)) {
405
+ processed += 1;
406
+ try {
407
+ const result = await (dependencies.cleanupExpiredRecordExport ?? cleanupExpiredRecordExport)({
408
+ approvalRequestId: workflow.approval.id, correlationId: input.correlationId, now, principal: input.principal, recordReference: workflow.recordRef });
409
+ if (result.status === 'completed') completed += 1; else retryRequired += 1;
410
+ } catch { retryRequired += 1; }
411
+ }
412
+ }
413
+ const remaining = await Promise.all((await capacity()).ids.map(load));
414
+ const remainingDue = remaining.filter(({ workflow }) => due(workflow)).length;
415
+ const remainingDeadlineBreaches = remaining.filter(({ workflow }) => workflow.cleanupDeadlineAt !== null && workflow.cleanupDeadlineAt <= now).length;
416
+ const pendingReports = await reports();
417
+ return { batches, completed, continuationRequired: retryRequired > 0 || remainingDue > 0,
418
+ deadlineBreached: deadlineBreached || remainingDeadlineBreaches > 0 || pendingReports.pending.length > 0, processed, remainingDeadlineBreaches, remainingDue, retryRequired };
419
+ }
420
+ `,
421
+ 'data/record-export-objects.ts': renderObjects(),
422
+ 'testing/data-rights-workflows.spec.ts': `import { describe, expect, it } from 'vitest';
423
+ import { createApprovalRequest, decideApprovalRequest, type AuthorizationPrincipal } from '@empire-builder-kit/runtime/authorization';
424
+ import { recordExportSchedule, recordExportObjectKey, runExportObjectCleanupAttempt, type RecordExportObjectStore } from '../data/record-export.js';
425
+ import { createRecordHold } from '../data/record-holds.js';
426
+ const owner: AuthorizationPrincipal = { kind: 'customer', actor: { type: 'user', id: 'owner-one' },
427
+ subject: { type: 'user', id: 'owner-one' }, authority: { mode: 'direct' }, roles: [], scopes: [] };
428
+ const now = '2026-09-12T12:00:00.000Z';
429
+ describe('native data rights', () => {
430
+ it('retains an exact upload-relative expiry and deadline on retry', () => {
431
+ const first = recordExportSchedule(now);
432
+ expect(first).toEqual({ uploadStartedAt: now, expiresAt: '2026-09-13T09:00:00.000Z', cleanupDeadlineAt: '2026-09-13T12:00:00.000Z' });
433
+ expect(recordExportSchedule('2026-09-12T13:00:00.000Z', first)).toEqual(first);
434
+ expect(() => recordExportSchedule(now, { uploadStartedAt: now })).toThrow('incomplete');
435
+ expect(() => recordExportSchedule(now, { ...first, expiresAt: now })).toThrow('inconsistent');
436
+ });
437
+ it('requires independent direct-human review', () => {
438
+ const request = createApprovalRequest({ action: '${name}:record-export', author: owner, command: { recordRef: 'record-ref' },
439
+ resource: { id: 'record-ref', type: 'record' }, policyVersion: '1.0.0', slice: '${name}', now, expiresAt: '2026-09-12T13:00:00.000Z' });
440
+ expect(decideApprovalRequest(request, { approver: { ...owner, kind: 'admin' }, expectedRequestDigest: request.requestDigest,
441
+ now, outcome: 'approved', reasonReference: 'review-1', requiredPolicyVersion: '1.0.0' }).decision.decision).toBe('deny');
442
+ expect(() => createRecordHold({ effects: ['block-export'], expiresAt: '2026-09-14T12:00:00.000Z', principal: owner,
443
+ purpose: 'legal', recordId: 'record-1', reviewAt: '2026-09-13T12:00:00.000Z' }, now)).toThrow('direct admin');
444
+ });
445
+ it('rejects review under a newer policy before granting export authority', () => {
446
+ const request = createApprovalRequest({ action: '${name}:record-export', author: owner, command: { recordRef: 'record-ref' },
447
+ resource: { id: 'record-ref', type: 'record' }, policyVersion: '1.0.0', slice: '${name}', now, expiresAt: '2026-09-12T13:00:00.000Z' });
448
+ const approver: AuthorizationPrincipal = { ...owner, kind: 'admin',
449
+ actor: { type: 'user', id: 'reviewer-two' }, subject: { type: 'user', id: 'reviewer-two' } };
450
+ expect(decideApprovalRequest(request, { approver, expectedRequestDigest: request.requestDigest,
451
+ now, outcome: 'approved', reasonReference: 'review-2', requiredPolicyVersion: '2.0.0' }).decision)
452
+ .toMatchObject({ decision: 'deny', category: 'policy-stale' });
453
+ });
454
+ it('persists exact version inventory before deletion and refuses to erase ambiguous errors', async () => {
455
+ const objectKey = recordExportObjectKey('00000000-0000-4000-8000-000000000001');
456
+ const seen: string[] = [];
457
+ let listing = 0;
458
+ const objectStore: RecordExportObjectStore = { async send(command) {
459
+ const value = command as { constructor: { name: string }; input: { Delete?: { Objects: unknown[] } } };
460
+ seen.push(value.constructor.name);
461
+ if (value.constructor.name === 'ListObjectVersionsCommand') return ++listing === 1
462
+ ? { Versions: [{ Key: objectKey, VersionId: 'version-1' }] } : {};
463
+ expect(value.constructor.name).toBe('DeleteObjectsCommand');
464
+ expect(seen).toContain('inventory-persisted');
465
+ expect(value.input.Delete?.Objects).toEqual([{ Key: objectKey, VersionId: 'version-1' }]);
466
+ return { Errors: [{ Key: objectKey }] };
467
+ } };
468
+ const priorBucket = process.env.DATA_EXPORT_BUCKET_NAME;
469
+ const priorKey = process.env.DATA_EXPORT_KMS_KEY_ARN;
470
+ process.env.DATA_EXPORT_BUCKET_NAME = 'test-exports';
471
+ process.env.DATA_EXPORT_KMS_KEY_ARN = 'arn:aws:kms:us-east-1:111111111111:key/test';
472
+ try {
473
+ const result = await runExportObjectCleanupAttempt({ objectKey, objectStore, trackedVersions: [],
474
+ recordDiscovered: async () => { seen.push('inventory-persisted'); }, finalize: async value => value });
475
+ expect(result.failedVersionIds).toEqual(['version-1']);
476
+ expect(result.remainingVersions).toEqual([]);
477
+ } finally {
478
+ if (priorBucket === undefined) delete process.env.DATA_EXPORT_BUCKET_NAME; else process.env.DATA_EXPORT_BUCKET_NAME = priorBucket;
479
+ if (priorKey === undefined) delete process.env.DATA_EXPORT_KMS_KEY_ARN; else process.env.DATA_EXPORT_KMS_KEY_ARN = priorKey;
480
+ }
481
+ });
482
+ });
483
+ `,
484
+ };
485
+ }
486
+ function renderObjects() {
487
+ return `import { createHash } from 'node:crypto';
488
+ import { S3Client, PutObjectCommand, HeadObjectCommand, GetObjectCommand, ListObjectVersionsCommand, DeleteObjectsCommand } from '@aws-sdk/client-s3';
489
+ const s3 = new S3Client({ maxAttempts: 3, requestHandler: { connectionTimeout: 5_000, requestTimeout: 30_000 } });
490
+ export interface RecordExportObjectStore { send(command: unknown): Promise<unknown> }
491
+ const defaultStore: RecordExportObjectStore = { send: command => s3.send(command as never) };
492
+ export const exportPayloadDigest = (body: string) => createHash('sha256').update(body).digest('hex');
493
+ function resources() {
494
+ const bucketName = process.env.DATA_EXPORT_BUCKET_NAME;
495
+ const kmsKeyArn = process.env.DATA_EXPORT_KMS_KEY_ARN;
496
+ if (!bucketName || !kmsKeyArn?.startsWith('arn:aws:kms:')) throw new Error('Confidential-export encryption resources are unavailable.');
497
+ return { bucketName, kmsKeyArn };
498
+ }
499
+ function exactKey(key: string) {
500
+ if (!/^confidential-exports[/][a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}[/]record[.]json$/i.test(key))
501
+ throw new Error('An exact confidential-export object key is required.');
502
+ }
503
+ export async function putEncryptedExport(objectKey: string, body: string, objectStore: RecordExportObjectStore = defaultStore): Promise<string> {
504
+ exactKey(objectKey);
505
+ if (Buffer.byteLength(body) > 64 * 1_024) throw new Error('The confidential export exceeds its size bound.');
506
+ const { bucketName, kmsKeyArn } = resources();
507
+ const digest = exportPayloadDigest(body);
508
+ try {
509
+ const result = await objectStore.send(new PutObjectCommand({ Bucket: bucketName, Key: objectKey, Body: body,
510
+ BucketKeyEnabled: true, ContentType: 'application/json', IfNoneMatch: '*', ServerSideEncryption: 'aws:kms',
511
+ SSEKMSKeyId: kmsKeyArn, Metadata: { 'ebk-content-sha256': digest } })) as { VersionId?: string };
512
+ if (!result.VersionId) throw new Error('Versioned export put returned no version identifier.');
513
+ return result.VersionId;
514
+ } catch (error) {
515
+ if ((error as { $metadata?: { httpStatusCode?: number } }).$metadata?.httpStatusCode !== 412) throw error;
516
+ const existing = await objectStore.send(new HeadObjectCommand({ Bucket: bucketName, Key: objectKey })) as {
517
+ VersionId?: string; ServerSideEncryption?: string; SSEKMSKeyId?: string; Metadata?: Record<string, string> };
518
+ if (!existing.VersionId || existing.ServerSideEncryption !== 'aws:kms' || existing.SSEKMSKeyId !== kmsKeyArn || existing.Metadata?.['ebk-content-sha256'] !== digest)
519
+ throw new Error('Existing export object failed encryption or content validation.');
520
+ return existing.VersionId;
521
+ }
522
+ }
523
+ export async function readExportObject(objectKey: string, versionId: string, expectedDigest: string, recordId: string) {
524
+ exactKey(objectKey);
525
+ const { bucketName, kmsKeyArn } = resources();
526
+ const object = await s3.send(new GetObjectCommand({ Bucket: bucketName, Key: objectKey, VersionId: versionId }));
527
+ if (object.ContentLength === undefined || object.ContentLength > 64 * 1_024 || object.ContentType !== 'application/json' ||
528
+ !object.Body || object.VersionId !== versionId || object.ServerSideEncryption !== 'aws:kms' || object.SSEKMSKeyId !== kmsKeyArn)
529
+ throw new Error('The confidential export artifact is invalid.');
530
+ const body = await object.Body.transformToString();
531
+ if (Buffer.byteLength(body) > 64 * 1_024 || exportPayloadDigest(body) !== expectedDigest) throw new Error('The confidential export content changed.');
532
+ const value = JSON.parse(body) as { id?: unknown; name?: unknown; runScope?: unknown };
533
+ if (value.id !== recordId || typeof value.name !== 'string' || value.name.length < 1 || value.name.length > 256 ||
534
+ typeof value.runScope !== 'string' || value.runScope.length < 1 || value.runScope.length > 128)
535
+ throw new Error('The confidential export artifact is invalid.');
536
+ return { id: recordId, name: value.name, runScope: value.runScope };
537
+ }
538
+ export interface ExportObjectVersion { isDeleteMarker: boolean; key: string; versionId: string }
539
+ async function list(key: string, store: RecordExportObjectStore) {
540
+ exactKey(key);
541
+ const versions = new Map<string, ExportObjectVersion>();
542
+ const seen = new Set<string>();
543
+ let keyMarker: string | undefined; let versionMarker: string | undefined;
544
+ for (let pageNumber = 0; pageNumber < 100; pageNumber += 1) {
545
+ const page = await store.send(new ListObjectVersionsCommand({ Bucket: resources().bucketName, Prefix: key,
546
+ KeyMarker: keyMarker, VersionIdMarker: versionMarker, MaxKeys: 100 })) as {
547
+ Versions?: Array<{ Key?: string; VersionId?: string }>; DeleteMarkers?: Array<{ Key?: string; VersionId?: string }>;
548
+ IsTruncated?: boolean; NextKeyMarker?: string; NextVersionIdMarker?: string };
549
+ for (const [isDeleteMarker, values] of [[false, page.Versions ?? []], [true, page.DeleteMarkers ?? []]] as const) {
550
+ for (const value of values) {
551
+ if (value.Key !== key) continue;
552
+ if (!value.VersionId || value.VersionId.length > 1_024) throw new Error('The exact export version is invalid.');
553
+ versions.set(value.VersionId, { key, versionId: value.VersionId, isDeleteMarker });
554
+ }
555
+ }
556
+ if (versions.size > 100) throw new Error('The exact export version inventory exceeded its bound.');
557
+ if (!page.IsTruncated) return [...versions.values()];
558
+ keyMarker = page.NextKeyMarker; versionMarker = page.NextVersionIdMarker;
559
+ const cursor = JSON.stringify([keyMarker, versionMarker]);
560
+ if (!keyMarker || !versionMarker || seen.has(cursor)) throw new Error('The exact export version listing did not advance.');
561
+ seen.add(cursor);
562
+ }
563
+ throw new Error('The exact export version listing exceeded its page bound.');
564
+ }
565
+ export interface ExportObjectCleanupResult { attemptedVersions: ExportObjectVersion[]; failedVersionIds: string[]; remainingVersions: ExportObjectVersion[] }
566
+ export async function runExportObjectCleanupAttempt<Result>(input: {
567
+ objectKey: string; trackedVersions: readonly ExportObjectVersion[]; objectStore?: RecordExportObjectStore;
568
+ recordDiscovered(versions: readonly ExportObjectVersion[]): Promise<void>; finalize(result: ExportObjectCleanupResult): Promise<Result>;
569
+ }): Promise<Result> {
570
+ exactKey(input.objectKey);
571
+ if (input.trackedVersions.length > 100 || input.trackedVersions.some(value => value.key !== input.objectKey || !value.versionId || value.versionId.length > 1_024))
572
+ throw new Error('The tracked export version inventory is invalid.');
573
+ const store = input.objectStore ?? defaultStore;
574
+ const discovered = await list(input.objectKey, store);
575
+ await input.recordDiscovered(discovered);
576
+ const attempted = new Map([...input.trackedVersions, ...discovered].map(value => [value.versionId, value]));
577
+ if (attempted.size > 100) throw new Error('The exact export version inventory exceeded its bound.');
578
+ const failed = new Set<string>();
579
+ if (attempted.size) {
580
+ const result = await store.send(new DeleteObjectsCommand({ Bucket: resources().bucketName,
581
+ Delete: { Objects: [...attempted.values()].map(value => ({ Key: value.key, VersionId: value.versionId })), Quiet: true } })) as {
582
+ Errors?: Array<{ Key?: string; VersionId?: string }> };
583
+ for (const error of result.Errors ?? []) {
584
+ if (error.VersionId && attempted.has(error.VersionId) && (error.Key === undefined || error.Key === input.objectKey)) failed.add(error.VersionId);
585
+ else for (const id of attempted.keys()) failed.add(id);
586
+ }
587
+ }
588
+ const remaining = await list(input.objectKey, store);
589
+ await input.recordDiscovered(remaining);
590
+ for (const value of remaining) { failed.add(value.versionId); attempted.set(value.versionId, value); }
591
+ return input.finalize({ attemptedVersions: [...attempted.values()], failedVersionIds: [...failed].sort(), remainingVersions: remaining });
592
+ }
593
+ `;
594
+ }
595
+ //# sourceMappingURL=built-in-plan-key-value-export.js.map
@@ -0,0 +1,2 @@
1
+ /** Native DynamoDB integration; this is not a SQL compatibility adapter. */
2
+ export declare function renderKeyValueRuntimeFiles(name: string): Readonly<Record<string, string>>;
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.renderKeyValueRuntimeFiles = renderKeyValueRuntimeFiles;
4
+ const built_in_plan_key_value_delivery_js_1 = require("./built-in-plan-key-value-delivery.js");
5
+ /** Native DynamoDB integration; this is not a SQL compatibility adapter. */
6
+ function renderKeyValueRuntimeFiles(name) {
7
+ return {
8
+ 'async/key-value-delivery.ts': (0, built_in_plan_key_value_delivery_js_1.renderKeyValueDeliverySource)(name),
9
+ 'data/key-value.ts': `import { DynamoDBClient } from '@aws-sdk/client-dynamodb';
10
+ import { createDynamoPersistence } from '@empire-builder-kit/runtime/key-value';
11
+
12
+ function required(name: string): string {
13
+ const value = process.env[name]?.trim();
14
+ if (!value) throw new Error(name + ' is required for this Slice/task data store.');
15
+ return value;
16
+ }
17
+
18
+ let store: ReturnType<typeof createDynamoPersistence> | undefined;
19
+ export function dataStore() {
20
+ return store ??= createDynamoPersistence({
21
+ client: new DynamoDBClient({}),
22
+ tableName: required('EBK_KEY_VALUE_TABLE'),
23
+ stage: required('EBK_STAGE'),
24
+ slice: '${name}',
25
+ eventBusName: required('EVENT_BUS_NAME'),
26
+ });
27
+ }
28
+ `,
29
+ };
30
+ }
31
+ //# sourceMappingURL=built-in-plan-key-value-files.js.map
@@ -0,0 +1,2 @@
1
+ /** Native data-rights holds. The versioned per-record set closes absent-hold races. */
2
+ export declare function renderKeyValueHoldFiles(name: string, pascalName: string): Readonly<Record<string, string>>;