@north-light/cli 0.3.532 → 0.3.533

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 (193) 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 +2 -0
  7. package/dist/builtin-memory/crouter-sdk/release-notes.md +8 -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/node/inspect.js +6 -6
  19. package/dist/commands/sys/context/expose.js +2 -2
  20. package/dist/commands/sys/db.d.ts +1 -0
  21. package/dist/commands/sys/db.js +1 -0
  22. package/dist/commands/sys.js +1 -1
  23. package/dist/core/bash-guard.js +9 -3
  24. package/dist/core/canvas/canvas.d.ts +12 -2
  25. package/dist/core/canvas/canvas.js +23 -20
  26. package/dist/core/canvas/daemon-actions.d.ts +0 -3
  27. package/dist/core/canvas/daemon-actions.js +7 -24
  28. package/dist/core/canvas/daemon-owner.d.ts +3 -0
  29. package/dist/core/canvas/daemon-owner.js +1 -6
  30. package/dist/core/canvas/db.d.ts +28 -20
  31. package/dist/core/canvas/db.js +4 -3
  32. package/dist/core/canvas/deliveries.d.ts +5 -0
  33. package/dist/core/canvas/deliveries.js +25 -30
  34. package/dist/core/canvas/export-sqlite.d.ts +14 -0
  35. package/dist/core/canvas/export-sqlite.js +3 -0
  36. package/dist/core/canvas/import-sqlite.d.ts +44 -0
  37. package/dist/core/canvas/import-sqlite.js +7 -0
  38. package/dist/core/canvas/node-tokens.js +3 -3
  39. package/dist/core/canvas/outcome-actions.js +4 -4
  40. package/dist/core/canvas/recovery.js +1 -1
  41. package/dist/core/canvas/schema-pg.sql +1022 -0
  42. package/dist/core/canvas/schema-version.d.ts +4 -0
  43. package/dist/core/canvas/schema-version.js +1 -0
  44. package/dist/core/canvas/sessions.js +3 -3
  45. package/dist/core/canvas/structured-requests.js +2 -2
  46. package/dist/core/canvas/tree.js +6 -6
  47. package/dist/core/canvas/waits.js +1 -1
  48. package/dist/core/feed/inbox.js +1 -1
  49. package/dist/core/feed/messages.js +5 -5
  50. package/dist/core/feed/reports.js +2 -2
  51. package/dist/core/grants/mirror.js +2 -2
  52. package/dist/core/graph/access.js +7 -7
  53. package/dist/core/graph/custom.js +10 -10
  54. package/dist/core/graph/deletion.js +6 -6
  55. package/dist/core/graph/documents.d.ts +1 -1
  56. package/dist/core/graph/documents.js +9 -9
  57. package/dist/core/graph/edges.d.ts +3 -3
  58. package/dist/core/graph/edges.js +3 -1
  59. package/dist/core/graph/events.js +7 -7
  60. package/dist/core/graph/exposures.d.ts +8 -8
  61. package/dist/core/graph/jobs.d.ts +1 -1
  62. package/dist/core/graph/jobs.js +2 -2
  63. package/dist/core/graph/kinds/custom.js +1 -1
  64. package/dist/core/graph/kinds/document.js +4 -4
  65. package/dist/core/graph/kinds/dto.js +1 -1
  66. package/dist/core/graph/kinds/job.js +2 -2
  67. package/dist/core/graph/kinds/kind.d.ts +2 -2
  68. package/dist/core/graph/kinds/kind.js +1 -1
  69. package/dist/core/graph/kinds/live-read.d.ts +5 -0
  70. package/dist/core/graph/kinds/live-read.js +1 -0
  71. package/dist/core/graph/kinds/node.js +5 -5
  72. package/dist/core/graph/kinds/owner.js +2 -2
  73. package/dist/core/graph/names.js +3 -3
  74. package/dist/core/graph/objects.d.ts +5 -5
  75. package/dist/core/graph/objects.js +10 -10
  76. package/dist/core/graph/package-docs.js +6 -5
  77. package/dist/core/graph/reader.d.ts +1 -1
  78. package/dist/core/graph/reader.js +2 -2
  79. package/dist/core/graph/receivers.js +4 -5
  80. package/dist/core/graph/repo-sync/exchange.js +2 -2
  81. package/dist/core/graph/repo-sync/repos.js +3 -3
  82. package/dist/core/graph/repo-sync/sync.js +1 -1
  83. package/dist/core/graph/rules.d.ts +3 -4
  84. package/dist/core/graph/rules.js +3 -3
  85. package/dist/core/graph/spaces/app.js +1 -1
  86. package/dist/core/graph/spaces/index.d.ts +1 -1
  87. package/dist/core/graph/spaces/index.js +1 -1
  88. package/dist/core/graph/spaces/own-memory.js +1 -1
  89. package/dist/core/graph/spaces/person.js +3 -3
  90. package/dist/core/graph/spaces/repo.d.ts +1 -1
  91. package/dist/core/graph/spaces/repo.js +1 -1
  92. package/dist/core/graph/types.d.ts +4 -3
  93. package/dist/core/graph/watches.d.ts +2 -2
  94. package/dist/core/graph/watches.js +17 -17
  95. package/dist/core/human/page-schema.js +5 -4
  96. package/dist/core/human/requests.d.ts +1 -1
  97. package/dist/core/human/requests.js +20 -23
  98. package/dist/core/peer/ingest.js +1 -1
  99. package/dist/core/peer/receiver.js +1 -1
  100. package/dist/core/peer/stubs.js +1 -1
  101. package/dist/core/providers/receipts.js +3 -2
  102. package/dist/core/review/comments.js +5 -4
  103. package/dist/core/runs/activity.js +4 -5
  104. package/dist/core/runs/confinement.d.ts +1 -1
  105. package/dist/core/runs/confinement.js +2 -2
  106. package/dist/core/runs/events.d.ts +1 -1
  107. package/dist/core/runs/events.js +5 -5
  108. package/dist/core/runs/operations.js +6 -4
  109. package/dist/core/runtime/close.d.ts +3 -0
  110. package/dist/core/runtime/close.js +1 -1
  111. package/dist/core/runtime/host.d.ts +5 -1
  112. package/dist/core/runtime/host.js +3 -3
  113. package/dist/core/runtime/launch.js +2 -2
  114. package/dist/core/runtime/ledger.js +3 -3
  115. package/dist/core/runtime/lifecycle.d.ts +9 -0
  116. package/dist/core/runtime/lifecycle.js +2 -2
  117. package/dist/core/runtime/nodes.d.ts +1 -1
  118. package/dist/core/runtime/nodes.js +1 -1
  119. package/dist/core/runtime/roadmap.js +1 -1
  120. package/dist/core/spaces/stop.d.ts +1 -0
  121. package/dist/core/spaces/stop.js +2 -2
  122. package/dist/core/statements.d.ts +17 -0
  123. package/dist/core/statements.js +2 -0
  124. package/dist/core/substrate/delivery/corpus.js +3 -3
  125. package/dist/core/substrate/delivery/deliver.js +5 -5
  126. package/dist/core/substrate/delivery/listings.js +1 -1
  127. package/dist/core/substrate/delivery/match.d.ts +2 -2
  128. package/dist/core/substrate/delivery/match.js +1 -1
  129. package/dist/core/substrate/delivery/plan.js +3 -3
  130. package/dist/core/substrate/delivery/render-boot.js +5 -5
  131. package/dist/core/substrate/delivery/render-event.js +6 -6
  132. package/dist/core/usage/ledger.js +8 -8
  133. package/dist/daemon/api/bridge.js +4 -4
  134. package/dist/daemon/api/document-listener.js +1 -1
  135. package/dist/daemon/api/handlers/broker-ops.js +1 -1
  136. package/dist/daemon/api/handlers/canvas.js +1 -1
  137. package/dist/daemon/api/handlers/crons.js +1 -1
  138. package/dist/daemon/api/handlers/custom-objects.js +3 -3
  139. package/dist/daemon/api/handlers/docs.js +1 -1
  140. package/dist/daemon/api/handlers/inbox.js +1 -1
  141. package/dist/daemon/api/handlers/memory.js +7 -7
  142. package/dist/daemon/api/handlers/messages.js +1 -1
  143. package/dist/daemon/api/handlers/nodes.js +1 -1
  144. package/dist/daemon/api/handlers/objects.js +3 -3
  145. package/dist/daemon/api/handlers/reviews.js +1 -1
  146. package/dist/daemon/api/handlers/structured-requests.js +1 -1
  147. package/dist/daemon/api/reader.js +1 -1
  148. package/dist/daemon/broker-signals/bus.d.ts +14 -6
  149. package/dist/daemon/broker-signals/bus.js +1 -10
  150. package/dist/daemon/crtrd-cli.js +1 -1
  151. package/dist/daemon/crtrd.js +12 -11
  152. package/dist/daemon/due.js +1 -1
  153. package/dist/daemon/export-sqlite-run.d.ts +1 -0
  154. package/dist/daemon/export-sqlite-run.js +4 -0
  155. package/dist/daemon/fleet.d.ts +1 -0
  156. package/dist/daemon/fleet.js +3 -3
  157. package/dist/daemon/human/settle.js +1 -1
  158. package/dist/daemon/manage.d.ts +10 -0
  159. package/dist/daemon/manage.js +3 -2
  160. package/dist/daemon/postgres/binary.d.ts +17 -0
  161. package/dist/daemon/postgres/binary.js +2 -0
  162. package/dist/daemon/postgres/cluster.d.ts +37 -0
  163. package/dist/daemon/postgres/cluster.js +6 -0
  164. package/dist/daemon/postgres/index.d.ts +2 -0
  165. package/dist/daemon/postgres/index.js +1 -0
  166. package/dist/daemon/postgres/pins.d.ts +7 -0
  167. package/dist/daemon/postgres/pins.js +1 -0
  168. package/dist/daemon/postgres/supervisor.d.ts +95 -0
  169. package/dist/daemon/postgres/supervisor.js +2 -0
  170. package/dist/daemon/reconcilers/bash-deadline.js +2 -2
  171. package/dist/daemon/reconcilers/delivery-lane.js +2 -2
  172. package/dist/daemon/reconcilers/node-lifecycle/freeze-lane.d.ts +7 -3
  173. package/dist/daemon/reconcilers/node-lifecycle/freeze-lane.js +1 -1
  174. package/dist/daemon/reconcilers/node-lifecycle/tick.js +1 -1
  175. package/dist/daemon/reconcilers/storage-maintenance.d.ts +0 -6
  176. package/dist/daemon/reconcilers/storage-maintenance.js +1 -8
  177. package/dist/daemon/runs/observer.js +5 -4
  178. package/dist/migrations/004-canvas-documents/index.js +1 -1
  179. package/dist/pi-extensions/canvas-doc-substrate.d.ts +2 -0
  180. package/dist/pi-extensions/canvas-doc-substrate.js +6 -6
  181. package/dist/pi-extensions/envelope-merge.d.ts +3 -2
  182. package/dist/pi-extensions/envelope-merge.js +9 -8
  183. package/dist/shared/env.d.ts +3 -0
  184. package/dist/shared/env.js +2 -2
  185. package/docs/apps/providers/README.md +2 -0
  186. package/docs/apps/providers/sms.md +2 -0
  187. package/docs/public-api.md +11 -2
  188. package/docs/sdk/release-notes.md +8 -0
  189. package/package.json +6 -6
  190. package/packages/crouter-identity/package.json +1 -1
  191. package/runtime.lock.json +13 -26
  192. package/scripts/install-runtime.mjs +53 -3
  193. package/scripts/lib/isolation-env.mjs +3 -1
