@north-light/cli 0.3.530 → 0.3.531

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 (495) hide show
  1. package/dist/clients/attach/session/connection.js +1 -1
  2. package/dist/clients/attach/session/reconnect.js +1 -1
  3. package/dist/clients/attach/viewer.js +3 -3
  4. package/dist/core/async-array.d.ts +7 -0
  5. package/dist/core/async-array.js +1 -0
  6. package/dist/core/audit.d.ts +1 -1
  7. package/dist/core/audit.js +2 -2
  8. package/dist/core/canvas/attention.d.ts +4 -4
  9. package/dist/core/canvas/attention.js +1 -1
  10. package/dist/core/canvas/boot.d.ts +4 -4
  11. package/dist/core/canvas/boot.js +1 -1
  12. package/dist/core/canvas/canvas.d.ts +59 -59
  13. package/dist/core/canvas/canvas.js +19 -19
  14. package/dist/core/canvas/context-strip.js +2 -2
  15. package/dist/core/canvas/crons.d.ts +27 -27
  16. package/dist/core/canvas/crons.js +11 -11
  17. package/dist/core/canvas/daemon-actions.d.ts +10 -10
  18. package/dist/core/canvas/daemon-actions.js +8 -8
  19. package/dist/core/canvas/daemon-owner.d.ts +3 -3
  20. package/dist/core/canvas/daemon-owner.js +2 -2
  21. package/dist/core/canvas/db.d.ts +19 -30
  22. package/dist/core/canvas/db.js +3 -2
  23. package/dist/core/canvas/deliveries.d.ts +16 -16
  24. package/dist/core/canvas/deliveries.js +24 -24
  25. package/dist/core/canvas/executions.d.ts +8 -8
  26. package/dist/core/canvas/executions.js +1 -1
  27. package/dist/core/canvas/focuses.d.ts +8 -8
  28. package/dist/core/canvas/focuses.js +1 -1
  29. package/dist/core/canvas/history.d.ts +3 -3
  30. package/dist/core/canvas/history.js +9 -9
  31. package/dist/core/canvas/install-id.d.ts +1 -1
  32. package/dist/core/canvas/install-id.js +1 -1
  33. package/dist/core/canvas/managed-worktree-sweep-candidates.d.ts +1 -1
  34. package/dist/core/canvas/managed-worktree-sweep-candidates.js +2 -2
  35. package/dist/core/canvas/memory-reads.d.ts +6 -6
  36. package/dist/core/canvas/memory-reads.js +1 -1
  37. package/dist/core/canvas/nav-model.d.ts +13 -13
  38. package/dist/core/canvas/nav-model.js +1 -1
  39. package/dist/core/canvas/node-agent-paths.d.ts +6 -6
  40. package/dist/core/canvas/node-agent-paths.js +1 -1
  41. package/dist/core/canvas/node-tokens.d.ts +7 -7
  42. package/dist/core/canvas/node-tokens.js +3 -3
  43. package/dist/core/canvas/outcome-actions.d.ts +5 -5
  44. package/dist/core/canvas/outcome-actions.js +3 -3
  45. package/dist/core/canvas/recovery.d.ts +26 -26
  46. package/dist/core/canvas/recovery.js +2 -2
  47. package/dist/core/canvas/render-source.d.ts +1 -1
  48. package/dist/core/canvas/render-source.js +1 -1
  49. package/dist/core/canvas/sessions.d.ts +10 -10
  50. package/dist/core/canvas/sessions.js +4 -4
  51. package/dist/core/canvas/source.js +1 -1
  52. package/dist/core/canvas/structured-requests.d.ts +15 -15
  53. package/dist/core/canvas/structured-requests.js +5 -5
  54. package/dist/core/canvas/tree.d.ts +9 -9
  55. package/dist/core/canvas/tree.js +5 -5
  56. package/dist/core/canvas/waits.d.ts +13 -13
  57. package/dist/core/canvas/waits.js +6 -6
  58. package/dist/core/canvas/worktrees.d.ts +15 -15
  59. package/dist/core/canvas/worktrees.js +1 -1
  60. package/dist/core/command-hooks/transport/exec-lifecycle.js +1 -1
  61. package/dist/core/conversation-store/file-store.d.ts +7 -7
  62. package/dist/core/conversation-store/file-store.js +9 -9
  63. package/dist/core/conversation-store/index.d.ts +16 -14
  64. package/dist/core/conversation-store/index.js +1 -1
  65. package/dist/core/conversation-store/listener.js +5 -5
  66. package/dist/core/conversation-store/patch.d.ts +3 -1
  67. package/dist/core/conversation-store/patch.js +1 -1
  68. package/dist/core/feed/feed.js +3 -3
  69. package/dist/core/feed/inbox.d.ts +2 -2
  70. package/dist/core/feed/inbox.js +1 -1
  71. package/dist/core/feed/messages.d.ts +11 -12
  72. package/dist/core/feed/messages.js +5 -5
  73. package/dist/core/feed/reports.d.ts +4 -4
  74. package/dist/core/feed/reports.js +2 -2
  75. package/dist/core/grants/cover.d.ts +1 -1
  76. package/dist/core/grants/cover.js +1 -1
  77. package/dist/core/grants/local.d.ts +1 -1
  78. package/dist/core/grants/local.js +1 -1
  79. package/dist/core/grants/mirror.d.ts +19 -19
  80. package/dist/core/grants/mirror.js +2 -2
  81. package/dist/core/grants/on-sync.d.ts +1 -1
  82. package/dist/core/grants/on-sync.js +1 -1
  83. package/dist/core/grants/remove.js +1 -1
  84. package/dist/core/grants/sync.js +1 -1
  85. package/dist/core/graph/access.d.ts +17 -17
  86. package/dist/core/graph/access.js +3 -3
  87. package/dist/core/graph/custom.d.ts +16 -16
  88. package/dist/core/graph/custom.js +9 -9
  89. package/dist/core/graph/deletion.d.ts +3 -7
  90. package/dist/core/graph/deletion.js +4 -4
  91. package/dist/core/graph/documents.d.ts +24 -27
  92. package/dist/core/graph/documents.js +7 -7
  93. package/dist/core/graph/edges.d.ts +13 -13
  94. package/dist/core/graph/edges.js +1 -1
  95. package/dist/core/graph/events.d.ts +7 -9
  96. package/dist/core/graph/events.js +8 -8
  97. package/dist/core/graph/exposures.d.ts +6 -6
  98. package/dist/core/graph/exposures.js +4 -4
  99. package/dist/core/graph/jobs.d.ts +6 -8
  100. package/dist/core/graph/jobs.js +2 -2
  101. package/dist/core/graph/kinds/action.js +1 -1
  102. package/dist/core/graph/kinds/custom.js +2 -2
  103. package/dist/core/graph/kinds/document.d.ts +1 -0
  104. package/dist/core/graph/kinds/document.js +4 -4
  105. package/dist/core/graph/kinds/dto.d.ts +2 -2
  106. package/dist/core/graph/kinds/dto.js +1 -1
  107. package/dist/core/graph/kinds/job.js +2 -2
  108. package/dist/core/graph/kinds/kind.d.ts +6 -8
  109. package/dist/core/graph/kinds/kind.js +1 -1
  110. package/dist/core/graph/kinds/node.js +5 -5
  111. package/dist/core/graph/kinds/owner.js +2 -2
  112. package/dist/core/graph/kinds/registry.d.ts +6 -9
  113. package/dist/core/graph/kinds/registry.js +1 -1
  114. package/dist/core/graph/names.d.ts +6 -6
  115. package/dist/core/graph/names.js +3 -3
  116. package/dist/core/graph/object-waits.d.ts +4 -7
  117. package/dist/core/graph/object-waits.js +1 -1
  118. package/dist/core/graph/objects.d.ts +14 -14
  119. package/dist/core/graph/objects.js +9 -9
  120. package/dist/core/graph/package-docs.d.ts +2 -7
  121. package/dist/core/graph/package-docs.js +5 -5
  122. package/dist/core/graph/package-kinds.d.ts +2 -5
  123. package/dist/core/graph/package-kinds.js +1 -1
  124. package/dist/core/graph/package-reconcile.d.ts +2 -5
  125. package/dist/core/graph/package-reconcile.js +1 -1
  126. package/dist/core/graph/reader.d.ts +18 -18
  127. package/dist/core/graph/reader.js +3 -3
  128. package/dist/core/graph/receivers.d.ts +4 -4
  129. package/dist/core/graph/receivers.js +5 -5
  130. package/dist/core/graph/repo-sync/exchange.d.ts +3 -7
  131. package/dist/core/graph/repo-sync/exchange.js +2 -2
  132. package/dist/core/graph/repo-sync/repos.d.ts +7 -5
  133. package/dist/core/graph/repo-sync/repos.js +3 -3
  134. package/dist/core/graph/repo-sync/sync.d.ts +3 -6
  135. package/dist/core/graph/repo-sync/sync.js +2 -2
  136. package/dist/core/graph/rules.d.ts +5 -5
  137. package/dist/core/graph/rules.js +3 -3
  138. package/dist/core/graph/spaces/app.js +1 -1
  139. package/dist/core/graph/spaces/index.d.ts +4 -5
  140. package/dist/core/graph/spaces/index.js +1 -1
  141. package/dist/core/graph/spaces/own-memory.d.ts +4 -4
  142. package/dist/core/graph/spaces/own-memory.js +1 -1
  143. package/dist/core/graph/spaces/person.js +3 -3
  144. package/dist/core/graph/spaces/repo.d.ts +1 -1
  145. package/dist/core/graph/spaces/repo.js +1 -1
  146. package/dist/core/graph/watches.d.ts +15 -15
  147. package/dist/core/graph/watches.js +10 -10
  148. package/dist/core/human/feedback-companion.d.ts +2 -2
  149. package/dist/core/human/feedback-companion.js +1 -1
  150. package/dist/core/human/feedback.d.ts +3 -3
  151. package/dist/core/human/feedback.js +1 -1
  152. package/dist/core/human/requests.d.ts +34 -33
  153. package/dist/core/human/requests.js +20 -20
  154. package/dist/core/human/scan.d.ts +2 -2
  155. package/dist/core/human/scan.js +1 -1
  156. package/dist/core/human/tickets.d.ts +9 -9
  157. package/dist/core/human/tickets.js +1 -1
  158. package/dist/core/llm/app-rungs.d.ts +1 -1
  159. package/dist/core/llm/app-rungs.js +1 -1
  160. package/dist/core/llm/run.js +1 -1
  161. package/dist/core/peer/directory.d.ts +1 -1
  162. package/dist/core/peer/directory.js +1 -1
  163. package/dist/core/peer/envelope.d.ts +3 -3
  164. package/dist/core/peer/envelope.js +1 -1
  165. package/dist/core/peer/home.d.ts +7 -7
  166. package/dist/core/peer/home.js +2 -2
  167. package/dist/core/peer/ingest.d.ts +6 -6
  168. package/dist/core/peer/ingest.js +1 -1
  169. package/dist/core/peer/outbox-store.d.ts +14 -14
  170. package/dist/core/peer/outbox-store.js +5 -5
  171. package/dist/core/peer/receiver.d.ts +2 -2
  172. package/dist/core/peer/receiver.js +1 -1
  173. package/dist/core/peer/stubs.d.ts +10 -10
  174. package/dist/core/peer/stubs.js +1 -1
  175. package/dist/core/providers/approval.d.ts +2 -2
  176. package/dist/core/providers/approval.js +2 -2
  177. package/dist/core/providers/audit.d.ts +3 -3
  178. package/dist/core/providers/audit.js +2 -2
  179. package/dist/core/providers/bundles.js +2 -2
  180. package/dist/core/providers/call.d.ts +2 -2
  181. package/dist/core/providers/call.js +1 -1
  182. package/dist/core/providers/files.d.ts +1 -1
  183. package/dist/core/providers/files.js +1 -1
  184. package/dist/core/providers/mint.js +1 -1
  185. package/dist/core/providers/receipts.d.ts +1 -1
  186. package/dist/core/providers/receipts.js +2 -2
  187. package/dist/core/review/birth.js +1 -1
  188. package/dist/core/review/comments.d.ts +19 -19
  189. package/dist/core/review/comments.js +5 -5
  190. package/dist/core/review/companion.d.ts +1 -1
  191. package/dist/core/review/companion.js +1 -1
  192. package/dist/core/review/document.d.ts +3 -3
  193. package/dist/core/review/document.js +2 -2
  194. package/dist/core/review/fork.js +2 -2
  195. package/dist/core/review/realize.js +1 -1
  196. package/dist/core/review/remap.d.ts +2 -2
  197. package/dist/core/review/remap.js +4 -4
  198. package/dist/core/review/stage.d.ts +1 -1
  199. package/dist/core/review/stage.js +1 -1
  200. package/dist/core/review/store.d.ts +21 -21
  201. package/dist/core/review/store.js +1 -1
  202. package/dist/core/runs/activity.d.ts +1 -1
  203. package/dist/core/runs/activity.js +5 -5
  204. package/dist/core/runs/confinement.d.ts +7 -7
  205. package/dist/core/runs/confinement.js +2 -2
  206. package/dist/core/runs/events.d.ts +12 -12
  207. package/dist/core/runs/events.js +4 -4
  208. package/dist/core/runs/operations.d.ts +11 -11
  209. package/dist/core/runs/operations.js +5 -5
  210. package/dist/core/runs/questions.d.ts +10 -10
  211. package/dist/core/runs/questions.js +3 -3
  212. package/dist/core/runtime/auth-reload.js +1 -1
  213. package/dist/core/runtime/bearings.d.ts +5 -5
  214. package/dist/core/runtime/bearings.js +6 -6
  215. package/dist/core/runtime/broker-inventory.js +1 -1
  216. package/dist/core/runtime/broker-request.js +1 -1
  217. package/dist/core/runtime/broker.js +1 -1
  218. package/dist/core/runtime/close.d.ts +3 -3
  219. package/dist/core/runtime/close.js +1 -1
  220. package/dist/core/runtime/deliver-live.js +1 -1
  221. package/dist/core/runtime/fleet.d.ts +2 -2
  222. package/dist/core/runtime/host.d.ts +3 -3
  223. package/dist/core/runtime/host.js +3 -3
  224. package/dist/core/runtime/kickoff.d.ts +12 -12
  225. package/dist/core/runtime/kickoff.js +17 -17
  226. package/dist/core/runtime/launch-target.d.ts +1 -1
  227. package/dist/core/runtime/launch-target.js +1 -1
  228. package/dist/core/runtime/ledger.d.ts +3 -3
  229. package/dist/core/runtime/ledger.js +3 -3
  230. package/dist/core/runtime/lifecycle.d.ts +1 -1
  231. package/dist/core/runtime/lifecycle.js +2 -2
  232. package/dist/core/runtime/memory-admission.js +1 -1
  233. package/dist/core/runtime/model-swap.d.ts +2 -2
  234. package/dist/core/runtime/model-swap.js +1 -1
  235. package/dist/core/runtime/node-read.d.ts +1 -1
  236. package/dist/core/runtime/node-read.js +2 -2
  237. package/dist/core/runtime/nodes.d.ts +6 -6
  238. package/dist/core/runtime/nodes.js +1 -1
  239. package/dist/core/runtime/outcome-document.d.ts +1 -1
  240. package/dist/core/runtime/outcome-document.js +1 -1
  241. package/dist/core/runtime/persona.d.ts +3 -3
  242. package/dist/core/runtime/persona.js +2 -2
  243. package/dist/core/runtime/placement.d.ts +11 -11
  244. package/dist/core/runtime/placement.js +1 -1
  245. package/dist/core/runtime/promote.d.ts +3 -3
  246. package/dist/core/runtime/promote.js +1 -1
  247. package/dist/core/runtime/recycle.js +1 -1
  248. package/dist/core/runtime/reopen.d.ts +5 -5
  249. package/dist/core/runtime/reopen.js +1 -1
  250. package/dist/core/runtime/reset.d.ts +4 -4
  251. package/dist/core/runtime/reset.js +1 -1
  252. package/dist/core/runtime/revive-all.d.ts +2 -2
  253. package/dist/core/runtime/revive-all.js +1 -1
  254. package/dist/core/runtime/revive.d.ts +4 -4
  255. package/dist/core/runtime/revive.js +2 -2
  256. package/dist/core/runtime/roadmap.d.ts +6 -6
  257. package/dist/core/runtime/roadmap.js +5 -5
  258. package/dist/core/runtime/session-branch.d.ts +1 -1
  259. package/dist/core/runtime/session-branch.js +1 -1
  260. package/dist/core/runtime/session-list-cache.js +1 -1
  261. package/dist/core/runtime/situational-live.js +1 -1
  262. package/dist/core/runtime/spawn.d.ts +2 -2
  263. package/dist/core/runtime/spawn.js +2 -2
  264. package/dist/core/runtime/stop-guard.d.ts +2 -2
  265. package/dist/core/runtime/stop-guard.js +3 -3
  266. package/dist/core/runtime/warm-pool.d.ts +2 -2
  267. package/dist/core/runtime/warm-pool.js +1 -1
  268. package/dist/core/spaces/mounts.d.ts +2 -2
  269. package/dist/core/spaces/mounts.js +1 -1
  270. package/dist/core/spaces/permissions.d.ts +1 -1
  271. package/dist/core/spaces/permissions.js +1 -1
  272. package/dist/core/spaces/process.d.ts +1 -1
  273. package/dist/core/spaces/process.js +1 -1
  274. package/dist/core/spaces/space.js +1 -1
  275. package/dist/core/spaces/stop.d.ts +3 -3
  276. package/dist/core/spaces/stop.js +2 -2
  277. package/dist/core/spaces/users.d.ts +6 -6
  278. package/dist/core/spaces/users.js +1 -1
  279. package/dist/core/storage/attachments.d.ts +2 -2
  280. package/dist/core/storage/attachments.js +1 -1
  281. package/dist/core/storage/shares.d.ts +2 -2
  282. package/dist/core/storage/shares.js +1 -1
  283. package/dist/core/storage/tables.d.ts +21 -21
  284. package/dist/core/storage/tables.js +3 -3
  285. package/dist/core/substrate/delivery/corpus.d.ts +5 -8
  286. package/dist/core/substrate/delivery/corpus.js +3 -3
  287. package/dist/core/substrate/delivery/deliver.d.ts +10 -15
  288. package/dist/core/substrate/delivery/deliver.js +3 -3
  289. package/dist/core/substrate/delivery/plan.d.ts +2 -12
  290. package/dist/core/substrate/delivery/plan.js +3 -3
  291. package/dist/core/substrate/delivery/render-boot.d.ts +4 -4
  292. package/dist/core/substrate/delivery/render-boot.js +18 -18
  293. package/dist/core/substrate/delivery/render-event.d.ts +7 -14
  294. package/dist/core/substrate/delivery/render-event.js +4 -4
  295. package/dist/core/substrate/subject.d.ts +2 -2
  296. package/dist/core/substrate/subject.js +1 -1
  297. package/dist/core/usage/ledger.d.ts +6 -6
  298. package/dist/core/usage/ledger.js +4 -4
  299. package/dist/core/worktree-close.js +4 -4
  300. package/dist/core/worktree-mutation-async.js +7 -7
  301. package/dist/core/worktree-quarantine.js +1 -1
  302. package/dist/core/worktree-sweep.d.ts +1 -1
  303. package/dist/core/worktree-sweep.js +6 -6
  304. package/dist/core/worktree.d.ts +5 -5
  305. package/dist/core/worktree.js +13 -13
  306. package/dist/daemon/analytics/compute.d.ts +2 -2
  307. package/dist/daemon/analytics/compute.js +1 -1
  308. package/dist/daemon/api/app-listener.d.ts +4 -4
  309. package/dist/daemon/api/app-listener.js +13 -13
  310. package/dist/daemon/api/bridge.js +5 -5
  311. package/dist/daemon/api/document-listener.js +6 -6
  312. package/dist/daemon/api/handlers/analytics.js +1 -1
  313. package/dist/daemon/api/handlers/attach.js +1 -1
  314. package/dist/daemon/api/handlers/bash-jobs.js +1 -1
  315. package/dist/daemon/api/handlers/bash.js +1 -1
  316. package/dist/daemon/api/handlers/broker-ops.d.ts +1 -1
  317. package/dist/daemon/api/handlers/broker-ops.js +1 -1
  318. package/dist/daemon/api/handlers/broker-recovery.d.ts +1 -1
  319. package/dist/daemon/api/handlers/broker-recovery.js +1 -1
  320. package/dist/daemon/api/handlers/broker-signals.d.ts +2 -2
  321. package/dist/daemon/api/handlers/broker-signals.js +2 -2
  322. package/dist/daemon/api/handlers/canvas.d.ts +1 -1
  323. package/dist/daemon/api/handlers/canvas.js +4 -4
  324. package/dist/daemon/api/handlers/chat-inventory.js +1 -1
  325. package/dist/daemon/api/handlers/crons.js +1 -1
  326. package/dist/daemon/api/handlers/custom-objects.d.ts +4 -4
  327. package/dist/daemon/api/handlers/custom-objects.js +3 -3
  328. package/dist/daemon/api/handlers/delivery-retry.js +1 -1
  329. package/dist/daemon/api/handlers/delivery.js +1 -1
  330. package/dist/daemon/api/handlers/docs.d.ts +4 -4
  331. package/dist/daemon/api/handlers/docs.js +1 -1
  332. package/dist/daemon/api/handlers/feedback-comments.js +3 -3
  333. package/dist/daemon/api/handlers/files.js +1 -1
  334. package/dist/daemon/api/handlers/focus.js +1 -1
  335. package/dist/daemon/api/handlers/health.js +3 -3
  336. package/dist/daemon/api/handlers/hook-exec.js +1 -1
  337. package/dist/daemon/api/handlers/human-requests.js +1 -1
  338. package/dist/daemon/api/handlers/inbox-page.d.ts +1 -1
  339. package/dist/daemon/api/handlers/inbox-page.js +1 -1
  340. package/dist/daemon/api/handlers/inbox.d.ts +1 -1
  341. package/dist/daemon/api/handlers/inbox.js +1 -1
  342. package/dist/daemon/api/handlers/llm.d.ts +1 -1
  343. package/dist/daemon/api/handlers/llm.js +3 -3
  344. package/dist/daemon/api/handlers/memory-reads.js +1 -1
  345. package/dist/daemon/api/handlers/memory.d.ts +5 -5
  346. package/dist/daemon/api/handlers/memory.js +5 -5
  347. package/dist/daemon/api/handlers/messages.js +2 -2
  348. package/dist/daemon/api/handlers/node-events.d.ts +2 -2
  349. package/dist/daemon/api/handlers/node-events.js +3 -3
  350. package/dist/daemon/api/handlers/node-outcomes.js +1 -1
  351. package/dist/daemon/api/handlers/node-records.js +2 -2
  352. package/dist/daemon/api/handlers/nodes.d.ts +1 -1
  353. package/dist/daemon/api/handlers/nodes.js +1 -1
  354. package/dist/daemon/api/handlers/objects.js +3 -3
  355. package/dist/daemon/api/handlers/package-docs.js +1 -1
  356. package/dist/daemon/api/handlers/plugin-app-token.d.ts +1 -1
  357. package/dist/daemon/api/handlers/plugin-app-token.js +1 -1
  358. package/dist/daemon/api/handlers/profiles.d.ts +3 -3
  359. package/dist/daemon/api/handlers/profiles.js +1 -1
  360. package/dist/daemon/api/handlers/providers.d.ts +1 -1
  361. package/dist/daemon/api/handlers/providers.js +1 -1
  362. package/dist/daemon/api/handlers/questions.js +1 -1
  363. package/dist/daemon/api/handlers/reports.d.ts +1 -1
  364. package/dist/daemon/api/handlers/reports.js +5 -5
  365. package/dist/daemon/api/handlers/review-comments.js +1 -1
  366. package/dist/daemon/api/handlers/reviews.js +1 -1
  367. package/dist/daemon/api/handlers/runs.js +1 -1
  368. package/dist/daemon/api/handlers/structured-requests.js +1 -1
  369. package/dist/daemon/api/handlers/subscriptions.js +1 -1
  370. package/dist/daemon/api/handlers/transfer.js +1 -1
  371. package/dist/daemon/api/map.d.ts +3 -3
  372. package/dist/daemon/api/map.js +1 -1
  373. package/dist/daemon/api/principal.d.ts +1 -1
  374. package/dist/daemon/api/principal.js +1 -1
  375. package/dist/daemon/api/reader.d.ts +5 -5
  376. package/dist/daemon/api/reader.js +1 -1
  377. package/dist/daemon/api/router.d.ts +5 -5
  378. package/dist/daemon/api/router.js +1 -1
  379. package/dist/daemon/api/server.js +1 -1
  380. package/dist/daemon/broker-signals/bus.d.ts +1 -1
  381. package/dist/daemon/broker-signals/bus.js +1 -1
  382. package/dist/daemon/companion-retire.js +1 -1
  383. package/dist/daemon/cron/armed-context.d.ts +2 -2
  384. package/dist/daemon/cron/armed-context.js +1 -1
  385. package/dist/daemon/cron/authority.d.ts +2 -2
  386. package/dist/daemon/cron/authority.js +1 -1
  387. package/dist/daemon/cron/disposition.js +1 -1
  388. package/dist/daemon/cron/ended.d.ts +1 -1
  389. package/dist/daemon/cron/ended.js +2 -2
  390. package/dist/daemon/cron/escalation.js +3 -3
  391. package/dist/daemon/cron/folders.d.ts +1 -1
  392. package/dist/daemon/cron/folders.js +1 -1
  393. package/dist/daemon/cron/held.d.ts +1 -1
  394. package/dist/daemon/cron/held.js +1 -1
  395. package/dist/daemon/cron/lease-recovery.d.ts +1 -1
  396. package/dist/daemon/cron/lease-recovery.js +1 -1
  397. package/dist/daemon/cron/passes.d.ts +2 -2
  398. package/dist/daemon/cron/passes.js +1 -1
  399. package/dist/daemon/cron/run-socket.d.ts +1 -1
  400. package/dist/daemon/cron/run-socket.js +1 -1
  401. package/dist/daemon/cron/settle.js +1 -1
  402. package/dist/daemon/cron/sinks.d.ts +1 -1
  403. package/dist/daemon/cron/sinks.js +2 -2
  404. package/dist/daemon/cron-run.d.ts +12 -3
  405. package/dist/daemon/cron-run.js +2 -2
  406. package/dist/daemon/crtrd.js +6 -6
  407. package/dist/daemon/delivery/run-delivery.js +1 -1
  408. package/dist/daemon/due-sources.d.ts +3 -3
  409. package/dist/daemon/due-sources.js +1 -1
  410. package/dist/daemon/due.d.ts +3 -3
  411. package/dist/daemon/due.js +7 -7
  412. package/dist/daemon/fleet.d.ts +2 -2
  413. package/dist/daemon/fleet.js +11 -11
  414. package/dist/daemon/human/finish.js +3 -3
  415. package/dist/daemon/human/settle.d.ts +1 -1
  416. package/dist/daemon/human/settle.js +1 -1
  417. package/dist/daemon/human/sweep.js +1 -1
  418. package/dist/daemon/joined-owner.d.ts +2 -2
  419. package/dist/daemon/joined-owner.js +1 -1
  420. package/dist/daemon/messaging/node-message.js +1 -1
  421. package/dist/daemon/park-activity.d.ts +2 -2
  422. package/dist/daemon/park-activity.js +1 -1
  423. package/dist/daemon/peer/authority.js +1 -1
  424. package/dist/daemon/peer/forward.d.ts +6 -6
  425. package/dist/daemon/peer/forward.js +1 -1
  426. package/dist/daemon/peer/handlers.js +1 -1
  427. package/dist/daemon/peer/ingress.d.ts +4 -4
  428. package/dist/daemon/peer/ingress.js +1 -1
  429. package/dist/daemon/peer/outbox.d.ts +2 -2
  430. package/dist/daemon/peer/outbox.js +1 -1
  431. package/dist/daemon/peer/relay-service.js +1 -1
  432. package/dist/daemon/plugin-objects/read-leaf.d.ts +2 -2
  433. package/dist/daemon/plugin-objects/read-leaf.js +2 -2
  434. package/dist/daemon/profile-delete.js +1 -1
  435. package/dist/daemon/readiness.d.ts +2 -2
  436. package/dist/daemon/readiness.js +1 -1
  437. package/dist/daemon/reconcilers/action-lane.d.ts +1 -1
  438. package/dist/daemon/reconcilers/action-lane.js +1 -1
  439. package/dist/daemon/reconcilers/bash-deadline.js +2 -2
  440. package/dist/daemon/reconcilers/broker-supervision.d.ts +1 -1
  441. package/dist/daemon/reconcilers/broker-supervision.js +4 -4
  442. package/dist/daemon/reconcilers/controller-death.d.ts +1 -1
  443. package/dist/daemon/reconcilers/controller-death.js +1 -1
  444. package/dist/daemon/reconcilers/cron-lane.d.ts +1 -1
  445. package/dist/daemon/reconcilers/cron-lane.js +1 -1
  446. package/dist/daemon/reconcilers/delivery-lane.d.ts +1 -1
  447. package/dist/daemon/reconcilers/delivery-lane.js +2 -2
  448. package/dist/daemon/reconcilers/fault-retry-backstop.d.ts +3 -3
  449. package/dist/daemon/reconcilers/fault-retry-backstop.js +1 -1
  450. package/dist/daemon/reconcilers/grove-instance-sweep.d.ts +2 -2
  451. package/dist/daemon/reconcilers/grove-instance-sweep.js +1 -1
  452. package/dist/daemon/reconcilers/live-obligation.d.ts +6 -6
  453. package/dist/daemon/reconcilers/live-obligation.js +1 -1
  454. package/dist/daemon/reconcilers/managed-worktree-sweep.js +1 -1
  455. package/dist/daemon/reconcilers/node-deadline.d.ts +1 -1
  456. package/dist/daemon/reconcilers/node-deadline.js +1 -1
  457. package/dist/daemon/reconcilers/node-lifecycle/freeze-lane.js +1 -1
  458. package/dist/daemon/reconcilers/node-lifecycle/respawn-policy.d.ts +3 -3
  459. package/dist/daemon/reconcilers/node-lifecycle/respawn-policy.js +1 -1
  460. package/dist/daemon/reconcilers/node-lifecycle/terminating.js +1 -1
  461. package/dist/daemon/reconcilers/node-lifecycle/tick.js +1 -1
  462. package/dist/daemon/reconcilers/node-lifecycle/wants-execution.d.ts +1 -1
  463. package/dist/daemon/reconcilers/node-lifecycle/wants-execution.js +1 -1
  464. package/dist/daemon/reconcilers/pending-review-submit.d.ts +1 -1
  465. package/dist/daemon/reconcilers/pending-review-submit.js +1 -1
  466. package/dist/daemon/reconcilers/storage-due-work.js +1 -1
  467. package/dist/daemon/reconcilers/storage-maintenance.d.ts +1 -1
  468. package/dist/daemon/reconcilers/storage-maintenance.js +2 -2
  469. package/dist/daemon/reconcilers/structured-request-lane.d.ts +1 -1
  470. package/dist/daemon/reconcilers/structured-request-lane.js +1 -1
  471. package/dist/daemon/review/comment-notify.js +2 -2
  472. package/dist/daemon/review/companion.d.ts +3 -3
  473. package/dist/daemon/review/companion.js +1 -1
  474. package/dist/daemon/review/finish.js +1 -1
  475. package/dist/daemon/review/sweep.js +1 -1
  476. package/dist/daemon/run-notices.d.ts +4 -4
  477. package/dist/daemon/run-notices.js +1 -1
  478. package/dist/daemon/runs/append-section.d.ts +2 -2
  479. package/dist/daemon/runs/append-section.js +2 -2
  480. package/dist/daemon/runs/observer.d.ts +2 -2
  481. package/dist/daemon/runs/observer.js +2 -2
  482. package/dist/daemon/structured-requests/boot.d.ts +1 -1
  483. package/dist/daemon/structured-requests/boot.js +1 -1
  484. package/dist/daemon/structured-requests/effects.js +1 -1
  485. package/dist/daemon/structured-requests/sidecar.d.ts +1 -1
  486. package/dist/daemon/structured-requests/sidecar.js +1 -1
  487. package/dist/migrations/004-canvas-documents/apply.d.ts +3 -3
  488. package/dist/migrations/004-canvas-documents/apply.js +1 -1
  489. package/dist/migrations/004-canvas-documents/index.d.ts +2 -2
  490. package/dist/migrations/004-canvas-documents/index.js +2 -2
  491. package/dist/migrations/activation.js +2 -2
  492. package/docs/public-api.md +11 -0
  493. package/package.json +3 -2
  494. package/packages/crouter-identity/package.json +1 -1
  495. package/runtime.lock.json +12 -12
