@elie-laloum/outpost 2.0.0 → 4.0.0

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 (588) hide show
  1. package/CHANGELOG.md +42 -0
  2. package/README.md +3 -1
  3. package/SECURITY.md +3 -1
  4. package/dist/adapters/agents/claude-diagnostics.d.ts +1 -0
  5. package/dist/adapters/agents/claude-diagnostics.js +7 -0
  6. package/dist/adapters/agents/claude-diagnostics.js.map +1 -0
  7. package/dist/adapters/agents/cli-diagnostics.constants.d.ts +12 -0
  8. package/dist/adapters/agents/cli-diagnostics.constants.js +24 -0
  9. package/dist/adapters/agents/cli-diagnostics.constants.js.map +1 -0
  10. package/dist/adapters/agents/cli-diagnostics.d.ts +4 -0
  11. package/dist/adapters/agents/cli-diagnostics.js +14 -0
  12. package/dist/adapters/agents/cli-diagnostics.js.map +1 -0
  13. package/dist/adapters/agents/cli-diagnostics.types.d.ts +13 -0
  14. package/dist/adapters/agents/cli-diagnostics.types.js +2 -0
  15. package/dist/adapters/agents/cli-diagnostics.types.js.map +1 -0
  16. package/dist/adapters/agents/codex-diagnostics.d.ts +1 -0
  17. package/dist/adapters/agents/codex-diagnostics.js +7 -0
  18. package/dist/adapters/agents/codex-diagnostics.js.map +1 -0
  19. package/dist/adapters/agents/gemini-adapter.d.ts +3 -0
  20. package/dist/adapters/agents/gemini-adapter.js +15 -0
  21. package/dist/adapters/agents/gemini-adapter.js.map +1 -0
  22. package/dist/adapters/agents/gemini-diagnostics.d.ts +2 -0
  23. package/dist/adapters/agents/gemini-diagnostics.js +15 -0
  24. package/dist/adapters/agents/gemini-diagnostics.js.map +1 -0
  25. package/dist/adapters/agents/gemini-events.d.ts +2 -0
  26. package/dist/adapters/agents/gemini-events.js +50 -0
  27. package/dist/adapters/agents/gemini-events.js.map +1 -0
  28. package/dist/adapters/agents/gemini-request.d.ts +4 -0
  29. package/dist/adapters/agents/gemini-request.js +21 -0
  30. package/dist/adapters/agents/gemini-request.js.map +1 -0
  31. package/dist/adapters/agents/gemini.types.d.ts +6 -0
  32. package/dist/adapters/agents/gemini.types.js +2 -0
  33. package/dist/adapters/agents/gemini.types.js.map +1 -0
  34. package/dist/adapters/agents/protocol-fixtures.constants.d.ts +2 -0
  35. package/dist/adapters/agents/protocol-fixtures.constants.js +105 -0
  36. package/dist/adapters/agents/protocol-fixtures.constants.js.map +1 -0
  37. package/dist/adapters/agents/protocol-fixtures.types.d.ts +6 -0
  38. package/dist/adapters/agents/protocol-fixtures.types.js +2 -0
  39. package/dist/adapters/agents/protocol-fixtures.types.js.map +1 -0
  40. package/dist/application/agent-bootstrap.constants.d.ts +1 -0
  41. package/dist/application/agent-bootstrap.constants.js +1 -0
  42. package/dist/application/agent-bootstrap.constants.js.map +1 -1
  43. package/dist/application/agent-bootstrap.js +6 -2
  44. package/dist/application/agent-bootstrap.js.map +1 -1
  45. package/dist/application/agent-output.js +9 -2
  46. package/dist/application/agent-output.js.map +1 -1
  47. package/dist/application/artifact-tasks.d.ts +5 -0
  48. package/dist/application/artifact-tasks.js +31 -0
  49. package/dist/application/artifact-tasks.js.map +1 -0
  50. package/dist/application/artifact-tasks.types.d.ts +8 -0
  51. package/dist/application/artifact-tasks.types.js +2 -0
  52. package/dist/application/artifact-tasks.types.js.map +1 -0
  53. package/dist/application/diagnostic-probe.d.ts +3 -0
  54. package/dist/application/diagnostic-probe.js +55 -0
  55. package/dist/application/diagnostic-probe.js.map +1 -0
  56. package/dist/application/dispatch-validation.js +2 -0
  57. package/dist/application/dispatch-validation.js.map +1 -1
  58. package/dist/application/doctor-agent.constants.d.ts +11 -0
  59. package/dist/application/doctor-agent.constants.js +10 -0
  60. package/dist/application/doctor-agent.constants.js.map +1 -0
  61. package/dist/application/doctor-agent.d.ts +3 -0
  62. package/dist/application/doctor-agent.js +53 -0
  63. package/dist/application/doctor-agent.js.map +1 -0
  64. package/dist/application/doctor-image.d.ts +3 -0
  65. package/dist/application/doctor-image.js +133 -0
  66. package/dist/application/doctor-image.js.map +1 -0
  67. package/dist/application/doctor-protocol.d.ts +3 -0
  68. package/dist/application/doctor-protocol.js +30 -0
  69. package/dist/application/doctor-protocol.js.map +1 -0
  70. package/dist/application/doctor-protocol.types.d.ts +10 -0
  71. package/dist/application/doctor-protocol.types.js +2 -0
  72. package/dist/application/doctor-protocol.types.js.map +1 -0
  73. package/dist/application/doctor-sandbox.constants.d.ts +5 -0
  74. package/dist/application/doctor-sandbox.constants.js +6 -0
  75. package/dist/application/doctor-sandbox.constants.js.map +1 -0
  76. package/dist/application/doctor-sandbox.d.ts +4 -0
  77. package/dist/application/doctor-sandbox.js +133 -0
  78. package/dist/application/doctor-sandbox.js.map +1 -0
  79. package/dist/application/doctor-sandbox.types.d.ts +23 -0
  80. package/dist/application/doctor-sandbox.types.js +2 -0
  81. package/dist/application/doctor-sandbox.types.js.map +1 -0
  82. package/dist/application/doctor-transfers.constants.d.ts +6 -0
  83. package/dist/application/doctor-transfers.constants.js +7 -0
  84. package/dist/application/doctor-transfers.constants.js.map +1 -0
  85. package/dist/application/doctor-transfers.d.ts +4 -0
  86. package/dist/application/doctor-transfers.js +88 -0
  87. package/dist/application/doctor-transfers.js.map +1 -0
  88. package/dist/application/doctor.constants.d.ts +9 -0
  89. package/dist/application/doctor.constants.js +15 -0
  90. package/dist/application/doctor.constants.js.map +1 -0
  91. package/dist/application/doctor.d.ts +3 -0
  92. package/dist/application/doctor.js +106 -0
  93. package/dist/application/doctor.js.map +1 -0
  94. package/dist/application/doctor.types.d.ts +39 -0
  95. package/dist/application/doctor.types.js +2 -0
  96. package/dist/application/doctor.types.js.map +1 -0
  97. package/dist/application/execution.js +1 -0
  98. package/dist/application/execution.js.map +1 -1
  99. package/dist/application/outpost.types.d.ts +4 -0
  100. package/dist/application/outpost.types.js.map +1 -1
  101. package/dist/application/queue-worker.d.ts +2 -0
  102. package/dist/application/queue-worker.js +75 -0
  103. package/dist/application/queue-worker.js.map +1 -0
  104. package/dist/application/queue-worker.types.d.ts +15 -0
  105. package/dist/application/queue-worker.types.js +2 -0
  106. package/dist/application/queue-worker.types.js.map +1 -0
  107. package/dist/application/queued-task.d.ts +3 -0
  108. package/dist/application/queued-task.js +56 -0
  109. package/dist/application/queued-task.js.map +1 -0
  110. package/dist/application/queued-task.types.d.ts +11 -0
  111. package/dist/application/queued-task.types.js +2 -0
  112. package/dist/application/queued-task.types.js.map +1 -0
  113. package/dist/application/recovery-checksum-capture.d.ts +2 -0
  114. package/dist/application/recovery-checksum-capture.js +32 -0
  115. package/dist/application/recovery-checksum-capture.js.map +1 -0
  116. package/dist/application/recovery-checksum-paths.d.ts +2 -0
  117. package/dist/application/recovery-checksum-paths.js +11 -0
  118. package/dist/application/recovery-checksum-paths.js.map +1 -0
  119. package/dist/application/recovery-checksums.constants.d.ts +5 -0
  120. package/dist/application/recovery-checksums.constants.js +6 -0
  121. package/dist/application/recovery-checksums.constants.js.map +1 -0
  122. package/dist/application/recovery-checksums.d.ts +3 -0
  123. package/dist/application/recovery-checksums.js +94 -0
  124. package/dist/application/recovery-checksums.js.map +1 -0
  125. package/dist/application/recovery-checksums.types.d.ts +17 -0
  126. package/dist/application/recovery-checksums.types.js +2 -0
  127. package/dist/application/recovery-checksums.types.js.map +1 -0
  128. package/dist/application/recovery-inspection.d.ts +2 -0
  129. package/dist/application/recovery-inspection.js +32 -0
  130. package/dist/application/recovery-inspection.js.map +1 -0
  131. package/dist/application/recovery-inspection.types.d.ts +18 -0
  132. package/dist/application/recovery-inspection.types.js +2 -0
  133. package/dist/application/recovery-inspection.types.js.map +1 -0
  134. package/dist/application/recovery-restorability.d.ts +2 -0
  135. package/dist/application/recovery-restorability.js +137 -0
  136. package/dist/application/recovery-restorability.js.map +1 -0
  137. package/dist/application/recovery-restore-snapshot.d.ts +2 -0
  138. package/dist/application/recovery-restore-snapshot.js +57 -0
  139. package/dist/application/recovery-restore-snapshot.js.map +1 -0
  140. package/dist/application/recovery-restore.d.ts +3 -0
  141. package/dist/application/recovery-restore.js +161 -0
  142. package/dist/application/recovery-restore.js.map +1 -0
  143. package/dist/application/recovery-restore.types.d.ts +28 -0
  144. package/dist/application/recovery-restore.types.js +2 -0
  145. package/dist/application/recovery-restore.types.js.map +1 -0
  146. package/dist/application/recovery-retention-policy.d.ts +2 -0
  147. package/dist/application/recovery-retention-policy.js +21 -0
  148. package/dist/application/recovery-retention-policy.js.map +1 -0
  149. package/dist/application/recovery-retention.constants.d.ts +3 -0
  150. package/dist/application/recovery-retention.constants.js +2 -0
  151. package/dist/application/recovery-retention.constants.js.map +1 -0
  152. package/dist/application/recovery-retention.d.ts +4 -0
  153. package/dist/application/recovery-retention.js +207 -0
  154. package/dist/application/recovery-retention.js.map +1 -0
  155. package/dist/application/recovery-retention.types.d.ts +52 -0
  156. package/dist/application/recovery-retention.types.js +2 -0
  157. package/dist/application/recovery-retention.types.js.map +1 -0
  158. package/dist/application/recovery-verification.constants.d.ts +5 -0
  159. package/dist/application/recovery-verification.constants.js +10 -0
  160. package/dist/application/recovery-verification.constants.js.map +1 -0
  161. package/dist/application/recovery-verification.d.ts +3 -0
  162. package/dist/application/recovery-verification.js +107 -0
  163. package/dist/application/recovery-verification.js.map +1 -0
  164. package/dist/application/recovery-verification.types.d.ts +26 -0
  165. package/dist/application/recovery-verification.types.js +2 -0
  166. package/dist/application/recovery-verification.types.js.map +1 -0
  167. package/dist/application/remote-apply.js +30 -6
  168. package/dist/application/remote-apply.js.map +1 -1
  169. package/dist/application/remote-backup.js +6 -2
  170. package/dist/application/remote-backup.js.map +1 -1
  171. package/dist/application/remote-download.js +38 -6
  172. package/dist/application/remote-download.js.map +1 -1
  173. package/dist/application/remote-history.d.ts +6 -0
  174. package/dist/application/remote-history.js +114 -0
  175. package/dist/application/remote-history.js.map +1 -0
  176. package/dist/application/remote-upload.d.ts +2 -0
  177. package/dist/application/remote-upload.js +17 -0
  178. package/dist/application/remote-upload.js.map +1 -0
  179. package/dist/application/remote-validation.js +39 -28
  180. package/dist/application/remote-validation.js.map +1 -1
  181. package/dist/application/remote-workspace.constants.d.ts +3 -0
  182. package/dist/application/remote-workspace.constants.js +2 -0
  183. package/dist/application/remote-workspace.constants.js.map +1 -0
  184. package/dist/application/remote-workspace.js +10 -10
  185. package/dist/application/remote-workspace.js.map +1 -1
  186. package/dist/application/remote-workspace.types.d.ts +3 -1
  187. package/dist/application/remote-workspace.types.js.map +1 -1
  188. package/dist/application/sandbox-activity.d.ts +3 -0
  189. package/dist/application/sandbox-activity.js +25 -0
  190. package/dist/application/sandbox-activity.js.map +1 -0
  191. package/dist/application/sandbox-provision.js +55 -10
  192. package/dist/application/sandbox-provision.js.map +1 -1
  193. package/dist/application/sandbox-session.types.d.ts +2 -0
  194. package/dist/application/sandbox-session.types.js.map +1 -1
  195. package/dist/application/sandbox.js +33 -10
  196. package/dist/application/sandbox.js.map +1 -1
  197. package/dist/application/speculation-host.d.ts +2 -0
  198. package/dist/application/speculation-host.js +30 -0
  199. package/dist/application/speculation-host.js.map +1 -0
  200. package/dist/application/speculation.constants.d.ts +4 -0
  201. package/dist/application/speculation.constants.js +2 -0
  202. package/dist/application/speculation.constants.js.map +1 -0
  203. package/dist/application/speculation.d.ts +2 -0
  204. package/dist/application/speculation.js +166 -0
  205. package/dist/application/speculation.js.map +1 -0
  206. package/dist/application/speculation.types.d.ts +56 -0
  207. package/dist/application/speculation.types.js +2 -0
  208. package/dist/application/speculation.types.js.map +1 -0
  209. package/dist/application/storage-reservation.d.ts +3 -0
  210. package/dist/application/storage-reservation.js +10 -0
  211. package/dist/application/storage-reservation.js.map +1 -0
  212. package/dist/application/storage-reservation.types.d.ts +4 -0
  213. package/dist/application/storage-reservation.types.js +2 -0
  214. package/dist/application/storage-reservation.types.js.map +1 -0
  215. package/dist/application/task-usage.d.ts +4 -0
  216. package/dist/application/task-usage.js +41 -0
  217. package/dist/application/task-usage.js.map +1 -0
  218. package/dist/application/task-usage.types.d.ts +5 -0
  219. package/dist/application/task-usage.types.js +2 -0
  220. package/dist/application/task-usage.types.js.map +1 -0
  221. package/dist/application/tasks.js +23 -2
  222. package/dist/application/tasks.js.map +1 -1
  223. package/dist/application/tasks.types.d.ts +4 -3
  224. package/dist/application/tasks.types.js.map +1 -1
  225. package/dist/application/workspace-allocation.d.ts +3 -0
  226. package/dist/application/workspace-allocation.js +34 -0
  227. package/dist/application/workspace-allocation.js.map +1 -0
  228. package/dist/application/workspace.js +2 -2
  229. package/dist/application/workspace.js.map +1 -1
  230. package/dist/cli/commands.js +4 -0
  231. package/dist/cli/commands.js.map +1 -1
  232. package/dist/cli/doctor-command.d.ts +3 -0
  233. package/dist/cli/doctor-command.js +38 -0
  234. package/dist/cli/doctor-command.js.map +1 -0
  235. package/dist/cli/main.constants.d.ts +38 -2
  236. package/dist/cli/main.constants.js +21 -2
  237. package/dist/cli/main.constants.js.map +1 -1
  238. package/dist/cli/recovery-command.d.ts +2 -0
  239. package/dist/cli/recovery-command.js +93 -0
  240. package/dist/cli/recovery-command.js.map +1 -0
  241. package/dist/cli/recovery-prune-command.d.ts +2 -0
  242. package/dist/cli/recovery-prune-command.js +34 -0
  243. package/dist/cli/recovery-prune-command.js.map +1 -0
  244. package/dist/cli/recovery-restore-command.d.ts +2 -0
  245. package/dist/cli/recovery-restore-command.js +34 -0
  246. package/dist/cli/recovery-restore-command.js.map +1 -0
  247. package/dist/cli/recovery-verify-command.d.ts +2 -0
  248. package/dist/cli/recovery-verify-command.js +43 -0
  249. package/dist/cli/recovery-verify-command.js.map +1 -0
  250. package/dist/cli/scaffold-files.js +2 -2
  251. package/dist/cli/scaffold-files.js.map +1 -1
  252. package/dist/cli/scaffold-validation.js +1 -1
  253. package/dist/cli/scaffold-validation.js.map +1 -1
  254. package/dist/cli/scaffold.constants.d.ts +5 -0
  255. package/dist/cli/scaffold.constants.js +7 -2
  256. package/dist/cli/scaffold.constants.js.map +1 -1
  257. package/dist/cli/scaffold.types.d.ts +1 -1
  258. package/dist/cli/scaffold.types.js.map +1 -1
  259. package/dist/domain/agent.types.d.ts +2 -0
  260. package/dist/domain/agent.types.js.map +1 -1
  261. package/dist/domain/artifact-reference.d.ts +4 -0
  262. package/dist/domain/artifact-reference.js +90 -0
  263. package/dist/domain/artifact-reference.js.map +1 -0
  264. package/dist/domain/artifact.constants.d.ts +2 -0
  265. package/dist/domain/artifact.constants.js +3 -0
  266. package/dist/domain/artifact.constants.js.map +1 -0
  267. package/dist/domain/artifact.d.ts +7 -0
  268. package/dist/domain/artifact.js +104 -0
  269. package/dist/domain/artifact.js.map +1 -0
  270. package/dist/domain/artifact.types.d.ts +44 -0
  271. package/dist/domain/artifact.types.js +2 -0
  272. package/dist/domain/artifact.types.js.map +1 -0
  273. package/dist/domain/egress.constants.d.ts +1 -0
  274. package/dist/domain/egress.constants.js +7 -0
  275. package/dist/domain/egress.constants.js.map +1 -0
  276. package/dist/domain/egress.d.ts +2 -0
  277. package/dist/domain/egress.js +48 -0
  278. package/dist/domain/egress.js.map +1 -0
  279. package/dist/domain/egress.types.d.ts +8 -0
  280. package/dist/domain/egress.types.js +2 -0
  281. package/dist/domain/egress.types.js.map +1 -0
  282. package/dist/domain/ports.d.ts +1 -1
  283. package/dist/domain/ports.js.map +1 -1
  284. package/dist/domain/sandbox.types.d.ts +13 -0
  285. package/dist/domain/sandbox.types.js.map +1 -1
  286. package/dist/domain/task-queue.constants.d.ts +8 -0
  287. package/dist/domain/task-queue.constants.js +9 -0
  288. package/dist/domain/task-queue.constants.js.map +1 -0
  289. package/dist/domain/task-queue.d.ts +11 -0
  290. package/dist/domain/task-queue.js +105 -0
  291. package/dist/domain/task-queue.js.map +1 -0
  292. package/dist/domain/task-queue.types.d.ts +41 -0
  293. package/dist/domain/task-queue.types.js +2 -0
  294. package/dist/domain/task-queue.types.js.map +1 -0
  295. package/dist/domain/workflow/budget.constants.d.ts +1 -0
  296. package/dist/domain/workflow/budget.constants.js +7 -0
  297. package/dist/domain/workflow/budget.constants.js.map +1 -0
  298. package/dist/domain/workflow/budget.d.ts +9 -0
  299. package/dist/domain/workflow/budget.js +69 -0
  300. package/dist/domain/workflow/budget.js.map +1 -0
  301. package/dist/domain/workflow/budget.types.d.ts +15 -0
  302. package/dist/domain/workflow/budget.types.js +2 -0
  303. package/dist/domain/workflow/budget.types.js.map +1 -0
  304. package/dist/domain/workflow/checkpoint-validation.d.ts +3 -0
  305. package/dist/domain/workflow/checkpoint-validation.js +81 -0
  306. package/dist/domain/workflow/checkpoint-validation.js.map +1 -0
  307. package/dist/domain/workflow/checkpoint-value.d.ts +2 -0
  308. package/dist/domain/workflow/checkpoint-value.js +49 -0
  309. package/dist/domain/workflow/checkpoint-value.js.map +1 -0
  310. package/dist/domain/workflow/checkpoint.d.ts +3 -0
  311. package/dist/domain/workflow/checkpoint.js +70 -0
  312. package/dist/domain/workflow/checkpoint.js.map +1 -0
  313. package/dist/domain/workflow/checkpoint.types.d.ts +40 -0
  314. package/dist/domain/workflow/checkpoint.types.js +2 -0
  315. package/dist/domain/workflow/checkpoint.types.js.map +1 -0
  316. package/dist/domain/workflow/gate-validation.d.ts +4 -0
  317. package/dist/domain/workflow/gate-validation.js +71 -0
  318. package/dist/domain/workflow/gate-validation.js.map +1 -0
  319. package/dist/domain/workflow/gates.constants.d.ts +4 -0
  320. package/dist/domain/workflow/gates.constants.js +5 -0
  321. package/dist/domain/workflow/gates.constants.js.map +1 -0
  322. package/dist/domain/workflow/gates.d.ts +7 -0
  323. package/dist/domain/workflow/gates.js +85 -0
  324. package/dist/domain/workflow/gates.js.map +1 -0
  325. package/dist/domain/workflow/gates.types.d.ts +27 -0
  326. package/dist/domain/workflow/gates.types.js +2 -0
  327. package/dist/domain/workflow/gates.types.js.map +1 -0
  328. package/dist/domain/workflow/task-runner.js +22 -3
  329. package/dist/domain/workflow/task-runner.js.map +1 -1
  330. package/dist/domain/workflow/usage-receipt.constants.d.ts +2 -0
  331. package/dist/domain/workflow/usage-receipt.constants.js +3 -0
  332. package/dist/domain/workflow/usage-receipt.constants.js.map +1 -0
  333. package/dist/domain/workflow/usage-receipt.d.ts +2 -0
  334. package/dist/domain/workflow/usage-receipt.js +18 -0
  335. package/dist/domain/workflow/usage-receipt.js.map +1 -0
  336. package/dist/domain/workflow/validation.js +6 -0
  337. package/dist/domain/workflow/validation.js.map +1 -1
  338. package/dist/domain/workflow/workflow-scheduler.js +68 -33
  339. package/dist/domain/workflow/workflow-scheduler.js.map +1 -1
  340. package/dist/domain/workflow/workflow-state.d.ts +2 -1
  341. package/dist/domain/workflow/workflow-state.js +107 -3
  342. package/dist/domain/workflow/workflow-state.js.map +1 -1
  343. package/dist/domain/workflow.d.ts +2 -0
  344. package/dist/domain/workflow.js +1 -0
  345. package/dist/domain/workflow.js.map +1 -1
  346. package/dist/domain/workflow.types.d.ts +23 -3
  347. package/dist/domain/workflow.types.js.map +1 -1
  348. package/dist/index.d.ts +44 -5
  349. package/dist/index.js +19 -2
  350. package/dist/index.js.map +1 -1
  351. package/dist/infrastructure/artifact-store.constants.d.ts +1 -0
  352. package/dist/infrastructure/artifact-store.constants.js +2 -0
  353. package/dist/infrastructure/artifact-store.constants.js.map +1 -0
  354. package/dist/infrastructure/artifact-store.d.ts +3 -0
  355. package/dist/infrastructure/artifact-store.js +100 -0
  356. package/dist/infrastructure/artifact-store.js.map +1 -0
  357. package/dist/infrastructure/artifact-store.types.d.ts +4 -0
  358. package/dist/infrastructure/artifact-store.types.js +2 -0
  359. package/dist/infrastructure/artifact-store.types.js.map +1 -0
  360. package/dist/infrastructure/file-manifest.d.ts +6 -0
  361. package/dist/infrastructure/file-manifest.js +92 -0
  362. package/dist/infrastructure/file-manifest.js.map +1 -0
  363. package/dist/infrastructure/git/lock-inspection.constants.d.ts +4 -0
  364. package/dist/infrastructure/git/lock-inspection.constants.js +5 -0
  365. package/dist/infrastructure/git/lock-inspection.constants.js.map +1 -0
  366. package/dist/infrastructure/git/lock-inspection.d.ts +3 -0
  367. package/dist/infrastructure/git/lock-inspection.js +64 -0
  368. package/dist/infrastructure/git/lock-inspection.js.map +1 -0
  369. package/dist/infrastructure/git/lock-inspection.types.d.ts +27 -0
  370. package/dist/infrastructure/git/lock-inspection.types.js +2 -0
  371. package/dist/infrastructure/git/lock-inspection.types.js.map +1 -0
  372. package/dist/infrastructure/git/lock.d.ts +1 -0
  373. package/dist/infrastructure/git/lock.js +70 -29
  374. package/dist/infrastructure/git/lock.js.map +1 -1
  375. package/dist/infrastructure/git/process-identity.d.ts +3 -0
  376. package/dist/infrastructure/git/process-identity.js +73 -0
  377. package/dist/infrastructure/git/process-identity.js.map +1 -0
  378. package/dist/infrastructure/git/process-identity.types.d.ts +10 -0
  379. package/dist/infrastructure/git/process-identity.types.js +2 -0
  380. package/dist/infrastructure/git/process-identity.types.js.map +1 -0
  381. package/dist/infrastructure/git/verification-command.d.ts +1 -0
  382. package/dist/infrastructure/git/verification-command.js +37 -0
  383. package/dist/infrastructure/git/verification-command.js.map +1 -0
  384. package/dist/infrastructure/git/workspace-lease.js +1 -0
  385. package/dist/infrastructure/git/workspace-lease.js.map +1 -1
  386. package/dist/infrastructure/git/workspace.js +5 -1
  387. package/dist/infrastructure/git/workspace.js.map +1 -1
  388. package/dist/infrastructure/git/worktree-inspection.constants.d.ts +5 -0
  389. package/dist/infrastructure/git/worktree-inspection.constants.js +16 -0
  390. package/dist/infrastructure/git/worktree-inspection.constants.js.map +1 -0
  391. package/dist/infrastructure/git/worktree-inspection.d.ts +3 -0
  392. package/dist/infrastructure/git/worktree-inspection.js +120 -0
  393. package/dist/infrastructure/git/worktree-inspection.js.map +1 -0
  394. package/dist/infrastructure/git/worktree-inspection.types.d.ts +19 -0
  395. package/dist/infrastructure/git/worktree-inspection.types.js +2 -0
  396. package/dist/infrastructure/git/worktree-inspection.types.js.map +1 -0
  397. package/dist/infrastructure/inspection-file.constants.d.ts +1 -0
  398. package/dist/infrastructure/inspection-file.constants.js +5 -0
  399. package/dist/infrastructure/inspection-file.constants.js.map +1 -0
  400. package/dist/infrastructure/inspection-file.d.ts +1 -0
  401. package/dist/infrastructure/inspection-file.js +43 -0
  402. package/dist/infrastructure/inspection-file.js.map +1 -0
  403. package/dist/infrastructure/inspection-hash.constants.d.ts +1 -0
  404. package/dist/infrastructure/inspection-hash.constants.js +2 -0
  405. package/dist/infrastructure/inspection-hash.constants.js.map +1 -0
  406. package/dist/infrastructure/inspection-hash.d.ts +2 -0
  407. package/dist/infrastructure/inspection-hash.js +62 -0
  408. package/dist/infrastructure/inspection-hash.js.map +1 -0
  409. package/dist/infrastructure/inspection-hash.types.d.ts +5 -0
  410. package/dist/infrastructure/inspection-hash.types.js +2 -0
  411. package/dist/infrastructure/inspection-hash.types.js.map +1 -0
  412. package/dist/infrastructure/journal-retention.constants.d.ts +4 -0
  413. package/dist/infrastructure/journal-retention.constants.js +5 -0
  414. package/dist/infrastructure/journal-retention.constants.js.map +1 -0
  415. package/dist/infrastructure/journal-retention.d.ts +2 -0
  416. package/dist/infrastructure/journal-retention.js +51 -0
  417. package/dist/infrastructure/journal-retention.js.map +1 -0
  418. package/dist/infrastructure/journal.js +37 -13
  419. package/dist/infrastructure/journal.js.map +1 -1
  420. package/dist/infrastructure/opentelemetry.constants.d.ts +10 -0
  421. package/dist/infrastructure/opentelemetry.constants.js +11 -0
  422. package/dist/infrastructure/opentelemetry.constants.js.map +1 -0
  423. package/dist/infrastructure/opentelemetry.d.ts +3 -0
  424. package/dist/infrastructure/opentelemetry.js +131 -0
  425. package/dist/infrastructure/opentelemetry.js.map +1 -0
  426. package/dist/infrastructure/opentelemetry.types.d.ts +21 -0
  427. package/dist/infrastructure/opentelemetry.types.js +2 -0
  428. package/dist/infrastructure/opentelemetry.types.js.map +1 -0
  429. package/dist/infrastructure/resource-activity-inspection.d.ts +2 -0
  430. package/dist/infrastructure/resource-activity-inspection.js +152 -0
  431. package/dist/infrastructure/resource-activity-inspection.js.map +1 -0
  432. package/dist/infrastructure/resource-activity.constants.d.ts +8 -0
  433. package/dist/infrastructure/resource-activity.constants.js +26 -0
  434. package/dist/infrastructure/resource-activity.constants.js.map +1 -0
  435. package/dist/infrastructure/resource-activity.d.ts +2 -0
  436. package/dist/infrastructure/resource-activity.js +166 -0
  437. package/dist/infrastructure/resource-activity.js.map +1 -0
  438. package/dist/infrastructure/resource-activity.types.d.ts +53 -0
  439. package/dist/infrastructure/resource-activity.types.js +2 -0
  440. package/dist/infrastructure/resource-activity.types.js.map +1 -0
  441. package/dist/infrastructure/storage-inventory.constants.d.ts +6 -0
  442. package/dist/infrastructure/storage-inventory.constants.js +11 -0
  443. package/dist/infrastructure/storage-inventory.constants.js.map +1 -0
  444. package/dist/infrastructure/storage-inventory.d.ts +2 -0
  445. package/dist/infrastructure/storage-inventory.js +123 -0
  446. package/dist/infrastructure/storage-inventory.js.map +1 -0
  447. package/dist/infrastructure/storage-inventory.types.d.ts +38 -0
  448. package/dist/infrastructure/storage-inventory.types.js +2 -0
  449. package/dist/infrastructure/storage-inventory.types.js.map +1 -0
  450. package/dist/infrastructure/storage-mutation-lock.constants.d.ts +5 -0
  451. package/dist/infrastructure/storage-mutation-lock.constants.js +6 -0
  452. package/dist/infrastructure/storage-mutation-lock.constants.js.map +1 -0
  453. package/dist/infrastructure/storage-mutation-lock.d.ts +1 -0
  454. package/dist/infrastructure/storage-mutation-lock.js +21 -0
  455. package/dist/infrastructure/storage-mutation-lock.js.map +1 -0
  456. package/dist/infrastructure/storage-reservations.constants.d.ts +4 -0
  457. package/dist/infrastructure/storage-reservations.constants.js +5 -0
  458. package/dist/infrastructure/storage-reservations.constants.js.map +1 -0
  459. package/dist/infrastructure/storage-reservations.d.ts +2 -0
  460. package/dist/infrastructure/storage-reservations.js +150 -0
  461. package/dist/infrastructure/storage-reservations.js.map +1 -0
  462. package/dist/infrastructure/storage-reservations.types.d.ts +21 -0
  463. package/dist/infrastructure/storage-reservations.types.js +2 -0
  464. package/dist/infrastructure/storage-reservations.types.js.map +1 -0
  465. package/dist/infrastructure/task-queue-http.constants.d.ts +2 -0
  466. package/dist/infrastructure/task-queue-http.constants.js +3 -0
  467. package/dist/infrastructure/task-queue-http.constants.js.map +1 -0
  468. package/dist/infrastructure/task-queue-http.d.ts +4 -0
  469. package/dist/infrastructure/task-queue-http.js +158 -0
  470. package/dist/infrastructure/task-queue-http.js.map +1 -0
  471. package/dist/infrastructure/task-queue-http.types.d.ts +16 -0
  472. package/dist/infrastructure/task-queue-http.types.js +2 -0
  473. package/dist/infrastructure/task-queue-http.types.js.map +1 -0
  474. package/dist/infrastructure/task-queue.d.ts +2 -0
  475. package/dist/infrastructure/task-queue.js +134 -0
  476. package/dist/infrastructure/task-queue.js.map +1 -0
  477. package/dist/infrastructure/transfer.js +17 -0
  478. package/dist/infrastructure/transfer.js.map +1 -1
  479. package/dist/infrastructure/workflow-checkpoint.constants.d.ts +1 -0
  480. package/dist/infrastructure/workflow-checkpoint.constants.js +2 -0
  481. package/dist/infrastructure/workflow-checkpoint.constants.js.map +1 -0
  482. package/dist/infrastructure/workflow-checkpoint.d.ts +3 -0
  483. package/dist/infrastructure/workflow-checkpoint.js +77 -0
  484. package/dist/infrastructure/workflow-checkpoint.js.map +1 -0
  485. package/dist/infrastructure/workflow-checkpoint.types.d.ts +4 -0
  486. package/dist/infrastructure/workflow-checkpoint.types.js +2 -0
  487. package/dist/infrastructure/workflow-checkpoint.types.js.map +1 -0
  488. package/dist/providers/agents.d.ts +2 -0
  489. package/dist/providers/agents.js +1 -0
  490. package/dist/providers/agents.js.map +1 -1
  491. package/dist/providers/cloud.constants.d.ts +1 -0
  492. package/dist/providers/cloud.constants.js +1 -0
  493. package/dist/providers/cloud.constants.js.map +1 -1
  494. package/dist/providers/container-cache.constants.d.ts +11 -0
  495. package/dist/providers/container-cache.constants.js +9 -0
  496. package/dist/providers/container-cache.constants.js.map +1 -0
  497. package/dist/providers/container-cache.d.ts +4 -0
  498. package/dist/providers/container-cache.js +48 -0
  499. package/dist/providers/container-cache.js.map +1 -0
  500. package/dist/providers/container-cache.types.d.ts +8 -0
  501. package/dist/providers/container-cache.types.js +2 -0
  502. package/dist/providers/container-cache.types.js.map +1 -0
  503. package/dist/providers/container-isolation.d.ts +2 -0
  504. package/dist/providers/container-isolation.js +29 -0
  505. package/dist/providers/container-isolation.js.map +1 -0
  506. package/dist/providers/container-mounts.js +7 -2
  507. package/dist/providers/container-mounts.js.map +1 -1
  508. package/dist/providers/container-network.d.ts +2 -0
  509. package/dist/providers/container-network.js +14 -0
  510. package/dist/providers/container-network.js.map +1 -0
  511. package/dist/providers/container-plan.js +6 -2
  512. package/dist/providers/container-plan.js.map +1 -1
  513. package/dist/providers/container.constants.d.ts +1 -0
  514. package/dist/providers/container.constants.js +1 -0
  515. package/dist/providers/container.constants.js.map +1 -1
  516. package/dist/providers/container.js +50 -3
  517. package/dist/providers/container.js.map +1 -1
  518. package/dist/providers/container.types.d.ts +5 -0
  519. package/dist/providers/container.types.js.map +1 -1
  520. package/dist/providers/daytona-command.js +10 -6
  521. package/dist/providers/daytona-command.js.map +1 -1
  522. package/dist/providers/daytona-terminal.d.ts +3 -0
  523. package/dist/providers/daytona-terminal.js +128 -0
  524. package/dist/providers/daytona-terminal.js.map +1 -0
  525. package/dist/providers/daytona.js +15 -4
  526. package/dist/providers/daytona.js.map +1 -1
  527. package/dist/providers/diagnostic-container.d.ts +4 -0
  528. package/dist/providers/diagnostic-container.js +15 -0
  529. package/dist/providers/diagnostic-container.js.map +1 -0
  530. package/dist/providers/docker.d.ts +2 -0
  531. package/dist/providers/docker.js.map +1 -1
  532. package/dist/providers/file-batches.constants.d.ts +10 -0
  533. package/dist/providers/file-batches.constants.js +57 -0
  534. package/dist/providers/file-batches.constants.js.map +1 -0
  535. package/dist/providers/file-batches.d.ts +2 -0
  536. package/dist/providers/file-batches.js +160 -0
  537. package/dist/providers/file-batches.js.map +1 -0
  538. package/dist/providers/file-upload.constants.d.ts +1 -0
  539. package/dist/providers/file-upload.constants.js +68 -0
  540. package/dist/providers/file-upload.constants.js.map +1 -0
  541. package/dist/providers/file-upload.d.ts +2 -0
  542. package/dist/providers/file-upload.js +146 -0
  543. package/dist/providers/file-upload.js.map +1 -0
  544. package/dist/providers/firecracker-command.d.ts +5 -0
  545. package/dist/providers/firecracker-command.js +114 -0
  546. package/dist/providers/firecracker-command.js.map +1 -0
  547. package/dist/providers/firecracker-files.constants.d.ts +1 -0
  548. package/dist/providers/firecracker-files.constants.js +21 -0
  549. package/dist/providers/firecracker-files.constants.js.map +1 -0
  550. package/dist/providers/firecracker-files.d.ts +3 -0
  551. package/dist/providers/firecracker-files.js +110 -0
  552. package/dist/providers/firecracker-files.js.map +1 -0
  553. package/dist/providers/firecracker-machine.d.ts +3 -0
  554. package/dist/providers/firecracker-machine.js +155 -0
  555. package/dist/providers/firecracker-machine.js.map +1 -0
  556. package/dist/providers/firecracker.constants.d.ts +10 -0
  557. package/dist/providers/firecracker.constants.js +11 -0
  558. package/dist/providers/firecracker.constants.js.map +1 -0
  559. package/dist/providers/firecracker.d.ts +4 -0
  560. package/dist/providers/firecracker.js +103 -0
  561. package/dist/providers/firecracker.js.map +1 -0
  562. package/dist/providers/firecracker.types.d.ts +36 -0
  563. package/dist/providers/firecracker.types.js +2 -0
  564. package/dist/providers/firecracker.types.js.map +1 -0
  565. package/dist/providers/local.js +2 -1
  566. package/dist/providers/local.js.map +1 -1
  567. package/dist/providers/podman.d.ts +2 -0
  568. package/dist/providers/podman.js.map +1 -1
  569. package/dist/providers/terminal-bridge.d.ts +14 -0
  570. package/dist/providers/terminal-bridge.js +100 -0
  571. package/dist/providers/terminal-bridge.js.map +1 -0
  572. package/dist/providers/vercel-directory.d.ts +2 -0
  573. package/dist/providers/vercel-directory.js +7 -0
  574. package/dist/providers/vercel-directory.js.map +1 -0
  575. package/dist/providers/vercel-files.js +3 -2
  576. package/dist/providers/vercel-files.js.map +1 -1
  577. package/dist/providers/vercel-network.d.ts +2 -0
  578. package/dist/providers/vercel-network.js +18 -0
  579. package/dist/providers/vercel-network.js.map +1 -0
  580. package/dist/providers/vercel.d.ts +1 -0
  581. package/dist/providers/vercel.js +8 -2
  582. package/dist/providers/vercel.js.map +1 -1
  583. package/dist/providers/vercel.types.d.ts +2 -0
  584. package/dist/providers/vercel.types.js.map +1 -1
  585. package/dist/providers/versions.constants.d.ts +1 -0
  586. package/dist/providers/versions.constants.js +1 -0
  587. package/dist/providers/versions.constants.js.map +1 -1
  588. package/package.json +16 -1