@@ -1,2 +1,2 @@
1
- var $=Object.defineProperty;var w=(t,i)=>$(t,"name",{value:i,configurable:!0});import{get as B,put as J}from"../bodies.js";import{setLinks as P,setUnresolved as U}from"../edges.js";import{collectUnlinked as Y,deleteDocument as I,documentRecord as C,heads as x,importDocument as z,insertImportedRevisions as G,moveDocument as K,restoreDocument as V,setDocumentRecord as b}from"../documents.js";import{CrtrError as q}from"../../errors.js";import{publish as D}from"../events.js";import{getById as S,getByRowid as M,setObjectKind as F}from"../objects.js";import{rulesOf as Q}from"../rules.js";import{SPACES as X}from"../spaces/index.js";import{docPath as Z,mergeDoc as ee,parseDoc as g,serializeDoc as A}from"./ref-format.js";import{withCanvasWrite as W}from"../../canvas/db.js";import{mapAsync as j}from"../../async-array.js";function H(t){const i=X[t.type];if(t.owner!==null||!i||i.sync!=="repo-ref")throw new Error(`${t.type} ${t.id} is not a space that syncs through a repo ref`)}w(H,"assertRepoRefSpace");function te(t){const i=new Map;for(const[r,n]of t??[]){const m=g(r,n);m.ok&&i.set(m.doc.id,m.doc)}return i}w(te,"parseMap");async function Oe(t,i,r,n=null){H(i);const m=te(r),p=await t.prepare("SELECT * FROM objects WHERE type = 'document' AND owner = ? AND privacy = 'public' ORDER BY rowid").all(i.rowid),l=t.prepare("SELECT rowid, rev_id, number, body_hash, author, rationale, created_at FROM revisions WHERE document = ? ORDER BY number, rev_id"),h=t.prepare("SELECT p.rev_id FROM revision_parents rp JOIN revisions p ON p.rowid = rp.parent WHERE rp.child = ?"),o=t.prepare(`SELECT e.written_as, o.id FROM edges e JOIN objects o ON o.rowid = e.dst
2
- WHERE e.type = 'links-to' AND e.src = ? ORDER BY e.written_as, o.id`),s=new Map;for(const e of p){const d=await C(t,e),c=new Map((m.get(e.id)?.revisions??[]).map(a=>[a.rev_id,a])),_=new Set((await x(t,e)).map(a=>a.rev_id)),v=(await o.all(e.rowid)).map(a=>({written_as:a.written_as??"",dst:a.id})),E=await j(await l.all(e.rowid),async a=>c.get(a.rev_id)??{rev_id:a.rev_id,number:a.number,parents:(await h.all(a.rowid)).map(R=>R.rev_id),body:B(a.body_hash),body_hash:a.body_hash,author:a.author===null?null:(await M(t,a.author))?.id??null,rationale:a.rationale,created_at:a.created_at,links:_.has(a.rev_id)?v:[]});if(E.length===0)continue;const y=(await Q(t,e)).map(a=>({position:a.position,on:a.on,match:a.match??null,match_frontmatter:a.matchFrontmatter??null,if:a.if??null,deliver:a.deliver})),N={id:e.id,name:e.name,kind:e.kind??"document",privacy:"public",preview:e.preview,summary:d.summary,why_it_exists:d.why_it_exists,unlisted:d.unlisted,lint_ignore:d.lint_ignore,extensions:d.extensions,created_at:e.created_at,deleted_at:e.deleted_at,rules:y,revisions:E};s.set(Z(e.id),A(N))}for(const e of ne(r,n)){const d=r.get(e),c=s.get(e);if(c===void 0){s.set(e,d);continue}const _=g(e,d),v=g(e,c);if(!_.ok){s.set(e,d);continue}if(!v.ok)continue;const E=n?.has(e)?g(e,n.get(e)):null,y=ee(E?.ok?E.doc:null,v.doc,_.doc);y&&s.set(e,A(y))}return s}w(Oe,"exportRepo");function ne(t,i){return[...t??[]].filter(([r,n])=>i?.get(r)!==n).map(([r])=>r)}w(ne,"pendingPaths");function ie(t){return[...t].sort((i,r)=>i.position-r.position).map(i=>({on:i.on,deliver:i.deliver,...i.match!==null&&i.match!==void 0?{match:i.match}:{},...i.match_frontmatter!==null&&i.match_frontmatter!==void 0?{matchFrontmatter:i.match_frontmatter}:{},...i.if!==null&&i.if!==void 0?{if:i.if}:{}}))}w(ie,"toRuleSpecs");const re=w((t,i)=>JSON.stringify(t??null)===JSON.stringify(i??null),"same");function L(t,i){const r={},n=w(m=>!t||!re(t[m],i[m]),"differs");return n("preview")&&(r.preview=i.preview),n("summary")&&(r.summary=i.summary),n("why_it_exists")&&(r.whyItExists=i.why_it_exists),n("unlisted")&&(r.unlisted=i.unlisted),n("lint_ignore")&&(r.lintIgnore=i.lint_ignore),n("extensions")&&(r.extensions=i.extensions),n("rules")&&(r.rules=ie(i.rules)),r}w(L,"changedFields");async function Se(t,i,r,n,m){H(i);const p={created:0,revisions:0,deleted:0,needsMerge:[],refused:[]},l=[];for(const[o,s]of n){if(r.get(o)===s)continue;const e=g(o,s);if(!e.ok){p.refused.push({path:o,reason:e.reason});continue}const d=r.has(o)?g(o,r.get(o)):null;l.push({path:o,prior:d?.ok?d.doc:null,doc:e.doc})}for(const[o,s]of r){if(n.has(o))continue;const e=g(o,s);e.ok&&l.push({path:o,prior:e.doc,doc:null,priorId:e.doc.id})}for(const o of l)for(const s of o.doc?.revisions??[])J(s.body);const h=[];return await W(async()=>{let o=l;for(;;){const s=[];for(const e of o){const d={created:0,revisions:0,deleted:0,needsMerge:[],refused:[]};try{const c=[];await W(async()=>await le(t,i,e.prior,e.doc,e.priorId??e.doc.id,d,m,c),{savepoint:!0}),h.push(...c),p.created+=d.created,p.revisions+=d.revisions,p.deleted+=d.deleted,p.needsMerge.push(...d.needsMerge)}catch(c){ce(c)?s.push({w:e,error:c}):p.refused.push({path:e.path,reason:c.message})}}if(s.length===0)break;if(s.length===o.length){for(const e of s)p.refused.push({path:e.w.path,reason:e.error.message});break}o=s.map(e=>e.w)}await oe(t,n,new Set(h),new Set(l.map(s=>s.path)))},{savepoint:!0}),p}w(Se,"importTree");async function oe(t,i,r,n){if(r.size===0)return;const m=t.prepare("INSERT OR IGNORE INTO edges (type, src, dst, written_as, created_at) VALUES ('links-to', ?, ?, ?, ?)"),p=new Date().toISOString();for(const[l,h]of i){if(!n.has(l)&&!se(h,r))continue;const o=g(l,h);if(!o.ok||o.doc.deleted_at)continue;const s=await S(t,o.doc.id);if(!s||s.type!=="document"||s.deleted_at)continue;const e=(await x(t,s))[0],d=o.doc.revisions.find(c=>c.rev_id===e?.rev_id)?.links??[];for(const c of d){const _=await S(t,c.dst);_&&_.rowid!==s.rowid&&await m.run(s.rowid,_.rowid,c.written_as,p)}}}w(oe,"completeLinks");const ae=/"dst":\s*"((?:[^"\\]|\\.)*)"/g;function se(t,i){for(const r of t.matchAll(ae))if(i.has(de(r[1])))return!0;return!1}w(se,"namesArrived");function de(t){if(!t.includes("\\"))return t;try{return JSON.parse(`"${t}"`)}catch{return t}}w(de,"decodeJsonString");function ce(t){return t instanceof q&&t.code==="conflict"&&t.details?.holder!==void 0}w(ce,"isNameConflict");async function le(t,i,r,n,m,p,l,h){const o=await S(t,m);if(o&&(o.type!=="document"||o.owner!==i.rowid))throw new Error(`id ${m} is held by ${o.type} ${o.name} outside ${i.name}`);if(!n){o&&!o.deleted_at&&(await I(t,null,o,l),p.deleted++);return}const s=t.prepare("SELECT count(*) AS n FROM revisions WHERE document = ?");let e,d=!1,c=!1,_=0,v=0;if(o){e=o,_=(await C(t,e)).revision,e.created_at!==n.created_at&&(await t.prepare("UPDATE objects SET created_at = ? WHERE rowid = ?").run(n.created_at,e.rowid),e=await M(t,e.rowid));const u=n.kind;(r?r.kind!==u:e.kind!==u)&&await F(t,e,u),c=!!e.deleted_at&&n.deleted_at===null&&(r===null||r.deleted_at!=null);let f=L(c?null:r,n);if(n.deleted_at&&e.deleted_at){const{rules:k,...O}=f;f=O}c&&(e=await V(t,e,n.name,l),h?.push(e.id)),Object.keys(f).length>0&&(e=await b(t,null,e,f)),n.name!==e.name&&!e.deleted_at&&(e=await K(t,null,e,{name:n.name},l))}else{const f=n.revisions.filter(k=>k.parents.length===0).sort((k,O)=>k.number-O.number||k.rev_id.localeCompare(O.rev_id))[0];if(!f)throw new Error(`${n.name}: no root revision`);e=await z(t,{id:n.id,owner:i,name:n.name,kind:n.kind,preview:n.preview,privacy:"public",...L(null,n),revisions:[{rev_id:f.rev_id,body_hash:f.body_hash,author:null,rationale:f.rationale,created_at:f.created_at}]},l),e.created_at!==n.created_at&&(await t.prepare("UPDATE objects SET created_at = ? WHERE rowid = ?").run(n.created_at,e.rowid),e=await M(t,e.rowid)),d=!0,h?.push(e.id),v=1}const E=(await s.get(e.rowid)).n,{headCount:y}=await G(t,e,n.revisions.map(u=>({rev_id:u.rev_id,parents:u.parents,body_hash:u.body_hash,rationale:u.rationale,created_at:u.created_at})));v+=(await s.get(e.rowid)).n-E,p.revisions+=v;const a=(await x(t,e))[0],R=new Map(n.revisions.map(u=>[u.rev_id,u]));if(v>0||c){const u=(await j(R.get(a.rev_id)?.links??[],async f=>({written_as:f.written_as,dst:await S(t,f.dst)}))).filter(f=>f.dst!==null);await Y(t,await P(t,e,u),l),await U(t,e,[])}if(y>1&&p.needsMerge.push(e.id),n.deleted_at&&!e.deleted_at){await I(t,null,e,l,n.deleted_at),p.deleted++;return}if(n.deleted_at&&e.deleted_at&&e.deleted_at!==n.deleted_at&&await t.prepare("UPDATE objects SET deleted_at = ? WHERE rowid = ?").run(n.deleted_at,e.rowid),d){p.created++,await D(t,{event:"created",object:e,actor:null,attrs:{revision:a.number},pointer:a.rev_id},l);return}if(c){p.created++,await D(t,{event:"created",object:e,actor:null,attrs:{revision:a.number},pointer:a.rev_id},l);return}if(v===0)return;const T=n.revisions.filter(u=>!r?.revisions.some(f=>f.rev_id===u.rev_id)).sort((u,f)=>f.number-u.number||f.created_at.localeCompare(u.created_at))[0]??R.get(a.rev_id);await D(t,{event:"edited",object:e,actor:null,pointer:a.rev_id,attrs:{revision:a.number,from_revision:_,rationale:T?.rationale??null,author:T?.author??null,heads:y,needs_merge:y>1}},l)}w(le,"importOne");export{Oe as exportRepo,Se as importTree,se as namesArrived,ne as pendingPaths};
1
+ var j=Object.defineProperty;var _=(t,i)=>j(t,"name",{value:i,configurable:!0});import{get as $,put as B}from"../bodies.js";import{setLinks as J,setUnresolved as P}from"../edges.js";import{collectUnlinked as U,deleteDocument as C,documentRecord as I,heads as x,importDocument as Y,insertImportedRevisions as z,moveDocument as b,restoreDocument as q,setDocumentRecord as F}from"../documents.js";import{CrtrError as G}from"../../errors.js";import{publish as D}from"../events.js";import{getById as k,setObjectKind as K}from"../objects.js";import{rulesOf as V}from"../rules.js";import{SPACES as Q}from"../spaces/index.js";import{docPath as X,mergeDoc as Z,parseDoc as g,serializeDoc as M}from"./ref-format.js";import{withCanvasWrite as A}from"../../canvas/db.js";import{mapAsync as H}from"../../async-array.js";function L(t){const i=Q[t.type];if(t.owner!==null||!i||i.sync!=="repo-ref")throw new Error(`${t.type} ${t.id} is not a space that syncs through a repo ref`)}_(L,"assertRepoRefSpace");function ee(t){const i=new Map;for(const[r,n]of t??[]){const m=g(r,n);m.ok&&i.set(m.doc.id,m.doc)}return i}_(ee,"parseMap");async function Oe(t,i,r,n=null){L(i);const m=ee(r),p=await t.prepare("SELECT * FROM objects WHERE type = 'document' AND owner = ? AND privacy = 'public' ORDER BY seq").all(i.id),l=t.prepare("SELECT rev_id, number, body_hash, author, rationale, created_at FROM revisions WHERE document = ? ORDER BY number, rev_id"),w=t.prepare("SELECT p.rev_id FROM revision_parents rp JOIN revisions p ON p.rev_id = rp.parent WHERE rp.child = ?"),a=t.prepare(`SELECT e.written_as, o.id FROM edges e JOIN objects o ON o.id = e.dst
2
+ WHERE e.type = 'links-to' AND e.src = ? ORDER BY e.written_as, o.id`),s=new Map;for(const e of p){const d=await I(t,e),c=new Map((m.get(e.id)?.revisions??[]).map(o=>[o.rev_id,o])),h=new Set((await x(t,e)).map(o=>o.rev_id)),v=(await a.all(e.id)).map(o=>({written_as:o.written_as??"",dst:o.id})),E=await H(await l.all(e.id),async o=>c.get(o.rev_id)??{rev_id:o.rev_id,number:o.number,parents:(await w.all(o.rev_id)).map(R=>R.rev_id),body:$(o.body_hash),body_hash:o.body_hash,author:o.author,rationale:o.rationale,created_at:o.created_at,links:h.has(o.rev_id)?v:[]});if(E.length===0)continue;const y=(await V(t,e)).map(o=>({position:o.position,on:o.on,match:o.match??null,match_frontmatter:o.matchFrontmatter??null,if:o.if??null,deliver:o.deliver})),N={id:e.id,name:e.name,kind:e.kind??"document",privacy:"public",preview:e.preview,summary:d.summary,why_it_exists:d.why_it_exists,unlisted:d.unlisted,lint_ignore:d.lint_ignore,extensions:d.extensions,created_at:e.created_at,deleted_at:e.deleted_at,rules:y,revisions:E};s.set(X(e.id),M(N))}for(const e of te(r,n)){const d=r.get(e),c=s.get(e);if(c===void 0){s.set(e,d);continue}const h=g(e,d),v=g(e,c);if(!h.ok){s.set(e,d);continue}if(!v.ok)continue;const E=n?.has(e)?g(e,n.get(e)):null,y=Z(E?.ok?E.doc:null,v.doc,h.doc);y&&s.set(e,M(y))}return s}_(Oe,"exportRepo");function te(t,i){return[...t??[]].filter(([r,n])=>i?.get(r)!==n).map(([r])=>r)}_(te,"pendingPaths");function ne(t){return[...t].sort((i,r)=>i.position-r.position).map(i=>({on:i.on,deliver:i.deliver,...i.match!==null&&i.match!==void 0?{match:i.match}:{},...i.match_frontmatter!==null&&i.match_frontmatter!==void 0?{matchFrontmatter:i.match_frontmatter}:{},...i.if!==null&&i.if!==void 0?{if:i.if}:{}}))}_(ne,"toRuleSpecs");const ie=_((t,i)=>JSON.stringify(t??null)===JSON.stringify(i??null),"same");function W(t,i){const r={},n=_(m=>!t||!ie(t[m],i[m]),"differs");return n("preview")&&(r.preview=i.preview),n("summary")&&(r.summary=i.summary),n("why_it_exists")&&(r.whyItExists=i.why_it_exists),n("unlisted")&&(r.unlisted=i.unlisted),n("lint_ignore")&&(r.lintIgnore=i.lint_ignore),n("extensions")&&(r.extensions=i.extensions),n("rules")&&(r.rules=ne(i.rules)),r}_(W,"changedFields");async function Re(t,i,r,n,m){L(i);const p={created:0,revisions:0,deleted:0,needsMerge:[],refused:[]},l=[];for(const[a,s]of n){if(r.get(a)===s)continue;const e=g(a,s);if(!e.ok){p.refused.push({path:a,reason:e.reason});continue}const d=r.has(a)?g(a,r.get(a)):null;l.push({path:a,prior:d?.ok?d.doc:null,doc:e.doc})}for(const[a,s]of r){if(n.has(a))continue;const e=g(a,s);e.ok&&l.push({path:a,prior:e.doc,doc:null,priorId:e.doc.id})}for(const a of l)for(const s of a.doc?.revisions??[])B(s.body);const w=[];return await A(async()=>{let a=l;for(;;){const s=[];for(const e of a){const d={created:0,revisions:0,deleted:0,needsMerge:[],refused:[]};try{const c=[];await A(async()=>await ce(t,i,e.prior,e.doc,e.priorId??e.doc.id,d,m,c),{savepoint:!0}),w.push(...c),p.created+=d.created,p.revisions+=d.revisions,p.deleted+=d.deleted,p.needsMerge.push(...d.needsMerge)}catch(c){de(c)?s.push({w:e,error:c}):p.refused.push({path:e.path,reason:c.message})}}if(s.length===0)break;if(s.length===a.length){for(const e of s)p.refused.push({path:e.w.path,reason:e.error.message});break}a=s.map(e=>e.w)}await re(t,n,new Set(w),new Set(l.map(s=>s.path)))},{savepoint:!0}),p}_(Re,"importTree");async function re(t,i,r,n){if(r.size===0)return;const m=t.prepare("INSERT INTO edges (type, src, dst, written_as, created_at) VALUES ('links-to', ?, ?, ?, ?) ON CONFLICT DO NOTHING"),p=new Date().toISOString();for(const[l,w]of i){if(!n.has(l)&&!oe(w,r))continue;const a=g(l,w);if(!a.ok||a.doc.deleted_at)continue;const s=await k(t,a.doc.id);if(!s||s.type!=="document"||s.deleted_at)continue;const e=(await x(t,s))[0],d=a.doc.revisions.find(c=>c.rev_id===e?.rev_id)?.links??[];for(const c of d){const h=await k(t,c.dst);h&&h.id!==s.id&&await m.run(s.id,h.id,c.written_as,p)}}}_(re,"completeLinks");const ae=/"dst":\s*"((?:[^"\\]|\\.)*)"/g;function oe(t,i){for(const r of t.matchAll(ae))if(i.has(se(r[1])))return!0;return!1}_(oe,"namesArrived");function se(t){if(!t.includes("\\"))return t;try{return JSON.parse(`"${t}"`)}catch{return t}}_(se,"decodeJsonString");function de(t){return t instanceof G&&t.code==="conflict"&&t.details?.holder!==void 0}_(de,"isNameConflict");async function ce(t,i,r,n,m,p,l,w){const a=await k(t,m);if(a&&(a.type!=="document"||a.owner!==i.id))throw new Error(`id ${m} is held by ${a.type} ${a.name} outside ${i.name}`);if(!n){a&&!a.deleted_at&&(await C(t,null,a,l),p.deleted++);return}const s=t.prepare("SELECT count(*) AS n FROM revisions WHERE document = ?");let e,d=!1,c=!1,h=0,v=0;if(a){e=a,h=(await I(t,e)).revision,e.created_at!==n.created_at&&(await t.prepare("UPDATE objects SET created_at = ? WHERE id = ?").run(n.created_at,e.id),e=await k(t,e.id));const u=n.kind;(r?r.kind!==u:e.kind!==u)&&await K(t,e,u),c=!!e.deleted_at&&n.deleted_at===null&&(r===null||r.deleted_at!=null);let f=W(c?null:r,n);if(n.deleted_at&&e.deleted_at){const{rules:O,...S}=f;f=S}c&&(e=await q(t,e,n.name,l),w?.push(e.id)),Object.keys(f).length>0&&(e=await F(t,null,e,f)),n.name!==e.name&&!e.deleted_at&&(e=await b(t,null,e,{name:n.name},l))}else{const f=n.revisions.filter(O=>O.parents.length===0).sort((O,S)=>O.number-S.number||O.rev_id.localeCompare(S.rev_id))[0];if(!f)throw new Error(`${n.name}: no root revision`);e=await Y(t,{id:n.id,owner:i,name:n.name,kind:n.kind,preview:n.preview,privacy:"public",...W(null,n),revisions:[{rev_id:f.rev_id,body_hash:f.body_hash,author:null,rationale:f.rationale,created_at:f.created_at}]},l),e.created_at!==n.created_at&&(await t.prepare("UPDATE objects SET created_at = ? WHERE id = ?").run(n.created_at,e.id),e=await k(t,e.id)),d=!0,w?.push(e.id),v=1}const E=(await s.get(e.id)).n,{headCount:y}=await z(t,e,n.revisions.map(u=>({rev_id:u.rev_id,parents:u.parents,body_hash:u.body_hash,rationale:u.rationale,created_at:u.created_at})));v+=(await s.get(e.id)).n-E,p.revisions+=v;const o=(await x(t,e))[0],R=new Map(n.revisions.map(u=>[u.rev_id,u]));if(v>0||c){const u=(await H(R.get(o.rev_id)?.links??[],async f=>({written_as:f.written_as,dst:await k(t,f.dst)}))).filter(f=>f.dst!==null);await U(t,await J(t,e,u),l),await P(t,e,[])}if(y>1&&p.needsMerge.push(e.id),n.deleted_at&&!e.deleted_at){await C(t,null,e,l,n.deleted_at),p.deleted++;return}if(n.deleted_at&&e.deleted_at&&e.deleted_at!==n.deleted_at&&await t.prepare("UPDATE objects SET deleted_at = ? WHERE id = ?").run(n.deleted_at,e.id),d){p.created++,await D(t,{event:"created",object:e,actor:null,attrs:{revision:o.number},pointer:o.rev_id},l);return}if(c){p.created++,await D(t,{event:"created",object:e,actor:null,attrs:{revision:o.number},pointer:o.rev_id},l);return}if(v===0)return;const T=n.revisions.filter(u=>!r?.revisions.some(f=>f.rev_id===u.rev_id)).sort((u,f)=>f.number-u.number||f.created_at.localeCompare(u.created_at))[0]??R.get(o.rev_id);await D(t,{event:"edited",object:e,actor:null,pointer:o.rev_id,attrs:{revision:o.number,from_revision:h,rationale:T?.rationale??null,author:T?.author??null,heads:y,needs_merge:y>1}},l)}_(ce,"importOne");export{Oe as exportRepo,Re as importTree,oe as namesArrived,te as pendingPaths};
@@ -1,3 +1,3 @@
1
- var l=Object.defineProperty;var a=(t,o)=>l(t,"name",{value:o,configurable:!0});import{resolve as c,sep as f}from"node:path";import{CrtrError as u}from"../../errors.js";import{realpathOrSelf as h}from"../../fs-utils.js";import{ExitCode as m}from"../../../types.js";import{ensureOwner as w}from"../objects.js";import{checkoutChain as d,handleHint as E}from"./identity.js";async function x(t,o,r){return await t.prepare(`SELECT o.* FROM identities i JOIN objects o ON o.rowid = i.object
2
- WHERE o.type = 'repo' AND i.scheme = ? AND i.external_id = ?`).get(o,r)??null}a(x,"existingRepo");async function N(t,o,r){const n=await x(t,o.scheme,o.externalId);if(n)return n;const s=r??o.handleHint,p=t.prepare("SELECT 1 FROM objects WHERE name = ? AND type = 'repo' AND home_machine IS NULL");let e=s;for(let i=2;await p.get(e);i++)e=`${s}-${i}`;return await w(t,"repo",o.scheme,o.externalId,e)}a(N,"ensureRepo");async function I(t,o){return(await C(t,o)).map(r=>r.repo)}a(I,"reposForCwd");function L(t){d(h(c(t)))}a(L,"warmCheckoutIdentities");async function C(t,o){const r=h(c(o)),n=[];for(const e of d(r)){if(!e.ok)throw new u("git-lookup-failed",`cannot identify the repo at ${e.dir}: ${e.reason}`,m.GENERAL,{dir:e.dir});n.push({root:e.root,repo:await N(t,e)})}const s=await t.prepare(`SELECT o.*, i.external_id AS path FROM identities i JOIN objects o ON o.rowid = i.object
3
- WHERE o.type = 'repo' AND i.scheme = 'local-path'`).all();for(const{path:e,...i}of s)(r===e||r.startsWith(e.endsWith(f)?e:e+f))&&n.push({root:e,repo:i});n.sort((e,i)=>i.root.length-e.root.length);const p=new Set;return n.filter(({repo:e})=>!p.has(e.rowid)&&(p.add(e.rowid),!0))}a(C,"checkoutsForCwd");export{C as checkoutsForCwd,N as ensureRepo,E as handleHint,I as reposForCwd,L as warmCheckoutIdentities};
1
+ var l=Object.defineProperty;var a=(t,o)=>l(t,"name",{value:o,configurable:!0});import{resolve as c,sep as f}from"node:path";import{CrtrError as u}from"../../errors.js";import{realpathOrSelf as h}from"../../fs-utils.js";import{ExitCode as m}from"../../../types.js";import{ensureOwner as w}from"../objects.js";import{checkoutChain as d,handleHint as E}from"./identity.js";async function x(t,o,r){return await t.prepare(`SELECT o.* FROM identities i JOIN objects o ON o.id = i.object
2
+ WHERE o.type = 'repo' AND i.scheme = ? AND i.external_id = ?`).get(o,r)??null}a(x,"existingRepo");async function N(t,o,r){const n=await x(t,o.scheme,o.externalId);if(n)return n;const s=r??o.handleHint,p=t.prepare("SELECT 1 FROM objects WHERE name = ? AND type = 'repo' AND home_machine IS NULL");let e=s;for(let i=2;await p.get(e);i++)e=`${s}-${i}`;return await w(t,"repo",o.scheme,o.externalId,e)}a(N,"ensureRepo");async function I(t,o){return(await C(t,o)).map(r=>r.repo)}a(I,"reposForCwd");function L(t){d(h(c(t)))}a(L,"warmCheckoutIdentities");async function C(t,o){const r=h(c(o)),n=[];for(const e of d(r)){if(!e.ok)throw new u("git-lookup-failed",`cannot identify the repo at ${e.dir}: ${e.reason}`,m.GENERAL,{dir:e.dir});n.push({root:e.root,repo:await N(t,e)})}const s=await t.prepare(`SELECT o.*, i.external_id AS path FROM identities i JOIN objects o ON o.id = i.object
3
+ WHERE o.type = 'repo' AND i.scheme = 'local-path'`).all();for(const{path:e,...i}of s)(r===e||r.startsWith(e.endsWith(f)?e:e+f))&&n.push({root:e,repo:i});n.sort((e,i)=>i.root.length-e.root.length);const p=new Set;return n.filter(({repo:e})=>!p.has(e.id)&&(p.add(e.id),!0))}a(C,"checkoutsForCwd");export{C as checkoutsForCwd,N as ensureRepo,E as handleHint,I as reposForCwd,L as warmCheckoutIdentities};
@@ -1,2 +1,2 @@
1
- var N=Object.defineProperty;var c=(t,n)=>N(t,"name",{value:n,configurable:!0});import{existsSync as D}from"node:fs";import{readFile as B,writeFile as q}from"node:fs/promises";import{join as R}from"node:path";import{emitEvent as K}from"../../events/emit.js";import{exportRepo as G,importTree as J,pendingPaths as Q}from"./exchange.js";import{checkoutChain as V}from"./identity.js";import{checkoutsForCwd as X,reposForCwd as Y,warmCheckoutIdentities as Z}from"./repos.js";import{commitTree as S,fetchDocs as ee,FIRST_FETCH_MARKER as te,isAncestor as I,mergeBase as ne,openMirror as b,pushDocs as re,readTree as m,remoteDocsTip as ae,resolveRef as h,setRef as y}from"./mirror.js";import{mergeTrees as ie}from"./ref-format.js";import{withCanvasWrite as se}from"../../canvas/db.js";import{filterAsync as oe}from"../../async-array.js";const ce=2e4,L=3,A="remote-url",w="refs/crtr/docs",fe="refs/crtr/remote-docs",g="refs/crtr/imported";function v(t){try{K(t)}catch{}}c(v,"emitEvent");let T=null;const M=new Map,H=new Set;async function Me(t,n){T={lifecycle:t,db:n}}c(Me,"startRepoSync");async function P(t,n){return n.type!=="repo"?!1:await t.prepare("SELECT 1 FROM identities WHERE object = ? AND scheme = 'git'").get(n.rowid)!==void 0}c(P,"gitScheme");async function U(t,n){const e=new Map;for(const f of n)for(const a of V(f))a.ok&&a.scheme==="git"&&e.set(a.externalId,a.remoteUrl);if(e.size===0)return;const r=(await T.db()).prepare("SELECT external_id FROM identities WHERE object = ? AND scheme = 'git'");for(const f of t){const a=await r.get(f.rowid),s=a&&e.get(a.external_id);if(!s)continue;const i=await b(f.id);await q(R(i.dir,A),`${s}
1
+ var N=Object.defineProperty;var c=(t,n)=>N(t,"name",{value:n,configurable:!0});import{existsSync as D}from"node:fs";import{readFile as B,writeFile as q}from"node:fs/promises";import{join as R}from"node:path";import{emitEvent as K}from"../../events/emit.js";import{exportRepo as G,importTree as J,pendingPaths as Q}from"./exchange.js";import{checkoutChain as V}from"./identity.js";import{checkoutsForCwd as X,reposForCwd as Y,warmCheckoutIdentities as Z}from"./repos.js";import{commitTree as S,fetchDocs as ee,FIRST_FETCH_MARKER as te,isAncestor as I,mergeBase as ne,openMirror as b,pushDocs as re,readTree as m,remoteDocsTip as ae,resolveRef as h,setRef as y}from"./mirror.js";import{mergeTrees as ie}from"./ref-format.js";import{withCanvasWrite as se}from"../../canvas/db.js";import{filterAsync as oe}from"../../async-array.js";const ce=2e4,L=3,A="remote-url",w="refs/crtr/docs",fe="refs/crtr/remote-docs",g="refs/crtr/imported";function v(t){try{K(t)}catch{}}c(v,"emitEvent");let T=null;const M=new Map,H=new Set;async function Me(t,n){T={lifecycle:t,db:n}}c(Me,"startRepoSync");async function P(t,n){return n.type!=="repo"?!1:await t.prepare("SELECT 1 FROM identities WHERE object = ? AND scheme = 'git'").get(n.id)!==void 0}c(P,"gitScheme");async function U(t,n){const e=new Map;for(const f of n)for(const a of V(f))a.ok&&a.scheme==="git"&&e.set(a.externalId,a.remoteUrl);if(e.size===0)return;const r=(await T.db()).prepare("SELECT external_id FROM identities WHERE object = ? AND scheme = 'git'");for(const f of t){const a=await r.get(f.id),s=a&&e.get(a.external_id);if(!s)continue;const i=await b(f.id);await q(R(i.dir,A),`${s}
2
2
  `)}}c(U,"recordRemoteUrls");async function de(t,n){const o=await E().db(),r=await oe(t,async i=>await P(o,i));if(r.length===0)return;await U(r,[n]);const f=[];for(const i of r){const l=!H.has(i.id)&&!D(R((await b(i.id)).dir,te)),u=k(i);l&&u&&f.push(u)}if(f.length===0)return;let a;const s=new Promise(i=>{a=setTimeout(i,ce)});await Promise.race([Promise.all(f),s]),clearTimeout(a)}c(de,"noteNodeWorking");async function _e(t){try{const n=await E().db(),e=await n.prepare("SELECT cwd FROM nodes WHERE node_id = ?").get(t);if(!e)return;Z(e.cwd);const o=await se(async()=>await Y(n,e.cwd));o.length>0&&await de(o,e.cwd)}catch(n){v({level:"warn",event:"repo_sync.failed",outcome:"failed",error:n,node_id:t,fields:{step:"fetch",reason:`the boot trigger failed: ${n instanceof Error?n.message:String(n)}`}})}}c(_e,"noteNodeBooting");async function xe(t,n=[]){const e=E();if(!await P(await e.db(),t))return;if(n.length===0){k(t);return}const o=U([t],n).then(()=>{k(t)},r=>{v({level:"error",event:"repo_sync.failed",error:r,fields:{repo:t.name,step:"fetch",reason:"recording the remote URL failed"}})});e.lifecycle.registerDetached(o)}c(xe,"noteRepoDocumentsChanged");function E(){if(!T)throw new Error("repo sync is not started: crtrd must call startRepoSync first");return T}c(E,"requireEngine");function k(t){const n=E(),e=M.get(t.id)??{running:null,again:!1};if(M.set(t.id,e),e.running)return e.again=!0,e.running.then(()=>M.get(t.id)?.running??null).then(r=>r??{ok:!0,pushed:!1,imported:$()});if(!n.lifecycle.acceptsDetachedWork())return null;H.add(t.id);const o=ue(t).then(r=>(W(t,r),r),r=>{const f={ok:!1,step:"export",reason:r instanceof Error?r.message:String(r)};return W(t,f),f}).finally(()=>{e.running=null,e.again&&(e.again=!1,k(t))});return e.running=o,n.lifecycle.registerDetached(o.then(()=>{})),o}c(k,"schedule");function W(t,n){if(n.ok){const e=n.imported;v({level:"info",event:"repo_sync.completed",outcome:"succeeded",fields:{repo:t.name,pushed:n.pushed,created:e.created,revisions:e.revisions,deleted:e.deleted,needs_merge:e.needsMerge,refused:e.refused}})}else v({level:"warn",event:"repo_sync.failed",outcome:"failed",fields:{repo:t.name,step:n.step,reason:n.reason}})}c(W,"report");function $(){return{created:0,revisions:0,deleted:0,needsMerge:[],refused:[]}}c($,"emptyImport");class _ extends Error{static{c(this,"StepError")}step;constructor(n,e){super(e),this.step=n}}async function x(t,n){try{return await n()}catch(e){throw e instanceof _?e:new _(t,e instanceof Error?e.message:String(e))}}c(x,"step");async function ue(t){const n=E();try{const e=await b(t.id),o=await le(e);if(o===null)return{ok:!1,step:"fetch",reason:`no checkout of ${t.name} with an origin remote has been seen by this runtime`};let r=$();const f=c(()=>x("import",async()=>{const a=await h(e,w),s=await h(e,g);if(a===null||s===a)return;const i=s?await m(e,g):new Map,l=await n.db(),u=await m(e,w),d=await J(l,t,i,u,async p=>await X(l,p));r={created:r.created+d.created,revisions:r.revisions+d.revisions,deleted:r.deleted+d.deleted,needsMerge:[...new Set([...r.needsMerge,...d.needsMerge])],refused:[...r.refused,...d.refused]},await j(e,a,u,i,new Set(d.refused.map(p=>p.path)),s)}),"importLocal");await f(),await x("export",async()=>{const a=await h(e,w),s=a?await m(e,w):null,i=await h(e,g),l=i?await m(e,g):null,u=await G(await n.db(),t,s,l);if(a?z(s,u):u.size===0)return;const d=await S(e,u,a?[a]:[],`crtr: export ${t.name}`);await y(e,w,d,a),await j(e,d,u,l??new Map,new Set(Q(s,l)),i)});for(let a=1;;a++){const s=await ae(e,o);if(!s.ok)return{ok:!1,step:"fetch",reason:s.reason};let i=await h(e,w);if(s.value!==null&&!(i&&await we(e,s.value)&&await I(e,s.value,i))){const u=await ee(e,o);if(!u.ok)return{ok:!1,step:"fetch",reason:u.reason};const d=u.value;i=await x("merge",async()=>{if(!i||await I(e,i,d))return await y(e,w,d,i),d;const p=await ne(e,i,d),C=ie(p?await m(e,p):new Map,await m(e,w),await m(e,fe));for(const O of C.refused)r.refused.push(O);const F=await S(e,C.tree,[i,d],`crtr: merge ${t.name}`);return await y(e,w,F,i),F})}if(await f(),i===null||i===s.value)return{ok:!0,pushed:!1,imported:r};const l=await re(e,o,i);if(l.ok)return{ok:!0,pushed:!0,imported:r};if(l.reason!=="rejected")return{ok:!1,step:"push",reason:l.reason};if(a>=L)return{ok:!1,step:"push",reason:`push rejected ${L} times`}}}catch(e){if(e instanceof _)return{ok:!1,step:e.step,reason:e.message};throw e}}c(ue,"syncRepo");async function j(t,n,e,o,r,f){if(r.size===0){await y(t,g,n,f);return}const a=new Map(e);for(const s of r)o.has(s)?a.set(s,o.get(s)):a.delete(s);f!==null&&z(o,a)||await y(t,g,await S(t,a,[],"crtr: imported baseline (some files pending)"),f)}c(j,"advanceImported");async function le(t){const n=R(t.dir,A);return D(n)&&(await B(n,"utf8")).trim()||null}c(le,"readUrl");async function we(t,n){return await h(t,n)!==null}c(we,"hasCommit");function z(t,n){if(t.size!==n.size)return!1;for(const[e,o]of t)if(n.get(e)!==o)return!1;return!0}c(z,"sameTree");export{ce as FIRST_FETCH_WAIT_MS,_e as noteNodeBooting,de as noteNodeWorking,xe as noteRepoDocumentsChanged,Me as startRepoSync,ue as syncRepo};
@@ -5,9 +5,8 @@ import type { ObjectRow, RuleOn, RuleSpec } from './types.js';
5
5
  import type { CanvasDb } from '../canvas/db.js';
6
6
  export declare const RULE_ONS: readonly RuleOn[];
7
7
  export interface RuleRow extends RuleSpec {
8
- rowid: number;
9
- object: number;
10
- owner: number | null;
8
+ object: string;
9
+ owner: string | null;
11
10
  position: number;
12
11
  }
13
12
  /** Replace the document's rules; `position` is the array index, `owner` the document's owner. */
@@ -16,7 +15,7 @@ export declare function replaceRules(db: CanvasDb, object: ObjectRow, specs: rea
16
15
  export declare function setRulesOwner(db: CanvasDb, object: ObjectRow): Promise<void>;
17
16
  export declare function rulesOf(db: CanvasDb, object: ObjectRow): Promise<RuleRow[]>;
18
17
  /** Every rule on one of `on` whose document belongs to one of `owners`. */
19
- export declare function rulesForOwners(db: CanvasDb, on: readonly RuleOn[], owners: readonly number[]): Promise<RuleRow[]>;
18
+ export declare function rulesForOwners(db: CanvasDb, on: readonly RuleOn[], owners: readonly string[]): Promise<RuleRow[]>;
20
19
  /** The only converter from package/legacy frontmatter (`surfaces`, `gate`,
21
20
  * `slash`) to rules. Tolerant like the runtime parser it replaces: invalid
22
21
  * entries are dropped; `lintRules` is the strict check. A document-level
@@ -1,3 +1,3 @@
1
- var O=Object.defineProperty;var d=(e,n)=>O(e,"name",{value:n,configurable:!0});import{forEachAsync as g}from"../async-array.js";const h=["boot","workspace-open","file-read","document-read","command","pre-command","slash-command"],m=["name","preview","content"],y=["file-read","document-read","command","pre-command"],E=["on","match","matchFrontmatter","if","deliver"];function w(e){return{rowid:e.rowid,object:e.object,owner:e.owner,position:e.position,on:e.on_event,deliver:e.deliver,...e.match_json!==null?{match:JSON.parse(e.match_json)}:{},...e.match_frontmatter_json!==null?{matchFrontmatter:JSON.parse(e.match_frontmatter_json)}:{},...e.if_json!==null?{if:JSON.parse(e.if_json)}:{}}}d(w,"fromRaw");async function _(e,n,t){const i=S(t);if(i!==null)throw new Error(`replaceRules(${n.id}): ${i}`);await e.prepare("DELETE FROM rules WHERE object = ?").run(n.rowid);const c=e.prepare(`INSERT INTO rules (object, owner, position, on_event, match_json, match_frontmatter_json, if_json, deliver)
2
- VALUES (?, ?, ?, ?, ?, ?, ?, ?)`);await g(t,async(r,o)=>{await c.run(n.rowid,n.owner,o,r.on,r.match!==void 0?JSON.stringify(r.match):null,r.matchFrontmatter!==void 0?JSON.stringify(r.matchFrontmatter):null,r.if!==void 0?JSON.stringify(r.if):null,r.deliver)})}d(_,"replaceRules");async function v(e,n){const t=await e.prepare("SELECT owner FROM objects WHERE rowid = ?").get(n.rowid);if(t===void 0)throw new Error(`setRulesOwner: object ${n.id} does not exist`);await e.prepare("UPDATE rules SET owner = ? WHERE object = ?").run(t.owner,n.rowid)}d(v,"setRulesOwner");async function $(e,n){return(await e.prepare("SELECT * FROM rules WHERE object = ? ORDER BY position").all(n.rowid)).map(w)}d($,"rulesOf");async function A(e,n,t){if(n.length===0||t.length===0)return[];const i=`SELECT * FROM rules WHERE on_event IN (${n.map(()=>"?").join(",")})
3
- AND owner IN (${t.map(()=>"?").join(",")}) ORDER BY object, position`;return(await e.prepareUncached(i).all(...n,...t)).map(w)}d(A,"rulesForOwners");const R={boot:"boot","workspace-open":"workspace-open",read:"file-read","memory-read":"document-read",command:"command","pre-command":"pre-command"};function s(e){return e!==null&&typeof e=="object"&&!Array.isArray(e)?e:void 0}d(s,"predicate");function j(e){if(typeof e=="string")return e.trim()===""?void 0:[e.trim()];if(!Array.isArray(e))return;const n=e.filter(t=>typeof t=="string"&&t.trim()!=="").map(t=>t.trim());return n.length>0?n:void 0}d(j,"globs");function b(e){const n=s(e.gate),t=d(r=>n!==void 0&&r!==void 0?{all:[n,r]}:n??r,"withGate"),i=[],c=Array.isArray(e.surfaces)?e.surfaces:[];for(const r of c){const o=s(r);if(o===void 0)continue;const a=typeof o.on=="string"?R[o.on]:void 0,u=o.at;if(a===void 0||typeof u!="string"||!m.includes(u))continue;const f=j(o.match),l=a==="file-read"?s(o["match-frontmatter"]):void 0;if(y.includes(a)&&f===void 0&&l===void 0)continue;const p=t(s(o.gate));i.push({on:a,deliver:u,...f!==void 0&&a!=="boot"&&a!=="workspace-open"?{match:f}:{},...l!==void 0?{matchFrontmatter:l}:{},...p!==void 0?{if:p}:{}})}return e.slash===!0&&i.push({on:"slash-command",deliver:"content",...n!==void 0?{if:n}:{}}),i}d(b,"rulesFromFrontmatter");function S(e){if(!Array.isArray(e))return`invalid rules: ${JSON.stringify(e)} (expected a list of {on, deliver, match?, matchFrontmatter?, if?} entries)`;for(const n of e){const t=s(n);if(t===void 0)return`invalid rule: ${JSON.stringify(n)} (expected an {on, deliver, match?, matchFrontmatter?, if?} object)`;for(const a of Object.keys(t))if(!E.includes(a))return`invalid rule: unknown key \`${a}\` (a rule carries only ${E.join(", ")})`;const i=t.on;if(typeof i!="string"||!h.includes(i))return`invalid rule \`on\`: ${JSON.stringify(i)} (expected ${h.join("|")})`;const c=t.deliver;if(typeof c!="string"||!m.includes(c))return`invalid rule \`deliver\`: ${JSON.stringify(c)} (expected ${m.join("|")})`;const r=t.match;if(r!==void 0){if(i==="boot"||i==="workspace-open"||i==="slash-command")return`invalid rule: \`match\` is meaningless on \`${i}\`; drop it`;if(!Array.isArray(r)||r.length===0||r.some(a=>typeof a!="string"||a.trim()===""))return`invalid rule \`match\`: ${JSON.stringify(r)} (expected a non-empty list of non-empty globs)`}const o=t.matchFrontmatter;if(o!==void 0){if(i!=="file-read")return"invalid rule: `matchFrontmatter` applies to `file-read` rules only";if(s(o)===void 0)return`invalid rule \`matchFrontmatter\`: ${JSON.stringify(o)} (expected a field\u2192matcher object)`}if(y.includes(i)&&r===void 0&&o===void 0)return`invalid rule: a \`${i}\` rule requires \`match\`${i==="file-read"?" or `matchFrontmatter`":""}`;if(t.if!==void 0&&s(t.if)===void 0)return`invalid rule \`if\`: ${JSON.stringify(t.if)} (expected a predicate object)`}return null}d(S,"lintRules");export{h as RULE_ONS,S as lintRules,_ as replaceRules,A as rulesForOwners,b as rulesFromFrontmatter,$ as rulesOf,v as setRulesOwner};
1
+ var g=Object.defineProperty;var d=(e,n)=>g(e,"name",{value:n,configurable:!0});import{forEachAsync as R}from"../async-array.js";const h=["boot","workspace-open","file-read","document-read","command","pre-command","slash-command"],m=["name","preview","content"],y=["file-read","document-read","command","pre-command"],E=["on","match","matchFrontmatter","if","deliver"];function O(e){return{object:e.object,owner:e.owner,position:e.position,on:e.on_event,deliver:e.deliver,...e.match_json!==null?{match:JSON.parse(e.match_json)}:{},...e.match_frontmatter_json!==null?{matchFrontmatter:JSON.parse(e.match_frontmatter_json)}:{},...e.if_json!==null?{if:JSON.parse(e.if_json)}:{}}}d(O,"fromRaw");async function _(e,n,t){const i=w(t);if(i!==null)throw new Error(`replaceRules(${n.id}): ${i}`);await e.prepare("DELETE FROM rules WHERE object = ?").run(n.id);const c=e.prepare(`INSERT INTO rules (object, owner, position, on_event, match_json, match_frontmatter_json, if_json, deliver)
2
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)`);await R(t,async(r,o)=>{await c.run(n.id,n.owner,o,r.on,r.match!==void 0?JSON.stringify(r.match):null,r.matchFrontmatter!==void 0?JSON.stringify(r.matchFrontmatter):null,r.if!==void 0?JSON.stringify(r.if):null,r.deliver)})}d(_,"replaceRules");async function v(e,n){const t=await e.prepare("SELECT owner FROM objects WHERE id = ?").get(n.id);if(t===void 0)throw new Error(`setRulesOwner: object ${n.id} does not exist`);await e.prepare("UPDATE rules SET owner = ? WHERE object = ?").run(t.owner,n.id)}d(v,"setRulesOwner");async function $(e,n){return(await e.prepare("SELECT * FROM rules WHERE object = ? ORDER BY position").all(n.id)).map(O)}d($,"rulesOf");async function A(e,n,t){if(n.length===0||t.length===0)return[];const i=`SELECT * FROM rules WHERE on_event IN (${n.map(()=>"?").join(",")})
3
+ AND owner IN (${t.map(()=>"?").join(",")}) ORDER BY object, position`;return(await e.prepareUncached(i).all(...n,...t)).map(O)}d(A,"rulesForOwners");const j={boot:"boot","workspace-open":"workspace-open",read:"file-read","memory-read":"document-read",command:"command","pre-command":"pre-command"};function s(e){return e!==null&&typeof e=="object"&&!Array.isArray(e)?e:void 0}d(s,"predicate");function S(e){if(typeof e=="string")return e.trim()===""?void 0:[e.trim()];if(!Array.isArray(e))return;const n=e.filter(t=>typeof t=="string"&&t.trim()!=="").map(t=>t.trim());return n.length>0?n:void 0}d(S,"globs");function b(e){const n=s(e.gate),t=d(r=>n!==void 0&&r!==void 0?{all:[n,r]}:n??r,"withGate"),i=[],c=Array.isArray(e.surfaces)?e.surfaces:[];for(const r of c){const o=s(r);if(o===void 0)continue;const a=typeof o.on=="string"?j[o.on]:void 0,u=o.at;if(a===void 0||typeof u!="string"||!m.includes(u))continue;const f=S(o.match),l=a==="file-read"?s(o["match-frontmatter"]):void 0;if(y.includes(a)&&f===void 0&&l===void 0)continue;const p=t(s(o.gate));i.push({on:a,deliver:u,...f!==void 0&&a!=="boot"&&a!=="workspace-open"?{match:f}:{},...l!==void 0?{matchFrontmatter:l}:{},...p!==void 0?{if:p}:{}})}return e.slash===!0&&i.push({on:"slash-command",deliver:"content",...n!==void 0?{if:n}:{}}),i}d(b,"rulesFromFrontmatter");function w(e){if(!Array.isArray(e))return`invalid rules: ${JSON.stringify(e)} (expected a list of {on, deliver, match?, matchFrontmatter?, if?} entries)`;for(const n of e){const t=s(n);if(t===void 0)return`invalid rule: ${JSON.stringify(n)} (expected an {on, deliver, match?, matchFrontmatter?, if?} object)`;for(const a of Object.keys(t))if(!E.includes(a))return`invalid rule: unknown key \`${a}\` (a rule carries only ${E.join(", ")})`;const i=t.on;if(typeof i!="string"||!h.includes(i))return`invalid rule \`on\`: ${JSON.stringify(i)} (expected ${h.join("|")})`;const c=t.deliver;if(typeof c!="string"||!m.includes(c))return`invalid rule \`deliver\`: ${JSON.stringify(c)} (expected ${m.join("|")})`;const r=t.match;if(r!==void 0){if(i==="boot"||i==="workspace-open"||i==="slash-command")return`invalid rule: \`match\` is meaningless on \`${i}\`; drop it`;if(!Array.isArray(r)||r.length===0||r.some(a=>typeof a!="string"||a.trim()===""))return`invalid rule \`match\`: ${JSON.stringify(r)} (expected a non-empty list of non-empty globs)`}const o=t.matchFrontmatter;if(o!==void 0){if(i!=="file-read")return"invalid rule: `matchFrontmatter` applies to `file-read` rules only";if(s(o)===void 0)return`invalid rule \`matchFrontmatter\`: ${JSON.stringify(o)} (expected a field\u2192matcher object)`}if(y.includes(i)&&r===void 0&&o===void 0)return`invalid rule: a \`${i}\` rule requires \`match\`${i==="file-read"?" or `matchFrontmatter`":""}`;if(t.if!==void 0&&s(t.if)===void 0)return`invalid rule \`if\`: ${JSON.stringify(t.if)} (expected a predicate object)`}return null}d(w,"lintRules");export{h as RULE_ONS,w as lintRules,_ as replaceRules,A as rulesForOwners,b as rulesFromFrontmatter,$ as rulesOf,v as setRulesOwner};
@@ -1 +1 @@
1
- var S=Object.defineProperty;var l=(o,n)=>S(o,"name",{value:n,configurable:!0});import{covers as r}from"@north-light/identity";import{identityOf as u}from"./index.js";import{memoryScope as a,missingOwnMemoryScope as p}from"./own-memory.js";import{objectPlace as x,runPlace as w,runsSeeEachOther as O}from"../../runs/confinement.js";const M={sync:"runtime",async canRead(o,n,i,t,e){if(n.class==="person"||t.length===0)return!0;if(n.app.rowid===i.rowid)return await m(o,n,t)&&await p(o,n,i,t,e,"read")===null;const s=(await u(o,i)).external_id,c=l(y=>n.scopes!==null&&n.scopes.some(g=>r(g,y)),"held");return t[0].type==="node"?c(`crtr:objects:read:${s}`)||e.type==="document"&&e.kind==="report"&&c(`crtr:conversations:read:${s}`):c(await a(o,s,"read",t))},async canChange(o,n,i,t,e){if(n.class==="person")return!0;if(n.app.rowid===i.rowid)return t.length===0||await m(o,n,t)&&await p(o,n,i,t,e,"rw")===null;if(t.length===0||t[0].type==="node")return!1;const s=await a(o,(await u(o,i)).external_id,"rw",t);return n.scopes!==null&&n.scopes.some(c=>r(c,s))}},f=new WeakMap;async function m(o,n,i){if(n.class==="person"||i.length===0||i[0].type!=="node"||n.class==="app"&&n.place===void 0)return!0;let t=f.get(n);if(t===void 0&&(t=n.class==="app"?n.place:n.class==="node"?await w(n.node.id,o):n.place??await x(n.object.rowid,o),f.set(n,t)),t===null)return!0;const e=await w(i[0].id,o);return e===null?!t.isolated:O(t,e)}l(m,"runConfined");export{M as appSpace};
1
+ var S=Object.defineProperty;var l=(i,n)=>S(i,"name",{value:n,configurable:!0});import{covers as u}from"@north-light/identity";import{identityOf as a}from"./index.js";import{memoryScope as r,missingOwnMemoryScope as p}from"./own-memory.js";import{objectPlace as x,runPlace as f,runsSeeEachOther as O}from"../../runs/confinement.js";const M={sync:"runtime",async canRead(i,n,e,t,o){if(n.class==="person"||t.length===0)return!0;if(n.app.id===e.id)return await w(i,n,t)&&await p(i,n,e,t,o,"read")===null;const s=(await a(i,e)).external_id,c=l(y=>n.scopes!==null&&n.scopes.some(g=>u(g,y)),"held");return t[0].type==="node"?c(`crtr:objects:read:${s}`)||o.type==="document"&&o.kind==="report"&&c(`crtr:conversations:read:${s}`):c(await r(i,s,"read",t))},async canChange(i,n,e,t,o){if(n.class==="person")return!0;if(n.app.id===e.id)return t.length===0||await w(i,n,t)&&await p(i,n,e,t,o,"rw")===null;if(t.length===0||t[0].type==="node")return!1;const s=await r(i,(await a(i,e)).external_id,"rw",t);return n.scopes!==null&&n.scopes.some(c=>u(c,s))}},m=new WeakMap;async function w(i,n,e){if(n.class==="person"||e.length===0||e[0].type!=="node"||n.class==="app"&&n.place===void 0)return!0;let t=m.get(n);if(t===void 0&&(t=n.class==="app"?n.place:n.class==="node"?await f(n.node.id,i):n.place??await x(n.object.id,i),m.set(n,t)),t===null)return!0;const o=await f(e[0].id,i);return o===null?!t.isolated:O(t,o)}l(w,"runConfined");export{M as appSpace};
@@ -1,7 +1,7 @@
1
1
  import type { ObjectRow, Reader } from '../types.js';
2
2
  import type { CanvasDb } from '../../canvas/db.js';
3
3
  export interface IdentityRow {
4
- object: number;
4
+ object: string;
5
5
  scheme: string;
6
6
  external_id: string;
7
7
  }
@@ -1 +1 @@
1
- var p=Object.defineProperty;var t=(r,e)=>p(r,"name",{value:e,configurable:!0});import{appSpace as i}from"./app.js";import{personSpace as n}from"./person.js";import{repoSpace as a}from"./repo.js";const f={person:n,app:i,repo:a};async function E(r,e){const o=await r.prepare("SELECT object, scheme, external_id FROM identities WHERE object = ?").get(e.rowid);if(!o)throw new Error(`${e.type} ${e.id} has no identity`);return o}t(E,"identityOf");export{f as SPACES,E as identityOf};
1
+ var p=Object.defineProperty;var o=(r,e)=>p(r,"name",{value:e,configurable:!0});import{appSpace as i}from"./app.js";import{personSpace as n}from"./person.js";import{repoSpace as a}from"./repo.js";const f={person:n,app:i,repo:a};async function E(r,e){const t=await r.prepare("SELECT object, scheme, external_id FROM identities WHERE object = ?").get(e.id);if(!t)throw new Error(`${e.type} ${e.id} has no identity`);return t}o(E,"identityOf");export{f as SPACES,E as identityOf};
@@ -1 +1 @@
1
- var m=Object.defineProperty;var l=(n,t)=>m(n,"name",{value:t,configurable:!0});import{covers as f}from"@north-light/identity";import{runPlace as s}from"../../runs/confinement.js";const a=l(async(n,t)=>(await n.prepare("SELECT external_id FROM identities WHERE object = ?").get(t.rowid)).external_id,"externalId");async function $(n,t,o,e,r,u){if(t.class==="person"||e.length===0||r!==null&&r.type!=="document")return null;const i=t.launched;if(i==null||u==="read"&&r?.kind==="report"&&e[0].type==="node"&&await y(n,t,e[0].id))return null;const c=await w(n,await a(n,o),u,e);return i.some(p=>f(p,c))?null:c}l($,"missingOwnMemoryScope");async function y(n,t,o){const e=t.class==="node"?await s(t.node.id,n):t.class==="person"?null:t.place??null,r=await s(o,n);return e!==null&&r!==null&&e.run===r.run}l(y,"inReadersRun");function g(n){return n.class==="person"?n:{...n,launched:null}}l(g,"asRuntimeWriter");async function w(n,t,o,e){const r=e[0];return r.type!=="profile"?`crtr:memory:${o}:${t}`:`crtr:memory:${o}:${t}:profile:${await a(n,r)}`}l(w,"memoryScope");export{g as asRuntimeWriter,w as memoryScope,$ as missingOwnMemoryScope};
1
+ var m=Object.defineProperty;var o=(n,t)=>m(n,"name",{value:t,configurable:!0});import{covers as f}from"@north-light/identity";import{runPlace as s}from"../../runs/confinement.js";const a=o(async(n,t)=>(await n.prepare("SELECT external_id FROM identities WHERE object = ?").get(t.id)).external_id,"externalId");async function $(n,t,l,e,r,u){if(t.class==="person"||e.length===0||r!==null&&r.type!=="document")return null;const i=t.launched;if(i==null||u==="read"&&r?.kind==="report"&&e[0].type==="node"&&await y(n,t,e[0].id))return null;const c=await d(n,await a(n,l),u,e);return i.some(p=>f(p,c))?null:c}o($,"missingOwnMemoryScope");async function y(n,t,l){const e=t.class==="node"?await s(t.node.id,n):t.class==="person"?null:t.place??null,r=await s(l,n);return e!==null&&r!==null&&e.run===r.run}o(y,"inReadersRun");function g(n){return n.class==="person"?n:{...n,launched:null}}o(g,"asRuntimeWriter");async function d(n,t,l,e){const r=e[0];return r.type!=="profile"?`crtr:memory:${l}:${t}`:`crtr:memory:${l}:${t}:profile:${await a(n,r)}`}o(d,"memoryScope");export{g as asRuntimeWriter,d as memoryScope,$ as missingOwnMemoryScope};
@@ -1,3 +1,3 @@
1
- import{covers as t}from"@north-light/identity";const f={sync:"runtime",async canRead(a,r,o,s,i){return r.class==="person"||r.class==="object"&&r.owner.rowid===o.rowid?!0:r.scopes===null?!1:r.app.rowid===o.rowid||s.length===0?!0:s[0].type!=="document"?!1:r.scopes.some(n=>t(n,"crtr:memory:manage:user"))||i.privacy==="public"?!0:i.privacy==="private"&&r.scopes.some(n=>t(n,"crtr:memory:read_private:user"))},async canChange(a,r,o,s,i){if(r.class==="person"||r.class==="object"&&r.owner.rowid===o.rowid||r.app.rowid===o.rowid||r.scopes?.some(e=>t(e,"crtr:memory:manage:user")))return!0;if(s.length===0)return r.scopes?.some(e=>t(e,"crtr:memory:rw:user"))??!1;if(s[0].type!=="document")return!1;const n=`crtr:memory:rw:user:${i.name}`;if(r.scopes===null||!r.scopes.some(e=>t(e,n)))return!1;const u=await a.prepare(`SELECT author.type, author.owner AS app FROM revisions r JOIN objects author ON author.rowid = r.author
2
- WHERE r.document = ? ORDER BY r.number, r.created_at LIMIT 1`).get(s[0].rowid);return u?u.type==="person"||u.app===r.app.rowid?!0:(await a.prepare(`SELECT g.resolved_scopes_json FROM grants g JOIN identities i ON i.external_id = g.grantee
3
- WHERE i.object = ? AND i.scheme = 'app'`).all(u.app)).some(({resolved_scopes_json:e})=>JSON.parse(e).some(({scope:c,mode:p})=>p==="always"&&t(c,"crtr:memory:manage:user"))):!1}};export{f as personSpace};
1
+ import{covers as t}from"@north-light/identity";const f={sync:"runtime",async canRead(a,e,n,s,i){return e.class==="person"||e.class==="object"&&e.owner.id===n.id?!0:e.scopes===null?!1:e.app.id===n.id||s.length===0?!0:s[0].type!=="document"?!1:e.scopes.some(o=>t(o,"crtr:memory:manage:user"))||i.privacy==="public"?!0:i.privacy==="private"&&e.scopes.some(o=>t(o,"crtr:memory:read_private:user"))},async canChange(a,e,n,s,i){if(e.class==="person"||e.class==="object"&&e.owner.id===n.id||e.app.id===n.id||e.scopes?.some(r=>t(r,"crtr:memory:manage:user")))return!0;if(s.length===0)return e.scopes?.some(r=>t(r,"crtr:memory:rw:user"))??!1;if(s[0].type!=="document")return!1;const o=`crtr:memory:rw:user:${i.name}`;if(e.scopes===null||!e.scopes.some(r=>t(r,o)))return!1;const u=await a.prepare(`SELECT author.type, author.owner AS app FROM revisions r JOIN objects author ON author.id = r.author
2
+ WHERE r.document = ? ORDER BY r.number, r.created_at LIMIT 1`).get(s[0].id);return u?u.type==="person"||u.app===e.app.id?!0:(await a.prepare(`SELECT g.resolved_scopes_json FROM grants g JOIN identities i ON i.external_id = g.grantee
3
+ WHERE i.object = ? AND i.scheme = 'app'`).all(u.app)).some(({resolved_scopes_json:r})=>JSON.parse(r).some(({scope:c,mode:p})=>p==="always"&&t(c,"crtr:memory:manage:user"))):!1}};export{f as personSpace};
@@ -6,7 +6,7 @@ import type { Space } from './index.js';
6
6
  * directory. A repo's documents change iff its files do. A repo-owned custom object is inside its
7
7
  * own repo. A Mac terminal node reaches every path. */
8
8
  export declare function insideRepo(db: Parameters<Space['canRead']>[0], reader: Reader, repo: {
9
- rowid: number;
9
+ id: string;
10
10
  }, access: 'read' | 'rw'): Promise<boolean>;
11
11
  /** A repo: read and changed by a run with a checkout of it (enclosing its cwd or one of its
12
12
  * profile's project paths) that its file permissions reach (see `insideRepo`). It owns only public documents, so a
@@ -1 +1 @@
1
- var p=Object.defineProperty;var c=(o,t)=>p(o,"name",{value:t,configurable:!0});import{fileRoot as l}from"../../spaces/file-root.js";import{identityOf as u}from"./index.js";async function i(o,t,e,r){if(t.class==="object")return t.repos.some(n=>n.rowid===e.rowid);if(t.class!=="node")return!1;const s=[...t.checkouts,...t.projectCheckouts].filter(n=>n.repo.rowid===e.rowid);if(s.length===0)return!1;const a={app:(await u(o,t.app)).external_id,resolved:t.scopes??[],launched:null};return s.some(n=>"root"in l(a,n.root,r))}c(i,"insideRepo");const m={sync:"repo-ref",async canRead(o,t,e,r){return t.class==="person"||r.length===0?!0:await i(o,t,e,"read")},async canChange(o,t,e,r,s){return s.privacy!=="public"?!1:t.class==="person"?!0:await i(o,t,e,"rw")}};export{i as insideRepo,m as repoSpace};
1
+ var p=Object.defineProperty;var i=(e,t)=>p(e,"name",{value:t,configurable:!0});import{fileRoot as l}from"../../spaces/file-root.js";import{identityOf as u}from"./index.js";async function r(e,t,n,s){if(t.class==="object")return t.repos.some(o=>o.id===n.id);if(t.class!=="node")return!1;const c=[...t.checkouts,...t.projectCheckouts].filter(o=>o.repo.id===n.id);if(c.length===0)return!1;const a={app:(await u(e,t.app)).external_id,resolved:t.scopes??[],launched:null};return c.some(o=>"root"in l(a,o.root,s))}i(r,"insideRepo");const y={sync:"repo-ref",async canRead(e,t,n,s){return t.class==="person"||s.length===0?!0:await r(e,t,n,"read")},async canChange(e,t,n,s,c){return c.privacy!=="public"?!1:t.class==="person"?!0:await r(e,t,n,"rw")}};export{r as insideRepo,y as repoSpace};
@@ -1,12 +1,13 @@
1
1
  /** Shared types of the canvas graph: documents, nodes, jobs and their owners as rows of `objects`. */
2
2
  export type Privacy = 'public' | 'friends' | 'private';
3
3
  export interface ObjectRow {
4
- rowid: number;
5
4
  id: string;
5
+ /** Insertion order: the identity column the object list pages by. */
6
+ seq: number;
6
7
  /** The kind name (`node`, `document`, `job`, an owner kind); the kind registry validates it on create. */
7
8
  type: string;
8
9
  kind: string | null;
9
- owner: number | null;
10
+ owner: string | null;
10
11
  privacy: Privacy;
11
12
  name: string;
12
13
  preview: string;
@@ -105,8 +106,8 @@ export interface RuleSpec {
105
106
  deliver: 'name' | 'preview' | 'content';
106
107
  }
107
108
  export interface Revision {
108
- rowid: number;
109
109
  rev_id: string;
110
+ seq: number;
110
111
  number: number;
111
112
  body_hash: string;
112
113
  /** the author object's id; null for revisions imported from another runtime */
@@ -4,7 +4,7 @@
4
4
  import type { ListenConfig, ObjectRow, Reader, WatchStart } from './types.js';
5
5
  import type { CanvasDb } from '../canvas/db.js';
6
6
  export interface Subscription {
7
- rowid: number;
7
+ subscription_id: string;
8
8
  pattern: string;
9
9
  filter: unknown;
10
10
  config: ListenConfig | null;
@@ -13,7 +13,7 @@ export interface Subscription {
13
13
  created_at: string;
14
14
  }
15
15
  export interface Watch {
16
- rowid: number;
16
+ watch_id: string;
17
17
  watcher: ObjectRow;
18
18
  object: ObjectRow;
19
19
  in_tree: boolean;
@@ -1,19 +1,19 @@
1
- var y=Object.defineProperty;var o=(e,t)=>y(e,"name",{value:t,configurable:!0});import{canRead as O}from"./access.js";import{receiverForObject as T}from"./receivers.js";import{getByRowid as R}from"./objects.js";import{filterAsync as D,mapAsync as j}from"../async-array.js";const _=["spawn","job-start","ask"],I=["report.final","report.result","notice.>"];function S(e){return JSON.stringify(Object.fromEntries(e.map(t=>[String(t.threshold),t.delivery])))}o(S,"configToJson");function A(e){const t=JSON.parse(e);return Object.entries(t).map(([a,n])=>({threshold:Number(a),delivery:n})).sort((a,n)=>n.threshold-a.threshold)}o(A,"configFromJson");async function u(e,t,a){return await e.prepare("SELECT * FROM watches WHERE watcher = ? AND object = ?").get(t.rowid,a.rowid)}o(u,"watchRow");async function E(e,t){return await e.prepare("SELECT * FROM watch_subscriptions WHERE watch = ? ORDER BY rowid").all(t)}o(E,"subsOf");async function l(e,t){const a=await E(e,t);if(a.length===0){await e.prepare("DELETE FROM watches WHERE rowid = ?").run(t);return}const n=a.some(r=>_.includes(r.started_by))?1:0;await e.prepare("UPDATE watches SET in_tree = ? WHERE rowid = ? AND in_tree != ?").run(n,t,n)}o(l,"settle");function C(e,t){return e==="message"?I:t.patterns?.length?t.patterns:[">"]}o(C,"defaultPatterns");async function H(e,t,a,n,r={}){if(n==="fork")throw new Error("recordWatch: fork watches are made by copyWatchesForFork");if(t.type.includes(".")&&!await T(e,t))throw new Error(`custom object ${t.id} has no receiver`);const c=new Date().toISOString();await e.prepare(`INSERT INTO watches (watcher, object, in_tree, read_heads_key, created_at, link_app) VALUES (?, ?, 0, ?, ?, ?)
2
- ON CONFLICT (watcher, object) DO UPDATE SET read_heads_key = COALESCE(excluded.read_heads_key, read_heads_key),
3
- link_app = COALESCE(excluded.link_app, link_app)`).run(t.rowid,a.rowid,r.readHeadsKey??null,c,r.linkApp?.rowid??null);const i=await u(e,t,a),s=n==="message"?r.endsOn??"final":null,h=_.includes(n),w=await E(e,i.rowid),d=e.prepare(`INSERT INTO watch_subscriptions (watch, pattern, filter_json, config_json, started_by, ends_on, created_at)
4
- VALUES (?, ?, ?, ?, ?, ?, ?)`);for(const f of C(n,r))w.some(p=>p.pattern===f&&(p.ends_on===null||p.ends_on===s)&&(!h||_.includes(p.started_by)))||await d.run(i.rowid,f,r.filter===void 0?null:JSON.stringify(r.filter),r.config?S(r.config):null,n,s,c);await l(e,i.rowid)}o(H,"recordWatch");async function M(e,t,a,n){await e.prepare("UPDATE watches SET link_app = ? WHERE watcher = ? AND object = ?").run(n.rowid,t.rowid,a.rowid)}o(M,"markLinkWatch");async function x(e,t,a,n){const r=await u(e,t,a);r&&(n===void 0?await e.prepare("DELETE FROM watch_subscriptions WHERE watch = ?").run(r.rowid):typeof n=="string"?await e.prepare("DELETE FROM watch_subscriptions WHERE watch = ? AND pattern = ?").run(r.rowid,n):await e.prepare("DELETE FROM watch_subscriptions WHERE watch = ? AND started_by = ?").run(r.rowid,n.startedBy),await l(e,r.rowid))}o(x,"unwatch");async function U(e,t,a,n,r){const c=await u(e,t,a),i=c?(await e.prepare("UPDATE watch_subscriptions SET config_json = ? WHERE watch = ? AND pattern = ?").run(r?S(r):null,c.rowid,n)).changes:0;if(Number(i)===0)throw new Error(`${t.id} has no subscription ${n} on ${a.id}`)}o(U,"setSubscriptionConfig");async function J(e,t,a){const n=typeof a=="string"?await e.prepare(`DELETE FROM watch_subscriptions WHERE started_by = 'message'
5
- AND watch IN (SELECT rowid FROM watches WHERE object = ?) RETURNING watch`).all(t.rowid):await e.prepare(`DELETE FROM watch_subscriptions WHERE started_by = 'message' AND ends_on = ?
6
- AND watch IN (SELECT rowid FROM watches WHERE object = ?) RETURNING watch`).all(`result:${a.result}`,t.rowid);for(const r of new Set(n.map(c=>c.watch)))await l(e,r)}o(J,"endMessageSubscriptions");async function g(e,t){const a=await R(e,t.watcher),n=await R(e,t.object);return!a||!n?null:{rowid:t.rowid,watcher:a,object:n,in_tree:t.in_tree===1,read_heads_key:t.read_heads_key,created_at:t.created_at,subscriptions:(await E(e,t.rowid)).map(r=>({rowid:r.rowid,pattern:r.pattern,started_by:r.started_by,ends_on:r.ends_on,created_at:r.created_at,filter:r.filter_json===null?null:JSON.parse(r.filter_json),config:r.config_json===null?null:A(r.config_json)}))}}o(g,"hydrate");async function N(e,t,a){const n=(await j(a,async r=>await g(e,r))).filter(r=>r!==null);return await D(n,async r=>await O(e,t,r.watcher)&&await O(e,t,r.object))}o(N,"visible");async function B(e,t,a){return await N(e,t,await e.prepare("SELECT * FROM watches WHERE watcher = ? ORDER BY rowid").all(a.rowid))}o(B,"watchesOf");async function Y(e,t,a){return await N(e,t,await e.prepare("SELECT * FROM watches WHERE object = ? ORDER BY rowid").all(a.rowid))}o(Y,"watchersOf");async function v(e,t){return(await e.prepare("SELECT o.id FROM watches w JOIN objects o ON o.rowid = w.watcher WHERE w.object = ? ORDER BY w.rowid").all(t.rowid)).map(a=>a.id)}o(v,"watcherIdsOf");async function P(e,t){return await e.prepare(`WITH RECURSIVE walk(rowid) AS (
7
- SELECT ?
1
+ var T=Object.defineProperty;var i=(t,e)=>T(t,"name",{value:e,configurable:!0});import{canRead as R}from"./access.js";import{receiverForObject as j}from"./receivers.js";import{getById as N}from"./objects.js";import{randomUUID as h}from"node:crypto";import{filterAsync as A,mapAsync as D}from"../async-array.js";const f=["spawn","job-start","ask"],b=["report.final","report.result","notice.>"];function S(t){return JSON.stringify(Object.fromEntries(t.map(e=>[String(e.threshold),e.delivery])))}i(S,"configToJson");function I(t){const e=JSON.parse(t);return Object.entries(e).map(([n,r])=>({threshold:Number(n),delivery:r})).sort((n,r)=>r.threshold-n.threshold)}i(I,"configFromJson");async function _(t,e,n){return await t.prepare("SELECT * FROM watches WHERE watcher = ? AND object = ?").get(e.id,n.id)}i(_,"watchRow");async function E(t,e){return await t.prepare("SELECT * FROM watch_subscriptions WHERE watch = ? ORDER BY seq").all(e)}i(E,"subsOf");async function u(t,e){const n=await E(t,e);if(n.length===0){await t.prepare("DELETE FROM watches WHERE watch_id = ?").run(e);return}const r=n.some(a=>f.includes(a.started_by))?1:0;await t.prepare("UPDATE watches SET in_tree = ? WHERE watch_id = ? AND in_tree != ?").run(r,e,r)}i(u,"settle");function m(t,e){return t==="message"?b:e.patterns?.length?e.patterns:[">"]}i(m,"defaultPatterns");async function x(t,e,n,r,a={}){if(r==="fork")throw new Error("recordWatch: fork watches are made by copyWatchesForFork");if(e.type.includes(".")&&!await j(t,e))throw new Error(`custom object ${e.id} has no receiver`);const o=new Date().toISOString();await t.prepare(`INSERT INTO watches (watch_id, watcher, object, in_tree, read_heads_key, created_at, link_app) VALUES (?, ?, ?, 0, ?, ?, ?)
2
+ ON CONFLICT (watcher, object) DO UPDATE SET read_heads_key = COALESCE(excluded.read_heads_key, watches.read_heads_key),
3
+ link_app = COALESCE(excluded.link_app, watches.link_app)`).run(h(),e.id,n.id,a.readHeadsKey??null,o,a.linkApp?.id??null);const c=await _(t,e,n),w=r==="message"?a.endsOn??"final":null,l=f.includes(r),s=await E(t,c.watch_id),d=t.prepare(`INSERT INTO watch_subscriptions (subscription_id, watch, pattern, filter_json, config_json, started_by, ends_on, created_at)
4
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)`);for(const O of m(r,a))s.some(p=>p.pattern===O&&(p.ends_on===null||p.ends_on===w)&&(!l||f.includes(p.started_by)))||await d.run(h(),c.watch_id,O,a.filter===void 0?null:JSON.stringify(a.filter),a.config?S(a.config):null,r,w,o);await u(t,c.watch_id)}i(x,"recordWatch");async function U(t,e,n,r){await t.prepare("UPDATE watches SET link_app = ? WHERE watcher = ? AND object = ?").run(r.id,e.id,n.id)}i(U,"markLinkWatch");async function J(t,e,n,r){const a=await _(t,e,n);a&&(r===void 0?await t.prepare("DELETE FROM watch_subscriptions WHERE watch = ?").run(a.watch_id):typeof r=="string"?await t.prepare("DELETE FROM watch_subscriptions WHERE watch = ? AND pattern = ?").run(a.watch_id,r):await t.prepare("DELETE FROM watch_subscriptions WHERE watch = ? AND started_by = ?").run(a.watch_id,r.startedBy),await u(t,a.watch_id))}i(J,"unwatch");async function v(t,e,n,r,a){const o=await _(t,e,n),c=o?(await t.prepare("UPDATE watch_subscriptions SET config_json = ? WHERE watch = ? AND pattern = ?").run(a?S(a):null,o.watch_id,r)).changes:0;if(Number(c)===0)throw new Error(`${e.id} has no subscription ${r} on ${n.id}`)}i(v,"setSubscriptionConfig");async function B(t,e,n){const r=typeof n=="string"?await t.prepare(`DELETE FROM watch_subscriptions WHERE started_by = 'message'
5
+ AND watch IN (SELECT watch_id FROM watches WHERE object = ?) RETURNING watch`).all(e.id):await t.prepare(`DELETE FROM watch_subscriptions WHERE started_by = 'message' AND ends_on = ?
6
+ AND watch IN (SELECT watch_id FROM watches WHERE object = ?) RETURNING watch`).all(`result:${n.result}`,e.id);for(const a of new Set(r.map(o=>o.watch)))await u(t,a)}i(B,"endMessageSubscriptions");async function g(t,e){const n=await N(t,e.watcher),r=await N(t,e.object);return!n||!r?null:{watch_id:e.watch_id,watcher:n,object:r,in_tree:e.in_tree===1,read_heads_key:e.read_heads_key,created_at:e.created_at,subscriptions:(await E(t,e.watch_id)).map(a=>({subscription_id:a.subscription_id,pattern:a.pattern,started_by:a.started_by,ends_on:a.ends_on,created_at:a.created_at,filter:a.filter_json===null?null:JSON.parse(a.filter_json),config:a.config_json===null?null:I(a.config_json)}))}}i(g,"hydrate");async function y(t,e,n){const r=(await D(n,async a=>await g(t,a))).filter(a=>a!==null);return await A(r,async a=>await R(t,e,a.watcher)&&await R(t,e,a.object))}i(y,"visible");async function P(t,e,n){return await y(t,e,await t.prepare("SELECT * FROM watches WHERE watcher = ? ORDER BY seq").all(n.id))}i(P,"watchesOf");async function V(t,e,n){return await y(t,e,await t.prepare("SELECT * FROM watches WHERE object = ? ORDER BY seq").all(n.id))}i(V,"watchersOf");async function q(t,e){return(await t.prepare("SELECT o.id FROM watches w JOIN objects o ON o.id = w.watcher WHERE w.object = ? ORDER BY w.seq").all(e.id)).map(n=>n.id)}i(q,"watcherIdsOf");async function Y(t,e){return await t.prepare(`WITH RECURSIVE walk(id) AS (
7
+ SELECT CAST(? AS text)
8
8
  UNION
9
- SELECT w.object FROM walk CROSS JOIN watches w INDEXED BY watches_tree_down ON w.watcher = walk.rowid AND w.in_tree = 1
10
- ) SELECT o.* FROM walk CROSS JOIN objects o ON o.rowid = walk.rowid
11
- WHERE o.type = 'node' AND o.rowid != ?`).all(t.rowid,t.rowid)}o(P,"descendants");async function V(e,t){return await e.prepare(`WITH RECURSIVE walk(rowid) AS (
12
- SELECT ?
9
+ SELECT w.object FROM walk JOIN watches w ON w.watcher = walk.id AND w.in_tree = 1
10
+ ) SELECT o.* FROM walk JOIN objects o ON o.id = walk.id
11
+ WHERE o.type = 'node' AND o.id != ?`).all(e.id,e.id)}i(Y,"descendants");async function $(t,e){return await t.prepare(`WITH RECURSIVE walk(id) AS (
12
+ SELECT CAST(? AS text)
13
13
  UNION
14
- SELECT w.watcher FROM walk CROSS JOIN watches w INDEXED BY watches_tree_up ON w.object = walk.rowid AND w.in_tree = 1
15
- ) SELECT o.* FROM walk CROSS JOIN objects o ON o.rowid = walk.rowid
16
- WHERE o.type = 'node' AND o.rowid != ?`).all(t.rowid,t.rowid)}o(V,"ancestors");async function $(e,t){return await e.prepare(`SELECT o.* FROM watches w INDEXED BY watches_tree_up CROSS JOIN objects o ON o.rowid = w.watcher
17
- WHERE w.object = ? AND w.in_tree = 1 ORDER BY w.rowid`).all(t.rowid)}o($,"treeWatchersOf");async function G(e,t,a){const n=new Date().toISOString(),r=await e.prepare("SELECT * FROM watches WHERE watcher = ?").all(t.rowid),c=e.prepare(`INSERT INTO watch_subscriptions (watch, pattern, filter_json, config_json, started_by, ends_on, created_at)
18
- VALUES (?, ?, ?, ?, 'fork', ?, ?)`);for(const i of r){if(i.object===a.rowid)continue;await e.prepare(`INSERT INTO watches (watcher, object, in_tree, read_heads_key, created_at) VALUES (?, ?, 0, ?, ?)
19
- ON CONFLICT (watcher, object) DO NOTHING`).run(a.rowid,i.object,i.read_heads_key,n);const s=await u(e,a,{rowid:i.object}),h=await E(e,s.rowid);for(const w of await E(e,i.rowid))h.some(d=>d.pattern===w.pattern&&d.ends_on===w.ends_on)||await c.run(s.rowid,w.pattern,w.filter_json,w.config_json,w.ends_on,n);await l(e,s.rowid)}}o(G,"copyWatchesForFork");export{V as ancestors,A as configFromJson,S as configToJson,G as copyWatchesForFork,P as descendants,J as endMessageSubscriptions,M as markLinkWatch,H as recordWatch,U as setSubscriptionConfig,$ as treeWatchersOf,x as unwatch,v as watcherIdsOf,Y as watchersOf,B as watchesOf};
14
+ SELECT w.watcher FROM walk JOIN watches w ON w.object = walk.id AND w.in_tree = 1
15
+ ) SELECT o.* FROM walk JOIN objects o ON o.id = walk.id
16
+ WHERE o.type = 'node' AND o.id != ?`).all(e.id,e.id)}i($,"ancestors");async function G(t,e){return await t.prepare(`SELECT o.* FROM watches w JOIN objects o ON o.id = w.watcher
17
+ WHERE w.object = ? AND w.in_tree = 1 ORDER BY w.seq`).all(e.id)}i(G,"treeWatchersOf");async function K(t,e,n){const r=new Date().toISOString(),a=await t.prepare("SELECT * FROM watches WHERE watcher = ?").all(e.id),o=t.prepare(`INSERT INTO watch_subscriptions (subscription_id, watch, pattern, filter_json, config_json, started_by, ends_on, created_at)
18
+ VALUES (?, ?, ?, ?, ?, 'fork', ?, ?)`);for(const c of a){if(c.object===n.id)continue;await t.prepare(`INSERT INTO watches (watch_id, watcher, object, in_tree, read_heads_key, created_at) VALUES (?, ?, ?, 0, ?, ?)
19
+ ON CONFLICT (watcher, object) DO NOTHING`).run(h(),n.id,c.object,c.read_heads_key,r);const w=await _(t,n,{id:c.object}),l=await E(t,w.watch_id);for(const s of await E(t,c.watch_id))l.some(d=>d.pattern===s.pattern&&d.ends_on===s.ends_on)||await o.run(h(),w.watch_id,s.pattern,s.filter_json,s.config_json,s.ends_on,r);await u(t,w.watch_id)}}i(K,"copyWatchesForFork");export{$ as ancestors,I as configFromJson,S as configToJson,K as copyWatchesForFork,Y as descendants,B as endMessageSubscriptions,U as markLinkWatch,x as recordWatch,v as setSubscriptionConfig,G as treeWatchersOf,J as unwatch,q as watcherIdsOf,V as watchersOf,P as watchesOf};
@@ -1,4 +1,5 @@
1
- var O=Object.defineProperty;var l=(t,i)=>O(t,"name",{value:i,configurable:!0});import{z as e}from"zod";import{BUILTIN_PAGE_KINDS as A,productPageComponent as q}from"./page-catalog.js";const P=/^[A-Za-z0-9_-]{1,64}$/,_=e.string().regex(P,{error:"slot id must match /^[A-Za-z0-9_-]{1,64}$/"}),p=e.string().min(1),x=e.enum(["none","single","multi"]),w=e.record(e.string(),e.unknown());function f(t,i,r){const o=new Set;t.forEach((s,d)=>{o.has(s.id)&&i.addIssue({code:"custom",path:[d,"id"],message:`duplicate ${r} id "${s.id}"`}),o.add(s.id)})}l(f,"uniqueIds");const N=e.discriminatedUnion("kind",[e.object({kind:e.literal("option"),optionId:p}).strict(),e.object({kind:e.literal("row"),rowId:p}).strict()]),k=e.object({id:e.string().min(1),anchor:N,text:e.string()}).strict(),L=e.object({id:p,label:e.string().min(1),description:e.string().optional(),recommended:e.boolean().optional()}).strict(),M=e.object({label:e.string().optional(),body:e.string().optional(),options:e.array(L).min(1).superRefine((t,i)=>f(t,i,"option")),mode:e.enum(["single","multi"]),required:e.boolean().optional(),allowFreetext:e.boolean().optional(),freetextLabel:e.string().optional(),freetextPlaceholder:e.string().optional()}).strict().superRefine((t,i)=>{const r=t.options.filter(o=>o.recommended===!0);t.mode==="single"&&r.length>1&&i.addIssue({code:"custom",path:["options"],message:`a mode="single" question may recommend at most one option, but ${r.length} are marked recommended (${r.map(o=>o.id).join(", ")}); keep one, or use mode="multi" to recommend several`})}),S=e.object({selectedOptionIds:e.array(p),comments:e.array(k),freetext:e.string().optional()}).strict(),T=e.object({label:e.string().optional(),initialText:e.string(),placeholder:e.string().optional(),singleLine:e.boolean().optional(),required:e.boolean().optional()}).strict(),E=e.object({text:e.string(),edited:e.boolean()}).strict(),F=e.object({id:p,label:e.string().min(1),align:e.enum(["left","right"]).optional(),mono:e.boolean().optional()}).strict(),D=e.union([e.string(),e.number(),e.boolean(),e.null()]),B=e.object({id:p,cells:e.record(e.string(),D)}).strict(),G=e.array(B).superRefine((t,i)=>f(t,i,"row")),U={label:e.string().optional(),body:e.string().optional(),columns:e.array(F).min(1).superRefine((t,i)=>f(t,i,"column")),rows:G.optional(),rowSelect:x.default("none"),columnSelect:x.default("none"),required:e.boolean().optional()},z=e.object(U).strict(),I=e.object({selectedRowIds:e.array(p),selectedColumnIds:e.array(p),comments:e.array(k)}).strict(),H=e.object({id:p,title:e.string().min(1),subtitle:e.string().optional(),body:e.string().optional(),tag:e.string().optional()}).strict(),Z=e.array(H).superRefine((t,i)=>f(t,i,"card")),K={label:e.string().optional(),body:e.string().optional(),cards:Z.optional(),mode:e.enum(["single","multi"]),columns:e.union([e.literal(2),e.literal(3)]).optional(),required:e.boolean().optional()},W=e.object(K).strict(),y=e.object({selectedCardIds:e.array(p)}).strict(),X=e.object({field:e.string().min(1),label:e.string().optional()}).strict(),J=e.array(e.record(e.string(),e.unknown())),Q={kind:e.enum(["line","bar","area"]),x:e.string().min(1),y:e.array(X).min(1),title:e.string().optional(),data:J.optional()},V=e.object(Q).strict(),Y=e.object({sessionName:e.string().optional(),askedBy:e.string().optional(),emittedAt:e.string().datetime({offset:!0}).optional(),profileName:e.string().optional(),nodeId:e.string().optional()}).strict(),ee=e.object({placement:e.enum(["inline","panel"]),inbox:e.boolean(),reply:e.boolean()}).strict(),te=e.object({id:_.optional(),kind:e.string().min(1),step:e.number().int().nonnegative(),config:w,unvalidated:e.literal(!0).optional(),display:e.literal(!0).optional()}).strict(),ne=e.object({schema:e.literal("crtr.page/v2"),dialect:e.enum(["jsx","html"]),title:e.string().trim().min(1),subtitle:e.string().optional(),delivery:ee,document:e.enum(["page.tsx","page.html"]),steps:e.number().int().positive(),slots:e.array(te),source:Y.optional()}).strict().superRefine((t,i)=>{t.dialect==="jsx"!=(t.document==="page.tsx")&&i.addIssue({code:"custom",path:["document"],message:"document must agree with dialect"}),t.dialect==="html"&&(t.steps!==1||t.slots.length!==0)&&i.addIssue({code:"custom",path:["slots"],message:"HTML pages have exactly one step and no slots"})}),oe={options:M,text:T,table:z,cards:W,chart:V},le={options:S,text:E,table:I,cards:y};function m(t){return t.issues.map(i=>`${i.path.length===0?"value":i.path.join(".")}: ${i.message}`).join("; ")}l(m,"issueText");function pe(t){const i=[];for(const d of t.slots){if(d.kind!=="options"||d.id===void 0)continue;const n=d.config,a=n.options.filter(c=>c.recommended===!0);for(const c of n.mode==="multi"?a:a.slice(0,1))i.push({slotId:d.id,optionId:c.id,label:c.label})}if(t.delivery.placement!=="panel")return{recommendedOptions:i};const r=t.slots.filter(g);if(r.length===0)return{recommendedOptions:i,fastAction:{kind:"acknowledge",responses:{}}};if(r.length>1)return{recommendedOptions:i};const o=r[0],s=i.filter(d=>d.slotId===o.id);return o.kind!=="options"||s.length===0?{recommendedOptions:i}:{recommendedOptions:i,fastAction:{kind:"answer",responses:{[o.id]:{selectedOptionIds:s.map(d=>d.optionId),comments:[]}}}}}l(pe,"pageOverviewActions");function ue(t){return t.delivery.reply||t.slots.some(g)}l(ue,"pageAwaitsResponse");function g(t){if(t.display===!0)return!1;if(t.unvalidated===!0||t.kind==="options"||t.kind==="text"||t.kind==="cards")return!0;if(t.kind!=="table")return!1;const i=t.config;return(i.rowSelect??"none")!=="none"||(i.columnSelect??"none")!=="none"}l(g,"isResponseBearingSlot");const me=l(t=>`(json_valid(${t}) AND COALESCE(json_extract(${t}, '$.delivery.reply'), 0) = 0
2
- AND NOT EXISTS (SELECT 1 FROM json_each(${t}, '$.slots') s WHERE COALESCE(json_extract(s.value, '$.display'), 0) <> 1
3
- AND (COALESCE(json_extract(s.value, '$.unvalidated'), 0) = 1 OR json_extract(s.value, '$.kind') IN ('options', 'text', 'cards')
4
- OR (json_extract(s.value, '$.kind') = 'table' AND (COALESCE(json_extract(s.value, '$.config.rowSelect'), 'none') <> 'none' OR COALESCE(json_extract(s.value, '$.config.columnSelect'), 'none') <> 'none')))))`,"pageIsNoticeSql");function v(t,i,r){const o=ne.parse(t);if(!r&&o.dialect==="html")return o;const s=new Set,d=o.slots.map((n,a)=>{if(n.step>=o.steps)throw new Error(`slot ${n.id===void 0?`#${a}`:`"${n.id}"`} has step ${n.step}, outside page steps ${o.steps}`);let c;if(A.includes(n.kind)){if(n.unvalidated===!0)throw new Error(`built-in slot kind "${n.kind}" cannot be unvalidated`);if(n.display===!0)throw new Error(`built-in slot kind "${n.kind}" cannot set display: true`);const u=oe[n.kind].safeParse(n.config);if(!u.success)throw new Error(`invalid config for slot ${n.id===void 0?`#${a}`:`"${n.id}"`} (${n.kind}): ${m(u.error)}`);if(r&&n.kind==="options"){const b=u.data,$=n.id===void 0?`#${a}`:`"${n.id}"`;if((b.label??"").trim()==="")throw new Error(`slot ${$} (options): label is required \u2014 the question itself, drawn as the bold first line`);if((b.body??"").trim()==="")throw new Error(`slot ${$} (options): body is required \u2014 the context under the question a label cannot carry`)}c={...n.id===void 0?{}:{id:n.id},kind:n.kind,step:n.step,config:u.data}}else{const u=i===void 0?void 0:q(n.kind,i);if(r&&u===void 0)throw new Error(`unregistered page slot kind "${n.kind}" at slot #${a}`);if(n.unvalidated!==!0)throw new Error(`registered page slot kind "${n.kind}" must set unvalidated: true`);if(!r)c={...n.id===void 0?{}:{id:n.id},kind:n.kind,step:n.step,config:n.config,unvalidated:!0,...n.display===!0?{display:!0}:{}};else{if(n.display===!0&&u?.display!==!0)throw new Error(`non-display page slot kind "${n.kind}" cannot set display: true`);c={...n.id===void 0?{}:{id:n.id},kind:n.kind,step:n.step,config:n.config,unvalidated:!0,...u?.display===!0?{display:!0}:{}}}}if(g(c)&&c.id===void 0)throw new Error(c.unvalidated===!0?`product slot kind "${c.kind}" at slot #${a} requires an id prop`:`response-bearing slot kind "${c.kind}" at slot #${a} requires an id prop`);if(c.id!==void 0){if(s.has(c.id))throw new Error(`duplicate slot id "${c.id}"`);s.add(c.id)}return c});return{...o,slots:d}}l(v,"validateManifest");function j(t){return v(t,void 0,!1)}l(j,"validatePageManifest");function fe(t,i=[]){return v(t,i,!0)}l(fe,"validateAuthoredPageManifest");function ie(){return e.custom(t=>{try{return j(t),!0}catch{return!1}},{error:"invalid page manifest"}).transform(t=>j(t))}l(ie,"createPageManifestSchema");const ge=ie();function h(t,i,r){if(new Set(t).size!==t.length)throw new Error(`slot "${i}" has duplicate id in ${r}`)}l(h,"assertUnique");function C(t,i){const r=t.config;for(const o of i){const s=o.anchor;if(t.kind==="options"&&s.kind==="option"){if(!r.options.some(d=>d.id===s.optionId))throw new Error(`slot "${t.id}" comment names unknown option id "${s.optionId}"`);continue}if(t.kind==="table"&&s.kind==="row"){if(!(r.rows??[]).some(d=>d.id===s.rowId))throw new Error(`slot "${t.id}" comment names unknown row id "${s.rowId}"`);continue}throw new Error(`slot "${t.id}" does not allow comment anchor kind "${s.kind}"`)}}l(C,"validateComments");function se(t){return t.required??t.mode==="single"}l(se,"optionsRequired");function re(t,i){if(t.unvalidated===!0){const r=w.safeParse(i);if(!r.success)throw new Error(`response for unvalidated slot "${t.id}" must be an object`);return r.data}if(t.kind==="options"){const r=S.safeParse(i);if(!r.success)throw new Error(`invalid response for slot "${t.id}": ${m(r.error)}`);const o=r.data,s=t.config;h(o.selectedOptionIds,t.id,"selectedOptionIds");for(const n of o.selectedOptionIds)if(!s.options.some(a=>a.id===n))throw new Error(`slot "${t.id}" selects unknown option id "${n}"`);if(o.freetext!==void 0&&s.allowFreetext!==!0)throw new Error(`slot "${t.id}" does not allow freetext`);if(s.mode==="single"&&o.selectedOptionIds.length>1)throw new Error(`slot "${t.id}" is single-select but received ${o.selectedOptionIds.length} option ids`);const d=s.allowFreetext===!0&&(o.freetext?.trim()??"")!=="";if(se(s)){if(s.mode==="single"&&o.selectedOptionIds.length!==1&&!d)throw new Error(`single-select slot "${t.id}" requires exactly one selection or nonempty allowed freetext`);if(s.mode==="multi"&&o.selectedOptionIds.length===0&&o.comments.length===0&&!d)throw new Error(`multi-select slot "${t.id}" requires a selection, comment, or nonempty allowed freetext`)}return C(t,o.comments),o}if(t.kind==="text"){const r=E.safeParse(i);if(!r.success)throw new Error(`invalid response for slot "${t.id}": ${m(r.error)}`);if(t.config.required===!0&&r.data.text.trim()==="")throw new Error(`slot "${t.id}" is required and was left empty`);return r.data}if(t.kind==="table"){const r=I.safeParse(i);if(!r.success)throw new Error(`invalid response for slot "${t.id}": ${m(r.error)}`);const o=r.data,s=t.config;h(o.selectedRowIds,t.id,"selectedRowIds"),h(o.selectedColumnIds,t.id,"selectedColumnIds");const d=new Set((s.rows??[]).map(a=>a.id)),n=new Set(s.columns.map(a=>a.id));for(const a of o.selectedRowIds)if(!d.has(a))throw new Error(`slot "${t.id}" selects unknown row id "${a}"`);for(const a of o.selectedColumnIds)if(!n.has(a))throw new Error(`slot "${t.id}" selects unknown column id "${a}"`);if(s.required===!0&&o.selectedRowIds.length===0&&o.selectedColumnIds.length===0)throw new Error(`slot "${t.id}" is required and nothing is selected`);if(s.rowSelect==="none"&&o.selectedRowIds.length>0||s.rowSelect==="single"&&o.selectedRowIds.length>1)throw new Error(`slot "${t.id}" response violates row select mode "${s.rowSelect}"`);if(s.columnSelect==="none"&&o.selectedColumnIds.length>0||s.columnSelect==="single"&&o.selectedColumnIds.length>1)throw new Error(`slot "${t.id}" response violates column select mode "${s.columnSelect}"`);return C(t,o.comments),o}if(t.kind==="cards"){const r=y.safeParse(i);if(!r.success)throw new Error(`invalid response for slot "${t.id}": ${m(r.error)}`);const o=r.data,s=t.config;h(o.selectedCardIds,t.id,"selectedCardIds");for(const d of o.selectedCardIds)if(!(s.cards??[]).some(n=>n.id===d))throw new Error(`slot "${t.id}" selects unknown card id "${d}"`);if(s.mode==="single"&&o.selectedCardIds.length>1)throw new Error(`slot "${t.id}" is single-select but received ${o.selectedCardIds.length} card ids`);if(s.required===!0&&o.selectedCardIds.length===0)throw new Error(`slot "${t.id}" is required and nothing is selected`);return o}throw new Error(`slot "${t.id}" kind "${t.kind}" does not accept a response`)}l(re,"parseResponse");function R(t,i,r){const o=w.safeParse(i);if(!o.success)throw new Error("page responses must be an object keyed by slot id");const s=new Map(t.slots.filter(g).map(n=>[n.id,n])),d={};for(const[n,a]of Object.entries(o.data)){const c=s.get(n);if(c===void 0)throw new Error(`response names unknown or non-response-bearing slot id "${n}"`);d[n]=re(c,a)}if(!r){for(const n of s.keys())if(!(n in d))throw new Error(`final page response is missing response-bearing slot id "${n}"`)}return d}l(R,"validateResponses");function he(t,i){return R(t,i,!1)}l(he,"validatePageResponses");function we(t,i){return R(t,i,!0)}l(we,"validatePartialPageResponses");export{oe as BUILTIN_PAGE_CONFIG_SCHEMAS,le as BUILTIN_PAGE_RESPONSE_SCHEMAS,P as PAGE_SLOT_ID_PATTERN,H as cardSchema,W as cardsConfigSchema,y as cardsResponseSchema,Z as cardsSchema,V as chartConfigSchema,J as chartDataRowsSchema,X as chartSeriesSchema,k as commentSchema,ie as createPageManifestSchema,g as isResponseBearingSlot,m as issueText,L as optionSchema,M as optionsConfigSchema,se as optionsRequired,S as optionsResponseSchema,ue as pageAwaitsResponse,N as pageCommentAnchorSchema,ee as pageDeliverySchema,me as pageIsNoticeSql,ge as pageManifestSchema,pe as pageOverviewActions,D as tableCellSchema,F as tableColumnSchema,z as tableConfigSchema,I as tableResponseSchema,B as tableRowSchema,G as tableRowsSchema,T as textConfigSchema,E as textResponseSchema,fe as validateAuthoredPageManifest,j as validatePageManifest,he as validatePageResponses,we as validatePartialPageResponses};
1
+ var A=Object.defineProperty;var c=(t,i)=>A(t,"name",{value:i,configurable:!0});import{z as e}from"zod";import{BUILTIN_PAGE_KINDS as O,productPageComponent as q}from"./page-catalog.js";const P=/^[A-Za-z0-9_-]{1,64}$/,N=e.string().regex(P,{error:"slot id must match /^[A-Za-z0-9_-]{1,64}$/"}),p=e.string().min(1),S=e.enum(["none","single","multi"]),w=e.record(e.string(),e.unknown());function m(t,i,r){const o=new Set;t.forEach((s,d)=>{o.has(s.id)&&i.addIssue({code:"custom",path:[d,"id"],message:`duplicate ${r} id "${s.id}"`}),o.add(s.id)})}c(m,"uniqueIds");const _=e.discriminatedUnion("kind",[e.object({kind:e.literal("option"),optionId:p}).strict(),e.object({kind:e.literal("row"),rowId:p}).strict()]),E=e.object({id:e.string().min(1),anchor:_,text:e.string()}).strict(),L=e.object({id:p,label:e.string().min(1),description:e.string().optional(),recommended:e.boolean().optional()}).strict(),T=e.object({label:e.string().optional(),body:e.string().optional(),options:e.array(L).min(1).superRefine((t,i)=>m(t,i,"option")),mode:e.enum(["single","multi"]),required:e.boolean().optional(),allowFreetext:e.boolean().optional(),freetextLabel:e.string().optional(),freetextPlaceholder:e.string().optional()}).strict().superRefine((t,i)=>{const r=t.options.filter(o=>o.recommended===!0);t.mode==="single"&&r.length>1&&i.addIssue({code:"custom",path:["options"],message:`a mode="single" question may recommend at most one option, but ${r.length} are marked recommended (${r.map(o=>o.id).join(", ")}); keep one, or use mode="multi" to recommend several`})}),k=e.object({selectedOptionIds:e.array(p),comments:e.array(E),freetext:e.string().optional()}).strict(),M=e.object({label:e.string().optional(),initialText:e.string(),placeholder:e.string().optional(),singleLine:e.boolean().optional(),required:e.boolean().optional()}).strict(),x=e.object({text:e.string(),edited:e.boolean()}).strict(),F=e.object({id:p,label:e.string().min(1),align:e.enum(["left","right"]).optional(),mono:e.boolean().optional()}).strict(),D=e.union([e.string(),e.number(),e.boolean(),e.null()]),H=e.object({id:p,cells:e.record(e.string(),D)}).strict(),B=e.array(H).superRefine((t,i)=>m(t,i,"row")),G={label:e.string().optional(),body:e.string().optional(),columns:e.array(F).min(1).superRefine((t,i)=>m(t,i,"column")),rows:B.optional(),rowSelect:S.default("none"),columnSelect:S.default("none"),required:e.boolean().optional()},U=e.object(G).strict(),I=e.object({selectedRowIds:e.array(p),selectedColumnIds:e.array(p),comments:e.array(E)}).strict(),z=e.object({id:p,title:e.string().min(1),subtitle:e.string().optional(),body:e.string().optional(),tag:e.string().optional()}).strict(),W=e.array(z).superRefine((t,i)=>m(t,i,"card")),Z={label:e.string().optional(),body:e.string().optional(),cards:W.optional(),mode:e.enum(["single","multi"]),columns:e.union([e.literal(2),e.literal(3)]).optional(),required:e.boolean().optional()},K=e.object(Z).strict(),y=e.object({selectedCardIds:e.array(p)}).strict(),X=e.object({field:e.string().min(1),label:e.string().optional()}).strict(),J=e.array(e.record(e.string(),e.unknown())),Q={kind:e.enum(["line","bar","area"]),x:e.string().min(1),y:e.array(X).min(1),title:e.string().optional(),data:J.optional()},V=e.object(Q).strict(),Y=e.object({sessionName:e.string().optional(),askedBy:e.string().optional(),emittedAt:e.string().datetime({offset:!0}).optional(),profileName:e.string().optional(),nodeId:e.string().optional()}).strict(),ee=e.object({placement:e.enum(["inline","panel"]),inbox:e.boolean(),reply:e.boolean()}).strict(),te=e.object({id:N.optional(),kind:e.string().min(1),step:e.number().int().nonnegative(),config:w,unvalidated:e.literal(!0).optional(),display:e.literal(!0).optional()}).strict(),ne=e.object({schema:e.literal("crtr.page/v2"),dialect:e.enum(["jsx","html"]),title:e.string().trim().min(1),subtitle:e.string().optional(),delivery:ee,document:e.enum(["page.tsx","page.html"]),steps:e.number().int().positive(),slots:e.array(te),source:Y.optional()}).strict().superRefine((t,i)=>{t.dialect==="jsx"!=(t.document==="page.tsx")&&i.addIssue({code:"custom",path:["document"],message:"document must agree with dialect"}),t.dialect==="html"&&(t.steps!==1||t.slots.length!==0)&&i.addIssue({code:"custom",path:["slots"],message:"HTML pages have exactly one step and no slots"})}),oe={options:T,text:M,table:U,cards:K,chart:V},ce={options:k,text:x,table:I,cards:y};function f(t){return t.issues.map(i=>`${i.path.length===0?"value":i.path.join(".")}: ${i.message}`).join("; ")}c(f,"issueText");function pe(t){const i=[];for(const d of t.slots){if(d.kind!=="options"||d.id===void 0)continue;const n=d.config,a=n.options.filter(l=>l.recommended===!0);for(const l of n.mode==="multi"?a:a.slice(0,1))i.push({slotId:d.id,optionId:l.id,label:l.label})}if(t.delivery.placement!=="panel")return{recommendedOptions:i};const r=t.slots.filter(g);if(r.length===0)return{recommendedOptions:i,fastAction:{kind:"acknowledge",responses:{}}};if(r.length>1)return{recommendedOptions:i};const o=r[0],s=i.filter(d=>d.slotId===o.id);return o.kind!=="options"||s.length===0?{recommendedOptions:i}:{recommendedOptions:i,fastAction:{kind:"answer",responses:{[o.id]:{selectedOptionIds:s.map(d=>d.optionId),comments:[]}}}}}c(pe,"pageOverviewActions");function ue(t){return t.delivery.reply||t.slots.some(g)}c(ue,"pageAwaitsResponse");function g(t){if(t.display===!0)return!1;if(t.unvalidated===!0||t.kind==="options"||t.kind==="text"||t.kind==="cards")return!0;if(t.kind!=="table")return!1;const i=t.config;return(i.rowSelect??"none")!=="none"||(i.columnSelect??"none")!=="none"}c(g,"isResponseBearingSlot");const fe=c(t=>`(COALESCE(${t} #>> '{delivery,reply}', 'false') = 'false'
2
+ AND NOT EXISTS (SELECT 1 FROM jsonb_array_elements(CASE WHEN jsonb_typeof(${t} -> 'slots') = 'array' THEN ${t} -> 'slots' ELSE '[]'::jsonb END) AS s(value)
3
+ WHERE COALESCE(s.value ->> 'display', 'false') <> 'true'
4
+ AND (COALESCE(s.value ->> 'unvalidated', 'false') = 'true' OR s.value ->> 'kind' IN ('options', 'text', 'cards')
5
+ OR (s.value ->> 'kind' = 'table' AND (COALESCE(s.value #>> '{config,rowSelect}', 'none') <> 'none' OR COALESCE(s.value #>> '{config,columnSelect}', 'none') <> 'none')))))`,"pageIsNoticeSql");function v(t,i,r){const o=ne.parse(t);if(!r&&o.dialect==="html")return o;const s=new Set,d=o.slots.map((n,a)=>{if(n.step>=o.steps)throw new Error(`slot ${n.id===void 0?`#${a}`:`"${n.id}"`} has step ${n.step}, outside page steps ${o.steps}`);let l;if(O.includes(n.kind)){if(n.unvalidated===!0)throw new Error(`built-in slot kind "${n.kind}" cannot be unvalidated`);if(n.display===!0)throw new Error(`built-in slot kind "${n.kind}" cannot set display: true`);const u=oe[n.kind].safeParse(n.config);if(!u.success)throw new Error(`invalid config for slot ${n.id===void 0?`#${a}`:`"${n.id}"`} (${n.kind}): ${f(u.error)}`);if(r&&n.kind==="options"){const b=u.data,$=n.id===void 0?`#${a}`:`"${n.id}"`;if((b.label??"").trim()==="")throw new Error(`slot ${$} (options): label is required \u2014 the question itself, drawn as the bold first line`);if((b.body??"").trim()==="")throw new Error(`slot ${$} (options): body is required \u2014 the context under the question a label cannot carry`)}l={...n.id===void 0?{}:{id:n.id},kind:n.kind,step:n.step,config:u.data}}else{const u=i===void 0?void 0:q(n.kind,i);if(r&&u===void 0)throw new Error(`unregistered page slot kind "${n.kind}" at slot #${a}`);if(n.unvalidated!==!0)throw new Error(`registered page slot kind "${n.kind}" must set unvalidated: true`);if(!r)l={...n.id===void 0?{}:{id:n.id},kind:n.kind,step:n.step,config:n.config,unvalidated:!0,...n.display===!0?{display:!0}:{}};else{if(n.display===!0&&u?.display!==!0)throw new Error(`non-display page slot kind "${n.kind}" cannot set display: true`);l={...n.id===void 0?{}:{id:n.id},kind:n.kind,step:n.step,config:n.config,unvalidated:!0,...u?.display===!0?{display:!0}:{}}}}if(g(l)&&l.id===void 0)throw new Error(l.unvalidated===!0?`product slot kind "${l.kind}" at slot #${a} requires an id prop`:`response-bearing slot kind "${l.kind}" at slot #${a} requires an id prop`);if(l.id!==void 0){if(s.has(l.id))throw new Error(`duplicate slot id "${l.id}"`);s.add(l.id)}return l});return{...o,slots:d}}c(v,"validateManifest");function C(t){return v(t,void 0,!1)}c(C,"validatePageManifest");function me(t,i=[]){return v(t,i,!0)}c(me,"validateAuthoredPageManifest");function ie(){return e.custom(t=>{try{return C(t),!0}catch{return!1}},{error:"invalid page manifest"}).transform(t=>C(t))}c(ie,"createPageManifestSchema");const ge=ie();function h(t,i,r){if(new Set(t).size!==t.length)throw new Error(`slot "${i}" has duplicate id in ${r}`)}c(h,"assertUnique");function j(t,i){const r=t.config;for(const o of i){const s=o.anchor;if(t.kind==="options"&&s.kind==="option"){if(!r.options.some(d=>d.id===s.optionId))throw new Error(`slot "${t.id}" comment names unknown option id "${s.optionId}"`);continue}if(t.kind==="table"&&s.kind==="row"){if(!(r.rows??[]).some(d=>d.id===s.rowId))throw new Error(`slot "${t.id}" comment names unknown row id "${s.rowId}"`);continue}throw new Error(`slot "${t.id}" does not allow comment anchor kind "${s.kind}"`)}}c(j,"validateComments");function se(t){return t.required??t.mode==="single"}c(se,"optionsRequired");function re(t,i){if(t.unvalidated===!0){const r=w.safeParse(i);if(!r.success)throw new Error(`response for unvalidated slot "${t.id}" must be an object`);return r.data}if(t.kind==="options"){const r=k.safeParse(i);if(!r.success)throw new Error(`invalid response for slot "${t.id}": ${f(r.error)}`);const o=r.data,s=t.config;h(o.selectedOptionIds,t.id,"selectedOptionIds");for(const n of o.selectedOptionIds)if(!s.options.some(a=>a.id===n))throw new Error(`slot "${t.id}" selects unknown option id "${n}"`);if(o.freetext!==void 0&&s.allowFreetext!==!0)throw new Error(`slot "${t.id}" does not allow freetext`);if(s.mode==="single"&&o.selectedOptionIds.length>1)throw new Error(`slot "${t.id}" is single-select but received ${o.selectedOptionIds.length} option ids`);const d=s.allowFreetext===!0&&(o.freetext?.trim()??"")!=="";if(se(s)){if(s.mode==="single"&&o.selectedOptionIds.length!==1&&!d)throw new Error(`single-select slot "${t.id}" requires exactly one selection or nonempty allowed freetext`);if(s.mode==="multi"&&o.selectedOptionIds.length===0&&o.comments.length===0&&!d)throw new Error(`multi-select slot "${t.id}" requires a selection, comment, or nonempty allowed freetext`)}return j(t,o.comments),o}if(t.kind==="text"){const r=x.safeParse(i);if(!r.success)throw new Error(`invalid response for slot "${t.id}": ${f(r.error)}`);if(t.config.required===!0&&r.data.text.trim()==="")throw new Error(`slot "${t.id}" is required and was left empty`);return r.data}if(t.kind==="table"){const r=I.safeParse(i);if(!r.success)throw new Error(`invalid response for slot "${t.id}": ${f(r.error)}`);const o=r.data,s=t.config;h(o.selectedRowIds,t.id,"selectedRowIds"),h(o.selectedColumnIds,t.id,"selectedColumnIds");const d=new Set((s.rows??[]).map(a=>a.id)),n=new Set(s.columns.map(a=>a.id));for(const a of o.selectedRowIds)if(!d.has(a))throw new Error(`slot "${t.id}" selects unknown row id "${a}"`);for(const a of o.selectedColumnIds)if(!n.has(a))throw new Error(`slot "${t.id}" selects unknown column id "${a}"`);if(s.required===!0&&o.selectedRowIds.length===0&&o.selectedColumnIds.length===0)throw new Error(`slot "${t.id}" is required and nothing is selected`);if(s.rowSelect==="none"&&o.selectedRowIds.length>0||s.rowSelect==="single"&&o.selectedRowIds.length>1)throw new Error(`slot "${t.id}" response violates row select mode "${s.rowSelect}"`);if(s.columnSelect==="none"&&o.selectedColumnIds.length>0||s.columnSelect==="single"&&o.selectedColumnIds.length>1)throw new Error(`slot "${t.id}" response violates column select mode "${s.columnSelect}"`);return j(t,o.comments),o}if(t.kind==="cards"){const r=y.safeParse(i);if(!r.success)throw new Error(`invalid response for slot "${t.id}": ${f(r.error)}`);const o=r.data,s=t.config;h(o.selectedCardIds,t.id,"selectedCardIds");for(const d of o.selectedCardIds)if(!(s.cards??[]).some(n=>n.id===d))throw new Error(`slot "${t.id}" selects unknown card id "${d}"`);if(s.mode==="single"&&o.selectedCardIds.length>1)throw new Error(`slot "${t.id}" is single-select but received ${o.selectedCardIds.length} card ids`);if(s.required===!0&&o.selectedCardIds.length===0)throw new Error(`slot "${t.id}" is required and nothing is selected`);return o}throw new Error(`slot "${t.id}" kind "${t.kind}" does not accept a response`)}c(re,"parseResponse");function R(t,i,r){const o=w.safeParse(i);if(!o.success)throw new Error("page responses must be an object keyed by slot id");const s=new Map(t.slots.filter(g).map(n=>[n.id,n])),d={};for(const[n,a]of Object.entries(o.data)){const l=s.get(n);if(l===void 0)throw new Error(`response names unknown or non-response-bearing slot id "${n}"`);d[n]=re(l,a)}if(!r){for(const n of s.keys())if(!(n in d))throw new Error(`final page response is missing response-bearing slot id "${n}"`)}return d}c(R,"validateResponses");function he(t,i){return R(t,i,!1)}c(he,"validatePageResponses");function we(t,i){return R(t,i,!0)}c(we,"validatePartialPageResponses");export{oe as BUILTIN_PAGE_CONFIG_SCHEMAS,ce as BUILTIN_PAGE_RESPONSE_SCHEMAS,P as PAGE_SLOT_ID_PATTERN,z as cardSchema,K as cardsConfigSchema,y as cardsResponseSchema,W as cardsSchema,V as chartConfigSchema,J as chartDataRowsSchema,X as chartSeriesSchema,E as commentSchema,ie as createPageManifestSchema,g as isResponseBearingSlot,f as issueText,L as optionSchema,T as optionsConfigSchema,se as optionsRequired,k as optionsResponseSchema,ue as pageAwaitsResponse,_ as pageCommentAnchorSchema,ee as pageDeliverySchema,fe as pageIsNoticeSql,ge as pageManifestSchema,pe as pageOverviewActions,D as tableCellSchema,F as tableColumnSchema,U as tableConfigSchema,I as tableResponseSchema,H as tableRowSchema,B as tableRowsSchema,M as textConfigSchema,x as textResponseSchema,me as validateAuthoredPageManifest,C as validatePageManifest,he as validatePageResponses,we as validatePartialPageResponses};
@@ -122,7 +122,7 @@ export declare function listRequests(filter?: {
122
122
  file?: string;
123
123
  page_source_node_id?: string;
124
124
  }): Promise<HumanRequestRecord[]>;
125
- /** An indexed preflight preserves the old map-before-filter error for corrupt page JSON. */
125
+ /** A preflight preserves the old map-before-filter error for malformed page results. */
126
126
  export declare function hasPageResultException(): Promise<boolean>;
127
127
  export declare function firstInvalidPageSpecification(): Promise<Pick<HumanRequestRecord, 'request_id' | 'specification_json'> | null>;
128
128
  export declare function openRequest(requestId: string, openedAt: string): Promise<boolean>;