@north-light/cli 0.3.532 → 0.3.534

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 (203) hide show
  1. package/dist/api/client.d.ts +6 -3
  2. package/dist/api/client.js +1 -1
  3. package/dist/api/contract.d.ts +1 -1
  4. package/dist/api/contract.js +1 -1
  5. package/dist/api/dto/canvas.d.ts +2 -0
  6. package/dist/api/dto/crons.d.ts +3 -1
  7. package/dist/builtin-memory/crouter-sdk/release-notes.md +13 -0
  8. package/dist/builtin-memory/northlight-apps/providers/README.md +2 -0
  9. package/dist/builtin-memory/northlight-apps/providers/sms.md +2 -0
  10. package/dist/clients/attach/chrome/inbox-strip.d.ts +6 -1
  11. package/dist/clients/attach/chrome/inbox-strip.js +1 -1
  12. package/dist/clients/attach/chrome/roster.js +1 -1
  13. package/dist/clients/attach/session/chrome-refresh.d.ts +12 -3
  14. package/dist/clients/attach/session/chrome-refresh.js +1 -1
  15. package/dist/clients/attach/session/document-links.js +1 -1
  16. package/dist/clients/attach/viewer.js +586 -587
  17. package/dist/commands/api-client.js +3 -3
  18. package/dist/commands/canvas.js +1 -1
  19. package/dist/commands/node/inspect.js +6 -6
  20. package/dist/commands/sys/context/expose.js +2 -2
  21. package/dist/commands/sys/db.d.ts +1 -0
  22. package/dist/commands/sys/db.js +1 -0
  23. package/dist/commands/sys.js +1 -1
  24. package/dist/core/bash-guard.js +9 -3
  25. package/dist/core/canvas/canvas.d.ts +12 -2
  26. package/dist/core/canvas/canvas.js +23 -20
  27. package/dist/core/canvas/daemon-actions.d.ts +0 -3
  28. package/dist/core/canvas/daemon-actions.js +7 -24
  29. package/dist/core/canvas/daemon-owner.d.ts +3 -0
  30. package/dist/core/canvas/daemon-owner.js +1 -6
  31. package/dist/core/canvas/db.d.ts +28 -20
  32. package/dist/core/canvas/db.js +4 -3
  33. package/dist/core/canvas/deliveries.d.ts +5 -0
  34. package/dist/core/canvas/deliveries.js +25 -30
  35. package/dist/core/canvas/export-sqlite.d.ts +14 -0
  36. package/dist/core/canvas/export-sqlite.js +3 -0
  37. package/dist/core/canvas/import-sqlite.d.ts +44 -0
  38. package/dist/core/canvas/import-sqlite.js +7 -0
  39. package/dist/core/canvas/node-tokens.js +3 -3
  40. package/dist/core/canvas/outcome-actions.js +4 -4
  41. package/dist/core/canvas/recovery.js +1 -1
  42. package/dist/core/canvas/schema-pg.sql +1022 -0
  43. package/dist/core/canvas/schema-version.d.ts +4 -0
  44. package/dist/core/canvas/schema-version.js +1 -0
  45. package/dist/core/canvas/sessions.js +3 -3
  46. package/dist/core/canvas/structured-requests.js +2 -2
  47. package/dist/core/canvas/tree.js +6 -6
  48. package/dist/core/canvas/waits.js +1 -1
  49. package/dist/core/feed/inbox.js +1 -1
  50. package/dist/core/feed/messages.js +5 -5
  51. package/dist/core/feed/reports.js +2 -2
  52. package/dist/core/grants/mirror.js +2 -2
  53. package/dist/core/graph/access.js +7 -7
  54. package/dist/core/graph/custom.js +10 -10
  55. package/dist/core/graph/deletion.js +6 -6
  56. package/dist/core/graph/documents.d.ts +1 -1
  57. package/dist/core/graph/documents.js +9 -9
  58. package/dist/core/graph/edges.d.ts +3 -3
  59. package/dist/core/graph/edges.js +3 -1
  60. package/dist/core/graph/events.js +7 -7
  61. package/dist/core/graph/exposures.d.ts +8 -8
  62. package/dist/core/graph/jobs.d.ts +1 -1
  63. package/dist/core/graph/jobs.js +2 -2
  64. package/dist/core/graph/kinds/custom.js +1 -1
  65. package/dist/core/graph/kinds/document.js +4 -4
  66. package/dist/core/graph/kinds/dto.js +1 -1
  67. package/dist/core/graph/kinds/job.js +2 -2
  68. package/dist/core/graph/kinds/kind.d.ts +2 -2
  69. package/dist/core/graph/kinds/kind.js +1 -1
  70. package/dist/core/graph/kinds/live-read.d.ts +5 -0
  71. package/dist/core/graph/kinds/live-read.js +1 -0
  72. package/dist/core/graph/kinds/node.js +5 -5
  73. package/dist/core/graph/kinds/owner.js +2 -2
  74. package/dist/core/graph/names.js +3 -3
  75. package/dist/core/graph/objects.d.ts +5 -5
  76. package/dist/core/graph/objects.js +10 -10
  77. package/dist/core/graph/package-docs.js +6 -5
  78. package/dist/core/graph/reader.d.ts +1 -1
  79. package/dist/core/graph/reader.js +2 -2
  80. package/dist/core/graph/receivers.js +4 -5
  81. package/dist/core/graph/repo-sync/exchange.js +2 -2
  82. package/dist/core/graph/repo-sync/repos.js +3 -3
  83. package/dist/core/graph/repo-sync/sync.js +1 -1
  84. package/dist/core/graph/rules.d.ts +3 -4
  85. package/dist/core/graph/rules.js +3 -3
  86. package/dist/core/graph/spaces/app.js +1 -1
  87. package/dist/core/graph/spaces/index.d.ts +1 -1
  88. package/dist/core/graph/spaces/index.js +1 -1
  89. package/dist/core/graph/spaces/own-memory.js +1 -1
  90. package/dist/core/graph/spaces/person.js +3 -3
  91. package/dist/core/graph/spaces/repo.d.ts +1 -1
  92. package/dist/core/graph/spaces/repo.js +1 -1
  93. package/dist/core/graph/types.d.ts +4 -3
  94. package/dist/core/graph/watches.d.ts +2 -2
  95. package/dist/core/graph/watches.js +17 -17
  96. package/dist/core/human/page-schema.js +5 -4
  97. package/dist/core/human/requests.d.ts +1 -1
  98. package/dist/core/human/requests.js +20 -23
  99. package/dist/core/peer/ingest.js +1 -1
  100. package/dist/core/peer/receiver.js +1 -1
  101. package/dist/core/peer/stubs.js +1 -1
  102. package/dist/core/providers/receipts.js +3 -2
  103. package/dist/core/review/comments.js +5 -4
  104. package/dist/core/runs/activity.js +4 -5
  105. package/dist/core/runs/confinement.d.ts +1 -1
  106. package/dist/core/runs/confinement.js +2 -2
  107. package/dist/core/runs/events.d.ts +1 -1
  108. package/dist/core/runs/events.js +5 -5
  109. package/dist/core/runs/operations.js +6 -4
  110. package/dist/core/runs/questions.d.ts +2 -0
  111. package/dist/core/runs/questions.js +1 -1
  112. package/dist/core/runtime/close.d.ts +3 -0
  113. package/dist/core/runtime/close.js +1 -1
  114. package/dist/core/runtime/host.d.ts +5 -1
  115. package/dist/core/runtime/host.js +3 -3
  116. package/dist/core/runtime/launch.js +2 -2
  117. package/dist/core/runtime/ledger.js +3 -3
  118. package/dist/core/runtime/lifecycle.d.ts +9 -0
  119. package/dist/core/runtime/lifecycle.js +2 -2
  120. package/dist/core/runtime/nodes.d.ts +1 -1
  121. package/dist/core/runtime/nodes.js +1 -1
  122. package/dist/core/runtime/roadmap.js +1 -1
  123. package/dist/core/spaces/stop.d.ts +1 -0
  124. package/dist/core/spaces/stop.js +2 -2
  125. package/dist/core/statements.d.ts +17 -0
  126. package/dist/core/statements.js +2 -0
  127. package/dist/core/substrate/delivery/corpus.js +3 -3
  128. package/dist/core/substrate/delivery/deliver.js +5 -5
  129. package/dist/core/substrate/delivery/listings.js +1 -1
  130. package/dist/core/substrate/delivery/match.d.ts +2 -2
  131. package/dist/core/substrate/delivery/match.js +1 -1
  132. package/dist/core/substrate/delivery/plan.js +3 -3
  133. package/dist/core/substrate/delivery/render-boot.js +5 -5
  134. package/dist/core/substrate/delivery/render-event.js +6 -6
  135. package/dist/core/usage/ledger.js +8 -8
  136. package/dist/core/worktree.js +8 -8
  137. package/dist/daemon/api/bridge.js +4 -4
  138. package/dist/daemon/api/document-listener.js +1 -1
  139. package/dist/daemon/api/handlers/broker-ops.js +1 -1
  140. package/dist/daemon/api/handlers/canvas.js +1 -1
  141. package/dist/daemon/api/handlers/crons.js +1 -1
  142. package/dist/daemon/api/handlers/custom-objects.js +3 -3
  143. package/dist/daemon/api/handlers/docs.js +1 -1
  144. package/dist/daemon/api/handlers/inbox.js +1 -1
  145. package/dist/daemon/api/handlers/memory.js +7 -7
  146. package/dist/daemon/api/handlers/messages.js +1 -1
  147. package/dist/daemon/api/handlers/nodes.js +1 -1
  148. package/dist/daemon/api/handlers/objects.js +3 -3
  149. package/dist/daemon/api/handlers/questions.js +1 -1
  150. package/dist/daemon/api/handlers/reviews.js +1 -1
  151. package/dist/daemon/api/handlers/structured-requests.js +1 -1
  152. package/dist/daemon/api/reader.js +1 -1
  153. package/dist/daemon/broker-signals/bus.d.ts +14 -6
  154. package/dist/daemon/broker-signals/bus.js +1 -10
  155. package/dist/daemon/cron/ended.d.ts +3 -0
  156. package/dist/daemon/cron/ended.js +2 -2
  157. package/dist/daemon/cron/narrowed.d.ts +5 -0
  158. package/dist/daemon/cron/narrowed.js +2 -0
  159. package/dist/daemon/cron/settle.js +1 -1
  160. package/dist/daemon/crtrd-cli.js +1 -1
  161. package/dist/daemon/crtrd.js +12 -11
  162. package/dist/daemon/due.js +1 -1
  163. package/dist/daemon/export-sqlite-run.d.ts +1 -0
  164. package/dist/daemon/export-sqlite-run.js +4 -0
  165. package/dist/daemon/fleet.d.ts +1 -0
  166. package/dist/daemon/fleet.js +3 -3
  167. package/dist/daemon/human/settle.js +1 -1
  168. package/dist/daemon/manage.d.ts +10 -0
  169. package/dist/daemon/manage.js +3 -2
  170. package/dist/daemon/postgres/binary.d.ts +17 -0
  171. package/dist/daemon/postgres/binary.js +2 -0
  172. package/dist/daemon/postgres/cluster.d.ts +37 -0
  173. package/dist/daemon/postgres/cluster.js +6 -0
  174. package/dist/daemon/postgres/index.d.ts +2 -0
  175. package/dist/daemon/postgres/index.js +1 -0
  176. package/dist/daemon/postgres/pins.d.ts +7 -0
  177. package/dist/daemon/postgres/pins.js +1 -0
  178. package/dist/daemon/postgres/supervisor.d.ts +95 -0
  179. package/dist/daemon/postgres/supervisor.js +2 -0
  180. package/dist/daemon/reconcilers/bash-deadline.js +2 -2
  181. package/dist/daemon/reconcilers/delivery-lane.js +2 -2
  182. package/dist/daemon/reconcilers/node-lifecycle/freeze-lane.d.ts +7 -3
  183. package/dist/daemon/reconcilers/node-lifecycle/freeze-lane.js +1 -1
  184. package/dist/daemon/reconcilers/node-lifecycle/tick.js +1 -1
  185. package/dist/daemon/reconcilers/storage-maintenance.d.ts +0 -6
  186. package/dist/daemon/reconcilers/storage-maintenance.js +1 -8
  187. package/dist/daemon/runs/observer.js +5 -4
  188. package/dist/migrations/004-canvas-documents/index.js +1 -1
  189. package/dist/pi-extensions/canvas-doc-substrate.d.ts +2 -0
  190. package/dist/pi-extensions/canvas-doc-substrate.js +6 -6
  191. package/dist/pi-extensions/envelope-merge.d.ts +3 -2
  192. package/dist/pi-extensions/envelope-merge.js +9 -8
  193. package/dist/shared/env.d.ts +3 -0
  194. package/dist/shared/env.js +2 -2
  195. package/docs/apps/providers/README.md +2 -0
  196. package/docs/apps/providers/sms.md +2 -0
  197. package/docs/public-api.md +11 -2
  198. package/docs/sdk/release-notes.md +13 -0
  199. package/package.json +6 -6
  200. package/packages/crouter-identity/package.json +1 -1
  201. package/runtime.lock.json +13 -26
  202. package/scripts/install-runtime.mjs +53 -3
  203. package/scripts/lib/isolation-env.mjs +3 -1
@@ -12,11 +12,11 @@ export interface Edge {
12
12
  /** One row per actor and object however many times the actor acts. */
13
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
- * rowids it no longer links to, so the caller can collect a kept document that lost its last link. */
15
+ * ids it no longer links to, so the caller can collect a kept document that lost its last link. */
16
16
  export declare function setLinks(db: CanvasDb, doc: ObjectRow, links: ReadonlyArray<{
17
17
  written_as: string;
18
18
  dst: ObjectRow;
19
- }>): Promise<number[]>;
19
+ }>): Promise<string[]>;
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
22
  export declare function setUnresolved(db: CanvasDb, doc: ObjectRow, names: readonly string[]): Promise<void>;
