@cleocode/core 2026.9.26 → 2026.10.2

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 (410) hide show
  1. package/dist/build-provenance.json +2 -2
  2. package/dist/cloud/journal.d.ts +9 -5
  3. package/dist/cloud/journal.d.ts.map +1 -1
  4. package/dist/cloud/journal.js +29 -8
  5. package/dist/cloud/journal.js.map +1 -1
  6. package/dist/cloud/manifest-check.d.ts +140 -4
  7. package/dist/cloud/manifest-check.d.ts.map +1 -1
  8. package/dist/cloud/manifest-check.js +309 -10
  9. package/dist/cloud/manifest-check.js.map +1 -1
  10. package/dist/cloud/nexus-attach.d.ts +119 -0
  11. package/dist/cloud/nexus-attach.d.ts.map +1 -0
  12. package/dist/cloud/nexus-attach.js +267 -0
  13. package/dist/cloud/nexus-attach.js.map +1 -0
  14. package/dist/cloud/nexus-auth.d.ts +15 -3
  15. package/dist/cloud/nexus-auth.d.ts.map +1 -1
  16. package/dist/cloud/nexus-auth.js +90 -6
  17. package/dist/cloud/nexus-auth.js.map +1 -1
  18. package/dist/cloud/nexus-cloud-activity.d.ts +37 -0
  19. package/dist/cloud/nexus-cloud-activity.d.ts.map +1 -0
  20. package/dist/cloud/nexus-cloud-activity.js +79 -0
  21. package/dist/cloud/nexus-cloud-activity.js.map +1 -0
  22. package/dist/cloud/nexus-cloud-status.d.ts +132 -0
  23. package/dist/cloud/nexus-cloud-status.d.ts.map +1 -0
  24. package/dist/cloud/nexus-cloud-status.js +476 -0
  25. package/dist/cloud/nexus-cloud-status.js.map +1 -0
  26. package/dist/cloud/nexus-cloud.d.ts +179 -0
  27. package/dist/cloud/nexus-cloud.d.ts.map +1 -0
  28. package/dist/cloud/nexus-cloud.js +296 -0
  29. package/dist/cloud/nexus-cloud.js.map +1 -0
  30. package/dist/cloud/nexus-device.d.ts +32 -7
  31. package/dist/cloud/nexus-device.d.ts.map +1 -1
  32. package/dist/cloud/nexus-device.js +54 -7
  33. package/dist/cloud/nexus-device.js.map +1 -1
  34. package/dist/cloud/nexus-enrol.d.ts +35 -4
  35. package/dist/cloud/nexus-enrol.d.ts.map +1 -1
  36. package/dist/cloud/nexus-enrol.js +192 -47
  37. package/dist/cloud/nexus-enrol.js.map +1 -1
  38. package/dist/cloud/nexus-home.d.ts +74 -0
  39. package/dist/cloud/nexus-home.d.ts.map +1 -0
  40. package/dist/cloud/nexus-home.js +97 -0
  41. package/dist/cloud/nexus-home.js.map +1 -0
  42. package/dist/cloud/nexus-link.d.ts +8 -1
  43. package/dist/cloud/nexus-link.d.ts.map +1 -1
  44. package/dist/cloud/nexus-link.js +138 -11
  45. package/dist/cloud/nexus-link.js.map +1 -1
  46. package/dist/cloud/nexus-logout.d.ts +114 -0
  47. package/dist/cloud/nexus-logout.d.ts.map +1 -0
  48. package/dist/cloud/nexus-logout.js +429 -0
  49. package/dist/cloud/nexus-logout.js.map +1 -0
  50. package/dist/cloud/nexus-vault-keys.d.ts +129 -0
  51. package/dist/cloud/nexus-vault-keys.d.ts.map +1 -0
  52. package/dist/cloud/nexus-vault-keys.js +277 -0
  53. package/dist/cloud/nexus-vault-keys.js.map +1 -0
  54. package/dist/cloud/nexus-vault-state.d.ts +121 -0
  55. package/dist/cloud/nexus-vault-state.d.ts.map +1 -0
  56. package/dist/cloud/nexus-vault-state.js +274 -0
  57. package/dist/cloud/nexus-vault-state.js.map +1 -0
  58. package/dist/cloud/nexus-vault.d.ts +160 -0
  59. package/dist/cloud/nexus-vault.d.ts.map +1 -0
  60. package/dist/cloud/nexus-vault.js +1733 -0
  61. package/dist/cloud/nexus-vault.js.map +1 -0
  62. package/dist/cloud/signing.d.ts +24 -8
  63. package/dist/cloud/signing.d.ts.map +1 -1
  64. package/dist/cloud/signing.js +61 -15
  65. package/dist/cloud/signing.js.map +1 -1
  66. package/dist/docs/export-document.js +8341 -3317
  67. package/dist/docs/export-document.js.map +3 -3
  68. package/dist/doctor/migrations.d.ts +75 -0
  69. package/dist/doctor/migrations.d.ts.map +1 -0
  70. package/dist/doctor/migrations.js +136 -0
  71. package/dist/doctor/migrations.js.map +1 -0
  72. package/dist/doctor/sync-sealer.d.ts +48 -0
  73. package/dist/doctor/sync-sealer.d.ts.map +1 -0
  74. package/dist/doctor/sync-sealer.js +109 -0
  75. package/dist/doctor/sync-sealer.js.map +1 -0
  76. package/dist/doctor/sync-triggers.d.ts +53 -0
  77. package/dist/doctor/sync-triggers.d.ts.map +1 -0
  78. package/dist/doctor/sync-triggers.js +157 -0
  79. package/dist/doctor/sync-triggers.js.map +1 -0
  80. package/dist/init.d.ts.map +1 -1
  81. package/dist/init.js +5 -1
  82. package/dist/init.js.map +1 -1
  83. package/dist/internal.d.ts +1 -1
  84. package/dist/internal.d.ts.map +1 -1
  85. package/dist/internal.js +1 -1
  86. package/dist/internal.js.map +1 -1
  87. package/dist/llm/plugin-facade.js +8668 -3644
  88. package/dist/llm/plugin-facade.js.map +3 -3
  89. package/dist/nexus/projects-clean.d.ts +3 -0
  90. package/dist/nexus/projects-clean.d.ts.map +1 -1
  91. package/dist/nexus/projects-clean.js +9 -3
  92. package/dist/nexus/projects-clean.js.map +1 -1
  93. package/dist/nexus/registry-roots.d.ts +3 -1
  94. package/dist/nexus/registry-roots.d.ts.map +1 -1
  95. package/dist/nexus/registry-roots.js +5 -2
  96. package/dist/nexus/registry-roots.js.map +1 -1
  97. package/dist/nexus/registry.d.ts +8 -1
  98. package/dist/nexus/registry.d.ts.map +1 -1
  99. package/dist/nexus/registry.js +24 -10
  100. package/dist/nexus/registry.js.map +1 -1
  101. package/dist/nexus/workspace.d.ts +4 -1
  102. package/dist/nexus/workspace.d.ts.map +1 -1
  103. package/dist/nexus/workspace.js +10 -4
  104. package/dist/nexus/workspace.js.map +1 -1
  105. package/dist/orchestrate/spawn-ops.d.ts.map +1 -1
  106. package/dist/orchestrate/spawn-ops.js +7 -2
  107. package/dist/orchestrate/spawn-ops.js.map +1 -1
  108. package/dist/orchestrate/worker-verify.d.ts +121 -12
  109. package/dist/orchestrate/worker-verify.d.ts.map +1 -1
  110. package/dist/orchestrate/worker-verify.js +172 -21
  111. package/dist/orchestrate/worker-verify.js.map +1 -1
  112. package/dist/orchestration/spawn-prompt.d.ts.map +1 -1
  113. package/dist/orchestration/spawn-prompt.js +15 -9
  114. package/dist/orchestration/spawn-prompt.js.map +1 -1
  115. package/dist/release/ci-evidence.d.ts +9 -0
  116. package/dist/release/ci-evidence.d.ts.map +1 -1
  117. package/dist/release/ci-evidence.js +9 -2
  118. package/dist/release/ci-evidence.js.map +1 -1
  119. package/dist/resources/backend.d.ts +15 -3
  120. package/dist/resources/backend.d.ts.map +1 -1
  121. package/dist/resources/backend.js +7 -3
  122. package/dist/resources/backend.js.map +1 -1
  123. package/dist/resources/darwin-backend.d.ts +142 -0
  124. package/dist/resources/darwin-backend.d.ts.map +1 -0
  125. package/dist/resources/darwin-backend.js +288 -0
  126. package/dist/resources/darwin-backend.js.map +1 -0
  127. package/dist/resources/governor.d.ts +44 -1
  128. package/dist/resources/governor.d.ts.map +1 -1
  129. package/dist/resources/governor.js +100 -36
  130. package/dist/resources/governor.js.map +1 -1
  131. package/dist/resources/heavy-command.d.ts +132 -0
  132. package/dist/resources/heavy-command.d.ts.map +1 -0
  133. package/dist/resources/heavy-command.js +768 -0
  134. package/dist/resources/heavy-command.js.map +1 -0
  135. package/dist/resources/monitor.d.ts +50 -1
  136. package/dist/resources/monitor.d.ts.map +1 -1
  137. package/dist/resources/monitor.js +83 -1
  138. package/dist/resources/monitor.js.map +1 -1
  139. package/dist/resources/run-admission.d.ts +303 -0
  140. package/dist/resources/run-admission.d.ts.map +1 -0
  141. package/dist/resources/run-admission.js +648 -0
  142. package/dist/resources/run-admission.js.map +1 -0
  143. package/dist/resources/run-class.d.ts +111 -0
  144. package/dist/resources/run-class.d.ts.map +1 -0
  145. package/dist/resources/run-class.js +658 -0
  146. package/dist/resources/run-class.js.map +1 -0
  147. package/dist/resources/run-governed.d.ts +158 -0
  148. package/dist/resources/run-governed.d.ts.map +1 -0
  149. package/dist/resources/run-governed.js +406 -0
  150. package/dist/resources/run-governed.js.map +1 -0
  151. package/dist/resources/slot-holder.d.ts +267 -0
  152. package/dist/resources/slot-holder.d.ts.map +1 -0
  153. package/dist/resources/slot-holder.js +505 -0
  154. package/dist/resources/slot-holder.js.map +1 -0
  155. package/dist/resources/tool-groups.d.ts +74 -0
  156. package/dist/resources/tool-groups.d.ts.map +1 -0
  157. package/dist/resources/tool-groups.js +118 -0
  158. package/dist/resources/tool-groups.js.map +1 -0
  159. package/dist/routing/build-command-groups.d.ts.map +1 -1
  160. package/dist/routing/build-command-groups.js +1 -0
  161. package/dist/routing/build-command-groups.js.map +1 -1
  162. package/dist/selfimprove/fix-gen.js +8676 -3652
  163. package/dist/selfimprove/fix-gen.js.map +3 -3
  164. package/dist/sentient/cross-project-hygiene.d.ts +3 -2
  165. package/dist/sentient/cross-project-hygiene.d.ts.map +1 -1
  166. package/dist/sentient/cross-project-hygiene.js +5 -2
  167. package/dist/sentient/cross-project-hygiene.js.map +1 -1
  168. package/dist/sentient/state.d.ts +7 -0
  169. package/dist/sentient/state.d.ts.map +1 -1
  170. package/dist/sentient/state.js.map +1 -1
  171. package/dist/sentient/tick.d.ts +14 -2
  172. package/dist/sentient/tick.d.ts.map +1 -1
  173. package/dist/sentient/tick.js +63 -4
  174. package/dist/sentient/tick.js.map +1 -1
  175. package/dist/setup/sections/nexus-account.d.ts +8 -6
  176. package/dist/setup/sections/nexus-account.d.ts.map +1 -1
  177. package/dist/setup/sections/nexus-account.js +53 -9
  178. package/dist/setup/sections/nexus-account.js.map +1 -1
  179. package/dist/store/backup-recover.d.ts.map +1 -1
  180. package/dist/store/backup-recover.js +5 -0
  181. package/dist/store/backup-recover.js.map +1 -1
  182. package/dist/store/data-accessor.d.ts +1 -0
  183. package/dist/store/data-accessor.d.ts.map +1 -1
  184. package/dist/store/data-accessor.js +7 -0
  185. package/dist/store/data-accessor.js.map +1 -1
  186. package/dist/store/dual-scope-db.d.ts +23 -1
  187. package/dist/store/dual-scope-db.d.ts.map +1 -1
  188. package/dist/store/dual-scope-db.js +126 -36
  189. package/dist/store/dual-scope-db.js.map +1 -1
  190. package/dist/store/exodus/recovery.d.ts.map +1 -1
  191. package/dist/store/exodus/recovery.js +15 -0
  192. package/dist/store/exodus/recovery.js.map +1 -1
  193. package/dist/store/legacy-tasks-lineage.d.ts.map +1 -1
  194. package/dist/store/legacy-tasks-lineage.js +5 -0
  195. package/dist/store/legacy-tasks-lineage.js.map +1 -1
  196. package/dist/store/lock.d.ts +8 -1
  197. package/dist/store/lock.d.ts.map +1 -1
  198. package/dist/store/lock.js +10 -2
  199. package/dist/store/lock.js.map +1 -1
  200. package/dist/store/migration-manager.d.ts +5 -0
  201. package/dist/store/migration-manager.d.ts.map +1 -1
  202. package/dist/store/migration-manager.js +11 -0
  203. package/dist/store/migration-manager.js.map +1 -1
  204. package/dist/store/migration-runner.d.ts +158 -0
  205. package/dist/store/migration-runner.d.ts.map +1 -0
  206. package/dist/store/migration-runner.js +493 -0
  207. package/dist/store/migration-runner.js.map +1 -0
  208. package/dist/store/portable-bundle-import.d.ts +15 -1
  209. package/dist/store/portable-bundle-import.d.ts.map +1 -1
  210. package/dist/store/portable-bundle-import.js +24 -4
  211. package/dist/store/portable-bundle-import.js.map +1 -1
  212. package/dist/store/portable-bundle-relocate.d.ts +43 -0
  213. package/dist/store/portable-bundle-relocate.d.ts.map +1 -1
  214. package/dist/store/portable-bundle-relocate.js +79 -5
  215. package/dist/store/portable-bundle-relocate.js.map +1 -1
  216. package/dist/store/portable-bundle-scan.d.ts +20 -0
  217. package/dist/store/portable-bundle-scan.d.ts.map +1 -1
  218. package/dist/store/portable-bundle-scan.js +38 -3
  219. package/dist/store/portable-bundle-scan.js.map +1 -1
  220. package/dist/store/portable-bundle.d.ts +33 -0
  221. package/dist/store/portable-bundle.d.ts.map +1 -1
  222. package/dist/store/portable-bundle.js +34 -7
  223. package/dist/store/portable-bundle.js.map +1 -1
  224. package/dist/store/row-identity-registry.d.ts +137 -7
  225. package/dist/store/row-identity-registry.d.ts.map +1 -1
  226. package/dist/store/row-identity-registry.js +364 -9
  227. package/dist/store/row-identity-registry.js.map +1 -1
  228. package/dist/store/row-identity.d.ts.map +1 -1
  229. package/dist/store/row-identity.js +9 -10
  230. package/dist/store/row-identity.js.map +1 -1
  231. package/dist/store/sqlite-data-accessor.d.ts.map +1 -1
  232. package/dist/store/sqlite-data-accessor.js +10 -0
  233. package/dist/store/sqlite-data-accessor.js.map +1 -1
  234. package/dist/store/sqlite.d.ts +31 -0
  235. package/dist/store/sqlite.d.ts.map +1 -1
  236. package/dist/store/sqlite.js +5 -1
  237. package/dist/store/sqlite.js.map +1 -1
  238. package/dist/store/sync/capture.d.ts +203 -0
  239. package/dist/store/sync/capture.d.ts.map +1 -0
  240. package/dist/store/sync/capture.js +562 -0
  241. package/dist/store/sync/capture.js.map +1 -0
  242. package/dist/store/sync/clock-store.d.ts.map +1 -1
  243. package/dist/store/sync/clock-store.js +2 -0
  244. package/dist/store/sync/clock-store.js.map +1 -1
  245. package/dist/store/sync/fk-orphans.d.ts +133 -0
  246. package/dist/store/sync/fk-orphans.d.ts.map +1 -0
  247. package/dist/store/sync/fk-orphans.js +265 -0
  248. package/dist/store/sync/fk-orphans.js.map +1 -0
  249. package/dist/store/sync/flags.d.ts +7 -0
  250. package/dist/store/sync/flags.d.ts.map +1 -1
  251. package/dist/store/sync/flags.js +16 -0
  252. package/dist/store/sync/flags.js.map +1 -1
  253. package/dist/store/sync/hlc.d.ts.map +1 -1
  254. package/dist/store/sync/hlc.js +4 -0
  255. package/dist/store/sync/hlc.js.map +1 -1
  256. package/dist/store/sync/identity-fill.d.ts +45 -0
  257. package/dist/store/sync/identity-fill.d.ts.map +1 -0
  258. package/dist/store/sync/identity-fill.js +85 -0
  259. package/dist/store/sync/identity-fill.js.map +1 -0
  260. package/dist/store/sync/machinery.d.ts +27 -0
  261. package/dist/store/sync/machinery.d.ts.map +1 -0
  262. package/dist/store/sync/machinery.js +44 -0
  263. package/dist/store/sync/machinery.js.map +1 -0
  264. package/dist/store/sync/netting.d.ts +120 -0
  265. package/dist/store/sync/netting.d.ts.map +1 -0
  266. package/dist/store/sync/netting.js +336 -0
  267. package/dist/store/sync/netting.js.map +1 -0
  268. package/dist/store/sync/replica.d.ts +59 -3
  269. package/dist/store/sync/replica.d.ts.map +1 -1
  270. package/dist/store/sync/replica.js +84 -3
  271. package/dist/store/sync/replica.js.map +1 -1
  272. package/dist/store/sync/schema.d.ts +18 -3
  273. package/dist/store/sync/schema.d.ts.map +1 -1
  274. package/dist/store/sync/schema.js +27 -3
  275. package/dist/store/sync/schema.js.map +1 -1
  276. package/dist/store/sync/seal-backlog.d.ts +21 -0
  277. package/dist/store/sync/seal-backlog.d.ts.map +1 -0
  278. package/dist/store/sync/seal-backlog.js +24 -0
  279. package/dist/store/sync/seal-backlog.js.map +1 -0
  280. package/dist/store/sync/sealer-values.d.ts +34 -0
  281. package/dist/store/sync/sealer-values.d.ts.map +1 -0
  282. package/dist/store/sync/sealer-values.js +53 -0
  283. package/dist/store/sync/sealer-values.js.map +1 -0
  284. package/dist/store/sync/sealer.d.ts +145 -0
  285. package/dist/store/sync/sealer.d.ts.map +1 -0
  286. package/dist/store/sync/sealer.js +906 -0
  287. package/dist/store/sync/sealer.js.map +1 -0
  288. package/dist/store/sync/structural.d.ts +63 -0
  289. package/dist/store/sync/structural.d.ts.map +1 -0
  290. package/dist/store/sync/structural.js +180 -0
  291. package/dist/store/sync/structural.js.map +1 -0
  292. package/dist/store/sync/timestamps.d.ts +92 -0
  293. package/dist/store/sync/timestamps.d.ts.map +1 -0
  294. package/dist/store/sync/timestamps.js +228 -0
  295. package/dist/store/sync/timestamps.js.map +1 -0
  296. package/dist/store/sync/tombstones.d.ts +75 -0
  297. package/dist/store/sync/tombstones.d.ts.map +1 -0
  298. package/dist/store/sync/tombstones.js +103 -0
  299. package/dist/store/sync/tombstones.js.map +1 -0
  300. package/dist/store/sync/trigger-classes.d.ts +221 -0
  301. package/dist/store/sync/trigger-classes.d.ts.map +1 -0
  302. package/dist/store/sync/trigger-classes.js +441 -0
  303. package/dist/store/sync/trigger-classes.js.map +1 -0
  304. package/dist/store/sync/trigger-suspend-at-path.d.ts +23 -0
  305. package/dist/store/sync/trigger-suspend-at-path.d.ts.map +1 -0
  306. package/dist/store/sync/trigger-suspend-at-path.js +44 -0
  307. package/dist/store/sync/trigger-suspend-at-path.js.map +1 -0
  308. package/dist/store/sync/writer-version.d.ts +43 -0
  309. package/dist/store/sync/writer-version.d.ts.map +1 -0
  310. package/dist/store/sync/writer-version.js +90 -0
  311. package/dist/store/sync/writer-version.js.map +1 -0
  312. package/dist/store/table-classification.d.ts.map +1 -1
  313. package/dist/store/table-classification.js +102 -0
  314. package/dist/store/table-classification.js.map +1 -1
  315. package/dist/store/trigger-suspend-schema.d.ts +44 -0
  316. package/dist/store/trigger-suspend-schema.d.ts.map +1 -0
  317. package/dist/store/trigger-suspend-schema.js +25 -0
  318. package/dist/store/trigger-suspend-schema.js.map +1 -0
  319. package/dist/store/vault-manifest.d.ts +365 -0
  320. package/dist/store/vault-manifest.d.ts.map +1 -0
  321. package/dist/store/vault-manifest.js +812 -0
  322. package/dist/store/vault-manifest.js.map +1 -0
  323. package/dist/store/writer-lease.d.ts +31 -0
  324. package/dist/store/writer-lease.d.ts.map +1 -1
  325. package/dist/store/writer-lease.js +65 -2
  326. package/dist/store/writer-lease.js.map +1 -1
  327. package/dist/system/health.d.ts.map +1 -1
  328. package/dist/system/health.js +21 -0
  329. package/dist/system/health.js.map +1 -1
  330. package/dist/system/project-health.d.ts.map +1 -1
  331. package/dist/system/project-health.js +3 -1
  332. package/dist/system/project-health.js.map +1 -1
  333. package/dist/tasks/affected-packages.d.ts +58 -0
  334. package/dist/tasks/affected-packages.d.ts.map +1 -1
  335. package/dist/tasks/affected-packages.js +75 -6
  336. package/dist/tasks/affected-packages.js.map +1 -1
  337. package/dist/tasks/affected-scope.d.ts +150 -23
  338. package/dist/tasks/affected-scope.d.ts.map +1 -1
  339. package/dist/tasks/affected-scope.js +320 -32
  340. package/dist/tasks/affected-scope.js.map +1 -1
  341. package/dist/tasks/change-set.d.ts +96 -0
  342. package/dist/tasks/change-set.d.ts.map +1 -1
  343. package/dist/tasks/change-set.js +169 -4
  344. package/dist/tasks/change-set.js.map +1 -1
  345. package/dist/tasks/complete-ci.d.ts +115 -0
  346. package/dist/tasks/complete-ci.d.ts.map +1 -0
  347. package/dist/tasks/complete-ci.js +171 -0
  348. package/dist/tasks/complete-ci.js.map +1 -0
  349. package/dist/tasks/complete.d.ts.map +1 -1
  350. package/dist/tasks/complete.js +50 -17
  351. package/dist/tasks/complete.js.map +1 -1
  352. package/dist/tasks/compute-task-view.d.ts.map +1 -1
  353. package/dist/tasks/compute-task-view.js +7 -0
  354. package/dist/tasks/compute-task-view.js.map +1 -1
  355. package/dist/tasks/done-plan.d.ts.map +1 -1
  356. package/dist/tasks/done-plan.js +51 -30
  357. package/dist/tasks/done-plan.js.map +1 -1
  358. package/dist/tasks/done-record.d.ts +6 -0
  359. package/dist/tasks/done-record.d.ts.map +1 -1
  360. package/dist/tasks/done-record.js +9 -3
  361. package/dist/tasks/done-record.js.map +1 -1
  362. package/dist/tasks/evidence.d.ts +3 -2
  363. package/dist/tasks/evidence.d.ts.map +1 -1
  364. package/dist/tasks/evidence.js +143 -12
  365. package/dist/tasks/evidence.js.map +1 -1
  366. package/dist/tasks/gate-notes.d.ts +22 -0
  367. package/dist/tasks/gate-notes.d.ts.map +1 -0
  368. package/dist/tasks/gate-notes.js +33 -0
  369. package/dist/tasks/gate-notes.js.map +1 -0
  370. package/dist/tasks/index.d.ts +2 -1
  371. package/dist/tasks/index.d.ts.map +1 -1
  372. package/dist/tasks/index.js +2 -1
  373. package/dist/tasks/index.js.map +1 -1
  374. package/dist/tasks/test-run-binding.d.ts +117 -0
  375. package/dist/tasks/test-run-binding.d.ts.map +1 -0
  376. package/dist/tasks/test-run-binding.js +365 -0
  377. package/dist/tasks/test-run-binding.js.map +1 -0
  378. package/dist/tasks/tool-cache-env.d.ts +123 -0
  379. package/dist/tasks/tool-cache-env.d.ts.map +1 -0
  380. package/dist/tasks/tool-cache-env.js +287 -0
  381. package/dist/tasks/tool-cache-env.js.map +1 -0
  382. package/dist/tasks/tool-cache-failed-first.d.ts +155 -0
  383. package/dist/tasks/tool-cache-failed-first.d.ts.map +1 -0
  384. package/dist/tasks/tool-cache-failed-first.js +285 -0
  385. package/dist/tasks/tool-cache-failed-first.js.map +1 -0
  386. package/dist/tasks/tool-cache.d.ts +375 -55
  387. package/dist/tasks/tool-cache.d.ts.map +1 -1
  388. package/dist/tasks/tool-cache.js +912 -303
  389. package/dist/tasks/tool-cache.js.map +1 -1
  390. package/dist/tasks/tool-resolver.d.ts +4 -3
  391. package/dist/tasks/tool-resolver.d.ts.map +1 -1
  392. package/dist/tasks/tool-resolver.js +15 -4
  393. package/dist/tasks/tool-resolver.js.map +1 -1
  394. package/dist/tasks/tool-semaphore.d.ts +67 -7
  395. package/dist/tasks/tool-semaphore.d.ts.map +1 -1
  396. package/dist/tasks/tool-semaphore.js +134 -56
  397. package/dist/tasks/tool-semaphore.js.map +1 -1
  398. package/dist/upgrade.d.ts.map +1 -1
  399. package/dist/upgrade.js +4 -0
  400. package/dist/upgrade.js.map +1 -1
  401. package/dist/validation/engine-ops.d.ts +6 -0
  402. package/dist/validation/engine-ops.d.ts.map +1 -1
  403. package/dist/validation/engine-ops.js +8 -0
  404. package/dist/validation/engine-ops.js.map +1 -1
  405. package/migrations/drizzle-cleo-project/20260930170000_t12819-trigger-suspend-clause/migration.sql +367 -0
  406. package/migrations/sync-journal/20260930120000_t12343-capture/migration.sql +47 -0
  407. package/migrations/sync-journal/20261001170000_t12984-sealer/migration.sql +101 -0
  408. package/package.json +13 -13
  409. package/templates/CLEO-INJECTION.md +5 -5
  410. package/templates/CLEO-REFERENCE.md +8 -4