@@ -1,6 +1,6 @@
1
- import type { DatabaseSync } from 'node:sqlite';
2
1
  import type { ObjectRow } from '../graph/types.js';
3
2
  import { type ClaimedRow, type PeerEventPayload } from './outbox-store.js';
3
+ import { type CanvasDb } from '../canvas/db.js';
4
4
  /** Most events one `peer.events` call carries. */
5
5
  export declare const MAX_EVENTS_PER_CALL = 100;
6
6
  export interface IngestResult {
@@ -25,11 +25,11 @@ export declare const ingestKey: (via: string, messageId: string) => string;
25
25
  * an app-made watch of a remote node's object is recorded here as the destination's own watch of the stub (start `act`, all events,
26
26
  * never changing a watch that exists), and a row whose message was already applied for another destination is published once more to
27
27
  * that destination alone. The delivery key `peer:<via>:<message_id>:<destination>` keeps each destination to one delivery. */
28
- export declare function ingestPeerEvents(db: DatabaseSync, via: string, events: readonly PeerEventPayload[]): IngestResult;
28
+ export declare function ingestPeerEvents(db: CanvasDb, via: string, events: readonly PeerEventPayload[]): Promise<IngestResult>;
29
29
  /** Whether `object` is a stub of `machine` (a sender may only describe what it homes). */
30
- export declare const isStubOf: (db: DatabaseSync, object: ObjectRow, machine: string) => boolean;
31
- export declare const claimFor: (db: DatabaseSync, via: string, limit: number) => ClaimedRow[];
32
- export declare const ackFor: (db: DatabaseSync, via: string, acks: ReadonlyArray<{
30
+ export declare const isStubOf: (db: CanvasDb, object: ObjectRow, machine: string) => Promise<boolean>;
31
+ export declare const claimFor: (db: CanvasDb, via: string, limit: number) => Promise<ClaimedRow[]>;
32
+ export declare const ackFor: (db: CanvasDb, via: string, acks: ReadonlyArray<{
33
33
  key: string;
34
34
  claim_token: string;
35
- }>) => string[];
35
+ }>) => Promise<string[]>;
@@ -1 +1 @@
1
- var k=Object.defineProperty;var r=(e,t)=>k(e,"name",{value:t,configurable:!0});import{prepared as d}from"../sqlite-statements.js";import{CrtrError as R}from"../errors.js";import{getById as O,getByRowid as S}from"../graph/objects.js";import{publish as L}from"../graph/events.js";import{markLinkWatch as h,recordWatch as w}from"../graph/watches.js";import{armObjectWaitForWatch as x}from"../graph/object-waits.js";import{ackRows as A,claimRows as T}from"./outbox-store.js";import{ensureStub as E,localOwnerActor as $,stubOf as f}from"./stubs.js";const P=100,G=r(e=>e==="unknown_event"||e==="unknown_kind","isCatalogLag"),m=r((e,t)=>`peer:${e}:${t}`,"ingestKey");function N(e,t){return d(e,"SELECT 1 FROM peer_ingested WHERE key = ?").get(t)!==void 0?!0:d(e,"SELECT 1 FROM deliveries WHERE idempotency_key >= ? AND idempotency_key < ? LIMIT 1").get(`${t}:`,`${t};`)!==void 0}r(N,"applied");const y=r((e,t,n)=>{d(e,"INSERT OR IGNORE INTO peer_ingested_destinations (key, ingested_at) VALUES (?, ?)").run(`${t}:${n}`,Date.now())},"markDestination");function C(e,t,n){return d(e,"SELECT 1 FROM peer_ingested_destinations WHERE key = ?").get(`${t}:${n}`)!==void 0||d(e,"SELECT 1 FROM deliveries WHERE idempotency_key = ?").get(`${t}:${n}`)!==void 0}r(C,"destinationDone");function F(e,t,n){return $(e,t)??E(e,t.id,t.type,n,void 0,t)}r(F,"actorFor");function _(e,t,n,c,i){const l=n.actor===null?null:F(e,n.actor,t),u=n.body_text,o=n.body===void 0&&u===void 0?void 0:{...n.body??{},...u===void 0?{}:{body:u}};L(e,{event:n.event,object:c,actor:l,level:n.level,attrs:n.attrs,...o===void 0?{}:{messageBody:o},idempotencyKey:m(t,n.message_id),...i===void 0?{}:{onlyWatchers:i}})}r(_,"apply");function I(e,t){const n=`ev:${t.message_id}:`;if(!t.key.startsWith(n)||t.key.length===n.length)return null;const c=O(e,t.key.slice(n.length));return c!==null&&c.type==="node"&&c.deleted_at===null&&f(e,c)===null?c:null}r(I,"localDestination");function U(e,t,n){const c={accepted:[],rejected:[]};for(const i of n){const l=m(t,i.message_id),u=N(e,l);e.exec("SAVEPOINT peer_event");try{const o=I(e,i);if(u&&o===null){e.exec("RELEASE peer_event"),c.accepted.push(i.key);continue}const s=E(e,i.object.id,i.object.type,t,void 0,i.object),p=i.linked===!0&&o!==null&&s.owner!==null?S(e,s.owner):null,a=p!==null&&p.type==="app"?p:null;if(o!==null&&d(e,"SELECT 1 FROM watches WHERE watcher = ? AND object = ?").get(o.rowid,s.rowid)===void 0?(w(e,o,s,"act",{patterns:[">"],...a===null?{}:{linkApp:a}}),x(e,o,s)):o!==null&&a!==null&&h(e,o,s,a),u)C(e,l,o.id)||_(e,t,i,s,[o.id]);else{_(e,t,i,s),d(e,"INSERT OR IGNORE INTO peer_ingested (key, ingested_at) VALUES (?, ?)").run(l,Date.now());for(const g of d(e,"SELECT destination_id FROM deliveries WHERE idempotency_key >= ? AND idempotency_key < ?").all(`${l}:`,`${l};`))y(e,l,g.destination_id)}o!==null&&y(e,l,o.id),e.exec("RELEASE peer_event"),c.accepted.push(i.key)}catch(o){e.exec("ROLLBACK TO peer_event"),e.exec("RELEASE peer_event");const s=o instanceof R?o.code:"invalid_event";c.rejected.push({key:i.key,code:s,message:o instanceof Error?o.message:String(o)})}}return c}r(U,"ingestPeerEvents");const X=r((e,t,n)=>f(e,t)?.home_machine===n,"isStubOf"),q=r((e,t,n)=>T(e,t,n),"claimFor"),z=r((e,t,n)=>A(e,t,n),"ackFor");export{P as MAX_EVENTS_PER_CALL,z as ackFor,q as claimFor,m as ingestKey,U as ingestPeerEvents,G as isCatalogLag,X as isStubOf};
1
+ var g=Object.defineProperty;var o=(e,t)=>g(e,"name",{value:t,configurable:!0});import{CrtrError as _}from"../errors.js";import{getById as k,getByRowid as R}from"../graph/objects.js";import{publish as O}from"../graph/events.js";import{markLinkWatch as h,recordWatch as S}from"../graph/watches.js";import{armObjectWaitForWatch as L}from"../graph/object-waits.js";import{ackRows as $,claimRows as T}from"./outbox-store.js";import{ensureStub as u,localOwnerActor as W,stubOf as w}from"./stubs.js";import{withCanvasWrite as x}from"../canvas/db.js";const P=100,U=o(e=>e==="unknown_event"||e==="unknown_kind","isCatalogLag"),y=o((e,t)=>`peer:${e}:${t}`,"ingestKey");async function A(e,t){return await e.prepare("SELECT 1 FROM peer_ingested WHERE key = ?").get(t)!==void 0?!0:await e.prepare("SELECT 1 FROM deliveries WHERE idempotency_key >= ? AND idempotency_key < ? LIMIT 1").get(`${t}:`,`${t};`)!==void 0}o(A,"applied");const f=o(async(e,t,n)=>{await e.prepare("INSERT OR IGNORE INTO peer_ingested_destinations (key, ingested_at) VALUES (?, ?)").run(`${t}:${n}`,Date.now())},"markDestination");async function C(e,t,n){return await e.prepare("SELECT 1 FROM peer_ingested_destinations WHERE key = ?").get(`${t}:${n}`)!==void 0||await e.prepare("SELECT 1 FROM deliveries WHERE idempotency_key = ?").get(`${t}:${n}`)!==void 0}o(C,"destinationDone");async function F(e,t,n){return await W(e,t)??await u(e,t.id,t.type,n,void 0,t)}o(F,"actorFor");async function E(e,t,n,r,a){const c=n.actor===null?null:await F(e,n.actor,t),l=n.body_text,i=n.body===void 0&&l===void 0?void 0:{...n.body??{},...l===void 0?{}:{body:l}};await O(e,{event:n.event,object:r,actor:c,level:n.level,attrs:n.attrs,...i===void 0?{}:{messageBody:i},idempotencyKey:y(t,n.message_id),...a===void 0?{}:{onlyWatchers:a}})}o(E,"apply");async function N(e,t){const n=`ev:${t.message_id}:`;if(!t.key.startsWith(n)||t.key.length===n.length)return null;const r=await k(e,t.key.slice(n.length));return r!==null&&r.type==="node"&&r.deleted_at===null&&await w(e,r)===null?r:null}o(N,"localDestination");async function X(e,t,n){const r={accepted:[],rejected:[]};for(const a of n){const c=y(t,a.message_id),l=await A(e,c);try{await x(async()=>{const i=await N(e,a);if(l&&i===null)return;const s=await u(e,a.object.id,a.object.type,t,void 0,a.object),d=a.linked===!0&&i!==null&&s.owner!==null?await R(e,s.owner):null,p=d!==null&&d.type==="app"?d:null;if(i!==null&&await e.prepare("SELECT 1 FROM watches WHERE watcher = ? AND object = ?").get(i.rowid,s.rowid)===void 0?(await S(e,i,s,"act",{patterns:[">"],...p===null?{}:{linkApp:p}}),await L(e,i,s)):i!==null&&p!==null&&await h(e,i,s,p),l)await C(e,c,i.id)||await E(e,t,a,s,[i.id]);else{await E(e,t,a,s),await e.prepare("INSERT OR IGNORE INTO peer_ingested (key, ingested_at) VALUES (?, ?)").run(c,Date.now());for(const m of await e.prepare("SELECT destination_id FROM deliveries WHERE idempotency_key >= ? AND idempotency_key < ?").all(`${c}:`,`${c};`))await f(e,c,m.destination_id)}i!==null&&await f(e,c,i.id)},{savepoint:!0}),r.accepted.push(a.key)}catch(i){const s=i instanceof _?i.code:"invalid_event";r.rejected.push({key:a.key,code:s,message:i instanceof Error?i.message:String(i)})}}return r}o(X,"ingestPeerEvents");const q=o(async(e,t,n)=>(await w(e,t))?.home_machine===n,"isStubOf"),v=o(async(e,t,n)=>await T(e,t,n),"claimFor"),z=o(async(e,t,n)=>await $(e,t,n),"ackFor");export{P as MAX_EVENTS_PER_CALL,z as ackFor,v as claimFor,y as ingestKey,X as ingestPeerEvents,U as isCatalogLag,q as isStubOf};
@@ -1,5 +1,5 @@
1
- import type { DatabaseSync } from 'node:sqlite';
2
1
  import type { ObjectRef } from './stubs.js';
2
+ import type { CanvasDb } from '../canvas/db.js';
3
3
  export type OutboxState = 'pending' | 'waiting' | 'claimed' | 'done' | 'expired';
4
4
  /** What one event looks like on the wire, in both directions (`peer.events` body, `peer.outbox.claim` rows). */
5
5
  export interface PeerEventPayload {
@@ -42,20 +42,20 @@ export declare const CATALOG_LAG_RETRY_MS: number;
42
42
  /** Subscribe to enqueues (the delivery lane pushes a relay peer's row at once). Returns the unsubscribe. */
43
43
  export declare function onPeerEnqueued(listener: (peer: string) => void): () => void;
44
44
  /** Write one row; a key already present adds nothing. Returns whether a row was added. Runs in the caller's transaction. */
45
- export declare function enqueuePeerRow(db: DatabaseSync, row: {
45
+ export declare function enqueuePeerRow(db: CanvasDb, row: {
46
46
  peer: string;
47
47
  kind: string;
48
48
  key: string;
49
49
  payload: unknown;
50
- }, now?: number): boolean;
50
+ }, now?: number): Promise<boolean>;
51
51
  /** Rows the lane may push now: pending and due. */
52
- export declare function dueRows(db: DatabaseSync, now: number, limit?: number): OutboxRow[];
52
+ export declare function dueRows(db: CanvasDb, now: number, limit?: number): Promise<OutboxRow[]>;
53
53
  /** Pending rows to one peer that are new or due (a relay peer's push at enqueue; a row that already failed waits for its backoff). */
54
- export declare function pendingFor(db: DatabaseSync, peer: string, now: number, limit?: number): OutboxRow[];
55
- export declare const markDone: (db: DatabaseSync, id: number) => void;
56
- export declare const markWaiting: (db: DatabaseSync, id: number, attempts: number) => void;
57
- export declare const markRetry: (db: DatabaseSync, id: number, attempts: number, nextAt: number, firstFailedAt: number) => void;
58
- export declare const markExpired: (db: DatabaseSync, id: number) => void;
54
+ export declare function pendingFor(db: CanvasDb, peer: string, now: number, limit?: number): Promise<OutboxRow[]>;
55
+ export declare const markDone: (db: CanvasDb, id: number) => Promise<void>;
56
+ export declare const markWaiting: (db: CanvasDb, id: number, attempts: number) => Promise<void>;
57
+ export declare const markRetry: (db: CanvasDb, id: number, attempts: number, nextAt: number, firstFailedAt: number) => Promise<void>;
58
+ export declare const markExpired: (db: CanvasDb, id: number) => Promise<void>;
59
59
  export interface ClaimedRow {
60
60
  key: string;
61
61
  claim_token: string;
@@ -63,14 +63,14 @@ export interface ClaimedRow {
63
63
  }
64
64
  /** The calling machine's own rows (`peer = via`, never another's), fenced with a fresh token. Takes pending and waiting rows
65
65
  * and claims whose lease ran out; a row still under a live lease is left alone. */
66
- export declare function claimRows(db: DatabaseSync, via: string, limit: number, now?: number): ClaimedRow[];
66
+ export declare function claimRows(db: CanvasDb, via: string, limit: number, now?: number): Promise<ClaimedRow[]>;
67
67
  /** Mark done the rows the caller still holds: `peer = via`, the same token, still `claimed`. Returns the keys acked. */
68
- export declare function ackRows(db: DatabaseSync, via: string, acks: ReadonlyArray<{
68
+ export declare function ackRows(db: CanvasDb, via: string, acks: ReadonlyArray<{
69
69
  key: string;
70
70
  claim_token: string;
71
- }>): string[];
71
+ }>): Promise<string[]>;
72
72
  /** Retire rows done long ago, so the table stays small. */
73
- export declare function pruneOutbox(db: DatabaseSync, now: number, keepMs?: number): void;
73
+ export declare function pruneOutbox(db: CanvasDb, now: number, keepMs?: number): Promise<void>;
74
74
  /** Give up on rows older than `OUTBOX_MAX_AGE_MS` that were never delivered, and on rows whose claim lapsed unacked (the receiver
75
75
  * refused them as catalog lag and left them to be claimed again) once they are older than `CATALOG_LAG_RETRY_MS`. Returns how many. */
76
- export declare function expireOld(db: DatabaseSync, now: number): number;
76
+ export declare function expireOld(db: CanvasDb, now: number): Promise<number>;
@@ -1,5 +1,5 @@
1
- var u=Object.defineProperty;var a=(t,e)=>u(t,"name",{value:e,configurable:!0});import{prepared as r}from"../sqlite-statements.js";import{randomBytes as x}from"node:crypto";const E=10*6e4,m=720*60*6e4,N=1440*6e4,d=new Set;function l(t){return d.add(t),()=>{d.delete(t)}}a(l,"onPeerEnqueued");function L(t,e,n=Date.now()){const o=r(t,`INSERT INTO peer_outbox (peer, kind, payload_json, idempotency_key, state, attempts, next_at, created_at)
2
- VALUES (?, ?, ?, ?, 'pending', 0, ?, ?) ON CONFLICT (idempotency_key) DO NOTHING`).run(e.peer,e.kind,JSON.stringify(e.payload),e.key,n,n);return Number(o.changes)===0?!1:(setImmediate(()=>{for(const i of[...d])try{i(e.peer)}catch{}}),!0)}a(L,"enqueuePeerRow");function T(t,e,n=200){return r(t,"SELECT * FROM peer_outbox WHERE state = 'pending' AND next_at <= ? ORDER BY id LIMIT ?").all(e,n)}a(T,"dueRows");function y(t,e,n,o=50){return r(t,"SELECT * FROM peer_outbox WHERE state = 'pending' AND peer = ? AND (attempts = 0 OR next_at <= ?) ORDER BY id LIMIT ?").all(e,n,o)}a(y,"pendingFor");const O=a((t,e)=>{r(t,"UPDATE peer_outbox SET state = 'done', claimed_by = NULL, next_at = NULL WHERE id = ? AND state IN ('pending', 'waiting')").run(e)},"markDone"),g=a((t,e,n)=>{r(t,"UPDATE peer_outbox SET state = 'waiting', attempts = ?, next_at = NULL WHERE id = ? AND state = 'pending'").run(n,e)},"markWaiting"),S=a((t,e,n,o,i)=>{r(t,"UPDATE peer_outbox SET attempts = ?, next_at = ?, first_failed_at = ? WHERE id = ? AND state = 'pending'").run(n,o,i,e)},"markRetry"),b=a((t,e)=>{r(t,"UPDATE peer_outbox SET state = 'expired', next_at = NULL WHERE id = ? AND state IN ('pending', 'waiting')").run(e)},"markExpired");function f(t,e,n,o=Date.now()){const i=Math.max(1,Math.min(n,100)),_=r(t,`SELECT * FROM peer_outbox WHERE peer = ?
3
- AND (state IN ('pending', 'waiting') OR (state = 'claimed' AND claimed_at <= ?)) ORDER BY id LIMIT ?`).all(e,o-E,i),s=x(16).toString("hex"),c=r(t,"UPDATE peer_outbox SET state = 'claimed', claimed_by = ?, claimed_at = ?, next_at = NULL WHERE id = ?");return _.map(p=>(c.run(s,o,p.id),{key:p.idempotency_key,claim_token:s,payload:JSON.parse(p.payload_json)}))}a(f,"claimRows");function k(t,e,n){const o=r(t,`UPDATE peer_outbox SET state = 'done', claimed_by = NULL WHERE idempotency_key = ? AND peer = ?
4
- AND state = 'claimed' AND claimed_by = ?`);return n.filter(i=>Number(o.run(i.key,e,i.claim_token).changes)>0).map(i=>i.key)}a(k,"ackRows");function I(t,e,n=1440*6e4){r(t,"DELETE FROM peer_outbox WHERE state IN ('done', 'expired') AND created_at < ?").run(e-n)}a(I,"pruneOutbox");function U(t,e){return Number(r(t,`UPDATE peer_outbox SET state = 'expired', next_at = NULL
5
- WHERE (state IN ('pending', 'waiting') AND created_at < ?) OR (state = 'claimed' AND claimed_at <= ? AND created_at < ?)`).run(e-m,e-E,e-N).changes)}a(U,"expireOld");export{N as CATALOG_LAG_RETRY_MS,E as CLAIM_LEASE_MS,m as OUTBOX_MAX_AGE_MS,k as ackRows,f as claimRows,T as dueRows,L as enqueuePeerRow,U as expireOld,O as markDone,b as markExpired,S as markRetry,g as markWaiting,l as onPeerEnqueued,y as pendingFor,I as pruneOutbox};
1
+ var _=Object.defineProperty;var n=(t,e)=>_(t,"name",{value:e,configurable:!0});import{randomBytes as u}from"node:crypto";import{filterAsync as x,mapAsync as m}from"../async-array.js";const c=10*6e4,y=720*60*6e4,N=1440*6e4,o=new Set;function l(t){return o.add(t),()=>{o.delete(t)}}n(l,"onPeerEnqueued");async function L(t,e,a=Date.now()){const r=await t.prepare(`INSERT INTO peer_outbox (peer, kind, payload_json, idempotency_key, state, attempts, next_at, created_at)
2
+ VALUES (?, ?, ?, ?, 'pending', 0, ?, ?) ON CONFLICT (idempotency_key) DO NOTHING`).run(e.peer,e.kind,JSON.stringify(e.payload),e.key,a,a);return Number(r.changes)===0?!1:(setImmediate(()=>{for(const i of[...o])try{i(e.peer)}catch{}}),!0)}n(L,"enqueuePeerRow");async function T(t,e,a=200){return await t.prepare("SELECT * FROM peer_outbox WHERE state = 'pending' AND next_at <= ? ORDER BY id LIMIT ?").all(e,a)}n(T,"dueRows");async function O(t,e,a,r=50){return await t.prepare("SELECT * FROM peer_outbox WHERE state = 'pending' AND peer = ? AND (attempts = 0 OR next_at <= ?) ORDER BY id LIMIT ?").all(e,a,r)}n(O,"pendingFor");const g=n(async(t,e)=>{await t.prepare("UPDATE peer_outbox SET state = 'done', claimed_by = NULL, next_at = NULL WHERE id = ? AND state IN ('pending', 'waiting')").run(e)},"markDone"),S=n(async(t,e,a)=>{await t.prepare("UPDATE peer_outbox SET state = 'waiting', attempts = ?, next_at = NULL WHERE id = ? AND state = 'pending'").run(a,e)},"markWaiting"),b=n(async(t,e,a,r,i)=>{await t.prepare("UPDATE peer_outbox SET attempts = ?, next_at = ?, first_failed_at = ? WHERE id = ? AND state = 'pending'").run(a,r,i,e)},"markRetry"),f=n(async(t,e)=>{await t.prepare("UPDATE peer_outbox SET state = 'expired', next_at = NULL WHERE id = ? AND state IN ('pending', 'waiting')").run(e)},"markExpired");async function k(t,e,a,r=Date.now()){const i=Math.max(1,Math.min(a,100)),d=await t.prepare(`SELECT * FROM peer_outbox WHERE peer = ?
3
+ AND (state IN ('pending', 'waiting') OR (state = 'claimed' AND claimed_at <= ?)) ORDER BY id LIMIT ?`).all(e,r-c,i),s=u(16).toString("hex"),E=t.prepare("UPDATE peer_outbox SET state = 'claimed', claimed_by = ?, claimed_at = ?, next_at = NULL WHERE id = ?");return await m(d,async p=>(await E.run(s,r,p.id),{key:p.idempotency_key,claim_token:s,payload:JSON.parse(p.payload_json)}))}n(k,"claimRows");async function w(t,e,a){const r=t.prepare(`UPDATE peer_outbox SET state = 'done', claimed_by = NULL WHERE idempotency_key = ? AND peer = ?
4
+ AND state = 'claimed' AND claimed_by = ?`);return(await x(a,async i=>Number((await r.run(i.key,e,i.claim_token)).changes)>0)).map(i=>i.key)}n(w,"ackRows");async function I(t,e,a=1440*6e4){await t.prepare("DELETE FROM peer_outbox WHERE state IN ('done', 'expired') AND created_at < ?").run(e-a)}n(I,"pruneOutbox");async function U(t,e){return Number((await t.prepare(`UPDATE peer_outbox SET state = 'expired', next_at = NULL
5
+ WHERE (state IN ('pending', 'waiting') AND created_at < ?) OR (state = 'claimed' AND claimed_at <= ? AND created_at < ?)`).run(e-y,e-c,e-N)).changes)}n(U,"expireOld");export{N as CATALOG_LAG_RETRY_MS,c as CLAIM_LEASE_MS,y as OUTBOX_MAX_AGE_MS,w as ackRows,k as claimRows,T as dueRows,L as enqueuePeerRow,U as expireOld,g as markDone,f as markExpired,b as markRetry,S as markWaiting,l as onPeerEnqueued,O as pendingFor,I as pruneOutbox};
@@ -1,8 +1,8 @@
1
- import type { DatabaseSync } from 'node:sqlite';
2
1
  import type { Receiver } from '../graph/receivers.js';
3
2
  import { type PeerEventPayload } from './outbox-store.js';
3
+ import type { CanvasDb } from '../canvas/db.js';
4
4
  /** The outbox key of one event to one destination stub. */
5
5
  export declare const eventKey: (messageId: string, destination: string) => string;
6
6
  /** The event as it crosses the wire: the object and actor by identity, the attributes, and the body inline. */
7
- export declare function payloadFor(db: DatabaseSync, messageId: string, key: string): PeerEventPayload;
7
+ export declare function payloadFor(db: CanvasDb, messageId: string, key: string): Promise<PeerEventPayload>;
8
8
  export declare const peerReceiver: Receiver;
@@ -1 +1 @@
1
- var p=Object.defineProperty;var s=(o,t)=>p(o,"name",{value:t,configurable:!0});import{prepared as a}from"../sqlite-statements.js";import{heads as _}from"../graph/documents.js";import{bodyOf as y}from"../graph/bodies.js";import{getById as i}from"../graph/objects.js";import{enqueuePeerRow as b}from"./outbox-store.js";import{describeObject as f,stubOf as j}from"./stubs.js";const g=s((o,t)=>`ev:${o}:${t}`,"eventKey");function h(o,t){const d=typeof t?.pointer=="string"?t.pointer:void 0,e=d===void 0?null:i(o,d);if(e===null||e.type!=="document"||e.deleted_at!==null)return;const n=_(o,e)[0];if(n===void 0)return;const r=a(o,"SELECT source_path FROM documents WHERE object = ?").get(e.rowid);return y(n.body_hash,r?.source_path??null)}s(h,"reportText");function v(o,t,d){const e=a(o,"SELECT message_id, event, object_id, level, actor_id, body_ref, body_json FROM messages WHERE message_id = ?").get(t);if(e===void 0)throw new Error(`no message ${t}`);const n=i(o,e.object_id);if(n===null)throw new Error(`no object ${e.object_id}`);const r=e.actor_id===null?null:i(o,e.actor_id),m=e.body_json===null?{}:JSON.parse(e.body_json),{push:c,bodyRef:E,...u}=m,l=e.body_ref===null?void 0:h(o,c);return{key:d,message_id:e.message_id,event:e.event,level:e.level,object:f(o,n),actor:r===null?null:f(o,r),attrs:c?.attrs??{},...Object.keys(u).length>0?{body:u}:{},...l===void 0?{}:{body_text:l}}}s(v,"payloadFor");const $={bodyOwner:s(()=>null,"bodyOwner"),enqueue(o,t,d){for(const e of d){const n=j(o,e.id);if(n===null)continue;const r=g(t.messageId,e.id);b(o,{peer:n.home_machine,kind:"event",key:r,payload:{...v(o,t.messageId,r),...e.linked?{linked:!0}:{}}})}}};export{g as eventKey,v as payloadFor,$ as peerReceiver};
1
+ var p=Object.defineProperty;var a=(t,n)=>p(t,"name",{value:n,configurable:!0});import{heads as y}from"../graph/documents.js";import{bodyOf as _}from"../graph/bodies.js";import{getById as s}from"../graph/objects.js";import{enqueuePeerRow as m}from"./outbox-store.js";import{describeObject as l,stubOf as w}from"./stubs.js";const b=a((t,n)=>`ev:${t}:${n}`,"eventKey");async function j(t,n){const i=typeof n?.pointer=="string"?n.pointer:void 0,e=i===void 0?null:await s(t,i);if(e===null||e.type!=="document"||e.deleted_at!==null)return;const o=(await y(t,e))[0];if(o===void 0)return;const r=await t.prepare("SELECT source_path FROM documents WHERE object = ?").get(e.rowid);return _(o.body_hash,r?.source_path??null)}a(j,"reportText");async function g(t,n,i){const e=await t.prepare("SELECT message_id, event, object_id, level, actor_id, body_ref, body_json FROM messages WHERE message_id = ?").get(n);if(e===void 0)throw new Error(`no message ${n}`);const o=await s(t,e.object_id);if(o===null)throw new Error(`no object ${e.object_id}`);const r=e.actor_id===null?null:await s(t,e.actor_id),f=e.body_json===null?{}:JSON.parse(e.body_json),{push:d,bodyRef:h,...c}=f,u=e.body_ref===null?void 0:await j(t,d);return{key:i,message_id:e.message_id,event:e.event,level:e.level,object:await l(t,o),actor:r===null?null:await l(t,r),attrs:d?.attrs??{},...Object.keys(c).length>0?{body:c}:{},...u===void 0?{}:{body_text:u}}}a(g,"payloadFor");const T={bodyOwner:a(()=>null,"bodyOwner"),async enqueue(t,n,i){for(const e of i){const o=await w(t,e.id);if(o===null)continue;const r=b(n.messageId,e.id);await m(t,{peer:o.home_machine,kind:"event",key:r,payload:{...await g(t,n.messageId,r),...e.linked?{linked:!0}:{}}})}}};export{b as eventKey,g as payloadFor,T as peerReceiver};
@@ -1,8 +1,8 @@
1
- import type { DatabaseSync } from 'node:sqlite';
2
1
  import type { ObjectRow, Privacy } from '../graph/types.js';
3
2
  import { type CustomEvents } from '../graph/custom.js';
4
3
  import type { ObjectDTO } from '../../api/dto/objects.js';
5
4
  import type { Envelope } from './envelope.js';
5
+ import type { CanvasDb } from '../canvas/db.js';
6
6
  /** The part of an envelope a stub stores: who the remote watcher is, never what it may do. */
7
7
  export interface StubIdentity {
8
8
  sub: string;
@@ -50,12 +50,12 @@ export interface StubRecord {
50
50
  identity: StubIdentity | null;
51
51
  }
52
52
  export declare const identityOfEnvelope: (envelope: Envelope) => StubIdentity;
53
- export declare function stubOf(db: DatabaseSync, object: ObjectRow | string): StubRecord | null;
54
- export declare const isStub: (db: DatabaseSync, object: ObjectRow) => boolean;
53
+ export declare function stubOf(db: CanvasDb, object: ObjectRow | string): Promise<StubRecord | null>;
54
+ export declare const isStub: (db: CanvasDb, object: ObjectRow) => Promise<boolean>;
55
55
  /** The local object for an app or person the other machine names as an event's actor, or null for any other type. An app or person is an
56
56
  * owner, not a thing that lives on one machine: it is the same object here as there, so it is never given a stub (a stub would collide
57
57
  * with the local owner object of the same handle, as with an installed plugin's app). */
58
- export declare function localOwnerActor(db: DatabaseSync, ref: ObjectRef): ObjectRow | null;
58
+ export declare function localOwnerActor(db: CanvasDb, ref: ObjectRef): Promise<ObjectRow | null>;
59
59
  /**
60
60
  * The stub of the object `id` that lives on `machine`, created on first sight. Idempotent: a second
61
61
  * call returns the same row and, given an `envelope`, replaces the identity it stores. Refuses
@@ -63,7 +63,7 @@ export declare function localOwnerActor(db: DatabaseSync, ref: ObjectRef): Objec
63
63
  * local app (or person) object of the remote owner, so the stub sits in a space the access rules
64
64
  * understand. No `nodes` row is written.
65
65
  */
66
- export declare function ensureStub(db: DatabaseSync, id: string, type: string, machine: string, envelope?: Envelope, ref?: ObjectRef): ObjectRow;
66
+ export declare function ensureStub(db: CanvasDb, id: string, type: string, machine: string, envelope?: Envelope, ref?: ObjectRef): Promise<ObjectRow>;
67
67
  /**
68
68
  * The stub of the node `nodeId` that lives on `machine`, as a watcher: created on first sight with no envelope
69
69
  * identity, owned by the local person, and marked `reception = 2` so `publish` considers it and the node
@@ -71,12 +71,12 @@ export declare function ensureStub(db: DatabaseSync, id: string, type: string, m
71
71
  * identity on the same row (`ensureStub` with an envelope). Refuses (`conflict`) an id that is a real local
72
72
  * object or a stub of another machine. Writes no `nodes` row.
73
73
  */
74
- export declare function ensureNodeStub(db: DatabaseSync, nodeId: string, machine: string): ObjectRow;
74
+ export declare function ensureNodeStub(db: CanvasDb, nodeId: string, machine: string): Promise<ObjectRow>;
75
75
  /** The object moved: the machine that answered for it is now its home. A no-op for a local object or a stub already homed there. */
76
- export declare function rehomeStub(db: DatabaseSync, id: string, machine: string): void;
76
+ export declare function rehomeStub(db: CanvasDb, id: string, machine: string): Promise<void>;
77
77
  /** How `o` is described to another machine. */
78
- export declare function describeObject(db: DatabaseSync, o: ObjectRow): ObjectRef;
78
+ export declare function describeObject(db: CanvasDb, o: ObjectRow): Promise<ObjectRef>;
79
79
  /** The declaration of the custom kind `type`, or null for a built-in (no `object_kinds` row). Carries no `read` leaf. */
80
- export declare function kindDeclarationOf(db: DatabaseSync, type: string): KindDeclaration | null;
80
+ export declare function kindDeclarationOf(db: CanvasDb, type: string): Promise<KindDeclaration | null>;
81
81
  /** `dto` with the declaration of its object's kind, when the kind is custom. */
82
- export declare function withKindDecl(db: DatabaseSync, row: ObjectRow, dto: ObjectDTO): ObjectDTO;
82
+ export declare function withKindDecl(db: CanvasDb, row: ObjectRow, dto: ObjectDTO): Promise<ObjectDTO>;
@@ -1 +1 @@
1
- var x=Object.defineProperty;var o=(n,e)=>x(n,"name",{value:e,configurable:!0});import{prepared as i}from"../sqlite-statements.js";import{createObject as A,ensureOwner as h,getById as y,getByRowid as p}from"../graph/objects.js";import{upsertKind as b}from"../graph/custom.js";import{CrtrError as f}from"../errors.js";import{ExitCode as m}from"../../types.js";import{normalizeMachineId as H}from"./names.js";const N=["public","friends","private"],W=o(n=>{const e=n.act.act;return e===void 0?{sub:n.sub,app:null,node:null,node_scopes:null,place:null}:{sub:n.sub,app:e.sub,node:e.node,node_scopes:e.node_scopes,place:e.place}},"identityOfEnvelope");function S(n,e){const r=typeof e=="string"?y(n,e):e;if(r===null)return null;const t=i(n,"SELECT home_machine, envelope_json FROM peer_stubs WHERE object = ?").get(r.rowid);return t?{object:r,home_machine:t.home_machine,identity:t.envelope_json===null?null:JSON.parse(t.envelope_json)}:null}o(S,"stubOf");const I=o((n,e)=>i(n,"SELECT 1 FROM peer_stubs WHERE object = ?").get(e.rowid)!==void 0,"isStub");function d(n){return h(n,"person","local-user","user:local","user")}o(d,"localPerson");function w(n,e){return e==="user:local"?d(n):h(n,"app","app",e,e.replace(/^app:/,""))}o(w,"localApp");function F(n,e){return e.type==="app"?w(n,`app:${e.name}`):e.type==="person"?d(n):null}o(F,"localOwnerActor");function v(n,e,r){if(e!==null)return e.app===null?d(n):w(n,e.app);const t=r?.owner;return t?.type==="app"?w(n,t.external_id??`app:${t.handle}`):d(n)}o(v,"ownerFor");function g(n,e,r,t,_,u){const l=_===void 0?null:W(_),s=u?.privacy??"public";if(!N.includes(s))throw new f("invalid_event",`invalid privacy ${JSON.stringify(s)}`,m.GENERAL,{id:e});const c=y(n,e);if(c!==null){const a=S(n,c);if(a===null)throw new f("conflict",`${e} is a local ${c.type}, not a stub of ${t}`,m.GENERAL,{id:e});if(a.home_machine!==t)throw new f("conflict",`${e} is already a stub of ${a.home_machine}, not ${t}`,m.GENERAL,{id:e,home_machine:a.home_machine});return l!==null&&(i(n,"UPDATE peer_stubs SET envelope_json = ? WHERE object = ?").run(JSON.stringify(l),c.rowid),i(n,"UPDATE objects SET reception = 2 WHERE rowid = ?").run(c.rowid)),u!==void 0&&(R(n,r,u),u.privacy!==void 0&&c.privacy!==s)?(i(n,"UPDATE objects SET privacy = ? WHERE rowid = ?").run(s,c.rowid),p(n,c.rowid)):c}const O=v(n,l,u);R(n,r,u);const E=A(n,{id:e,type:r,kind:u?.kind??null,owner:O.rowid,privacy:s,name:u?.name??e,preview:u?.preview??"",home_machine:t});return i(n,"INSERT INTO peer_stubs (object, home_machine, envelope_json, created_at) VALUES (?, ?, ?, ?)").run(E.rowid,t,l===null?null:JSON.stringify(l),new Date().toISOString()),l!==null&&i(n,"UPDATE objects SET reception = 2 WHERE rowid = ?").run(E.rowid),p(n,E.rowid)}o(g,"ensureStub");function R(n,e,r){const t=r?.kind_decl;t===void 0||t.name!==e||b(n,{name:t.name,owner:v(n,null,{...r,owner:t.owner}),description:t.description,events:t.events,read:null,source:"peer"})}o(R,"holdKind");function J(n,e,r){const t=g(n,e,"node",H(r));return i(n,"UPDATE objects SET reception = 2 WHERE rowid = ?").run(t.rowid),p(n,t.rowid)}o(J,"ensureNodeStub");function M(n,e,r){const t=S(n,e);t===null||t.home_machine===r||(i(n,"UPDATE peer_stubs SET home_machine = ? WHERE object = ?").run(r,t.object.rowid),i(n,"UPDATE objects SET home_machine = ? WHERE rowid = ?").run(r,t.object.rowid))}o(M,"rehomeStub");function G(n,e){const r=j(n,e.owner===null?null:p(n,e.owner)),t=T(n,e.type);return{id:e.id,type:e.type,kind:e.kind,name:e.name,preview:e.preview,owner:r,privacy:e.privacy,...t===null?{}:{kind_decl:t}}}o(G,"describeObject");function j(n,e){if(e===null||e.type!=="person"&&e.type!=="app"&&e.type!=="repo"&&e.type!=="profile")return null;const r=i(n,"SELECT scheme, external_id FROM identities WHERE object = ?").get(e.rowid);return{id:e.id,type:e.type,scheme:r?.scheme??null,external_id:r?.external_id??null,handle:e.name}}o(j,"ownerRefOf");function T(n,e){const r=i(n,"SELECT owner, description, events_json FROM object_kinds WHERE name = ?").get(e),t=r===void 0?null:j(n,p(n,r.owner));return r===void 0||t===null?null:{name:e,description:r.description,events:JSON.parse(r.events_json),owner:t}}o(T,"kindDeclarationOf");function K(n,e,r){const t=T(n,e.type);return t===null?r:{...r,kind_decl:t}}o(K,"withKindDecl");export{G as describeObject,J as ensureNodeStub,g as ensureStub,W as identityOfEnvelope,I as isStub,T as kindDeclarationOf,F as localOwnerActor,M as rehomeStub,S as stubOf,K as withKindDecl};
1
+ var O=Object.defineProperty;var i=(n,e)=>O(n,"name",{value:e,configurable:!0});import{createObject as x,ensureOwner as y,getById as _,getByRowid as u}from"../graph/objects.js";import{upsertKind as A}from"../graph/custom.js";import{CrtrError as d}from"../errors.js";import{ExitCode as E}from"../../types.js";import{normalizeMachineId as b}from"./names.js";const H=["public","friends","private"],N=i(n=>{const e=n.act.act;return e===void 0?{sub:n.sub,app:null,node:null,node_scopes:null,place:null}:{sub:n.sub,app:e.sub,node:e.node,node_scopes:e.node_scopes,place:e.place}},"identityOfEnvelope");async function h(n,e){const r=typeof e=="string"?await _(n,e):e;if(r===null)return null;const t=await n.prepare("SELECT home_machine, envelope_json FROM peer_stubs WHERE object = ?").get(r.rowid);return t?{object:r,home_machine:t.home_machine,identity:t.envelope_json===null?null:JSON.parse(t.envelope_json)}:null}i(h,"stubOf");const U=i(async(n,e)=>await n.prepare("SELECT 1 FROM peer_stubs WHERE object = ?").get(e.rowid)!==void 0,"isStub");async function l(n){return await y(n,"person","local-user","user:local","user")}i(l,"localPerson");async function f(n,e){return e==="user:local"?await l(n):await y(n,"app","app",e,e.replace(/^app:/,""))}i(f,"localApp");async function C(n,e){return e.type==="app"?await f(n,`app:${e.name}`):e.type==="person"?await l(n):null}i(C,"localOwnerActor");async function v(n,e,r){if(e!==null)return e.app===null?await l(n):await f(n,e.app);const t=r?.owner;return t?.type==="app"?await f(n,t.external_id??`app:${t.handle}`):await l(n)}i(v,"ownerFor");async function W(n,e,r,t,m,a){const c=m===void 0?null:N(m),p=a?.privacy??"public";if(!H.includes(p))throw new d("invalid_event",`invalid privacy ${JSON.stringify(p)}`,E.GENERAL,{id:e});const o=await _(n,e);if(o!==null){const s=await h(n,o);if(s===null)throw new d("conflict",`${e} is a local ${o.type}, not a stub of ${t}`,E.GENERAL,{id:e});if(s.home_machine!==t)throw new d("conflict",`${e} is already a stub of ${s.home_machine}, not ${t}`,E.GENERAL,{id:e,home_machine:s.home_machine});return c!==null&&(await n.prepare("UPDATE peer_stubs SET envelope_json = ? WHERE object = ?").run(JSON.stringify(c),o.rowid),await n.prepare("UPDATE objects SET reception = 2 WHERE rowid = ?").run(o.rowid)),a!==void 0&&(await S(n,r,a),a.privacy!==void 0&&o.privacy!==p)?(await n.prepare("UPDATE objects SET privacy = ? WHERE rowid = ?").run(p,o.rowid),await u(n,o.rowid)):o}const T=await v(n,c,a);await S(n,r,a);const w=await x(n,{id:e,type:r,kind:a?.kind??null,owner:T.rowid,privacy:p,name:a?.name??e,preview:a?.preview??"",home_machine:t});return await n.prepare("INSERT INTO peer_stubs (object, home_machine, envelope_json, created_at) VALUES (?, ?, ?, ?)").run(w.rowid,t,c===null?null:JSON.stringify(c),new Date().toISOString()),c!==null&&await n.prepare("UPDATE objects SET reception = 2 WHERE rowid = ?").run(w.rowid),await u(n,w.rowid)}i(W,"ensureStub");async function S(n,e,r){const t=r?.kind_decl;t===void 0||t.name!==e||await A(n,{name:t.name,owner:await v(n,null,{...r,owner:t.owner}),description:t.description,events:t.events,read:null,source:"peer"})}i(S,"holdKind");async function I(n,e,r){const t=await W(n,e,"node",b(r));return await n.prepare("UPDATE objects SET reception = 2 WHERE rowid = ?").run(t.rowid),await u(n,t.rowid)}i(I,"ensureNodeStub");async function F(n,e,r){const t=await h(n,e);t===null||t.home_machine===r||(await n.prepare("UPDATE peer_stubs SET home_machine = ? WHERE object = ?").run(r,t.object.rowid),await n.prepare("UPDATE objects SET home_machine = ? WHERE rowid = ?").run(r,t.object.rowid))}i(F,"rehomeStub");async function J(n,e){const r=await R(n,e.owner===null?null:await u(n,e.owner)),t=await j(n,e.type);return{id:e.id,type:e.type,kind:e.kind,name:e.name,preview:e.preview,owner:r,privacy:e.privacy,...t===null?{}:{kind_decl:t}}}i(J,"describeObject");async function R(n,e){if(e===null||e.type!=="person"&&e.type!=="app"&&e.type!=="repo"&&e.type!=="profile")return null;const r=await n.prepare("SELECT scheme, external_id FROM identities WHERE object = ?").get(e.rowid);return{id:e.id,type:e.type,scheme:r?.scheme??null,external_id:r?.external_id??null,handle:e.name}}i(R,"ownerRefOf");async function j(n,e){const r=await n.prepare("SELECT owner, description, events_json FROM object_kinds WHERE name = ?").get(e),t=r===void 0?null:await R(n,await u(n,r.owner));return r===void 0||t===null?null:{name:e,description:r.description,events:JSON.parse(r.events_json),owner:t}}i(j,"kindDeclarationOf");async function M(n,e,r){const t=await j(n,e.type);return t===null?r:{...r,kind_decl:t}}i(M,"withKindDecl");export{J as describeObject,I as ensureNodeStub,W as ensureStub,N as identityOfEnvelope,U as isStub,j as kindDeclarationOf,C as localOwnerActor,F as rehomeStub,h as stubOf,M as withKindDecl};
@@ -9,11 +9,11 @@ export interface ApprovalQuestion {
9
9
  }>;
10
10
  }
11
11
  /** A runless repeat consumes an answer exactly once, before any provider request. */
12
- export declare function consumeApproval(caller: ProviderCaller, input: ProviderCallInput, callShape: string): {
12
+ export declare function consumeApproval(caller: ProviderCaller, input: ProviderCallInput, callShape: string): Promise<{
13
13
  option: string;
14
14
  requestId: string;
15
15
  prepared: PreparedFileCall | null;
16
- };
16
+ }>;
17
17
  /** Called when the human ticket settles (answer or cancel), in the settlement transaction. */
18
18
  export declare function notifyProviderApproval(questionId: string): void;
19
19
  /** Create a page and either suspend a run or return its durable id to an app. */
@@ -1,3 +1,3 @@
1
- var b=Object.defineProperty;var a=(r,e)=>b(r,"name",{value:e,configurable:!0});import{prepared as l}from"../sqlite-statements.js";import{createHash as q}from"node:crypto";import{openDb as E,withCanvasWrite as v}from"../canvas/db.js";import{newNodeId as A}from"../runtime/nodes.js";import{createPageRequest as S,getRequest as N}from"../human/requests.js";import{providerApprovalPage as O}from"../runs/questions.js";import{ProviderError as c}from"./errors.js";function _(r){return Array.isArray(r)?r.map(_):r!==null&&typeof r=="object"?Object.fromEntries(Object.entries(r).sort(([e],[n])=>e.localeCompare(n)).map(([e,n])=>[e,_(n)])):r}a(_,"canonical");function y(r){return q("sha256").update(JSON.stringify(_(r))).digest("hex")}a(y,"hashArgs");function f(){return new c("invalid_request","approval is not an answered question for this call",{param:"approval"})}a(f,"invalidApproval");function s(){return new c("user_denied","the user did not approve this call")}a(s,"denied");function R(r){if(r.aborted)throw s()}a(R,"canceled");function m(r){return l(E(),"SELECT * FROM provider_approvals WHERE question_id = ?").get(r)}a(m,"row");function z(r,e,n){const o=e.approval;if(!o||r.run_id!==null||r.grantee===null||r.sub===null)throw f();const t=m(o);if(!t||t.grantee!==r.grantee||t.sub!==r.sub||t.provider!==e.provider||t.tool!==e.tool||t.version!==(e.version??null)||t.args_hash!==y(e.arguments)||t.call_shape!==n)throw f();const p=N(o);if(!p||p.state!=="settled"||p.outcome!=="answered"||t.status!=="answered")throw f();const i=t.option_id;if(!i||v(d=>l(d,"UPDATE provider_approvals SET status = 'consumed' WHERE question_id = ? AND status = 'answered'").run(o).changes)!==1)throw f();if(i==="deny")throw s();return{option:i,requestId:t.request_id,prepared:t.prepared_files?JSON.parse(t.prepared_files):null}}a(z,"consumeApproval");function T(r){if(!r||typeof r!="object"||Array.isArray(r))throw new c("provider_error","provider approval question is invalid",{origin:"provider"});const e=r,n=e.options;if(typeof e.title!="string"||!e.title.trim()||typeof e.body!="string"||!Array.isArray(n)||n.length===0||n.some(o=>!o||typeof o!="object"||typeof o.option_id!="string"||!/^[A-Za-z0-9_-]{1,64}$/.test(o.option_id)||o.option_id==="deny"||typeof o.label!="string"||!o.label.trim())||new Set(n.map(o=>o.option_id)).size!==n.length)throw new c("provider_error","provider approval question is invalid",{origin:"provider"});return e}a(T,"validateQuestion");const w=new Map;function C(r){for(const e of w.get(r)??[])queueMicrotask(e)}a(C,"notifyProviderApproval");async function P(r,e){const n=a(()=>{const t=m(r);if(!t||t.status==="canceled")throw s();return t.status==="answered"?t.option_id:null},"read");if(e.aborted)throw s();let o=n();if(o==="deny")throw s();if(o!==null)return o;if(await new Promise(t=>{const p=w.get(r)??new Set,i=a(()=>{e.removeEventListener("abort",i),p.delete(i),p.size||w.delete(r),t()},"wake");p.add(i),w.set(r,p),e.addEventListener("abort",i,{once:!0}),(e.aborted||m(r)?.status!=="open")&&i()}),e.aborted||(o=n(),o===null||o==="deny"))throw s();return o}a(P,"waitForApproval");async function F(r,e,n,o,t,p,i){const g=T(o);if(!r.sub||!r.grantee)throw new c("grant_revoked","caller has no active grant");R(t);const d=A();v(u=>l(u,`INSERT INTO provider_approvals
1
+ var g=Object.defineProperty;var a=(r,e)=>g(r,"name",{value:e,configurable:!0});import{createHash as b}from"node:crypto";import{openDb as f}from"../canvas/db.js";import{newNodeId as q}from"../runtime/nodes.js";import{createPageRequest as E,getRequest as A}from"../human/requests.js";import{providerApprovalPage as S}from"../runs/questions.js";import{ProviderError as c}from"./errors.js";function h(r){return Array.isArray(r)?r.map(h):r!==null&&typeof r=="object"?Object.fromEntries(Object.entries(r).sort(([e],[i])=>e.localeCompare(i)).map(([e,i])=>[e,h(i)])):r}a(h,"canonical");function m(r){return b("sha256").update(JSON.stringify(h(r))).digest("hex")}a(m,"hashArgs");function w(){return new c("invalid_request","approval is not an answered question for this call",{param:"approval"})}a(w,"invalidApproval");function s(){return new c("user_denied","the user did not approve this call")}a(s,"denied");function N(r){if(r.aborted)throw s()}a(N,"canceled");async function v(r){return await(await f()).prepare("SELECT * FROM provider_approvals WHERE question_id = ?").get(r)}a(v,"row");async function x(r,e,i){const o=e.approval;if(!o||r.run_id!==null||r.grantee===null||r.sub===null)throw w();const t=await v(o);if(!t||t.grantee!==r.grantee||t.sub!==r.sub||t.provider!==e.provider||t.tool!==e.tool||t.version!==(e.version??null)||t.args_hash!==m(e.arguments)||t.call_shape!==i)throw w();const p=await A(o);if(!p||p.state!=="settled"||p.outcome!=="answered"||t.status!=="answered")throw w();const n=t.option_id;if(!n||(await(await f()).prepare("UPDATE provider_approvals SET status = 'consumed' WHERE question_id = ? AND status = 'answered'").run(o)).changes!==1)throw w();if(n==="deny")throw s();return{option:n,requestId:t.request_id,prepared:t.prepared_files?JSON.parse(t.prepared_files):null}}a(x,"consumeApproval");function O(r){if(!r||typeof r!="object"||Array.isArray(r))throw new c("provider_error","provider approval question is invalid",{origin:"provider"});const e=r,i=e.options;if(typeof e.title!="string"||!e.title.trim()||typeof e.body!="string"||!Array.isArray(i)||i.length===0||i.some(o=>!o||typeof o!="object"||typeof o.option_id!="string"||!/^[A-Za-z0-9_-]{1,64}$/.test(o.option_id)||o.option_id==="deny"||typeof o.label!="string"||!o.label.trim())||new Set(i.map(o=>o.option_id)).size!==i.length)throw new c("provider_error","provider approval question is invalid",{origin:"provider"});return e}a(O,"validateQuestion");const l=new Map;function M(r){for(const e of l.get(r)??[])queueMicrotask(e)}a(M,"notifyProviderApproval");async function R(r,e){const i=a(async()=>{const t=await v(r);if(!t||t.status==="canceled")throw s();return t.status==="answered"?t.option_id:null},"read");if(e.aborted)throw s();let o=await i();if(o==="deny")throw s();if(o!==null)return o;if(await new Promise(async t=>{const p=l.get(r)??new Set,n=a(()=>{e.removeEventListener("abort",n),p.delete(n),p.size||l.delete(r),t()},"wake");p.add(n),l.set(r,p),e.addEventListener("abort",n,{once:!0}),(e.aborted||(await v(r))?.status!=="open")&&n()}),e.aborted||(o=await i(),o===null||o==="deny"))throw s();return o}a(R,"waitForApproval");async function z(r,e,i,o,t,p,n){const _=O(o);if(!r.sub||!r.grantee)throw new c("grant_revoked","caller has no active grant");N(t);const d=await q();await(await f()).prepare(`INSERT INTO provider_approvals
2
2
  (question_id, grantee, sub, provider, tool, version, args_hash, request_id, status, call_shape, prepared_files)
3
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, 'open', ?, ?)`).run(d,r.grantee,r.sub,e.provider,e.tool,e.version??null,y(e.arguments),n,p??null,i&&(i.copies.length||i.upload)?JSON.stringify(i):null));try{S({request_id:d,requester_node_id:r.run_id?r.node_id:null,prepared:O(g)})}catch(u){throw v(h=>l(h,"DELETE FROM provider_approvals WHERE question_id = ? AND status = 'open'").run(d)),u}if(!r.run_id){if(t.aborted){const{cancelHumanTicket:u}=await import("../../daemon/human/finish.js");throw await u(d,{reason:"the provider call was canceled"}),s()}throw new c("approval_pending","the provider requires the user to answer a question",{question_id:d})}try{const u=await P(d,t);if(t.aborted)throw s();return{option:u,questionId:d}}catch(u){if(t.aborted){const{cancelHumanTicket:h}=await import("../../daemon/human/finish.js");throw await h(d,{reason:"the provider call was canceled"}),s()}throw u}}a(F,"requireProviderApproval");export{z as consumeApproval,C as notifyProviderApproval,F as requireProviderApproval};
3
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, 'open', ?, ?)`).run(d,r.grantee,r.sub,e.provider,e.tool,e.version??null,m(e.arguments),i,p??null,n&&(n.copies.length||n.upload)?JSON.stringify(n):null);try{await E({request_id:d,requester_node_id:r.run_id?r.node_id:null,prepared:S(_)})}catch(u){throw await(await f()).prepare("DELETE FROM provider_approvals WHERE question_id = ? AND status = 'open'").run(d),u}if(!r.run_id){if(t.aborted){const{cancelHumanTicket:u}=await import("../../daemon/human/finish.js");throw await u(d,{reason:"the provider call was canceled"}),s()}throw new c("approval_pending","the provider requires the user to answer a question",{question_id:d})}try{const u=await R(d,t);if(t.aborted)throw s();return{option:u,questionId:d}}catch(u){if(t.aborted){const{cancelHumanTicket:y}=await import("../../daemon/human/finish.js");throw await y(d,{reason:"the provider call was canceled"}),s()}throw u}}a(z,"requireProviderApproval");export{x as consumeApproval,M as notifyProviderApproval,z as requireProviderApproval};
@@ -12,7 +12,7 @@ export interface ProviderAudit {
12
12
  question_id?: string;
13
13
  }
14
14
  /** One row per authorization, including refusals before a token is minted. */
15
- export declare function writeProviderAudit(row: ProviderAudit): void;
15
+ export declare function writeProviderAudit(row: ProviderAudit): Promise<void>;
16
16
  export interface AuditFilters {
17
17
  after?: number;
18
18
  limit: number;
@@ -22,7 +22,7 @@ export interface AuditFilters {
22
22
  since?: string;
23
23
  until?: string;
24
24
  }
25
- export declare function listAudit(grantee: string | null, filters: AuditFilters): {
25
+ export declare function listAudit(grantee: string | null, filters: AuditFilters): Promise<{
26
26
  rows: Record<string, unknown>[];
27
27
  next: string | null;
28
- };
28
+ }>;
@@ -1,4 +1,4 @@
1
- var a=Object.defineProperty;var r=(n,e)=>a(n,"name",{value:e,configurable:!0});import{prepared as m}from"../sqlite-statements.js";import{openDb as p}from"../canvas/db.js";import{runtimeId as h}from"../grants/sync.js";import{terminalGrant as _}from"../grants/mirror.js";function O(n){const{caller:e}=n,i=e.sub??(e.class==="person"?_()?.sub??null:null),t=e.grantee??i,o=i&&t?[i,t,`runtime:${h()}`]:null;m(p(),`INSERT INTO audit_rows
1
+ var p=Object.defineProperty;var r=(i,n)=>p(i,"name",{value:n,configurable:!0});import{openDb as a}from"../canvas/db.js";import{runtimeId as m}from"../grants/sync.js";import{terminalGrant as h}from"../grants/mirror.js";async function E(i){const{caller:n}=i,e=n.sub??(n.class==="person"?(await h())?.sub??null:null),t=n.grantee??e,o=e&&t?[e,t,`runtime:${m()}`]:null;await(await a()).prepare(`INSERT INTO audit_rows
2
2
  (request_id, time, grantee, sub, client_id, class, operation, scope_checked,
3
3
  outcome, node_id, run_id, resource, initiator_chain, provider, tool, jti, receipt_id, responder, question_id)
4
- VALUES (?, ?, ?, ?, ?, ?, 'provider.call', ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(n.request_id,new Date().toISOString(),t,i,e.client_id,e.class,n.scope_checked??null,n.outcome,e.node_id,e.run_id,`${n.provider} ${n.tool}`,o?JSON.stringify(o):null,n.provider,n.tool,n.jti??null,n.receipt_id??null,n.responder??null,n.question_id??null)}r(O,"writeProviderAudit");function $(n,e){const i=[],t=[];n!==null&&(i.push("grantee = ?"),t.push(n)),e.after!==void 0&&(i.push("id < ?"),t.push(e.after));for(const u of["operation","outcome","run_id"])e[u]!==void 0&&(i.push(`${u} = ?`),t.push(e[u]));e.since!==void 0&&(i.push("time >= ?"),t.push(e.since)),e.until!==void 0&&(i.push("time <= ?"),t.push(e.until));const o=p().prepare(`SELECT * FROM audit_rows ${i.length?`WHERE ${i.join(" AND ")}`:""} ORDER BY id DESC LIMIT ?`).all(...t,e.limit+1),d=o.length>e.limit;d&&o.pop();const l=d?String(o.at(-1)?.id):null;return{rows:o.map(({id:u,initiator_chain:s,...c})=>({...c,initiator_chain:typeof s=="string"?JSON.parse(s):null})),next:l}}r($,"listAudit");export{$ as listAudit,O as writeProviderAudit};
4
+ VALUES (?, ?, ?, ?, ?, ?, 'provider.call', ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(i.request_id,new Date().toISOString(),t,e,n.client_id,n.class,i.scope_checked??null,i.outcome,n.node_id,n.run_id,`${i.provider} ${i.tool}`,o?JSON.stringify(o):null,i.provider,i.tool,i.jti??null,i.receipt_id??null,i.responder??null,i.question_id??null)}r(E,"writeProviderAudit");async function I(i,n){const e=[],t=[];i!==null&&(e.push("grantee = ?"),t.push(i)),n.after!==void 0&&(e.push("id < ?"),t.push(n.after));for(const u of["operation","outcome","run_id"])n[u]!==void 0&&(e.push(`${u} = ?`),t.push(n[u]));n.since!==void 0&&(e.push("time >= ?"),t.push(n.since)),n.until!==void 0&&(e.push("time <= ?"),t.push(n.until));const o=await(await a()).prepareUncached(`SELECT * FROM audit_rows ${e.length?`WHERE ${e.join(" AND ")}`:""} ORDER BY id DESC LIMIT ?`).all(...t,n.limit+1),s=o.length>n.limit;s&&o.pop();const c=s?String(o.at(-1)?.id):null;return{rows:o.map(({id:u,initiator_chain:d,...l})=>({...l,initiator_chain:typeof d=="string"?JSON.parse(d):null})),next:c}}r(I,"listAudit");export{I as listAudit,E as writeProviderAudit};
@@ -1,2 +1,2 @@
1
- var se=Object.defineProperty;var i=(e,n)=>se(e,"name",{value:n,configurable:!0});import{existsSync as w,readdirSync as z,readFileSync as S,rmSync as $,statSync as k}from"node:fs";import{join as u}from"node:path";import{validateCommandManifest as de}from"../../api/command-manifest/manifest.js";import{crtrHome as F}from"../canvas/paths.js";import{withCanvasWrite as G}from"../canvas/db.js";import{bundleVersion as ue,isInstalledGeneration as ce,recordCheckedGeneration as fe}from"../command-plugins/bundle.js";import{readConfig as q,readState as le,updateConfig as pe,updateState as me}from"../config.js";import{emitEvent as m}from"../events/emit.js";import{withExclusiveDirectoryLockAsync as V}from"../exclusive-lock.js";import{atomicWriteText as x,ensureDir as T,pathExists as ve}from"../fs-utils.js";import{reconcilePackages as Z}from"../graph/package-reconcile.js";import{readPluginManifest as C}from"../manifest.js";import{bundleSwapLockPath as L}from"../plugin-swap-lock.js";import{pluginsDir as he,userScopeRoot as J}from"../scope.js";import{listInstalledPlugins as ge}from"../resolver.js";import{localGrants as j}from"../grants/mirror.js";import{ProviderError as c}from"./errors.js";const A="[A-Za-z0-9_-]{1,64}",we=new RegExp(`^(${A}):(${A})$`),K=new RegExp(`^${A}$`),$e=3e4,Q=3e4;function X(e){const n=new Set;for(const r of e)if(r.status==="active")for(const{scope:t}of r.resolved_scopes){const o=we.exec(t);o&&o[1]!=="crtr"&&n.add(o[1])}return[...n].sort()}i(X,"providerIdsFromGrants");function v(e){return u(he("user"),e)}i(v,"pluginRoot");function R(){return u(F(),"providers")}i(R,"providersRoot");function Y(e,n){return u(R(),e,`v${n}`)}i(Y,"majorDir");function B(e){if(!K.test(e))throw new c("not_found",`"${e}" is not a provider id`,{param:"provider"})}i(B,"assertId");function E(){const e=q("user").runtime?.issuer;if(!e)throw new c("not_found","provider bundles need a directory-connected runtime");return e.replace(/\/+$/,"")}i(E,"directoryBase");async function ee(e,n){const r=`${E()}/providers/${encodeURIComponent(e)}/plugin${n.version!==void 0?`?version=${n.version}`:""}`;let t;try{t=await fetch(r,{headers:{Accept:"application/x-tar",...n.ifNoneMatch!==void 0?{"If-None-Match":n.ifNoneMatch}:{}},signal:AbortSignal.timeout($e)})}catch(s){return{status:"failed",message:`could not reach ${r}: ${s instanceof Error?s.message:String(s)}`}}if(t.status===304)return n.ifNoneMatch===void 0?{status:"failed",message:`HTTP 304 from ${r} without a conditional request`}:{status:304};if(t.status===404||t.status===410)return await t.body?.cancel().catch(()=>{}),{status:t.status===404?404:410,message:`HTTP ${t.status} from ${r}`};if(t.status<200||t.status>=300)return await t.body?.cancel().catch(()=>{}),{status:"failed",message:`HTTP ${t.status} from ${r}`};let o;try{o=new Uint8Array(await t.arrayBuffer())}catch(s){return{status:"failed",message:`reading ${r} failed: ${s instanceof Error?s.message:String(s)}`}}const a=t.headers.get("etag");return{status:200,raw:o,...a!==null?{etag:a}:{}}}i(ee,"fetchProviderBundle");const I=new WeakSet;class M extends Error{static{i(this,"BundleInvalid")}issues;constructor(n,r){super(n),this.issues=r}}function ne(e,n,r){if(r.provider===void 0)return"the archive carries no provider block";if(r.provider.id!==e)return`the archive is provider "${r.provider.id}", not "${e}"`;if(n!==void 0&&r.provider.major!==n)return`the archive is major ${r.provider.major}, not ${n}`;const t=["hooks","kinds","page_components","memory_extensions"].filter(o=>r[o]!==void 0);if(t.length>0)return`a provider bundle may not carry ${t.join(", ")}`}i(ne,"wrongBundle");function D(e,n,r){m({level:"error",event:"daemon.providers.bundle_invalid",fields:{provider:e,...n!==void 0?{major:n}:{},...r instanceof M?{issues:r.issues}:{}},error:r})}i(D,"logInvalid");function re(e,n,r){m({level:"warn",event:"daemon.providers.bundle_fetch_failed",fields:{provider:e,...n!==void 0?{major:n}:{},message:r}})}i(re,"logFailure");async function te(){return import("../../commands/pkg/plugin-manage.js")}i(te,"pluginManage");const y=new Map,b=i(e=>`${F()}\0${e}`,"installKey");function ye(e){const n=e,r=n?.code??n?.cause?.code;return typeof r=="string"&&/^[A-Z][A-Z0-9_]{1,30}$/.test(r)?`${r} on provider install directory`:e instanceof c&&e.message.includes("HTTP 404")?"directory returned HTTP 404":e instanceof c&&e.message.includes("HTTP 410")?"directory returned HTTP 410":"provider bundle could not be installed"}i(ye,"publicInstallCause");function be(e){if(h(e)===void 0)return y.get(b(e))??{status:"installing"}}i(be,"providerInstallState");function _e(e){return new c("provider_unavailable",`provider "${e}" unavailable: ${be(e)?.error??"bundle installation pending"}`)}i(_e,"unavailableProviderError");function h(e){const n=C(v(e));if(!(n?.provider===void 0||n.transport?.kind!=="http"&&n.transport?.kind!=="machine")&&ve(u(v(e),"commands.json"))){try{if(k(u(v(e),"commands.json")).size===0)return}catch{return}return{provider:n.provider,transport:n.transport.kind==="machine"?{kind:"machine"}:{kind:"http",endpoint:n.transport.endpoint}}}}i(h,"installedManifest");async function N(e,n,r=!1){const t=J();h(e)===void 0&&y.set(b(e),{status:"installing"});try{return T(u(t,"tmp")),await V(L(t,e),async()=>{const o=v(e),a=C(o);if(a!==null&&a.provider===void 0)throw new c("provider_unavailable",`plugin "${e}" is installed and is not the directory's provider bundle`);const s=h(e)!==void 0;if(s&&r)return"unchanged";const f=s&&n?le("user").plugins[e]?.etag:void 0,d=await ee(e,f!==void 0?{ifNoneMatch:f}:{});if(d.status===304)return"unchanged";if(d.status===404||d.status===410)throw new c("not_found",`the directory serves no provider "${e}" (${d.message})`,{param:"provider"});if(d.status==="failed")throw new c("provider_unavailable",`provider "${e}" bundle fetch failed: ${d.message}`);const l=ue(d.raw);if(s&&ce(e,"user",o,l))return fe("user",e,d.etag,{swapped:!1}),"unchanged";const{installPluginArchive:g}=await te();try{await g(e,d.raw,{scope:"user",scopeRootPath:t,root:o,version:l,etag:d.etag,enable:!s,bundle:{endpoint:`${E()}/providers/${encodeURIComponent(e)}/plugin`},transport:{kind:"http",endpoint:E()},accept:i(p=>ne(e,void 0,p),"accept")})}catch(p){D(e,void 0,p);const W=new c("not_found",`provider "${e}" served an invalid bundle: ${p instanceof Error?p.message:String(p)}`,{param:"provider"});throw I.add(W),W}try{G(p=>Z(p))}catch(p){m({level:"error",event:"daemon.providers.docs_reconcile_failed",fields:{provider:e},error:p})}return m({level:"info",event:"daemon.providers.bundle_installed",fields:{provider:e,version:l,replaced:s}}),y.delete(b(e)),s?"updated":"installed"},{timeoutMs:Q,timeoutError:i(()=>new c("provider_unavailable",`timed out waiting for another process replacing plugin "${e}"`),"timeoutError")})}catch(o){throw h(e)===void 0&&y.set(b(e),{status:"install_failed",error:ye(o)}),o instanceof c?o:(m({level:"error",event:"daemon.providers.bundle_install_failed",fields:{provider:e},error:o}),_e(e))}}i(N,"refreshInstalled");async function Je(e){B(e),h(e)===void 0&&await N(e,!1,!0)}i(Je,"ensureProviderBundle");async function Ke(e,n){return B(e),n.version!==void 0&&h(e)?.provider.major!==n.version?H(e,n.version,n.conditional):N(e,n.conditional)}i(Ke,"refreshProviderBundle");async function oe(e,n,r){const{validatePluginArchive:t}=await te(),o=await t(r);if(o.bundle===void 0)throw new M(`provider "${e}" major ${n} bundle is invalid: ${o.issues.map(s=>s.message).join("; ")}`,o.issues);const a=ne(e,n,o.bundle);if(a!==void 0)throw new M(`provider "${e}" major ${n} bundle is invalid: ${a}`,[]);if(o.bundle.transport===void 0)throw new M(`provider "${e}" major ${n} bundle declares no transport`,[]);return o.bundle}i(oe,"validateArchive");function Pe(e){T(e),x(u(e,"retired"),`${new Date().toISOString()}
2
- `),$(u(e,"bundle.tar"),{force:!0}),$(u(e,"etag"),{force:!0})}i(Pe,"retire");function ie(e,n){return new c("provider_version_retired",`provider "${e}" major ${n} is retired`,{param:"version"})}i(ie,"retiredError");async function H(e,n,r){const t=Y(e,n),o=u(t,"bundle.tar"),a=w(o),s=a&&r&&w(u(t,"etag"))?S(u(t,"etag"),"utf8"):void 0,f=await ee(e,{version:n,...s!==void 0?{ifNoneMatch:s}:{}});if(f.status===304)return"unchanged";if(f.status===410)throw Pe(t),m({level:"info",event:"daemon.providers.major_retired",fields:{provider:e,major:n}}),ie(e,n);if(f.status===404)throw new c("not_found",`provider "${e}" never served major ${n}`,{param:"version"});if(f.status==="failed")throw new c("provider_unavailable",`provider "${e}" major ${n} bundle fetch failed: ${f.message}`);try{await oe(e,n,f.raw)}catch(l){D(e,n,l);const g=new c(a?"provider_unavailable":"not_found",l instanceof Error?l.message:String(l),{param:"version"});throw I.add(g),g}T(t),$(u(t,"retired"),{force:!0});const d=a&&Buffer.from(f.raw).equals(S(o));return d||x(o,f.raw),f.etag!==void 0?x(u(t,"etag"),f.etag):$(u(t,"etag"),{force:!0}),d?"unchanged":a?"updated":"installed"}i(H,"refreshPinned");function Se(){const e=[],n=R();if(!w(n))return e;for(const r of z(n)){if(!K.test(r))continue;let t;try{t=z(u(n,r))}catch{continue}for(const o of t){const a=/^v([1-9][0-9]*)$/.exec(o);a&&w(u(n,r,o,"bundle.tar"))&&e.push([r,Number(a[1])])}}return e}i(Se,"cachedMajors");function Ee(e){const n=de(e,{transport:"http",reservedCoreNames:new Set});if(n.manifest===void 0)throw new c("not_found","the provider bundle's commands.json no longer validates");return n.manifest}i(Ee,"readCommands");const _=new Map,O=new Map;function Ie(e,n){const r=k(n),t=`${r.ino}:${r.mtimeMs}:${r.size}`,o=O.get(e);if(o?.stamp===t)return o.commands;const a=Ee(JSON.parse(S(n,"utf8")));return O.set(e,{stamp:t,commands:a}),a}i(Ie,"installedCommands");async function Qe(e,n){B(e);const r=h(e);if(n===void 0||r?.provider.major===n){if(r===void 0)throw new c("not_found",`provider "${e}" has no installed bundle`,{param:"provider"});const l=v(e),g=Ie(e,u(l,"commands.json"));return{id:e,major:r.provider.major,provider:r.provider,commands:g,transport:r.transport,source:"installed",root:l}}if(!Number.isInteger(n)||n<1)throw new c("invalid_request","version must be an integer of at least 1",{param:"version"});const t=Y(e,n);if(w(u(t,"retired")))throw ie(e,n);const o=u(t,"bundle.tar");w(o)||await H(e,n,!1);const a=`${e}/${n}`,s=k(o),f=`${s.mtimeMs}:${s.size}`;let d=_.get(a)?.stamp===f?_.get(a).bundle:void 0;if(d===void 0){try{d=await oe(e,n,new Uint8Array(S(o)))}catch(l){throw D(e,n,l),new c("not_found",`provider "${e}" has no valid bundle for major ${n}`,{param:"version"})}_.set(a,{stamp:f,bundle:d})}return{id:e,major:n,provider:d.provider,commands:d.commands,transport:d.transport.kind==="machine"?{kind:"machine"}:{kind:"http",endpoint:d.transport.endpoint},source:"pinned"}}i(Qe,"resolveProviderBundle");let P=null,U=!1;function Me(e,n){return e?.provider?.id===n&&e.bundle?.endpoint===`${E()}/providers/${encodeURIComponent(n)}/plugin`}i(Me,"isDirectoryBundle");function ae(e){return X(j()).includes(e)}i(ae,"grantNames");async function ke(e){await V(L(J(),e),async()=>{if(!(ae(e)||!Me(C(v(e)),e))){$(v(e),{recursive:!0,force:!0}),pe("user",n=>{delete n.plugins[e]}),me("user",n=>{delete n.plugins[e]}),$(u(R(),e),{recursive:!0,force:!0}),O.delete(e),y.delete(b(e));for(const n of[..._.keys()])n.startsWith(`${e}/`)&&_.delete(n);try{G(n=>Z(n))}catch(n){m({level:"error",event:"daemon.providers.docs_reconcile_failed",fields:{provider:e},error:n})}m({level:"info",event:"daemon.providers.bundle_uninstalled",fields:{provider:e}})}},{timeoutMs:Q,timeoutError:i(()=>new c("provider_unavailable",`timed out waiting for another process replacing plugin "${e}"`),"timeoutError")})}i(ke,"uninstallProvider");async function xe(){if(!j().every(e=>e.status!=="active")){for(const e of ge("user"))if(!(e.manifest.provider===void 0||ae(e.name)))try{await ke(e.name)}catch(n){m({level:"error",event:"daemon.providers.bundle_uninstall_failed",fields:{provider:e.name},error:n})}}}i(xe,"uninstallDisconnected");async function Te(){if(!q("user").runtime?.issuer)return;const e=X(j());for(const n of e)try{await N(n,!0)}catch(r){r instanceof Object&&I.has(r)||re(n,void 0,r instanceof Error?r.message:String(r))}await xe();for(const[n,r]of Se())try{await H(n,r,!0)}catch(t){if(t instanceof c&&t.code==="provider_version_retired"||t instanceof Object&&I.has(t))continue;re(n,r,t instanceof Error?t.message:String(t))}}i(Te,"syncOnce");function Xe(){return P!==null?(U=!0,P):(P=(async()=>{try{do U=!1,await Te();while(U)}finally{P=null}})(),P)}i(Xe,"syncProviderBundles");export{Je as ensureProviderBundle,X as providerIdsFromGrants,be as providerInstallState,Ke as refreshProviderBundle,Qe as resolveProviderBundle,Xe as syncProviderBundles,_e as unavailableProviderError};
1
+ var se=Object.defineProperty;var i=(e,n)=>se(e,"name",{value:n,configurable:!0});import{existsSync as g,readdirSync as z,readFileSync as S,rmSync as $,statSync as k}from"node:fs";import{join as u}from"node:path";import{validateCommandManifest as de}from"../../api/command-manifest/manifest.js";import{crtrHome as F}from"../canvas/paths.js";import{withCanvasWrite as G}from"../canvas/db.js";import{bundleVersion as ue,isInstalledGeneration as ce,recordCheckedGeneration as fe}from"../command-plugins/bundle.js";import{readConfig as q,readState as le,updateConfig as pe,updateState as me}from"../config.js";import{emitEvent as m}from"../events/emit.js";import{withExclusiveDirectoryLockAsync as V}from"../exclusive-lock.js";import{atomicWriteText as x,ensureDir as T,pathExists as ve}from"../fs-utils.js";import{reconcilePackages as Z}from"../graph/package-reconcile.js";import{readPluginManifest as C}from"../manifest.js";import{bundleSwapLockPath as L}from"../plugin-swap-lock.js";import{pluginsDir as he,userScopeRoot as J}from"../scope.js";import{listInstalledPlugins as we}from"../resolver.js";import{localGrants as j}from"../grants/mirror.js";import{ProviderError as c}from"./errors.js";const A="[A-Za-z0-9_-]{1,64}",ge=new RegExp(`^(${A}):(${A})$`),K=new RegExp(`^${A}$`),$e=3e4,Q=3e4;function X(e){const n=new Set;for(const r of e)if(r.status==="active")for(const{scope:t}of r.resolved_scopes){const o=ge.exec(t);o&&o[1]!=="crtr"&&n.add(o[1])}return[...n].sort()}i(X,"providerIdsFromGrants");function v(e){return u(he("user"),e)}i(v,"pluginRoot");function R(){return u(F(),"providers")}i(R,"providersRoot");function Y(e,n){return u(R(),e,`v${n}`)}i(Y,"majorDir");function B(e){if(!K.test(e))throw new c("not_found",`"${e}" is not a provider id`,{param:"provider"})}i(B,"assertId");function E(){const e=q("user").runtime?.issuer;if(!e)throw new c("not_found","provider bundles need a directory-connected runtime");return e.replace(/\/+$/,"")}i(E,"directoryBase");async function ee(e,n){const r=`${E()}/providers/${encodeURIComponent(e)}/plugin${n.version!==void 0?`?version=${n.version}`:""}`;let t;try{t=await fetch(r,{headers:{Accept:"application/x-tar",...n.ifNoneMatch!==void 0?{"If-None-Match":n.ifNoneMatch}:{}},signal:AbortSignal.timeout($e)})}catch(s){return{status:"failed",message:`could not reach ${r}: ${s instanceof Error?s.message:String(s)}`}}if(t.status===304)return n.ifNoneMatch===void 0?{status:"failed",message:`HTTP 304 from ${r} without a conditional request`}:{status:304};if(t.status===404||t.status===410)return await t.body?.cancel().catch(()=>{}),{status:t.status===404?404:410,message:`HTTP ${t.status} from ${r}`};if(t.status<200||t.status>=300)return await t.body?.cancel().catch(()=>{}),{status:"failed",message:`HTTP ${t.status} from ${r}`};let o;try{o=new Uint8Array(await t.arrayBuffer())}catch(s){return{status:"failed",message:`reading ${r} failed: ${s instanceof Error?s.message:String(s)}`}}const a=t.headers.get("etag");return{status:200,raw:o,...a!==null?{etag:a}:{}}}i(ee,"fetchProviderBundle");const I=new WeakSet;class M extends Error{static{i(this,"BundleInvalid")}issues;constructor(n,r){super(n),this.issues=r}}function ne(e,n,r){if(r.provider===void 0)return"the archive carries no provider block";if(r.provider.id!==e)return`the archive is provider "${r.provider.id}", not "${e}"`;if(n!==void 0&&r.provider.major!==n)return`the archive is major ${r.provider.major}, not ${n}`;const t=["hooks","kinds","page_components","memory_extensions"].filter(o=>r[o]!==void 0);if(t.length>0)return`a provider bundle may not carry ${t.join(", ")}`}i(ne,"wrongBundle");function D(e,n,r){m({level:"error",event:"daemon.providers.bundle_invalid",fields:{provider:e,...n!==void 0?{major:n}:{},...r instanceof M?{issues:r.issues}:{}},error:r})}i(D,"logInvalid");function re(e,n,r){m({level:"warn",event:"daemon.providers.bundle_fetch_failed",fields:{provider:e,...n!==void 0?{major:n}:{},message:r}})}i(re,"logFailure");async function te(){return import("../../commands/pkg/plugin-manage.js")}i(te,"pluginManage");const y=new Map,b=i(e=>`${F()}\0${e}`,"installKey");function ye(e){const n=e,r=n?.code??n?.cause?.code;return typeof r=="string"&&/^[A-Z][A-Z0-9_]{1,30}$/.test(r)?`${r} on provider install directory`:e instanceof c&&e.message.includes("HTTP 404")?"directory returned HTTP 404":e instanceof c&&e.message.includes("HTTP 410")?"directory returned HTTP 410":"provider bundle could not be installed"}i(ye,"publicInstallCause");function be(e){if(h(e)===void 0)return y.get(b(e))??{status:"installing"}}i(be,"providerInstallState");function _e(e){return new c("provider_unavailable",`provider "${e}" unavailable: ${be(e)?.error??"bundle installation pending"}`)}i(_e,"unavailableProviderError");function h(e){const n=C(v(e));if(!(n?.provider===void 0||n.transport?.kind!=="http"&&n.transport?.kind!=="machine")&&ve(u(v(e),"commands.json"))){try{if(k(u(v(e),"commands.json")).size===0)return}catch{return}return{provider:n.provider,transport:n.transport.kind==="machine"?{kind:"machine"}:{kind:"http",endpoint:n.transport.endpoint}}}}i(h,"installedManifest");async function N(e,n,r=!1){const t=J();h(e)===void 0&&y.set(b(e),{status:"installing"});try{return T(u(t,"tmp")),await V(L(t,e),async()=>{const o=v(e),a=C(o);if(a!==null&&a.provider===void 0)throw new c("provider_unavailable",`plugin "${e}" is installed and is not the directory's provider bundle`);const s=h(e)!==void 0;if(s&&r)return"unchanged";const f=s&&n?le("user").plugins[e]?.etag:void 0,d=await ee(e,f!==void 0?{ifNoneMatch:f}:{});if(d.status===304)return"unchanged";if(d.status===404||d.status===410)throw new c("not_found",`the directory serves no provider "${e}" (${d.message})`,{param:"provider"});if(d.status==="failed")throw new c("provider_unavailable",`provider "${e}" bundle fetch failed: ${d.message}`);const l=ue(d.raw);if(s&&ce(e,"user",o,l))return fe("user",e,d.etag,{swapped:!1}),"unchanged";const{installPluginArchive:w}=await te();try{await w(e,d.raw,{scope:"user",scopeRootPath:t,root:o,version:l,etag:d.etag,enable:!s,bundle:{endpoint:`${E()}/providers/${encodeURIComponent(e)}/plugin`},transport:{kind:"http",endpoint:E()},accept:i(p=>ne(e,void 0,p),"accept")})}catch(p){D(e,void 0,p);const W=new c("not_found",`provider "${e}" served an invalid bundle: ${p instanceof Error?p.message:String(p)}`,{param:"provider"});throw I.add(W),W}try{await G(async p=>await Z(p))}catch(p){m({level:"error",event:"daemon.providers.docs_reconcile_failed",fields:{provider:e},error:p})}return m({level:"info",event:"daemon.providers.bundle_installed",fields:{provider:e,version:l,replaced:s}}),y.delete(b(e)),s?"updated":"installed"},{timeoutMs:Q,timeoutError:i(()=>new c("provider_unavailable",`timed out waiting for another process replacing plugin "${e}"`),"timeoutError")})}catch(o){throw h(e)===void 0&&y.set(b(e),{status:"install_failed",error:ye(o)}),o instanceof c?o:(m({level:"error",event:"daemon.providers.bundle_install_failed",fields:{provider:e},error:o}),_e(e))}}i(N,"refreshInstalled");async function Je(e){B(e),h(e)===void 0&&await N(e,!1,!0)}i(Je,"ensureProviderBundle");async function Ke(e,n){return B(e),n.version!==void 0&&h(e)?.provider.major!==n.version?H(e,n.version,n.conditional):N(e,n.conditional)}i(Ke,"refreshProviderBundle");async function oe(e,n,r){const{validatePluginArchive:t}=await te(),o=await t(r);if(o.bundle===void 0)throw new M(`provider "${e}" major ${n} bundle is invalid: ${o.issues.map(s=>s.message).join("; ")}`,o.issues);const a=ne(e,n,o.bundle);if(a!==void 0)throw new M(`provider "${e}" major ${n} bundle is invalid: ${a}`,[]);if(o.bundle.transport===void 0)throw new M(`provider "${e}" major ${n} bundle declares no transport`,[]);return o.bundle}i(oe,"validateArchive");function Pe(e){T(e),x(u(e,"retired"),`${new Date().toISOString()}
2
+ `),$(u(e,"bundle.tar"),{force:!0}),$(u(e,"etag"),{force:!0})}i(Pe,"retire");function ie(e,n){return new c("provider_version_retired",`provider "${e}" major ${n} is retired`,{param:"version"})}i(ie,"retiredError");async function H(e,n,r){const t=Y(e,n),o=u(t,"bundle.tar"),a=g(o),s=a&&r&&g(u(t,"etag"))?S(u(t,"etag"),"utf8"):void 0,f=await ee(e,{version:n,...s!==void 0?{ifNoneMatch:s}:{}});if(f.status===304)return"unchanged";if(f.status===410)throw Pe(t),m({level:"info",event:"daemon.providers.major_retired",fields:{provider:e,major:n}}),ie(e,n);if(f.status===404)throw new c("not_found",`provider "${e}" never served major ${n}`,{param:"version"});if(f.status==="failed")throw new c("provider_unavailable",`provider "${e}" major ${n} bundle fetch failed: ${f.message}`);try{await oe(e,n,f.raw)}catch(l){D(e,n,l);const w=new c(a?"provider_unavailable":"not_found",l instanceof Error?l.message:String(l),{param:"version"});throw I.add(w),w}T(t),$(u(t,"retired"),{force:!0});const d=a&&Buffer.from(f.raw).equals(S(o));return d||x(o,f.raw),f.etag!==void 0?x(u(t,"etag"),f.etag):$(u(t,"etag"),{force:!0}),d?"unchanged":a?"updated":"installed"}i(H,"refreshPinned");function Se(){const e=[],n=R();if(!g(n))return e;for(const r of z(n)){if(!K.test(r))continue;let t;try{t=z(u(n,r))}catch{continue}for(const o of t){const a=/^v([1-9][0-9]*)$/.exec(o);a&&g(u(n,r,o,"bundle.tar"))&&e.push([r,Number(a[1])])}}return e}i(Se,"cachedMajors");function Ee(e){const n=de(e,{transport:"http",reservedCoreNames:new Set});if(n.manifest===void 0)throw new c("not_found","the provider bundle's commands.json no longer validates");return n.manifest}i(Ee,"readCommands");const _=new Map,O=new Map;function Ie(e,n){const r=k(n),t=`${r.ino}:${r.mtimeMs}:${r.size}`,o=O.get(e);if(o?.stamp===t)return o.commands;const a=Ee(JSON.parse(S(n,"utf8")));return O.set(e,{stamp:t,commands:a}),a}i(Ie,"installedCommands");async function Qe(e,n){B(e);const r=h(e);if(n===void 0||r?.provider.major===n){if(r===void 0)throw new c("not_found",`provider "${e}" has no installed bundle`,{param:"provider"});const l=v(e),w=Ie(e,u(l,"commands.json"));return{id:e,major:r.provider.major,provider:r.provider,commands:w,transport:r.transport,source:"installed",root:l}}if(!Number.isInteger(n)||n<1)throw new c("invalid_request","version must be an integer of at least 1",{param:"version"});const t=Y(e,n);if(g(u(t,"retired")))throw ie(e,n);const o=u(t,"bundle.tar");g(o)||await H(e,n,!1);const a=`${e}/${n}`,s=k(o),f=`${s.mtimeMs}:${s.size}`;let d=_.get(a)?.stamp===f?_.get(a).bundle:void 0;if(d===void 0){try{d=await oe(e,n,new Uint8Array(S(o)))}catch(l){throw D(e,n,l),new c("not_found",`provider "${e}" has no valid bundle for major ${n}`,{param:"version"})}_.set(a,{stamp:f,bundle:d})}return{id:e,major:n,provider:d.provider,commands:d.commands,transport:d.transport.kind==="machine"?{kind:"machine"}:{kind:"http",endpoint:d.transport.endpoint},source:"pinned"}}i(Qe,"resolveProviderBundle");let P=null,U=!1;function Me(e,n){return e?.provider?.id===n&&e.bundle?.endpoint===`${E()}/providers/${encodeURIComponent(n)}/plugin`}i(Me,"isDirectoryBundle");async function ae(e){return X(await j()).includes(e)}i(ae,"grantNames");async function ke(e){await V(L(J(),e),async()=>{if(!(await ae(e)||!Me(C(v(e)),e))){$(v(e),{recursive:!0,force:!0}),pe("user",n=>{delete n.plugins[e]}),me("user",n=>{delete n.plugins[e]}),$(u(R(),e),{recursive:!0,force:!0}),O.delete(e),y.delete(b(e));for(const n of[..._.keys()])n.startsWith(`${e}/`)&&_.delete(n);try{await G(async n=>await Z(n))}catch(n){m({level:"error",event:"daemon.providers.docs_reconcile_failed",fields:{provider:e},error:n})}m({level:"info",event:"daemon.providers.bundle_uninstalled",fields:{provider:e}})}},{timeoutMs:Q,timeoutError:i(()=>new c("provider_unavailable",`timed out waiting for another process replacing plugin "${e}"`),"timeoutError")})}i(ke,"uninstallProvider");async function xe(){if(!(await j()).every(e=>e.status!=="active")){for(const e of we("user"))if(!(e.manifest.provider===void 0||await ae(e.name)))try{await ke(e.name)}catch(n){m({level:"error",event:"daemon.providers.bundle_uninstall_failed",fields:{provider:e.name},error:n})}}}i(xe,"uninstallDisconnected");async function Te(){if(!q("user").runtime?.issuer)return;const e=X(await j());for(const n of e)try{await N(n,!0)}catch(r){r instanceof Object&&I.has(r)||re(n,void 0,r instanceof Error?r.message:String(r))}await xe();for(const[n,r]of Se())try{await H(n,r,!0)}catch(t){if(t instanceof c&&t.code==="provider_version_retired"||t instanceof Object&&I.has(t))continue;re(n,r,t instanceof Error?t.message:String(t))}}i(Te,"syncOnce");function Xe(){return P!==null?(U=!0,P):(P=(async()=>{try{do U=!1,await Te();while(U)}finally{P=null}})(),P)}i(Xe,"syncProviderBundles");export{Je as ensureProviderBundle,X as providerIdsFromGrants,be as providerInstallState,Ke as refreshProviderBundle,Qe as resolveProviderBundle,Xe as syncProviderBundles,_e as unavailableProviderError};
@@ -64,9 +64,9 @@ export interface ProviderResponseContext {
64
64
  status: number;
65
65
  headers: Record<string, string | string[] | undefined>;
66
66
  }
67
- export declare function onProviderResponse(context: ProviderResponseContext): string | undefined;
67
+ export declare function onProviderResponse(context: ProviderResponseContext): Promise<string | undefined>;
68
68
  export declare function mapProviderResponse(status: number, body: unknown, headers: Record<string, string | string[] | undefined>, approved?: boolean): ProviderError;
69
69
  /** `Crtr-Caller` for a provider HTTP call: the calling node and run, that node's profile, and this machine once the runtime is joined (`ownMachineId`
70
70
  * throws on an unjoined runtime). Empty fields are omitted; no field means no header. Never carries a token or scopes. */
71
- export declare function crtrCallerHeader(caller: ProviderCaller): Record<string, string>;
71
+ export declare function crtrCallerHeader(caller: ProviderCaller): Promise<Record<string, string>>;
72
72
  export declare function callProvider(caller: ProviderCaller, rawInput: ProviderCallInput, request: ProviderRequest): Promise<ProviderCallResult>;
@@ -1 +1 @@
1
- var re=Object.defineProperty;var v=(e,r)=>re(e,"name",{value:r,configurable:!0});import{validateDeclaredResult as I}from"../../api/command-manifest/result.js";import{callerAllows as te,requireGroup as oe}from"../../daemon/api/handlers/providers.js";import{terminalGrant as ne}from"../grants/mirror.js";import{UNCAPPED_GRANTEE as ie}from"../usage/ledger.js";import{listInstalledPlugins as se}from"../resolver.js";import{ProviderError as p}from"./errors.js";import{resolveProviderRef as ae}from"./roots.js";import{providerToolPath as de}from"../plugin-objects-manifest.js";import{ensureProviderBundle as ue,refreshProviderBundle as le,resolveProviderBundle as U,unavailableProviderError as pe}from"./bundles.js";import{prepareFileCall as ce,resignForRetry as G,resolveFileResult as z}from"./files.js";import{consumeApproval as fe,requireProviderApproval as me}from"./approval.js";import{outboundToken as ve}from"./mint.js";import{discardFile as ge}from"./token-cache.js";import{registerProviderCall as he}from"./inflight.js";import{buildRequestPlan as we}from"../command-plugins/transport/http-plan.js";import{sendProviderRequest as be,ProviderTransportError as ye}from"./request.js";import{acceptProviderReceipt as _e}from"./receipts.js";import{writeProviderAudit as Ae}from"./audit.js";import{selectDevice as je,sendDeviceCall as ke,deviceFailure as Pe,deviceUnreachable as Q,DEFAULT_DEVICE_REQUEST_MS as qe}from"./device.js";import{isLibsSearch as V,wantsBundling as Ee,callLibsSearch as $e,bundleExec as Ce,mapLibOutcome as Re,reportLibCalls as Se}from"./device-libs.js";import{directoryIssuer as Ne,ownMachineId as Te}from"../peer/directory.js";import{formatCrtrCaller as K}from"../command-plugins/caller-header.js";import{getNode as De}from"../canvas/canvas.js";import{envelopeForProviderCaller as Fe}from"../peer/envelope.js";function W(e){const r=[],s=v((c,t,o)=>{const a=[...t,c.name],d=o||c.tier==="hidden";if(c.kind==="branch"){for(const m of c.children)s(m,a,d);return}const A=de(e.roots.length,a);r.push({tool:A,leaf:c,hidden:d})},"walk");for(const c of e.roots)s(c,[],!1);return r}v(W,"providerLeaves");function X(e){if(e.kind!=="branch")return null;const r=[];for(const h of e.children)if(h.kind==="branch"){const j=X(h);j&&r.push(j)}else if("group"in h&&h.group){const{kind:j,name:u,description:_,whenToUse:g,tier:w,summary:P,params:n,output:k,effects:i,group:b}=h;r.push({kind:j,name:u,description:_,whenToUse:g,...w===void 0?{}:{tier:w},summary:P,params:n,output:k,effects:i,group:b})}if(r.length===0)return null;const{kind:s,name:c,description:t,whenToUse:o,tier:a,summary:d,model:A,rootEntry:m}=e;return{kind:s,name:c,description:t,whenToUse:o,...a===void 0?{}:{tier:a},summary:d,...A===void 0?{}:{model:A},...m===void 0?{}:{rootEntry:m},children:r}}v(X,"providerHelpBranch");async function mr(e,r){const s=await U(r),c=W(s.commands),t=se("user").find(o=>o.name===r)?.manifest.description??r;return{provider:r,status:"available",major:s.major,display_name:t,transport:s.transport.kind,groups:s.provider.groups.filter(o=>te(e,`${r}:${o.group}`)).map(o=>({group:o.group,leaves:c.filter(({leaf:a,hidden:d})=>!d&&a.group===o.group).map(({tool:a,leaf:d})=>({tool:a,description:d.description,summary:d.summary,params:d.params,output:d.output}))})),commands:s.commands.roots.flatMap(o=>{const a=X(o);return a?[a]:[]})}}v(mr,"providerTools");function Me(e){return _e(e.headers["crtr-receipt"],e)}v(Me,"onProviderResponse");function Oe(e){if(e.class==="person"){const r=ne()?.sub;if(!r)throw new p("grant_revoked","This machine has no active Northlight grant for your terminal. Run `crtr sys join` again from /account/machines.");return{sub:r,grantee:r}}if(!e.sub||!e.grantee)throw new p("grant_revoked","the caller has no active grant");return{sub:e.sub,grantee:e.grantee}}v(Oe,"identity");function Ie(e,r){return[`${e.id}:${r.group}`]}v(Ie,"callScope");function Ue(e,r){const s=W(e.commands).find(c=>c.tool===r);if(!s)throw new p("not_found",`tool "${r}" is not in provider "${e.id}"`,{param:"tool"});if(!s.leaf.group)throw new p("not_found",`tool "${r}" has no group`,{param:"tool"});return s.leaf}v(Ue,"leafFor");function B(e){if(!e||typeof e!="object"||Array.isArray(e))return{};const r=e.error;return!r||typeof r!="object"||Array.isArray(r)?{}:r}v(B,"errorBody");function Be(e){const r=Array.isArray(e)?e[0]:e;if(!r)return;const s=Number(r);if(Number.isFinite(s)&&s>=0)return s;const c=Date.parse(r);return Number.isFinite(c)?Math.max(0,Math.ceil((c-Date.now())/1e3)):void 0}v(Be,"retryAfter");function D(e,r,s,c=!1){const t=B(r),o=typeof t.code=="string"?t.code:void 0,a=typeof t.message=="string"?t.message:`provider answered HTTP ${e}`,d=typeof t.field=="string"?t.field:void 0,m={origin:"provider",details:{code:o??null,message:a,...d?{field:d}:{},...typeof t.next=="string"?{next:t.next}:{},...t.received!==void 0?{received:t.received}:{},status:e},...d?{param:d}:{}};return e===429?new p("provider_rate_limited",a,{...m,retry_after_s:Be(s["retry-after"])}):e===401||e>=500?new p("provider_unavailable",a,m):e===403&&o==="provider_refused"?new p("provider_refused",a,m):e===403&&o==="approval_required"?new p("provider_error",c?"provider asked for approval again":"provider approval question is invalid",{...m,status:e}):new p("provider_error",a,{...m,status:e})}v(D,"mapProviderResponse");function Y(e,r){return JSON.stringify({major:e.major,endpoint:e.transport.kind==="http"?e.transport.endpoint:null,baseUrl:e.commands.baseUrl??null,rest:r.rest,params:r.params,output:r.output})}v(Y,"approvalShape");function Le(e){const r=e.origin!==void 0?K({node:e.origin.node??void 0,run:e.origin.run??void 0,machine:e.origin.machine}):K({node:e.node_id??void 0,run:e.run_id??void 0,profile:e.node_id?De(e.node_id)?.profile_id??void 0:void 0,machine:Ne()!==null?Te():void 0});return r===""?{}:{"Crtr-Caller":r}}v(Le,"crtrCallerHeader");async function vr(e,r,s){const c=ae(r.provider);if(c===null)throw new p("not_found",`provider "${r.provider}" is not available`,{param:"provider"});const t={...r,provider:c},o=new AbortController,a=v(()=>o.abort(s.signal.reason),"abort");s.signal.aborted?a():s.signal.addEventListener("abort",a,{once:!0});let d=s.requestId;const A=he({request_id:d,run_id:e.run_id,node_id:e.node_id,controller:o});let m,h,j,u,_,g,w,P="allowed";try{try{await ue(t.provider)}catch{throw pe(t.provider)}let n=await U(t.provider,t.version),k=!1,i,b,q,L=!1,J=!1,F,H=0;for(;;){const y=Ue(n,t.tool);if(j=`${n.id}:${y.group}`,oe(e,n.id,y.group),n.transport.kind!=="machine"&&t.machine!==void 0)throw new p("invalid_argument",`provider "${n.id}" is not served by a device, so it takes no machine`,{param:"machine"});n.transport.kind==="machine"&&F===void 0&&(F=await je(t.machine,void 0,{newest:V(n.major,t.tool)}),H=Date.now()+(n.commands.timeouts?.requestMs??qe));let M=null;if(t.approval&&!L){const l=fe(e,t,Y(n,y));q=l.option,M=l.prepared,w=t.approval,d=l.requestId,L=!0}const C={params:y.params.filter(l=>"type"in l&&l.type==="file").map(l=>l.name),output:y.output.find(l=>l.type==="file")?.name??null},x=JSON.stringify(C);if(b!==void 0&&b!==x)throw new p("provider_bad_response","the refreshed manifest changed the tool file contract",{origin:"provider",details:{status:409,message:"manifest_stale changed the tool file contract"}});b=x,M&&(i=await G(e,C,t.arguments,M,{signal:o.signal})),i??=await ce(e,C,t.arguments,{signal:o.signal});const{sub:O,grantee:R}=Oe(e);if(n.transport.kind==="machine"){const l=await Je(e,n,t,y,i,{sub:O,requestId:d,deadlineAt:H,signal:o.signal,machine:F});return g=l.responder,m=l.cleanup,{status:200,body:l.result}}const E=await ve({audience:n.transport.endpoint,sub:O,grantee:R,initiating_app:R,scope:Ie(n,y)},{signal:o.signal});u=E.jti;const Z={registration:{name:n.id,endpoint:n.transport.endpoint},...n.commands.baseUrl?{baseUrl:n.commands.baseUrl}:{},...n.commands.timeouts?{timeouts:n.commands.timeouts}:{},params:y.params,rest:y.rest,output:y.output,commandPath:[n.id,...t.tool.split(" ")]},ee=we(Z,i.arguments,void 0,{authorization:`Bearer ${E.access_token}`,requestId:d,fileMode:"pass-through",extraHeaders:{...e.run_id?{"Crtr-Run-Id":e.run_id}:{},...Le(e),...q?{"Crtr-Approval":q}:{},...i.headers}});h??=Date.now()+(n.commands.timeouts?.requestMs??3e4);let f;try{if(f=await be(ee,{connectMs:n.commands.timeouts?.connectMs,requestMs:n.commands.timeouts?.requestMs,deadlineAt:h,signal:o.signal}),o.signal.aborted)throw o.signal.reason??new Error("provider call aborted")}catch(l){throw o.signal.aborted?o.signal.reason??l:l instanceof ye?new p("provider_unavailable",l.message,{origin:"provider",details:{status:null,code:l.kind}}):l}if(_??=Me({provider:n.id,tool:t.tool,request_id:d,run_id:e.run_id,sub:O,grantee:R,payer:E.payer,ledger_grantee:e.class==="person"?ie:R,jti:E.jti,status:f.status,headers:f.headers}),g=f.headers["crtr-responder"],f.status===401&&ge(E.key),f.status>=200&&f.status<300){const l=f.body;if(!l||typeof l!="object"||Array.isArray(l))throw new p("provider_bad_response","provider result is not a JSON object",{origin:"provider",details:{status:f.status,message:"provider result is not a JSON object"}});let N;try{N=await z(e,i,l,{signal:o.signal})}catch($){throw $ instanceof p&&$.code==="provider_error"?new p("provider_bad_response",$.message,{origin:"provider",details:{status:f.status,message:$.message}}):$}m=N.cleanup;const T=I(y.output,N.result);if(T)throw new p("provider_bad_response",`provider result has an invalid output field "${T.field}"`,{origin:"provider",param:T.field,details:{status:f.status,...T}});if(o.signal.aborted)throw o.signal.reason??new Error("provider call aborted");return{status:200,body:N.result}}const S=B(f.body);if(f.status===403&&S.code==="approval_required"&&!q&&!J){J=!0;const l=await me(e,t,d,S.question,o.signal,Y(n,y),i);if(w=l.questionId,q=l.option,i=await G(e,C,t.arguments,i,{signal:o.signal}),h=void 0,o.signal.aborted)throw new p("user_denied","the approval wait was canceled");continue}if(f.status===403&&S.code==="approval_required"&&q)throw D(f.status,f.body,f.headers,!0);if(f.status!==401&&S.manifest_stale===!0&&!k){k=!0,await le(n.id,{conditional:!1,...t.version===void 0?{}:{version:t.version}}),n=await U(n.id,t.version);continue}throw D(f.status,f.body,f.headers,!!q)}}catch(n){throw n instanceof p&&n.question_id&&(w=n.question_id),g===void 0&&n instanceof p&&typeof n.responder=="string"&&(g=n.responder),P=`refused:${n instanceof p?n.code:"server_error"}`,m?.(),n}finally{try{Ae({request_id:d,caller:e,provider:t.provider,tool:t.tool,scope_checked:j,outcome:P,jti:u,receipt_id:_,responder:g,question_id:w})}finally{A()}s.signal.removeEventListener("abort",a)}}v(vr,"callProvider");async function Je(e,r,s,c,t,o){const{machine:a}=o,d=Fe(e,o.sub),A={machine:a,envelope:d,signal:o.signal,deadlineAt:o.deadlineAt,mapFailure:D};if(V(r.major,s.tool)){const i=await $e(A,t.arguments,r.major),b=I(c.output,i);if(b)throw new p("provider_bad_response",`the libraries result has an invalid output field "${b.field}"`,{origin:"provider",param:b.field,details:{status:200,...b}});return{result:i,responder:void 0,cleanup:void 0}}let m=t.arguments,h=null,j="";if(Ee(r.major,s.tool,t.arguments)){const i=await Ce(A,t.arguments,r.major);if(o.deadlineAt-Date.now()<=0)throw Q(a,"timeout","");i!==null&&(m=i.arguments,h=i.services,j=i.release)}const u=await ke(a,{tool:s.tool,arguments:m,version:r.major,requestId:o.requestId,runId:e.run_id,deadlineAt:o.deadlineAt,upload:t.upload===null?null:{id:t.upload.upload_id,link:t.upload.upload_link}},d,o.signal);if(o.signal.aborted)throw o.signal.reason??new Error("provider call aborted");if("unreachable"in u)throw Q(a,u.unreachable.reason,u.unreachable.message);const _=u.headers["crtr-responder"],g=B(u.body);if(u.status<200||u.status>=300){const i=Pe(a,u.status,typeof g.code=="string"?g.code:void 0,typeof g.message=="string"?g.message:void 0,u.body),b=i===null&&u.status>=500&&typeof g.code=="string"?new p("provider_error",typeof g.message=="string"?g.message:`the device answered HTTP ${u.status}`,{origin:"runtime",status:u.status,details:{code:g.code,status:u.status}}):null;throw Object.assign(i??b??D(u.status,u.body,u.headers),{responder:_})}const w=u.body&&typeof u.body=="object"&&!Array.isArray(u.body)?u.body.result:void 0;if(!w||typeof w!="object"||Array.isArray(w))throw Object.assign(new p("provider_bad_response","the device result is not a JSON object",{origin:"provider",details:{status:u.status,message:"the device result is not a JSON object"}}),{responder:_});let P=w;if(h!==null){const i=Re(P,h);if(Se(a,d,j,i.calls),"error"in i)throw Object.assign(i.error,{responder:_});P=i.result}let n;try{n=await z(e,t,P,{signal:o.signal})}catch(i){throw i instanceof p&&i.code==="provider_error"?Object.assign(new p("provider_bad_response",i.message,{origin:"provider",details:{status:u.status,message:i.message}}),{responder:_}):i}const k=I(c.output,n.result);if(k)throw n.cleanup?.(),Object.assign(new p("provider_bad_response",`the device result has an invalid output field "${k.field}"`,{origin:"provider",param:k.field,details:{status:u.status,...k}}),{responder:_});return{result:n.result,responder:_,cleanup:n.cleanup}}v(Je,"callDevice");export{vr as callProvider,Le as crtrCallerHeader,D as mapProviderResponse,Me as onProviderResponse,W as providerLeaves,mr as providerTools};
1
+ var re=Object.defineProperty;var v=(e,r)=>re(e,"name",{value:r,configurable:!0});import{validateDeclaredResult as I}from"../../api/command-manifest/result.js";import{callerAllows as te,requireGroup as oe}from"../../daemon/api/handlers/providers.js";import{terminalGrant as ie}from"../grants/mirror.js";import{UNCAPPED_GRANTEE as ne}from"../usage/ledger.js";import{listInstalledPlugins as se}from"../resolver.js";import{ProviderError as p}from"./errors.js";import{resolveProviderRef as ae}from"./roots.js";import{providerToolPath as de}from"../plugin-objects-manifest.js";import{ensureProviderBundle as ue,refreshProviderBundle as le,resolveProviderBundle as U,unavailableProviderError as pe}from"./bundles.js";import{prepareFileCall as ce,resignForRetry as G,resolveFileResult as z}from"./files.js";import{consumeApproval as fe,requireProviderApproval as me}from"./approval.js";import{outboundToken as ve}from"./mint.js";import{discardFile as ge}from"./token-cache.js";import{registerProviderCall as he}from"./inflight.js";import{buildRequestPlan as we}from"../command-plugins/transport/http-plan.js";import{sendProviderRequest as be,ProviderTransportError as ye}from"./request.js";import{acceptProviderReceipt as _e}from"./receipts.js";import{writeProviderAudit as Ae}from"./audit.js";import{selectDevice as je,sendDeviceCall as ke,deviceFailure as Pe,deviceUnreachable as Q,DEFAULT_DEVICE_REQUEST_MS as qe}from"./device.js";import{isLibsSearch as V,wantsBundling as Ee,callLibsSearch as $e,bundleExec as Ce,mapLibOutcome as Re,reportLibCalls as Se}from"./device-libs.js";import{directoryIssuer as Ne,ownMachineId as Te}from"../peer/directory.js";import{formatCrtrCaller as K}from"../command-plugins/caller-header.js";import{getNode as De}from"../canvas/canvas.js";import{envelopeForProviderCaller as Fe}from"../peer/envelope.js";function W(e){const r=[],s=v((c,t,o)=>{const a=[...t,c.name],d=o||c.tier==="hidden";if(c.kind==="branch"){for(const m of c.children)s(m,a,d);return}const A=de(e.roots.length,a);r.push({tool:A,leaf:c,hidden:d})},"walk");for(const c of e.roots)s(c,[],!1);return r}v(W,"providerLeaves");function X(e){if(e.kind!=="branch")return null;const r=[];for(const h of e.children)if(h.kind==="branch"){const j=X(h);j&&r.push(j)}else if("group"in h&&h.group){const{kind:j,name:u,description:_,whenToUse:g,tier:w,summary:P,params:i,output:k,effects:n,group:b}=h;r.push({kind:j,name:u,description:_,whenToUse:g,...w===void 0?{}:{tier:w},summary:P,params:i,output:k,effects:n,group:b})}if(r.length===0)return null;const{kind:s,name:c,description:t,whenToUse:o,tier:a,summary:d,model:A,rootEntry:m}=e;return{kind:s,name:c,description:t,whenToUse:o,...a===void 0?{}:{tier:a},summary:d,...A===void 0?{}:{model:A},...m===void 0?{}:{rootEntry:m},children:r}}v(X,"providerHelpBranch");async function mr(e,r){const s=await U(r),c=W(s.commands),t=se("user").find(o=>o.name===r)?.manifest.description??r;return{provider:r,status:"available",major:s.major,display_name:t,transport:s.transport.kind,groups:s.provider.groups.filter(o=>te(e,`${r}:${o.group}`)).map(o=>({group:o.group,leaves:c.filter(({leaf:a,hidden:d})=>!d&&a.group===o.group).map(({tool:a,leaf:d})=>({tool:a,description:d.description,summary:d.summary,params:d.params,output:d.output}))})),commands:s.commands.roots.flatMap(o=>{const a=X(o);return a?[a]:[]})}}v(mr,"providerTools");async function Me(e){return await _e(e.headers["crtr-receipt"],e)}v(Me,"onProviderResponse");async function Oe(e){if(e.class==="person"){const r=(await ie())?.sub;if(!r)throw new p("grant_revoked","This machine has no active Northlight grant for your terminal. Run `crtr sys join` again from /account/machines.");return{sub:r,grantee:r}}if(!e.sub||!e.grantee)throw new p("grant_revoked","the caller has no active grant");return{sub:e.sub,grantee:e.grantee}}v(Oe,"identity");function Ie(e,r){return[`${e.id}:${r.group}`]}v(Ie,"callScope");function Ue(e,r){const s=W(e.commands).find(c=>c.tool===r);if(!s)throw new p("not_found",`tool "${r}" is not in provider "${e.id}"`,{param:"tool"});if(!s.leaf.group)throw new p("not_found",`tool "${r}" has no group`,{param:"tool"});return s.leaf}v(Ue,"leafFor");function B(e){if(!e||typeof e!="object"||Array.isArray(e))return{};const r=e.error;return!r||typeof r!="object"||Array.isArray(r)?{}:r}v(B,"errorBody");function Be(e){const r=Array.isArray(e)?e[0]:e;if(!r)return;const s=Number(r);if(Number.isFinite(s)&&s>=0)return s;const c=Date.parse(r);return Number.isFinite(c)?Math.max(0,Math.ceil((c-Date.now())/1e3)):void 0}v(Be,"retryAfter");function D(e,r,s,c=!1){const t=B(r),o=typeof t.code=="string"?t.code:void 0,a=typeof t.message=="string"?t.message:`provider answered HTTP ${e}`,d=typeof t.field=="string"?t.field:void 0,m={origin:"provider",details:{code:o??null,message:a,...d?{field:d}:{},...typeof t.next=="string"?{next:t.next}:{},...t.received!==void 0?{received:t.received}:{},status:e},...d?{param:d}:{}};return e===429?new p("provider_rate_limited",a,{...m,retry_after_s:Be(s["retry-after"])}):e===401||e>=500?new p("provider_unavailable",a,m):e===403&&o==="provider_refused"?new p("provider_refused",a,m):e===403&&o==="approval_required"?new p("provider_error",c?"provider asked for approval again":"provider approval question is invalid",{...m,status:e}):new p("provider_error",a,{...m,status:e})}v(D,"mapProviderResponse");function Y(e,r){return JSON.stringify({major:e.major,endpoint:e.transport.kind==="http"?e.transport.endpoint:null,baseUrl:e.commands.baseUrl??null,rest:r.rest,params:r.params,output:r.output})}v(Y,"approvalShape");async function Le(e){const r=e.origin!==void 0?K({node:e.origin.node??void 0,run:e.origin.run??void 0,machine:e.origin.machine}):K({node:e.node_id??void 0,run:e.run_id??void 0,profile:e.node_id?(await De(e.node_id))?.profile_id??void 0:void 0,machine:Ne()!==null?Te():void 0});return r===""?{}:{"Crtr-Caller":r}}v(Le,"crtrCallerHeader");async function vr(e,r,s){const c=ae(r.provider);if(c===null)throw new p("not_found",`provider "${r.provider}" is not available`,{param:"provider"});const t={...r,provider:c},o=new AbortController,a=v(()=>o.abort(s.signal.reason),"abort");s.signal.aborted?a():s.signal.addEventListener("abort",a,{once:!0});let d=s.requestId;const A=he({request_id:d,run_id:e.run_id,node_id:e.node_id,controller:o});let m,h,j,u,_,g,w,P="allowed";try{try{await ue(t.provider)}catch{throw pe(t.provider)}let i=await U(t.provider,t.version),k=!1,n,b,q,L=!1,J=!1,F,H=0;for(;;){const y=Ue(i,t.tool);if(j=`${i.id}:${y.group}`,oe(e,i.id,y.group),i.transport.kind!=="machine"&&t.machine!==void 0)throw new p("invalid_argument",`provider "${i.id}" is not served by a device, so it takes no machine`,{param:"machine"});i.transport.kind==="machine"&&F===void 0&&(F=await je(t.machine,void 0,{newest:V(i.major,t.tool)}),H=Date.now()+(i.commands.timeouts?.requestMs??qe));let M=null;if(t.approval&&!L){const l=await fe(e,t,Y(i,y));q=l.option,M=l.prepared,w=t.approval,d=l.requestId,L=!0}const C={params:y.params.filter(l=>"type"in l&&l.type==="file").map(l=>l.name),output:y.output.find(l=>l.type==="file")?.name??null},x=JSON.stringify(C);if(b!==void 0&&b!==x)throw new p("provider_bad_response","the refreshed manifest changed the tool file contract",{origin:"provider",details:{status:409,message:"manifest_stale changed the tool file contract"}});b=x,M&&(n=await G(e,C,t.arguments,M,{signal:o.signal})),n??=await ce(e,C,t.arguments,{signal:o.signal});const{sub:O,grantee:R}=await Oe(e);if(i.transport.kind==="machine"){const l=await Je(e,i,t,y,n,{sub:O,requestId:d,deadlineAt:H,signal:o.signal,machine:F});return g=l.responder,m=l.cleanup,{status:200,body:l.result}}const E=await ve({audience:i.transport.endpoint,sub:O,grantee:R,initiating_app:R,scope:Ie(i,y)},{signal:o.signal});u=E.jti;const Z={registration:{name:i.id,endpoint:i.transport.endpoint},...i.commands.baseUrl?{baseUrl:i.commands.baseUrl}:{},...i.commands.timeouts?{timeouts:i.commands.timeouts}:{},params:y.params,rest:y.rest,output:y.output,commandPath:[i.id,...t.tool.split(" ")]},ee=we(Z,n.arguments,void 0,{authorization:`Bearer ${E.access_token}`,requestId:d,fileMode:"pass-through",extraHeaders:{...e.run_id?{"Crtr-Run-Id":e.run_id}:{},...await Le(e),...q?{"Crtr-Approval":q}:{},...n.headers}});h??=Date.now()+(i.commands.timeouts?.requestMs??3e4);let f;try{if(f=await be(ee,{connectMs:i.commands.timeouts?.connectMs,requestMs:i.commands.timeouts?.requestMs,deadlineAt:h,signal:o.signal}),o.signal.aborted)throw o.signal.reason??new Error("provider call aborted")}catch(l){throw o.signal.aborted?o.signal.reason??l:l instanceof ye?new p("provider_unavailable",l.message,{origin:"provider",details:{status:null,code:l.kind}}):l}if(_??=await Me({provider:i.id,tool:t.tool,request_id:d,run_id:e.run_id,sub:O,grantee:R,payer:E.payer,ledger_grantee:e.class==="person"?ne:R,jti:E.jti,status:f.status,headers:f.headers}),g=f.headers["crtr-responder"],f.status===401&&ge(E.key),f.status>=200&&f.status<300){const l=f.body;if(!l||typeof l!="object"||Array.isArray(l))throw new p("provider_bad_response","provider result is not a JSON object",{origin:"provider",details:{status:f.status,message:"provider result is not a JSON object"}});let N;try{N=await z(e,n,l,{signal:o.signal})}catch($){throw $ instanceof p&&$.code==="provider_error"?new p("provider_bad_response",$.message,{origin:"provider",details:{status:f.status,message:$.message}}):$}m=N.cleanup;const T=I(y.output,N.result);if(T)throw new p("provider_bad_response",`provider result has an invalid output field "${T.field}"`,{origin:"provider",param:T.field,details:{status:f.status,...T}});if(o.signal.aborted)throw o.signal.reason??new Error("provider call aborted");return{status:200,body:N.result}}const S=B(f.body);if(f.status===403&&S.code==="approval_required"&&!q&&!J){J=!0;const l=await me(e,t,d,S.question,o.signal,Y(i,y),n);if(w=l.questionId,q=l.option,n=await G(e,C,t.arguments,n,{signal:o.signal}),h=void 0,o.signal.aborted)throw new p("user_denied","the approval wait was canceled");continue}if(f.status===403&&S.code==="approval_required"&&q)throw D(f.status,f.body,f.headers,!0);if(f.status!==401&&S.manifest_stale===!0&&!k){k=!0,await le(i.id,{conditional:!1,...t.version===void 0?{}:{version:t.version}}),i=await U(i.id,t.version);continue}throw D(f.status,f.body,f.headers,!!q)}}catch(i){throw i instanceof p&&i.question_id&&(w=i.question_id),g===void 0&&i instanceof p&&typeof i.responder=="string"&&(g=i.responder),P=`refused:${i instanceof p?i.code:"server_error"}`,await m?.(),i}finally{try{await Ae({request_id:d,caller:e,provider:t.provider,tool:t.tool,scope_checked:j,outcome:P,jti:u,receipt_id:_,responder:g,question_id:w})}finally{A()}s.signal.removeEventListener("abort",a)}}v(vr,"callProvider");async function Je(e,r,s,c,t,o){const{machine:a}=o,d=await Fe(e,o.sub),A={machine:a,envelope:d,signal:o.signal,deadlineAt:o.deadlineAt,mapFailure:D};if(V(r.major,s.tool)){const n=await $e(A,t.arguments,r.major),b=I(c.output,n);if(b)throw new p("provider_bad_response",`the libraries result has an invalid output field "${b.field}"`,{origin:"provider",param:b.field,details:{status:200,...b}});return{result:n,responder:void 0,cleanup:void 0}}let m=t.arguments,h=null,j="";if(Ee(r.major,s.tool,t.arguments)){const n=await Ce(A,t.arguments,r.major);if(o.deadlineAt-Date.now()<=0)throw Q(a,"timeout","");n!==null&&(m=n.arguments,h=n.services,j=n.release)}const u=await ke(a,{tool:s.tool,arguments:m,version:r.major,requestId:o.requestId,runId:e.run_id,deadlineAt:o.deadlineAt,upload:t.upload===null?null:{id:t.upload.upload_id,link:t.upload.upload_link}},d,o.signal);if(o.signal.aborted)throw o.signal.reason??new Error("provider call aborted");if("unreachable"in u)throw Q(a,u.unreachable.reason,u.unreachable.message);const _=u.headers["crtr-responder"],g=B(u.body);if(u.status<200||u.status>=300){const n=Pe(a,u.status,typeof g.code=="string"?g.code:void 0,typeof g.message=="string"?g.message:void 0,u.body),b=n===null&&u.status>=500&&typeof g.code=="string"?new p("provider_error",typeof g.message=="string"?g.message:`the device answered HTTP ${u.status}`,{origin:"runtime",status:u.status,details:{code:g.code,status:u.status}}):null;throw Object.assign(n??b??D(u.status,u.body,u.headers),{responder:_})}const w=u.body&&typeof u.body=="object"&&!Array.isArray(u.body)?u.body.result:void 0;if(!w||typeof w!="object"||Array.isArray(w))throw Object.assign(new p("provider_bad_response","the device result is not a JSON object",{origin:"provider",details:{status:u.status,message:"the device result is not a JSON object"}}),{responder:_});let P=w;if(h!==null){const n=Re(P,h);if(Se(a,d,j,n.calls),"error"in n)throw Object.assign(n.error,{responder:_});P=n.result}let i;try{i=await z(e,t,P,{signal:o.signal})}catch(n){throw n instanceof p&&n.code==="provider_error"?Object.assign(new p("provider_bad_response",n.message,{origin:"provider",details:{status:u.status,message:n.message}}),{responder:_}):n}const k=I(c.output,i.result);if(k)throw await i.cleanup?.(),Object.assign(new p("provider_bad_response",`the device result has an invalid output field "${k.field}"`,{origin:"provider",param:k.field,details:{status:u.status,...k}}),{responder:_});return{result:i.result,responder:_,cleanup:i.cleanup}}v(Je,"callDevice");export{vr as callProvider,Le as crtrCallerHeader,D as mapProviderResponse,Me as onProviderResponse,W as providerLeaves,mr as providerTools};
@@ -57,7 +57,7 @@ export interface ResolvedFileResult {
57
57
  upload_id: string;
58
58
  } | null;
59
59
  /** Remove what this resolve wrote (for a failure after it). Idempotent. */
60
- cleanup: () => void;
60
+ cleanup: () => Promise<void>;
61
61
  }
62
62
  /** The fetch of a file result is bounded like an attachment fetch. */
63
63
  export declare const FILE_RESULT_FETCH_BUDGET_MS = 110000;
@@ -1 +1 @@
1
- var te=Object.defineProperty;var d=(e,t)=>te(e,"name",{value:t,configurable:!0});import{prepared as oe}from"../sqlite-statements.js";import{createHash as ne}from"node:crypto";import{closeSync as D,constants as re,createWriteStream as ie}from"node:fs";import{basename as ae,extname as se,isAbsolute as de,join as F}from"node:path";import{Transform as ue}from"node:stream";import{pipeline as le}from"node:stream/promises";import{appSpace as I}from"../layout.js";import{RunError as T}from"../runs/operations.js";import{createFileBeneath as ce,existsBeneath as M,openBeneath as fe,removeTreeBeneath as N,setModeBeneath as pe,unlinkBeneath as he,withDirBeneath as we}from"../spaces/open-beneath.js";import{ensureAppSpace as me}from"../spaces/space.js";import{invalidStorageName as H,storageClient as B,StorageRefused as U,UPLOAD_MAX_BYTES as C}from"../storage/client.js";import{contentTypeFor as _e,openCallerFile as ge}from"../storage/download.js";import{withCanvasWrite as ye}from"../canvas/db.js";import{deleteUploadUse as be,getUpload as $e,insertUpload as Se,insertUploadUses as ve,setUploadSize as Ue,uploadUseAt as ze}from"../storage/tables.js";import{ProviderError as l}from"./errors.js";const Ee=11e4,Ae="app:terminal";function P(e){if(e.class==="person")return e.grantee??Ae;if(!e.grantee)throw new l("server_error","provider caller has no grantee");return e.grantee}d(P,"grantee");function Fe(e){return e.class==="person"?null:{app:P(e),resolved:e.resolved??[],launched:e.class==="broker"?e.nodeScopes:null}}d(Fe,"fileCaller");function y(e){return e instanceof l?e:e instanceof U?new l("storage_unavailable",`storage refused: ${e.message}`):e instanceof T&&e.code==="storage_unavailable"?new l("storage_unavailable",e.message):e}d(y,"storageFailure");const b=d(e=>new l("provider_error",e,{origin:"provider"}),"providerError");function Te(e,t,n){if(typeof n!="string"||!n||!de(n)||n.includes("\0"))throw new l("invalid_request",`${t} must be an absolute runtime path`,{param:t});let i;try{i=ge(Fe(e),n)}catch(r){throw r instanceof T?r.code==="scope_missing"?new l("scope_missing",r.message,{param:t,...r.scope?{scope:r.scope}:{}}):r.code==="not_found"||r.code==="invalid_request"?new l("not_found",`no such file: ${n}`,{param:t}):r:r}try{if(i.size>C)throw new l("invalid_request",`${t} exceeds 100 MiB`,{param:t});const r=ae(i.path),o=H(r);if(o)throw new l("invalid_request",`${t}: file name cannot be sent: ${o}`,{param:t});return{param:t,file:i,name:r,mediaType:_e(i.path)}}catch(r){throw D(i.fd),r}}d(Te,"checkFileArgument");async function Be(e,t){try{const n=await e.createOutbound({name:t.name,size:t.file.size,media_type:t.mediaType});await e.putFileBytes(n.upload_link,t.file.fd,t.file.size,t.mediaType);const i=await e.signOutbound(n.object_id);return{param:t.param,path:t.file.path,name:t.name,object_id:n.object_id,url:i.url}}catch(n){throw y(n)}}d(Be,"copyOutbound");async function k(e,t,n,i){const r=[];try{for(const a of t)n[a]===void 0||n[a]===null||r.push(Te(e,a,n[a]));if(!r.length)return[];let o;try{o=i()}catch(a){throw y(a)}const c=[];for(const a of r)c.push(await Be(o,a));return c}finally{for(const o of r)D(o.file.fd)}}d(k,"copyArguments");function q(e){const t=H(e);if(t)throw new l("server_error",`file output ${e} cannot name an upload: ${t}`)}d(q,"checkOutputField");async function W(e,t,n){q(t);const i=P(e),r="application/octet-stream";let o;try{o=await n().createResultUpload({name:t,media_type:r,max_size:C})}catch(c){throw y(c)}return Se({upload_id:o.upload_id,grantee:i,name:t,media_type:r,size:C,created_at:new Date().toISOString()}),{field:t,upload_id:o.upload_id,upload_link:o.upload_link,grantee:i}}d(W,"createResultUpload");function X(e){return e?{"Crtr-Upload-Id":e.upload_id,"Crtr-Upload-Link":e.upload_link}:{}}d(X,"uploadHeaders");function Y(e,t){const n={...e};for(const i of t)n[i.param]=i.url;return n}d(Y,"withUrls");async function Je(e,t,n,i={}){const r=i.storage??B;t.output&&q(t.output);const o=await k(e,t.params,n,r),c=t.output?await W(e,t.output,r):null;return{arguments:Y(n,o),copies:o,upload:c,headers:X(c)}}d(Je,"prepareFileCall");async function Ke(e,t,n,i,r={}){const o=r.storage??B,c=[];for(const s of i.copies)try{const p=await o().signOutbound(s.object_id);c.push({...s,url:p.url})}catch(p){if(!(p instanceof U))throw y(p);c.push(...await k(e,[s.param],n,o))}let a=i.upload;if(a)try{const s=await o().signUploadLink(a.upload_id);a={...a,upload_link:s.upload_link}}catch(s){if(!(s instanceof U))throw y(s);s.status===404&&(a=await W(e,t.output??a.field,o))}return{arguments:Y(n,c),copies:c,upload:a,headers:X(a)}}d(Ke,"resignForRetry");const Ce=/^[0-9a-f]{64}$/i;function Oe(e,t){if(t===1)return e;const n=se(e);return n&&n!==e?`${e.slice(0,-n.length)}-${t}${n}`:`${e}-${t}`}d(Oe,"candidate");async function Qe(e,t,n,i={}){const r={result:n,file:null,cleanup:d(()=>{},"cleanup")},o=t.upload;if(!o||!n||typeof n!="object"||Array.isArray(n))return r;const c=n,a=c[o.field];if(a==null)return r;if(typeof a!="object"||Array.isArray(a))throw b(`${o.field} must be {upload_id, size, sha256}`);const s=a;if(typeof s.upload_id!="string"||typeof s.size!="number"||!Number.isSafeInteger(s.size)||s.size<0||typeof s.sha256!="string"||!Ce.test(s.sha256))throw b(`${o.field} must be {upload_id, size, sha256}`);if(s.upload_id!==o.upload_id)throw b(`${o.field} names an upload other than Crtr-Upload-Id`);const p=s.size,G=s.sha256.toLowerCase(),z=AbortSignal.timeout(i.budgetMs??Ee),O=i.signal?AbortSignal.any([z,i.signal]):z;let h;try{h=await(i.storage??B)().fetchUpload(o.upload_id,O)}catch(m){throw m instanceof U?b(`${o.field} names an upload with nothing stored`):y(m)}if(h.size===null)throw h.body.destroy(),new l("storage_unavailable",`storage did not say how many bytes ${o.field} holds`);if(h.size!==p)throw h.body.destroy(),b(`${o.field} claims ${p} bytes; storage holds ${h.size}`);const E=o.grantee,$=e.node_id!==null,J=await me(E),f=$?I(E).nodes:I(E).files,A=$?F(f,e.node_id):f,S=$?F(A,"attachments"):f,K={uid:process.getuid?.()??0,gid:J.gid},R=$&&!M(f,A),Q=$&&!R&&!M(f,S);let w=null,v=null,x=!1;const L=d(()=>{if(!x){if(x=!0,v)try{be(v)}catch{}if(w)try{he(f,w)}catch{}try{R?N(f,A):Q&&N(f,S)}catch{}}},"cleanup");try{we(f,S,()=>{},!0);for(let u=1;;u++){const _=F(S,Oe(o.field,u));if(!ze(_))try{ce(f,_,Buffer.alloc(0),432),w=_;break}catch(g){if(g.code!=="EEXIST")throw g}}let m=0;const j=ne("sha256"),V=new ue({transform(u,_,g){m+=u.length,j.update(u),g(null,u)}}),Z=fe(f,w,re.O_WRONLY);try{await le(h.body,V,ie("",{fd:Z,autoClose:!0}),{signal:O})}catch(u){throw z.aborted?new l("storage_unavailable","the file result could not be fetched within 110 s"):u instanceof T?y(u):new l("storage_unavailable",`storage stopped sending ${o.field}: ${u instanceof Error?u.message:String(u)}`)}if(m!==p)throw new l("storage_unavailable",`storage sent ${m} of ${p} bytes of ${o.field}`);if(j.digest("hex")!==G)throw b(`${o.field}: the stored bytes do not match sha256`);pe(f,w,432,K);const ee=w;ye(u=>{const _=$e(o.upload_id,u);if(!_||_.delete_pending_since)throw new l("not_found",`${o.field}: the upload was deleted while it was fetched`);if(Ue(o.upload_id,p,u),!e.run_id)return;const g=oe(u,"SELECT deleting_at FROM nodes WHERE node_id = ?").get(e.run_id);if(!g||g.deleting_at)throw new l("not_found",`run ${e.run_id} was deleted while its file result was fetched`);v={upload_id:o.upload_id,run_id:e.run_id,path:ee},ve([v],u)})}catch(m){throw h.body.destroy(),L(),m}return{result:{...c,[o.field]:w},file:{path:w,upload_id:o.upload_id},cleanup:L}}d(Qe,"resolveFileResult");export{Ee as FILE_RESULT_FETCH_BUDGET_MS,Je as prepareFileCall,Ke as resignForRetry,Qe as resolveFileResult};
1
+ var te=Object.defineProperty;var d=(e,t)=>te(e,"name",{value:t,configurable:!0});import{createHash as oe}from"node:crypto";import{closeSync as D,constants as ne,createWriteStream as ie}from"node:fs";import{basename as re,extname as ae,isAbsolute as se,join as F}from"node:path";import{Transform as de}from"node:stream";import{pipeline as ue}from"node:stream/promises";import{appSpace as I}from"../layout.js";import{RunError as T}from"../runs/operations.js";import{createFileBeneath as ce,existsBeneath as M,openBeneath as le,removeTreeBeneath as N,setModeBeneath as fe,unlinkBeneath as pe,withDirBeneath as he}from"../spaces/open-beneath.js";import{ensureAppSpace as we}from"../spaces/space.js";import{invalidStorageName as H,storageClient as B,StorageRefused as U,UPLOAD_MAX_BYTES as C}from"../storage/client.js";import{contentTypeFor as _e,openCallerFile as me}from"../storage/download.js";import{withCanvasWrite as ge}from"../canvas/db.js";import{deleteUploadUse as ye,getUpload as be,insertUpload as $e,insertUploadUses as Se,setUploadSize as ve,uploadUseAt as Ue}from"../storage/tables.js";import{ProviderError as c}from"./errors.js";const ze=11e4,Ee="app:terminal";function P(e){if(e.class==="person")return e.grantee??Ee;if(!e.grantee)throw new c("server_error","provider caller has no grantee");return e.grantee}d(P,"grantee");function Ae(e){return e.class==="person"?null:{app:P(e),resolved:e.resolved??[],launched:e.class==="broker"?e.nodeScopes:null}}d(Ae,"fileCaller");function y(e){return e instanceof c?e:e instanceof U?new c("storage_unavailable",`storage refused: ${e.message}`):e instanceof T&&e.code==="storage_unavailable"?new c("storage_unavailable",e.message):e}d(y,"storageFailure");const b=d(e=>new c("provider_error",e,{origin:"provider"}),"providerError");function Fe(e,t,n){if(typeof n!="string"||!n||!se(n)||n.includes("\0"))throw new c("invalid_request",`${t} must be an absolute runtime path`,{param:t});let r;try{r=me(Ae(e),n)}catch(i){throw i instanceof T?i.code==="scope_missing"?new c("scope_missing",i.message,{param:t,...i.scope?{scope:i.scope}:{}}):i.code==="not_found"||i.code==="invalid_request"?new c("not_found",`no such file: ${n}`,{param:t}):i:i}try{if(r.size>C)throw new c("invalid_request",`${t} exceeds 100 MiB`,{param:t});const i=re(r.path),o=H(i);if(o)throw new c("invalid_request",`${t}: file name cannot be sent: ${o}`,{param:t});return{param:t,file:r,name:i,mediaType:_e(r.path)}}catch(i){throw D(r.fd),i}}d(Fe,"checkFileArgument");async function Te(e,t){try{const n=await e.createOutbound({name:t.name,size:t.file.size,media_type:t.mediaType});await e.putFileBytes(n.upload_link,t.file.fd,t.file.size,t.mediaType);const r=await e.signOutbound(n.object_id);return{param:t.param,path:t.file.path,name:t.name,object_id:n.object_id,url:r.url}}catch(n){throw y(n)}}d(Te,"copyOutbound");async function k(e,t,n,r){const i=[];try{for(const a of t)n[a]===void 0||n[a]===null||i.push(Fe(e,a,n[a]));if(!i.length)return[];let o;try{o=r()}catch(a){throw y(a)}const l=[];for(const a of i)l.push(await Te(o,a));return l}finally{for(const o of i)D(o.file.fd)}}d(k,"copyArguments");function q(e){const t=H(e);if(t)throw new c("server_error",`file output ${e} cannot name an upload: ${t}`)}d(q,"checkOutputField");async function W(e,t,n){q(t);const r=P(e),i="application/octet-stream";let o;try{o=await n().createResultUpload({name:t,media_type:i,max_size:C})}catch(l){throw y(l)}return await $e({upload_id:o.upload_id,grantee:r,name:t,media_type:i,size:C,created_at:new Date().toISOString()}),{field:t,upload_id:o.upload_id,upload_link:o.upload_link,grantee:r}}d(W,"createResultUpload");function X(e){return e?{"Crtr-Upload-Id":e.upload_id,"Crtr-Upload-Link":e.upload_link}:{}}d(X,"uploadHeaders");function Y(e,t){const n={...e};for(const r of t)n[r.param]=r.url;return n}d(Y,"withUrls");async function Ye(e,t,n,r={}){const i=r.storage??B;t.output&&q(t.output);const o=await k(e,t.params,n,i),l=t.output?await W(e,t.output,i):null;return{arguments:Y(n,o),copies:o,upload:l,headers:X(l)}}d(Ye,"prepareFileCall");async function Ge(e,t,n,r,i={}){const o=i.storage??B,l=[];for(const s of r.copies)try{const p=await o().signOutbound(s.object_id);l.push({...s,url:p.url})}catch(p){if(!(p instanceof U))throw y(p);l.push(...await k(e,[s.param],n,o))}let a=r.upload;if(a)try{const s=await o().signUploadLink(a.upload_id);a={...a,upload_link:s.upload_link}}catch(s){if(!(s instanceof U))throw y(s);s.status===404&&(a=await W(e,t.output??a.field,o))}return{arguments:Y(n,l),copies:l,upload:a,headers:X(a)}}d(Ge,"resignForRetry");const Be=/^[0-9a-f]{64}$/i;function Ce(e,t){if(t===1)return e;const n=ae(e);return n&&n!==e?`${e.slice(0,-n.length)}-${t}${n}`:`${e}-${t}`}d(Ce,"candidate");async function Je(e,t,n,r={}){const i={result:n,file:null,cleanup:d(async()=>{},"cleanup")},o=t.upload;if(!o||!n||typeof n!="object"||Array.isArray(n))return i;const l=n,a=l[o.field];if(a==null)return i;if(typeof a!="object"||Array.isArray(a))throw b(`${o.field} must be {upload_id, size, sha256}`);const s=a;if(typeof s.upload_id!="string"||typeof s.size!="number"||!Number.isSafeInteger(s.size)||s.size<0||typeof s.sha256!="string"||!Be.test(s.sha256))throw b(`${o.field} must be {upload_id, size, sha256}`);if(s.upload_id!==o.upload_id)throw b(`${o.field} names an upload other than Crtr-Upload-Id`);const p=s.size,G=s.sha256.toLowerCase(),z=AbortSignal.timeout(r.budgetMs??ze),O=r.signal?AbortSignal.any([z,r.signal]):z;let h;try{h=await(r.storage??B)().fetchUpload(o.upload_id,O)}catch(_){throw _ instanceof U?b(`${o.field} names an upload with nothing stored`):y(_)}if(h.size===null)throw h.body.destroy(),new c("storage_unavailable",`storage did not say how many bytes ${o.field} holds`);if(h.size!==p)throw h.body.destroy(),b(`${o.field} claims ${p} bytes; storage holds ${h.size}`);const E=o.grantee,$=e.node_id!==null,J=await we(E),f=$?I(E).nodes:I(E).files,A=$?F(f,e.node_id):f,S=$?F(A,"attachments"):f,K={uid:process.getuid?.()??0,gid:J.gid},R=$&&!M(f,A),Q=$&&!R&&!M(f,S);let w=null,v=null,x=!1;const L=d(async()=>{if(!x){if(x=!0,v)try{await ye(v)}catch{}if(w)try{pe(f,w)}catch{}try{R?N(f,A):Q&&N(f,S)}catch{}}},"cleanup");try{he(f,S,()=>{},!0);for(let u=1;;u++){const m=F(S,Ce(o.field,u));if(!await Ue(m))try{ce(f,m,Buffer.alloc(0),432),w=m;break}catch(g){if(g.code!=="EEXIST")throw g}}let _=0;const j=oe("sha256"),V=new de({transform(u,m,g){_+=u.length,j.update(u),g(null,u)}}),Z=le(f,w,ne.O_WRONLY);try{await ue(h.body,V,ie("",{fd:Z,autoClose:!0}),{signal:O})}catch(u){throw z.aborted?new c("storage_unavailable","the file result could not be fetched within 110 s"):u instanceof T?y(u):new c("storage_unavailable",`storage stopped sending ${o.field}: ${u instanceof Error?u.message:String(u)}`)}if(_!==p)throw new c("storage_unavailable",`storage sent ${_} of ${p} bytes of ${o.field}`);if(j.digest("hex")!==G)throw b(`${o.field}: the stored bytes do not match sha256`);fe(f,w,432,K);const ee=w;await ge(async u=>{const m=await be(o.upload_id,u);if(!m||m.delete_pending_since)throw new c("not_found",`${o.field}: the upload was deleted while it was fetched`);if(await ve(o.upload_id,p,u),!e.run_id)return;const g=await u.prepare("SELECT deleting_at FROM nodes WHERE node_id = ?").get(e.run_id);if(!g||g.deleting_at)throw new c("not_found",`run ${e.run_id} was deleted while its file result was fetched`);v={upload_id:o.upload_id,run_id:e.run_id,path:ee},await Se([v],u)})}catch(_){throw h.body.destroy(),await L(),_}return{result:{...l,[o.field]:w},file:{path:w,upload_id:o.upload_id},cleanup:L}}d(Je,"resolveFileResult");export{ze as FILE_RESULT_FETCH_BUDGET_MS,Ye as prepareFileCall,Ge as resignForRetry,Je as resolveFileResult};