@@ -25,7 +25,7 @@ export declare function dropUnresolved(db: CanvasDb, doc: ObjectRow, names: Iter
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
27
  export declare function unresolvedLinksCouldName(db: CanvasDb, name: string, id: string): Promise<Array<{
28
- src: number;
28
+ src: string;
29
29
  name: string;
30
30
  }>>;
31
31
  /** The document's current `links-to` edges as the links they were written from. */
@@ -1 +1,3 @@
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
+ var y=Object.defineProperty;var i=(t,n)=>y(t,"name",{value:n,configurable:!0});import{canRead as f}from"./access.js";import{getById as w}from"./objects.js";import{mapAsync as N}from"../async-array.js";async function _(t,n,e){await t.prepare(`INSERT INTO edges (type, src, dst, written_as, created_at) VALUES ('acted-on', ?, ?, NULL, ?)
2
+ ON CONFLICT DO NOTHING`).run(n.id,e.id,new Date().toISOString())}i(_,"recordActedOn");async function k(t,n,e){const s=(await t.prepare("SELECT dst FROM edges WHERE type = 'links-to' AND src = ?").all(n.id)).map(({dst:a})=>a);await t.prepare("DELETE FROM edges WHERE type = 'links-to' AND src = ?").run(n.id);const o=t.prepare(`INSERT INTO edges (type, src, dst, written_as, created_at) VALUES ('links-to', ?, ?, ?, ?)
3
+ ON CONFLICT DO NOTHING`),d=new Date().toISOString();for(const a of e)await o.run(n.id,a.dst.id,a.written_as,d);const c=new Set(e.map(a=>a.dst.id));return s.filter(a=>!c.has(a))}i(k,"setLinks");async function D(t,n,e){await t.prepare("DELETE FROM unresolved_links WHERE src = ?").run(n.id);const s=t.prepare("INSERT INTO unresolved_links (src, name) VALUES (?, ?) ON CONFLICT DO NOTHING");for(const o of e)await s.run(n.id,o)}i(D,"setUnresolved");async function A(t,n,e){const s=t.prepare("DELETE FROM unresolved_links WHERE src = ? AND name = ?");for(const o of e)await s.run(n.id,o)}i(A,"dropUnresolved");async function I(t,n,e){return await t.prepare("SELECT src, name FROM unresolved_links WHERE name = ? OR name = ? OR right(name, length(CAST(? AS text)) + 1) = '/' || CAST(? AS text) ORDER BY src, name").all(n,e,n,n)}i(I,"unresolvedLinksCouldName");async function C(t,n){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(n.id);return await N(e,async s=>({written_as:s.written_as??"",dst:await w(t,s.dst)}))}i(C,"linksOf");async function g(t,n,e){return await R(t,n,e,{type:"links-to",direction:"in"})}i(g,"backlinks");async function R(t,n,e,s={}){if(!await f(t,n,e))return[];const o=s.direction??"both",d=s.type?[s.type]:["acted-on","links-to"],c=[];for(const r of d)o!=="in"&&c.push(...await t.prepare("SELECT * FROM edges WHERE type = ? AND src = ?").all(r,e.id)),o!=="out"&&c.push(...await t.prepare("SELECT * FROM edges WHERE type = ? AND dst = ?").all(r,e.id));const a=new Set,l=[];for(const r of c){const u=`${r.type}|${r.src}|${r.dst}`;if(a.has(u))continue;a.add(u);const p=r.src===e.id?e:await w(t,r.src),E=r.dst===e.id?e:await w(t,r.dst);if(!p||!E)continue;const O=p===e?E:p;O!==e&&!await f(t,n,O)||l.push({type:r.type,src:p,dst:E,written_as:r.written_as,created_at:r.created_at})}return l}i(R,"edgesOf");export{g as backlinks,A as dropUnresolved,R as edgesOf,C as linksOf,_ as recordActedOn,k as setLinks,D as setUnresolved,I as unresolvedLinksCouldName};
@@ -1,11 +1,11 @@
1
- var H=Object.defineProperty;var d=(n,e)=>H(n,"name",{value:e,configurable:!0});import{EventEmitter as x}from"node:events";const v=new x;v.setMaxListeners(0);async function pe(n,e){const o=d(i=>e(i),"listener");return v.on(n,o),()=>v.off(n,o)}d(pe,"subscribeDocumentEvents");import{evalCondition as $}from"../predicate.js";import{finalizeNodeMail as B,insertMessage as J}from"../feed/messages.js";import{linkAuthorizes as K,ownerChain as U,readCheck as G}from"./access.js";import{getByRowid as q}from"./objects.js";import{appScopesNow as z,publishLookups as X,readerForObject as Y}from"./reader.js";import{configFromJson as T}from"./watches.js";import{CrtrError as A}from"../errors.js";import{ExitCode as L}from"../../types.js";import{eventSpec as P,kindOf as k}from"./kinds/registry.js";import{machineNameOf as M}from"../peer/names.js";import{settleObjectWaits as V}from"../canvas/waits.js";import{RECEIVERS as D}from"./receivers.js";import{DEFAULT_LISTEN as F}from"./types.js";import{afterCommit as Q}from"../canvas/db.js";function Z(n,e){if(n.level===void 0||n.level===e.level||e.levels?.includes(n.level))return n.level??e.level;const o=[e.level,...e.levels??[]].filter((i,t,s)=>s.indexOf(i)===t).sort((i,t)=>i-t);throw new A("invalid_level",`${n.object.type} ${n.event} publishes at level ${o.join(", ")}, not ${n.level}`,L.USAGE,{kind:n.object.type,event:n.event,level:n.level,allowed:o})}d(Z,"resolveLevel");function ee(n,e){const o=n.split("."),i=e.split(".");for(let t=0;t<o.length;t++){if(o[t]===">")return t===o.length-1&&i.length>t;if(t>=i.length||o[t]!=="*"&&o[t]!==i[t])return!1}return o.length===i.length}d(ee,"matchSubject");const W={"next-turn":1,"after-turn":2,steer:3,interrupt:4};function te(n,e){let o=null;for(const i of n){let t=null;for(const s of i)s.threshold<=e&&(!t||s.threshold>t.threshold)&&(t=s);t&&(!o||W[t.delivery]>W[o])&&(o=t.delivery)}return o}d(te,"resolveDelivery");async function ve(n,e,o){if(e.config)return e.config;const i=await n.prepare("SELECT listen_json FROM objects WHERE rowid = ?").get(o.rowid);return i?.listen_json?T(i.listen_json):F}d(ve,"listenConfigFor");function ne(n,e){return e.inboxKind??(n.level>=7?"urgent":"update")}d(ne,"inboxKind");async function oe(n,e){return e.type==="node"?e.id:await n.prepare(`SELECT 1 FROM objects WHERE type IN ('person','app','repo','profile')
2
- AND name = ? AND rowid != ? LIMIT 1`).get(e.name,e.rowid)?`${e.type}:${e.name}`:e.name}d(oe,"ownerHandleOf");async function ie(n,e,o){const i=e.object.owner===null?null:await n.prepare("SELECT * FROM objects WHERE rowid = ?").get(e.object.owner),t=i?.id??null,s=i?await oe(n,i):null;return{event:e.event,level:e.level,object:{id:e.object.id,type:e.object.type,kind:e.object.kind,owner:t,owner_handle:s,name:e.object.name,...e.object.home_machine?{machine:M(e.object.home_machine),machine_id:e.object.home_machine}:{}},actor:e.actor?.id??null,...e.actor?.home_machine?{actor_machine:M(e.actor.home_machine),actor_machine_id:e.actor.home_machine}:{},attrs:o,...e.pointer===void 0?{}:{pointer:e.pointer}}}d(ie,"pushFields");async function se(n,e,o,i){const t=await ie(n,e,i),s=e.messageBody!==void 0&&o.carriesBody===!0,f=s?typeof e.messageBody=="object"&&e.messageBody!==null&&!Array.isArray(e.messageBody)?{...e.messageBody,push:t}:{body:e.messageBody,push:t}:{push:t},c=s?e.messageBody:null,l=c?.bodyRef===void 0?null:c;return{kind:ne(e,o),label:l?.label??(typeof c?.label=="string"?c.label:e.object.type.includes(".")&&typeof e.messageBody?.summary=="string"?e.messageBody.summary.split(`
1
+ var H=Object.defineProperty;var d=(n,e)=>H(n,"name",{value:e,configurable:!0});import{EventEmitter as x}from"node:events";const v=new x;v.setMaxListeners(0);async function pe(n,e){const o=d(i=>e(i),"listener");return v.on(n,o),()=>v.off(n,o)}d(pe,"subscribeDocumentEvents");import{evalCondition as $}from"../predicate.js";import{finalizeNodeMail as B,insertMessage as J}from"../feed/messages.js";import{linkAuthorizes as K,ownerChain as U,readCheck as G}from"./access.js";import{getById as q}from"./objects.js";import{appScopesNow as z,publishLookups as P,readerForObject as V}from"./reader.js";import{configFromJson as k}from"./watches.js";import{CrtrError as L}from"../errors.js";import{ExitCode as A}from"../../types.js";import{eventSpec as X,kindOf as C}from"./kinds/registry.js";import{machineNameOf as M}from"../peer/names.js";import{settleObjectWaits as Y}from"../canvas/waits.js";import{RECEIVERS as F}from"./receivers.js";import{DEFAULT_LISTEN as D}from"./types.js";import{afterCommit as Q}from"../canvas/db.js";function Z(n,e){if(n.level===void 0||n.level===e.level||e.levels?.includes(n.level))return n.level??e.level;const o=[e.level,...e.levels??[]].filter((i,t,s)=>s.indexOf(i)===t).sort((i,t)=>i-t);throw new L("invalid_level",`${n.object.type} ${n.event} publishes at level ${o.join(", ")}, not ${n.level}`,A.USAGE,{kind:n.object.type,event:n.event,level:n.level,allowed:o})}d(Z,"resolveLevel");function ee(n,e){const o=n.split("."),i=e.split(".");for(let t=0;t<o.length;t++){if(o[t]===">")return t===o.length-1&&i.length>t;if(t>=i.length||o[t]!=="*"&&o[t]!==i[t])return!1}return o.length===i.length}d(ee,"matchSubject");const W={"next-turn":1,"after-turn":2,steer:3,interrupt:4};function te(n,e){let o=null;for(const i of n){let t=null;for(const s of i)s.threshold<=e&&(!t||s.threshold>t.threshold)&&(t=s);t&&(!o||W[t.delivery]>W[o])&&(o=t.delivery)}return o}d(te,"resolveDelivery");async function ve(n,e,o){if(e.config)return e.config;const i=await n.prepare("SELECT listen_json FROM objects WHERE id = ?").get(o.id);return i?.listen_json?k(i.listen_json):D}d(ve,"listenConfigFor");function ne(n,e){return e.inboxKind??(n.level>=7?"urgent":"update")}d(ne,"inboxKind");async function oe(n,e){return e.type==="node"?e.id:await n.prepare(`SELECT 1 FROM objects WHERE type IN ('person','app','repo','profile')
2
+ AND name = ? AND id != ? LIMIT 1`).get(e.name,e.id)?`${e.type}:${e.name}`:e.name}d(oe,"ownerHandleOf");async function ie(n,e,o){const i=e.object.owner===null?null:await n.prepare("SELECT * FROM objects WHERE id = ?").get(e.object.owner),t=i?.id??null,s=i?await oe(n,i):null;return{event:e.event,level:e.level,object:{id:e.object.id,type:e.object.type,kind:e.object.kind,owner:t,owner_handle:s,name:e.object.name,...e.object.home_machine?{machine:M(e.object.home_machine),machine_id:e.object.home_machine}:{}},actor:e.actor?.id??null,...e.actor?.home_machine?{actor_machine:M(e.actor.home_machine),actor_machine_id:e.actor.home_machine}:{},attrs:o,...e.pointer===void 0?{}:{pointer:e.pointer}}}d(ie,"pushFields");async function se(n,e,o,i){const t=await ie(n,e,i),s=e.messageBody!==void 0&&o.carriesBody===!0,f=s?typeof e.messageBody=="object"&&e.messageBody!==null&&!Array.isArray(e.messageBody)?{...e.messageBody,push:t}:{body:e.messageBody,push:t}:{push:t},c=s?e.messageBody:null,l=c?.bodyRef===void 0?null:c;return{kind:ne(e,o),label:l?.label??(typeof c?.label=="string"?c.label:e.object.type.includes(".")&&typeof e.messageBody?.summary=="string"?e.messageBody.summary.split(`
3
3
  `)[0]:`${e.event} ${e.object.type} ${e.object.name}`),...l?.bodyRef===void 0?{}:{bodyRef:l.bodyRef},...l?.disposition===void 0?{}:{disposition:l.disposition},senderNodeId:e.actor?.type==="node"?e.actor.id:null,senderName:e.actor===null||e.actor===void 0?null:e.actor.home_machine?`${e.actor.name} on ${M(e.actor.home_machine)}`:e.actor.name,bodyJson:f}}d(se,"messageInput");async function re(n,e,o,i,t){if(!o.supersedes)return[{attrs:e.attrs,destinations:[...i]}];const s=n.prepare(`SELECT d.delivery_id, d.message_id, d.state, m.body_json FROM deliveries d
4
4
  JOIN messages m ON m.message_id = d.message_id
5
5
  WHERE d.destination_id = ? AND d.state IN ('pending', 'handed_off')
6
6
  AND d.canceled_at IS NULL AND m.event = ? AND m.object_id = ?
7
- ORDER BY m.seq`),f=n.prepare("DELETE FROM deliveries WHERE delivery_id = ?"),c=n.prepare("SELECT * FROM objects WHERE id = ?"),l=new Map,g=new Set;for(const m of i){const E=t(m),N=await c.get(E),S=N===void 0?void 0:await k(n,N.type),_=await s.all(E,e.event,e.object.id),j=new Set;for(const a of _)a.state==="handed_off"?await S?.supersedeClaimed?.(n,a.delivery_id)&&j.add(a.delivery_id):(await f.run(a.delivery_id),g.add(a.message_id));const w=_.filter(a=>a.state==="pending"||j.has(a.delivery_id)).at(-1),b=w?.message_id??null,r=l.get(b)??{prior:w?.body_json?JSON.parse(w.body_json).push?.attrs??null:null,destinations:[]};r.destinations.push(m),l.set(b,r)}const R=n.prepare("DELETE FROM messages WHERE message_id = ? AND NOT EXISTS (SELECT 1 FROM deliveries WHERE message_id = ?)");for(const m of g)await R.run(m,m);return[...l.values()].map(m=>({attrs:o.merge?o.merge(m.prior,e):e.attrs,destinations:m.destinations}))}d(re,"supersede");async function ae(n,e,o,i,t){const s=await q(n,i);if(s===null||s.type!=="app")return!1;const f=await n.prepare("SELECT 1 FROM peer_stubs WHERE object = ?").get(e.rowid)!==void 0,c=f?null:await z(n,s,t);return(f||c!==null)&&await K(n,s,c,e,o)}d(ae,"linkDelivers");const C=8;class ce extends A{static{d(this,"HopLimitError")}constructor(e){super("hop_limit",`event depth ${e} exceeds ${C}`,L.GENERAL,{depth:e,limit:C})}}async function Se(n,e,o=async()=>[]){const i=await P(n,e.object.type,e.event),t={...e,level:Z(e,i)};t.object.type==="document"&&(t.event==="edited"||t.event==="deleted")&&Q(()=>v.emit(t.object.id,t.event));const s=e.cause??null,f=s===null?null:await n.prepare(`SELECT depth FROM messages WHERE message_id = ?
8
- UNION ALL SELECT depth FROM message_causes WHERE message_id = ? LIMIT 1`).get(s,s);if(s!==null&&f===void 0)throw new A("unknown_cause",`no message ${s}`,L.USAGE,{cause:s});const c=f===null?0:f.depth+1;if(c>C)throw new ce(c);(i.endsWait===!0||t.event==="deleted")&&await V(n,t.object.id);const l=await U(n,t.object),g=`w.watcher, o.id AS watcher_id, o.type AS watcher_type, o.reception, s.pattern, s.filter_json,
9
- COALESCE(s.config_json, o.listen_json) AS config_json, w.link_app`,R=await n.prepareUncached(i.durable?`SELECT ${g} FROM watches w JOIN watch_subscriptions s ON s.watch = w.rowid
10
- JOIN objects o ON o.rowid = w.watcher WHERE w.object = ? AND w.watcher != ? AND o.reception >= 1`:`SELECT ${g} FROM objects o INDEXED BY objects_receiving CROSS JOIN watches w CROSS JOIN watch_subscriptions s
11
- WHERE o.reception = 2 AND w.watcher = o.rowid AND s.watch = w.rowid AND w.object = ? AND w.watcher != ?`).all(t.object.rowid,t.actor?.rowid??-1);if(R.length===0)return{delivered:0,message_id:null,depth:c};const m={event:t.event,level:t.level,id:t.object.id,type:t.object.type,kind:t.object.kind,actor:t.actor?.id??null,...t.attrs},E=new Map;for(const r of R){if(t.onlyWatchers!==void 0&&!t.onlyWatchers.includes(r.watcher_id)||!ee(r.pattern,t.event)||r.filter_json!==null&&!$(JSON.parse(r.filter_json),m))continue;const a=E.get(r.watcher)??{id:r.watcher_id,type:r.watcher_type,reception:r.reception,configs:[],linkApp:r.link_app};a.configs.push(r.config_json?T(r.config_json):F),E.set(r.watcher,a)}const N=(l.length?l[l.length-1]:t.object).type==="repo",S=d(async()=>[],"noRepos"),_=await G(n,t.object),j=X(n),w=[];for(const r of E.values()){const a=await n.prepare("SELECT * FROM objects WHERE id = ?").get(r.id),u=await k(n,a.type),O=u.receiverFor?await u.receiverFor(n,a):u.receiver;if(O===void 0)continue;const h=te(r.configs,t.level);if(h===null)continue;const y=await Y(n,a,N?o:S,j);if(y.scopes===null&&(y.class==="node"||y.owner.type!=="person"))continue;const p=r.linkApp!==null&&!await _(y)&&await ae(n,t.object,a,r.linkApp,j);!p&&!await _(y)||w.push({id:r.id,reception:r.reception,delivery:h,receiver:O,...p?{linked:p}:{}})}if(w.length===0)return{delivered:0,message_id:null,depth:c};let b=null;for(const r of await re(n,t,i,w,a=>a.id)){const a=new Map;for(const p of r.destinations)a.set(p.receiver,[...a.get(p.receiver)??[],p]);const u=await se(n,t,i,r.attrs),O=[...a].map(([p,I])=>D[p].bodyOwner(I)).find(p=>p!==null)??null,h=B({...u,urgency:"normal"},O),y=await J(n,{operationId:h.operationId,createdAt:h.createdAt,senderNodeId:u.senderNodeId,senderName:u.senderName,kind:u.kind,label:u.label,bodyRef:h.bodyRef,bodyJson:h.bodyJson,disposition:u.disposition??null,event:{event:t.event,objectId:t.object.id,level:t.level,actorId:t.actor?.id??null},causeMessageId:s,depth:c});b??=y;for(const[p,I]of a)await D[p].enqueue(n,{messageId:y,event:t.event,level:t.level,senderNodeId:u.senderNodeId,elevatesTier:i.elevatesTier===!0,...t.idempotencyKey===void 0?{}:{idempotencyKey:t.idempotencyKey}},I)}return{delivered:w.length,message_id:b,depth:c}}d(Se,"publish");export{C as HOP_LIMIT,ce as HopLimitError,ve as listenConfigFor,ee as matchSubject,Se as publish,te as resolveDelivery,Z as resolveLevel,pe as subscribeDocumentEvents,re as supersede};
7
+ ORDER BY m.seq`),f=n.prepare("DELETE FROM deliveries WHERE delivery_id = ?"),c=n.prepare("SELECT * FROM objects WHERE id = ?"),l=new Map,g=new Set;for(const m of i){const E=t(m),N=await c.get(E),I=N===void 0?void 0:await C(n,N.type),_=await s.all(E,e.event,e.object.id),j=new Set;for(const a of _)a.state==="handed_off"?await I?.supersedeClaimed?.(n,a.delivery_id)&&j.add(a.delivery_id):(await f.run(a.delivery_id),g.add(a.message_id));const h=_.filter(a=>a.state==="pending"||j.has(a.delivery_id)).at(-1),b=h?.message_id??null,r=l.get(b)??{prior:h?.body_json?JSON.parse(h.body_json).push?.attrs??null:null,destinations:[]};r.destinations.push(m),l.set(b,r)}const R=n.prepare("DELETE FROM messages WHERE message_id = ? AND NOT EXISTS (SELECT 1 FROM deliveries WHERE message_id = ?)");for(const m of g)await R.run(m,m);return[...l.values()].map(m=>({attrs:o.merge?o.merge(m.prior,e):e.attrs,destinations:m.destinations}))}d(re,"supersede");async function ae(n,e,o,i,t){const s=await q(n,i);if(s===null||s.type!=="app")return!1;const f=await n.prepare("SELECT 1 FROM peer_stubs WHERE object = ?").get(e.id)!==void 0,c=f?null:await z(n,s,t);return(f||c!==null)&&await K(n,s,c,e,o)}d(ae,"linkDelivers");const T=8;class ce extends L{static{d(this,"HopLimitError")}constructor(e){super("hop_limit",`event depth ${e} exceeds ${T}`,A.GENERAL,{depth:e,limit:T})}}async function Ie(n,e,o=async()=>[]){const i=await X(n,e.object.type,e.event),t={...e,level:Z(e,i)};t.object.type==="document"&&(t.event==="edited"||t.event==="deleted")&&Q(()=>v.emit(t.object.id,t.event));const s=e.cause??null,f=s===null?null:await n.prepare(`SELECT depth FROM messages WHERE message_id = ?
8
+ UNION ALL SELECT depth FROM message_causes WHERE message_id = ? LIMIT 1`).get(s,s);if(s!==null&&f===void 0)throw new L("unknown_cause",`no message ${s}`,A.USAGE,{cause:s});const c=f===null?0:f.depth+1;if(c>T)throw new ce(c);(i.endsWait===!0||t.event==="deleted")&&await Y(n,t.object.id);const l=await U(n,t.object),g=`w.watcher, o.id AS watcher_id, o.type AS watcher_type, o.reception, s.pattern, s.filter_json,
9
+ COALESCE(s.config_json, o.listen_json) AS config_json, w.link_app`,R=await n.prepareUncached(i.durable?`SELECT ${g} FROM watches w JOIN watch_subscriptions s ON s.watch = w.watch_id
10
+ JOIN objects o ON o.id = w.watcher WHERE w.object = ? AND w.watcher != ? AND o.reception >= 1`:`SELECT ${g} FROM objects o JOIN watches w ON w.watcher = o.id JOIN watch_subscriptions s ON s.watch = w.watch_id
11
+ WHERE o.reception = 2 AND w.object = ? AND w.watcher != ?`).all(t.object.id,t.actor?.id??"");if(R.length===0)return{delivered:0,message_id:null,depth:c};const m={event:t.event,level:t.level,id:t.object.id,type:t.object.type,kind:t.object.kind,actor:t.actor?.id??null,...t.attrs},E=new Map;for(const r of R){if(t.onlyWatchers!==void 0&&!t.onlyWatchers.includes(r.watcher_id)||!ee(r.pattern,t.event)||r.filter_json!==null&&!$(JSON.parse(r.filter_json),m))continue;const a=E.get(r.watcher)??{id:r.watcher_id,type:r.watcher_type,reception:r.reception,configs:[],linkApp:r.link_app};a.configs.push(r.config_json?k(r.config_json):D),E.set(r.watcher,a)}const N=(l.length?l[l.length-1]:t.object).type==="repo",I=d(async()=>[],"noRepos"),_=await G(n,t.object),j=P(n),h=[];for(const r of E.values()){const a=await n.prepare("SELECT * FROM objects WHERE id = ?").get(r.id),u=await C(n,a.type),O=u.receiverFor?await u.receiverFor(n,a):u.receiver;if(O===void 0)continue;const w=te(r.configs,t.level);if(w===null)continue;const y=await V(n,a,N?o:I,j);if(y.scopes===null&&(y.class==="node"||y.owner.type!=="person"))continue;const p=r.linkApp!==null&&!await _(y)&&await ae(n,t.object,a,r.linkApp,j);!p&&!await _(y)||h.push({id:r.id,reception:r.reception,delivery:w,receiver:O,...p?{linked:p}:{}})}if(h.length===0)return{delivered:0,message_id:null,depth:c};let b=null;for(const r of await re(n,t,i,h,a=>a.id)){const a=new Map;for(const p of r.destinations)a.set(p.receiver,[...a.get(p.receiver)??[],p]);const u=await se(n,t,i,r.attrs),O=[...a].map(([p,S])=>F[p].bodyOwner(S)).find(p=>p!==null)??null,w=B({...u,urgency:"normal"},O),y=await J(n,{operationId:w.operationId,createdAt:w.createdAt,senderNodeId:u.senderNodeId,senderName:u.senderName,kind:u.kind,label:u.label,bodyRef:w.bodyRef,bodyJson:w.bodyJson,disposition:u.disposition??null,event:{event:t.event,objectId:t.object.id,level:t.level,actorId:t.actor?.id??null},causeMessageId:s,depth:c});b??=y;for(const[p,S]of a)await F[p].enqueue(n,{messageId:y,event:t.event,level:t.level,senderNodeId:u.senderNodeId,elevatesTier:i.elevatesTier===!0,...t.idempotencyKey===void 0?{}:{idempotencyKey:t.idempotencyKey}},S)}return{delivered:h.length,message_id:b,depth:c}}d(Ie,"publish");export{T as HOP_LIMIT,ce as HopLimitError,ve as listenConfigFor,ee as matchSubject,Ie as publish,te as resolveDelivery,Z as resolveLevel,pe as subscribeDocumentEvents,re as supersede};
@@ -17,27 +17,27 @@ export type Listed = {
17
17
  transcript?: ExposureLevel;
18
18
  };
19
19
  export interface Ledger {
20
- node: number;
20
+ node: string;
21
21
  preferenceSnapshot: string | null;
22
- objects: Map<number, Held>;
22
+ objects: Map<string, Held>;
23
23
  /** key = `<owner object id>/<prefix>` */
24
24
  listed: Map<string, Listed>;
25
25
  }
26
26
  export interface Exposed {
27
- object: number;
27
+ object: string;
28
28
  headsKey: string | null;
29
29
  contentHash: string | null;
30
30
  }
31
- export declare function loadLedger(db: CanvasDb, node: number): Promise<Ledger>;
31
+ export declare function loadLedger(db: CanvasDb, node: string): Promise<Ledger>;
32
32
  /** Write what changed since `loadLedger` (a ledger never loaded is written whole). */
33
33
  export declare function saveLedger(db: CanvasDb, ledger: Ledger): Promise<void>;
34
34
  /** Whether the node has a ledger at all (a context session or any exposure). */
35
- export declare function hasLedger(db: CanvasDb, node: number): Promise<boolean>;
35
+ export declare function hasLedger(db: CanvasDb, node: string): Promise<boolean>;
36
36
  /** End the node's context session: nothing is held any more. */
37
- export declare function clearLedger(db: CanvasDb, node: number): Promise<void>;
37
+ export declare function clearLedger(db: CanvasDb, node: string): Promise<void>;
38
38
  /** Seed a fork with what the source's transcript holds; the fork builds its own
39
39
  * system prompt, so system rows and the preference snapshot are not copied. */
40
- export declare function forkLedger(db: CanvasDb, source: number, fork: number): Promise<void>;
40
+ export declare function forkLedger(db: CanvasDb, source: string, fork: string): Promise<void>;
41
41
  /** Held at `level` or above: this object, or any held object with the same body
42
42
  * (content hash). The object itself counts at content level only for the same revision. */
43
43
  export declare function heldAtOrAbove(ledger: Ledger, exposed: Exposed, level: ExposureLevel, channel?: Channel): boolean;
@@ -47,7 +47,7 @@ export declare function listedAtOrAbove(ledger: Ledger, key: string, level: Expo
47
47
  export declare function holdListing(ledger: Ledger, channel: Channel, key: string, level: ExposureLevel): void;
48
48
  /** Forget the transcript's copy of the object and of every held object with the
49
49
  * same body (compaction dropped it); system holdings stay. */
50
- export declare function demoteTranscript(ledger: Ledger, object: number): void;
50
+ export declare function demoteTranscript(ledger: Ledger, object: string): void;
51
51
  /** The byte-stable preference block: the first render is kept for the session. */
52
52
  export declare function freezePreferences(ledger: Ledger, rendered: string): string;
53
53
  export declare function hasTranscript(ledger: Ledger): boolean;
@@ -2,7 +2,7 @@ import type { ObjectRow } from './types.js';
2
2
  import type { CanvasDb } from '../canvas/db.js';
3
3
  export type JobStatus = 'running' | 'exited' | 'killed';
4
4
  export interface JobRow {
5
- object: number;
5
+ object: string;
6
6
  command: string;
7
7
  status: JobStatus;
8
8
  exit_code: number | null;
@@ -1,2 +1,2 @@
1
- var m=Object.defineProperty;var e=(t,r)=>m(t,"name",{value:r,configurable:!0});import{recordActedOn as s}from"./edges.js";import{publish as u}from"./events.js";import{createObject as f,getByRowid as E}from"./objects.js";import{recordWatch as h}from"./watches.js";function w(t){return t.split(`
2
- `,1)[0].trim()}e(w,"firstLine");function d(t,r){return`${w(t)} (${r})`}e(d,"previewOf");async function b(t,r){return await t.prepare("SELECT * FROM jobs WHERE object = ?").get(r.rowid)??null}e(b,"jobRow");async function R(t,r,i){if(r.type!=="node")throw new Error(`startJob: ${r.id} is a ${r.type}, not a node`);const o=await f(t,{...i.id===void 0?{}:{id:i.id},type:"job",kind:"bash",owner:r.rowid,privacy:"public",name:w(i.command)||"bash",preview:d(i.command,"running")});return await t.prepare("INSERT INTO jobs (object, command, status, exit_code, job_dir, log_path) VALUES (?, ?, 'running', NULL, ?, ?)").run(o.rowid,i.command,i.jobDir,i.logPath),await s(t,r,o),await h(t,r,o,"job-start"),await u(t,{event:"created",object:o,actor:r,attrs:{}}),o}e(R,"startJob");async function T(t,r,i){const o=await b(t,r);if(o===null)throw new Error(`finishJob: ${r.id} has no jobs row`);if(o.status!=="running")return r;const a="killedBy"in i,c=a?"killed":"exited",n=a?null:i.exitCode;await t.prepare("UPDATE jobs SET status = ?, exit_code = ? WHERE object = ?").run(c,n,r.rowid);const p=a?"killed":`exited ${n}`;await t.prepare("UPDATE objects SET preview = ? WHERE rowid = ?").run(d(o.command,p),r.rowid);const l=await E(t,r.rowid);return a&&i.killedBy!==null&&await s(t,i.killedBy,l),await u(t,{event:c,object:l,actor:a?i.killedBy:null,attrs:a?{"log-path":o.log_path,...i.reason===void 0?{}:{reason:i.reason}}:{"exit-code":n,"log-path":o.log_path}}),l}e(T,"finishJob");export{T as finishJob,b as jobRow,R as startJob};
1
+ var m=Object.defineProperty;var e=(t,i)=>m(t,"name",{value:i,configurable:!0});import{recordActedOn as s}from"./edges.js";import{publish as u}from"./events.js";import{createObject as f,getById as E}from"./objects.js";import{recordWatch as h}from"./watches.js";function d(t){return t.split(`
2
+ `,1)[0].trim()}e(d,"firstLine");function p(t,i){return`${d(t)} (${i})`}e(p,"previewOf");async function b(t,i){return await t.prepare("SELECT * FROM jobs WHERE object = ?").get(i.id)??null}e(b,"jobRow");async function T(t,i,r){if(i.type!=="node")throw new Error(`startJob: ${i.id} is a ${i.type}, not a node`);const a=await f(t,{...r.id===void 0?{}:{id:r.id},type:"job",kind:"bash",owner:i.id,privacy:"public",name:d(r.command)||"bash",preview:p(r.command,"running")});return await t.prepare("INSERT INTO jobs (object, command, status, exit_code, job_dir, log_path) VALUES (?, ?, 'running', NULL, ?, ?)").run(a.id,r.command,r.jobDir,r.logPath),await s(t,i,a),await h(t,i,a,"job-start"),await u(t,{event:"created",object:a,actor:i,attrs:{}}),a}e(T,"startJob");async function v(t,i,r){const a=await b(t,i);if(a===null)throw new Error(`finishJob: ${i.id} has no jobs row`);if(a.status!=="running")return i;const o="killedBy"in r,c=o?"killed":"exited",n=o?null:r.exitCode;await t.prepare("UPDATE jobs SET status = ?, exit_code = ? WHERE object = ?").run(c,n,i.id);const w=o?"killed":`exited ${n}`;await t.prepare("UPDATE objects SET preview = ? WHERE id = ?").run(p(a.command,w),i.id);const l=await E(t,i.id);return o&&r.killedBy!==null&&await s(t,r.killedBy,l),await u(t,{event:c,object:l,actor:o?r.killedBy:null,attrs:o?{"log-path":a.log_path,...r.reason===void 0?{}:{reason:r.reason}}:{"exit-code":n,"log-path":a.log_path}}),l}e(v,"finishJob");export{v as finishJob,b as jobRow,T as startJob};
@@ -1,4 +1,4 @@
1
- var l=Object.defineProperty;var c=(s,a)=>l(s,"name",{value:a,configurable:!0});import{recordLiveRead as u}from"./kind.js";import{header as m}from"./render.js";import{objectDTO as v}from"./dto.js";import{receiverForObject as j}from"../receivers.js";function $(s,a){const d=Object.fromEntries(Object.entries(a).map(([t,{ends_wait:i,...o}])=>[`${s}.${t}`,{...o,carriesBody:!0,...i===void 0?{}:{endsWait:i}}]));return{name:s,events:{created:{level:4},read:{level:1},watched:{level:1},deleted:{level:5},configured:{level:1},...d},addressable:"name",receiverFor:j,async read(t,i,o,p){await u(t,i,o,p.reposFn);const e=await t.prepare("SELECT description, summary, state_json, published_at, receiver_json, dropped FROM custom_objects WHERE object = ?").get(o.rowid),n=e?.receiver_json==null?null:JSON.parse(e.receiver_json),r={object:await v(t,o),description:e?.description??"",summary:e?.summary??null,state:e?.state_json==null?null:JSON.parse(e.state_json),published_at:e?.published_at??null,receiver:typeof n=="string"?n:n&&typeof n=="object"?Object.keys(n)[0]:null,dropped:e?.dropped??0};return{data:r,text:`${m("object",r.object)}
1
+ var l=Object.defineProperty;var c=(s,a)=>l(s,"name",{value:a,configurable:!0});import{recordLiveRead as u}from"./live-read.js";import{header as m}from"./render.js";import{objectDTO as v}from"./dto.js";import{receiverForObject as j}from"../receivers.js";function $(s,a){const d=Object.fromEntries(Object.entries(a).map(([t,{ends_wait:i,...o}])=>[`${s}.${t}`,{...o,carriesBody:!0,...i===void 0?{}:{endsWait:i}}]));return{name:s,events:{created:{level:4},read:{level:1},watched:{level:1},deleted:{level:5},configured:{level:1},...d},addressable:"name",receiverFor:j,async read(t,i,o,p){await u(t,i,o,p.reposFn);const e=await t.prepare("SELECT description, summary, state_json, published_at, receiver_json, dropped FROM custom_objects WHERE object = ?").get(o.id),n=e?.receiver_json==null?null:JSON.parse(e.receiver_json),r={object:await v(t,o),description:e?.description??"",summary:e?.summary??null,state:e?.state_json==null?null:JSON.parse(e.state_json),published_at:e?.published_at??null,receiver:typeof n=="string"?n:n&&typeof n=="object"?Object.keys(n)[0]:null,dropped:e?.dropped??0};return{data:r,text:`${m("object",r.object)}
2
2
  Description: ${r.description}
3
3
  Summary: ${r.summary??""}
4
4
  State: ${JSON.stringify(r.state)}
@@ -1,5 +1,5 @@
1
- var _=Object.defineProperty;var m=(e,t)=>_(e,"name",{value:t,configurable:!0});import{recordMemoryReadsIn as v}from"../../canvas/memory-reads.js";import{deliveryDocOf as x,nodeSubject as $,ownerHandle as D}from"../../substrate/delivery/corpus.js";import{recordContentDelivery as R}from"../../substrate/delivery/deliver.js";import{renderExplicitRead as S}from"../../substrate/delivery/render-event.js";import{canRead as N}from"../access.js";import{documentRecord as j,readDocument as k}from"../documents.js";import{loadLedger as A,saveLedger as E}from"../exposures.js";import{getByRowid as O}from"../objects.js";import{rulesOf as h}from"../rules.js";import{objectDTO as d}from"./dto.js";import{withBase as L}from"./kind.js";import{attr as l,header as I,section as M}from"./render.js";import{filterAsync as b,mapAsync as p}from"../../async-array.js";async function B(e,t,n){const i=`${n.name}/`,s=await e.prepare(`SELECT * FROM objects WHERE type = 'document' AND deleted_at IS NULL AND home_machine IS NULL AND owner IS ?
2
- AND substr(name, 1, ?) = ? ORDER BY name`).all(n.owner,i.length,i);return await p(await b(s,async r=>!r.name.slice(i.length).includes("/")&&await N(e,t,r)),async r=>await d(e,r))}m(B,"listingOf");async function T(e,t,n){const i=t.class==="node",s=i?await A(e,t.node.rowid):{node:0,preferenceSnapshot:null,objects:new Map,listed:new Map},r={db:e,reader:t,subject:i?await $(e,t):null,ledger:s,channel:"transcript"},o=await S(r,await x(e,t,n));return i&&(await R(e,t,o.delivered),await E(e,s)),{attachments:o.attachments,linked:o.linked.map(c=>c.object)}}m(T,"explicitReadAttachments");async function W(e,t,n){if(t.class!=="node"||n.kind!=="knowledge"&&n.kind!=="preference"||n.owner===null)return;const i=await O(e,n.owner);i!==null&&await v(e,t.node.id,[{name:n.name,scope:D(i),at:new Date().toISOString(),type:"read"}])}m(W,"recordExplicitMemoryRead");function C(e,t){const n=[];if(t.attachments&&n.push(t.attachments,""),n.push(I("object",e,l("privacy",e.privacy)+l("revision",t.revision))),n.push(`Preview: ${e.preview}`),t.summary&&n.push(`Summary: ${t.summary}`),t.fields!==void 0&&n.push(`<fields>
1
+ var _=Object.defineProperty;var m=(e,t)=>_(e,"name",{value:t,configurable:!0});import{recordMemoryReadsIn as v}from"../../canvas/memory-reads.js";import{deliveryDocOf as x,nodeSubject as D,ownerHandle as N}from"../../substrate/delivery/corpus.js";import{recordContentDelivery as S}from"../../substrate/delivery/deliver.js";import{renderExplicitRead as $}from"../../substrate/delivery/render-event.js";import{canRead as R}from"../access.js";import{documentRecord as O,readDocument as j}from"../documents.js";import{loadLedger as k,saveLedger as A}from"../exposures.js";import{getById as E}from"../objects.js";import{rulesOf as h}from"../rules.js";import{objectDTO as d}from"./dto.js";import{withBase as I}from"./kind.js";import{attr as l,header as L,section as M}from"./render.js";import{filterAsync as T,mapAsync as p}from"../../async-array.js";async function b(e,t,n){const i=`${n.name}/`,s=await e.prepare(`SELECT * FROM objects WHERE type = 'document' AND deleted_at IS NULL AND home_machine IS NULL AND owner IS NOT DISTINCT FROM ?
2
+ AND substr(name, 1, ?) = ? ORDER BY name`).all(n.owner,i.length,i);return await p(await T(s,async a=>!a.name.slice(i.length).includes("/")&&await R(e,t,a)),async a=>await d(e,a))}m(b,"listingOf");async function B(e,t,n){const i=t.class==="node",s=i?await k(e,t.node.id):{node:"",preferenceSnapshot:null,objects:new Map,listed:new Map},a={db:e,reader:t,subject:i?await D(e,t):null,ledger:s,channel:"transcript"},o=await $(a,await x(e,t,n));return i&&(await S(e,t,o.delivered),await A(e,s)),{attachments:o.attachments,linked:o.linked.map(c=>c.object)}}m(B,"explicitReadAttachments");async function C(e,t,n){if(t.class!=="node"||n.kind!=="knowledge"&&n.kind!=="preference"||n.owner===null)return;const i=await E(e,n.owner);i!==null&&await v(e,t.node.id,[{name:n.name,scope:N(i),at:new Date().toISOString(),type:"read"}])}m(C,"recordExplicitMemoryRead");function W(e,t){const n=[];if(t.attachments&&n.push(t.attachments,""),n.push(L("object",e,l("privacy",e.privacy)+l("revision",t.revision))),n.push(`Preview: ${e.preview}`),t.summary&&n.push(`Summary: ${t.summary}`),t.fields!==void 0&&n.push(`<fields>
3
3
  ${JSON.stringify(t.fields,null,2)}
4
- </fields>`),t.needs_merge?(t.heads.forEach((i,s)=>{n.push(`<head${l("rev",i.rev_id)}${l("number",i.number)}${l("author",i.author_id)}>`,t.bodies[s]??"","</head>")}),n.push(`This document has ${t.heads.length} heads. Your next \`crtr doc edit\` writes the merged body and joins them into one revision.`)):n.push("",t.bodies[0]??""),t.listing&&t.listing.length>0){const i=t.listing.some(o=>o.owner?.id===e.owner?.id&&o.name.startsWith(`${e.name}/`)),s=t.listing.some(o=>o.owner?.id!==e.owner?.id||!o.name.startsWith(`${e.name}/`)),r=i&&s?`Names under ${e.name}/ and documents it links to`:i?`Names under ${e.name}/`:"Documents it links to";n.push("",...M(r,t.listing))}return n.join(`
5
- `)}m(C,"render");function H(e){const t=e.attrs.revision,n=e.attrs.from_revision??(typeof t=="number"?t-1:null),i=e.attrs.rationale;return{...e.attrs,from_revision:n,revision:t,authors:e.actor?[e.actor.id]:[],rationales:typeof i=="string"?[i]:[]}}m(H,"editAttrs");const U=m((e,t)=>{const n=H(t);if(e===null)return n;const i=e.authors??[];return{...n,from_revision:e.from_revision??null,authors:[...i,...n.authors.filter(s=>!i.includes(s))],rationales:[...e.rationales??[],...n.rationales]}},"mergeEdits"),ne={name:"document",addressable:"name",events:L({edited:{level:8,supersedes:!0,merge:U},deleted:{level:8}}),async listItem(e,t){return{summary:(await j(e,t)).summary??null,rules:(await h(e,t)).length}},async read(e,t,n,i){const s=await k(e,t,n,i.reposFn);await W(e,t,n);const r=s.record,o=await B(e,t,n),{attachments:c,linked:w}=await T(e,t,n),y=new Set(o.map(a=>a.id)),f=[...o,...await p(w.filter(a=>!y.has(a.id)),async a=>await d(e,a))],u={summary:r.summary??null,revision:r.revision,heads:s.heads.map(a=>({rev_id:a.rev_id,number:a.number,author_id:a.author,created_at:a.created_at})),bodies:s.heads.map(a=>a.body),needs_merge:s.needsMerge,...f.length>0?{listing:f}:{},...c===""?{}:{attachments:c}};return i.fields&&(u.fields={why_it_exists:r.why_it_exists??null,unlisted:r.unlisted,lint_ignore:r.lint_ignore??[],extensions:r.extensions??{},rules:(await h(e,n)).map(({matchFrontmatter:a,...g})=>({...g,...a===void 0?{}:{match_frontmatter:a}}))}),{data:u,text:C(await d(e,n),u)}}};export{ne as documentKind};
4
+ </fields>`),t.needs_merge?(t.heads.forEach((i,s)=>{n.push(`<head${l("rev",i.rev_id)}${l("number",i.number)}${l("author",i.author_id)}>`,t.bodies[s]??"","</head>")}),n.push(`This document has ${t.heads.length} heads. Your next \`crtr doc edit\` writes the merged body and joins them into one revision.`)):n.push("",t.bodies[0]??""),t.listing&&t.listing.length>0){const i=t.listing.some(o=>o.owner?.id===e.owner?.id&&o.name.startsWith(`${e.name}/`)),s=t.listing.some(o=>o.owner?.id!==e.owner?.id||!o.name.startsWith(`${e.name}/`)),a=i&&s?`Names under ${e.name}/ and documents it links to`:i?`Names under ${e.name}/`:"Documents it links to";n.push("",...M(a,t.listing))}return n.join(`
5
+ `)}m(W,"render");function F(e){const t=e.attrs.revision,n=e.attrs.from_revision??(typeof t=="number"?t-1:null),i=e.attrs.rationale;return{...e.attrs,from_revision:n,revision:t,authors:e.actor?[e.actor.id]:[],rationales:typeof i=="string"?[i]:[]}}m(F,"editAttrs");const H=m((e,t)=>{const n=F(t);if(e===null)return n;const i=e.authors??[];return{...n,from_revision:e.from_revision??null,authors:[...i,...n.authors.filter(s=>!i.includes(s))],rationales:[...e.rationales??[],...n.rationales]}},"mergeEdits"),ne={name:"document",addressable:"name",events:I({edited:{level:8,supersedes:!0,merge:H},deleted:{level:8}}),async listItem(e,t){return{summary:(await O(e,t)).summary??null,rules:(await h(e,t)).length}},async read(e,t,n,i){const s=await j(e,t,n,i.reposFn);await C(e,t,n);const a=s.record,o=await b(e,t,n),{attachments:c,linked:w}=await B(e,t,n),y=new Set(o.map(r=>r.id)),f=[...o,...await p(w.filter(r=>!y.has(r.id)),async r=>await d(e,r))],u={summary:a.summary??null,revision:a.revision,heads:s.heads.map(r=>({rev_id:r.rev_id,number:r.number,author_id:r.author,created_at:r.created_at})),bodies:s.heads.map(r=>r.body),needs_merge:s.needsMerge,...f.length>0?{listing:f}:{},...c===""?{}:{attachments:c}};return i.fields&&(u.fields={why_it_exists:a.why_it_exists??null,unlisted:a.unlisted,lint_ignore:a.lint_ignore??[],extensions:a.extensions??{},rules:(await h(e,n)).map(({matchFrontmatter:r,...g})=>({...g,...r===void 0?{}:{match_frontmatter:r}}))}),{data:u,text:W(await d(e,n),u)}}};export{ne as documentKind};
@@ -1 +1 @@
1
- var a=Object.defineProperty;var d=(n,e)=>a(n,"name",{value:e,configurable:!0});import{getByRowid as i}from"../objects.js";async function l(n,e){const t=e.owner===null?null:await i(n,e.owner),r=t?{id:t.id,type:t.type,handle:t.type==="node"?t.id:t.name}:null;return{id:e.id,type:e.type,kind:e.kind,owner:r,privacy:e.privacy,name:e.name,preview:e.preview??"",created_at:e.created_at,deleted_at:e.deleted_at}}d(l,"objectDTO");export{l as objectDTO};
1
+ var a=Object.defineProperty;var d=(n,e)=>a(n,"name",{value:e,configurable:!0});import{getById as i}from"../objects.js";async function l(n,e){const t=e.owner===null?null:await i(n,e.owner),r=t?{id:t.id,type:t.type,handle:t.type==="node"?t.id:t.name}:null;return{id:e.id,type:e.type,kind:e.kind,owner:r,privacy:e.privacy,name:e.name,preview:e.preview??"",created_at:e.created_at,deleted_at:e.deleted_at}}d(l,"objectDTO");export{l as objectDTO};
@@ -1,2 +1,2 @@
1
- import{jobRow as c}from"../jobs.js";import{objectDTO as m}from"./dto.js";import{recordLiveRead as l,withBase as p}from"./kind.js";import{attr as r,header as w}from"./render.js";const f={name:"job",addressable:"id",events:p({exited:{level:7},killed:{level:7}}),async read(a,s,e,i){const o=await c(a,e);if(!o)throw new Error(`job object ${e.id} has no jobs row`);await l(a,s,e,i.reposFn);const n=await m(a,e),t={command:o.command,status:o.status,exit_code:o.exit_code,log_path:o.log_path},d=[w("object",n,r("status",t.status)+r("exit_code",t.exit_code)),`Command: ${t.command}`,`Log: ${t.log_path}`].join(`
2
- `);return{data:t,text:d}}};export{f as jobKind};
1
+ import{jobRow as d}from"../jobs.js";import{objectDTO as c}from"./dto.js";import{withBase as l}from"./kind.js";import{recordLiveRead as p}from"./live-read.js";import{attr as r,header as w}from"./render.js";const u={name:"job",addressable:"id",events:l({exited:{level:7},killed:{level:7}}),async read(a,i,e,s){const o=await d(a,e);if(!o)throw new Error(`job object ${e.id} has no jobs row`);await p(a,i,e,s.reposFn);const m=await c(a,e),t={command:o.command,status:o.status,exit_code:o.exit_code,log_path:o.log_path},n=[w("object",m,r("status",t.status)+r("exit_code",t.exit_code)),`Command: ${t.command}`,`Log: ${t.log_path}`].join(`
2
+ `);return{data:t,text:n}}};export{u as jobKind};
@@ -1,3 +1,5 @@
1
+ /** The one interface every canvas object kind implements: its declared events, how it is
2
+ * addressed, and how it reads. The kind name is what `objects.type` stores. */
1
3
  import type { ReposFn } from '../reader.js';
2
4
  import type { ReceiverName } from '../receivers.js';
3
5
  import type { CanvasEvent, Level, ObjectRow, Reader } from '../types.js';
@@ -63,5 +65,3 @@ export interface ObjectKind {
63
65
  export declare const BASE_EVENTS: EventCatalog;
64
66
  /** The base events with a kind's own merged over them. */
65
67
  export declare function withBase(own?: EventCatalog): EventCatalog;
66
- /** A live read of a non-document object: the reader watches it and its other watchers hear `read`. */
67
- export declare function recordLiveRead(db: CanvasDb, reader: Reader, object: ObjectRow, reposFn: ReposFn): Promise<void>;
@@ -1 +1 @@
1
- var d=Object.defineProperty;var a=(e,r)=>d(e,"name",{value:r,configurable:!0});import{actorOf as l}from"../documents.js";import{publish as c}from"../events.js";import{recordWatch as n}from"../watches.js";const f={created:{level:4},read:{level:1},watched:{level:1},deleted:{level:5},configured:{level:1}};function u(e={}){return{...f,...e}}a(u,"withBase");async function w(e,r,t,i){const o=l(r);o.rowid!==t.rowid&&(await n(e,o,t,"read"),await c(e,{event:"read",object:t,actor:o,attrs:{}},i))}a(w,"recordLiveRead");export{f as BASE_EVENTS,w as recordLiveRead,u as withBase};
1
+ var r=Object.defineProperty;var l=(e,t)=>r(e,"name",{value:t,configurable:!0});const d={created:{level:4},read:{level:1},watched:{level:1},deleted:{level:5},configured:{level:1}};function n(e={}){return{...d,...e}}l(n,"withBase");export{d as BASE_EVENTS,n as withBase};
@@ -0,0 +1,5 @@
1
+ import type { ReposFn } from '../reader.js';
2
+ import type { ObjectRow, Reader } from '../types.js';
3
+ import type { CanvasDb } from '../../canvas/db.js';
4
+ /** A live read of a non-document object: the reader watches it and its other watchers hear `read`. */
5
+ export declare function recordLiveRead(db: CanvasDb, reader: Reader, object: ObjectRow, reposFn: ReposFn): Promise<void>;
@@ -0,0 +1 @@
1
+ var c=Object.defineProperty;var o=(r,t)=>c(r,"name",{value:t,configurable:!0});import{actorOf as d}from"../documents.js";import{publish as f}from"../events.js";import{recordWatch as m}from"../watches.js";async function h(r,t,a,e){const i=d(t);i.id!==a.id&&(await m(r,i,a,"read"),await f(r,{event:"read",object:a,actor:i,attrs:{}},e))}o(h,"recordLiveRead");export{h as recordLiveRead};
@@ -1,5 +1,5 @@
1
- var E=Object.defineProperty;var l=(t,r)=>E(t,"name",{value:r,configurable:!0});import{cancelCronsOnWake as _}from"../../canvas/crons.js";import{settleMatchingControllerWait as T}from"../../canvas/waits.js";import{effectiveTier as b,listenDeliveryTier as R,newId as I}from"../../feed/messages.js";import{readGoal as N}from"../../runtime/kickoff.js";import{canRead as h}from"../access.js";import{objectDTO as f}from"./dto.js";import{recordLiveRead as S,withBase as L}from"./kind.js";import{attr as O,header as D,section as m}from"./render.js";import{filterAsync as j,mapAsync as C}from"../../async-array.js";const p=[3,5,7];function g(t){return t?.split(`
2
- `).map(r=>r.trim()).find(r=>r!=="")??""}l(g,"firstLine");const K={bodyOwner:l(t=>t[0]?.id??null,"bodyOwner"),async enqueue(t,r,a){const d=Date.now(),s=r.senderNodeId,n=a.map(e=>e.id),c=`(${n.map(()=>"?").join(",")})`,u=s===null?new Set:new Set((await t.prepareUncached(`SELECT DISTINCT node_id FROM waits WHERE kind = 'controller' AND target_id = ? AND satisfied_at IS NULL AND node_id IN ${c}`).all(s,...n)).map(e=>e.node_id)),i=new Set((await t.prepareUncached(`SELECT DISTINCT anchor_node FROM crons WHERE cancel_on_wake = 1 AND anchor_node IN ${c}`).all(...n)).map(e=>e.anchor_node)),w=t.prepare(`INSERT INTO deliveries (delivery_id, message_id, destination_id, urgency, wake, state, created_at, updated_at, idempotency_key)
3
- VALUES (?, ?, ?, ?, ?, 'pending', ?, ?, ?)`);for(const e of a){const o=R(e.delivery),v=e.reception===2?o.wake:0,y=r.elevatesTier?await b(e.id,o.urgency):o.urgency;await w.run(I(),r.messageId,e.id,y,v,d,d,r.idempotencyKey===void 0?null:`${r.idempotencyKey}:${e.id}`),u.has(e.id)&&await T(e.id,s,d,t),v===1&&y!=="deferred"&&i.has(e.id)&&await _(e.id)}}},J={name:"node",addressable:"id",receiver:"inbox",receiverFor:l(async(t,r)=>await t.prepare("SELECT 1 FROM peer_stubs WHERE object = ?").get(r.rowid)===void 0?"inbox":"peer","receiverFor"),events:L({configured:{level:1,durable:!0},messaged:{level:2,durable:!0},sent:{level:1,durable:!0},"report.update":{level:5,levels:p,durable:!0,carriesBody:!0,elevatesTier:!0},"report.final":{level:7,durable:!0,carriesBody:!0,elevatesTier:!0,inboxKind:"final"},outcome:{level:1,durable:!0,supersedes:!0,carriesBody:!0},"report.result":{level:5,durable:!0,carriesBody:!0,elevatesTier:!0,inboxKind:"completed"},"notice.crash":{level:5,levels:p,durable:!0,carriesBody:!0,elevatesTier:!0},"notice.deadline":{level:5,levels:p,durable:!0,carriesBody:!0,elevatesTier:!0},"notice.close":{level:5,levels:p,durable:!0,carriesBody:!0,elevatesTier:!0}}),async read(t,r,a,d){const s=await t.prepare("SELECT status FROM nodes WHERE node_id = ?").get(a.id),n=l(async e=>await C(await j(e,async o=>await h(t,r,o)),async o=>await f(t,o)),"visible"),c=await t.prepare(`SELECT o.* FROM nodes n JOIN objects o ON o.id = n.node_id
4
- WHERE n.parent = ? AND o.deleted_at IS NULL ORDER BY o.rowid`).all(a.id),u=await t.prepare("SELECT * FROM objects WHERE owner = ? AND deleted_at IS NULL ORDER BY rowid").all(a.rowid);await S(t,r,a,d.reposFn);const i={status:s?.status??"deleted",mandate_first_line:g(await N(a.id)),children:await n(c),owned:await n(u.filter(e=>e.type!=="job")),jobs:await n(u.filter(e=>e.type==="job"))},w=[D("object",await f(t,a),O("status",i.status)),`Mandate: ${i.mandate_first_line}`,...m("Children",i.children),...m("Owns",i.owned),...m("Jobs",i.jobs)].join(`
5
- `);return{data:i,text:w}}};export{K as nodeInbox,J as nodeKind};
1
+ var E=Object.defineProperty;var l=(t,r)=>E(t,"name",{value:r,configurable:!0});import{cancelCronsOnWake as _}from"../../canvas/crons.js";import{settleMatchingControllerWait as T}from"../../canvas/waits.js";import{effectiveTier as b,listenDeliveryTier as R,newId as I}from"../../feed/messages.js";import{readGoal as N}from"../../runtime/kickoff.js";import{canRead as h}from"../access.js";import{objectDTO as y}from"./dto.js";import{withBase as S}from"./kind.js";import{recordLiveRead as L}from"./live-read.js";import{attr as O,header as D,section as m}from"./render.js";import{filterAsync as j,mapAsync as C}from"../../async-array.js";const p=[3,5,7];function g(t){return t?.split(`
2
+ `).map(r=>r.trim()).find(r=>r!=="")??""}l(g,"firstLine");const q={bodyOwner:l(t=>t[0]?.id??null,"bodyOwner"),async enqueue(t,r,a){const d=Date.now(),s=r.senderNodeId,n=a.map(e=>e.id),c=`(${n.map(()=>"?").join(",")})`,u=s===null?new Set:new Set((await t.prepareUncached(`SELECT DISTINCT node_id FROM waits WHERE kind = 'controller' AND target_id = ? AND satisfied_at IS NULL AND node_id IN ${c}`).all(s,...n)).map(e=>e.node_id)),i=new Set((await t.prepareUncached(`SELECT DISTINCT anchor_node FROM crons WHERE cancel_on_wake = 1 AND anchor_node IN ${c}`).all(...n)).map(e=>e.anchor_node)),w=t.prepare(`INSERT INTO deliveries (delivery_id, message_id, destination_id, urgency, wake, state, created_at, updated_at, idempotency_key)
3
+ VALUES (?, ?, ?, ?, ?, 'pending', ?, ?, ?)`);for(const e of a){const o=R(e.delivery),f=e.reception===2?o.wake:0,v=r.elevatesTier?await b(e.id,o.urgency):o.urgency;await w.run(I(),r.messageId,e.id,v,f,d,d,r.idempotencyKey===void 0?null:`${r.idempotencyKey}:${e.id}`),u.has(e.id)&&await T(e.id,s,d,t),f===1&&v!=="deferred"&&i.has(e.id)&&await _(e.id)}}},J={name:"node",addressable:"id",receiver:"inbox",receiverFor:l(async(t,r)=>await t.prepare("SELECT 1 FROM peer_stubs WHERE object = ?").get(r.id)===void 0?"inbox":"peer","receiverFor"),events:S({configured:{level:1,durable:!0},messaged:{level:2,durable:!0},sent:{level:1,durable:!0},"report.update":{level:5,levels:p,durable:!0,carriesBody:!0,elevatesTier:!0},"report.final":{level:7,durable:!0,carriesBody:!0,elevatesTier:!0,inboxKind:"final"},outcome:{level:1,durable:!0,supersedes:!0,carriesBody:!0},"report.result":{level:5,durable:!0,carriesBody:!0,elevatesTier:!0,inboxKind:"completed"},"notice.crash":{level:5,levels:p,durable:!0,carriesBody:!0,elevatesTier:!0},"notice.deadline":{level:5,levels:p,durable:!0,carriesBody:!0,elevatesTier:!0},"notice.close":{level:5,levels:p,durable:!0,carriesBody:!0,elevatesTier:!0}}),async read(t,r,a,d){const s=await t.prepare("SELECT status FROM nodes WHERE node_id = ?").get(a.id),n=l(async e=>await C(await j(e,async o=>await h(t,r,o)),async o=>await y(t,o)),"visible"),c=await t.prepare(`SELECT o.* FROM nodes n JOIN objects o ON o.id = n.node_id
4
+ WHERE n.parent = ? AND o.deleted_at IS NULL ORDER BY o.seq`).all(a.id),u=await t.prepare("SELECT * FROM objects WHERE owner = ? AND deleted_at IS NULL ORDER BY seq").all(a.id);await L(t,r,a,d.reposFn);const i={status:s?.status??"deleted",mandate_first_line:g(await N(a.id)),children:await n(c),owned:await n(u.filter(e=>e.type!=="job")),jobs:await n(u.filter(e=>e.type==="job"))},w=[D("object",await y(t,a),O("status",i.status)),`Mandate: ${i.mandate_first_line}`,...m("Children",i.children),...m("Owns",i.owned),...m("Jobs",i.jobs)].join(`
5
+ `);return{data:i,text:w}}};export{q as nodeInbox,J as nodeKind};
@@ -1,2 +1,2 @@
1
- var m=Object.defineProperty;var d=(n,t)=>m(n,"name",{value:t,configurable:!0});import{objectDTO as c}from"./dto.js";import{recordLiveRead as l,withBase as h}from"./kind.js";import{header as y}from"./render.js";function i(n){return{name:n,addressable:"handle",events:h(),async read(t,s,e,o){const r=await t.prepare("SELECT scheme, external_id FROM identities WHERE object = ?").get(e.rowid);await l(t,s,e,o.reposFn);const a={handle:e.name,display_name:e.preview||e.name,identity:{scheme:r?.scheme??"",external_id:r?.external_id??""}},p=[y("object",await c(t,e)),`Handle: ${a.handle}`,`Display name: ${a.display_name}`,`Identity: ${a.identity.scheme}:${a.identity.external_id}`].join(`
2
- `);return{data:a,text:p}}}}d(i,"ownerKind");const E=[i("person"),i("app"),i("repo"),i("profile")];export{E as ownerKinds};
1
+ var p=Object.defineProperty;var d=(n,t)=>p(n,"name",{value:t,configurable:!0});import{objectDTO as c}from"./dto.js";import{withBase as l}from"./kind.js";import{recordLiveRead as h}from"./live-read.js";import{header as y}from"./render.js";function a(n){return{name:n,addressable:"handle",events:l(),async read(t,o,e,s){const r=await t.prepare("SELECT scheme, external_id FROM identities WHERE object = ?").get(e.id);await h(t,o,e,s.reposFn);const i={handle:e.name,display_name:e.preview||e.name,identity:{scheme:r?.scheme??"",external_id:r?.external_id??""}},m=[y("object",await c(t,e)),`Handle: ${i.handle}`,`Display name: ${i.display_name}`,`Identity: ${i.identity.scheme}:${i.identity.external_id}`].join(`
2
+ `);return{data:i,text:m}}}}d(a,"ownerKind");const $=[a("person"),a("app"),a("repo"),a("profile")];export{$ as ownerKinds};
@@ -1,3 +1,3 @@
1
- var $=Object.defineProperty;var s=(e,t)=>$(e,"name",{value:t,configurable:!0});import{isSafeNodeId as H}from"../canvas/paths.js";import{canRead as D,toolApps as C}from"./access.js";import{getById as M}from"./objects.js";import{filterAsync as O,findAsync as d,flatMapAsync as h}from"../async-array.js";async function S(e,t){const n=await e.prepare("SELECT * FROM objects WHERE type = 'person' AND name = 'user' AND home_machine IS NULL").get(),r=await C(e,t),o=t.class==="node"?[t.node,...t.repos,...t.projectRepos,t.profile,t.app]:t.class==="app"?[t.app]:t.class==="object"?[t.owner,...t.repos,t.app]:[],c=new Set;return[...o,n,...r].filter(a=>!!a&&!c.has(a.rowid)&&!!c.add(a.rowid))}s(S,"viewOf");async function m(e,t,n,r,o=!1){return await e.prepareUncached(`SELECT * FROM objects WHERE (type = 'document' OR instr(type, '.') > 0) AND owner = ? AND name = ? AND home_machine IS ${o?"NOT NULL":"NULL"}
2
- AND deleted_at IS ${r?"NOT NULL ORDER BY deleted_at DESC":"NULL"}`).all(t.rowid,n)}s(m,"namedObjects");const b=["person","app","repo","profile"],j=/^(person|app|repo|profile|node):([^/]+)\/(.+)$/,I=s(e=>e.trim().replace(/^\[\[(.*)\]\]$/,"$1").trim(),"unwrapRef");function g(e){const t=j.exec(e);if(t)return{type:t[1],handle:t[2],rest:t[3]};const n=e.indexOf("/");return n>0?{handle:e.slice(0,n),rest:e.slice(n+1)}:null}s(g,"splitOwnerRef");async function x(e,t,n){return n==="node"?await e.prepare("SELECT * FROM objects WHERE type = 'node' AND id = ?").all(t):n?await e.prepare("SELECT * FROM objects WHERE type = ? AND (name = ? OR id = ?) AND home_machine IS NULL").all(n,t,t):await e.prepare(`SELECT * FROM objects WHERE (type = 'node' AND id = ?)
3
- OR (type IN ('person','app','repo','profile') AND (name = ? OR id = ?) AND home_machine IS NULL)`).all(t,t,t)}s(x,"ownersByHandle");async function P(e,t,n,r){let o=I(n);const c=/^([^:/]+):reports\/(.+?)(?:\.md)?$/.exec(o);c&&!j.test(o)&&(o=`${c[1]}/reports/${c[2]}`);const a=r?.readable??(async p=>await D(e,t,p)),w=await M(e,o);if(w&&await a(w))return w.deleted_at?{deleted:w}:{object:w};const y=r?.view??await S(e,t);for(const p of y){const f=await d(await m(e,p,o,!1),a);if(f)return{object:f}}const u=g(o);if(u){const{type:p,handle:f,rest:R}=u,T=p!==void 0,N=await x(e,f,p),L=s(i=>{const l=y.findIndex(_=>_.rowid===i.rowid);return l<0?1/0:l},"rank"),U=N.filter(i=>L(i)<1/0).sort((i,l)=>L(i)-L(l));for(const i of U){const l=await d(await m(e,i,R,!1),a);if(l)return{object:l}}const E=await O(await h(N,async i=>await m(e,i,R,!1)),a);if(E.length===1)return{object:E[0]};if(E.length>1)return{ambiguous:E};const A=await d(await h(N,async i=>await m(e,i,R,!0)),a);return A?{deleted:A}:!T&&N.length===0&&H(f)?{remote:o}:{missing:!0}}for(const p of y){const f=await d(await m(e,p,o,!0),a);if(f)return{deleted:f}}return{missing:!0}}s(P,"resolveName");async function V(e,t,n){const r=I(n),o=s(async(w,y)=>await O(await h(w,async u=>await m(e,u,y,!1,!0)),async u=>await D(e,t,u)),"found"),c=await o(await S(e,t),r);if(c.length)return c;const a=g(r);return a?await o(await x(e,a.handle,a.type),a.rest):[]}s(V,"stubsNamed");export{b as HANDLE_TYPES,x as ownersByHandle,P as resolveName,V as stubsNamed,I as unwrapRef,S as viewOf};
1
+ var $=Object.defineProperty;var s=(e,t)=>$(e,"name",{value:t,configurable:!0});import{isSafeNodeId as H}from"../canvas/paths.js";import{canRead as D,toolApps as C}from"./access.js";import{getById as M}from"./objects.js";import{filterAsync as O,findAsync as d,flatMapAsync as h}from"../async-array.js";async function S(e,t){const n=await e.prepare("SELECT * FROM objects WHERE type = 'person' AND name = 'user' AND home_machine IS NULL").get(),r=await C(e,t),o=t.class==="node"?[t.node,...t.repos,...t.projectRepos,t.profile,t.app]:t.class==="app"?[t.app]:t.class==="object"?[t.owner,...t.repos,t.app]:[],c=new Set;return[...o,n,...r].filter(a=>!!a&&!c.has(a.id)&&!!c.add(a.id))}s(S,"viewOf");async function m(e,t,n,r,o=!1){return await e.prepareUncached(`SELECT * FROM objects WHERE (type = 'document' OR strpos(type, '.') > 0) AND owner = ? AND name = ? AND home_machine IS ${o?"NOT NULL":"NULL"}
2
+ AND deleted_at IS ${r?"NOT NULL ORDER BY deleted_at DESC":"NULL"}`).all(t.id,n)}s(m,"namedObjects");const b=["person","app","repo","profile"],j=/^(person|app|repo|profile|node):([^/]+)\/(.+)$/,I=s(e=>e.trim().replace(/^\[\[(.*)\]\]$/,"$1").trim(),"unwrapRef");function g(e){const t=j.exec(e);if(t)return{type:t[1],handle:t[2],rest:t[3]};const n=e.indexOf("/");return n>0?{handle:e.slice(0,n),rest:e.slice(n+1)}:null}s(g,"splitOwnerRef");async function x(e,t,n){return n==="node"?await e.prepare("SELECT * FROM objects WHERE type = 'node' AND id = ?").all(t):n?await e.prepare("SELECT * FROM objects WHERE type = ? AND (name = ? OR id = ?) AND home_machine IS NULL").all(n,t,t):await e.prepare(`SELECT * FROM objects WHERE (type = 'node' AND id = ?)
3
+ OR (type IN ('person','app','repo','profile') AND (name = ? OR id = ?) AND home_machine IS NULL)`).all(t,t,t)}s(x,"ownersByHandle");async function P(e,t,n,r){let o=I(n);const c=/^([^:/]+):reports\/(.+?)(?:\.md)?$/.exec(o);c&&!j.test(o)&&(o=`${c[1]}/reports/${c[2]}`);const a=r?.readable??(async p=>await D(e,t,p)),l=await M(e,o);if(l&&await a(l))return l.deleted_at?{deleted:l}:{object:l};const y=r?.view??await S(e,t);for(const p of y){const f=await d(await m(e,p,o,!1),a);if(f)return{object:f}}const u=g(o);if(u){const{type:p,handle:f,rest:R}=u,T=p!==void 0,N=await x(e,f,p),L=s(i=>{const w=y.findIndex(_=>_.id===i.id);return w<0?1/0:w},"rank"),U=N.filter(i=>L(i)<1/0).sort((i,w)=>L(i)-L(w));for(const i of U){const w=await d(await m(e,i,R,!1),a);if(w)return{object:w}}const E=await O(await h(N,async i=>await m(e,i,R,!1)),a);if(E.length===1)return{object:E[0]};if(E.length>1)return{ambiguous:E};const A=await d(await h(N,async i=>await m(e,i,R,!0)),a);return A?{deleted:A}:!T&&N.length===0&&H(f)?{remote:o}:{missing:!0}}for(const p of y){const f=await d(await m(e,p,o,!0),a);if(f)return{deleted:f}}return{missing:!0}}s(P,"resolveName");async function V(e,t,n){const r=I(n),o=s(async(l,y)=>await O(await h(l,async u=>await m(e,u,y,!1,!0)),async u=>await D(e,t,u)),"found"),c=await o(await S(e,t),r);if(c.length)return c;const a=g(r);return a?await o(await x(e,a.handle,a.type),a.rest):[]}s(V,"stubsNamed");export{b as HANDLE_TYPES,x as ownersByHandle,P as resolveName,V as stubsNamed,I as unwrapRef,S as viewOf};
@@ -2,12 +2,11 @@ import type { ObjectRow, Privacy, Reader } from './types.js';
2
2
  import type { CanvasDb } from '../canvas/db.js';
3
3
  export type OwnerType = 'person' | 'app' | 'repo' | 'profile';
4
4
  export declare function getById(db: CanvasDb, id: string): Promise<ObjectRow | null>;
5
- export declare function getByRowid(db: CanvasDb, rowid: number): Promise<ObjectRow | null>;
6
5
  export declare function createObject(db: CanvasDb, spec: {
7
6
  id?: string;
8
7
  type: string;
9
8
  kind: string | null;
10
- owner: number | null;
9
+ owner: string | null;
11
10
  privacy: Privacy;
12
11
  name: string;
13
12
  preview: string;
@@ -28,7 +27,7 @@ export declare function renameProfileObject(db: CanvasDb, profileId: string, han
28
27
  /** The owner object of a node grantee: `user:local` → person `user`; `app:<x>` → app `<x>`. */
29
28
  export declare function ownerForGrantee(db: CanvasDb, grantee: string): Promise<ObjectRow>;
30
29
  /** The owner's live document named `name`, or null. */
31
- export declare function liveDocumentNamed(db: CanvasDb, owner: number, name: string): Promise<ObjectRow | null>;
30
+ export declare function liveDocumentNamed(db: CanvasDb, owner: string, name: string): Promise<ObjectRow | null>;
32
31
  export declare function nodeObject(db: CanvasDb, nodeId: string): Promise<ObjectRow>;
33
32
  export declare function setObjectName(db: CanvasDb, object: ObjectRow, name: string): Promise<void>;
34
33
  export declare function setObjectKind(db: CanvasDb, object: ObjectRow, kind: string | null): Promise<void>;
@@ -40,11 +39,12 @@ export interface ObjectFilter {
40
39
  name?: string;
41
40
  deleted?: boolean;
42
41
  }
42
+ /** `after_seq` is the `seq` of the last object on the previous page (the `/v1` cursor, a decimal number). */
43
43
  export interface Page {
44
44
  limit?: number;
45
- after_rowid?: number;
45
+ after_seq?: number;
46
46
  }
47
- /** Objects the reader can read, in rowid order. Records nothing. `limit` ≤ 100. */
47
+ /** Objects the reader can read, in `seq` (insertion) order. Records nothing. `limit` ≤ 100. */
48
48
  export declare function listObjects(db: CanvasDb, reader: Reader, filter: ObjectFilter, page?: Page): Promise<ObjectRow[]>;
49
49
  export interface SearchQuery {
50
50
  text: string;
@@ -1,11 +1,11 @@
1
- var y=Object.defineProperty;var a=(o,e)=>y(o,"name",{value:e,configurable:!0});import{CrtrError as L,notFound as j}from"../errors.js";import{ExitCode as O}from"../../types.js";import{newNodeId as _}from"../runtime/nodes.js";import{kindOf as b}from"./kinds/registry.js";import{canRead as l}from"./access.js";import{bodyOf as A}from"./bodies.js";const I=new Set(["person","app","repo","profile"]);function h(o){return o||null}a(h,"rowFrom");async function T(o,e){return h(await o.prepare("SELECT * FROM objects WHERE id = ?").get(e))}a(T,"getById");async function M(o,e){return h(await o.prepare("SELECT * FROM objects WHERE rowid = ?").get(e))}a(M,"getByRowid");async function x(o,e){return await b(o,e.type),await o.prepare(`INSERT INTO objects (id, type, kind, owner, privacy, name, preview, created_at, home_machine)
2
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING *`).get(e.id??await _(),e.type,e.kind,e.owner,e.privacy,e.name,e.preview,new Date().toISOString(),e.home_machine??null)}a(x,"createObject");async function R(o,e,t,i,n,r){if(!I.has(e))throw new Error(`ensureOwner: ${e} is not an owner type`);const d=await o.prepare(`SELECT o.* FROM identities i JOIN objects o ON o.rowid = i.object
3
- WHERE i.scheme = ? AND i.external_id = ?`).get(t,i);if(d)return d;const s=await o.prepare(`SELECT o.id, o.type, i.scheme, i.external_id FROM objects o
4
- LEFT JOIN identities i ON i.object = o.rowid
5
- WHERE o.name = ? AND o.type = ? AND o.home_machine IS NULL`).get(n,e);if(s)throw new L("conflict",`handle "${n}" is held by ${s.type} ${s.id} (${s.scheme}:${s.external_id}); cannot give it to ${e} ${t}:${i}`,O.GENERAL,{handle:n,holder:s.id});const p=await x(o,{type:e,kind:null,owner:e==="profile"?r?.rowid??null:null,privacy:"public",name:n,preview:""});return await o.prepare("INSERT INTO identities (object, scheme, external_id) VALUES (?, ?, ?)").run(p.rowid,t,i),p}a(R,"ensureOwner");async function k(o,e,t){const i=await o.prepare(`SELECT o.* FROM identities i JOIN objects o ON o.rowid = i.object
1
+ var y=Object.defineProperty;var s=(o,e)=>y(o,"name",{value:e,configurable:!0});import{CrtrError as N,notFound as _}from"../errors.js";import{ExitCode as L}from"../../types.js";import{newNodeId as j}from"../runtime/nodes.js";import{kindOf as I}from"./kinds/registry.js";import{canRead as l}from"./access.js";import{bodyOf as A}from"./bodies.js";const b=new Set(["person","app","repo","profile"]);function O(o){return o||null}s(O,"rowFrom");async function T(o,e){return O(await o.prepare("SELECT * FROM objects WHERE id = ?").get(e))}s(T,"getById");async function D(o,e){return await I(o,e.type),await o.prepare(`INSERT INTO objects (id, type, kind, owner, privacy, name, preview, created_at, home_machine)
2
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING *`).get(e.id??await j(),e.type,e.kind,e.owner,e.privacy,e.name,e.preview,new Date().toISOString(),e.home_machine??null)}s(D,"createObject");async function R(o,e,t,r,n,i){if(!b.has(e))throw new Error(`ensureOwner: ${e} is not an owner type`);const d=await o.prepare(`SELECT o.* FROM identities i JOIN objects o ON o.id = i.object
3
+ WHERE i.scheme = ? AND i.external_id = ?`).get(t,r);if(d)return d;const c=await o.prepare(`SELECT o.id, o.type, i.scheme, i.external_id FROM objects o
4
+ LEFT JOIN identities i ON i.object = o.id
5
+ WHERE o.name = ? AND o.type = ? AND o.home_machine IS NULL`).get(n,e);if(c)throw new N("conflict",`handle "${n}" is held by ${c.type} ${c.id} (${c.scheme}:${c.external_id}); cannot give it to ${e} ${t}:${r}`,L.GENERAL,{handle:n,holder:c.id});const p=await D(o,{type:e,kind:null,owner:e==="profile"?i?.id??null:null,privacy:"public",name:n,preview:""});return await o.prepare("INSERT INTO identities (object, scheme, external_id) VALUES (?, ?, ?)").run(p.id,t,r),p}s(R,"ensureOwner");async function M(o,e,t){const r=await o.prepare(`SELECT o.* FROM identities i JOIN objects o ON o.id = i.object
6
6
  WHERE i.scheme = 'profile' AND i.external_id = ? AND o.type = 'profile' AND o.deleted_at IS NULL`).get(e),n=await o.prepare(`SELECT o.id FROM objects o
7
- WHERE o.name = ? AND o.type = 'profile' AND o.deleted_at IS NULL AND o.home_machine IS NULL AND o.rowid <> ?`).get(t,i?i.rowid:-1);if(n)throw new L("conflict",`handle "${t}" is already held by profile object ${n.id}; cannot rename profile ${e} to it`,O.GENERAL,{handle:t,holder:n.id});if(!i)return!1;const r=i;return r.name===t?!1:(await D(o,r,t),!0)}a(k,"renameProfileObject");async function P(o,e){if(e==="user:local")return await R(o,"person","local-user",e,"user");if(/^app:[a-z0-9][a-z0-9._-]*$/.test(e))return await R(o,"app","app",e,e.slice(4));throw new Error(`node grantee ${JSON.stringify(e)} is neither app:<name> nor user:local`)}a(P,"ownerForGrantee");async function J(o,e,t){return h(await o.prepare("SELECT * FROM objects WHERE (type = 'document' OR instr(type, '.') > 0) AND owner = ? AND name = ? AND deleted_at IS NULL AND home_machine IS NULL").get(e,t))}a(J,"liveDocumentNamed");async function B(o,e){const t=await T(o,e);if(!t||t.type!=="node")throw j(`no node object ${e}`);return t}a(B,"nodeObject");async function D(o,e,t){await o.prepare("UPDATE objects SET name = ? WHERE rowid = ?").run(t,e.rowid)}a(D,"setObjectName");async function G(o,e,t){await o.prepare("UPDATE objects SET kind = ? WHERE rowid = ?").run(t,e.rowid)}a(G,"setObjectKind");async function K(o,e,t,i={}){const n=["rowid > ?"],r=[i.after_rowid??0];return t.type!==void 0&&(n.push("type = ?"),r.push(t.type)),t.kind!==void 0&&(n.push("kind = ?"),r.push(t.kind)),t.owner!==void 0&&(n.push("owner = ?"),r.push(t.owner.rowid)),t.privacy!==void 0&&(n.push("privacy = ?"),r.push(t.privacy)),t.name!==void 0&&(n.push("name = ?"),r.push(t.name)),n.push("home_machine IS NULL"),n.push(t.deleted?"deleted_at IS NOT NULL":"deleted_at IS NULL"),await g(o,e,`SELECT * FROM objects WHERE ${n.join(" AND ")}`,r,Math.min(i.limit??100,100))}a(K,"listObjects");async function Y(o,e,t){const n=[],r=`%${t.text.replace(/[\\%_]/g,c=>`\\${c}`)}%`;if(!t.grep){const c=await o.prepare(`SELECT o.*, d.summary AS _summary FROM objects o LEFT JOIN documents d ON d.object = o.rowid
8
- WHERE o.deleted_at IS NULL AND o.home_machine IS NULL AND (o.name LIKE ?1 ESCAPE '\\' OR o.preview LIKE ?1 ESCAPE '\\' OR d.summary LIKE ?1 ESCAPE '\\')
9
- ORDER BY o.rowid`).all(r),w=t.text.toLowerCase();for(const f of c){const{_summary:E,...u}=f,m=u;if(!await l(o,e,m))continue;const N=m.name.toLowerCase().includes(w)?"name":m.preview.toLowerCase().includes(w)?"preview":"summary";if(n.push({object:m,field:N,...N==="summary"?{text:String(E)}:{}}),n.length>=100)return n}}if(!t.body&&!t.grep)return n;const d=new Set(n.map(c=>c.object.rowid)),s=t.grep?(c=>w=>c.test(w))(new RegExp(t.text)):c=>c.includes(t.text),p=await o.prepare("SELECT * FROM objects WHERE type = 'document' AND deleted_at IS NULL ORDER BY rowid").all(),S=o.prepare(`SELECT r.body_hash, d.source_path FROM revisions r JOIN documents d ON d.object = r.document WHERE r.document = ?
10
- AND NOT EXISTS (SELECT 1 FROM revision_parents p WHERE p.parent = r.rowid)`);for(const c of p)if(!(d.has(c.rowid)||!await l(o,e,c)))for(const{body_hash:w,source_path:f}of await S.all(c.rowid)){const E=A(w,f).split(`
11
- `),u=E.findIndex(s);if(!(u<0)){if(n.push({object:c,field:"body",line:u+1,text:E[u]}),n.length>=100)return n;break}}return n}a(Y,"searchObjects");async function g(o,e,t,i,n){const r=[],d=o.prepareUncached(`${t} ORDER BY rowid LIMIT ${n*4}`);for(;;){const s=await d.all(...i);for(const p of s)if(await l(o,e,p)&&r.push(p),r.length===n)return r;if(s.length<n*4)return r;i[0]=s[s.length-1].rowid}}a(g,"readablePages");export{x as createObject,R as ensureOwner,T as getById,M as getByRowid,K as listObjects,J as liveDocumentNamed,B as nodeObject,P as ownerForGrantee,k as renameProfileObject,Y as searchObjects,G as setObjectKind,D as setObjectName};
7
+ WHERE o.name = ? AND o.type = 'profile' AND o.deleted_at IS NULL AND o.home_machine IS NULL AND o.id <> ?`).get(t,r?r.id:"");if(n)throw new N("conflict",`handle "${t}" is already held by profile object ${n.id}; cannot rename profile ${e} to it`,L.GENERAL,{handle:t,holder:n.id});if(!r)return!1;const i=r;return i.name===t?!1:(await x(o,i,t),!0)}s(M,"renameProfileObject");async function k(o,e){if(e==="user:local")return await R(o,"person","local-user",e,"user");if(/^app:[a-z0-9][a-z0-9._-]*$/.test(e))return await R(o,"app","app",e,e.slice(4));throw new Error(`node grantee ${JSON.stringify(e)} is neither app:<name> nor user:local`)}s(k,"ownerForGrantee");async function P(o,e,t){return O(await o.prepare("SELECT * FROM objects WHERE (type = 'document' OR strpos(type, '.') > 0) AND owner = ? AND name = ? AND deleted_at IS NULL AND home_machine IS NULL").get(e,t))}s(P,"liveDocumentNamed");async function J(o,e){const t=await T(o,e);if(!t||t.type!=="node")throw _(`no node object ${e}`);return t}s(J,"nodeObject");async function x(o,e,t){await o.prepare("UPDATE objects SET name = ? WHERE id = ?").run(t,e.id)}s(x,"setObjectName");async function B(o,e,t){await o.prepare("UPDATE objects SET kind = ? WHERE id = ?").run(t,e.id)}s(B,"setObjectKind");async function G(o,e,t,r={}){const n=["seq > ?"],i=[r.after_seq??0];return t.type!==void 0&&(n.push("type = ?"),i.push(t.type)),t.kind!==void 0&&(n.push("kind = ?"),i.push(t.kind)),t.owner!==void 0&&(n.push("owner = ?"),i.push(t.owner.id)),t.privacy!==void 0&&(n.push("privacy = ?"),i.push(t.privacy)),t.name!==void 0&&(n.push("name = ?"),i.push(t.name)),n.push("home_machine IS NULL"),n.push(t.deleted?"deleted_at IS NOT NULL":"deleted_at IS NULL"),await $(o,e,`SELECT * FROM objects WHERE ${n.join(" AND ")}`,i,Math.min(r.limit??100,100))}s(G,"listObjects");async function K(o,e,t){const n=[],i=`%${t.text.replace(/[\\%_]/g,a=>`\\${a}`)}%`;if(!t.grep){const a=await o.prepare(`SELECT o.*, d.summary AS _summary FROM objects o LEFT JOIN documents d ON d.object = o.id
8
+ WHERE o.deleted_at IS NULL AND o.home_machine IS NULL AND (o.name ILIKE ?1 ESCAPE '\\' OR o.preview ILIKE ?1 ESCAPE '\\' OR d.summary ILIKE ?1 ESCAPE '\\')
9
+ ORDER BY o.seq`).all(i),u=t.text.toLowerCase();for(const f of a){const{_summary:m,...E}=f,w=E;if(!await l(o,e,w))continue;const h=w.name.toLowerCase().includes(u)?"name":w.preview.toLowerCase().includes(u)?"preview":"summary";if(n.push({object:w,field:h,...h==="summary"?{text:String(m)}:{}}),n.length>=100)return n}}if(!t.body&&!t.grep)return n;const d=new Set(n.map(a=>a.object.id)),c=t.grep?(a=>u=>a.test(u))(new RegExp(t.text)):a=>a.includes(t.text),p=await o.prepare("SELECT * FROM objects WHERE type = 'document' AND deleted_at IS NULL ORDER BY seq").all(),S=o.prepare(`SELECT r.body_hash, d.source_path FROM revisions r JOIN documents d ON d.object = r.document WHERE r.document = ?
10
+ AND NOT EXISTS (SELECT 1 FROM revision_parents p WHERE p.parent = r.rev_id)`);for(const a of p)if(!(d.has(a.id)||!await l(o,e,a)))for(const{body_hash:u,source_path:f}of await S.all(a.id)){const m=A(u,f).split(`
11
+ `),E=m.findIndex(c);if(!(E<0)){if(n.push({object:a,field:"body",line:E+1,text:m[E]}),n.length>=100)return n;break}}return n}s(K,"searchObjects");async function $(o,e,t,r,n){const i=[],d=o.prepareUncached(`${t} ORDER BY seq LIMIT ${n*4}`);for(;;){const c=await d.all(...r);for(const p of c)if(await l(o,e,p)&&i.push(p),i.length===n)return i;if(c.length<n*4)return i;r[0]=c[c.length-1].seq}}s($,"readablePages");export{D as createObject,R as ensureOwner,T as getById,G as listObjects,P as liveDocumentNamed,J as nodeObject,k as ownerForGrantee,M as renameProfileObject,K as searchObjects,B as setObjectKind,x as setObjectName};
@@ -1,5 +1,6 @@
1
- var v=Object.defineProperty;var u=(e,a)=>v(e,"name",{value:a,configurable:!0});import{createHash as O,randomUUID as _}from"node:crypto";import{CrtrError as E}from"../errors.js";import{emitEvent as D}from"../events/emit.js";import{quarantineBrokenPlugins as I}from"../plugin-quarantine.js";import{listInstalledPlugins as A}from"../resolver.js";import{builtinMemoryRoot as k,pluginMemoryDir as L}from"../scope.js";import{documentFields as T}from"../../migrations/004-canvas-documents/fields.js";import{applyDocumentFields as j,deleteDocument as R,documentRecord as x,heads as U,importDocument as F,linksIn as b,moveDocument as J}from"./documents.js";import{isShipped as C}from"./access.js";import{setLinks as H}from"./edges.js";import{publish as W}from"./events.js";import{resolveName as M}from"./names.js";import{packageFiles as P}from"./package-files.js";import{ensureOwner as q,getByRowid as h,setObjectKind as B}from"./objects.js";import{checkoutsForCwd as K}from"./repo-sync/repos.js";import{rulesOf as $}from"./rules.js";function z(){return[{plugin:"crtr",dir:k()},...A("user").filter(e=>e.enabled).map(e=>({plugin:e.name,dir:L(e)}))]}u(z,"packageSources");const G=u(e=>O("sha256").update(e,"utf8").digest("hex"),"sha256");async function we(e,a){const n={created:0,updated:0,deleted:0,conflicts:[],invalid:[],quarantined:[]};if(a===void 0){n.quarantined=I();for(const o of n.quarantined)D({level:"error",event:"daemon.plugins.quarantined",fields:{plugin:o.name,file:o.file,reason:o.reason,...o.movedTo!==void 0?{moved_to:o.movedTo}:{}}})}const l=a??z(),p=u(async o=>await K(e,o),"reposFn"),i=new Set,r=[],w=new Set;for(const o of l){let s;try{if(w.has(o.plugin))throw new E("conflict",`plugin "${o.plugin}" is already provided by another package`);w.add(o.plugin),s=await q(e,"app","app",`app:${o.plugin}`,o.plugin)}catch(c){if(!(c instanceof E)||c.code!=="conflict")throw c;n.conflicts.push({plugin:o.plugin,message:c.message});continue}i.add(s.rowid);const{files:m,invalid:f}=P(o.dir);n.invalid.push(...f);const y=new Set;for(const c of m){const d=await V(e,s,c,n,p);y.add(d),r.push({owner:s,rowid:d,body:c.body})}await S(e,s,y,n,p)}const t=await e.prepare(`SELECT DISTINCT o.owner AS rowid FROM objects o JOIN documents d ON d.object = o.rowid
2
- WHERE o.type = 'document' AND o.deleted_at IS NULL AND d.source_path IS NOT NULL`).all();for(const{rowid:o}of t)i.has(o)||await S(e,await h(e,o),new Set,n,p);for(const{owner:o,rowid:s,body:m}of r)await Q(e,o,await h(e,s),m);return n}u(we,"reconcilePackageDocuments");async function Q(e,a,n,l){if(n.deleted_at!==null)return;const p={class:"app",app:a,scopes:[]},i=[];for(const t of b(l)){const o=await M(e,p,t);"object"in o&&o.object.rowid!==n.rowid&&await C(e,o.object)&&i.push({written_as:t,dst:o.object})}const r=u(t=>JSON.stringify(t.map(o=>[o.dst,o.written_as]).sort()),"key"),w=await e.prepare("SELECT dst, written_as FROM edges WHERE type = 'links-to' AND src = ?").all(n.rowid);r(w)!==r(i.map(t=>({dst:t.dst.rowid,written_as:t.written_as})))&&await H(e,n,i)}u(Q,"deriveLinks");async function V(e,a,n,l,p){const i=T(n.frontmatter,n.body,{missingPrivacy:"public"}),r={preview:i.preview.trim()===""?n.name:i.preview,summary:i.summary,whyItExists:i.whyItExists,unlisted:i.unlisted,rules:i.rules,lintIgnore:Array.isArray(i.lintIgnore)?i.lintIgnore.filter(d=>typeof d=="string"):null,extensions:i.extensions!==null&&typeof i.extensions=="object"&&!Array.isArray(i.extensions)?i.extensions:null},w=G(n.body);let t=await e.prepare(`SELECT o.* FROM objects o JOIN documents d ON d.object = o.rowid
3
- WHERE o.type = 'document' AND o.owner = ? AND o.deleted_at IS NULL AND d.source_path = ?`).get(a.rowid,n.path);if(t||(t=await e.prepare(`SELECT o.* FROM objects o JOIN documents d ON d.object = o.rowid
4
- WHERE o.type = 'document' AND o.owner = ? AND o.deleted_at IS NULL AND o.name = ? AND d.source_path IS NOT NULL`).get(a.rowid,n.name),t&&await e.prepare("UPDATE documents SET source_path = ? WHERE object = ?").run(n.path,t.rowid)),!t){const d=await F(e,{owner:a,name:n.name,kind:i.kind,privacy:"public",...r,revisions:[{body_hash:w,author:a,rationale:null,created_at:new Date().toISOString()}]});return await e.prepare("UPDATE documents SET source_path = ? WHERE object = ?").run(n.path,d.rowid),l.created+=1,d.rowid}const o=t.name!==n.name||t.kind!==i.kind;t.name!==n.name&&(t=await J(e,null,t,{name:n.name})),t.kind!==i.kind&&(await B(e,t,i.kind),t=await h(e,t.rowid));const s=await x(e,t),[m]=await U(e,t),f=m?.body_hash!==w,y=t.preview!==r.preview||s.summary!==r.summary||s.why_it_exists!==r.whyItExists||s.unlisted!==r.unlisted||JSON.stringify(s.lint_ignore)!==JSON.stringify(r.lintIgnore)||JSON.stringify(s.extensions)!==JSON.stringify(r.extensions)||JSON.stringify((await $(e,t)).map(N))!==JSON.stringify(r.rules.map(N));if(!f&&!y&&!o)return t.rowid;const c=await j(e,t,r);if(f&&m){const d=_(),g=m.number+1;await e.prepare("UPDATE revisions SET rev_id = ?, number = ?, body_hash = ?, created_at = ? WHERE rowid = ?").run(d,g,w,new Date().toISOString(),m.rowid),await e.prepare("UPDATE documents SET heads_key = ?, revision = ? WHERE object = ?").run(d,g,c.rowid),await W(e,{event:"edited",object:c,actor:a,pointer:d,attrs:{revision:g,from_revision:m.number,rationale:"package file changed"}},p)}return l.updated+=1,c.rowid}u(V,"convergeFile");function N(e){return[e.on,e.deliver,e.match??null,e.matchFrontmatter??null,e.if??null]}u(N,"ruleKey");async function S(e,a,n,l,p){const i=await e.prepare(`SELECT o.* FROM objects o JOIN documents d ON d.object = o.rowid
5
- WHERE o.type = 'document' AND o.owner = ? AND o.deleted_at IS NULL AND d.source_path IS NOT NULL`).all(a.rowid);for(const r of i)n.has(r.rowid)||(await R(e,null,r,p),l.deleted+=1)}u(S,"deleteMissing");export{z as packageSources,we as reconcilePackageDocuments};
1
+ var S=Object.defineProperty;var u=(e,a)=>S(e,"name",{value:a,configurable:!0});import{createHash as _,randomUUID as O}from"node:crypto";import{CrtrError as g}from"../errors.js";import{emitEvent as I}from"../events/emit.js";import{quarantineBrokenPlugins as D}from"../plugin-quarantine.js";import{listInstalledPlugins as T}from"../resolver.js";import{builtinMemoryRoot as L,pluginMemoryDir as R}from"../scope.js";import{documentFields as k}from"../../migrations/004-canvas-documents/fields.js";import{applyDocumentFields as A,deleteDocument as j,documentRecord as F,heads as x,importDocument as C,linksIn as H,moveDocument as U}from"./documents.js";import{isShipped as b}from"./access.js";import{setLinks as J}from"./edges.js";import{publish as M}from"./events.js";import{resolveName as W}from"./names.js";import{packageFiles as P}from"./package-files.js";import{ensureOwner as q,getById as E,setObjectKind as B}from"./objects.js";import{checkoutsForCwd as K}from"./repo-sync/repos.js";import{rulesOf as $}from"./rules.js";function z(){return[{plugin:"crtr",dir:L()},...T("user").filter(e=>e.enabled).map(e=>({plugin:e.name,dir:R(e)}))]}u(z,"packageSources");const G=u(e=>_("sha256").update(e,"utf8").digest("hex"),"sha256");async function fe(e,a){const i={created:0,updated:0,deleted:0,conflicts:[],invalid:[],quarantined:[]};if(a===void 0){i.quarantined=D();for(const n of i.quarantined)I({level:"error",event:"daemon.plugins.quarantined",fields:{plugin:n.name,file:n.file,reason:n.reason,...n.movedTo!==void 0?{moved_to:n.movedTo}:{}}})}const l=a??z(),m=u(async n=>await K(e,n),"reposFn"),o=new Set,r=[],f=new Set;for(const n of l){let s;try{if(f.has(n.plugin))throw new g("conflict",`plugin "${n.plugin}" is already provided by another package`);f.add(n.plugin),s=await q(e,"app","app",`app:${n.plugin}`,n.plugin)}catch(p){if(!(p instanceof g)||p.code!=="conflict")throw p;i.conflicts.push({plugin:n.plugin,message:p.message});continue}o.add(s.id);const{files:d,invalid:w}=P(n.dir);i.invalid.push(...w);const h=new Set;for(const p of d){const c=await V(e,s,p,i,m);h.add(c),r.push({owner:s,id:c,body:p.body})}await v(e,s,h,i,m)}const t=await e.prepare(`SELECT DISTINCT o.owner AS id FROM objects o JOIN documents d ON d.object = o.id
2
+ WHERE o.type = 'document' AND o.deleted_at IS NULL AND d.source_path IS NOT NULL`).all();for(const{id:n}of t)o.has(n)||await v(e,await E(e,n),new Set,i,m);for(const{owner:n,id:s,body:d}of r)await Q(e,n,await E(e,s),d);return i}u(fe,"reconcilePackageDocuments");async function Q(e,a,i,l){if(i.deleted_at!==null)return;const m={class:"app",app:a,scopes:[]},o=[];for(const t of H(l)){const n=await W(e,m,t);"object"in n&&n.object.id!==i.id&&await b(e,n.object)&&o.push({written_as:t,dst:n.object})}const r=u(t=>JSON.stringify(t.map(n=>[n.dst,n.written_as]).sort()),"key"),f=await e.prepare("SELECT dst, written_as FROM edges WHERE type = 'links-to' AND src = ?").all(i.id);r(f)!==r(o.map(t=>({dst:t.dst.id,written_as:t.written_as})))&&await J(e,i,o)}u(Q,"deriveLinks");async function V(e,a,i,l,m){const o=k(i.frontmatter,i.body,{missingPrivacy:"public"}),r={preview:o.preview.trim()===""?i.name:o.preview,summary:o.summary,whyItExists:o.whyItExists,unlisted:o.unlisted,rules:o.rules,lintIgnore:Array.isArray(o.lintIgnore)?o.lintIgnore.filter(c=>typeof c=="string"):null,extensions:o.extensions!==null&&typeof o.extensions=="object"&&!Array.isArray(o.extensions)?o.extensions:null},f=G(i.body);let t=await e.prepare(`SELECT o.* FROM objects o JOIN documents d ON d.object = o.id
3
+ WHERE o.type = 'document' AND o.owner = ? AND o.deleted_at IS NULL AND d.source_path = ?`).get(a.id,i.path);if(t||(t=await e.prepare(`SELECT o.* FROM objects o JOIN documents d ON d.object = o.id
4
+ WHERE o.type = 'document' AND o.owner = ? AND o.deleted_at IS NULL AND o.name = ? AND d.source_path IS NOT NULL`).get(a.id,i.name),t&&await e.prepare("UPDATE documents SET source_path = ? WHERE object = ?").run(i.path,t.id)),!t){const c=await C(e,{owner:a,name:i.name,kind:o.kind,privacy:"public",...r,revisions:[{body_hash:f,author:a,rationale:null,created_at:new Date().toISOString()}]});return await e.prepare("UPDATE documents SET source_path = ? WHERE object = ?").run(i.path,c.id),l.created+=1,c.id}const n=t.name!==i.name||t.kind!==o.kind;t.name!==i.name&&(t=await U(e,null,t,{name:i.name})),t.kind!==o.kind&&(await B(e,t,o.kind),t=await E(e,t.id));const s=await F(e,t),[d]=await x(e,t),w=d?.body_hash!==f,h=t.preview!==r.preview||s.summary!==r.summary||s.why_it_exists!==r.whyItExists||s.unlisted!==r.unlisted||JSON.stringify(s.lint_ignore)!==JSON.stringify(r.lintIgnore)||JSON.stringify(s.extensions)!==JSON.stringify(r.extensions)||JSON.stringify((await $(e,t)).map(N))!==JSON.stringify(r.rules.map(N));if(!w&&!h&&!n)return t.id;const p=await A(e,t,r);if(w&&d){const c=O(),y=d.number+1;await e.prepare(`INSERT INTO revisions (rev_id, document, number, body_hash, author, rationale, verbatim, created_at)
5
+ SELECT ?, document, ?, ?, author, rationale, verbatim, ? FROM revisions WHERE rev_id = ?`).run(c,y,f,new Date().toISOString(),d.rev_id),await e.prepare("INSERT INTO revision_parents (child, parent) SELECT ?, parent FROM revision_parents WHERE child = ?").run(c,d.rev_id),await e.prepare("DELETE FROM revisions WHERE rev_id = ?").run(d.rev_id),await e.prepare("UPDATE documents SET heads_key = ?, revision = ? WHERE object = ?").run(c,y,p.id),await M(e,{event:"edited",object:p,actor:a,pointer:c,attrs:{revision:y,from_revision:d.number,rationale:"package file changed"}},m)}return l.updated+=1,p.id}u(V,"convergeFile");function N(e){return[e.on,e.deliver,e.match??null,e.matchFrontmatter??null,e.if??null]}u(N,"ruleKey");async function v(e,a,i,l,m){const o=await e.prepare(`SELECT o.* FROM objects o JOIN documents d ON d.object = o.id
6
+ WHERE o.type = 'document' AND o.owner = ? AND o.deleted_at IS NULL AND d.source_path IS NOT NULL`).all(a.id);for(const r of o)i.has(r.id)||(await j(e,null,r,m),l.deleted+=1)}u(v,"deleteMissing");export{z as packageSources,fe as reconcilePackageDocuments};
@@ -33,7 +33,7 @@ export interface ReaderLookups {
33
33
  terminalHasIssuer(): boolean;
34
34
  /** The scopes of the `crtr_app_` token a local plugin's app (`app:<plugin>`) holds, or null when it holds none. */
35
35
  pluginScopes(grantee: string): readonly string[] | null;
36
- object(rowid: number): Promise<ObjectRow | null>;
36
+ object(id: string): Promise<ObjectRow | null>;
37
37
  profile(profileId: string, app: ObjectRow): Promise<ObjectRow>;
38
38
  /** The profile's project paths in manifest order; none in a sandboxed node, whose profile store is unreadable. */
39
39
  projectPaths(profileId: string): readonly string[];
@@ -1,3 +1,3 @@
1
- var F=Object.defineProperty;var p=(o,e)=>F(o,"name",{value:e,configurable:!0});import{coveredByAny as f,isSandboxedNode as x}from"../../shared/env.js";import{existsSync as H}from"node:fs";import{CrtrError as C}from"../errors.js";import{getStoredProfile as L}from"../scoped-state/profiles.js";import{userScopeRoot as A}from"../scope.js";import{parseScope as R}from"@north-light/identity";import{activeGrant as O,grantFor as v}from"../grants/mirror.js";import{ApiError as b}from"../../api/errors.js";import{readConfig as $}from"../config.js";import{pluginAppToken as M}from"../secrets.js";import{SCOPE_VOCABULARY as d}from"../scopes.js";import{loadExactProfileManifest as T}from"../profiles/manifest.js";import{ensureOwner as _,getByRowid as W,nodeObject as D}from"./objects.js";async function y(o,e,t,a){const r=e===null?[]:a.projectPaths(e),n=await t(o),l=new Set(n.map(s=>s.repo.rowid)),c=[];for(const s of r){if(!H(s))continue;let i;try{i=await t(s)}catch(u){if(u instanceof C&&u.code==="git-lookup-failed")continue;throw u}for(const u of i)l.has(u.repo.rowid)||(l.add(u.repo.rowid),c.push(u))}return{repos:n.map(s=>s.repo),checkouts:n,projectRepos:c.map(s=>s.repo),projectCheckouts:c}}p(y,"viewRepos");async function re(o,e,t){if(e.class==="anonymous")throw new Error("a publish token cannot read as a principal");if(e.class==="person")return{class:"person",person:await E(o)};if(e.class==="app")return{class:"app",app:await g(o,e.app),scopes:e.scopes};if(e.class==="machine")throw new Error("a machine token cannot read as a principal");if(e.class==="forwarded"){if(e.actor.kind==="person")return{class:"person",person:await E(o)};const c=await v(e.actor.app,e.sub);if(!c)throw new b(403,"app_not_granted",`${e.actor.app} holds no active grant for ${e.sub} on this machine`);const s=e.actor.node_scopes;return{class:"app",app:await g(o,e.actor.app),place:e.actor.place,launched:s,scopes:s===null?c.resolved:s.filter(i=>f(c.resolved,i))}}if(e.class==="cron"){const c=e.grant?(await O(e.grant))?.resolved??[]:d,s=e.scopes;return{class:"app",app:await g(o,e.app),scopes:s===null?c:s.filter(i=>f(c,i)),launched:s,place:{run:e.origin_run??"",isolated:e.isolated}}}const a=m(o),r=await D(o,e.node),n=r.owner===null?null:await a.object(r.owner);if(!n)throw new Error(`node ${e.node} has no owner`);const l=await o.prepare("SELECT cwd, profile_id FROM nodes WHERE node_id = ?").get(e.node);return{class:"node",node:r,app:n,scopes:await N(e.app,e.sub,e.grant,e.scopes,a),launched:e.scopes,cwd:l.cwd,...await y(l.cwd,l.profile_id,t,a),profile:l.profile_id===null?null:await a.profile(l.profile_id,n)}}p(re,"readerFor");async function B(o,e,t,a=m(o),r=!1){const n=await o.prepare("SELECT o.* FROM objects o WHERE o.id = ? AND o.type = 'node'").get(e),l=await o.prepare(`SELECT (SELECT external_id FROM identities WHERE object = ?) AS grantee,
2
- sub, grant_id, scopes_json, cwd, profile_id FROM nodes WHERE node_id = ?`).get(n?.owner??null,e);if(!n||!l)throw new Error(`no node ${e}`);const{grantee:c,sub:s,grant_id:i,scopes_json:u,cwd:w,profile_id:j}=l,h=n.owner===null?null:await a.object(n.owner);if(!h)throw new Error(`node ${e} has no owner`);const S=u===null?null:JSON.parse(u);return{class:"node",node:n,app:h,scopes:await N(c,s??"",i,S,a,r),launched:S,cwd:w,...await y(w,j,t,a),profile:j===null?null:await a.profile(j,h)}}p(B,"readerForNode");async function ne(o,e,t=async()=>[],a=m(o)){const r=await o.prepare("SELECT envelope_json FROM peer_stubs WHERE object = ?").get(e.rowid);if(r!==void 0)return await P(o,e,r.envelope_json===null?null:JSON.parse(r.envelope_json),a);if(e.type==="node")return await B(o,e.id,t,a,!0);const n=e.owner===null?null:await a.object(e.owner);if(!n)throw new Error(`watcher ${e.id} has no owner`);const c=(n.type==="app"?n:n.type==="profile"&&n.owner!==null?await a.object(n.owner):null)??await o.prepare("SELECT o.* FROM identities i JOIN objects o ON o.rowid = i.object WHERE i.external_id = 'app:terminal' AND i.scheme = 'app'").get()??await o.prepare("SELECT * FROM objects WHERE type = 'person' AND name = 'user' AND home_machine IS NULL").get();if(!c)throw new Error("no terminal app or person object");const s=(await o.prepare("SELECT external_id FROM identities WHERE object = ? AND scheme = 'app'").get(c.rowid))?.external_id??"app:terminal",i=await o.prepare("SELECT resolved_scopes_json FROM grants WHERE grantee = ? AND status = 'active'").all(s),u=n.type==="person"?null:i.length===0?s==="app:terminal"&&!a.terminalHasIssuer()?d:a.pluginScopes(s):i.length===1?JSON.parse(i[0].resolved_scopes_json).filter(w=>w.mode==="always").map(w=>R(w.scope)):null;return{class:"object",object:e,node:e,owner:n,app:c,scopes:u,repos:n.type==="repo"?[n]:[]}}p(ne,"readerForObject");async function te(o,e,t){const a=(await o.prepare("SELECT external_id FROM identities WHERE object = ? AND scheme = 'app'").get(e.rowid))?.external_id;if(a===void 0)return null;const r=await o.prepare("SELECT resolved_scopes_json FROM grants WHERE grantee = ? AND status = 'active'").all(a);return r.length===0?a==="app:terminal"&&!t.terminalHasIssuer()?d:t.pluginScopes(a):r.length>1?null:JSON.parse(r[0].resolved_scopes_json).filter(n=>n.mode==="always").map(n=>R(n.scope))}p(te,"appScopesNow");async function P(o,e,t,a){const r=await E(o);if(t!==null&&t.app===null)return{class:"object",object:e,node:e,owner:r,app:r,scopes:null,repos:[]};const n=t?.app==null?null:await g(o,t.app),l=t?.app==null?null:await a.grantFor(t.app,t.sub),c=t===null||l===null?null:t.node_scopes===null?l.resolved:t.node_scopes.filter(i=>f(l.resolved,i)),s=n??(e.owner===null?r:await a.object(e.owner)??r);return{class:"object",object:e,node:e,owner:s,app:s,scopes:c,launched:t?.node_scopes??null,repos:[],...t?.place==null?{}:{place:t.place}}}p(P,"readerForStub");function m(o){return{grantById:O,grantFor:v,terminalHasIssuer:p(()=>!!$("user").runtime?.issuer,"terminalHasIssuer"),pluginScopes:p(e=>M(e.replace(/^app:/,""))?.scopes??null,"pluginScopes"),object:p(async e=>await W(o,e),"object"),profile:p(async(e,t)=>await I(o,e,t),"profile"),projectPaths:p(e=>x()?[]:L(A(),e)?.manifest.projects.map(t=>t.path)??[],"projectPaths")}}p(m,"liveLookups");function ae(o){const e=m(o),t=new Map,a=p((r,n)=>(t.has(r)||t.set(r,n()),t.get(r)),"memo");return{grantById:p(r=>a(`g\0${r}`,()=>e.grantById(r)),"grantById"),grantFor:p((r,n)=>a(`a\0${r}\0${n}`,()=>e.grantFor(r,n)),"grantFor"),terminalHasIssuer:p(()=>a("issuer",()=>e.terminalHasIssuer()),"terminalHasIssuer"),pluginScopes:p(r=>a(`t\0${r}`,()=>e.pluginScopes(r)),"pluginScopes"),object:p(async r=>await a(`o\0${r}`,async()=>await e.object(r)),"object"),profile:p(async(r,n)=>await a(`p\0${r}\0${n.rowid}`,async()=>await e.profile(r,n)),"profile"),projectPaths:p(r=>a(`j\0${r}`,()=>e.projectPaths(r)),"projectPaths")}}p(ae,"publishLookups");async function N(o,e,t,a,r,n=!1){const l=t?await r.grantById(t):await r.grantFor(o,e),c=l&&l.grantee===o?l.resolved:o==="app:terminal"&&!r.terminalHasIssuer()?d:null;if(c===null){if(n)return null;throw new Error(`the grant of ${o} is not active`)}return a===null?c:a.filter(s=>f(c,s))}p(N,"nodeScopes");async function E(o){return await _(o,"person","local-user","user:local","user")}p(E,"personObject");async function g(o,e){return e==="user:local"?await E(o):await _(o,"app","app",e,e.replace(/^app:/,""))}p(g,"appObject");async function I(o,e,t){return await o.prepare(`SELECT o.* FROM identities i JOIN objects o ON o.rowid = i.object
1
+ var F=Object.defineProperty;var p=(o,e)=>F(o,"name",{value:e,configurable:!0});import{coveredByAny as f,isSandboxedNode as x}from"../../shared/env.js";import{existsSync as H}from"node:fs";import{CrtrError as C}from"../errors.js";import{getStoredProfile as L}from"../scoped-state/profiles.js";import{userScopeRoot as A}from"../scope.js";import{parseScope as O}from"@north-light/identity";import{activeGrant as R,grantFor as v}from"../grants/mirror.js";import{ApiError as b}from"../../api/errors.js";import{readConfig as $}from"../config.js";import{pluginAppToken as M}from"../secrets.js";import{SCOPE_VOCABULARY as d}from"../scopes.js";import{loadExactProfileManifest as T}from"../profiles/manifest.js";import{ensureOwner as _,getById as W,nodeObject as D}from"./objects.js";async function y(o,e,t,a){const r=e===null?[]:a.projectPaths(e),n=await t(o),l=new Set(n.map(s=>s.repo.id)),c=[];for(const s of r){if(!H(s))continue;let i;try{i=await t(s)}catch(u){if(u instanceof C&&u.code==="git-lookup-failed")continue;throw u}for(const u of i)l.has(u.repo.id)||(l.add(u.repo.id),c.push(u))}return{repos:n.map(s=>s.repo),checkouts:n,projectRepos:c.map(s=>s.repo),projectCheckouts:c}}p(y,"viewRepos");async function re(o,e,t){if(e.class==="anonymous")throw new Error("a publish token cannot read as a principal");if(e.class==="person")return{class:"person",person:await E(o)};if(e.class==="app")return{class:"app",app:await g(o,e.app),scopes:e.scopes};if(e.class==="machine")throw new Error("a machine token cannot read as a principal");if(e.class==="forwarded"){if(e.actor.kind==="person")return{class:"person",person:await E(o)};const c=await v(e.actor.app,e.sub);if(!c)throw new b(403,"app_not_granted",`${e.actor.app} holds no active grant for ${e.sub} on this machine`);const s=e.actor.node_scopes;return{class:"app",app:await g(o,e.actor.app),place:e.actor.place,launched:s,scopes:s===null?c.resolved:s.filter(i=>f(c.resolved,i))}}if(e.class==="cron"){const c=e.grant?(await R(e.grant))?.resolved??[]:d,s=e.scopes;return{class:"app",app:await g(o,e.app),scopes:s===null?c:s.filter(i=>f(c,i)),launched:s,place:{run:e.origin_run??"",isolated:e.isolated}}}const a=m(o),r=await D(o,e.node),n=r.owner===null?null:await a.object(r.owner);if(!n)throw new Error(`node ${e.node} has no owner`);const l=await o.prepare("SELECT cwd, profile_id FROM nodes WHERE node_id = ?").get(e.node);return{class:"node",node:r,app:n,scopes:await N(e.app,e.sub,e.grant,e.scopes,a),launched:e.scopes,cwd:l.cwd,...await y(l.cwd,l.profile_id,t,a),profile:l.profile_id===null?null:await a.profile(l.profile_id,n)}}p(re,"readerFor");async function B(o,e,t,a=m(o),r=!1){const n=await o.prepare("SELECT o.* FROM objects o WHERE o.id = ? AND o.type = 'node'").get(e),l=await o.prepare(`SELECT (SELECT external_id FROM identities WHERE object = ?) AS grantee,
2
+ sub, grant_id, scopes_json, cwd, profile_id FROM nodes WHERE node_id = ?`).get(n?.owner??null,e);if(!n||!l)throw new Error(`no node ${e}`);const{grantee:c,sub:s,grant_id:i,scopes_json:u,cwd:w,profile_id:j}=l,h=n.owner===null?null:await a.object(n.owner);if(!h)throw new Error(`node ${e} has no owner`);const S=u===null?null:JSON.parse(u);return{class:"node",node:n,app:h,scopes:await N(c,s??"",i,S,a,r),launched:S,cwd:w,...await y(w,j,t,a),profile:j===null?null:await a.profile(j,h)}}p(B,"readerForNode");async function ne(o,e,t=async()=>[],a=m(o)){const r=await o.prepare("SELECT envelope_json FROM peer_stubs WHERE object = ?").get(e.id);if(r!==void 0)return await P(o,e,r.envelope_json===null?null:JSON.parse(r.envelope_json),a);if(e.type==="node")return await B(o,e.id,t,a,!0);const n=e.owner===null?null:await a.object(e.owner);if(!n)throw new Error(`watcher ${e.id} has no owner`);const c=(n.type==="app"?n:n.type==="profile"&&n.owner!==null?await a.object(n.owner):null)??await o.prepare("SELECT o.* FROM identities i JOIN objects o ON o.id = i.object WHERE i.external_id = 'app:terminal' AND i.scheme = 'app'").get()??await o.prepare("SELECT * FROM objects WHERE type = 'person' AND name = 'user' AND home_machine IS NULL").get();if(!c)throw new Error("no terminal app or person object");const s=(await o.prepare("SELECT external_id FROM identities WHERE object = ? AND scheme = 'app'").get(c.id))?.external_id??"app:terminal",i=await o.prepare("SELECT resolved_scopes_json FROM grants WHERE grantee = ? AND status = 'active'").all(s),u=n.type==="person"?null:i.length===0?s==="app:terminal"&&!a.terminalHasIssuer()?d:a.pluginScopes(s):i.length===1?JSON.parse(i[0].resolved_scopes_json).filter(w=>w.mode==="always").map(w=>O(w.scope)):null;return{class:"object",object:e,node:e,owner:n,app:c,scopes:u,repos:n.type==="repo"?[n]:[]}}p(ne,"readerForObject");async function te(o,e,t){const a=(await o.prepare("SELECT external_id FROM identities WHERE object = ? AND scheme = 'app'").get(e.id))?.external_id;if(a===void 0)return null;const r=await o.prepare("SELECT resolved_scopes_json FROM grants WHERE grantee = ? AND status = 'active'").all(a);return r.length===0?a==="app:terminal"&&!t.terminalHasIssuer()?d:t.pluginScopes(a):r.length>1?null:JSON.parse(r[0].resolved_scopes_json).filter(n=>n.mode==="always").map(n=>O(n.scope))}p(te,"appScopesNow");async function P(o,e,t,a){const r=await E(o);if(t!==null&&t.app===null)return{class:"object",object:e,node:e,owner:r,app:r,scopes:null,repos:[]};const n=t?.app==null?null:await g(o,t.app),l=t?.app==null?null:await a.grantFor(t.app,t.sub),c=t===null||l===null?null:t.node_scopes===null?l.resolved:t.node_scopes.filter(i=>f(l.resolved,i)),s=n??(e.owner===null?r:await a.object(e.owner)??r);return{class:"object",object:e,node:e,owner:s,app:s,scopes:c,launched:t?.node_scopes??null,repos:[],...t?.place==null?{}:{place:t.place}}}p(P,"readerForStub");function m(o){return{grantById:R,grantFor:v,terminalHasIssuer:p(()=>!!$("user").runtime?.issuer,"terminalHasIssuer"),pluginScopes:p(e=>M(e.replace(/^app:/,""))?.scopes??null,"pluginScopes"),object:p(async e=>await W(o,e),"object"),profile:p(async(e,t)=>await I(o,e,t),"profile"),projectPaths:p(e=>x()?[]:L(A(),e)?.manifest.projects.map(t=>t.path)??[],"projectPaths")}}p(m,"liveLookups");function ae(o){const e=m(o),t=new Map,a=p((r,n)=>(t.has(r)||t.set(r,n()),t.get(r)),"memo");return{grantById:p(r=>a(`g\0${r}`,()=>e.grantById(r)),"grantById"),grantFor:p((r,n)=>a(`a\0${r}\0${n}`,()=>e.grantFor(r,n)),"grantFor"),terminalHasIssuer:p(()=>a("issuer",()=>e.terminalHasIssuer()),"terminalHasIssuer"),pluginScopes:p(r=>a(`t\0${r}`,()=>e.pluginScopes(r)),"pluginScopes"),object:p(async r=>await a(`o\0${r}`,async()=>await e.object(r)),"object"),profile:p(async(r,n)=>await a(`p\0${r}\0${n.id}`,async()=>await e.profile(r,n)),"profile"),projectPaths:p(r=>a(`j\0${r}`,()=>e.projectPaths(r)),"projectPaths")}}p(ae,"publishLookups");async function N(o,e,t,a,r,n=!1){const l=t?await r.grantById(t):await r.grantFor(o,e),c=l&&l.grantee===o?l.resolved:o==="app:terminal"&&!r.terminalHasIssuer()?d:null;if(c===null){if(n)return null;throw new Error(`the grant of ${o} is not active`)}return a===null?c:a.filter(s=>f(c,s))}p(N,"nodeScopes");async function E(o){return await _(o,"person","local-user","user:local","user")}p(E,"personObject");async function g(o,e){return e==="user:local"?await E(o):await _(o,"app","app",e,e.replace(/^app:/,""))}p(g,"appObject");async function I(o,e,t){return await o.prepare(`SELECT o.* FROM identities i JOIN objects o ON o.id = i.object
3
3
  WHERE i.scheme = 'profile' AND i.external_id = ?`).get(e)??await _(o,"profile","profile",e,T(e).manifest.name,t)}p(I,"profileObject");export{te as appScopesNow,m as liveLookups,I as profileObject,ae as publishLookups,re as readerFor,B as readerForNode,ne as readerForObject,y as viewRepos};
@@ -1,7 +1,6 @@
1
- var p=Object.defineProperty;var i=(e,r)=>p(e,"name",{value:r,configurable:!0});import{randomBytes as l}from"node:crypto";import{nodeInbox as f}from"./kinds/node.js";import{peerReceiver as g}from"../peer/receiver.js";async function T(e,r){const t=await e.prepare("SELECT receiver_json FROM custom_objects WHERE object = ?").get(r.rowid);if(!t?.receiver_json)return;const n=JSON.parse(t.receiver_json);if(n==="queue")return"queue";if(n&&typeof n=="object"&&!Array.isArray(n)){if("url"in n)return"url";if("argv"in n)return"argv"}}i(T,"receiverForObject");const u=1e3,s=new Map;async function y(e,r){const t=s.get(e)??new Set;return t.add(r),s.set(e,t),()=>{t.delete(r),t.size===0&&s.delete(e)}}i(y,"onQueueSignal");function _(e){setImmediate(()=>{for(const r of s.get(e)??[])r()})}i(_,"signalQueue");async function R(e,r){const t=(await e.prepare(`SELECT COUNT(*) AS n FROM deliveries WHERE destination_id = ?
2
- AND state = 'pending' AND canceled_at IS NULL`).get(r)).n;if(t<=u)return;const n=await e.prepare(`SELECT delivery_id, message_id FROM deliveries
1
+ var E=Object.defineProperty;var i=(e,t)=>E(e,"name",{value:t,configurable:!0});import{randomBytes as l}from"node:crypto";import{nodeInbox as f}from"./kinds/node.js";import{peerReceiver as g}from"../peer/receiver.js";async function O(e,t){const r=await e.prepare("SELECT receiver_json FROM custom_objects WHERE object = ?").get(t.id);if(!r?.receiver_json)return;const n=JSON.parse(r.receiver_json);if(n==="queue")return"queue";if(n&&typeof n=="object"&&!Array.isArray(n)){if("url"in n)return"url";if("argv"in n)return"argv"}}i(O,"receiverForObject");const u=1e3,s=new Map;async function T(e,t){const r=s.get(e)??new Set;return r.add(t),s.set(e,r),()=>{r.delete(t),r.size===0&&s.delete(e)}}i(T,"onQueueSignal");function _(e){setImmediate(()=>{for(const t of s.get(e)??[])t()})}i(_,"signalQueue");async function m(e,t){const r=(await e.prepare(`SELECT COUNT(*) AS n FROM deliveries WHERE destination_id = ?
2
+ AND state = 'pending' AND canceled_at IS NULL`).get(t)).n;if(r<=u)return;const n=await e.prepare(`SELECT delivery_id, message_id FROM deliveries
3
3
  WHERE destination_id = ? AND state = 'pending' AND canceled_at IS NULL
4
- ORDER BY created_at, rowid LIMIT ?`).all(r,t-u);for(const a of n)await e.prepare("DELETE FROM deliveries WHERE delivery_id = ?").run(a.delivery_id),await e.prepare("DELETE FROM messages WHERE message_id = ? AND NOT EXISTS (SELECT 1 FROM deliveries WHERE message_id = ?)").run(a.message_id,a.message_id);n.length&&await e.prepare(`UPDATE custom_objects SET dropped = dropped + ? WHERE object =
5
- (SELECT rowid FROM objects WHERE id = ?)`).run(n.length,r)}i(R,"cap");function c(e,r){return{bodyOwner:i(()=>null,"bodyOwner"),async enqueue(t,n,a){const o=Date.now(),E=t.prepare(`INSERT INTO deliveries
4
+ ORDER BY created_at, seq LIMIT ?`).all(t,r-u);for(const a of n)await e.prepare("DELETE FROM deliveries WHERE delivery_id = ?").run(a.delivery_id),await e.prepare("DELETE FROM messages WHERE message_id = ? AND NOT EXISTS (SELECT 1 FROM deliveries WHERE message_id = ?)").run(a.message_id,a.message_id);n.length&&await e.prepare("UPDATE custom_objects SET dropped = dropped + ? WHERE object = ?").run(n.length,t)}i(m,"cap");function c(e,t){return{bodyOwner:i(()=>null,"bodyOwner"),async enqueue(r,n,a){const o=Date.now(),p=r.prepare(`INSERT INTO deliveries
6
5
  (delivery_id, message_id, destination_id, urgency, wake, state, next_attempt_at, created_at, updated_at)
7
- VALUES (?, ?, ?, 'normal', 0, 'pending', ?, ?, ?)`);for(const d of a)await E.run(l(16).toString("hex"),n.messageId,d.id,e?o:null,o,o),await R(t,d.id),r&&_(d.id)}}}i(c,"pushReceiver");const m=c(!0,!1),L={inbox:f,argv:m,url:c(!0,!1),queue:c(!1,!0),peer:g};export{u as BACKLOG_CAP,L as RECEIVERS,m as argvReceiver,y as onQueueSignal,T as receiverForObject,_ as signalQueue};
6
+ VALUES (?, ?, ?, 'normal', 0, 'pending', ?, ?, ?)`);for(const d of a)await p.run(l(16).toString("hex"),n.messageId,d.id,e?o:null,o,o),await m(r,d.id),t&&_(d.id)}}}i(c,"pushReceiver");const v=c(!0,!1),L={inbox:f,argv:v,url:c(!0,!1),queue:c(!1,!0),peer:g};export{u as BACKLOG_CAP,L as RECEIVERS,v as argvReceiver,T as onQueueSignal,O as receiverForObject,_ as signalQueue};