@north-light/cli 0.3.530 → 0.3.532

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 +508 -508
  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 +2 -2
  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 +13 -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 +13 -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,12 +1,12 @@
1
- var x=Object.defineProperty;var m=(e,t)=>x(e,"name",{value:t,configurable:!0});import{prepared as a}from"../sqlite-statements.js";import{createHash as J,randomBytes as P,timingSafeEqual as q}from"node:crypto";import{CrtrError as j,usage as p}from"../errors.js";import{ExitCode as O}from"../../types.js";import{createObject as F,liveDocumentNamed as M}from"./objects.js";import{invalidateCustomKind as D}from"./kinds/registry.js";import{customReachable as k,mayActAs as L}from"./access.js";import{publish as N,HOP_LIMIT as B,HopLimitError as K}from"./events.js";import{checkoutsForCwd as T}from"./repo-sync/repos.js";import{onQueueSignal as V,signalQueue as R}from"./receivers.js";import{receiverEndpoint as G,isPublicReceiverAddress as Q}from"./receiver-url.js";import{isIP as Y}from"node:net";import{KIND as H,LOCAL as I,MAX_KIND_EVENTS as z,RESERVED_KIND_ROOTS as X,eventCatalogReasons as Z}from"../plugin-objects-manifest.js";const ee=["public","friends","private"];function w(e,t){throw new j(e,t,O.GENERAL)}m(w,"conflict");function A(e){return J("sha256").update(e).digest("hex")}m(A,"hash");function W(){return`crtr_pub_${P(32).toString("base64url")}`}m(W,"issueToken");function te(e){if(e==null)return null;if(e==="queue")return JSON.stringify(e);if(typeof e!="object"||Array.isArray(e))throw p("invalid custom receiver; expected queue, an https url, or argv and absolute cwd");if("url"in e&&typeof e.url=="string")try{const s=G(e.url).hostname.replace(/^\[|\]$/g,"");if(Y(s)&&!Q(s))throw new Error("non-public IP address");return JSON.stringify({url:e.url})}catch(t){throw p(`invalid custom receiver: ${String(t)}`)}if("argv"in e&&Array.isArray(e.argv)&&e.argv.length>0&&e.argv.every(t=>typeof t=="string")&&typeof e.cwd=="string"&&e.cwd.startsWith("/"))return JSON.stringify(e);throw p("invalid custom receiver; url must be https and argv requires a command and absolute cwd")}m(te,"receiverJson");function ge(e,t,s){const{kind:n,name:i,owner:o,description:d,events:l,receiver:c,rotateToken:h,privacy:f}=s;if(f!==void 0&&!ee.includes(f))throw p(`invalid privacy ${JSON.stringify(f)}`);if(L(e,t,o)||w("forbidden",`cannot act as ${o.id}`),!H.test(n)||X.includes(n.split(".")[0]))throw p(`invalid or reserved kind ${n}`);if(!i.trim()||i!==i.trim()||i.includes("\0"))throw p(`invalid object name ${JSON.stringify(i)}`);const E=te(c);if(c!=="queue"&&c!==null&&c!==void 0&&"argv"in c&&t.class!=="person"&&t.class!=="node"&&w("argv_forbidden","argv receiver requires a person or node principal"),l===void 0){const u=a(e,"SELECT source FROM object_kinds WHERE name = ?").get(n);if(u?.source!=="manifest"&&u?.source!=="peer")throw p("events is required unless the kind is declared by an installed plugin")}else if(Object.keys(l).length>z||Object.entries(l).some(([u,g])=>!I.test(u)||!Number.isInteger(g?.level)||g.level<1||g.level>10||g.supersedes!==void 0&&typeof g.supersedes!="boolean"||g.ends_wait!==void 0&&typeof g.ends_wait!="boolean"))throw p("invalid custom event catalog");const r=M(e,o.rowid,i);if(r&&!k(e,t,r)&&w("forbidden",`cannot act as ${o.id}`),r&&t.class!=="person"&&t.class!=="node"){const u=a(e,"SELECT receiver_json FROM custom_objects WHERE object = ?").get(r.rowid)?.receiver_json;u&&typeof JSON.parse(u)=="object"&&"argv"in JSON.parse(u)&&w("argv_forbidden","argv receiver requires a person or node principal")}r&&r.type!==n&&w("name_taken",`${o.name}/${i} is already held by ${r.id}`);const v=l===void 0?null:ne(e,{name:n,owner:o,description:d,events:l,read:null,source:"register"});if(!r){const u=F(e,{type:n,kind:null,owner:o.rowid,privacy:f??"public",name:i,preview:""}),g=W();return a(e,`INSERT INTO custom_objects (object, description, receiver_json, token_hash)
2
- VALUES (?, ?, ?, ?)`).run(u.rowid,d,E,A(g)),t.class==="node"&&a(e,"UPDATE custom_objects SET registered_by = ? WHERE object = ?").run(t.node.id,u.rowid),E!==null&&a(e,"UPDATE objects SET reception = 2 WHERE rowid = ?").run(u.rowid),N(e,{event:"created",object:u,actor:t.class==="object"?t.object:t.class==="person"?t.person:t.class==="app"?t.app:t.node,attrs:{}},$=>T(e,$)),{object:u,token:g,created:!0,changed:[]}}const y=a(e,"SELECT description, receiver_json FROM custom_objects WHERE object = ?").get(r.rowid);y||w("name_taken",`${o.name}/${i} is not a custom object`);const _=[];if(y.description!==d&&_.push("description"),y.receiver_json!==E&&_.push("receiver"),v?.changed.includes("events")&&_.push("events"),v?.changed.includes("description")&&!_.includes("description")&&_.push("description"),f!==void 0&&r.privacy!==f&&_.push("privacy"),h&&_.push("token"),_.length===0)return{object:r,created:!1,changed:_};const S=h?W():void 0,b=_.includes("privacy")?{...r,privacy:f}:r;if(b!==r&&a(e,"UPDATE objects SET privacy = ? WHERE rowid = ?").run(f,r.rowid),a(e,"UPDATE custom_objects SET description = ?, receiver_json = ?, token_hash = COALESCE(?, token_hash) WHERE object = ?").run(d,E,S===void 0?null:A(S),r.rowid),a(e,"UPDATE objects SET reception = ? WHERE rowid = ?").run(E===null?0:2,r.rowid),y.receiver_json!==E){const u=Date.now();if(E===null){const g=a(e,`UPDATE deliveries SET canceled_at = ?, updated_at = ?
3
- WHERE destination_id = ? AND state = 'pending' AND canceled_at IS NULL`).run(u,u,r.id);a(e,"UPDATE custom_objects SET dropped = dropped + ? WHERE object = ?").run(g.changes,r.rowid)}else a(e,`UPDATE deliveries SET next_attempt_at = ?, updated_at = ?
4
- WHERE destination_id = ? AND state = 'pending' AND canceled_at IS NULL`).run(E==='"queue"'?null:u,u,r.id);R(r.id)}return h&&R(r.id),N(e,{event:"configured",object:b,actor:t.class==="object"?t.object:t.class==="person"?t.person:t.class==="app"?t.app:t.node,attrs:{changed:_.join(",")}},u=>T(e,u)),{object:b,...S===void 0?{}:{token:S},created:!1,changed:_}}m(ge,"registerCustomObject");function ne(e,t){const{name:s,owner:n,description:i,events:o,read:d,source:l}=t;if(!H.test(s))throw p(`invalid kind ${s}`);if(Z(o,s).length>0)throw p("invalid custom event catalog");const c=a(e,"SELECT owner, description, events_json, read_json, source, declared FROM object_kinds WHERE name = ?").get(s),h=U(o),f=l==="manifest"&&d!==null?JSON.stringify({command:d.command}):null,E=new Date().toISOString();if(!c)return a(e,`INSERT INTO object_kinds (name, owner, description, events_json, created_at, updated_at, read_json, source, declared)
5
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, 1)`).run(s,n.rowid,i,h,E,E,f,l),D(e,s),{outcome:"inserted",changed:[]};const r=c.owner===n.rowid;if(l==="peer"){if(c.source!=="peer")return{outcome:"skipped",changed:[]}}else if(c.source!=="peer"&&(r||w("kind_owned",`${s} belongs to another owner`),l==="register"&&c.source==="manifest"))return{outcome:"skipped",changed:[]};const v=[];return U(JSON.parse(c.events_json))!==h&&v.push("events"),c.description!==i&&v.push("description"),(c.read_json??null)!==f&&v.push("read"),v.length===0&&r&&c.source===l&&c.declared===1?{outcome:"unchanged",changed:v}:(a(e,"UPDATE object_kinds SET owner = ?, description = ?, events_json = ?, read_json = ?, source = ?, declared = 1, updated_at = ? WHERE name = ?").run(n.rowid,i,h,f,l,E,s),D(e,s),{outcome:"updated",changed:v})}m(ne,"upsertKind");function he(e,t,s,n){const i=a(e,"SELECT events_json FROM object_kinds WHERE name = ?").get(t.type);if(!i||t.deleted_at!==null)throw p(`${t.id} is not a live custom object`);const o=JSON.parse(i.events_json);if(!I.test(n.event)||!Object.hasOwn(o,n.event))throw new j("unknown_event",`${t.type} declares ${Object.keys(o).join(", ")}, not ${n.event}`,O.USAGE,{declared:Object.keys(o),event:n.event});if(typeof n.summary!="string")throw p("summary must be text");const d=n.state===void 0?null:JSON.stringify(n.state);if(n.state!==void 0&&d===void 0)throw p("state must be JSON-serializable");if(Buffer.byteLength(JSON.stringify({summary:n.summary,...n.state===void 0?{}:{state:n.state}}))>64*1024)throw new j("body_too_large","custom event summary and state exceed 64 KiB",O.USAGE);if(d!==null&&Buffer.byteLength(d)>64*1024)throw p("state exceeds 64 KiB");const l=n.cause??null,c=l===null?null:a(e,`SELECT depth FROM messages WHERE message_id = ?
6
- UNION ALL SELECT depth FROM message_causes WHERE message_id = ? LIMIT 1`).get(l,l);if(l!==null&&c===void 0)throw new j("unknown_cause",`no message ${l}`,O.USAGE);if(c&&c.depth>=B)throw new K(c.depth+1);const h=new Date().toISOString();return a(e,"UPDATE custom_objects SET summary = ?, state_json = ?, published_at = ? WHERE object = ?").run(n.summary,d,h,t.rowid),a(e,"UPDATE objects SET preview = ? WHERE rowid = ?").run(n.summary.split(`
7
- `)[0],t.rowid),N(e,{event:`${t.type}.${n.event}`,object:t,actor:s,attrs:{},messageBody:{summary:n.summary,...n.state===void 0?{}:{state:n.state}},...n.cause===void 0?{}:{cause:n.cause}},f=>T(e,f))}m(he,"publishCustom");function ve(e,t,s){if(t.deleted_at!==null)return;N(e,{event:"deleted",object:t,actor:s,attrs:{}},i=>T(e,i));const n=new Date().toISOString();a(e,"UPDATE objects SET deleted_at = ?, reception = 0 WHERE rowid = ?").run(n,t.rowid),a(e,"UPDATE deliveries SET canceled_at = ?, updated_at = ? WHERE destination_id = ? AND state = 'pending' AND canceled_at IS NULL").run(Date.now(),Date.now(),t.id),R(t.id)}m(ve,"unregisterCustomObject");function U(e){return JSON.stringify(Object.fromEntries(Object.entries(e).sort(([t],[s])=>t.localeCompare(s)).map(([t,s])=>[t,{level:s.level,...s.supersedes===void 0?{}:{supersedes:s.supersedes},...s.ends_wait===void 0?{}:{ends_wait:s.ends_wait}}])))}m(U,"canonicalEvents");function we(e,t,s=0){return C(e,t.id,s,"pending")}m(we,"pendingFor");function ye(e,t){const s=a(e,"SELECT destination_id FROM deliveries WHERE delivery_id = ?").get(t);return s?C(e,s.destination_id,-1,"handed_off").find(n=>n.delivery_id===t)??null:null}m(ye,"pushLineFor");function C(e,t,s,n){return a(e,`SELECT d.delivery_id, m.message_id, m.seq, m.event, m.level, m.object_id, m.actor_id, m.body_json, m.body_ref, m.depth, m.created_at,
1
+ var $=Object.defineProperty;var l=(e,t)=>$(e,"name",{value:t,configurable:!0});import{createHash as x,randomBytes as J,timingSafeEqual as P}from"node:crypto";import{CrtrError as j,usage as f}from"../errors.js";import{ExitCode as S}from"../../types.js";import{createObject as q,liveDocumentNamed as F}from"./objects.js";import{invalidateCustomKind as A}from"./kinds/registry.js";import{customReachable as D,mayActAs as k}from"./access.js";import{publish as O,HOP_LIMIT as M,HopLimitError as B}from"./events.js";import{checkoutsForCwd as N}from"./repo-sync/repos.js";import{onQueueSignal as K,signalQueue as b}from"./receivers.js";import{receiverEndpoint as V,isPublicReceiverAddress as G}from"./receiver-url.js";import{isIP as Q}from"node:net";import{KIND as L,LOCAL as H,MAX_KIND_EVENTS as Y,RESERVED_KIND_ROOTS as z,eventCatalogReasons as X}from"../plugin-objects-manifest.js";const Z=["public","friends","private"];function h(e,t){throw new j(e,t,S.GENERAL)}l(h,"conflict");function R(e){return x("sha256").update(e).digest("hex")}l(R,"hash");function I(){return`crtr_pub_${J(32).toString("base64url")}`}l(I,"issueToken");function ee(e){if(e==null)return null;if(e==="queue")return JSON.stringify(e);if(typeof e!="object"||Array.isArray(e))throw f("invalid custom receiver; expected queue, an https url, or argv and absolute cwd");if("url"in e&&typeof e.url=="string")try{const i=V(e.url).hostname.replace(/^\[|\]$/g,"");if(Q(i)&&!G(i))throw new Error("non-public IP address");return JSON.stringify({url:e.url})}catch(t){throw f(`invalid custom receiver: ${String(t)}`)}if("argv"in e&&Array.isArray(e.argv)&&e.argv.length>0&&e.argv.every(t=>typeof t=="string")&&typeof e.cwd=="string"&&e.cwd.startsWith("/"))return JSON.stringify(e);throw f("invalid custom receiver; url must be https and argv requires a command and absolute cwd")}l(ee,"receiverJson");async function we(e,t,i){const{kind:n,name:r,owner:s,description:o,events:u,receiver:d,rotateToken:_,privacy:p}=i;if(p!==void 0&&!Z.includes(p))throw f(`invalid privacy ${JSON.stringify(p)}`);if(await k(e,t,s)||h("forbidden",`cannot act as ${s.id}`),!L.test(n)||z.includes(n.split(".")[0]))throw f(`invalid or reserved kind ${n}`);if(!r.trim()||r!==r.trim()||r.includes("\0"))throw f(`invalid object name ${JSON.stringify(r)}`);const m=ee(d);if(d!=="queue"&&d!==null&&d!==void 0&&"argv"in d&&t.class!=="person"&&t.class!=="node"&&h("argv_forbidden","argv receiver requires a person or node principal"),u===void 0){const c=await e.prepare("SELECT source FROM object_kinds WHERE name = ?").get(n);if(c?.source!=="manifest"&&c?.source!=="peer")throw f("events is required unless the kind is declared by an installed plugin")}else if(Object.keys(u).length>Y||Object.entries(u).some(([c,E])=>!H.test(c)||!Number.isInteger(E?.level)||E.level<1||E.level>10||E.supersedes!==void 0&&typeof E.supersedes!="boolean"||E.ends_wait!==void 0&&typeof E.ends_wait!="boolean"))throw f("invalid custom event catalog");const a=await F(e,s.rowid,r);if(a&&!await D(e,t,a)&&h("forbidden",`cannot act as ${s.id}`),a&&t.class!=="person"&&t.class!=="node"){const c=(await e.prepare("SELECT receiver_json FROM custom_objects WHERE object = ?").get(a.rowid))?.receiver_json;c&&typeof JSON.parse(c)=="object"&&"argv"in JSON.parse(c)&&h("argv_forbidden","argv receiver requires a person or node principal")}a&&a.type!==n&&h("name_taken",`${s.name}/${r} is already held by ${a.id}`);const g=u===void 0?null:await te(e,{name:n,owner:s,description:o,events:u,read:null,source:"register"});if(!a){const c=await q(e,{type:n,kind:null,owner:s.rowid,privacy:p??"public",name:r,preview:""}),E=I();return await e.prepare(`INSERT INTO custom_objects (object, description, receiver_json, token_hash)
2
+ VALUES (?, ?, ?, ?)`).run(c.rowid,o,m,R(E)),t.class==="node"&&await e.prepare("UPDATE custom_objects SET registered_by = ? WHERE object = ?").run(t.node.id,c.rowid),m!==null&&await e.prepare("UPDATE objects SET reception = 2 WHERE rowid = ?").run(c.rowid),await O(e,{event:"created",object:c,actor:t.class==="object"?t.object:t.class==="person"?t.person:t.class==="app"?t.app:t.node,attrs:{}},async C=>await N(e,C)),{object:c,token:E,created:!0,changed:[]}}const v=await e.prepare("SELECT description, receiver_json FROM custom_objects WHERE object = ?").get(a.rowid);v||h("name_taken",`${s.name}/${r} is not a custom object`);const w=[];if(v.description!==o&&w.push("description"),v.receiver_json!==m&&w.push("receiver"),g?.changed.includes("events")&&w.push("events"),g?.changed.includes("description")&&!w.includes("description")&&w.push("description"),p!==void 0&&a.privacy!==p&&w.push("privacy"),_&&w.push("token"),w.length===0)return{object:a,created:!1,changed:w};const y=_?I():void 0,T=w.includes("privacy")?{...a,privacy:p}:a;if(T!==a&&await e.prepare("UPDATE objects SET privacy = ? WHERE rowid = ?").run(p,a.rowid),await e.prepare("UPDATE custom_objects SET description = ?, receiver_json = ?, token_hash = COALESCE(?, token_hash) WHERE object = ?").run(o,m,y===void 0?null:R(y),a.rowid),await e.prepare("UPDATE objects SET reception = ? WHERE rowid = ?").run(m===null?0:2,a.rowid),v.receiver_json!==m){const c=Date.now();if(m===null){const E=await e.prepare(`UPDATE deliveries SET canceled_at = ?, updated_at = ?
3
+ WHERE destination_id = ? AND state = 'pending' AND canceled_at IS NULL`).run(c,c,a.id);await e.prepare("UPDATE custom_objects SET dropped = dropped + ? WHERE object = ?").run(E.changes,a.rowid)}else await e.prepare(`UPDATE deliveries SET next_attempt_at = ?, updated_at = ?
4
+ WHERE destination_id = ? AND state = 'pending' AND canceled_at IS NULL`).run(m==='"queue"'?null:c,c,a.id);b(a.id)}return _&&b(a.id),await O(e,{event:"configured",object:T,actor:t.class==="object"?t.object:t.class==="person"?t.person:t.class==="app"?t.app:t.node,attrs:{changed:w.join(",")}},async c=>await N(e,c)),{object:T,...y===void 0?{}:{token:y},created:!1,changed:w}}l(we,"registerCustomObject");async function te(e,t){const{name:i,owner:n,description:r,events:s,read:o,source:u}=t;if(!L.test(i))throw f(`invalid kind ${i}`);if(X(s,i).length>0)throw f("invalid custom event catalog");const d=await e.prepare("SELECT owner, description, events_json, read_json, source, declared FROM object_kinds WHERE name = ?").get(i),_=W(s),p=u==="manifest"&&o!==null?JSON.stringify({command:o.command}):null,m=new Date().toISOString();if(!d)return await e.prepare(`INSERT INTO object_kinds (name, owner, description, events_json, created_at, updated_at, read_json, source, declared)
5
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, 1)`).run(i,n.rowid,r,_,m,m,p,u),A(e,i),{outcome:"inserted",changed:[]};const a=d.owner===n.rowid;if(u==="peer"){if(d.source!=="peer")return{outcome:"skipped",changed:[]}}else if(d.source!=="peer"&&(a||h("kind_owned",`${i} belongs to another owner`),u==="register"&&d.source==="manifest"))return{outcome:"skipped",changed:[]};const g=[];return W(JSON.parse(d.events_json))!==_&&g.push("events"),d.description!==r&&g.push("description"),(d.read_json??null)!==p&&g.push("read"),g.length===0&&a&&d.source===u&&d.declared===1?{outcome:"unchanged",changed:g}:(await e.prepare("UPDATE object_kinds SET owner = ?, description = ?, events_json = ?, read_json = ?, source = ?, declared = 1, updated_at = ? WHERE name = ?").run(n.rowid,r,_,p,u,m,i),A(e,i),{outcome:"updated",changed:g})}l(te,"upsertKind");async function Ee(e,t,i,n){const r=await e.prepare("SELECT events_json FROM object_kinds WHERE name = ?").get(t.type);if(!r||t.deleted_at!==null)throw f(`${t.id} is not a live custom object`);const s=JSON.parse(r.events_json);if(!H.test(n.event)||!Object.hasOwn(s,n.event))throw new j("unknown_event",`${t.type} declares ${Object.keys(s).join(", ")}, not ${n.event}`,S.USAGE,{declared:Object.keys(s),event:n.event});if(typeof n.summary!="string")throw f("summary must be text");const o=n.state===void 0?null:JSON.stringify(n.state);if(n.state!==void 0&&o===void 0)throw f("state must be JSON-serializable");if(Buffer.byteLength(JSON.stringify({summary:n.summary,...n.state===void 0?{}:{state:n.state}}))>64*1024)throw new j("body_too_large","custom event summary and state exceed 64 KiB",S.USAGE);if(o!==null&&Buffer.byteLength(o)>64*1024)throw f("state exceeds 64 KiB");const u=n.cause??null,d=u===null?null:await e.prepare(`SELECT depth FROM messages WHERE message_id = ?
6
+ UNION ALL SELECT depth FROM message_causes WHERE message_id = ? LIMIT 1`).get(u,u);if(u!==null&&d===void 0)throw new j("unknown_cause",`no message ${u}`,S.USAGE);if(d&&d.depth>=M)throw new B(d.depth+1);const _=new Date().toISOString();return await e.prepare("UPDATE custom_objects SET summary = ?, state_json = ?, published_at = ? WHERE object = ?").run(n.summary,o,_,t.rowid),await e.prepare("UPDATE objects SET preview = ? WHERE rowid = ?").run(n.summary.split(`
7
+ `)[0],t.rowid),await O(e,{event:`${t.type}.${n.event}`,object:t,actor:i,attrs:{},messageBody:{summary:n.summary,...n.state===void 0?{}:{state:n.state}},...n.cause===void 0?{}:{cause:n.cause}},async p=>await N(e,p))}l(Ee,"publishCustom");async function _e(e,t,i){if(t.deleted_at!==null)return;await O(e,{event:"deleted",object:t,actor:i,attrs:{}},async r=>await N(e,r));const n=new Date().toISOString();await e.prepare("UPDATE objects SET deleted_at = ?, reception = 0 WHERE rowid = ?").run(n,t.rowid),await e.prepare("UPDATE deliveries SET canceled_at = ?, updated_at = ? WHERE destination_id = ? AND state = 'pending' AND canceled_at IS NULL").run(Date.now(),Date.now(),t.id),b(t.id)}l(_e,"unregisterCustomObject");function W(e){return JSON.stringify(Object.fromEntries(Object.entries(e).sort(([t],[i])=>t.localeCompare(i)).map(([t,i])=>[t,{level:i.level,...i.supersedes===void 0?{}:{supersedes:i.supersedes},...i.ends_wait===void 0?{}:{ends_wait:i.ends_wait}}])))}l(W,"canonicalEvents");async function ge(e,t,i=0){return await U(e,t.id,i,"pending")}l(ge,"pendingFor");async function he(e,t){const i=await e.prepare("SELECT destination_id FROM deliveries WHERE delivery_id = ?").get(t);return i?(await U(e,i.destination_id,-1,"handed_off")).find(n=>n.delivery_id===t)??null:null}l(he,"pushLineFor");async function U(e,t,i,n){return(await e.prepare(`SELECT d.delivery_id, m.message_id, m.seq, m.event, m.level, m.object_id, m.actor_id, m.body_json, m.body_ref, m.depth, m.created_at,
8
8
  o.type, o.name, owner.id AS owner_id
9
9
  FROM deliveries d JOIN messages m ON m.message_id = d.message_id JOIN objects o ON o.id = m.object_id
10
10
  LEFT JOIN objects owner ON owner.rowid = o.owner
11
- WHERE d.destination_id = ? AND d.state = ? AND d.canceled_at IS NULL AND m.seq > ? ORDER BY m.seq`).all(t,n,s).map(o=>{const d=o.body_json?JSON.parse(o.body_json):{};return{delivery_id:o.delivery_id,message_id:o.message_id,seq:o.seq,event:o.event,level:o.level,object:{id:o.object_id,type:o.type,name:o.name,owner:o.owner_id},actor:o.actor_id,attrs:d.push?.attrs??{},...d.summary===void 0?{}:{summary:d.summary},...d.state===void 0?{}:{state:d.state},...d.push?.pointer===void 0?{}:{pointer:d.push.pointer},depth:o.depth,created_at:o.created_at}})}m(C,"queueLines");function Se(e,t,s){const n=Date.now(),i=[];let o=0;for(const d of s){const l=a(e,`UPDATE deliveries SET state = 'acknowledged', acknowledged_at = ?, updated_at = ?
12
- WHERE delivery_id = ? AND destination_id = ? AND state = 'pending' AND canceled_at IS NULL`).run(n,n,d,t.id);Number(l.changes)?o++:i.push(d)}return{acknowledged:o,...i.length?{unknown:i}:{}}}m(Se,"acknowledge");function je(e,t,s){const n=a(e,"SELECT token_hash FROM custom_objects WHERE object = ?").get(t.rowid),i=Buffer.from(n?.token_hash??"".padEnd(64,"0"),"hex"),o=Buffer.from(A(s),"hex");return s.startsWith("crtr_pub_")&&t.deleted_at===null&&i.length===o.length&&q(i,o)&&n?.token_hash!=null}m(je,"verifyPublishToken");export{Se as acknowledge,k as customReachable,L as mayActAs,V as onQueueSignal,we as pendingFor,he as publishCustom,ye as pushLineFor,ge as registerCustomObject,ve as unregisterCustomObject,ne as upsertKind,je as verifyPublishToken};
11
+ WHERE d.destination_id = ? AND d.state = ? AND d.canceled_at IS NULL AND m.seq > ? ORDER BY m.seq`).all(t,n,i)).map(s=>{const o=s.body_json?JSON.parse(s.body_json):{};return{delivery_id:s.delivery_id,message_id:s.message_id,seq:s.seq,event:s.event,level:s.level,object:{id:s.object_id,type:s.type,name:s.name,owner:s.owner_id},actor:s.actor_id,attrs:o.push?.attrs??{},...o.summary===void 0?{}:{summary:o.summary},...o.state===void 0?{}:{state:o.state},...o.push?.pointer===void 0?{}:{pointer:o.push.pointer},depth:s.depth,created_at:s.created_at}})}l(U,"queueLines");async function ve(e,t,i){const n=Date.now(),r=[];let s=0;for(const o of i){const u=await e.prepare(`UPDATE deliveries SET state = 'acknowledged', acknowledged_at = ?, updated_at = ?
12
+ WHERE delivery_id = ? AND destination_id = ? AND state = 'pending' AND canceled_at IS NULL`).run(n,n,o,t.id);Number(u.changes)?s++:r.push(o)}return{acknowledged:s,...r.length?{unknown:r}:{}}}l(ve,"acknowledge");async function ye(e,t,i){const n=await e.prepare("SELECT token_hash FROM custom_objects WHERE object = ?").get(t.rowid),r=Buffer.from(n?.token_hash??"".padEnd(64,"0"),"hex"),s=Buffer.from(R(i),"hex");return i.startsWith("crtr_pub_")&&t.deleted_at===null&&r.length===s.length&&P(r,s)&&n?.token_hash!=null}l(ye,"verifyPublishToken");export{ve as acknowledge,D as customReachable,k as mayActAs,K as onQueueSignal,ge as pendingFor,Ee as publishCustom,he as pushLineFor,we as registerCustomObject,_e as unregisterCustomObject,te as upsertKind,ye as verifyPublishToken};
@@ -1,17 +1,13 @@
1
- /** Deleting a node with what it owns (spec §6 "Deletion follows the owner", A9). Rows are kept
2
- * with `deleted_at` so every pointer resolves to "deleted" with the last preview. A document a
3
- * live document outside the deletion links to is kept: it stays owned by the deleted node, under
4
- * its name and rules, and is collected when its last link goes (`collectUnlinked`). */
5
- import type { DatabaseSync } from 'node:sqlite';
6
1
  import type { ObjectRow } from './types.js';