@@ -0,0 +1,137 @@
1
+ import { copyFile, lstat, mkdir, mkdtemp, realpath, rm, } from "node:fs/promises";
2
+ import { tmpdir } from "node:os";
3
+ import { join } from "node:path";
4
+ import { directory, safeDestination } from "../infrastructure/files.js";
5
+ import { verificationGit as git } from "../infrastructure/git/verification-command.js";
6
+ import { hashInspectionEntry } from "../infrastructure/inspection-hash.js";
7
+ import { recoveryTransferPatches } from "./recovery-verification.constants.js";
8
+ export async function verifyRecoveryRestorability(root, state, repository) {
9
+ const temporary = await realpath(await mkdtemp(join(tmpdir(), "outpost-restore-check-")));
10
+ const checks = [];
11
+ let stage = "REPOSITORY_OBJECTS";
12
+ try {
13
+ const source = await directory(repository);
14
+ stage = "SOURCE_UNSUPPORTED";
15
+ const common = (await git(source, [
16
+ "rev-parse",
17
+ "--path-format=absolute",
18
+ "--git-common-dir",
19
+ ])).trim();
20
+ const configuration = await git(source, [
21
+ "config",
22
+ "--local",
23
+ "--null",
24
+ "--list",
25
+ ]);
26
+ if (/(?:extensions\.partialclone|remote\.[^\n\0]+\.(?:promisor|partialclonefilter))\n/i.test(configuration))
27
+ throw new Error("Partial repositories are unsupported");
28
+ for (const name of [
29
+ "shallow",
30
+ "objects/info/alternates",
31
+ "objects/info/http-alternates",
32
+ ]) {
33
+ const exists = await lstat(join(common, name)).then(() => true, (error) => {
34
+ if (error &&
35
+ typeof error === "object" &&
36
+ "code" in error &&
37
+ error.code === "ENOENT")
38
+ return false;
39
+ throw error;
40
+ });
41
+ if (exists)
42
+ throw new Error("Repository depends on external or shallow objects");
43
+ }
44
+ const checkout = join(temporary, "checkout");
45
+ const snapshot = join(temporary, "transfer");
46
+ await mkdir(snapshot);
47
+ for (const name of [
48
+ ...recoveryTransferPatches,
49
+ ...(state.previous !== state.next ? ["commits.bundle"] : []),
50
+ ]) {
51
+ stage = "TRANSFER_SNAPSHOT";
52
+ const path = await safeDestination(root, name);
53
+ const before = await hashInspectionEntry(path);
54
+ if (before.kind !== "file")
55
+ throw new Error("Expected a regular transfer file");
56
+ await copyFile(path, join(snapshot, name));
57
+ const copied = await hashInspectionEntry(join(snapshot, name));
58
+ if (before.sha256 !== copied.sha256 || before.bytes !== copied.bytes)
59
+ throw new Error("Transfer changed while copying");
60
+ }
61
+ stage = "REPOSITORY_OBJECTS";
62
+ await git(temporary, [
63
+ "clone",
64
+ "--local",
65
+ "--no-hardlinks",
66
+ "--no-checkout",
67
+ "--",
68
+ source,
69
+ checkout,
70
+ ]);
71
+ if (state.previous !== state.next) {
72
+ stage = "BUNDLE_OBJECTS";
73
+ await git(checkout, [
74
+ "bundle",
75
+ "verify",
76
+ join(snapshot, "commits.bundle"),
77
+ ]);
78
+ await git(checkout, [
79
+ "bundle",
80
+ "unbundle",
81
+ join(snapshot, "commits.bundle"),
82
+ ]);
83
+ checks.push({
84
+ path: join(root, "commits.bundle"),
85
+ status: "pass",
86
+ code: "BUNDLE_OBJECTS_VALID",
87
+ });
88
+ }
89
+ stage = "COMMIT_OBJECTS";
90
+ await git(checkout, ["cat-file", "-e", `${state.previous}^{commit}`]);
91
+ await git(checkout, ["cat-file", "-e", `${state.next}^{commit}`]);
92
+ await git(checkout, [
93
+ "fsck",
94
+ "--strict",
95
+ "--no-reflogs",
96
+ state.previous,
97
+ state.next,
98
+ ]);
99
+ checks.push({ path: root, status: "pass", code: "COMMIT_OBJECTS_VALID" });
100
+ for (const [name, commit, cached] of [
101
+ ["previous.patch", state.previous, false],
102
+ ["previous-index.patch", state.previous, true],
103
+ ["remote.patch", state.next, false],
104
+ ]) {
105
+ stage = `PATCH_${name.toUpperCase().replaceAll(/[.-]/g, "_")}`;
106
+ await git(checkout, ["reset", "--hard", commit]);
107
+ const patch = join(snapshot, name);
108
+ if ((await lstat(patch)).size) {
109
+ const args = [
110
+ "apply",
111
+ "--binary",
112
+ ...(cached ? ["--cached"] : []),
113
+ patch,
114
+ ];
115
+ await git(checkout, [...args.slice(0, -1), "--check", patch]);
116
+ await git(checkout, args);
117
+ }
118
+ checks.push({
119
+ path: join(root, name),
120
+ status: "pass",
121
+ code: "PATCH_APPLIES",
122
+ });
123
+ }
124
+ }
125
+ catch {
126
+ checks.push({
127
+ path: root,
128
+ status: "fail",
129
+ code: stage === "SOURCE_UNSUPPORTED" ? stage : `${stage}_FAILED`,
130
+ });
131
+ }
132
+ finally {
133
+ await rm(temporary, { recursive: true, force: true, maxRetries: 3 });
134
+ }
135
+ return checks;
136
+ }
137
+ //# sourceMappingURL=recovery-restorability.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recovery-restorability.js","sourceRoot":"","sources":["../../src/application/recovery-restorability.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n copyFile,\n lstat,\n mkdir,\n mkdtemp,\n realpath,\n rm,\n} from \"node:fs/promises\";\nimport { tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { directory, safeDestination } from \"../infrastructure/files.ts\";\nimport { verificationGit as git } from \"../infrastructure/git/verification-command.ts\";\nimport { hashInspectionEntry } from \"../infrastructure/inspection-hash.ts\";\nimport { recoveryTransferPatches } from \"./recovery-verification.constants.ts\";\nimport type {\n RecoveryStructureCheck,\n RecoveryTransferState,\n} from \"./recovery-verification.types.ts\";\n\nexport async function verifyRecoveryRestorability(\n root: string,\n state: RecoveryTransferState,\n repository: string,\n): Promise<readonly RecoveryStructureCheck[]> {\n const temporary = await realpath(\n await mkdtemp(join(tmpdir(), \"outpost-restore-check-\")),\n );\n const checks: RecoveryStructureCheck[] = [];\n let stage = \"REPOSITORY_OBJECTS\";\n try {\n const source = await directory(repository);\n stage = \"SOURCE_UNSUPPORTED\";\n const common = (\n await git(source, [\n \"rev-parse\",\n \"--path-format=absolute\",\n \"--git-common-dir\",\n ])\n ).trim();\n const configuration = await git(source, [\n \"config\",\n \"--local\",\n \"--null\",\n \"--list\",\n ]);\n if (\n /(?:extensions\\.partialclone|remote\\.[^\\n\\0]+\\.(?:promisor|partialclonefilter))\\n/i.test(\n configuration,\n )\n )\n throw new Error(\"Partial repositories are unsupported\");\n for (const name of [\n \"shallow\",\n \"objects/info/alternates\",\n \"objects/info/http-alternates\",\n ]) {\n const exists = await lstat(join(common, name)).then(\n () => true,\n (error: unknown) => {\n if (\n error &&\n typeof error === \"object\" &&\n \"code\" in error &&\n error.code === \"ENOENT\"\n )\n return false;\n throw error;\n },\n );\n if (exists)\n throw new Error(\"Repository depends on external or shallow objects\");\n }\n const checkout = join(temporary, \"checkout\");\n const snapshot = join(temporary, \"transfer\");\n await mkdir(snapshot);\n for (const name of [\n ...recoveryTransferPatches,\n ...(state.previous !== state.next ? [\"commits.bundle\"] : []),\n ]) {\n stage = \"TRANSFER_SNAPSHOT\";\n const path = await safeDestination(root, name);\n const before = await hashInspectionEntry(path);\n if (before.kind !== \"file\")\n throw new Error(\"Expected a regular transfer file\");\n await copyFile(path, join(snapshot, name));\n const copied = await hashInspectionEntry(join(snapshot, name));\n if (before.sha256 !== copied.sha256 || before.bytes !== copied.bytes)\n throw new Error(\"Transfer changed while copying\");\n }\n stage = \"REPOSITORY_OBJECTS\";\n await git(temporary, [\n \"clone\",\n \"--local\",\n \"--no-hardlinks\",\n \"--no-checkout\",\n \"--\",\n source,\n checkout,\n ]);\n if (state.previous !== state.next) {\n stage = \"BUNDLE_OBJECTS\";\n await git(checkout, [\n \"bundle\",\n \"verify\",\n join(snapshot, \"commits.bundle\"),\n ]);\n await git(checkout, [\n \"bundle\",\n \"unbundle\",\n join(snapshot, \"commits.bundle\"),\n ]);\n checks.push({\n path: join(root, \"commits.bundle\"),\n status: \"pass\",\n code: \"BUNDLE_OBJECTS_VALID\",\n });\n }\n stage = \"COMMIT_OBJECTS\";\n await git(checkout, [\"cat-file\", \"-e\", `${state.previous}^{commit}`]);\n await git(checkout, [\"cat-file\", \"-e\", `${state.next}^{commit}`]);\n await git(checkout, [\n \"fsck\",\n \"--strict\",\n \"--no-reflogs\",\n state.previous,\n state.next,\n ]);\n checks.push({ path: root, status: \"pass\", code: \"COMMIT_OBJECTS_VALID\" });\n for (const [name, commit, cached] of [\n [\"previous.patch\", state.previous, false],\n [\"previous-index.patch\", state.previous, true],\n [\"remote.patch\", state.next, false],\n ] as const) {\n stage = `PATCH_${name.toUpperCase().replaceAll(/[.-]/g, \"_\")}`;\n await git(checkout, [\"reset\", \"--hard\", commit]);\n const patch = join(snapshot, name);\n if ((await lstat(patch)).size) {\n const args = [\n \"apply\",\n \"--binary\",\n ...(cached ? [\"--cached\"] : []),\n patch,\n ];\n await git(checkout, [...args.slice(0, -1), \"--check\", patch]);\n await git(checkout, args);\n }\n checks.push({\n path: join(root, name),\n status: \"pass\",\n code: \"PATCH_APPLIES\",\n });\n }\n } catch {\n checks.push({\n path: root,\n status: \"fail\",\n code: stage === \"SOURCE_UNSUPPORTED\" ? stage : `${stage}_FAILED`,\n });\n } finally {\n await rm(temporary, { recursive: true, force: true, maxRetries: 3 });\n }\n return checks;\n}\n"]}
@@ -0,0 +1,2 @@
1
+ import type { RecoveryRestoreSnapshot } from "./recovery-restore.types.ts";
2
+ export declare function snapshotRecoveryTransfer(path: string, maxBytes?: number): Promise<RecoveryRestoreSnapshot>;
@@ -0,0 +1,57 @@
1
+ import { createHash } from "node:crypto";
2
+ import { cp, lstat, mkdir, mkdtemp, realpath, rm, writeFile, } from "node:fs/promises";
3
+ import { tmpdir } from "node:os";
4
+ import { dirname, join } from "node:path";
5
+ import { invariant, positive } from "../domain/errors.js";
6
+ import { directory, safeDestination } from "../infrastructure/files.js";
7
+ import { readInspectionFile } from "../infrastructure/inspection-file.js";
8
+ import { recoveryChecksumPaths } from "./recovery-checksum-paths.js";
9
+ import { recoveryChecksumDefaults } from "./recovery-checksums.constants.js";
10
+ import { recoveryVerificationDefaults } from "./recovery-verification.constants.js";
11
+ import { transferState, verifyRecoveryTransfer, } from "./recovery-verification.js";
12
+ export async function snapshotRecoveryTransfer(path, maxBytes = recoveryChecksumDefaults.maxBytes) {
13
+ positive(maxBytes, "maxBytes");
14
+ const source = await directory(path);
15
+ const stateBytes = await readInspectionFile(join(source, "state.json"), recoveryVerificationDefaults.maxStateBytes);
16
+ const state = JSON.parse(stateBytes.toString("utf8"));
17
+ invariant(transferState(state), "Invalid recovery transfer state");
18
+ const manifest = await readInspectionFile(join(source, recoveryChecksumDefaults.filename), recoveryChecksumDefaults.maxManifestBytes);
19
+ const snapshot = await realpath(await mkdtemp(join(tmpdir(), "outpost-restore-")));
20
+ const dispose = () => rm(snapshot, { recursive: true, force: true, maxRetries: 3 });
21
+ try {
22
+ await writeFile(join(snapshot, "state.json"), stateBytes, { mode: 0o600 });
23
+ await writeFile(join(snapshot, recoveryChecksumDefaults.filename), manifest, { mode: 0o600 });
24
+ let bytes = stateBytes.length;
25
+ for (const entry of recoveryChecksumPaths(state).filter((name) => name !== "state.json")) {
26
+ const from = await safeDestination(source, entry);
27
+ const info = await lstat(from);
28
+ invariant(info.isFile() || info.isSymbolicLink(), "Unsupported recovery payload type");
29
+ bytes += info.size;
30
+ invariant(bytes <= maxBytes, "Recovery snapshot byte limit exceeded");
31
+ const to = await safeDestination(snapshot, entry);
32
+ await mkdir(dirname(to), { recursive: true, mode: 0o700 });
33
+ await cp(from, to, {
34
+ dereference: false,
35
+ verbatimSymlinks: true,
36
+ force: false,
37
+ errorOnExist: true,
38
+ });
39
+ }
40
+ const verified = await verifyRecoveryTransfer(snapshot, {
41
+ checksums: true,
42
+ maxBytes,
43
+ });
44
+ invariant(verified.complete && verified.integrity === "checksums-match", "Recovery snapshot integrity verification failed");
45
+ return {
46
+ directory: snapshot,
47
+ state,
48
+ manifestSha256: createHash("sha256").update(manifest).digest("hex"),
49
+ dispose,
50
+ };
51
+ }
52
+ catch (error) {
53
+ await dispose();
54
+ throw error;
55
+ }
56
+ }
57
+ //# sourceMappingURL=recovery-restore-snapshot.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recovery-restore-snapshot.js","sourceRoot":"","sources":["../../src/application/recovery-restore-snapshot.ts"],"names":[],"mappings":"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","sourcesContent":["import { createHash } from \"node:crypto\";\nimport {\n cp,\n lstat,\n mkdir,\n mkdtemp,\n realpath,\n rm,\n writeFile,\n} from \"node:fs/promises\";\nimport { tmpdir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\nimport { invariant, positive } from \"../domain/errors.ts\";\nimport { directory, safeDestination } from \"../infrastructure/files.ts\";\nimport { readInspectionFile } from \"../infrastructure/inspection-file.ts\";\nimport { recoveryChecksumPaths } from \"./recovery-checksum-paths.ts\";\nimport { recoveryChecksumDefaults } from \"./recovery-checksums.constants.ts\";\nimport { recoveryVerificationDefaults } from \"./recovery-verification.constants.ts\";\nimport {\n transferState,\n verifyRecoveryTransfer,\n} from \"./recovery-verification.ts\";\nimport type { RecoveryRestoreSnapshot } from \"./recovery-restore.types.ts\";\n\nexport async function snapshotRecoveryTransfer(\n path: string,\n maxBytes: number = recoveryChecksumDefaults.maxBytes,\n): Promise<RecoveryRestoreSnapshot> {\n positive(maxBytes, \"maxBytes\");\n const source = await directory(path);\n const stateBytes = await readInspectionFile(\n join(source, \"state.json\"),\n recoveryVerificationDefaults.maxStateBytes,\n );\n const state: unknown = JSON.parse(stateBytes.toString(\"utf8\"));\n invariant(transferState(state), \"Invalid recovery transfer state\");\n const manifest = await readInspectionFile(\n join(source, recoveryChecksumDefaults.filename),\n recoveryChecksumDefaults.maxManifestBytes,\n );\n const snapshot = await realpath(\n await mkdtemp(join(tmpdir(), \"outpost-restore-\")),\n );\n const dispose = () =>\n rm(snapshot, { recursive: true, force: true, maxRetries: 3 });\n try {\n await writeFile(join(snapshot, \"state.json\"), stateBytes, { mode: 0o600 });\n await writeFile(\n join(snapshot, recoveryChecksumDefaults.filename),\n manifest,\n { mode: 0o600 },\n );\n let bytes = stateBytes.length;\n for (const entry of recoveryChecksumPaths(state).filter(\n (name) => name !== \"state.json\",\n )) {\n const from = await safeDestination(source, entry);\n const info = await lstat(from);\n invariant(\n info.isFile() || info.isSymbolicLink(),\n \"Unsupported recovery payload type\",\n );\n bytes += info.size;\n invariant(bytes <= maxBytes, \"Recovery snapshot byte limit exceeded\");\n const to = await safeDestination(snapshot, entry);\n await mkdir(dirname(to), { recursive: true, mode: 0o700 });\n await cp(from, to, {\n dereference: false,\n verbatimSymlinks: true,\n force: false,\n errorOnExist: true,\n });\n }\n const verified = await verifyRecoveryTransfer(snapshot, {\n checksums: true,\n maxBytes,\n });\n invariant(\n verified.complete && verified.integrity === \"checksums-match\",\n \"Recovery snapshot integrity verification failed\",\n );\n return {\n directory: snapshot,\n state,\n manifestSha256: createHash(\"sha256\").update(manifest).digest(\"hex\"),\n dispose,\n };\n } catch (error) {\n await dispose();\n throw error;\n }\n}\n"]}
@@ -0,0 +1,3 @@
1
+ import type { RecoveryRestoreOptions, RecoveryRestorePlan, RecoveryRestoreResult } from "./recovery-restore.types.ts";
2
+ export declare function planRecoveryRestore(options: RecoveryRestoreOptions): Promise<RecoveryRestorePlan>;
3
+ export declare function restoreRecoveryTransfer(plan: RecoveryRestorePlan): Promise<RecoveryRestoreResult>;
@@ -0,0 +1,161 @@
1
+ import { createHash } from "node:crypto";
2
+ import { cp, lstat, mkdir } from "node:fs/promises";
3
+ import { basename, dirname, join, resolve } from "node:path";
4
+ import { invariant, OutpostError } from "../domain/errors.js";
5
+ import { directory, inside, safeDestination } from "../infrastructure/files.js";
6
+ import { verificationGit as git } from "../infrastructure/git/verification-command.js";
7
+ import { verifyRecoveryRestorability } from "./recovery-restorability.js";
8
+ import { snapshotRecoveryTransfer } from "./recovery-restore-snapshot.js";
9
+ function planFingerprint(plan) {
10
+ return createHash("sha256")
11
+ .update(JSON.stringify([
12
+ plan.directory,
13
+ plan.repository,
14
+ plan.destination,
15
+ plan.side,
16
+ plan.maxBytes ?? null,
17
+ plan.manifestSha256,
18
+ plan.commit,
19
+ plan.payloads,
20
+ plan.staging,
21
+ ]))
22
+ .digest("hex");
23
+ }
24
+ async function absent(path) {
25
+ const present = await lstat(path).then(() => true, (error) => {
26
+ if (error &&
27
+ typeof error === "object" &&
28
+ "code" in error &&
29
+ error.code === "ENOENT")
30
+ return false;
31
+ throw error;
32
+ });
33
+ invariant(!present, "Recovery destination already exists");
34
+ }
35
+ async function locations(options) {
36
+ invariant(options.side === "previous" || options.side === "incoming", "Recovery side must be previous or incoming");
37
+ const repository = await directory(options.repository);
38
+ const transfer = await directory(options.directory);
39
+ const destination = join(await directory(dirname(resolve(options.destination))), basename(resolve(options.destination)));
40
+ const common = await directory((await git(repository, [
41
+ "rev-parse",
42
+ "--path-format=absolute",
43
+ "--git-common-dir",
44
+ ])).trim());
45
+ invariant(!inside(repository, destination) &&
46
+ !inside(transfer, destination) &&
47
+ !inside(common, destination), "Recovery destination must be outside the source repository, Git metadata and transfer");
48
+ await absent(destination);
49
+ return { repository, directory: transfer, destination };
50
+ }
51
+ export async function planRecoveryRestore(options) {
52
+ const paths = await locations(options);
53
+ const snapshot = await snapshotRecoveryTransfer(paths.directory, options.maxBytes);
54
+ try {
55
+ const checks = await verifyRecoveryRestorability(snapshot.directory, snapshot.state, paths.repository);
56
+ invariant(checks.every((check) => check.status === "pass"), "Recovery Git restorability verification failed");
57
+ const plan = {
58
+ ...options,
59
+ ...paths,
60
+ manifestSha256: snapshot.manifestSha256,
61
+ commit: options.side === "previous"
62
+ ? snapshot.state.previous
63
+ : snapshot.state.next,
64
+ payloads: options.side === "previous"
65
+ ? snapshot.state.previousExtras
66
+ : snapshot.state.incoming,
67
+ staging: options.side === "previous"
68
+ ? "preserved"
69
+ : "unavailable",
70
+ };
71
+ return { ...plan, fingerprint: planFingerprint(plan) };
72
+ }
73
+ finally {
74
+ await snapshot.dispose();
75
+ }
76
+ }
77
+ async function applyPatch(checkout, patch, cached = false) {
78
+ if (!(await lstat(patch)).size)
79
+ return;
80
+ await git(checkout, [
81
+ "apply",
82
+ "--binary",
83
+ ...(cached ? ["--cached"] : []),
84
+ patch,
85
+ ]);
86
+ }
87
+ export async function restoreRecoveryTransfer(plan) {
88
+ invariant(plan.fingerprint === planFingerprint(plan), "Recovery plan changed after planning");
89
+ const paths = await locations(plan);
90
+ invariant(paths.repository === plan.repository &&
91
+ paths.directory === plan.directory &&
92
+ paths.destination === plan.destination, "Recovery plan paths changed after planning");
93
+ const snapshot = await snapshotRecoveryTransfer(paths.directory, plan.maxBytes);
94
+ let owned = false;
95
+ try {
96
+ invariant(snapshot.manifestSha256 === plan.manifestSha256, "Recovery transfer changed since planning");
97
+ const commit = plan.side === "previous" ? snapshot.state.previous : snapshot.state.next;
98
+ invariant(commit === plan.commit, "Recovery plan commit changed");
99
+ const checks = await verifyRecoveryRestorability(snapshot.directory, snapshot.state, paths.repository);
100
+ invariant(checks.every((check) => check.status === "pass"), "Recovery Git restorability verification failed");
101
+ await mkdir(paths.destination, { mode: 0o700 });
102
+ owned = true;
103
+ await git(dirname(paths.destination), [
104
+ "clone",
105
+ "--local",
106
+ "--no-hardlinks",
107
+ "--no-checkout",
108
+ "--",
109
+ paths.repository,
110
+ paths.destination,
111
+ ]);
112
+ await git(paths.destination, ["remote", "remove", "origin"]);
113
+ if (snapshot.state.previous !== snapshot.state.next) {
114
+ await git(paths.destination, [
115
+ "bundle",
116
+ "verify",
117
+ join(snapshot.directory, "commits.bundle"),
118
+ ]);
119
+ await git(paths.destination, [
120
+ "bundle",
121
+ "unbundle",
122
+ join(snapshot.directory, "commits.bundle"),
123
+ ]);
124
+ }
125
+ await git(paths.destination, ["checkout", "--detach", commit]);
126
+ await applyPatch(paths.destination, join(snapshot.directory, plan.side === "previous" ? "previous.patch" : "remote.patch"));
127
+ if (plan.side === "previous")
128
+ await applyPatch(paths.destination, join(snapshot.directory, "previous-index.patch"), true);
129
+ const entries = plan.side === "previous"
130
+ ? snapshot.state.previousExtras
131
+ : snapshot.state.incoming;
132
+ const prefix = plan.side === "previous" ? "previous-files" : "incoming";
133
+ for (const entry of entries) {
134
+ const to = await safeDestination(paths.destination, entry);
135
+ await absent(to);
136
+ await mkdir(dirname(to), { recursive: true, mode: 0o700 });
137
+ await cp(await safeDestination(snapshot.directory, `${prefix}/${entry}`), to, {
138
+ dereference: false,
139
+ verbatimSymlinks: true,
140
+ force: false,
141
+ errorOnExist: true,
142
+ });
143
+ }
144
+ return {
145
+ directory: paths.destination,
146
+ commit,
147
+ side: plan.side,
148
+ staging: plan.side === "previous" ? "preserved" : "unavailable",
149
+ sourceRetained: true,
150
+ };
151
+ }
152
+ catch (cause) {
153
+ if (!owned)
154
+ throw cause;
155
+ throw new OutpostError("workspace", "Recovery restoration failed; source and partial destination retained", { destination: paths.destination, transfer: paths.directory }, cause);
156
+ }
157
+ finally {
158
+ await snapshot.dispose();
159
+ }
160
+ }
161
+ //# sourceMappingURL=recovery-restore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recovery-restore.js","sourceRoot":"","sources":["../../src/application/recovery-restore.ts"],"names":[],"mappings":"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","sourcesContent":["import { createHash } from \"node:crypto\";\nimport { cp, lstat, mkdir } from \"node:fs/promises\";\nimport { basename, dirname, join, resolve } from \"node:path\";\nimport { invariant, OutpostError } from \"../domain/errors.ts\";\nimport { directory, inside, safeDestination } from \"../infrastructure/files.ts\";\nimport { verificationGit as git } from \"../infrastructure/git/verification-command.ts\";\nimport { verifyRecoveryRestorability } from \"./recovery-restorability.ts\";\nimport { snapshotRecoveryTransfer } from \"./recovery-restore-snapshot.ts\";\nimport type {\n RecoveryRestoreOptions,\n RecoveryRestorePlan,\n RecoveryRestoreResult,\n} from \"./recovery-restore.types.ts\";\n\nfunction planFingerprint(\n plan: Omit<RecoveryRestorePlan, \"fingerprint\">,\n): string {\n return createHash(\"sha256\")\n .update(\n JSON.stringify([\n plan.directory,\n plan.repository,\n plan.destination,\n plan.side,\n plan.maxBytes ?? null,\n plan.manifestSha256,\n plan.commit,\n plan.payloads,\n plan.staging,\n ]),\n )\n .digest(\"hex\");\n}\n\nasync function absent(path: string): Promise<void> {\n const present = await lstat(path).then(\n () => true,\n (error: unknown) => {\n if (\n error &&\n typeof error === \"object\" &&\n \"code\" in error &&\n error.code === \"ENOENT\"\n )\n return false;\n throw error;\n },\n );\n invariant(!present, \"Recovery destination already exists\");\n}\n\nasync function locations(options: RecoveryRestoreOptions) {\n invariant(\n options.side === \"previous\" || options.side === \"incoming\",\n \"Recovery side must be previous or incoming\",\n );\n const repository = await directory(options.repository);\n const transfer = await directory(options.directory);\n const destination = join(\n await directory(dirname(resolve(options.destination))),\n basename(resolve(options.destination)),\n );\n const common = await directory(\n (\n await git(repository, [\n \"rev-parse\",\n \"--path-format=absolute\",\n \"--git-common-dir\",\n ])\n ).trim(),\n );\n invariant(\n !inside(repository, destination) &&\n !inside(transfer, destination) &&\n !inside(common, destination),\n \"Recovery destination must be outside the source repository, Git metadata and transfer\",\n );\n await absent(destination);\n return { repository, directory: transfer, destination };\n}\n\nexport async function planRecoveryRestore(\n options: RecoveryRestoreOptions,\n): Promise<RecoveryRestorePlan> {\n const paths = await locations(options);\n const snapshot = await snapshotRecoveryTransfer(\n paths.directory,\n options.maxBytes,\n );\n try {\n const checks = await verifyRecoveryRestorability(\n snapshot.directory,\n snapshot.state,\n paths.repository,\n );\n invariant(\n checks.every((check) => check.status === \"pass\"),\n \"Recovery Git restorability verification failed\",\n );\n const plan = {\n ...options,\n ...paths,\n manifestSha256: snapshot.manifestSha256,\n commit:\n options.side === \"previous\"\n ? snapshot.state.previous\n : snapshot.state.next,\n payloads:\n options.side === \"previous\"\n ? snapshot.state.previousExtras\n : snapshot.state.incoming,\n staging:\n options.side === \"previous\"\n ? (\"preserved\" as const)\n : (\"unavailable\" as const),\n };\n return { ...plan, fingerprint: planFingerprint(plan) };\n } finally {\n await snapshot.dispose();\n }\n}\n\nasync function applyPatch(\n checkout: string,\n patch: string,\n cached = false,\n): Promise<void> {\n if (!(await lstat(patch)).size) return;\n await git(checkout, [\n \"apply\",\n \"--binary\",\n ...(cached ? [\"--cached\"] : []),\n patch,\n ]);\n}\n\nexport async function restoreRecoveryTransfer(\n plan: RecoveryRestorePlan,\n): Promise<RecoveryRestoreResult> {\n invariant(\n plan.fingerprint === planFingerprint(plan),\n \"Recovery plan changed after planning\",\n );\n const paths = await locations(plan);\n invariant(\n paths.repository === plan.repository &&\n paths.directory === plan.directory &&\n paths.destination === plan.destination,\n \"Recovery plan paths changed after planning\",\n );\n const snapshot = await snapshotRecoveryTransfer(\n paths.directory,\n plan.maxBytes,\n );\n let owned = false;\n try {\n invariant(\n snapshot.manifestSha256 === plan.manifestSha256,\n \"Recovery transfer changed since planning\",\n );\n const commit =\n plan.side === \"previous\" ? snapshot.state.previous : snapshot.state.next;\n invariant(commit === plan.commit, \"Recovery plan commit changed\");\n const checks = await verifyRecoveryRestorability(\n snapshot.directory,\n snapshot.state,\n paths.repository,\n );\n invariant(\n checks.every((check) => check.status === \"pass\"),\n \"Recovery Git restorability verification failed\",\n );\n await mkdir(paths.destination, { mode: 0o700 });\n owned = true;\n await git(dirname(paths.destination), [\n \"clone\",\n \"--local\",\n \"--no-hardlinks\",\n \"--no-checkout\",\n \"--\",\n paths.repository,\n paths.destination,\n ]);\n await git(paths.destination, [\"remote\", \"remove\", \"origin\"]);\n if (snapshot.state.previous !== snapshot.state.next) {\n await git(paths.destination, [\n \"bundle\",\n \"verify\",\n join(snapshot.directory, \"commits.bundle\"),\n ]);\n await git(paths.destination, [\n \"bundle\",\n \"unbundle\",\n join(snapshot.directory, \"commits.bundle\"),\n ]);\n }\n await git(paths.destination, [\"checkout\", \"--detach\", commit]);\n await applyPatch(\n paths.destination,\n join(\n snapshot.directory,\n plan.side === \"previous\" ? \"previous.patch\" : \"remote.patch\",\n ),\n );\n if (plan.side === \"previous\")\n await applyPatch(\n paths.destination,\n join(snapshot.directory, \"previous-index.patch\"),\n true,\n );\n const entries =\n plan.side === \"previous\"\n ? snapshot.state.previousExtras\n : snapshot.state.incoming;\n const prefix = plan.side === \"previous\" ? \"previous-files\" : \"incoming\";\n for (const entry of entries) {\n const to = await safeDestination(paths.destination, entry);\n await absent(to);\n await mkdir(dirname(to), { recursive: true, mode: 0o700 });\n await cp(\n await safeDestination(snapshot.directory, `${prefix}/${entry}`),\n to,\n {\n dereference: false,\n verbatimSymlinks: true,\n force: false,\n errorOnExist: true,\n },\n );\n }\n return {\n directory: paths.destination,\n commit,\n side: plan.side,\n staging: plan.side === \"previous\" ? \"preserved\" : \"unavailable\",\n sourceRetained: true,\n };\n } catch (cause) {\n if (!owned) throw cause;\n throw new OutpostError(\n \"workspace\",\n \"Recovery restoration failed; source and partial destination retained\",\n { destination: paths.destination, transfer: paths.directory },\n cause,\n );\n } finally {\n await snapshot.dispose();\n }\n}\n"]}
@@ -0,0 +1,28 @@
1
+ import type { RecoveryTransferState } from "./recovery-verification.types.ts";
2
+ export interface RecoveryRestoreOptions {
3
+ readonly directory: string;
4
+ readonly repository: string;
5
+ readonly destination: string;
6
+ readonly side: "previous" | "incoming";
7
+ readonly maxBytes?: number;
8
+ }
9
+ export interface RecoveryRestorePlan extends RecoveryRestoreOptions {
10
+ readonly fingerprint: string;
11
+ readonly manifestSha256: string;
12
+ readonly commit: string;
13
+ readonly payloads: readonly string[];
14
+ readonly staging: "preserved" | "unavailable";
15
+ }
16
+ export interface RecoveryRestoreResult {
17
+ readonly directory: string;
18
+ readonly commit: string;
19
+ readonly side: "previous" | "incoming";
20
+ readonly staging: "preserved" | "unavailable";
21
+ readonly sourceRetained: true;
22
+ }
23
+ export interface RecoveryRestoreSnapshot {
24
+ readonly directory: string;
25
+ readonly state: RecoveryTransferState;
26
+ readonly manifestSha256: string;
27
+ dispose(): Promise<void>;
28
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=recovery-restore.types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recovery-restore.types.js","sourceRoot":"","sources":["../../src/application/recovery-restore.types.ts"],"names":[],"mappings":"","sourcesContent":["import type { RecoveryTransferState } from \"./recovery-verification.types.ts\";\n\nexport interface RecoveryRestoreOptions {\n readonly directory: string;\n readonly repository: string;\n readonly destination: string;\n readonly side: \"previous\" | \"incoming\";\n readonly maxBytes?: number;\n}\n\nexport interface RecoveryRestorePlan extends RecoveryRestoreOptions {\n readonly fingerprint: string;\n readonly manifestSha256: string;\n readonly commit: string;\n readonly payloads: readonly string[];\n readonly staging: \"preserved\" | \"unavailable\";\n}\n\nexport interface RecoveryRestoreResult {\n readonly directory: string;\n readonly commit: string;\n readonly side: \"previous\" | \"incoming\";\n readonly staging: \"preserved\" | \"unavailable\";\n readonly sourceRetained: true;\n}\n\nexport interface RecoveryRestoreSnapshot {\n readonly directory: string;\n readonly state: RecoveryTransferState;\n readonly manifestSha256: string;\n dispose(): Promise<void>;\n}\n"]}
@@ -0,0 +1,2 @@
1
+ import type { RecoveryRetentionPolicy } from "./recovery-retention.types.ts";
2
+ export declare function retentionPolicy(value: unknown): asserts value is RecoveryRetentionPolicy;
@@ -0,0 +1,21 @@
1
+ import { invariant } from "../domain/errors.js";
2
+ export function retentionPolicy(value) {
3
+ invariant(!!value && typeof value === "object", "Retention policy must be an object");
4
+ invariant("version" in value && value.version === 1, "Retention policy version must be 1");
5
+ invariant("scopes" in value &&
6
+ Array.isArray(value.scopes) &&
7
+ value.scopes.length > 0 &&
8
+ value.scopes.every((scope) => scope === "clean-workspaces" || scope === "closed-logs"), "Retention scopes must contain clean-workspaces or closed-logs");
9
+ invariant("minAgeMs" in value &&
10
+ typeof value.minAgeMs === "number" &&
11
+ Number.isSafeInteger(value.minAgeMs) &&
12
+ value.minAgeMs >= 0, "minAgeMs must be a nonnegative integer");
13
+ for (const key of ["maxBytes", "maxWorkspaces"]) {
14
+ if (!(key in value))
15
+ continue;
16
+ const limit = Object.getOwnPropertyDescriptor(value, key)?.value;
17
+ invariant(typeof limit === "number" && Number.isSafeInteger(limit) && limit >= 0, `${key} must be a nonnegative integer`);
18
+ }
19
+ invariant(Object.keys(value).every((key) => ["version", "scopes", "minAgeMs", "maxBytes", "maxWorkspaces"].includes(key)), "Unsupported retention policy field");
20
+ }
21
+ //# sourceMappingURL=recovery-retention-policy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recovery-retention-policy.js","sourceRoot":"","sources":["../../src/application/recovery-retention-policy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAGhD,MAAM,UAAU,eAAe,CAC7B,KAAc;IAEd,SAAS,CACP,CAAC,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,EACpC,oCAAoC,CACrC,CAAC;IACF,SAAS,CACP,SAAS,IAAI,KAAK,IAAI,KAAK,CAAC,OAAO,KAAK,CAAC,EACzC,oCAAoC,CACrC,CAAC;IACF,SAAS,CACP,QAAQ,IAAI,KAAK;QACf,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC;QAC3B,KAAK,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC;QACvB,KAAK,CAAC,MAAM,CAAC,KAAK,CAChB,CAAC,KAAc,EAAE,EAAE,CACjB,KAAK,KAAK,kBAAkB,IAAI,KAAK,KAAK,aAAa,CAC1D,EACH,+DAA+D,CAChE,CAAC;IACF,SAAS,CACP,UAAU,IAAI,KAAK;QACjB,OAAO,KAAK,CAAC,QAAQ,KAAK,QAAQ;QAClC,MAAM,CAAC,aAAa,CAAC,KAAK,CAAC,QAAQ,CAAC;QACpC,KAAK,CAAC,QAAQ,IAAI,CAAC,EACrB,wCAAwC,CACzC,CAAC;IACF,KAAK,MAAM,GAAG,IAAI,CAAC,UAAU,EAAE,eAAe,CAAU,EAAE,CAAC;QACzD,IAAI,CAAC,CAAC,GAAG,IAAI,KAAK,CAAC;YAAE,SAAS;QAC9B,MAAM,KAAK,GAAY,MAAM,CAAC,wBAAwB,CAAC,KAAK,EAAE,GAAG,CAAC,EAAE,KAAK,CAAC;QAC1E,SAAS,CACP,OAAO,KAAK,KAAK,QAAQ,IAAI,MAAM,CAAC,aAAa,CAAC,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC,EACtE,GAAG,GAAG,gCAAgC,CACvC,CAAC;IACJ,CAAC;IACD,SAAS,CACP,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE,CAC/B,CAAC,SAAS,EAAE,QAAQ,EAAE,UAAU,EAAE,UAAU,EAAE,eAAe,CAAC,CAAC,QAAQ,CACrE,GAAG,CACJ,CACF,EACD,oCAAoC,CACrC,CAAC;AACJ,CAAC","sourcesContent":["import { invariant } from \"../domain/errors.ts\";\nimport type { RecoveryRetentionPolicy } from \"./recovery-retention.types.ts\";\n\nexport function retentionPolicy(\n value: unknown,\n): asserts value is RecoveryRetentionPolicy {\n invariant(\n !!value && typeof value === \"object\",\n \"Retention policy must be an object\",\n );\n invariant(\n \"version\" in value && value.version === 1,\n \"Retention policy version must be 1\",\n );\n invariant(\n \"scopes\" in value &&\n Array.isArray(value.scopes) &&\n value.scopes.length > 0 &&\n value.scopes.every(\n (scope: unknown) =>\n scope === \"clean-workspaces\" || scope === \"closed-logs\",\n ),\n \"Retention scopes must contain clean-workspaces or closed-logs\",\n );\n invariant(\n \"minAgeMs\" in value &&\n typeof value.minAgeMs === \"number\" &&\n Number.isSafeInteger(value.minAgeMs) &&\n value.minAgeMs >= 0,\n \"minAgeMs must be a nonnegative integer\",\n );\n for (const key of [\"maxBytes\", \"maxWorkspaces\"] as const) {\n if (!(key in value)) continue;\n const limit: unknown = Object.getOwnPropertyDescriptor(value, key)?.value;\n invariant(\n typeof limit === \"number\" && Number.isSafeInteger(limit) && limit >= 0,\n `${key} must be a nonnegative integer`,\n );\n }\n invariant(\n Object.keys(value).every((key) =>\n [\"version\", \"scopes\", \"minAgeMs\", \"maxBytes\", \"maxWorkspaces\"].includes(\n key,\n ),\n ),\n \"Unsupported retention policy field\",\n );\n}\n"]}
@@ -0,0 +1,3 @@
1
+ export declare const recoveryRetentionLimits: {
2
+ readonly maxPolicyBytes: 65536;
3
+ };
@@ -0,0 +1,2 @@
1
+ export const recoveryRetentionLimits = { maxPolicyBytes: 65_536 };
2
+ //# sourceMappingURL=recovery-retention.constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recovery-retention.constants.js","sourceRoot":"","sources":["../../src/application/recovery-retention.constants.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,uBAAuB,GAAG,EAAE,cAAc,EAAE,MAAM,EAAW,CAAC","sourcesContent":["export const recoveryRetentionLimits = { maxPolicyBytes: 65_536 } as const;\n"]}
@@ -0,0 +1,4 @@
1
+ import type { RecoveryPruneResult, RecoveryQuotaOptions, RecoveryRetentionOptions, RecoveryRetentionPlan } from "./recovery-retention.types.ts";
2
+ export declare function planRecoveryRetention(options: RecoveryRetentionOptions): Promise<RecoveryRetentionPlan>;
3
+ export declare function pruneRecoveryRetention(plan: RecoveryRetentionPlan): Promise<RecoveryPruneResult>;
4
+ export declare function assertRecoveryQuota(options: RecoveryQuotaOptions): Promise<void>;