@@ -0,0 +1,906 @@
1
+ /**
2
+ * The sealer, S3a + S3b (journal spec §2.5 phase B, §2.4, §1.6, §2.6, §4.3;
3
+ * T12984, T12985).
4
+ *
5
+ * `sealPending` turns live `_sync_capture` rows into sealed transactions:
6
+ *
7
+ * 1. **Group (§2.4).** A validated frame (its `_sync_frame` row exists) is
8
+ * one transaction. Every capture with no validated frame is a singleton
9
+ * transaction flagged `unframed`, provenance `foreign` (ruling (c)): the
10
+ * sealer never claims atomicity it did not observe. A batch ends on a
11
+ * group boundary. Apply and rebase frames wait for S5's intent subtraction.
12
+ * 2. **Draft ops (§2.6).** Each capture becomes one draft. Values are decoded
13
+ * from the capture's `enc()` text to typed wire values; references become
14
+ * uids (resolved from the local key when the capture saw none); secret
15
+ * columns and the local columns a stored ref uid is derived from (`ac_id`)
16
+ * are removed. Natural rows carry `k`, their key with references as uids.
17
+ * An unreadable capture is quarantined (`_sync_quarantine`, its table
18
+ * suspect) and never stalls the outbox (T13036).
19
+ * 3. **Net (§2.4, {@link netTransaction}).** Per (table, uid) inside the
20
+ * transaction. Across transactions, the dead incarnation of a row that
21
+ * never got a uid (its captures up to its delete) is dropped whole
22
+ * (T13036). A minted row with no uid or `birth_fp` keeps its group
23
+ * pending, and nothing after it seals first (§2.9).
24
+ * 4. **HLC.** `tick(at_ms)` per op in order, at its last capture's time; the
25
+ * transaction's HLC is its maximum.
26
+ * 5. **Write.** `_sync_txn`, `_sync_op`; `_sync_row_meta` upserted per op
27
+ * (version, origin, actor, per-field `fhlc`, tombstone on D, key on
28
+ * natural rows) and MOVED on K (hlc, fhlc, version and chash kept);
29
+ * `chash` recomputed from the live row once no live capture of that row
30
+ * remains; `_sync_ledger` per table; the `sealer.local_seq` counter.
31
+ * 6. **Consume.** Sealed, dropped and quarantined captures are deleted, and
32
+ * frames no live capture references.
33
+ *
34
+ * S3c: timestamp columns are canonical on the wire and in `chash`
35
+ * ({@link canonicalStoreTimestamp}; local rows are never rewritten here), and
36
+ * a delete in an append-only table leaves no per-row tombstone (§1.7 R5-5).
37
+ * The step-0 fill and the repair diff of suspect tables are S3d. `sync.seal`
38
+ * stays unreleased until those land: the sealer refuses a persisted flag too.
39
+ *
40
+ * Phase B is synchronous: one `BEGIN IMMEDIATE` … `COMMIT` with no await, so
41
+ * a caller on the accessor's transaction queue serializes it with every
42
+ * writer on the handle.
43
+ *
44
+ * @module store/sync/sealer
45
+ * @task T12984
46
+ * @epic T12323
47
+ */
48
+ import { createHash } from 'node:crypto';
49
+ import { naturalRowUid } from '../row-identity.js';
50
+ import { BIRTH_FP_COLUMN, rowIdentitySpec, UID_COLUMN } from '../row-identity-registry.js';
51
+ import { captureTableDef, chunkedObject, enc, SECRET_MARKER, } from './capture.js';
52
+ import { tickClock, withImmediateTransaction } from './clock-store.js';
53
+ import { isSyncFlagOn, UNRELEASED_FLAGS } from './flags.js';
54
+ import { netTransaction } from './netting.js';
55
+ import { activeReplica } from './replica.js';
56
+ import { hasTable } from './schema.js';
57
+ import { canonicalJson, decodeEnc } from './sealer-values.js';
58
+ import { markSuspect } from './structural.js';
59
+ import { canonicalStoreTimestamp, timestampColumns } from './timestamps.js';
60
+ export { sealBacklog } from './seal-backlog.js';
61
+ export { canonicalJson, decodeEnc } from './sealer-values.js';
62
+ const emptyReport = (refused) => ({
63
+ txns: 0,
64
+ ops: 0,
65
+ captures: 0,
66
+ unframed: 0,
67
+ pending: [],
68
+ dropped: 0,
69
+ quarantined: [],
70
+ refused,
71
+ });
72
+ /** Ledger transaction kinds a frame kind maps to (§2.6). */
73
+ const TXN_KINDS = new Set(['write', 'remint', 'rekey', 'repair', 'exodus', 'import']);
74
+ const q = (id) => `"${id.replaceAll('"', '""')}"`;
75
+ /** The two identity columns an op carries as `u` / `bfp` instead of in its images. */
76
+ const OP_IDENTITY = new Set([UID_COLUMN, BIRTH_FP_COLUMN]);
77
+ /** A capture the sealer cannot read (a table left the sync set, a malformed image). */
78
+ class SealInputError extends Error {
79
+ }
80
+ class TableContext {
81
+ db;
82
+ scope;
83
+ defs = new Map();
84
+ stmts = new Map();
85
+ sources = new Map();
86
+ stamps = new Map();
87
+ constructor(db, scope) {
88
+ this.db = db;
89
+ this.scope = scope;
90
+ }
91
+ /** A statement prepared once per sealing pass (T13032). */
92
+ stmt(sql) {
93
+ let st = this.stmts.get(sql);
94
+ if (!st) {
95
+ st = this.db.prepare(sql);
96
+ this.stmts.set(sql, st);
97
+ }
98
+ return st;
99
+ }
100
+ /**
101
+ * The local columns a stored ref uid is derived from (`ac_id` for
102
+ * `ac_uid`): another replica's local ids, so they never travel or hash;
103
+ * the stored uid carries the reference (T13037).
104
+ */
105
+ refSources(table) {
106
+ let out = this.sources.get(table);
107
+ if (!out) {
108
+ const spec = rowIdentitySpec(this.scope, table);
109
+ out = new Set((spec?.storedRefUids ?? []).map((r) => r.from));
110
+ this.sources.set(table, out);
111
+ }
112
+ return out;
113
+ }
114
+ /** The table's key columns: a D-then-I U never carries them (§2.4). */
115
+ keyColumns(table) {
116
+ return rowIdentitySpec(this.scope, table)?.key ?? [];
117
+ }
118
+ /** The birth_fp row meta recorded for a uid (survives a delete or a re-key). */
119
+ metaBirthFp(table, uid) {
120
+ const row = this.stmt('SELECT bfp AS f FROM _sync_row_meta WHERE tbl = ? AND uid = ?').get(table, uid);
121
+ return row?.f ?? undefined;
122
+ }
123
+ /** The live row's uid by its local key (the capture's `rk`). */
124
+ uidByKey(table, rk) {
125
+ const def = this.def(table);
126
+ if (!def.identity.includes(UID_COLUMN))
127
+ return null;
128
+ const parts = JSON.parse(rk).map((p) => decodeEnc(p));
129
+ if (parts.some((v) => v !== null && typeof v === 'object'))
130
+ return null;
131
+ const where = def.key.map((k) => `${q(k)} = ?`).join(' AND ');
132
+ const row = this.stmt(`SELECT ${q(UID_COLUMN)} AS u FROM ${q(table)} WHERE ${where}`).get(...parts);
133
+ return row?.u ?? null;
134
+ }
135
+ /** A non-symmetric natural row's uid from its key (refs as uids), or null. */
136
+ naturalUid(table, key) {
137
+ const spec = rowIdentitySpec(this.scope, table);
138
+ if (!spec || spec.kind === 'minted' || spec.symmetric)
139
+ return null;
140
+ const parts = spec.key.map((c) => key[c]);
141
+ if (parts.some((v) => v === null || v === undefined || typeof v === 'object'))
142
+ return null;
143
+ return naturalRowUid(this.scope, table, parts);
144
+ }
145
+ /** The live row's birth_fp, so U ops of minted rows carry `bfp` (H5). */
146
+ liveBirthFp(table, uid) {
147
+ const row = this.stmt(`SELECT ${q(BIRTH_FP_COLUMN)} AS f FROM ${q(table)} WHERE ${q(UID_COLUMN)} = ?`).get(uid);
148
+ return row?.f ?? undefined;
149
+ }
150
+ def(table) {
151
+ let d = this.defs.get(table);
152
+ if (d === undefined) {
153
+ d = captureTableDef(this.db, this.scope, table) ?? null;
154
+ this.defs.set(table, d);
155
+ }
156
+ // §2.10: every op's table is in the sync set. A capture of any other table
157
+ // holds its group (reported), never aborts the batch (T13029).
158
+ if (d === null)
159
+ throw new SealInputError(`capture for ${table}, which is not in the sync set`);
160
+ return d;
161
+ }
162
+ minted(table) {
163
+ return rowIdentitySpec(this.scope, table)?.kind === 'minted';
164
+ }
165
+ /** The table's captured timestamp columns (§1.8). */
166
+ timestamps(table) {
167
+ let t = this.stamps.get(table);
168
+ if (!t) {
169
+ t = timestampColumns(this.scope, table);
170
+ this.stamps.set(table, t);
171
+ }
172
+ return t;
173
+ }
174
+ /** The uid of `table`'s row whose first key column is `key`. */
175
+ uidOf(table, keyColumn, key) {
176
+ if (key === null || typeof key === 'object')
177
+ return null;
178
+ const row = this.stmt(`SELECT ${q(UID_COLUMN)} AS u FROM ${q(table)} WHERE ${q(keyColumn)} = ?`).get(key);
179
+ return row?.u ?? null;
180
+ }
181
+ /**
182
+ * The first live delete of (table, rk) after `seq`, if any (T13041). The
183
+ * live row under that local key is then a later incarnation, so it must
184
+ * not lend its uid to an earlier capture.
185
+ */
186
+ laterDelete(table, rk, seq) {
187
+ return this.stmt("SELECT uid FROM _sync_capture WHERE state = 'live' AND tbl = ? AND rk = ? AND op = 'D' AND seq > ? ORDER BY seq LIMIT 1").get(table, rk, seq);
188
+ }
189
+ }
190
+ /**
191
+ * A timestamp column's wire value: canonical when the canonicalizer accepts
192
+ * it, else the raw text (`timestamp_ambiguous`, §1.8).
193
+ */
194
+ function wireTimestamp(stamps, col, v) {
195
+ if (typeof v !== 'string' || !stamps.has(col))
196
+ return v;
197
+ return canonicalStoreTimestamp(v) ?? v;
198
+ }
199
+ /**
200
+ * A decoded column value: references become uids, secrets disappear,
201
+ * timestamps are canonical. Decoded by the value's shape (T13029): a
202
+ * `[local key, uid]` pair is a reference however the column is declared now,
203
+ * a string is an `enc()` value.
204
+ */
205
+ function columnValue(ctx, def, col, raw) {
206
+ if (def.secret.has(col))
207
+ return undefined;
208
+ if (Array.isArray(raw)) {
209
+ const [localKey, uid] = raw;
210
+ if (typeof uid === 'string')
211
+ return uid;
212
+ const local = typeof localKey === 'string' ? decodeEnc(localKey) : null;
213
+ if (local === null)
214
+ return null;
215
+ const ref = def.refs.get(col);
216
+ return ref ? ctx.uidOf(ref.table, ref.key, local) : local;
217
+ }
218
+ if (typeof raw !== 'string')
219
+ throw new SealInputError(`${def.table}.${col}: unexpected image value`);
220
+ if (raw === SECRET_MARKER)
221
+ return undefined;
222
+ let v;
223
+ try {
224
+ v = decodeEnc(raw);
225
+ }
226
+ catch (err) {
227
+ throw new SealInputError(`${def.table}.${col}: ${err.message}`);
228
+ }
229
+ return wireTimestamp(ctx.timestamps(def.table), col, v);
230
+ }
231
+ function imageValues(ctx, def, img, skipIdentity) {
232
+ const out = {};
233
+ for (const [col, raw] of Object.entries(img)) {
234
+ // Only uid and birth_fp move to `u` / `bfp`; stored ref uids (ac_uid,
235
+ // ac_text_hash) are row content and stay in the image (T13030).
236
+ if (skipIdentity && OP_IDENTITY.has(col))
237
+ continue;
238
+ if (ctx.refSources(def.table).has(col))
239
+ continue;
240
+ const v = columnValue(ctx, def, col, raw);
241
+ if (v !== undefined)
242
+ out[col] = v;
243
+ }
244
+ return out;
245
+ }
246
+ /** Natural rows: the key, with references as uids, from the capture's `rk`. */
247
+ function naturalKey(ctx, def, rk) {
248
+ const parts = JSON.parse(rk);
249
+ const out = {};
250
+ def.key.forEach((col, i) => {
251
+ const local = decodeEnc(parts[i]);
252
+ const ref = def.refs.get(col);
253
+ out[col] = ref ? ctx.uidOf(ref.table, ref.key, local) : local;
254
+ });
255
+ return out;
256
+ }
257
+ function str(v) {
258
+ return typeof v === 'string' ? v : undefined;
259
+ }
260
+ const rowKey = (t, u) => `${t}\u0000${u}`;
261
+ /**
262
+ * The birth_fp every capture of the batch records: I and D images, and both
263
+ * sides of a K. A later op on a row that was since deleted or re-keyed then
264
+ * still carries `bfp` (T13030). Unreadable captures are skipped here; their
265
+ * group reports them.
266
+ */
267
+ function batchBirths(batch) {
268
+ const out = new Map();
269
+ for (const c of batch) {
270
+ try {
271
+ const img = JSON.parse(c.img);
272
+ if (c.op === 'K') {
273
+ const u = img[UID_COLUMN];
274
+ const f = img[BIRTH_FP_COLUMN];
275
+ if (f) {
276
+ // A K that changes only birth_fp keeps its uid (the capture's).
277
+ const [ou, nu] = u
278
+ ? [str(decodeEnc(u[0])), str(decodeEnc(u[1]))]
279
+ : [c.uid ?? undefined, c.uid ?? undefined];
280
+ const [of, nf] = [str(decodeEnc(f[0])), str(decodeEnc(f[1]))];
281
+ if (ou && of && ou !== nu)
282
+ out.set(rowKey(c.tbl, ou), of);
283
+ if (nu && nf)
284
+ out.set(rowKey(c.tbl, nu), nf);
285
+ }
286
+ continue;
287
+ }
288
+ const uid = c.uid ??
289
+ (typeof img[UID_COLUMN] === 'string'
290
+ ? str(decodeEnc(img[UID_COLUMN]))
291
+ : undefined);
292
+ const bfp = typeof img[BIRTH_FP_COLUMN] === 'string'
293
+ ? str(decodeEnc(img[BIRTH_FP_COLUMN]))
294
+ : undefined;
295
+ if (uid && bfp)
296
+ out.set(rowKey(c.tbl, uid), bfp);
297
+ }
298
+ catch {
299
+ // reported by the capture's group
300
+ }
301
+ }
302
+ return out;
303
+ }
304
+ /**
305
+ * A minted row's birth_fp when its own image lacks it (T13029, T13030): the
306
+ * batch first, then row meta (kept across a delete or re-key), then the live
307
+ * row.
308
+ */
309
+ function resolveBirthFp(ctx, births, table, uid) {
310
+ if (uid === null)
311
+ return undefined;
312
+ return (births.get(rowKey(table, uid)) ?? ctx.metaBirthFp(table, uid) ?? ctx.liveBirthFp(table, uid));
313
+ }
314
+ /**
315
+ * Build one draft op from a capture (S3b: netting runs on drafts). The uid
316
+ * may stay NULL here; the netted op is checked afterwards, so a clear-and-
317
+ * refill pair (K x → NULL, K NULL → y) can net to one K first (N8).
318
+ */
319
+ function buildDraft(ctx, c, births) {
320
+ const def = ctx.def(c.tbl);
321
+ const img = JSON.parse(c.img);
322
+ const minted = ctx.minted(c.tbl);
323
+ const natural = !minted ? { k: naturalKey(ctx, def, c.rk) } : {};
324
+ const base = { t: c.tbl, rk: c.rk, seq: c.seq };
325
+ if (c.op === 'K') {
326
+ const pair = (col) => {
327
+ const p = img[col];
328
+ return p ? [str(decodeEnc(p[0])), str(decodeEnc(p[1]))] : [undefined, undefined];
329
+ };
330
+ const [, nu] = pair(UID_COLUMN);
331
+ const [obfp, bfp] = pair(BIRTH_FP_COLUMN);
332
+ return {
333
+ ...base,
334
+ o: 'K',
335
+ u: c.uid,
336
+ nu: nu ?? null,
337
+ ...(bfp ? { bfp } : {}),
338
+ ...(obfp ? { obfp } : {}),
339
+ ...natural,
340
+ };
341
+ }
342
+ let uid = c.uid;
343
+ if (uid === null && def.identity.includes(UID_COLUMN)) {
344
+ const raw = img[UID_COLUMN];
345
+ if (typeof raw === 'string')
346
+ uid = str(decodeEnc(raw)) ?? null;
347
+ }
348
+ // Resolve a missing uid from the live row by its local key (§2.5 step 3),
349
+ // unless a later capture deletes that local row: the live row is then a
350
+ // later incarnation, and this one is resolved by the netting or dropped as
351
+ // dead (T13041).
352
+ if (uid === null && !ctx.laterDelete(c.tbl, c.rk, c.seq))
353
+ uid = ctx.uidByKey(c.tbl, c.rk);
354
+ // A natural row's uid is a function of its key with references as uids
355
+ // (T12341 §5.3), so a capture taken before the fill still seals. Symmetric
356
+ // edges need the fill's twin rule and wait for it (the step-0 fill, S3d).
357
+ if (uid === null && !minted && natural.k)
358
+ uid = ctx.naturalUid(c.tbl, natural.k);
359
+ switch (c.op) {
360
+ case 'I': {
361
+ // The uid may have come from the live row (the capture predates the
362
+ // fill): take birth_fp the same way, so the I never waits forever (T13029).
363
+ const bfp = str(columnValue(ctx, def, BIRTH_FP_COLUMN, img[BIRTH_FP_COLUMN] ?? 'NULL')) ??
364
+ (minted ? resolveBirthFp(ctx, births, c.tbl, uid) : undefined);
365
+ return {
366
+ ...base,
367
+ o: 'I',
368
+ u: uid,
369
+ ...(bfp ? { bfp } : {}),
370
+ ...natural,
371
+ a: imageValues(ctx, def, img, true),
372
+ };
373
+ }
374
+ case 'U': {
375
+ const a = {};
376
+ const b = {};
377
+ for (const [col, pair] of Object.entries(img)) {
378
+ if (ctx.refSources(def.table).has(col))
379
+ continue;
380
+ const [before, after] = pair;
381
+ const nv = columnValue(ctx, def, col, after);
382
+ const ov = columnValue(ctx, def, col, before);
383
+ if (nv !== undefined)
384
+ a[col] = nv;
385
+ if (ov !== undefined)
386
+ b[col] = ov;
387
+ }
388
+ const bfp = minted ? resolveBirthFp(ctx, births, c.tbl, uid) : undefined;
389
+ return { ...base, o: 'U', u: uid, ...(bfp ? { bfp } : {}), ...natural, a, b };
390
+ }
391
+ case 'D': {
392
+ const bfp = str(columnValue(ctx, def, BIRTH_FP_COLUMN, img[BIRTH_FP_COLUMN] ?? 'NULL')) ??
393
+ (minted ? resolveBirthFp(ctx, births, c.tbl, uid) : undefined);
394
+ return {
395
+ ...base,
396
+ o: 'D',
397
+ u: uid,
398
+ ...(bfp ? { bfp } : {}),
399
+ ...natural,
400
+ b: imageValues(ctx, def, img, true),
401
+ };
402
+ }
403
+ }
404
+ }
405
+ /** Why a netted op cannot be sealed yet, or null. */
406
+ function unsealable(ctx, op) {
407
+ if (op.u === null)
408
+ return `${op.t} seq ${op.seq}: row has no uid`;
409
+ if (op.o === 'K' && (op.nu ?? null) === null)
410
+ return `${op.t} seq ${op.seq}: re-key to a NULL uid`;
411
+ if (op.o === 'I' &&
412
+ ctx.minted(op.t) &&
413
+ ctx.def(op.t).identity.includes(BIRTH_FP_COLUMN) &&
414
+ op.bfp === undefined) {
415
+ return `${op.t} seq ${op.seq}: minted row has no birth_fp`;
416
+ }
417
+ return null;
418
+ }
419
+ /**
420
+ * sha256 of a row's canonical WIRE image (§2.7, M6; T13031): the values an I
421
+ * op of the row would carry, so every replica hashes identical bytes. Secret
422
+ * columns, uid and birth_fp, and a minted table's local key (a display id or
423
+ * an autoincrement id, which differ per replica) are left out; references are
424
+ * their uids; NULL columns are omitted, as in an I image; and timestamp
425
+ * columns hash their canonical form (§1.8), so a replica holding legacy text
426
+ * hashes like one that received the canonical value.
427
+ */
428
+ export function rowChash(db, scope, def, uid) {
429
+ return chashOf(new TableContext(db, scope), def, uid);
430
+ }
431
+ function chashOf(ctx, def, uid) {
432
+ const spec = rowIdentitySpec(ctx.scope, def.table);
433
+ const localKey = new Set(spec?.kind === 'minted' ? spec.key : []);
434
+ const sources = ctx.refSources(def.table);
435
+ const cols = def.columns.filter((c) => !def.secret.has(c) && !OP_IDENTITY.has(c) && !localKey.has(c) && !sources.has(c));
436
+ if (cols.length === 0)
437
+ return null;
438
+ const stamps = ctx.timestamps(def.table);
439
+ const row = ctx
440
+ .stmt(`SELECT ${chunkedObject(cols.map((c) => [c, enc(q(c))]))} AS img FROM ${q(def.table)} WHERE ${q(UID_COLUMN)} = ?`)
441
+ .get(uid);
442
+ if (!row)
443
+ return null;
444
+ const wire = {};
445
+ for (const [col, raw] of Object.entries(JSON.parse(row.img))) {
446
+ const local = decodeEnc(raw);
447
+ const ref = def.refs.get(col);
448
+ const v = ref && local !== null
449
+ ? ctx.uidOf(ref.table, ref.key, local)
450
+ : wireTimestamp(stamps, col, local);
451
+ if (v !== null)
452
+ wire[col] = v;
453
+ }
454
+ return createHash('sha256').update(canonicalJson(wire)).digest('hex');
455
+ }
456
+ function nextFhlc(prev, def, changed, h) {
457
+ if (!prev)
458
+ return null;
459
+ const old = prev.fhlc ? JSON.parse(prev.fhlc) : {};
460
+ const out = {};
461
+ for (const col of def.columns) {
462
+ if (def.identity.includes(col) || changed.includes(col))
463
+ continue;
464
+ const at = old[col] ?? prev.hlc;
465
+ if (at < h)
466
+ out[col] = at;
467
+ }
468
+ return Object.keys(out).length > 0 ? canonicalJson(out) : null;
469
+ }
470
+ // ---------------------------------------------------------------------------
471
+ // sealPending
472
+ // ---------------------------------------------------------------------------
473
+ /**
474
+ * Why the sealer refuses to run, or `null` when it may. A persisted
475
+ * `sync.seal` is refused while the flag is unreleased (T13037), whatever
476
+ * wrote it.
477
+ */
478
+ export function sealPreconditions(db, env, allowUnreleased = false) {
479
+ if (!hasTable(db, '_sync_capture') || !hasTable(db, '_sync_txn')) {
480
+ return 'sync schema not installed';
481
+ }
482
+ if (!isSyncFlagOn(db, 'sync.seal', env))
483
+ return 'sync.seal is off';
484
+ if (UNRELEASED_FLAGS.has('sync.seal') && !allowUnreleased) {
485
+ return 'sync.seal is unreleased until S3b–S3d land (T13032)';
486
+ }
487
+ return null;
488
+ }
489
+ /** Where the sealer's transaction counter is persisted (T13033). */
490
+ export const SEAL_COUNTER_KEY = 'sealer.local_seq';
491
+ /**
492
+ * Seal up to `budget` live captures (ending on a group boundary) into
493
+ * transactions, in one synchronous `BEGIN IMMEDIATE` transaction.
494
+ *
495
+ * Groups seal strictly in capture order (§2.9): the first group that cannot
496
+ * seal yet (a row without uid or birth_fp, an unreadable capture) stops the
497
+ * batch, and is reported in `pending` until it can. Nothing after it gets an
498
+ * HLC first.
499
+ *
500
+ * @returns what was sealed, what stays pending, or why nothing ran.
501
+ */
502
+ export function sealPending(db, opts) {
503
+ const refused = sealPreconditions(db, opts.env ?? process.env, opts.allowUnreleased === true);
504
+ if (refused)
505
+ return emptyReport(refused);
506
+ const replica = opts.replica ?? activeReplica(db, opts.scope)?.replicaId;
507
+ if (!replica)
508
+ return emptyReport('no bound replica');
509
+ const now = opts.now ?? Date.now;
510
+ const budget = Math.max(1, opts.budget ?? 5000);
511
+ return withImmediateTransaction(db, () => sealInTransaction(db, { ...opts, replica }, budget, now));
512
+ }
513
+ const CAPTURE_COLS = 'seq, tbl, op, rk, uid, img, at_ms, frame';
514
+ /** The uid pair a K capture's image records, decoded; null when unreadable. */
515
+ function kUids(img) {
516
+ try {
517
+ const pair = JSON.parse(img)[UID_COLUMN];
518
+ if (!Array.isArray(pair) || typeof pair[0] !== 'string' || typeof pair[1] !== 'string') {
519
+ return null;
520
+ }
521
+ return [str(decodeEnc(pair[0])) ?? null, str(decodeEnc(pair[1])) ?? null];
522
+ }
523
+ catch {
524
+ return null;
525
+ }
526
+ }
527
+ /**
528
+ * A clear K(x → NULL) and what follows it on the same local row (T13041).
529
+ * Until the row's next delete or its refill K(NULL → y), the row is still x:
530
+ * those captures are pointed at x (in `_sync_capture`, so a later pass sees
531
+ * it too) and the clear is consumed. A cleared-then-deleted row then seals as
532
+ * D(x), and a clear and refill in different transactions as K(x → y) (N8).
533
+ * With neither yet, the clear waits.
534
+ *
535
+ * @returns x and the seqs pointed at it, or null when `c` is not a clear or
536
+ * must wait.
537
+ */
538
+ function resolveClear(ctx, c) {
539
+ if (c.op !== 'K' || c.uid === null)
540
+ return null;
541
+ const pair = kUids(c.img);
542
+ if (pair === null || pair[1] !== null)
543
+ return null;
544
+ const end = ctx
545
+ .stmt("SELECT seq, op, img FROM _sync_capture WHERE state = 'live' AND tbl = ? AND rk = ? AND seq > ? AND op IN ('D', 'K') ORDER BY seq LIMIT 1")
546
+ .get(c.tbl, c.rk, c.seq);
547
+ if (!end)
548
+ return null;
549
+ // Only a refill (a K from NULL) continues the cleared row.
550
+ if (end.op === 'K' && kUids(end.img)?.[0] !== null)
551
+ return null;
552
+ const seqs = ctx
553
+ .stmt("SELECT seq FROM _sync_capture WHERE state = 'live' AND tbl = ? AND rk = ? AND seq > ? AND seq <= ? AND uid IS NULL ORDER BY seq")
554
+ .all(c.tbl, c.rk, c.seq, end.seq).map((r) => r.seq);
555
+ ctx
556
+ .stmt("UPDATE _sync_capture SET uid = ? WHERE state = 'live' AND tbl = ? AND rk = ? AND seq > ? AND seq <= ? AND uid IS NULL")
557
+ .run(c.uid, c.tbl, c.rk, c.seq, end.seq);
558
+ return { uid: c.uid, seqs };
559
+ }
560
+ /**
561
+ * The seqs of the dead incarnation that starts at draft `d` (T13036), or
562
+ * null. `d` has no uid; its row's live captures from `d` on run to a delete
563
+ * of the same local row; none of them names a uid row meta knows as live;
564
+ * and no earlier capture of this incarnation (back to the previous delete of
565
+ * the local row) names a uid some sealed op carried (T13041). Otherwise some
566
+ * replica knew the row, and it waits.
567
+ */
568
+ function deadIncarnation(ctx, facts, d) {
569
+ const earlier = ctx
570
+ .stmt("SELECT op, uid, img FROM _sync_capture WHERE state = 'live' AND tbl = ? AND rk = ? AND seq < ? ORDER BY seq DESC")
571
+ .all(d.t, d.rk, d.seq);
572
+ for (const r of earlier) {
573
+ if (r.op === 'D')
574
+ break;
575
+ const named = r.op === 'K' ? [r.uid, ...(kUids(r.img) ?? [])] : [r.uid];
576
+ if (named.some((u) => u !== null && u !== undefined && facts.known(d.t, u)))
577
+ return null;
578
+ }
579
+ const rows = ctx
580
+ .stmt("SELECT seq, op, uid, img FROM _sync_capture WHERE state = 'live' AND tbl = ? AND rk = ? AND seq >= ? ORDER BY seq")
581
+ .all(d.t, d.rk, d.seq);
582
+ const out = [];
583
+ for (const r of rows) {
584
+ out.push(r.seq);
585
+ const uids = [r.uid];
586
+ if (r.op === 'K') {
587
+ try {
588
+ const pair = JSON.parse(r.img)[UID_COLUMN];
589
+ if (Array.isArray(pair) && typeof pair[1] === 'string')
590
+ uids.push(str(decodeEnc(pair[1])) ?? null);
591
+ }
592
+ catch {
593
+ return null;
594
+ }
595
+ }
596
+ if (uids.some((u) => u !== null && u !== undefined && facts.live(d.t, u)))
597
+ return null;
598
+ if (r.op === 'D')
599
+ return out;
600
+ }
601
+ return null;
602
+ }
603
+ /**
604
+ * The net row-count effect of a table's live captures, for the ledger's
605
+ * first sight (§4.3; T13037), mirroring how they will seal: per local row,
606
+ * `(exists after the last capture) − (existed before the first)`. A first I
607
+ * counts as a new row unless its uid is one row meta knows live: that is a
608
+ * foreign REPLACE, which seals as a U and adds nothing.
609
+ */
610
+ function waitingEffect(db, tbl, facts) {
611
+ const rows = db
612
+ .prepare("SELECT rk, op, uid FROM _sync_capture WHERE tbl = ? AND state = 'live' ORDER BY seq")
613
+ .all(tbl);
614
+ const span = new Map();
615
+ for (const r of rows) {
616
+ const s = span.get(r.rk);
617
+ if (s)
618
+ s.last = r;
619
+ else
620
+ span.set(r.rk, { first: r, last: r });
621
+ }
622
+ let n = 0;
623
+ for (const { first, last } of span.values()) {
624
+ const before = first.op === 'I' && !(first.uid !== null && facts.live(tbl, first.uid)) ? 0 : 1;
625
+ const after = last.op === 'D' ? 0 : 1;
626
+ n += after - before;
627
+ }
628
+ return n;
629
+ }
630
+ function sealInTransaction(db, opts, budget, now) {
631
+ const ctx = new TableContext(db, opts.scope);
632
+ const started = performance.now();
633
+ const maxMs = opts.maxMs ?? 200;
634
+ const replica = opts.replica;
635
+ // 1. Read a batch. A frame cut by the budget is completed only when it is
636
+ // the batch's first group (it must seal whole); otherwise it is left for
637
+ // the next batch, so the extension stays bounded (T13032).
638
+ let batch = db
639
+ .prepare(`SELECT ${CAPTURE_COLS} FROM _sync_capture WHERE state = 'live' ORDER BY seq LIMIT ?`)
640
+ .all(budget);
641
+ if (batch.length === 0)
642
+ return emptyReport(null);
643
+ const lastFrame = batch[batch.length - 1]?.frame ?? null;
644
+ if (lastFrame !== null && batch.length === budget) {
645
+ if (batch[0]?.frame === lastFrame) {
646
+ const maxSeq = batch[batch.length - 1]?.seq ?? 0;
647
+ batch.push(...db
648
+ .prepare(`SELECT ${CAPTURE_COLS} FROM _sync_capture WHERE state = 'live' AND frame = ? AND seq > ? ORDER BY seq`)
649
+ .all(lastFrame, maxSeq));
650
+ }
651
+ else {
652
+ batch = batch.filter((c) => c.frame !== lastFrame);
653
+ }
654
+ }
655
+ const births = batchBirths(batch);
656
+ // 2. Group: a validated frame is one transaction; anything else a singleton.
657
+ const frames = new Map();
658
+ for (const f of db.prepare('SELECT frame, kind, actor FROM _sync_frame').all()) {
659
+ frames.set(f.frame, { kind: f.kind, actor: f.actor });
660
+ }
661
+ const groups = [];
662
+ const byFrame = new Map();
663
+ for (const c of batch) {
664
+ const f = c.frame !== null ? frames.get(c.frame) : undefined;
665
+ if (c.frame !== null && f) {
666
+ let g = byFrame.get(c.frame);
667
+ if (!g) {
668
+ g = { frame: c.frame, kind: f.kind, actor: f.actor, captures: [] };
669
+ byFrame.set(c.frame, g);
670
+ groups.push(g);
671
+ }
672
+ g.captures.push(c);
673
+ }
674
+ else {
675
+ groups.push({ frame: null, kind: 'write', actor: null, captures: [c] });
676
+ }
677
+ }
678
+ // 3–5. Seal each group, in order.
679
+ const meta = {
680
+ get: db.prepare('SELECT hlc, fhlc, version, deleted, key_json, chash, bfp FROM _sync_row_meta WHERE tbl = ? AND uid = ?'),
681
+ upsert: db.prepare(`INSERT INTO _sync_row_meta (tbl, uid, hlc, fhlc, origin, actor, version, deleted, key_json, chash, bfp)
682
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
683
+ ON CONFLICT (tbl, uid) DO UPDATE SET hlc = excluded.hlc, fhlc = excluded.fhlc,
684
+ origin = excluded.origin, actor = excluded.actor, version = excluded.version,
685
+ deleted = excluded.deleted, key_json = coalesce(excluded.key_json, key_json),
686
+ chash = excluded.chash, bfp = coalesce(excluded.bfp, bfp)`),
687
+ remove: db.prepare('DELETE FROM _sync_row_meta WHERE tbl = ? AND uid = ?'),
688
+ // A re-key moves the row's meta and keeps hlc, fhlc, version and chash
689
+ // (§2.5 step 5, T13031); only the key and birth_fp follow the new uid.
690
+ move: db.prepare(`UPDATE _sync_row_meta SET uid = ?, key_json = coalesce(?, key_json), bfp = coalesce(?, bfp)
691
+ WHERE tbl = ? AND uid = ?`),
692
+ flags: db.prepare('SELECT sent, deleted FROM _sync_row_meta WHERE tbl = ? AND uid = ?'),
693
+ };
694
+ const insTxn = db.prepare(`INSERT INTO _sync_txn (txn, local_seq, replica, hlc, scope, via, kind, actor, frame, unframed, partial, op_count, sealed_at_ms)
695
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`);
696
+ const insOp = db.prepare('INSERT INTO _sync_op (txn, idx, tbl, uid, o, hlc, body) VALUES (?, ?, ?, ?, ?, ?, ?)');
697
+ // The counter only rises: a txn id is never reused after old rows are
698
+ // collected (T13033).
699
+ const stored = db.prepare('SELECT value FROM _sync_meta WHERE key = ?').get(SEAL_COUNTER_KEY);
700
+ const maxRow = db.prepare('SELECT coalesce(max(local_seq), 0) AS n FROM _sync_txn').get().n;
701
+ let localSeq = Math.max(Number(stored?.value ?? 0) || 0, maxRow);
702
+ const firstSeq = localSeq;
703
+ let txns = 0;
704
+ let ops = 0;
705
+ let unframed = 0;
706
+ const consumed = new Set();
707
+ const pending = [];
708
+ const touched = new Map();
709
+ const ledgerDelta = new Map();
710
+ const metaFacts = {
711
+ sent: (t, u) => meta.flags.get(t, u)?.sent === 1,
712
+ live: (t, u) => meta.flags.get(t, u)?.deleted === 0,
713
+ known: (t, u) => meta.flags.get(t, u) !== undefined,
714
+ };
715
+ const quarantine = db.prepare(`INSERT INTO _sync_quarantine
716
+ (seq, tbl, op, rk, uid, img, at_ms, frame, reason, quarantined_at_ms)
717
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ON CONFLICT (seq) DO NOTHING`);
718
+ const dead = new Set();
719
+ // Captures pointed at a cleared row's uid in this pass (T13041).
720
+ const pointedAt = new Map();
721
+ let dropped = 0;
722
+ const quarantined = [];
723
+ for (const g of groups) {
724
+ // Bound the time this transaction holds the write lock (T13032).
725
+ if (txns > 0 && performance.now() - started > maxMs)
726
+ break;
727
+ // T13041: a clear whose row is deleted or refilled later is consumed, and
728
+ // what follows it on the row is pointed at the cleared uid.
729
+ for (const c of g.captures) {
730
+ if (dead.has(c.seq))
731
+ continue;
732
+ const cleared = resolveClear(ctx, c);
733
+ if (cleared === null)
734
+ continue;
735
+ for (const seq of cleared.seqs)
736
+ pointedAt.set(seq, cleared.uid);
737
+ dead.add(c.seq);
738
+ consumed.add(c.seq);
739
+ }
740
+ const captures = g.captures
741
+ .filter((c) => !dead.has(c.seq))
742
+ .map((c) => (pointedAt.has(c.seq) ? { ...c, uid: pointedAt.get(c.seq) ?? null } : c));
743
+ if (captures.length === 0)
744
+ continue;
745
+ const head = captures[0]?.seq ?? 0;
746
+ if (g.frame !== null && (g.kind === 'apply' || g.kind === 'rebase')) {
747
+ // §3.3: an apply or rebase frame is sealed only after its apply intents
748
+ // are subtracted, which is S5. Until then it waits (T13037).
749
+ pending.push({ firstSeq: head, reason: `${g.kind} frames wait for S5 intent subtraction` });
750
+ break;
751
+ }
752
+ const capOf = new Map(captures.map((c) => [c.seq, c]));
753
+ let drafts = [];
754
+ let partial = false;
755
+ for (const c of captures) {
756
+ try {
757
+ drafts.push(buildDraft(ctx, c, births));
758
+ }
759
+ catch (err) {
760
+ if (!(err instanceof SealInputError))
761
+ throw err;
762
+ // T13036: an unreadable capture never stalls the outbox. It moves to
763
+ // _sync_quarantine, which marks its table suspect for S3d's repair
764
+ // diff, and the rest of the group seals.
765
+ quarantine.run(c.seq, c.tbl, c.op, c.rk, c.uid, c.img, c.at_ms, c.frame, err.message, now());
766
+ markSuspect(db, opts.scope, [c.tbl]);
767
+ quarantined.push({ seq: c.seq, tbl: c.tbl, reason: err.message });
768
+ consumed.add(c.seq);
769
+ partial = true;
770
+ }
771
+ }
772
+ // T13036: a row that never had a uid and is gone again is a dead
773
+ // incarnation no replica ever knew (§2.4: an I and a later D of a uid
774
+ // that never left the device drop both). Its captures, up to its delete,
775
+ // are dropped wherever they sit, so it cannot hold the outbox forever.
776
+ for (const d of drafts) {
777
+ if (d.u !== null || d.o === 'K' || dead.has(d.seq))
778
+ continue;
779
+ for (const seq of deadIncarnation(ctx, metaFacts, d) ?? []) {
780
+ if (dead.has(seq))
781
+ continue;
782
+ dead.add(seq);
783
+ consumed.add(seq);
784
+ dropped += 1;
785
+ }
786
+ }
787
+ drafts = drafts.filter((d) => !dead.has(d.seq));
788
+ const netted = netTransaction(drafts, metaFacts, { keyColumns: (t) => ctx.keyColumns(t) });
789
+ const wait = netted.ops.map((op) => unsealable(ctx, op)).find((r) => r !== null) ?? null;
790
+ if (wait !== null) {
791
+ // §2.9: stop here. Nothing after a waiting group seals before it.
792
+ pending.push({ firstSeq: head, reason: wait });
793
+ break;
794
+ }
795
+ // Dropped re-keys (no sealed op carried the old uid): the meta follows the row.
796
+ for (const r of netted.renames) {
797
+ meta.remove.run(r.t, r.to);
798
+ meta.move.run(r.to, null, null, r.t, r.from);
799
+ }
800
+ for (const c of captures)
801
+ consumed.add(c.seq);
802
+ if (netted.ops.length === 0)
803
+ continue; // everything netted away
804
+ localSeq += 1;
805
+ const txn = `${replica}:${localSeq}`;
806
+ // An op's time and local key are its LAST capture's (T13037).
807
+ const at = (op) => capOf.get(op.last) ?? capOf.get(op.seq);
808
+ const sealedOps = netted.ops.map((op) => {
809
+ const { seq, last, ...rest } = op;
810
+ return {
811
+ ...rest,
812
+ seq,
813
+ last,
814
+ h: tickClock(db, replica, at(op)?.at_ms ?? now()),
815
+ };
816
+ });
817
+ const txnHlc = sealedOps.reduce((m, o) => (o.h > m ? o.h : m), sealedOps[0]?.h ?? '');
818
+ const kind = g.frame !== null && TXN_KINDS.has(g.kind) ? g.kind : 'write';
819
+ insTxn.run(txn, localSeq, replica, txnHlc, opts.scope, g.frame === null ? 'foreign' : 'accessor', kind, g.actor, g.frame, g.frame === null ? 1 : 0, partial ? 1 : 0, sealedOps.length, now());
820
+ sealedOps.forEach(({ seq, last, ...op }, i) => {
821
+ const rk = at({ seq, last })?.rk ?? '';
822
+ insOp.run(txn, i, op.t, op.u, op.o, op.h, canonicalJson(op));
823
+ const def = ctx.def(op.t);
824
+ const prev = meta.get.get(op.t, op.u);
825
+ const keyJson = op.k ? canonicalJson(op.k) : null;
826
+ if (op.o === 'K' && op.nu !== undefined) {
827
+ // A K that keeps its uid changes only birth_fp: its meta stays put.
828
+ if (op.nu !== op.u)
829
+ meta.remove.run(op.t, op.nu);
830
+ if (prev) {
831
+ meta.move.run(op.nu, keyJson, op.bfp ?? null, op.t, op.u);
832
+ }
833
+ else {
834
+ meta.upsert.run(op.t, op.nu, op.h, null, replica, g.actor, 1, 0, keyJson, null, op.bfp ?? null);
835
+ }
836
+ touched.delete(rowKey(op.t, op.u));
837
+ touched.set(rowKey(op.t, op.nu), { tbl: op.t, uid: op.nu, rk });
838
+ return;
839
+ }
840
+ if (op.o === 'D' && def.appendOnly) {
841
+ // §1.7 R5-5: append-only rows get no per-row tombstone; deleted vs
842
+ // never seen is decided by the prune cutoff. The D op still travels.
843
+ meta.remove.run(op.t, op.u);
844
+ ledgerDelta.set(op.t, (ledgerDelta.get(op.t) ?? 0) - 1);
845
+ touched.delete(rowKey(op.t, op.u));
846
+ return;
847
+ }
848
+ const changed = op.o === 'U' ? Object.keys(op.a ?? {}) : [];
849
+ const fhlc = op.o === 'U' ? nextFhlc(prev, def, changed, op.h) : null;
850
+ meta.upsert.run(op.t, op.u, op.h, fhlc, replica, g.actor, (prev?.version ?? 0) + 1, op.o === 'D' ? 1 : 0, keyJson, op.o === 'D' ? (prev?.chash ?? null) : null, op.bfp ?? null);
851
+ if (op.o === 'I')
852
+ ledgerDelta.set(op.t, (ledgerDelta.get(op.t) ?? 0) + 1);
853
+ if (op.o === 'D')
854
+ ledgerDelta.set(op.t, (ledgerDelta.get(op.t) ?? 0) - 1);
855
+ if (op.o === 'D')
856
+ touched.delete(rowKey(op.t, op.u));
857
+ else
858
+ touched.set(rowKey(op.t, op.u), { tbl: op.t, uid: op.u, rk });
859
+ });
860
+ txns += 1;
861
+ ops += sealedOps.length;
862
+ if (g.frame === null)
863
+ unframed += 1;
864
+ }
865
+ if (localSeq !== firstSeq) {
866
+ db.prepare('INSERT INTO _sync_meta (key, value, updated_at) VALUES (?, ?, ?) ' +
867
+ 'ON CONFLICT(key) DO UPDATE SET value = excluded.value, updated_at = excluded.updated_at').run(SEAL_COUNTER_KEY, String(localSeq), new Date(now()).toISOString());
868
+ }
869
+ // Consume the sealed captures (and frames nothing references any more).
870
+ const del = db.prepare('DELETE FROM _sync_capture WHERE seq = ?');
871
+ for (const seq of consumed)
872
+ del.run(seq);
873
+ db.exec("DELETE FROM _sync_frame WHERE NOT EXISTS (SELECT 1 FROM _sync_capture c WHERE c.frame = _sync_frame.frame AND c.state = 'live')");
874
+ // chash from the live row, once no live capture of that row remains.
875
+ const stillLive = db.prepare("SELECT 1 FROM _sync_capture WHERE tbl = ? AND rk = ? AND state = 'live' LIMIT 1");
876
+ const setChash = db.prepare('UPDATE _sync_row_meta SET chash = ? WHERE tbl = ? AND uid = ?');
877
+ for (const { tbl, uid, rk } of touched.values()) {
878
+ if (stillLive.get(tbl, rk))
879
+ continue;
880
+ setChash.run(chashOf(ctx, ctx.def(tbl), uid), tbl, uid);
881
+ }
882
+ // Ledger: sealed live rows per table. First sight: count(*) minus the net
883
+ // effect of captures still waiting to be sealed.
884
+ const ledgerGet = db.prepare('SELECT live FROM _sync_ledger WHERE tbl = ?');
885
+ const ledgerSet = db.prepare('INSERT INTO _sync_ledger (tbl, live) VALUES (?, ?) ON CONFLICT (tbl) DO UPDATE SET live = excluded.live');
886
+ for (const [tbl, delta] of ledgerDelta) {
887
+ const row = ledgerGet.get(tbl);
888
+ if (row) {
889
+ ledgerSet.run(tbl, row.live + delta);
890
+ continue;
891
+ }
892
+ const count = db.prepare(`SELECT count(*) AS n FROM ${q(tbl)}`).get().n;
893
+ ledgerSet.run(tbl, count - waitingEffect(db, tbl, metaFacts));
894
+ }
895
+ return {
896
+ txns,
897
+ ops,
898
+ captures: consumed.size,
899
+ unframed,
900
+ pending,
901
+ dropped,
902
+ quarantined,
903
+ refused: null,
904
+ };
905
+ }
906
+ //# sourceMappingURL=sealer.js.map