2
+ import { type CanvasDb } from '../canvas/db.js';
7
3
  /** Mark the node and everything it owns deleted except kept documents, which stay owned by the
8
4
  * deleted node; drop the node's watches (both ends) and its `nodes` row. One savepoint, so it runs as one
9
5
  * transaction or inside the caller's. Refuses a node whose managed worktree is unreconciled. */
10
- export declare function deleteNodeWithOwned(db: DatabaseSync, node: ObjectRow): void;
6
+ export declare function deleteNodeWithOwned(db: CanvasDb, node: ObjectRow): Promise<void>;
11
7
  /** Delete a profile object with what it owns, in the same flow as the profile's own deletion
12
8
  * (`crtr profile delete`): its documents follow the node rule — deleted, except one a live document
13
9
  * outside the deletion links to, which stays owned by the deleted profile until its last link goes.
14
10
  * The object row stays with `deleted_at` (kept documents still name it); its handle is released so
15
11
  * a new profile can take the name, and its identity row stays so a kept document's permission
16
12
  * string still names the profile id. Returns whether a profile object existed for `profileId`. */
17
- export declare function deleteProfileWithOwned(db: DatabaseSync, profileId: string): boolean;
13
+ export declare function deleteProfileWithOwned(db: CanvasDb, profileId: string): Promise<boolean>;
@@ -1,6 +1,6 @@
1
- var R=Object.defineProperty;var E=(e,t)=>R(e,"name",{value:t,configurable:!0});import{prepared as n}from"../sqlite-statements.js";import{hasUnreconciledWorktree as f}from"../canvas/worktrees.js";import{deleteDocument as p}from"./documents.js";import{publish as s}from"./events.js";import{getByRowid as w}from"./objects.js";import{rememberDeletedIsolated as S}from"../runs/confinement.js";let a=0;function I(e,t){if(t.type!=="node")throw new Error(`deleteNodeWithOwned: ${t.id} is a ${t.type}, not a node`);if(f(t.id))throw new Error(`refusing to delete node ${t.id}: its managed worktree is not reconciled`);const o=`graph_delete_${++a}`;e.exec(`SAVEPOINT ${o}`);try{h(e,t),e.exec(`RELEASE ${o}`)}catch(i){throw e.exec(`ROLLBACK TO ${o}`),e.exec(`RELEASE ${o}`),i}}E(I,"deleteNodeWithOwned");function j(e,t){const o=n(e,`SELECT o.* FROM identities i JOIN objects o ON o.rowid = i.object
2
- WHERE i.scheme = 'profile' AND i.external_id = ? AND o.type = 'profile' AND o.deleted_at IS NULL`).get(t);if(!o)return!1;const i=`graph_delete_${++a}`;e.exec(`SAVEPOINT ${i}`);try{u(e,o),n(e,"UPDATE objects SET deleted_at = ?, name = ? WHERE rowid = ?").run(new Date().toISOString(),`${o.name}.deleted-${o.rowid}`,o.rowid),s(e,{event:"deleted",object:w(e,o.rowid),actor:null,attrs:{}}),n(e,"DELETE FROM watches WHERE object = ? OR watcher = ?").run(o.rowid,o.rowid),e.exec(`RELEASE ${i}`)}catch(d){throw e.exec(`ROLLBACK TO ${i}`),e.exec(`RELEASE ${i}`),d}return!0}E(j,"deleteProfileWithOwned");function h(e,t){const o=u(e,t);n(e,"UPDATE objects SET deleted_at = ? WHERE rowid = ?").run(o,t.rowid),s(e,{event:"deleted",object:w(e,t.rowid),actor:null,attrs:{}}),n(e,"DELETE FROM watches WHERE object = ? OR watcher = ?").run(t.rowid,t.rowid),S(t.id,e),n(e,"UPDATE nodes SET run_id = NULL WHERE run_id = ? AND node_id != ? AND isolated = 0").run(t.id,t.id),n(e,"DELETE FROM nodes WHERE node_id = ?").run(t.id)}E(h,"deleteInside");function u(e,t){const o=n(e,`WITH RECURSIVE sub(rowid) AS (
1
+ var u=Object.defineProperty;var i=(e,t)=>u(e,"name",{value:t,configurable:!0});import{hasUnreconciledWorktree as f}from"../canvas/worktrees.js";import{deleteDocument as O}from"./documents.js";import{publish as w}from"./events.js";import{getByRowid as d}from"./objects.js";import{rememberDeletedIsolated as R}from"../runs/confinement.js";import{withCanvasWrite as E}from"../canvas/db.js";async function j(e,t){if(t.type!=="node")throw new Error(`deleteNodeWithOwned: ${t.id} is a ${t.type}, not a node`);if(await f(t.id))throw new Error(`refusing to delete node ${t.id}: its managed worktree is not reconciled`);await E(async()=>await m(e,t),{savepoint:!0})}i(j,"deleteNodeWithOwned");async function I(e,t){const r=await e.prepare(`SELECT o.* FROM identities i JOIN objects o ON o.rowid = i.object
2
+ WHERE i.scheme = 'profile' AND i.external_id = ? AND o.type = 'profile' AND o.deleted_at IS NULL`).get(t);return r?(await E(async()=>{await c(e,r),await e.prepare("UPDATE objects SET deleted_at = ?, name = ? WHERE rowid = ?").run(new Date().toISOString(),`${r.name}.deleted-${r.rowid}`,r.rowid),await w(e,{event:"deleted",object:await d(e,r.rowid),actor:null,attrs:{}}),await e.prepare("DELETE FROM watches WHERE object = ? OR watcher = ?").run(r.rowid,r.rowid)},{savepoint:!0}),!0):!1}i(I,"deleteProfileWithOwned");async function m(e,t){const r=await c(e,t);await e.prepare("UPDATE objects SET deleted_at = ? WHERE rowid = ?").run(r,t.rowid),await w(e,{event:"deleted",object:await d(e,t.rowid),actor:null,attrs:{}}),await e.prepare("DELETE FROM watches WHERE object = ? OR watcher = ?").run(t.rowid,t.rowid),await R(t.id,e),await e.prepare("UPDATE nodes SET run_id = NULL WHERE run_id = ? AND node_id != ? AND isolated = 0").run(t.id,t.id),await e.prepare("DELETE FROM nodes WHERE node_id = ?").run(t.id)}i(m,"deleteInside");async function c(e,t){const r=await e.prepare(`WITH RECURSIVE sub(rowid) AS (
3
3
  SELECT rowid FROM objects WHERE owner = ?
4
4
  UNION SELECT o.rowid FROM objects o JOIN sub ON o.owner = sub.rowid)
5
- SELECT o.* FROM objects o JOIN sub ON sub.rowid = o.rowid WHERE o.deleted_at IS NULL`).all(t.rowid),i=new Set(o.map(r=>r.rowid)),d=n(e,`SELECT e.src FROM edges e JOIN objects s ON s.rowid = e.src
6
- WHERE e.type = 'links-to' AND e.dst = ? AND s.deleted_at IS NULL`);for(let r=!0;r;){r=!1;for(const c of o)c.type!=="document"||!i.has(c.rowid)||d.all(c.rowid).some(({src:O})=>!i.has(O))&&(i.delete(c.rowid),r=!0)}const l=new Date().toISOString();for(const r of o)if(i.has(r.rowid)){if(r.type==="document"){p(e,null,r);continue}n(e,"UPDATE objects SET deleted_at = ? WHERE rowid = ?").run(l,r.rowid),s(e,{event:"deleted",object:w(e,r.rowid),actor:null,attrs:{}}),n(e,"DELETE FROM watches WHERE object = ? OR watcher = ?").run(r.rowid,r.rowid)}return l}E(u,"deleteOwned");export{I as deleteNodeWithOwned,j as deleteProfileWithOwned};
5
+ SELECT o.* FROM objects o JOIN sub ON sub.rowid = o.rowid WHERE o.deleted_at IS NULL`).all(t.rowid),a=new Set(r.map(o=>o.rowid)),l=e.prepare(`SELECT e.src FROM edges e JOIN objects s ON s.rowid = e.src
6
+ WHERE e.type = 'links-to' AND e.dst = ? AND s.deleted_at IS NULL`);for(let o=!0;o;){o=!1;for(const n of r)n.type!=="document"||!a.has(n.rowid)||(await l.all(n.rowid)).some(({src:p})=>!a.has(p))&&(a.delete(n.rowid),o=!0)}const s=new Date().toISOString();for(const o of r)if(a.has(o.rowid)){if(o.type==="document"){await O(e,null,o);continue}await e.prepare("UPDATE objects SET deleted_at = ? WHERE rowid = ?").run(s,o.rowid),await w(e,{event:"deleted",object:await d(e,o.rowid),actor:null,attrs:{}}),await e.prepare("DELETE FROM watches WHERE object = ? OR watcher = ?").run(o.rowid,o.rowid)}return s}i(c,"deleteOwned");export{j as deleteNodeWithOwned,I as deleteProfileWithOwned};
@@ -1,9 +1,6 @@
1
- /** Documents: write, CAS edit, revisions and heads, links per revision, record fields, move,
2
- * delete, history, read, and the two import paths (migration, repo sync). Every act records
3
- * its actor's `acted-on` edge and watch and publishes its event in the caller's transaction. */
4
- import type { DatabaseSync } from 'node:sqlite';
5
1
  import { type ReposFn } from './reader.js';
6
2
  import type { ObjectRow, Privacy, Reader, Revision, RuleSpec } from './types.js';
3
+ import { type CanvasDb } from '../canvas/db.js';
7
4
  export interface DocumentFields {
8
5
  preview?: string;
9
6
  summary?: string | null;
@@ -59,31 +56,31 @@ export interface DocumentRead {
59
56
  /** The object a reader acts as: its node, its app, or the person. */
60
57
  export declare function actorOf(reader: Reader): ObjectRow;
61
58
  /** Head revisions (no child), highest number first. More than one means the document needs a merge. */
62
- export declare function heads(db: DatabaseSync, doc: ObjectRow): Revision[];
63
- export declare function documentRecord(db: DatabaseSync, doc: ObjectRow): DocumentRecord;
59
+ export declare function heads(db: CanvasDb, doc: ObjectRow): Promise<Revision[]>;
60
+ export declare function documentRecord(db: CanvasDb, doc: ObjectRow): Promise<DocumentRecord>;
64
61
  /** The `[[name]]` links a body names, in order, each once. */
65
62
  export declare function linksIn(body: string): string[];
66
63
  /** Derive the document's `links-to` edges from `body`, resolving each name in the writer's
67
64
  * view. A name that resolves to nothing or to several objects stays text and is returned,
68
65
  * and remembered so {@link linkNewlyNamed} can link it when a document by that name appears;
69
66
  * one that may live on another runtime is neither linked nor reported. */
70
- export declare function setRevisionLinks(db: DatabaseSync, reader: Reader, doc: ObjectRow, body: string): string[];
67
+ export declare function setRevisionLinks(db: CanvasDb, reader: Reader, doc: ObjectRow, body: string): Promise<string[]>;
71
68
  /** `body` with each `[[link]]` the document's `links-to` edges resolved shown under its target's
72
69
  * current name, so a rename rewrites no stored body yet every read shows the new name (spec §4).
73
70
  * A link written as the target's id, or to a deleted target, stays as written. */
74
- export declare function withCurrentNames(db: DatabaseSync, doc: ObjectRow, body: string): string;
71
+ export declare function withCurrentNames(db: CanvasDb, doc: ObjectRow, body: string): Promise<string>;
75
72
  /** Write the record fields that are present; `null` clears a nullable one. Rules are
76
73
  * replaced when given. Does not publish; callers publish the act the fields belong to. */
77
- export declare function applyDocumentFields(db: DatabaseSync, doc: ObjectRow, fields: DocumentFields): ObjectRow;
74
+ export declare function applyDocumentFields(db: CanvasDb, doc: ObjectRow, fields: DocumentFields): Promise<ObjectRow>;
78
75
  /** Create a document with its first revision. The actor becomes a watcher whose read base is
79
76
  * the new revision; `created` is published. Returns the names that stayed text. */
80
- export declare function writeDocument(db: DatabaseSync, reader: Reader, spec: WriteSpec, body: string, reposFn?: ReposFn): {
77
+ export declare function writeDocument(db: CanvasDb, reader: Reader, spec: WriteSpec, body: string, reposFn?: ReposFn): Promise<{
81
78
  object: ObjectRow;
82
79
  revision: number;
83
80
  unresolved: string[];
84
- };
81
+ }>;
85
82
  /** The base of the reader's next edit: the heads it last read or wrote, or null when it never has. */
86
- export declare function readBase(db: DatabaseSync, reader: Reader, doc: ObjectRow): string | null;
83
+ export declare function readBase(db: CanvasDb, reader: Reader, doc: ObjectRow): Promise<string | null>;
87
84
  /** Apply exact-text replacements to one head's body; each `old` must occur exactly once. */
88
85
  export declare function applyReplacements(body: string, replace: ReadonlyArray<{
89
86
  old: string;
@@ -96,7 +93,7 @@ export declare function applyReplacements(body: string, replace: ReadonlyArray<{
96
93
  * head, so an edit from a read that showed several heads merges them. `fields` are record
97
94
  * changes applied with the edit.
98
95
  */
99
- export declare function editDocument(db: DatabaseSync, reader: Reader, doc: ObjectRow, change: DocumentChange, rationale: string, base: string | null, fields?: DocumentFields, reposFn?: ReposFn): {
96
+ export declare function editDocument(db: CanvasDb, reader: Reader, doc: ObjectRow, change: DocumentChange, rationale: string, base: string | null, fields?: DocumentFields, reposFn?: ReposFn): Promise<{
100
97
  revision: number;
101
98
  heads_key: string;
102
99
  unresolved: string[];
@@ -105,37 +102,37 @@ export declare function editDocument(db: DatabaseSync, reader: Reader, doc: Obje
105
102
  heads_key: string;
106
103
  revision: number;
107
104
  };
108
- };
105
+ }>;
109
106
  /** Change record fields (preview, summary, privacy, rules, …) without a new revision. A null
110
107
  * reader is repo sync, which carries no reader and checks no access. */
111
- export declare function setDocumentRecord(db: DatabaseSync, reader: Reader | null, doc: ObjectRow, fields: DocumentFields): ObjectRow;
108
+ export declare function setDocumentRecord(db: CanvasDb, reader: Reader | null, doc: ObjectRow, fields: DocumentFields): Promise<ObjectRow>;
112
109
  /** Record that the reader holds the document's current heads: a `read` watch with that read
113
110
  * base, and a `read` push. Delivery's content load calls this without reading the body. */
114
- export declare function recordRead(db: DatabaseSync, reader: Reader, doc: ObjectRow, reposFn?: ReposFn): void;
111
+ export declare function recordRead(db: CanvasDb, reader: Reader, doc: ObjectRow, reposFn?: ReposFn): Promise<void>;
115
112
  /** The document's record, each head with its body (several = needs merge) and its links under
116
113
  * their current names; records the read. */
117
- export declare function readDocument(db: DatabaseSync, reader: Reader, doc: ObjectRow, reposFn?: ReposFn): DocumentRead;
114
+ export declare function readDocument(db: CanvasDb, reader: Reader, doc: ObjectRow, reposFn?: ReposFn): Promise<DocumentRead>;
118
115
  /** Every revision, newest first, with authors, rationales and parents. Records nothing. */
119
- export declare function history(db: DatabaseSync, reader: Reader, doc: ObjectRow): Revision[];
116
+ export declare function history(db: CanvasDb, reader: Reader, doc: ObjectRow): Promise<Revision[]>;
120
117
  /** Rename and/or re-own a document. Only `objects` changes: links point at the id, so no body is
121
118
  * rewritten. A null actor is repo sync, which carries no reader and checks no access. */
122
- export declare function moveDocument(db: DatabaseSync, reader: Reader | null, doc: ObjectRow, to: {
119
+ export declare function moveDocument(db: CanvasDb, reader: Reader | null, doc: ObjectRow, to: {
123
120
  name?: string;
124
121
  owner?: ObjectRow;
125
- }, reposFn?: ReposFn): ObjectRow;
122
+ }, reposFn?: ReposFn): Promise<ObjectRow>;
126
123
  /** Mark the document deleted; the row stays with its last preview. Publishes `deleted`
127
124
  * (level 8), then ends the watches on it and drops its rules. A null actor is repo sync or
128
125
  * node deletion; `deletedAt` is the tombstone's own time when sync imports one. What it linked to is re-checked by {@link collectUnlinked}. */
129
- export declare function deleteDocument(db: DatabaseSync, reader: Reader | null, doc: ObjectRow, reposFn?: ReposFn, deletedAt?: string): ObjectRow;
126
+ export declare function deleteDocument(db: CanvasDb, reader: Reader | null, doc: ObjectRow, reposFn?: ReposFn, deletedAt?: string): Promise<ObjectRow>;
130
127
  /** Repo sync: bring a deleted document back under `name` (checked free first). Revisions, record
131
128
  * and links are untouched; the watches and rules deletion dropped are not recreated here. */
132
- export declare function restoreDocument(db: DatabaseSync, doc: ObjectRow, name: string, reposFn?: ReposFn): ObjectRow;
129
+ export declare function restoreDocument(db: CanvasDb, doc: ObjectRow, name: string, reposFn?: ReposFn): Promise<ObjectRow>;
133
130
  /** Delete each of `targets` that is a kept document nothing links to any more: a live document
134
131
  * whose owner is deleted (node deletion kept it because a live document linked to it) and that
135
132
  * no other live document links to. Each one deleted re-checks what it linked to, so chains of
136
133
  * kept documents collapse; a cycle of kept documents keeps itself. Call it after a document
137
134
  * stops linking to `targets` — it was deleted, or an edit dropped the links. */
138
- export declare function collectUnlinked(db: DatabaseSync, targets: Iterable<number>, reposFn?: ReposFn): void;
135
+ export declare function collectUnlinked(db: CanvasDb, targets: Iterable<number>, reposFn?: ReposFn): Promise<void>;
139
136
  export interface ImportedRevision {
140
137
  rev_id?: string;
141
138
  body_hash: string;
@@ -151,7 +148,7 @@ export interface ImportSpec extends WriteSpec {
151
148
  /** Migration: a document with its linear history (oldest first; bodies already in the body
152
149
  * store). Explicit authors and times; records no edge or watch and publishes nothing — the
153
150
  * caller adds links (`setRevisionLinks`), acted-on edges and watches. */
154
- export declare function importDocument(db: DatabaseSync, spec: ImportSpec, reposFn?: ReposFn): ObjectRow;
151
+ export declare function importDocument(db: CanvasDb, spec: ImportSpec, reposFn?: ReposFn): Promise<ObjectRow>;
155
152
  export interface SyncedRevision {
156
153
  rev_id: string;
157
154
  parents: readonly string[];
@@ -163,9 +160,9 @@ export interface SyncedRevision {
163
160
  /** Repo sync: add revisions that arrived from another runtime, skipping known `rev_id`s. No
164
161
  * CAS, author NULL, publishes nothing; the caller publishes `edited` (with `needs_merge`
165
162
  * when `headCount > 1`) and re-derives links from the head it trusts. */
166
- export declare function insertImportedRevisions(db: DatabaseSync, doc: ObjectRow, revs: readonly SyncedRevision[]): {
163
+ export declare function insertImportedRevisions(db: CanvasDb, doc: ObjectRow, revs: readonly SyncedRevision[]): Promise<{
167
164
  heads_key: string;
168
165
  headCount: number;
169
- };
166
+ }>;
170
167
  /** Look up a live document by id (convenience for handlers and importers). */
171
- export declare function documentById(db: DatabaseSync, id: string): ObjectRow;
168
+ export declare function documentById(db: CanvasDb, id: string): Promise<ObjectRow>;
@@ -1,10 +1,10 @@
1
- var ie=Object.defineProperty;var a=(e,t)=>ie(e,"name",{value:t,configurable:!0});import{prepared as l}from"../sqlite-statements.js";import{randomUUID as se}from"node:crypto";import{CrtrError as O,notFound as N,usage as w}from"../errors.js";import{ExitCode as D}from"../../types.js";import{canChange as j,canRead as P,missingMemoryScope as ae,missingMemoryScopeUnder as ue,ownerChain as ce}from"./access.js";import{bodyOf as le,get as me,put as B}from"./bodies.js";import{dropUnresolved as we,linksOf as de,recordActedOn as R,setLinks as K,setUnresolved as pe,unresolvedLinksCouldName as fe}from"./edges.js";import{publish as x}from"./events.js";import{resolveName as he}from"./names.js";import{createObject as Ee,getById as _e,getByRowid as p}from"./objects.js";import{liveLookups as ye,readerForNode as ve,readerForObject as Ne}from"./reader.js";import{replaceRules as G,setRulesOwner as Re}from"./rules.js";import{recordWatch as $}from"./watches.js";function y(e){return e.class==="node"?e.node:e.class==="app"?e.app:e.class==="object"?e.object:e.person}a(y,"actorOf");let ge=0;function E(e,t){const n=`graph_doc_${++ge}`;e.exec(`SAVEPOINT ${n}`);try{const r=t();return e.exec(`RELEASE ${n}`),r}catch(r){throw e.exec(`ROLLBACK TO ${n}`),e.exec(`RELEASE ${n}`),r}}a(E,"atomic");function Se(e,t){return new O("conflict",e,D.GENERAL,t)}a(Se,"conflict");function _(e){if(e.type!=="document")throw w(`${e.type} ${e.id} is not a document`)}a(_,"assertDocument");function V(e,t){const n=ce(e,t);return(n.length?n[n.length-1]:t).type}a(V,"spaceType");function I(e,t,n){if(n!=="public"&&V(e,t)==="repo")throw w(`a repo owns only public documents; ${t.name} cannot own a ${n} one`,{rule:"repo-public-only",next:"Write it as public, or give it another owner (your own documents can carry `if: {repo: <handle>}`)."})}a(I,"assertPublicInRepo");function H(e,t,n,r){if(n.trim()===""||n!==n.trim())throw w(`invalid document name ${JSON.stringify(n)}`);const o=l(e,"SELECT id FROM objects WHERE (type = 'document' OR instr(type, '.') > 0) AND owner = ? AND name = ? AND deleted_at IS NULL AND home_machine IS NULL").get(t.rowid,n);if(o&&o.id!==r?.id)throw Se(`${t.name} already has a document named ${n}`,{name:n,holder:o.id})}a(H,"assertNameFree");function C(e,t,n){if(!P(e,t,n))throw N(`no document ${n.id}`)}a(C,"readable");function Y(e){return new O("scope_missing",`missing scope ${e}`,D.GENERAL,{scope:e})}a(Y,"scopeMissing");function T(e,t,n){C(e,t,n);const r=ae(e,t,n,"rw");if(r!==null)throw Y(r);if(!j(e,t,n))throw new O("forbidden",`you cannot change ${n.name}`,D.GENERAL,{id:n.id})}a(T,"changeable");function X(e,t){const n=l(e,`SELECT p.rev_id FROM revision_parents rp JOIN revisions p ON p.rowid = rp.parent
2
- WHERE rp.child = ? ORDER BY p.rev_id`).all(t.rowid);return{rowid:t.rowid,rev_id:t.rev_id,number:t.number,body_hash:t.body_hash,author:t.author===null?null:p(e,t.author)?.id??null,rationale:t.rationale,verbatim:t.verbatim===1,created_at:t.created_at,parents:n.map(r=>r.rev_id)}}a(X,"toRevision");function U(e,t){return l(e,`SELECT * FROM revisions r WHERE r.document = ?
3
- AND NOT EXISTS (SELECT 1 FROM revision_parents p WHERE p.parent = r.rowid) ORDER BY r.number DESC, r.rev_id`).all(t.rowid).map(r=>X(e,r))}a(U,"heads");function Oe(e){return e.map(t=>t.rev_id).sort().join(",")}a(Oe,"headsKeyOf");function k(e,t){const n=l(e,"SELECT * FROM documents WHERE object = ?").get(t.rowid);if(!n)throw N(`no document record for ${t.id}`);return{summary:n.summary,heads_key:n.heads_key,revision:n.revision,why_it_exists:n.why_it_exists,unlisted:n.unlisted===1,lint_ignore:n.lint_ignore_json===null?null:JSON.parse(n.lint_ignore_json),extensions:n.extensions_json===null?null:JSON.parse(n.extensions_json),source_path:n.source_path}}a(k,"documentRecord");function L(e,t,n){const r=l(e,`INSERT INTO revisions (document, rev_id, number, body_hash, author, rationale, verbatim, created_at)
4
- VALUES (?, ?, ?, ?, ?, ?, ?, ?) RETURNING *`).get(t.rowid,n.rev_id??se(),n.number,n.body_hash,n.author?.rowid??null,n.rationale,n.verbatim?1:0,n.created_at??new Date().toISOString()),o=l(e,"INSERT INTO revision_parents (child, parent) VALUES (?, ?)");for(const i of n.parents)o.run(r.rowid,i);return r}a(L,"insertRevision");function De(e){const t=new Set;for(const n of e.matchAll(/\[\[([^[\]\n]+?)\]\]/g))t.add(n[1].trim());return[...t]}a(De,"linksIn");function q(e,t,n){const r=[],o=[];for(const i of n){const s=he(e,t,i);"object"in s?r.push({written_as:i,dst:s.object}):"deleted"in s?r.push({written_as:i,dst:s.deleted}):"remote"in s||o.push(i)}return{links:r,unresolved:o}}a(q,"resolveLinks");function z(e,t,n,r){const{links:o,unresolved:i}=q(e,t,De(r));return te(e,K(e,n,o)),pe(e,n,i),i}a(z,"setRevisionLinks");function W(e,t,n){const r=new Map;for(const{src:o,name:i}of fe(e,t.name,t.id))r.set(o,[...r.get(o)??[],i]);for(const[o,i]of r){const s=p(e,o),u=s?.owner==null?null:p(e,s.owner);if(!s||s.deleted_at||s.home_machine!==null||!u||u.deleted_at)continue;const c=u.type==="node"?ve(e,u.id,n??(()=>[]),ye(e),!0):Ne(e,s,n),m=q(e,c,i).links.filter(d=>d.dst.rowid===t.rowid);m.length!==0&&(K(e,s,[...de(e,s),...m]),we(e,s,m.map(d=>d.written_as)))}}a(W,"linkNewlyNamed");function xe(e,t,n){return t.type==="node"?t.id:l(e,`SELECT 1 FROM objects o JOIN objects d ON d.owner = o.rowid
1
+ var oe=Object.defineProperty;var s=(e,n)=>oe(e,"name",{value:n,configurable:!0});import{randomUUID as se}from"node:crypto";import{CrtrError as O,notFound as v,usage as p}from"../errors.js";import{ExitCode as D}from"../../types.js";import{canChange as L,canRead as P,missingMemoryScope as we,missingMemoryScopeUnder as ue,ownerChain as ce}from"./access.js";import{bodyOf as pe,get as le,put as B}from"./bodies.js";import{dropUnresolved as me,linksOf as de,recordActedOn as N,setLinks as G,setUnresolved as fe,unresolvedLinksCouldName as ye}from"./edges.js";import{publish as k}from"./events.js";import{resolveName as he}from"./names.js";import{createObject as Ee,getById as _e,getByRowid as m}from"./objects.js";import{liveLookups as ve,readerForNode as Ne,readerForObject as Re}from"./reader.js";import{replaceRules as K,setRulesOwner as ge}from"./rules.js";import{recordWatch as I}from"./watches.js";import{withCanvasWrite as y}from"../canvas/db.js";import{filterAsync as Y,forEachAsync as Se,mapAsync as R}from"../async-array.js";function E(e){return e.class==="node"?e.node:e.class==="app"?e.app:e.class==="object"?e.object:e.person}s(E,"actorOf");function Oe(e,n){return new O("conflict",e,D.GENERAL,n)}s(Oe,"conflict");function h(e){if(e.type!=="document")throw p(`${e.type} ${e.id} is not a document`)}s(h,"assertDocument");async function V(e,n){const t=await ce(e,n);return(t.length?t[t.length-1]:n).type}s(V,"spaceType");async function $(e,n,t){if(t!=="public"&&await V(e,n)==="repo")throw p(`a repo owns only public documents; ${n.name} cannot own a ${t} one`,{rule:"repo-public-only",next:"Write it as public, or give it another owner (your own documents can carry `if: {repo: <handle>}`)."})}s($,"assertPublicInRepo");async function H(e,n,t,a){if(t.trim()===""||t!==t.trim())throw p(`invalid document name ${JSON.stringify(t)}`);const i=await e.prepare("SELECT id FROM objects WHERE (type = 'document' OR instr(type, '.') > 0) AND owner = ? AND name = ? AND deleted_at IS NULL AND home_machine IS NULL").get(n.rowid,t);if(i&&i.id!==a?.id)throw Oe(`${n.name} already has a document named ${t}`,{name:t,holder:i.id})}s(H,"assertNameFree");async function U(e,n,t){if(!await P(e,n,t))throw v(`no document ${t.id}`)}s(U,"readable");function X(e){return new O("scope_missing",`missing scope ${e}`,D.GENERAL,{scope:e})}s(X,"scopeMissing");async function x(e,n,t){await U(e,n,t);const a=await we(e,n,t,"rw");if(a!==null)throw X(a);if(!await L(e,n,t))throw new O("forbidden",`you cannot change ${t.name}`,D.GENERAL,{id:t.id})}s(x,"changeable");async function q(e,n){const t=await e.prepare(`SELECT p.rev_id FROM revision_parents rp JOIN revisions p ON p.rowid = rp.parent
2
+ WHERE rp.child = ? ORDER BY p.rev_id`).all(n.rowid);return{rowid:n.rowid,rev_id:n.rev_id,number:n.number,body_hash:n.body_hash,author:n.author===null?null:(await m(e,n.author))?.id??null,rationale:n.rationale,verbatim:n.verbatim===1,created_at:n.created_at,parents:t.map(a=>a.rev_id)}}s(q,"toRevision");async function C(e,n){const t=await e.prepare(`SELECT * FROM revisions r WHERE r.document = ?
3
+ AND NOT EXISTS (SELECT 1 FROM revision_parents p WHERE p.parent = r.rowid) ORDER BY r.number DESC, r.rev_id`).all(n.rowid);return await R(t,async a=>await q(e,a))}s(C,"heads");function De(e){return e.map(n=>n.rev_id).sort().join(",")}s(De,"headsKeyOf");async function T(e,n){const t=await e.prepare("SELECT * FROM documents WHERE object = ?").get(n.rowid);if(!t)throw v(`no document record for ${n.id}`);return{summary:t.summary,heads_key:t.heads_key,revision:t.revision,why_it_exists:t.why_it_exists,unlisted:t.unlisted===1,lint_ignore:t.lint_ignore_json===null?null:JSON.parse(t.lint_ignore_json),extensions:t.extensions_json===null?null:JSON.parse(t.extensions_json),source_path:t.source_path}}s(T,"documentRecord");async function j(e,n,t){const a=await e.prepare(`INSERT INTO revisions (document, rev_id, number, body_hash, author, rationale, verbatim, created_at)
4
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?) RETURNING *`).get(n.rowid,t.rev_id??se(),t.number,t.body_hash,t.author?.rowid??null,t.rationale,t.verbatim?1:0,t.created_at??new Date().toISOString()),i=e.prepare("INSERT INTO revision_parents (child, parent) VALUES (?, ?)");for(const r of t.parents)await i.run(a.rowid,r);return a}s(j,"insertRevision");function ke(e){const n=new Set;for(const t of e.matchAll(/\[\[([^[\]\n]+?)\]\]/g))n.add(t[1].trim());return[...n]}s(ke,"linksIn");async function z(e,n,t){const a=[],i=[];for(const r of t){const o=await he(e,n,r);"object"in o?a.push({written_as:r,dst:o.object}):"deleted"in o?a.push({written_as:r,dst:o.deleted}):"remote"in o||i.push(r)}return{links:a,unresolved:i}}s(z,"resolveLinks");async function Q(e,n,t,a){const{links:i,unresolved:r}=await z(e,n,ke(a));return await ae(e,await G(e,t,i)),await fe(e,t,r),r}s(Q,"setRevisionLinks");async function W(e,n,t){const a=new Map;for(const{src:i,name:r}of await ye(e,n.name,n.id))a.set(i,[...a.get(i)??[],r]);for(const[i,r]of a){const o=await m(e,i),w=o?.owner==null?null:await m(e,o.owner);if(!o||o.deleted_at||o.home_machine!==null||!w||w.deleted_at)continue;const u=w.type==="node"?await Ne(e,w.id,t??(async()=>[]),ve(e),!0):await Re(e,o,t),c=(await z(e,u,r)).links.filter(l=>l.dst.rowid===n.rowid);c.length!==0&&(await G(e,o,[...await de(e,o),...c]),await me(e,o,c.map(l=>l.written_as)))}}s(W,"linkNewlyNamed");async function xe(e,n,t){return n.type==="node"?n.id:await e.prepare(`SELECT 1 FROM objects o JOIN objects d ON d.owner = o.rowid
5
5
  WHERE o.name = ? AND o.type <> ? AND o.type IN ('person','app','repo','profile')
6
- AND d.type = 'document' AND d.name = ? AND d.deleted_at IS NULL LIMIT 1`).get(t.name,t.type,n)?`${t.type}:${t.name}`:t.name}a(xe,"ownerPrefix");function Q(e,t,n){const r=l(e,`SELECT e.written_as, o.* FROM edges e JOIN objects o ON o.rowid = e.dst
7
- WHERE e.type = 'links-to' AND e.src = ? AND e.written_as IS NOT NULL`).all(t.rowid);if(r.length===0)return n;const o=new Map;for(const i of r){if(i.deleted_at||i.written_as===i.id)continue;const s=!i.written_as.includes("/");if(s&&i.name===i.written_as)continue;const u=i.owner===null?null:p(e,i.owner),c=u?`${xe(e,u,i.name)}/${i.name}`:i.name,m=s&&i.owner===t.owner?i.name:c;m!==i.written_as&&o.set(i.written_as,m)}return o.size===0?n:n.replace(/\[\[([^[\]\n]+?)\]\]/g,(i,s)=>{const u=o.get(s.trim());return u===void 0?i:`[[${u}]]`})}a(Q,"withCurrentNames");function M(e,t,n){if(n.preview!==void 0){if(n.preview.trim()==="")throw w("a document needs a preview",{field:"preview"});l(e,"UPDATE objects SET preview = ? WHERE rowid = ?").run(n.preview,t.rowid)}n.privacy!==void 0&&(I(e,p(e,t.owner),n.privacy),l(e,"UPDATE objects SET privacy = ? WHERE rowid = ?").run(n.privacy,t.rowid));const r=a((i,s)=>e.prepare(`UPDATE documents SET ${i} = ? WHERE object = ?`).run(s,t.rowid),"set");n.summary!==void 0&&r("summary",n.summary),n.whyItExists!==void 0&&r("why_it_exists",n.whyItExists),n.unlisted!==void 0&&r("unlisted",n.unlisted?1:0),n.lintIgnore!==void 0&&r("lint_ignore_json",n.lintIgnore===null?null:JSON.stringify(n.lintIgnore)),n.extensions!==void 0&&r("extensions_json",n.extensions===null?null:JSON.stringify(n.extensions));const o=p(e,t.rowid);return n.rules!==void 0&&G(e,o,n.rules),o}a(M,"applyDocumentFields");function Z(e,t,n){if(t.owner.deleted_at)throw w(`${t.owner.name} is deleted`);if(t.preview.trim()==="")throw w("a document needs a preview",{field:"preview"});I(e,t.owner,t.privacy),H(e,t.owner,t.name);const r=Ee(e,{...t.id?{id:t.id}:{},type:"document",kind:t.kind,owner:t.owner.rowid,privacy:t.privacy,name:t.name,preview:t.preview});l(e,"INSERT INTO documents (object, heads_key, revision) VALUES (?, '', 0)").run(r.rowid);const o=M(e,r,{...t,preview:void 0,privacy:void 0,rules:t.rules??[]});return W(e,o,n),o}a(Z,"createDocument");function F(e,t){const n=U(e,t),r=Oe(n),o=Math.max(0,...n.map(i=>i.number));return l(e,"UPDATE documents SET heads_key = ?, revision = ? WHERE object = ?").run(r,o,t.rowid),{heads_key:r,revision:o,headCount:n.length}}a(F,"setHeads");function Ke(e,t,n,r,o){const i=B(r);return E(e,()=>{const s=y(t),u=ue(e,t,n.owner,"rw");if(u!==null)throw Y(u);const c=Z(e,n,o),m=L(e,c,{number:1,body_hash:i,author:s,rationale:null,parents:[]}),{heads_key:d}=F(e,c);if(!j(e,t,c))throw N(`no owner ${n.owner.name} you can write to`);const f=z(e,t,c,r);return R(e,s,c),$(e,s,c,"write",{readHeadsKey:d}),x(e,{event:"created",object:c,actor:s,attrs:{revision:1},pointer:m.rev_id},o),{object:c,revision:1,unresolved:f}})}a(Ke,"writeDocument");function Ge(e,t,n){return l(e,"SELECT read_heads_key FROM watches WHERE watcher = ? AND object = ?").get(y(t).rowid,n.rowid)?.read_heads_key??null}a(Ge,"readBase");function Te(e,t){let n=e;for(const[r,{old:o,new:i}]of t.entries()){if(o==="")throw w(`block ${r+1}: a replacement needs non-empty old text`,{field:"replace"});const s=n.indexOf(o);if(s<0)throw w(`block ${r+1}: old text not found: ${JSON.stringify(o.slice(0,120))}`,{field:"replace",old:o});if(n.indexOf(o,s+1)>=0)throw w(`block ${r+1}: old text occurs more than once: ${JSON.stringify(o.slice(0,120))}`,{field:"replace",old:o});n=n.slice(0,s)+i+n.slice(s+o.length)}return n}a(Te,"applyReplacements");function Ve(e,t,n,r,o,i,s={},u){if(_(n),T(e,t,n),n.deleted_at)throw w(`${n.name} is deleted`);if(i===null)throw new O("read_first",`read ${n.name} before editing it`,D.GENERAL,{id:n.id});if(o.trim()==="")throw w("an edit needs a rationale",{field:"rationale"});const c=k(e,n);if(c.heads_key!==i)return{stale:{heads_key:c.heads_key,revision:c.revision}};const m=U(e,n);let d;if("body"in r)d=r.body;else{if(m.length!==1)throw w(`${n.name} has ${m.length} heads and needs a merge; pass the whole merged body`,{heads:m.length});d=Te(Q(e,n,me(m[0].body_hash)),r.replace)}const f=B(d);try{return E(e,()=>{const h=y(t),g=1+Math.max(0,...m.map(v=>v.number)),J=L(e,n,{number:g,body_hash:f,author:h,rationale:o,verbatim:r.verbatim===!0,parents:m.map(v=>v.rowid)}),A=J.rev_id,re=l(e,"UPDATE documents SET heads_key = ?, revision = ? WHERE object = ? AND heads_key = ?").run(A,g,n.rowid,i);if(Number(re.changes)===0){const v=k(e,n);throw new b(v.heads_key,v.revision)}const S=M(e,n,s),oe=z(e,t,S,d);return R(e,h,S),$(e,h,S,"write",{readHeadsKey:A}),x(e,{event:"edited",object:S,actor:h,pointer:J.rev_id,attrs:{revision:g,from_revision:c.revision,rationale:o}},u),{revision:g,heads_key:A,unresolved:oe}})}catch(h){if(h instanceof b)return{stale:{heads_key:h.heads_key,revision:h.revision}};throw h}}a(Ve,"editDocument");class b extends Error{static{a(this,"StaleEdit")}heads_key;revision;constructor(t,n){super("stale"),this.heads_key=t,this.revision=n}}function Ye(e,t,n,r){return _(n),t&&T(e,t,n),E(e,()=>{const o=M(e,n,r);return t&&R(e,y(t),o),o})}a(Ye,"setDocumentRecord");function ke(e,t,n,r){const o=y(t),{heads_key:i}=k(e,n);$(e,o,n,"read",{readHeadsKey:i}),x(e,{event:"read",object:n,actor:o,attrs:{}},r)}a(ke,"recordRead");function Xe(e,t,n,r){return _(n),C(e,t,n),E(e,()=>{const o=k(e,n),i=U(e,n).map(u=>({...u,body:Q(e,n,le(u.body_hash,o.source_path))})),s=l(e,"SELECT dst, written_as FROM edges WHERE type = 'links-to' AND src = ? ORDER BY written_as").all(n.rowid).map(u=>({written_as:u.written_as??"",object:p(e,u.dst)})).filter(u=>u.object&&P(e,t,u.object)).map(u=>({...u,deleted:u.object.deleted_at!==null}));return n.deleted_at||ke(e,t,n,r),{object:n,record:o,heads:i,needsMerge:i.length>1,links:s}})}a(Xe,"readDocument");function qe(e,t,n){return _(n),C(e,t,n),l(e,"SELECT * FROM revisions WHERE document = ? ORDER BY number DESC, created_at DESC, rowid DESC").all(n.rowid).map(o=>X(e,o))}a(qe,"history");function ze(e,t,n,r,o){if(_(n),n.deleted_at)throw w(`${n.name} is deleted`);return t&&T(e,t,n),E(e,()=>{const i=r.owner??p(e,n.owner),s=r.name??n.name;H(e,i,s,n),I(e,i,n.privacy),l(e,"UPDATE objects SET name = ?, owner = ? WHERE rowid = ?").run(s,i.rowid,n.rowid);const u=p(e,n.rowid);if(i.rowid!==n.owner&&(Re(e,u),t&&!j(e,t,u)))throw N(`no owner ${i.name} you can move documents to`);return t&&R(e,y(t),u),(s!==n.name||i.rowid!==n.owner)&&W(e,u,o),u})}a(ze,"moveDocument");function Qe(e,t,n,r,o){return _(n),n.deleted_at?n:(t&&T(e,t,n),E(e,()=>{const i=ee(e,t,n,r,o);return te(e,ne(e,n.rowid),r),i}))}a(Qe,"deleteDocument");function Ze(e,t,n,r){return _(t),t.deleted_at?E(e,()=>{H(e,p(e,t.owner),n,t),l(e,"UPDATE objects SET deleted_at = NULL, name = ? WHERE rowid = ?").run(n,t.rowid);const o=p(e,t.rowid);return W(e,o,r),o}):t}a(Ze,"restoreDocument");function ee(e,t,n,r,o){l(e,"UPDATE objects SET deleted_at = ? WHERE rowid = ?").run(o??new Date().toISOString(),n.rowid);const i=p(e,n.rowid),s=t?y(t):null;return s&&R(e,s,i),x(e,{event:"deleted",object:i,actor:s,attrs:{}},r),l(e,"DELETE FROM watches WHERE object = ?").run(n.rowid),G(e,i,[]),i}a(ee,"markDeleted");function ne(e,t){return l(e,"SELECT dst FROM edges WHERE type = 'links-to' AND src = ?").all(t).map(({dst:n})=>n)}a(ne,"linkTargets");function te(e,t,n){const r=l(e,`SELECT 1 FROM objects d JOIN objects w ON w.rowid = d.owner
6
+ AND d.type = 'document' AND d.name = ? AND d.deleted_at IS NULL LIMIT 1`).get(n.name,n.type,t)?`${n.type}:${n.name}`:n.name}s(xe,"ownerPrefix");async function Z(e,n,t){const a=await e.prepare(`SELECT e.written_as, o.* FROM edges e JOIN objects o ON o.rowid = e.dst
7
+ WHERE e.type = 'links-to' AND e.src = ? AND e.written_as IS NOT NULL`).all(n.rowid);if(a.length===0)return t;const i=new Map;for(const r of a){if(r.deleted_at||r.written_as===r.id)continue;const o=!r.written_as.includes("/");if(o&&r.name===r.written_as)continue;const w=r.owner===null?null:await m(e,r.owner),u=w?`${await xe(e,w,r.name)}/${r.name}`:r.name,c=o&&r.owner===n.owner?r.name:u;c!==r.written_as&&i.set(r.written_as,c)}return i.size===0?t:t.replace(/\[\[([^[\]\n]+?)\]\]/g,(r,o)=>{const w=i.get(o.trim());return w===void 0?r:`[[${w}]]`})}s(Z,"withCurrentNames");async function M(e,n,t){if(t.preview!==void 0){if(t.preview.trim()==="")throw p("a document needs a preview",{field:"preview"});await e.prepare("UPDATE objects SET preview = ? WHERE rowid = ?").run(t.preview,n.rowid)}t.privacy!==void 0&&(await $(e,await m(e,n.owner),t.privacy),await e.prepare("UPDATE objects SET privacy = ? WHERE rowid = ?").run(t.privacy,n.rowid));const a=s(async(r,o)=>await e.prepareUncached(`UPDATE documents SET ${r} = ? WHERE object = ?`).run(o,n.rowid),"set");t.summary!==void 0&&await a("summary",t.summary),t.whyItExists!==void 0&&await a("why_it_exists",t.whyItExists),t.unlisted!==void 0&&await a("unlisted",t.unlisted?1:0),t.lintIgnore!==void 0&&await a("lint_ignore_json",t.lintIgnore===null?null:JSON.stringify(t.lintIgnore)),t.extensions!==void 0&&await a("extensions_json",t.extensions===null?null:JSON.stringify(t.extensions));const i=await m(e,n.rowid);return t.rules!==void 0&&await K(e,i,t.rules),i}s(M,"applyDocumentFields");async function b(e,n,t){if(n.owner.deleted_at)throw p(`${n.owner.name} is deleted`);if(n.preview.trim()==="")throw p("a document needs a preview",{field:"preview"});await $(e,n.owner,n.privacy),await H(e,n.owner,n.name);const a=await Ee(e,{...n.id?{id:n.id}:{},type:"document",kind:n.kind,owner:n.owner.rowid,privacy:n.privacy,name:n.name,preview:n.preview});await e.prepare("INSERT INTO documents (object, heads_key, revision) VALUES (?, '', 0)").run(a.rowid);const i=await M(e,a,{...n,preview:void 0,privacy:void 0,rules:n.rules??[]});return await W(e,i,t),i}s(b,"createDocument");async function F(e,n){const t=await C(e,n),a=De(t),i=Math.max(0,...t.map(r=>r.number));return await e.prepare("UPDATE documents SET heads_key = ?, revision = ? WHERE object = ?").run(a,i,n.rowid),{heads_key:a,revision:i,headCount:t.length}}s(F,"setHeads");async function Ye(e,n,t,a,i){const r=B(a);return await y(async()=>{const o=E(n),w=await ue(e,n,t.owner,"rw");if(w!==null)throw X(w);const u=await b(e,t,i),c=await j(e,u,{number:1,body_hash:r,author:o,rationale:null,parents:[]}),{heads_key:l}=await F(e,u);if(!await L(e,n,u))throw v(`no owner ${t.owner.name} you can write to`);const d=await Q(e,n,u,a);return await N(e,o,u),await I(e,o,u,"write",{readHeadsKey:l}),await k(e,{event:"created",object:u,actor:o,attrs:{revision:1},pointer:c.rev_id},i),{object:u,revision:1,unresolved:d}},{savepoint:!0})}s(Ye,"writeDocument");async function Ve(e,n,t){return(await e.prepare("SELECT read_heads_key FROM watches WHERE watcher = ? AND object = ?").get(E(n).rowid,t.rowid))?.read_heads_key??null}s(Ve,"readBase");function Te(e,n){let t=e;for(const[a,{old:i,new:r}]of n.entries()){if(i==="")throw p(`block ${a+1}: a replacement needs non-empty old text`,{field:"replace"});const o=t.indexOf(i);if(o<0)throw p(`block ${a+1}: old text not found: ${JSON.stringify(i.slice(0,120))}`,{field:"replace",old:i});if(t.indexOf(i,o+1)>=0)throw p(`block ${a+1}: old text occurs more than once: ${JSON.stringify(i.slice(0,120))}`,{field:"replace",old:i});t=t.slice(0,o)+r+t.slice(o+i.length)}return t}s(Te,"applyReplacements");async function Xe(e,n,t,a,i,r,o={},w){if(h(t),await x(e,n,t),t.deleted_at)throw p(`${t.name} is deleted`);if(r===null)throw new O("read_first",`read ${t.name} before editing it`,D.GENERAL,{id:t.id});if(i.trim()==="")throw p("an edit needs a rationale",{field:"rationale"});const u=await T(e,t);if(u.heads_key!==r)return{stale:{heads_key:u.heads_key,revision:u.revision}};const c=await C(e,t);let l;if("body"in a)l=a.body;else{if(c.length!==1)throw p(`${t.name} has ${c.length} heads and needs a merge; pass the whole merged body`,{heads:c.length});l=Te(await Z(e,t,le(c[0].body_hash)),a.replace)}const d=B(l);try{return await y(async()=>{const f=E(n),g=1+Math.max(0,...c.map(_=>_.number)),J=await j(e,t,{number:g,body_hash:d,author:f,rationale:i,verbatim:a.verbatim===!0,parents:c.map(_=>_.rowid)}),A=J.rev_id,ie=await e.prepare("UPDATE documents SET heads_key = ?, revision = ? WHERE object = ? AND heads_key = ?").run(A,g,t.rowid,r);if(Number(ie.changes)===0){const _=await T(e,t);throw new ee(_.heads_key,_.revision)}const S=await M(e,t,o),re=await Q(e,n,S,l);return await N(e,f,S),await I(e,f,S,"write",{readHeadsKey:A}),await k(e,{event:"edited",object:S,actor:f,pointer:J.rev_id,attrs:{revision:g,from_revision:u.revision,rationale:i}},w),{revision:g,heads_key:A,unresolved:re}},{savepoint:!0})}catch(f){if(f instanceof ee)return{stale:{heads_key:f.heads_key,revision:f.revision}};throw f}}s(Xe,"editDocument");class ee extends Error{static{s(this,"StaleEdit")}heads_key;revision;constructor(n,t){super("stale"),this.heads_key=n,this.revision=t}}async function qe(e,n,t,a){return h(t),n&&await x(e,n,t),await y(async()=>{const i=await M(e,t,a);return n&&await N(e,E(n),i),i},{savepoint:!0})}s(qe,"setDocumentRecord");async function je(e,n,t,a){const i=E(n),{heads_key:r}=await T(e,t);await I(e,i,t,"read",{readHeadsKey:r}),await k(e,{event:"read",object:t,actor:i,attrs:{}},a)}s(je,"recordRead");async function ze(e,n,t,a){return h(t),await U(e,n,t),await y(async()=>{const i=await T(e,t),r=await R(await C(e,t),async w=>({...w,body:await Z(e,t,pe(w.body_hash,i.source_path))})),o=(await Y(await R(await e.prepare("SELECT dst, written_as FROM edges WHERE type = 'links-to' AND src = ? ORDER BY written_as").all(t.rowid),async w=>({written_as:w.written_as??"",object:await m(e,w.dst)})),async w=>w.object&&await P(e,n,w.object))).map(w=>({...w,deleted:w.object.deleted_at!==null}));return t.deleted_at||await je(e,n,t,a),{object:t,record:i,heads:r,needsMerge:r.length>1,links:o}},{savepoint:!0})}s(ze,"readDocument");async function Qe(e,n,t){h(t),await U(e,n,t);const a=await e.prepare("SELECT * FROM revisions WHERE document = ? ORDER BY number DESC, created_at DESC, rowid DESC").all(t.rowid);return await R(a,async i=>await q(e,i))}s(Qe,"history");async function Ze(e,n,t,a,i){if(h(t),t.deleted_at)throw p(`${t.name} is deleted`);return n&&await x(e,n,t),await y(async()=>{const r=a.owner??await m(e,t.owner),o=a.name??t.name;await H(e,r,o,t),await $(e,r,t.privacy),await e.prepare("UPDATE objects SET name = ?, owner = ? WHERE rowid = ?").run(o,r.rowid,t.rowid);const w=await m(e,t.rowid);if(r.rowid!==t.owner&&(await ge(e,w),n&&!await L(e,n,w)))throw v(`no owner ${r.name} you can move documents to`);return n&&await N(e,E(n),w),(o!==t.name||r.rowid!==t.owner)&&await W(e,w,i),w},{savepoint:!0})}s(Ze,"moveDocument");async function be(e,n,t,a,i){return h(t),t.deleted_at?t:(n&&await x(e,n,t),await y(async()=>{const r=await te(e,n,t,a,i);return await ae(e,await ne(e,t.rowid),a),r},{savepoint:!0}))}s(be,"deleteDocument");async function et(e,n,t,a){return h(n),n.deleted_at?await y(async()=>{await H(e,await m(e,n.owner),t,n),await e.prepare("UPDATE objects SET deleted_at = NULL, name = ? WHERE rowid = ?").run(t,n.rowid);const i=await m(e,n.rowid);return await W(e,i,a),i},{savepoint:!0}):n}s(et,"restoreDocument");async function te(e,n,t,a,i){await e.prepare("UPDATE objects SET deleted_at = ? WHERE rowid = ?").run(i??new Date().toISOString(),t.rowid);const r=await m(e,t.rowid),o=n?E(n):null;return o&&await N(e,o,r),await k(e,{event:"deleted",object:r,actor:o,attrs:{}},a),await e.prepare("DELETE FROM watches WHERE object = ?").run(t.rowid),await K(e,r,[]),r}s(te,"markDeleted");async function ne(e,n){return(await e.prepare("SELECT dst FROM edges WHERE type = 'links-to' AND src = ?").all(n)).map(({dst:t})=>t)}s(ne,"linkTargets");async function ae(e,n,t){const a=e.prepare(`SELECT 1 FROM objects d JOIN objects w ON w.rowid = d.owner
8
8
  WHERE d.rowid = ? AND d.type = 'document' AND d.deleted_at IS NULL AND w.deleted_at IS NOT NULL
9
9
  AND NOT EXISTS (SELECT 1 FROM edges e JOIN objects s ON s.rowid = e.src
10
- WHERE e.type = 'links-to' AND e.dst = d.rowid AND e.src != d.rowid AND s.deleted_at IS NULL)`),o=[...t];for(;o.length>0;){const i=o.pop();r.get(i)!==void 0&&(ee(e,null,p(e,i),n),o.push(...ne(e,i)))}}a(te,"collectUnlinked");function be(e,t,n){if(t.revisions.length===0)throw w(`import of ${t.name}: no revisions`);return E(e,()=>{const r=Z(e,t,n);l(e,"UPDATE objects SET created_at = ? WHERE rowid = ?").run(t.revisions[0].created_at,r.rowid);let o=null;return t.revisions.forEach((i,s)=>{o=L(e,r,{...i,number:s+1,parents:o===null?[]:[o]}).rowid}),F(e,r),p(e,r.rowid)})}a(be,"importDocument");function en(e,t,n){if(_(t),t.privacy!=="public"&&V(e,t)==="repo")throw w(`a repo owns only public documents; refusing revisions of ${t.name}`);return E(e,()=>{const r=l(e,"SELECT rowid, number, document FROM revisions WHERE rev_id = ?");let o=n.filter(u=>!r.get(u.rev_id));for(;o.length>0;){const u=[];for(const c of o){const m=c.parents.map(f=>r.get(f));if(m.some(f=>f===void 0)){u.push(c);continue}const d=m;if(d.some(f=>f.document!==t.rowid))throw w(`revision ${c.rev_id} names a parent of another document`);L(e,t,{...c,author:null,number:1+Math.max(0,...d.map(f=>f.number)),parents:d.map(f=>f.rowid)})}if(u.length===o.length)throw w(`revisions of ${t.name} name unknown parents: ${u.map(c=>c.rev_id).join(", ")}`);o=u}const{heads_key:i,headCount:s}=F(e,t);return{heads_key:i,headCount:s}})}a(en,"insertImportedRevisions");function nn(e,t){const n=_e(e,t);if(!n||n.type!=="document")throw N(`no document ${t}`);return n}a(nn,"documentById");export{y as actorOf,M as applyDocumentFields,Te as applyReplacements,te as collectUnlinked,Qe as deleteDocument,nn as documentById,k as documentRecord,Ve as editDocument,U as heads,qe as history,be as importDocument,en as insertImportedRevisions,De as linksIn,ze as moveDocument,Ge as readBase,Xe as readDocument,ke as recordRead,Ze as restoreDocument,Ye as setDocumentRecord,z as setRevisionLinks,Q as withCurrentNames,Ke as writeDocument};
10
+ WHERE e.type = 'links-to' AND e.dst = d.rowid AND e.src != d.rowid AND s.deleted_at IS NULL)`),i=[...n];for(;i.length>0;){const r=i.pop();await a.get(r)!==void 0&&(await te(e,null,await m(e,r),t),i.push(...await ne(e,r)))}}s(ae,"collectUnlinked");async function tt(e,n,t){if(n.revisions.length===0)throw p(`import of ${n.name}: no revisions`);return await y(async()=>{const a=await b(e,n,t);await e.prepare("UPDATE objects SET created_at = ? WHERE rowid = ?").run(n.revisions[0].created_at,a.rowid);let i=null;return await Se(n.revisions,async(r,o)=>{i=(await j(e,a,{...r,number:o+1,parents:i===null?[]:[i]})).rowid}),await F(e,a),await m(e,a.rowid)},{savepoint:!0})}s(tt,"importDocument");async function nt(e,n,t){if(h(n),n.privacy!=="public"&&await V(e,n)==="repo")throw p(`a repo owns only public documents; refusing revisions of ${n.name}`);return await y(async()=>{const a=e.prepare("SELECT rowid, number, document FROM revisions WHERE rev_id = ?");let i=await Y(t,async w=>!await a.get(w.rev_id));for(;i.length>0;){const w=[];for(const u of i){const c=await R(u.parents,async d=>await a.get(d));if(c.some(d=>d===void 0)){w.push(u);continue}const l=c;if(l.some(d=>d.document!==n.rowid))throw p(`revision ${u.rev_id} names a parent of another document`);await j(e,n,{...u,author:null,number:1+Math.max(0,...l.map(d=>d.number)),parents:l.map(d=>d.rowid)})}if(w.length===i.length)throw p(`revisions of ${n.name} name unknown parents: ${w.map(u=>u.rev_id).join(", ")}`);i=w}const{heads_key:r,headCount:o}=await F(e,n);return{heads_key:r,headCount:o}},{savepoint:!0})}s(nt,"insertImportedRevisions");async function at(e,n){const t=await _e(e,n);if(!t||t.type!=="document")throw v(`no document ${n}`);return t}s(at,"documentById");export{E as actorOf,M as applyDocumentFields,Te as applyReplacements,ae as collectUnlinked,be as deleteDocument,at as documentById,T as documentRecord,Xe as editDocument,C as heads,Qe as history,tt as importDocument,nt as insertImportedRevisions,ke as linksIn,Ze as moveDocument,Ve as readBase,ze as readDocument,je as recordRead,et as restoreDocument,qe as setDocumentRecord,Q as setRevisionLinks,Z as withCurrentNames,Ye as writeDocument};
@@ -1,6 +1,6 @@
1
1
  /** `acted-on` and `links-to` edges. An edge is visible only to a reader who may read both ends. */
2
- import type { DatabaseSync } from 'node:sqlite';
3
2
  import type { ObjectRow, Reader } from './types.js';
3
+ import type { CanvasDb } from '../canvas/db.js';
4
4
  export type EdgeType = 'acted-on' | 'links-to';
5
5
  export interface Edge {
6
6
  type: EdgeType;
@@ -10,32 +10,32 @@ export interface Edge {
10
10
  created_at: string;
11
11
  }
12
12
  /** One row per actor and object however many times the actor acts. */
13
- export declare function recordActedOn(db: DatabaseSync, actor: ObjectRow, object: ObjectRow): void;
13
+ export declare function recordActedOn(db: CanvasDb, actor: ObjectRow, object: ObjectRow): Promise<void>;
14
14
  /** Replace the document's `links-to` edges with the links of its current revision. Answers the
15
15
  * rowids it no longer links to, so the caller can collect a kept document that lost its last link. */
16
- export declare function setLinks(db: DatabaseSync, doc: ObjectRow, links: ReadonlyArray<{
16
+ export declare function setLinks(db: CanvasDb, doc: ObjectRow, links: ReadonlyArray<{
17
17
  written_as: string;
18
18
  dst: ObjectRow;
19
- }>): number[];
19
+ }>): Promise<number[]>;
20
20
  /** Replace the names the document's current revision links that resolved to nothing or to several objects.
21
21
  * Kept so that when a document with such a name comes into being, the link can gain its edge. */
22
- export declare function setUnresolved(db: DatabaseSync, doc: ObjectRow, names: readonly string[]): void;
22
+ export declare function setUnresolved(db: CanvasDb, doc: ObjectRow, names: readonly string[]): Promise<void>;
23
23
  /** Forget `names` among the document's remembered unresolved links: they have gained an edge. */
24
- export declare function dropUnresolved(db: DatabaseSync, doc: ObjectRow, names: Iterable<string>): void;
24
+ export declare function dropUnresolved(db: CanvasDb, doc: ObjectRow, names: Iterable<string>): Promise<void>;
25
25
  /** The unresolved links, as `{src, name}`, whose written name is the document's id or `name`, or ends in `/<name>`: every
26
26
  * link that could name a document called `name`, bare or qualified by its owner. */
27
- export declare function unresolvedLinksCouldName(db: DatabaseSync, name: string, id: string): Array<{
27
+ export declare function unresolvedLinksCouldName(db: CanvasDb, name: string, id: string): Promise<Array<{
28
28
  src: number;
29
29
  name: string;
30
- }>;
30
+ }>>;
31
31
  /** The document's current `links-to` edges as the links they were written from. */
32
- export declare function linksOf(db: DatabaseSync, doc: ObjectRow): Array<{
32
+ export declare function linksOf(db: CanvasDb, doc: ObjectRow): Promise<Array<{
33
33
  written_as: string;
34
34
  dst: ObjectRow;
35
- }>;
35
+ }>>;
36
36
  /** Documents whose body links to `object`. */
37
- export declare function backlinks(db: DatabaseSync, reader: Reader, object: ObjectRow): Edge[];
38
- export declare function edgesOf(db: DatabaseSync, reader: Reader, object: ObjectRow, opts?: {
37
+ export declare function backlinks(db: CanvasDb, reader: Reader, object: ObjectRow): Promise<Edge[]>;
38
+ export declare function edgesOf(db: CanvasDb, reader: Reader, object: ObjectRow, opts?: {
39
39
  type?: EdgeType;
40
40
  direction?: 'out' | 'in' | 'both';
41
- }): Edge[];
41
+ }): Promise<Edge[]>;
@@ -1 +1 @@
1
- var m=Object.defineProperty;var c=(t,e)=>m(t,"name",{value:e,configurable:!0});import{prepared as i}from"../sqlite-statements.js";import{canRead as O}from"./access.js";import{getByRowid as p}from"./objects.js";function L(t,e,n){i(t,"INSERT OR IGNORE INTO edges (type, src, dst, written_as, created_at) VALUES ('acted-on', ?, ?, NULL, ?)").run(e.rowid,n.rowid,new Date().toISOString())}c(L,"recordActedOn");function T(t,e,n){const s=i(t,"SELECT dst FROM edges WHERE type = 'links-to' AND src = ?").all(e.rowid).map(({dst:o})=>o);i(t,"DELETE FROM edges WHERE type = 'links-to' AND src = ?").run(e.rowid);const d=i(t,"INSERT OR IGNORE INTO edges (type, src, dst, written_as, created_at) VALUES ('links-to', ?, ?, ?, ?)"),u=new Date().toISOString();for(const o of n)d.run(e.rowid,o.dst.rowid,o.written_as,u);const a=new Set(n.map(o=>o.dst.rowid));return s.filter(o=>!a.has(o))}c(T,"setLinks");function D(t,e,n){i(t,"DELETE FROM unresolved_links WHERE src = ?").run(e.rowid);const s=i(t,"INSERT OR IGNORE INTO unresolved_links (src, name) VALUES (?, ?)");for(const d of n)s.run(e.rowid,d)}c(D,"setUnresolved");function g(t,e,n){const s=i(t,"DELETE FROM unresolved_links WHERE src = ? AND name = ?");for(const d of n)s.run(e.rowid,d)}c(g,"dropUnresolved");function I(t,e,n){return i(t,"SELECT src, name FROM unresolved_links WHERE name = ? OR name = ? OR substr(name, -length(?) - 1) = '/' || ? ORDER BY src, name").all(e,n,e,e)}c(I,"unresolvedLinksCouldName");function A(t,e){return i(t,"SELECT e.dst, e.written_as FROM edges e WHERE e.type = 'links-to' AND e.src = ? ORDER BY e.written_as").all(e.rowid).map(s=>({written_as:s.written_as??"",dst:p(t,s.dst)}))}c(A,"linksOf");function h(t,e,n){return S(t,e,n,{type:"links-to",direction:"in"})}c(h,"backlinks");function S(t,e,n,s={}){if(!O(t,e,n))return[];const d=s.direction??"both",u=s.type?[s.type]:["acted-on","links-to"],a=[];for(const r of u)d!=="in"&&a.push(...i(t,"SELECT * FROM edges WHERE type = ? AND src = ?").all(r,n.rowid)),d!=="out"&&a.push(...i(t,"SELECT * FROM edges WHERE type = ? AND dst = ?").all(r,n.rowid));const o=new Set,w=[];for(const r of a){const R=`${r.type}|${r.src}|${r.dst}`;if(o.has(R))continue;o.add(R);const E=r.src===n.rowid?n:p(t,r.src),l=r.dst===n.rowid?n:p(t,r.dst);if(!E||!l)continue;const f=E===n?l:E;f!==n&&!O(t,e,f)||w.push({type:r.type,src:E,dst:l,written_as:r.written_as,created_at:r.created_at})}return w}c(S,"edgesOf");export{h as backlinks,g as dropUnresolved,S as edgesOf,A as linksOf,L as recordActedOn,T as setLinks,D as setUnresolved,I as unresolvedLinksCouldName};
1
+ var y=Object.defineProperty;var i=(t,r)=>y(t,"name",{value:r,configurable:!0});import{canRead as f}from"./access.js";import{getByRowid as E}from"./objects.js";import{mapAsync as O}from"../async-array.js";async function L(t,r,e){await t.prepare("INSERT OR IGNORE INTO edges (type, src, dst, written_as, created_at) VALUES ('acted-on', ?, ?, NULL, ?)").run(r.rowid,e.rowid,new Date().toISOString())}i(L,"recordActedOn");async function T(t,r,e){const s=(await t.prepare("SELECT dst FROM edges WHERE type = 'links-to' AND src = ?").all(r.rowid)).map(({dst:a})=>a);await t.prepare("DELETE FROM edges WHERE type = 'links-to' AND src = ?").run(r.rowid);const o=t.prepare("INSERT OR IGNORE INTO edges (type, src, dst, written_as, created_at) VALUES ('links-to', ?, ?, ?, ?)"),w=new Date().toISOString();for(const a of e)await o.run(r.rowid,a.dst.rowid,a.written_as,w);const c=new Set(e.map(a=>a.dst.rowid));return s.filter(a=>!c.has(a))}i(T,"setLinks");async function D(t,r,e){await t.prepare("DELETE FROM unresolved_links WHERE src = ?").run(r.rowid);const s=t.prepare("INSERT OR IGNORE INTO unresolved_links (src, name) VALUES (?, ?)");for(const o of e)await s.run(r.rowid,o)}i(D,"setUnresolved");async function g(t,r,e){const s=t.prepare("DELETE FROM unresolved_links WHERE src = ? AND name = ?");for(const o of e)await s.run(r.rowid,o)}i(g,"dropUnresolved");async function A(t,r,e){return await t.prepare("SELECT src, name FROM unresolved_links WHERE name = ? OR name = ? OR substr(name, -length(?) - 1) = '/' || ? ORDER BY src, name").all(r,e,r,r)}i(A,"unresolvedLinksCouldName");async function I(t,r){const e=await t.prepare("SELECT e.dst, e.written_as FROM edges e WHERE e.type = 'links-to' AND e.src = ? ORDER BY e.written_as").all(r.rowid);return await O(e,async s=>({written_as:s.written_as??"",dst:await E(t,s.dst)}))}i(I,"linksOf");async function h(t,r,e){return await m(t,r,e,{type:"links-to",direction:"in"})}i(h,"backlinks");async function m(t,r,e,s={}){if(!await f(t,r,e))return[];const o=s.direction??"both",w=s.type?[s.type]:["acted-on","links-to"],c=[];for(const n of w)o!=="in"&&c.push(...await t.prepare("SELECT * FROM edges WHERE type = ? AND src = ?").all(n,e.rowid)),o!=="out"&&c.push(...await t.prepare("SELECT * FROM edges WHERE type = ? AND dst = ?").all(n,e.rowid));const a=new Set,u=[];for(const n of c){const l=`${n.type}|${n.src}|${n.dst}`;if(a.has(l))continue;a.add(l);const p=n.src===e.rowid?e:await E(t,n.src),d=n.dst===e.rowid?e:await E(t,n.dst);if(!p||!d)continue;const R=p===e?d:p;R!==e&&!await f(t,r,R)||u.push({type:n.type,src:p,dst:d,written_as:n.written_as,created_at:n.created_at})}return u}i(m,"edgesOf");export{h as backlinks,g as dropUnresolved,m as edgesOf,I as linksOf,L as recordActedOn,T as setLinks,D as setUnresolved,A as unresolvedLinksCouldName};
@@ -1,12 +1,10 @@
1
- /** The event catalog, subject matching, listening-config resolution and `publish`: the one
2
- * path by which an event on an object reaches its watchers' inboxes. */
3
- import type { DatabaseSync } from 'node:sqlite';
4
- export declare function subscribeDocumentEvents(id: string, callback: (event: 'edited' | 'deleted') => void): () => void;
1
+ export declare function subscribeDocumentEvents(id: string, callback: (event: 'edited' | 'deleted') => void): Promise<() => void>;
5
2
  import { type ReposFn } from './reader.js';
6
3
  import { type Subscription } from './watches.js';
7
4
  import { CrtrError } from '../errors.js';
8
5
  import type { EventSpec } from './kinds/kind.js';
9
6
  import { type CanvasEvent, type Level, type ListenConfig, type ListenDelivery, type ObjectRow } from './types.js';
7
+ import { type CanvasDb } from '../canvas/db.js';
10
8
  /** The level `ev` publishes at: the declared level when none is supplied; a supplied level
11
9
  * must equal it or be one of the event's declared `levels`. Throws `unknown_event` for an
12
10
  * event the object's kind does not declare, `invalid_level` for any other level. */
@@ -17,7 +15,7 @@ export declare function matchSubject(pattern: string, event: string): boolean;
17
15
  * strongest. Null when the level is below every threshold of every config. */
18
16
  export declare function resolveDelivery(configs: readonly ListenConfig[], level: Level): ListenDelivery | null;
19
17
  /** A subscription's own config, else the watcher's `objects.listen_json`, else the global default. */
20
- export declare function listenConfigFor(db: DatabaseSync, subscription: Pick<Subscription, 'config'>, watcher: ObjectRow): ListenConfig;
18
+ export declare function listenConfigFor(db: CanvasDb, subscription: Pick<Subscription, 'config'>, watcher: ObjectRow): Promise<ListenConfig>;
21
19
  /** Supersede (`spec.supersedes`): each destination's pending deliveries of the same
22
20
  * event on the same object are deleted. A receiver kind may fence its claimed delivery if
23
21
  * that in-flight execution is replaceable. The replacement carries `spec.merge(prior, ev)` —
@@ -26,10 +24,10 @@ export declare function listenConfigFor(db: DatabaseSync, subscription: Pick<Sub
26
24
  * each group shares one replacement message. Messages left with no delivery are deleted.
27
25
  * The core selects matches by delivery destination and the message's event and object.
28
26
  * An event that does not supersede is one group with its own attrs. */
29
- export declare function supersede<D>(db: DatabaseSync, ev: CanvasEvent, spec: EventSpec, destinations: readonly D[], idOf: (d: D) => string): Array<{
27
+ export declare function supersede<D>(db: CanvasDb, ev: CanvasEvent, spec: EventSpec, destinations: readonly D[], idOf: (d: D) => string): Promise<Array<{
30
28
  attrs: Record<string, unknown>;
31
29
  destinations: D[];
32
- }>;
30
+ }>>;
33
31
  /**
34
32
  * Validate the event against its object's kind (`resolveLevel`), then push it to every watcher of
35
33
  * the object itself whose subscriptions receive it — a watch on an owner hears that owner's own
@@ -44,8 +42,8 @@ export declare const HOP_LIMIT = 8;
44
42
  export declare class HopLimitError extends CrtrError {
45
43
  constructor(depth: number);
46
44
  }
47
- export declare function publish(db: DatabaseSync, input: CanvasEvent, reposFn?: ReposFn): {
45
+ export declare function publish(db: CanvasDb, input: CanvasEvent, reposFn?: ReposFn): Promise<{
48
46
  delivered: number;
49
47
  message_id: string | null;
50
48
  depth: number;
51
- };
49
+ }>;