@north-light/cli 0.3.532 → 0.3.534
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api/client.d.ts +6 -3
- package/dist/api/client.js +1 -1
- package/dist/api/contract.d.ts +1 -1
- package/dist/api/contract.js +1 -1
- package/dist/api/dto/canvas.d.ts +2 -0
- package/dist/api/dto/crons.d.ts +3 -1
- package/dist/builtin-memory/crouter-sdk/release-notes.md +13 -0
- package/dist/builtin-memory/northlight-apps/providers/README.md +2 -0
- package/dist/builtin-memory/northlight-apps/providers/sms.md +2 -0
- package/dist/clients/attach/chrome/inbox-strip.d.ts +6 -1
- package/dist/clients/attach/chrome/inbox-strip.js +1 -1
- package/dist/clients/attach/chrome/roster.js +1 -1
- package/dist/clients/attach/session/chrome-refresh.d.ts +12 -3
- package/dist/clients/attach/session/chrome-refresh.js +1 -1
- package/dist/clients/attach/session/document-links.js +1 -1
- package/dist/clients/attach/viewer.js +586 -587
- package/dist/commands/api-client.js +3 -3
- package/dist/commands/canvas.js +1 -1
- package/dist/commands/node/inspect.js +6 -6
- package/dist/commands/sys/context/expose.js +2 -2
- package/dist/commands/sys/db.d.ts +1 -0
- package/dist/commands/sys/db.js +1 -0
- package/dist/commands/sys.js +1 -1
- package/dist/core/bash-guard.js +9 -3
- package/dist/core/canvas/canvas.d.ts +12 -2
- package/dist/core/canvas/canvas.js +23 -20
- package/dist/core/canvas/daemon-actions.d.ts +0 -3
- package/dist/core/canvas/daemon-actions.js +7 -24
- package/dist/core/canvas/daemon-owner.d.ts +3 -0
- package/dist/core/canvas/daemon-owner.js +1 -6
- package/dist/core/canvas/db.d.ts +28 -20
- package/dist/core/canvas/db.js +4 -3
- package/dist/core/canvas/deliveries.d.ts +5 -0
- package/dist/core/canvas/deliveries.js +25 -30
- package/dist/core/canvas/export-sqlite.d.ts +14 -0
- package/dist/core/canvas/export-sqlite.js +3 -0
- package/dist/core/canvas/import-sqlite.d.ts +44 -0
- package/dist/core/canvas/import-sqlite.js +7 -0
- package/dist/core/canvas/node-tokens.js +3 -3
- package/dist/core/canvas/outcome-actions.js +4 -4
- package/dist/core/canvas/recovery.js +1 -1
- package/dist/core/canvas/schema-pg.sql +1022 -0
- package/dist/core/canvas/schema-version.d.ts +4 -0
- package/dist/core/canvas/schema-version.js +1 -0
- package/dist/core/canvas/sessions.js +3 -3
- package/dist/core/canvas/structured-requests.js +2 -2
- package/dist/core/canvas/tree.js +6 -6
- package/dist/core/canvas/waits.js +1 -1
- package/dist/core/feed/inbox.js +1 -1
- package/dist/core/feed/messages.js +5 -5
- package/dist/core/feed/reports.js +2 -2
- package/dist/core/grants/mirror.js +2 -2
- package/dist/core/graph/access.js +7 -7
- package/dist/core/graph/custom.js +10 -10
- package/dist/core/graph/deletion.js +6 -6
- package/dist/core/graph/documents.d.ts +1 -1
- package/dist/core/graph/documents.js +9 -9
- package/dist/core/graph/edges.d.ts +3 -3
- package/dist/core/graph/edges.js +3 -1
- package/dist/core/graph/events.js +7 -7
- package/dist/core/graph/exposures.d.ts +8 -8
- package/dist/core/graph/jobs.d.ts +1 -1
- package/dist/core/graph/jobs.js +2 -2
- package/dist/core/graph/kinds/custom.js +1 -1
- package/dist/core/graph/kinds/document.js +4 -4
- package/dist/core/graph/kinds/dto.js +1 -1
- package/dist/core/graph/kinds/job.js +2 -2
- package/dist/core/graph/kinds/kind.d.ts +2 -2
- package/dist/core/graph/kinds/kind.js +1 -1
- package/dist/core/graph/kinds/live-read.d.ts +5 -0
- package/dist/core/graph/kinds/live-read.js +1 -0
- package/dist/core/graph/kinds/node.js +5 -5
- package/dist/core/graph/kinds/owner.js +2 -2
- package/dist/core/graph/names.js +3 -3
- package/dist/core/graph/objects.d.ts +5 -5
- package/dist/core/graph/objects.js +10 -10
- package/dist/core/graph/package-docs.js +6 -5
- package/dist/core/graph/reader.d.ts +1 -1
- package/dist/core/graph/reader.js +2 -2
- package/dist/core/graph/receivers.js +4 -5
- package/dist/core/graph/repo-sync/exchange.js +2 -2
- package/dist/core/graph/repo-sync/repos.js +3 -3
- package/dist/core/graph/repo-sync/sync.js +1 -1
- package/dist/core/graph/rules.d.ts +3 -4
- package/dist/core/graph/rules.js +3 -3
- package/dist/core/graph/spaces/app.js +1 -1
- package/dist/core/graph/spaces/index.d.ts +1 -1
- package/dist/core/graph/spaces/index.js +1 -1
- package/dist/core/graph/spaces/own-memory.js +1 -1
- package/dist/core/graph/spaces/person.js +3 -3
- package/dist/core/graph/spaces/repo.d.ts +1 -1
- package/dist/core/graph/spaces/repo.js +1 -1
- package/dist/core/graph/types.d.ts +4 -3
- package/dist/core/graph/watches.d.ts +2 -2
- package/dist/core/graph/watches.js +17 -17
- package/dist/core/human/page-schema.js +5 -4
- package/dist/core/human/requests.d.ts +1 -1
- package/dist/core/human/requests.js +20 -23
- package/dist/core/peer/ingest.js +1 -1
- package/dist/core/peer/receiver.js +1 -1
- package/dist/core/peer/stubs.js +1 -1
- package/dist/core/providers/receipts.js +3 -2
- package/dist/core/review/comments.js +5 -4
- package/dist/core/runs/activity.js +4 -5
- package/dist/core/runs/confinement.d.ts +1 -1
- package/dist/core/runs/confinement.js +2 -2
- package/dist/core/runs/events.d.ts +1 -1
- package/dist/core/runs/events.js +5 -5
- package/dist/core/runs/operations.js +6 -4
- package/dist/core/runs/questions.d.ts +2 -0
- package/dist/core/runs/questions.js +1 -1
- package/dist/core/runtime/close.d.ts +3 -0
- package/dist/core/runtime/close.js +1 -1
- package/dist/core/runtime/host.d.ts +5 -1
- package/dist/core/runtime/host.js +3 -3
- package/dist/core/runtime/launch.js +2 -2
- package/dist/core/runtime/ledger.js +3 -3
- package/dist/core/runtime/lifecycle.d.ts +9 -0
- package/dist/core/runtime/lifecycle.js +2 -2
- package/dist/core/runtime/nodes.d.ts +1 -1
- package/dist/core/runtime/nodes.js +1 -1
- package/dist/core/runtime/roadmap.js +1 -1
- package/dist/core/spaces/stop.d.ts +1 -0
- package/dist/core/spaces/stop.js +2 -2
- package/dist/core/statements.d.ts +17 -0
- package/dist/core/statements.js +2 -0
- package/dist/core/substrate/delivery/corpus.js +3 -3
- package/dist/core/substrate/delivery/deliver.js +5 -5
- package/dist/core/substrate/delivery/listings.js +1 -1
- package/dist/core/substrate/delivery/match.d.ts +2 -2
- package/dist/core/substrate/delivery/match.js +1 -1
- package/dist/core/substrate/delivery/plan.js +3 -3
- package/dist/core/substrate/delivery/render-boot.js +5 -5
- package/dist/core/substrate/delivery/render-event.js +6 -6
- package/dist/core/usage/ledger.js +8 -8
- package/dist/core/worktree.js +8 -8
- package/dist/daemon/api/bridge.js +4 -4
- package/dist/daemon/api/document-listener.js +1 -1
- package/dist/daemon/api/handlers/broker-ops.js +1 -1
- package/dist/daemon/api/handlers/canvas.js +1 -1
- package/dist/daemon/api/handlers/crons.js +1 -1
- package/dist/daemon/api/handlers/custom-objects.js +3 -3
- package/dist/daemon/api/handlers/docs.js +1 -1
- package/dist/daemon/api/handlers/inbox.js +1 -1
- package/dist/daemon/api/handlers/memory.js +7 -7
- package/dist/daemon/api/handlers/messages.js +1 -1
- package/dist/daemon/api/handlers/nodes.js +1 -1
- package/dist/daemon/api/handlers/objects.js +3 -3
- package/dist/daemon/api/handlers/questions.js +1 -1
- package/dist/daemon/api/handlers/reviews.js +1 -1
- package/dist/daemon/api/handlers/structured-requests.js +1 -1
- package/dist/daemon/api/reader.js +1 -1
- package/dist/daemon/broker-signals/bus.d.ts +14 -6
- package/dist/daemon/broker-signals/bus.js +1 -10
- package/dist/daemon/cron/ended.d.ts +3 -0
- package/dist/daemon/cron/ended.js +2 -2
- package/dist/daemon/cron/narrowed.d.ts +5 -0
- package/dist/daemon/cron/narrowed.js +2 -0
- package/dist/daemon/cron/settle.js +1 -1
- package/dist/daemon/crtrd-cli.js +1 -1
- package/dist/daemon/crtrd.js +12 -11
- package/dist/daemon/due.js +1 -1
- package/dist/daemon/export-sqlite-run.d.ts +1 -0
- package/dist/daemon/export-sqlite-run.js +4 -0
- package/dist/daemon/fleet.d.ts +1 -0
- package/dist/daemon/fleet.js +3 -3
- package/dist/daemon/human/settle.js +1 -1
- package/dist/daemon/manage.d.ts +10 -0
- package/dist/daemon/manage.js +3 -2
- package/dist/daemon/postgres/binary.d.ts +17 -0
- package/dist/daemon/postgres/binary.js +2 -0
- package/dist/daemon/postgres/cluster.d.ts +37 -0
- package/dist/daemon/postgres/cluster.js +6 -0
- package/dist/daemon/postgres/index.d.ts +2 -0
- package/dist/daemon/postgres/index.js +1 -0
- package/dist/daemon/postgres/pins.d.ts +7 -0
- package/dist/daemon/postgres/pins.js +1 -0
- package/dist/daemon/postgres/supervisor.d.ts +95 -0
- package/dist/daemon/postgres/supervisor.js +2 -0
- package/dist/daemon/reconcilers/bash-deadline.js +2 -2
- package/dist/daemon/reconcilers/delivery-lane.js +2 -2
- package/dist/daemon/reconcilers/node-lifecycle/freeze-lane.d.ts +7 -3
- package/dist/daemon/reconcilers/node-lifecycle/freeze-lane.js +1 -1
- package/dist/daemon/reconcilers/node-lifecycle/tick.js +1 -1
- package/dist/daemon/reconcilers/storage-maintenance.d.ts +0 -6
- package/dist/daemon/reconcilers/storage-maintenance.js +1 -8
- package/dist/daemon/runs/observer.js +5 -4
- package/dist/migrations/004-canvas-documents/index.js +1 -1
- package/dist/pi-extensions/canvas-doc-substrate.d.ts +2 -0
- package/dist/pi-extensions/canvas-doc-substrate.js +6 -6
- package/dist/pi-extensions/envelope-merge.d.ts +3 -2
- package/dist/pi-extensions/envelope-merge.js +9 -8
- package/dist/shared/env.d.ts +3 -0
- package/dist/shared/env.js +2 -2
- package/docs/apps/providers/README.md +2 -0
- package/docs/apps/providers/sms.md +2 -0
- package/docs/public-api.md +11 -2
- package/docs/sdk/release-notes.md +13 -0
- package/package.json +6 -6
- package/packages/crouter-identity/package.json +1 -1
- package/runtime.lock.json +13 -26
- package/scripts/install-runtime.mjs +53 -3
- package/scripts/lib/isolation-env.mjs +3 -1
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
/** The canvas schema version `schema-pg.sql` writes to `canvas_meta.schema_version`. `db.ts` refuses a database at
|
|
2
|
+
* any other version, and `scripts/install-runtime.mjs` reads this module from a candidate generation to refuse one older
|
|
3
|
+
* than the live cluster. Kept free of imports so the installer can load it alone. */
|
|
4
|
+
export declare const CANVAS_SCHEMA_VERSION = 1;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const A=1;export{A as CANVAS_SCHEMA_VERSION};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
var v=Object.defineProperty;var a=(n,e)=>v(n,"name",{value:e,configurable:!0});import{randomUUID as w}from"node:crypto";import{closeSync as y,existsSync as N,fsyncSync as C,openSync as T,readFileSync as U,readSync as A,renameSync as W,statSync as H,truncateSync as I,unlinkSync as D,writeFileSync as M}from"node:fs";import{openDb as c,withCanvasWrite as l}from"./db.js";import{canonicalSessionFile as R}from"./canvas.js";import{join as O}from"node:path";import{readConfig as x}from"../config.js";import{appSpace as F,socketDir as P}from"../layout.js";import{createFileStore as B,conversationStore as $,defaultConversationRoot as k,installConversationStore as b}from"../conversation-store/index.js";import{listenConversationStore as J}from"../conversation-store/listener.js";import{appendConversationEvents as h}from"../../daemon/runs/append-section.js";function S(){return new Date().toISOString()}a(S,"now");async function m(n,e,s){return await n.prepare("SELECT 1 FROM executions WHERE execution_id = ? AND node_id = ? AND state != 'exited'").get(s,e)!==void 0}a(m,"liveExecution");function j(n){return{bindingId:n.binding_id,sessionId:n.session_id??null,nodeId:n.node_id,transcriptPath:n.transcript_path??null,sourceSessionId:n.source_session_id??null,forkEntryId:n.fork_entry_id??null,createdAt:n.created_at,boundAt:n.bound_at,unboundAt:n.unbound_at??null}}a(j,"hydrate");async function rn(n){const e=await(await c()).prepare("SELECT * FROM sessions WHERE node_id = ? AND unbound_at IS NULL").get(n);return e===void 0?null:j(e)}a(rn,"readLiveSession");async function an(n){return(await(await c()).prepare("SELECT node_id FROM sessions WHERE transcript_path = ? AND unbound_at IS NULL").get(R(n)))?.node_id??null}a(an,"findNodeBySessionFileSql");async function dn(n,e){return await l(async s=>{if(!await m(s,n,e.executionId))return"shutdown";const i=S(),o=e.transcriptPath===null?null:R(e.transcriptPath),r=await s.prepare("SELECT binding_id, session_id FROM sessions WHERE node_id = ? AND unbound_at IS NULL").get(n);if(r!==void 0&&r.session_id===e.sessionId)await s.prepare("UPDATE sessions SET transcript_path = ?, source_session_id = ?, bound_at = ? WHERE binding_id = ?").run(o,e.sourceSessionId??null,i,r.binding_id);else{r!==void 0&&await s.prepare("UPDATE sessions SET unbound_at = ? WHERE binding_id = ?").run(i,r.binding_id);const t=e.sessionId===null?void 0:await s.prepare("SELECT binding_id FROM sessions WHERE node_id = ? AND session_id = ? ORDER BY created_at DESC LIMIT 1").get(n,e.sessionId);t?await s.prepare("UPDATE sessions SET transcript_path = ?, source_session_id = ?, bound_at = ?, unbound_at = NULL WHERE binding_id = ?").run(o,e.sourceSessionId??null,i,t.binding_id):await s.prepare("INSERT INTO sessions (binding_id, session_id, node_id, transcript_path, source_session_id, fork_entry_id, created_at, bound_at) VALUES (?, ?, ?, ?, ?, NULL, ?, ?)").run(w(),e.sessionId,n,o,e.sourceSessionId??null,i,i)}return await s.prepare("UPDATE nodes SET cycle_pending = 0 WHERE node_id = ?").run(n),"bound"})}a(dn,"bindSession");async function cn(n,e){await l(async s=>{const i=S();await s.prepare("UPDATE sessions SET unbound_at = ? WHERE node_id = ? AND unbound_at IS NULL").run(i,n),await s.prepare("INSERT INTO sessions (binding_id, session_id, node_id, transcript_path, source_session_id, fork_entry_id, created_at, bound_at) VALUES (?, ?, ?, ?, NULL, NULL, ?, ?)").run(w(),e.sessionId,n,e.transcriptPath===null?null:R(e.transcriptPath),i,i),await s.prepare("UPDATE nodes SET cycle_pending = 0 WHERE node_id = ?").run(n)})}a(cn,"resetSession");async function _n(n){return await l(async e=>{if(!await m(e,n.toNodeId,n.executionId))return"shutdown";if(await e.prepare("SELECT binding_id FROM sessions WHERE node_id = ? AND binding_id = ? AND unbound_at IS NULL").get(n.fromNodeId,n.fromBindingId)===void 0)return"changed";if(await e.prepare("SELECT run_id FROM nodes WHERE node_id IN (?, ?) AND run_id IS NOT NULL LIMIT 1").get(n.fromNodeId,n.toNodeId))throw new Error("run conversation transfer is not supported");const o=S();return await e.prepare("UPDATE sessions SET unbound_at = ? WHERE binding_id = ?").run(o,n.fromBindingId),await e.prepare("UPDATE sessions SET unbound_at = ? WHERE node_id = ? AND unbound_at IS NULL").run(o,n.toNodeId),await e.prepare("INSERT INTO sessions (binding_id, session_id, node_id, transcript_path, source_session_id, fork_entry_id, created_at, bound_at) VALUES (?, ?, ?, ?, NULL, NULL, ?, ?)").run(w(),n.sessionId,n.toNodeId,n.transcriptPath===null?null:R(n.transcriptPath),o,o),await e.prepare("UPDATE nodes SET cycle_pending = 0 WHERE node_id = ?").run(n.toNodeId),"transferred"})}a(_n,"transferSession");async function un(n){await(await c()).prepare("UPDATE sessions SET unbound_at = ? WHERE node_id = ? AND unbound_at IS NULL").run(S(),n)}a(un,"unbindSession");async function En(n,e,s){return await l(async i=>{const o=await i.prepare("SELECT binding_id, transcript_path FROM sessions WHERE node_id = ? AND transcript_path IS NOT NULL").all(n),r=[];try{for(const t of o){if(!N(t.transcript_path))continue;const _=U(t.transcript_path),f=_.indexOf(10);if(f<0)continue;let u;try{u=JSON.parse(_.subarray(0,f).toString("utf8"))}catch{continue}if(u.type!=="session"||u.cwd!==e)continue;const E=Buffer.concat([Buffer.from(JSON.stringify({...u,cwd:s}),"utf8"),_.subarray(f)]),d=`${t.transcript_path}.${w()}.tmp`;r.push({binding_id:t.binding_id,path:t.transcript_path,temp:d,delta:E.length-_.length}),M(d,E,{flag:"wx",mode:384});const p=T(d,"r");try{C(p)}finally{y(p)}}for(const t of r)t.delta!==0&&await i.prepare("UPDATE sessions SET event_offset = event_offset + ? WHERE binding_id = ? AND event_offset IS NOT NULL AND event_offset > 0").run(t.delta,t.binding_id);for(const t of r)W(t.temp,t.path)}finally{for(const t of r)N(t.temp)&&D(t.temp)}return r.length})}a(En,"relocateSessionCwd");async function pn(n,e){await(await c()).prepare("UPDATE nodes SET cycle_pending = ? WHERE node_id = ?").run(e?1:0,n)}a(pn,"setCyclePending");const L="unbound_at IS NULL DESC, created_at DESC,
|
|
2
|
-
FROM sessions s JOIN nodes n ON n.node_id = s.node_id WHERE s.session_id = ? ORDER BY s.unbound_at IS NULL DESC, s.created_at DESC, s.
|
|
1
|
+
var v=Object.defineProperty;var a=(n,e)=>v(n,"name",{value:e,configurable:!0});import{randomUUID as w}from"node:crypto";import{closeSync as y,existsSync as N,fsyncSync as C,openSync as T,readFileSync as U,readSync as A,renameSync as W,statSync as H,truncateSync as I,unlinkSync as D,writeFileSync as M}from"node:fs";import{openDb as c,withCanvasWrite as l}from"./db.js";import{canonicalSessionFile as R}from"./canvas.js";import{join as O}from"node:path";import{readConfig as x}from"../config.js";import{appSpace as F,socketDir as P}from"../layout.js";import{createFileStore as B,conversationStore as $,defaultConversationRoot as k,installConversationStore as b}from"../conversation-store/index.js";import{listenConversationStore as J}from"../conversation-store/listener.js";import{appendConversationEvents as h}from"../../daemon/runs/append-section.js";function S(){return new Date().toISOString()}a(S,"now");async function m(n,e,s){return await n.prepare("SELECT 1 FROM executions WHERE execution_id = ? AND node_id = ? AND state != 'exited'").get(s,e)!==void 0}a(m,"liveExecution");function j(n){return{bindingId:n.binding_id,sessionId:n.session_id??null,nodeId:n.node_id,transcriptPath:n.transcript_path??null,sourceSessionId:n.source_session_id??null,forkEntryId:n.fork_entry_id??null,createdAt:n.created_at,boundAt:n.bound_at,unboundAt:n.unbound_at??null}}a(j,"hydrate");async function rn(n){const e=await(await c()).prepare("SELECT * FROM sessions WHERE node_id = ? AND unbound_at IS NULL").get(n);return e===void 0?null:j(e)}a(rn,"readLiveSession");async function an(n){return(await(await c()).prepare("SELECT node_id FROM sessions WHERE transcript_path = ? AND unbound_at IS NULL").get(R(n)))?.node_id??null}a(an,"findNodeBySessionFileSql");async function dn(n,e){return await l(async s=>{if(!await m(s,n,e.executionId))return"shutdown";const i=S(),o=e.transcriptPath===null?null:R(e.transcriptPath),r=await s.prepare("SELECT binding_id, session_id FROM sessions WHERE node_id = ? AND unbound_at IS NULL").get(n);if(r!==void 0&&r.session_id===e.sessionId)await s.prepare("UPDATE sessions SET transcript_path = ?, source_session_id = ?, bound_at = ? WHERE binding_id = ?").run(o,e.sourceSessionId??null,i,r.binding_id);else{r!==void 0&&await s.prepare("UPDATE sessions SET unbound_at = ? WHERE binding_id = ?").run(i,r.binding_id);const t=e.sessionId===null?void 0:await s.prepare("SELECT binding_id FROM sessions WHERE node_id = ? AND session_id = ? ORDER BY created_at DESC LIMIT 1").get(n,e.sessionId);t?await s.prepare("UPDATE sessions SET transcript_path = ?, source_session_id = ?, bound_at = ?, unbound_at = NULL WHERE binding_id = ?").run(o,e.sourceSessionId??null,i,t.binding_id):await s.prepare("INSERT INTO sessions (binding_id, session_id, node_id, transcript_path, source_session_id, fork_entry_id, created_at, bound_at) VALUES (?, ?, ?, ?, ?, NULL, ?, ?)").run(w(),e.sessionId,n,o,e.sourceSessionId??null,i,i)}return await s.prepare("UPDATE nodes SET cycle_pending = 0 WHERE node_id = ?").run(n),"bound"})}a(dn,"bindSession");async function cn(n,e){await l(async s=>{const i=S();await s.prepare("UPDATE sessions SET unbound_at = ? WHERE node_id = ? AND unbound_at IS NULL").run(i,n),await s.prepare("INSERT INTO sessions (binding_id, session_id, node_id, transcript_path, source_session_id, fork_entry_id, created_at, bound_at) VALUES (?, ?, ?, ?, NULL, NULL, ?, ?)").run(w(),e.sessionId,n,e.transcriptPath===null?null:R(e.transcriptPath),i,i),await s.prepare("UPDATE nodes SET cycle_pending = 0 WHERE node_id = ?").run(n)})}a(cn,"resetSession");async function _n(n){return await l(async e=>{if(!await m(e,n.toNodeId,n.executionId))return"shutdown";if(await e.prepare("SELECT binding_id FROM sessions WHERE node_id = ? AND binding_id = ? AND unbound_at IS NULL").get(n.fromNodeId,n.fromBindingId)===void 0)return"changed";if(await e.prepare("SELECT run_id FROM nodes WHERE node_id IN (?, ?) AND run_id IS NOT NULL LIMIT 1").get(n.fromNodeId,n.toNodeId))throw new Error("run conversation transfer is not supported");const o=S();return await e.prepare("UPDATE sessions SET unbound_at = ? WHERE binding_id = ?").run(o,n.fromBindingId),await e.prepare("UPDATE sessions SET unbound_at = ? WHERE node_id = ? AND unbound_at IS NULL").run(o,n.toNodeId),await e.prepare("INSERT INTO sessions (binding_id, session_id, node_id, transcript_path, source_session_id, fork_entry_id, created_at, bound_at) VALUES (?, ?, ?, ?, NULL, NULL, ?, ?)").run(w(),n.sessionId,n.toNodeId,n.transcriptPath===null?null:R(n.transcriptPath),o,o),await e.prepare("UPDATE nodes SET cycle_pending = 0 WHERE node_id = ?").run(n.toNodeId),"transferred"})}a(_n,"transferSession");async function un(n){await(await c()).prepare("UPDATE sessions SET unbound_at = ? WHERE node_id = ? AND unbound_at IS NULL").run(S(),n)}a(un,"unbindSession");async function En(n,e,s){return await l(async i=>{const o=await i.prepare("SELECT binding_id, transcript_path FROM sessions WHERE node_id = ? AND transcript_path IS NOT NULL").all(n),r=[];try{for(const t of o){if(!N(t.transcript_path))continue;const _=U(t.transcript_path),f=_.indexOf(10);if(f<0)continue;let u;try{u=JSON.parse(_.subarray(0,f).toString("utf8"))}catch{continue}if(u.type!=="session"||u.cwd!==e)continue;const E=Buffer.concat([Buffer.from(JSON.stringify({...u,cwd:s}),"utf8"),_.subarray(f)]),d=`${t.transcript_path}.${w()}.tmp`;r.push({binding_id:t.binding_id,path:t.transcript_path,temp:d,delta:E.length-_.length}),M(d,E,{flag:"wx",mode:384});const p=T(d,"r");try{C(p)}finally{y(p)}}for(const t of r)t.delta!==0&&await i.prepare("UPDATE sessions SET event_offset = event_offset + ? WHERE binding_id = ? AND event_offset IS NOT NULL AND event_offset > 0").run(t.delta,t.binding_id);for(const t of r)W(t.temp,t.path)}finally{for(const t of r)N(t.temp)&&D(t.temp)}return r.length})}a(En,"relocateSessionCwd");async function pn(n,e){await(await c()).prepare("UPDATE nodes SET cycle_pending = ? WHERE node_id = ?").run(e?1:0,n)}a(pn,"setCyclePending");const L="unbound_at IS NULL DESC, created_at DESC, seq DESC";async function fn(n){return(await(await c()).prepare(`SELECT node_id FROM sessions WHERE session_id = ? ORDER BY ${L} LIMIT 1`).get(n))?.node_id??null}a(fn,"conversationOwner");const Y={appendSection:a(async(n,e,s)=>{const i=e.kind==="create"?e:void 0;i&&await l(async o=>{if(!await o.prepare("SELECT node_id FROM nodes WHERE node_id = ?").get(i.nodeId))throw new Error(`missing conversation owner ${i.nodeId}`);const t=S();await o.prepare("INSERT INTO sessions (binding_id, session_id, node_id, transcript_path, source_session_id, fork_entry_id, created_at, bound_at, unbound_at, event_offset) VALUES (?, ?, ?, ?, ?, NULL, ?, ?, ?, 0)").run(w(),n,i.nodeId,i.path,i.sourceId??null,t,t,t)}),await l(async o=>{const r=await o.prepare(`SELECT node_id, binding_id, input_ids_json FROM sessions WHERE session_id = ? ORDER BY ${L} LIMIT 1`).get(n),t=i?i.nodeId:r?.node_id;if(!t)throw new Error(`conversation ${n} has no active owner`);const _=await o.prepare("SELECT run_id FROM nodes WHERE node_id = ?").get(t);if(!_)throw new Error(`cannot write conversation ${n}: missing node ${t}`);if(e.kind==="replace"&&_.run_id!==null)throw new Error(`run conversation ${n} is append-only; replace refused`);const f=r.binding_id,u=s();if(_.run_id!==null&&e.kind!=="replace"){const E=i?.sourceId?[]:e.entries,d=await h(o,_.run_id,t,E,JSON.parse(r?.input_ids_json??"[]"));await o.prepare("UPDATE sessions SET event_offset = ?, indexed_entry_id = ?, input_ids_json = ? WHERE binding_id = ?").run(u,E.at(-1)?.id??null,JSON.stringify(d),f)}})},"appendSection"),async abortCreate(n){await(await c()).prepare("DELETE FROM sessions WHERE session_id = ? AND event_offset = 0").run(n)},async delete(n){await(await c()).prepare("DELETE FROM sessions WHERE session_id = ?").run(n)},async pathFor(n){return(await(await c()).prepare(`SELECT transcript_path FROM sessions WHERE session_id = ? ORDER BY ${L} LIMIT 1`).get(n))?.transcript_path??void 0},async createPath(n,e){const s=await(await c()).prepare("SELECT grantee FROM node_rows WHERE node_id = ?").get(n);if(!s)throw new Error(`missing conversation owner ${n}`);return O(F(s.grantee).conversations,n,`${e.timestamp.replace(/[:.]/g,"-")}_${e.id}.jsonl`)},async repair(n,e){await V(n,e)},async owners(){const n=new Map,e=await(await c()).prepare(`SELECT session_id, node_id FROM sessions WHERE session_id IS NOT NULL ORDER BY session_id, ${L}`).all();for(const s of e)n.has(s.session_id)||n.set(s.session_id,s.node_id);return n}};async function V(n,e){const s=await(await c()).prepare(`SELECT s.binding_id, s.node_id, s.event_offset, s.input_ids_json, s.source_session_id, n.run_id
|
|
2
|
+
FROM sessions s JOIN nodes n ON n.node_id = s.node_id WHERE s.session_id = ? ORDER BY s.unbound_at IS NULL DESC, s.created_at DESC, s.seq DESC LIMIT 1`).get(n);if(!s?.run_id||s.event_offset===null)return;if(s.event_offset===0&&!N(e)){await(await c()).prepare("DELETE FROM sessions WHERE binding_id = ?").run(s.binding_id);return}const i=H(e).size;if(i<s.event_offset)throw new Error(`conversation shorter than indexed offset: ${n}`);if(i===s.event_offset)return;const o=T(e,"r"),r=[];try{const d=Buffer.allocUnsafe(65536);for(let p=s.event_offset;p<i;){const g=A(o,d,0,Math.min(d.length,i-p),p);if(!g)throw new Error(`conversation read ended early: ${n}`);r.push(Buffer.from(d.subarray(0,g))),p+=g}}finally{y(o)}const t=Buffer.concat(r).toString("utf8"),_=t.lastIndexOf(`
|
|
3
3
|
`);if(_<0){s.event_offset===0?(D(e),await(await c()).prepare("DELETE FROM sessions WHERE binding_id = ?").run(s.binding_id)):I(e,s.event_offset);return}const f=t.slice(0,_+1),u=f.split(`
|
|
4
|
-
`).filter(Boolean).map(d=>JSON.parse(d)).filter(d=>d.type!=="session"),E=s.event_offset+Buffer.byteLength(f);E<i&&I(e,E),await l(async d=>{const p=s.source_session_id?[]:await h(d,s.run_id,s.node_id,u,JSON.parse(s.input_ids_json));await d.prepare("UPDATE sessions SET event_offset = ?, indexed_entry_id = ?, input_ids_json = ? WHERE binding_id = ?").run(E,u.at(-1)?.id??null,JSON.stringify(p),s.binding_id)})}a(V,"repairConversationTail");function
|
|
4
|
+
`).filter(Boolean).map(d=>JSON.parse(d)).filter(d=>d.type!=="session"),E=s.event_offset+Buffer.byteLength(f);E<i&&I(e,E),await l(async d=>{const p=s.source_session_id?[]:await h(d,s.run_id,s.node_id,u,JSON.parse(s.input_ids_json));await d.prepare("UPDATE sessions SET event_offset = ?, indexed_entry_id = ?, input_ids_json = ? WHERE binding_id = ?").run(E,u.at(-1)?.id??null,JSON.stringify(p),s.binding_id)})}a(V,"repairConversationTail");function q(n){return B(n,Y)}a(q,"openCanvasConversationStore");async function ln(n){const e=await(await c()).prepare("SELECT DISTINCT s.session_id FROM sessions s JOIN nodes n ON n.node_id = s.node_id WHERE n.run_id = ? AND s.session_id IS NOT NULL").all(n),s=$();for(const i of e)s.repair?.(i.session_id)}a(ln,"repairRunConversations");async function wn(){const n=x("user").store,e=n?.address??O(P(),"store.sock"),s=q(n?.root??k());b(s),process.env.CRTR_STORE_ADDRESS=e;const i=await J(e,s);return{async close(){await i.close(),b(void 0)}}}a(wn,"serveCanvasConversationStore");export{dn as bindSession,fn as conversationOwner,an as findNodeBySessionFileSql,q as openCanvasConversationStore,rn as readLiveSession,En as relocateSessionCwd,ln as repairRunConversations,cn as resetSession,wn as serveCanvasConversationStore,pn as setCyclePending,_n as transferSession,un as unbindSession};
|
|
@@ -10,6 +10,6 @@ var g=Object.defineProperty;var d=(e,n)=>g(e,"name",{value:n,configurable:!0});i
|
|
|
10
10
|
settled_at = ?
|
|
11
11
|
WHERE request_id = ? AND state = 'pending'`).run(a,t.intended,a,t.intended,i,a,t.intended,u?.reason??null,a,t.intended,u?.code??null,a,t.intended,u===void 0?null:u.retryable?1:0,a,t.intended,S,a,t.intended,q,a,n)).changes)===1,row:await c(e,n)}}d(N,"settleStructuredRequestIn");async function U(e,n){const t=await l(async a=>await N(a,e,n));return t.changed&&E(t.row),t}d(U,"settleStructuredRequest");async function m(e,n,t){const a=r(await e.prepareUncached("SELECT * FROM structured_requests WHERE node_id = ? AND state = 'pending'").get(n));return a===null?{changed:!1,row:null}:await N(e,a.request_id,t)}d(m,"settlePendingStructuredRequestForNodeIn");async function O(e,n){const t=await l(async a=>await m(a,e,n));return t.changed&&E(t.row),t}d(O,"settlePendingStructuredRequestForNode");async function W(e){return(await(await s()).prepareUncached("SELECT * FROM structured_requests WHERE state = 'pending' AND deadline_at IS NOT NULL AND deadline_at <= ?").all(e)).map(n=>r(n))}d(W,"pendingStructuredRequestsPast");async function x(){return(await(await s()).prepareUncached("SELECT * FROM structured_requests WHERE state != 'pending' AND effects_done_at IS NULL").all()).map(e=>r(e))}d(x,"incompleteStructuredRequestEffects");async function C(e){return e.node_id===null?!1:e.submission==="oneoff"?!0:(await(await s()).prepareUncached(`SELECT request_id FROM structured_requests
|
|
12
12
|
WHERE node_id = ? AND submission = 'terminal' AND state IN ('completed', 'declined')
|
|
13
|
-
ORDER BY settled_at DESC,
|
|
13
|
+
ORDER BY settled_at DESC, seq DESC LIMIT 1`).get(e.node_id))?.request_id===e.request_id}d(C,"ownsStructuredRequestResultProjection");async function b(e){return e.node_id===null?!1:(await(await s()).prepareUncached(`SELECT request_id FROM structured_requests
|
|
14
14
|
WHERE node_id = ? AND state = 'declined'
|
|
15
|
-
ORDER BY settled_at DESC,
|
|
15
|
+
ORDER BY settled_at DESC, seq DESC LIMIT 1`).get(e.node_id))?.request_id===e.request_id}d(b,"ownsStructuredRequestDeclineProjection");async function j(e,n){await(await s()).prepareUncached("UPDATE structured_requests SET effects_done_at = ?, result_path = COALESCE(?, result_path) WHERE request_id = ? AND state != 'pending'").run(Date.now(),n,e)}d(j,"markStructuredRequestEffectsDone");async function F(e,n,t,a){const i=await p(e);return i!==null?i:await R({requestId:`legacy-${D().replace(/-/g,"")}`,mode:"async",submission:n,dedicated:n==="terminal",schema:t,deadlineAt:null,nodeId:e,requestMessageId:a??null})}d(F,"registerLegacyStructuredRequest");function M(e){return{request_id:e.request_id,node_id:e.node_id,mode:e.mode,submission:e.submission,state:e.state,created_at:new Date(e.created_at).toISOString(),deadline_at:e.deadline_at===null?null:new Date(e.deadline_at).toISOString(),settled_at:e.settled_at===null?null:new Date(e.settled_at).toISOString(),result:e.state==="completed"?e.result:null,declined:e.state==="declined"?e.declined:null,failure:e.state==="failed"&&e.failure_reason!==null?{reason:e.failure_reason,detail:e.failure_detail}:null}}d(M,"toStructuredRequestDTO");export{R as admitStructuredRequest,I as bindStructuredRequest,p as getPendingStructuredRequestForNode,y as getStructuredRequest,x as incompleteStructuredRequestEffects,j as markStructuredRequestEffectsDone,b as ownsStructuredRequestDeclineProjection,C as ownsStructuredRequestResultProjection,W as pendingStructuredRequestsPast,F as registerLegacyStructuredRequest,A as registerStructuredRequestEffectRunner,E as runStructuredRequestEffects,O as settlePendingStructuredRequestForNode,m as settlePendingStructuredRequestForNodeIn,U as settleStructuredRequest,N as settleStructuredRequestIn,M as toStructuredRequestDTO};
|
package/dist/core/canvas/tree.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
var N=Object.defineProperty;var
|
|
1
|
+
var N=Object.defineProperty;var i=(o,t)=>N(o,"name",{value:t,configurable:!0});import{openDb as c,withCanvasWrite as d}from"./db.js";import{getById as A,nodeObject as r}from"../graph/objects.js";import{recordWatch as S,unwatch as v,descendants as b,configFromJson as y,configToJson as O}from"../graph/watches.js";import{publish as R}from"../graph/events.js";import{DEFAULT_LISTEN as T}from"../graph/types.js";import{filterAsync as j}from"../async-array.js";const D=["spawn","job-start","ask"],E="('spawn','job-start','ask')",I=[{threshold:3,delivery:"next-turn"}];function h(o){const t=o.find(a=>a.threshold<=7);return t!==void 0&&t.delivery!=="next-turn"}i(h,"wakesAtSeven");async function w(o,t,...a){const n=await o.prepareUncached(`SELECT wo.id AS from_id, oo.id AS to_id, ws.config_json, ws.created_at,
|
|
2
2
|
wo.listen_json, wn.status AS from_status, onode.status AS to_status
|
|
3
3
|
FROM watches w
|
|
4
|
-
JOIN objects wo ON wo.
|
|
5
|
-
JOIN objects oo ON oo.
|
|
6
|
-
JOIN watch_subscriptions ws ON ws.watch = w.
|
|
4
|
+
JOIN objects wo ON wo.id = w.watcher AND wo.type = 'node'
|
|
5
|
+
JOIN objects oo ON oo.id = w.object AND oo.type = 'node'
|
|
6
|
+
JOIN watch_subscriptions ws ON ws.watch = w.watch_id AND ws.started_by IN ${E}
|
|
7
7
|
JOIN nodes wn ON wn.node_id = wo.id
|
|
8
8
|
JOIN nodes onode ON onode.node_id = oo.id
|
|
9
9
|
WHERE w.in_tree = 1 ${t}
|
|
10
|
-
ORDER BY ws.created_at, ws.
|
|
10
|
+
ORDER BY ws.created_at, ws.seq`).all(...a),s=new Map;for(const e of n){const u=e.config_json,f=e.listen_json,_=u!=null?y(u):f!=null?y(f):T,p=`${e.from_id}\0${e.to_id}`,m=s.get(p);if(m){m.active||=h(_);continue}s.set(p,{from_id:e.from_id,to_id:e.to_id,active:h(_),created:e.created_at,from_status:e.from_status??null,to_status:e.to_status??null})}return[...s.values()]}i(w,"treeEdges");async function C(){return(await w(await c(),"")).map(({from_id:o,to_id:t,active:a,created:n})=>({from_id:o,to_id:t,active:a,created:n}))}i(C,"rosterEdges");async function H(o,t,a=!0){await d(async n=>{const s=await r(n,o),e=await r(n,t);await S(n,s,e,"ask"),await g(o,t,a),await R(n,{event:"watched",object:e,actor:s,attrs:{}})})}i(H,"subscribe");async function M(o,t){await d(async a=>{const n=await r(a,o),s=await r(a,t);for(const e of D)await v(a,n,s,{startedBy:e})})}i(M,"unsubscribe");async function g(o,t,a){await d(async n=>{await n.prepareUncached(`UPDATE watch_subscriptions SET config_json = ?
|
|
11
11
|
WHERE started_by IN ${E}
|
|
12
|
-
AND watch IN (SELECT
|
|
12
|
+
AND watch IN (SELECT watch_id FROM watches WHERE watcher = ? AND object = ?)`).run(a?null:O(I),(await r(n,o)).id,(await r(n,t)).id)})}i(g,"setSubscriptionActive");async function U(o){return(await w(await c(),"AND oo.id = ?",o)).map(t=>({node_id:t.from_id,active:t.active,created:t.created}))}i(U,"subscribersOf");async function B(o){return(await w(await c(),"AND wo.id = ?",o)).map(t=>({node_id:t.to_id,active:t.active,created:t.created}))}i(B,"subscriptionsOf");async function P(o){const t=await c(),a=await A(t,o);if(a?.type!=="node")return[];const n=t.prepare("SELECT 1 FROM nodes WHERE node_id = ?");return await j((await b(t,a)).map(s=>s.id),async s=>await n.get(s)!==void 0)}i(P,"view");const l=new Set(["active","idle"]);async function V(o){return(await w(await c(),"AND wo.id = ?",o)).some(t=>t.active&&l.has(t.to_status??""))}i(V,"hasActiveLiveSubscription");async function q(o){return(await w(await c(),"AND oo.id = ?",o)).some(t=>t.active&&l.has(t.from_status??""))}i(q,"hasLiveSubscriber");export{V as hasActiveLiveSubscription,q as hasLiveSubscriber,C as rosterEdges,g as setSubscriptionActive,H as subscribe,U as subscribersOf,B as subscriptionsOf,M as unsubscribe,P as view};
|
|
@@ -6,6 +6,6 @@ var w=Object.defineProperty;var n=(t,e)=>w(t,"name",{value:e,configurable:!0});i
|
|
|
6
6
|
WHERE NOT EXISTS (SELECT 1 FROM waits WHERE node_id = ? AND kind = 'object' AND target_id = ? AND satisfied_at IS NULL)`).run(_(),e,i,a,e,i)}n(D,"armObjectWait");async function S(t,e,i=null,a=Date.now()){return Number(i===null?(await t.prepare("UPDATE waits SET satisfied_at = ? WHERE kind = 'object' AND target_id = ? AND satisfied_at IS NULL").run(a,e)).changes:(await t.prepare("UPDATE waits SET satisfied_at = ? WHERE kind = 'object' AND target_id = ? AND node_id = ? AND satisfied_at IS NULL").run(a,e,i)).changes)}n(S,"settleObjectWaits");async function T(t,e,i=Date.now()){return Number((await t.prepare("UPDATE waits SET satisfied_at = ? WHERE kind = 'object' AND node_id = ? AND satisfied_at IS NULL").run(i,e)).changes)}n(T,"settleNodeObjectWaits");async function R(t){return t??=await d(),(await t.prepare(`SELECT w.wait_id, w.node_id, w.target_id, w.created_at, o.type AS object_type, o.name AS object_name
|
|
7
7
|
FROM waits w JOIN objects o ON o.id = w.target_id
|
|
8
8
|
WHERE w.kind = 'object' AND w.satisfied_at IS NULL AND o.deleted_at IS NULL
|
|
9
|
-
ORDER BY w.node_id, w.created_at, w.
|
|
9
|
+
ORDER BY w.node_id, w.created_at, w.seq`).all()).map(e=>({waitId:e.wait_id,nodeId:e.node_id,objectId:e.target_id,createdAt:e.created_at,objectType:e.object_type,objectName:e.object_name}))}n(R,"liveObjectWaitsNamed");async function W(t){return await(await d()).prepare("SELECT 1 FROM waits WHERE node_id = ? AND kind = 'object' AND satisfied_at IS NULL LIMIT 1").get(t)!==void 0}n(W,"hasLiveObjectWait");async function I(t){return await(await d()).prepare(`SELECT 1 FROM waits w JOIN nodes target ON target.node_id = w.target_id
|
|
10
10
|
WHERE w.node_id = ? AND w.kind = 'controller' AND w.satisfied_at IS NULL
|
|
11
11
|
AND target.status IN ('active', 'idle') LIMIT 1`).get(t)!==void 0}n(I,"hasLiveControllerWait");export{f as armControllerWait,D as armObjectWait,I as hasLiveControllerWait,W as hasLiveObjectWait,A as liveControllerWaits,R as liveObjectWaitsNamed,p as readControllerWait,g as settleDeadControllerWait,L as settleMatchingControllerWait,T as settleNodeObjectWaits,S as settleObjectWaits};
|
package/dist/core/feed/inbox.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var f=Object.defineProperty;var i=(n,e)=>f(n,"name",{value:e,configurable:!0});import{openDb as u}from"../canvas/db.js";import{heads as m}from"../graph/documents.js";import{getById as p}from"../graph/objects.js";import{bodyOf as l}from"../graph/bodies.js";import{validateOperationId as y}from"../events/operation-id.js";import{formatInboxCard as h,machineOfEntries as b}from"../../shared/generated-context.js";import{inlineBody as
|
|
1
|
+
var f=Object.defineProperty;var i=(n,e)=>f(n,"name",{value:e,configurable:!0});import{openDb as u}from"../canvas/db.js";import{heads as m}from"../graph/documents.js";import{getById as p}from"../graph/objects.js";import{bodyOf as l}from"../graph/bodies.js";import{validateOperationId as y}from"../events/operation-id.js";import{formatInboxCard as h,machineOfEntries as b}from"../../shared/generated-context.js";import{inlineBody as I,renderEntryBody as g,reportRefNodeId as w}from"../../shared/inbox-entry-body.js";import{mapAsync as E}from"../async-array.js";const _=/^(?!0{32}$)[0-9a-f]{32}$/;function x(n){if(typeof n!="string"||!_.test(n))throw new TypeError("entry_id must be 32 lowercase non-zero hexadecimal characters");return n}i(x,"validateInboxEntryId");function S(n){const e=n.message;return{entry_id:x(e.messageId),operation_id:y(e.operationId),ts:e.createdAt,from:e.senderNodeId,...e.senderName===null?{}:{from_name:e.senderName},tier:n.urgency,kind:e.kind,...e.bodyRef===null?{}:{ref:e.bodyRef},label:e.label,...e.bodyJson===null?{}:{data:e.bodyJson},...e.disposition===null?{}:{disposition:e.disposition}}}i(S,"nodeMailEntry");async function k(n){const e=await u(),o=await p(e,n);if(o===null||o.type!=="document"||o.deleted_at!==null)return null;const s=(await m(e,o))[0];if(s===void 0)return null;const d=await e.prepare("SELECT source_path FROM documents WHERE object = ?").get(o.id);return l(s.body_hash,d?.source_path??null)}i(k,"reportDocumentBody");async function B(n){const e=n.data?.push?.object?.id,o=w(n.ref)!==void 0&&e!==void 0?await k(e):null;return g(n,o)}i(B,"entryBody");async function N(n){return{kind:n.kind,body:await B(n),...n.ref===void 0?{}:{ref:n.ref},...n.disposition===void 0?{}:{disposition:n.disposition}}}i(N,"cardEntry");async function $(n){if(n.length===0)return[];const e=new Map;for(const t of n){const r=t.from??"system";e.has(r)||e.set(r,[]),e.get(r).push(t)}const o=[],s=[];let d=-1;for(const[t,r]of e){if(t==="human"){for(const a of r){const c=I(a);o.push({kind:"human",text:c===""?a.label:c,entries:[a]})}continue}d<0&&(d=o.length,o.push({kind:"card",text:"",entries:[]})),s.push({id:t,...b(r),entries:await E(r,N)})}return d>=0&&(o[d]={kind:"card",text:h(s),entries:n.filter(t=>(t.from??"system")!=="human")}),o}i($,"coalesce");export{$ as coalesce,S as nodeMailEntry,k as reportDocumentBody};
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
var p=Object.defineProperty;var s=(r,e)=>p(r,"name",{value:e,configurable:!0});import{existsSync as _,mkdirSync as E,renameSync as N,writeFileSync as I}from"node:fs";import{randomBytes as v,randomUUID as b}from"node:crypto";import{join as k}from"node:path";import{cancelCronsOnWake as u}from"../canvas/crons.js";import{withCanvasWrite as c,openDb as h}from"../canvas/db.js";import{getRow as S}from"../canvas/canvas.js";import{messagesDir as R}from"../canvas/paths.js";import{syncDirectory as D,syncFile as
|
|
1
|
+
var p=Object.defineProperty;var s=(r,e)=>p(r,"name",{value:e,configurable:!0});import{existsSync as _,mkdirSync as E,renameSync as N,writeFileSync as I}from"node:fs";import{randomBytes as v,randomUUID as b}from"node:crypto";import{join as k}from"node:path";import{cancelCronsOnWake as u}from"../canvas/crons.js";import{withCanvasWrite as c,openDb as h}from"../canvas/db.js";import{getRow as S}from"../canvas/canvas.js";import{messagesDir as R}from"../canvas/paths.js";import{syncDirectory as D,syncFile as T}from"../fs-utils.js";import{settleDeadControllerWait as A,settleMatchingControllerWait as O}from"../canvas/waits.js";import{generateOperationId as x,operationIdContext as L,validateOperationId as C}from"../events/operation-id.js";import{clipBody as J}from"../../shared/inbox-entry-body.js";function y(){let r;do r=v(16).toString("hex");while(r==="00000000000000000000000000000000");return r}s(y,"newId");function M(r,e){const t=JSON.stringify(r);if(t===void 0)throw new TypeError(`${e} must be JSON-serializable`);return t}s(M,"stringify");async function U(r,e){return e!=="normal"&&e!=="deferred"?e:(await S(r))?.lifecycle==="terminal"?"urgent":e}s(U,"effectiveTier");function W(r,e,t){const n=R(r);_(n)||E(n,{recursive:!0});const a=e.replace(/[^0-9]/g,""),d=k(n,`${a}-${b().slice(0,6)}.md`),i=`${d}.tmp`;return I(i,t,"utf8"),T(i),N(i,d),D(n),d}s(W,"writeMessageBody");function q(r){if(typeof r!="object"||r===null)return"";const e=r.body;return typeof e=="string"?e.trim():""}s(q,"inlineBody");async function m(r,e){const t=e.messageId??y(),n=Number((await r.prepare("UPDATE message_sequence SET seq = seq + 1 WHERE id = 1 RETURNING seq").get()).seq);return await r.prepare(`INSERT INTO messages
|
|
2
2
|
(message_id, seq, operation_id, created_at, sender_node_id, sender_name, kind, label, body_ref, body_json, disposition,
|
|
3
3
|
event, object_id, level, actor_id, cause_message_id, depth)
|
|
4
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(t,n,e.operationId,e.createdAt,e.senderNodeId,e.senderName,e.kind,e.label,e.bodyRef,e.bodyJson===void 0?null:
|
|
4
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(t,n,e.operationId,e.createdAt,e.senderNodeId,e.senderName,e.kind,e.label,e.bodyRef,e.bodyJson===void 0?null:M(e.bodyJson,"message body"),e.disposition,e.event?.event??null,e.event?.objectId??null,e.event?.level??null,e.event?.actorId??null,e.causeMessageId??null,e.depth??0),t}s(m,"insertMessage");async function f(r,e,t,n,a,d,i){const o=y();return await r.prepare(`INSERT INTO deliveries
|
|
5
5
|
(delivery_id, message_id, destination_id, urgency, wake, state, idempotency_key, created_at, updated_at)
|
|
6
|
-
VALUES (?, ?, ?, ?, ?, 'pending', ?, ?, ?)`).run(o,e,t,n,a,i??null,d,d),o}s(f,"insertNodeDelivery");function g(r,e){const t=new Date().toISOString(),n=r.operationId===void 0?L.current()??x():
|
|
7
|
-
FROM deliveries d JOIN messages m ON m.message_id = d.message_id WHERE d.idempotency_key = ?`).get(e.idempotencyKey);if(l!==void 0)return{messageId:l.message_id,deliveryId:l.delivery_id,urgency:l.urgency,createdAt:l.created_at}}const d=Date.now(),i=await
|
|
8
|
-
WHERE w.node_id = ? AND w.kind = 'controller' AND w.target_id = ? AND w.satisfied_at IS NULL`).get(r,e);if(a===void 0||a.controller_status==="active"||a.controller_status==="idle")return null;const d=await
|
|
6
|
+
VALUES (?, ?, ?, ?, ?, 'pending', ?, ?, ?)`).run(o,e,t,n,a,i??null,d,d),o}s(f,"insertNodeDelivery");function g(r,e){const t=new Date().toISOString(),n=r.operationId===void 0?L.current()??x():C(r.operationId);let a=r.bodyRef??null,d=r.bodyJson;if(a===null&&e!==null&&r.senderNodeId!=="human"){const i=q(d),o=J(i);o.clipped&&(a=W(e,t,i),d={...d,body:o.text})}return{createdAt:t,operationId:n,bodyRef:a,bodyJson:d}}s(g,"finalizeNodeMail");async function F(r,e){const t=g(e,r);return await c(async n=>{const a=await n.prepare("SELECT run_id FROM nodes WHERE node_id = ?").get(r);if(a?.run_id&&(await n.prepare("SELECT deleting_at FROM nodes WHERE node_id = ?").get(a.run_id))?.deleting_at)throw new Error("run is deleting");if(e.idempotencyKey!==void 0){const l=await n.prepare(`SELECT d.delivery_id, d.message_id, d.urgency, m.created_at
|
|
7
|
+
FROM deliveries d JOIN messages m ON m.message_id = d.message_id WHERE d.idempotency_key = ?`).get(e.idempotencyKey);if(l!==void 0)return{messageId:l.message_id,deliveryId:l.delivery_id,urgency:l.urgency,createdAt:l.created_at}}const d=Date.now(),i=await U(r,e.urgency),o=await m(n,{messageId:e.messageId,operationId:t.operationId,createdAt:t.createdAt,senderNodeId:e.senderNodeId??null,senderName:e.senderName??null,kind:e.kind,label:e.label,bodyRef:t.bodyRef,bodyJson:t.bodyJson,disposition:e.disposition??null}),w=await f(n,o,r,i,e.wake,d,e.idempotencyKey);return await O(r,e.senderNodeId??null,d,n),await e.withinEnqueue?.(n,o),e.wake===1&&i!=="deferred"&&await u(r),{messageId:o,deliveryId:w,urgency:i,createdAt:t.createdAt}})}s(F,"enqueueNodeMail");function Z(r){switch(r){case"interrupt":return{urgency:"critical",wake:1};case"steer":return{urgency:"urgent",wake:1};case"after-turn":return{urgency:"normal",wake:1};case"next-turn":return{urgency:"deferred",wake:0}}}s(Z,"listenDeliveryTier");async function ee(r,e,t){const n={kind:"update",label:t.label??"notice",bodyJson:{body:t.body},urgency:t.tier,wake:t.wake},a=g(n,e),d=Date.now(),i=await m(r,{operationId:a.operationId,createdAt:a.createdAt,senderNodeId:null,senderName:null,kind:n.kind,label:n.label,bodyRef:a.bodyRef,bodyJson:a.bodyJson,disposition:null}),o=await f(r,i,e,t.tier,t.wake,d);return t.wake===1&&t.tier!=="deferred"&&await u(e),{messageId:i,deliveryId:o,urgency:t.tier,createdAt:a.createdAt}}s(ee,"queueNodeNotice");async function re(r,e=Date.now()){return Number((await(await h()).prepare("UPDATE deliveries SET canceled_at = ?, updated_at = ? WHERE delivery_id = ? AND canceled_at IS NULL").run(e,e,r)).changes)===1}s(re,"cancelDelivery");async function te(r,e={}){return await c(async t=>{const n=["d.destination_id = ?","d.canceled_at IS NULL","d.state IN ('pending', 'handed_off')"],a=[r];e.senderNodeId!==void 0&&(n.push("m.sender_node_id IS NOT DISTINCT FROM ?"),a.push(e.senderNodeId)),e.kind!==void 0&&(n.push("m.kind = ?"),a.push(e.kind));const d=await t.prepareUncached(`SELECT d.delivery_id FROM deliveries d JOIN messages m ON m.message_id = d.message_id WHERE ${n.join(" AND ")}`).all(...a);if(d.length===0)return[];const i=Date.now();return await t.prepareUncached(`UPDATE deliveries SET canceled_at = ?, updated_at = ? WHERE delivery_id IN (${d.map(()=>"?").join(",")})`).run(i,i,...d.map(o=>o.delivery_id)),d.map(o=>o.delivery_id)})}s(te,"cancelPendingNodeMail");async function ne(r,e){return await c(async t=>{const n=Date.now(),a=await t.prepare(`SELECT target.status AS controller_status FROM waits w LEFT JOIN nodes target ON target.node_id = w.target_id
|
|
8
|
+
WHERE w.node_id = ? AND w.kind = 'controller' AND w.target_id = ? AND w.satisfied_at IS NULL`).get(r,e);if(a===void 0||a.controller_status==="active"||a.controller_status==="idle")return null;const d=await F(r,{kind:"urgent",label:"declared controller is no longer live",bodyJson:{body:`Controller ${e} is no longer live; the declared message wait was cleared.`},urgency:"urgent",wake:1});if(!await A(r,e,n,t))throw new Error(`controller wait changed while notifying ${r}`);return d})}s(ne,"enqueueControllerDeathNotice");export{re as cancelDelivery,te as cancelPendingNodeMail,U as effectiveTier,ne as enqueueControllerDeathNotice,F as enqueueNodeMail,g as finalizeNodeMail,m as insertMessage,Z as listenDeliveryTier,y as newId,ee as queueNodeNotice};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var f=Object.defineProperty;var o=(t,e)=>f(t,"name",{value:e,configurable:!0});import{openDb as a}from"../canvas/db.js";import{get as u}from"../graph/bodies.js";import{heads as s}from"../graph/documents.js";import{getById as d}from"../graph/objects.js";async function D(t){const e=await a(),n=await d(e,t);return n===null||n.type!=="node"?!1:await e.prepare("SELECT 1 FROM objects WHERE owner = ? AND type = 'document' AND kind = 'report' AND deleted_at IS NULL LIMIT 1").get(n.
|
|
2
|
-
ORDER BY created_at DESC, name DESC LIMIT 1`).get(n.
|
|
1
|
+
var f=Object.defineProperty;var o=(t,e)=>f(t,"name",{value:e,configurable:!0});import{openDb as a}from"../canvas/db.js";import{get as u}from"../graph/bodies.js";import{heads as s}from"../graph/documents.js";import{getById as d}from"../graph/objects.js";async function D(t){const e=await a(),n=await d(e,t);return n===null||n.type!=="node"?!1:await e.prepare("SELECT 1 FROM objects WHERE owner = ? AND type = 'document' AND kind = 'report' AND deleted_at IS NULL LIMIT 1").get(n.id)!==void 0}o(D,"hasReportDocuments");async function p(t){const e=await a(),n=await d(e,t);if(!(n===null||n.type!=="node"))return await e.prepare(`SELECT * FROM objects WHERE owner = ? AND type = 'document' AND kind = 'report' AND deleted_at IS NULL
|
|
2
|
+
ORDER BY created_at DESC, name DESC LIMIT 1`).get(n.id)}o(p,"newestReport");async function N(t){const e=await p(t);return e===void 0?null:`${t}/${e.name}`}o(N,"newestReportName");async function h(t){const e=await a(),n=await p(t);if(n===void 0)return"";const r=(await s(e,n))[0];if(r===void 0)return"";try{return u(r.body_hash).trim()}catch{return""}}o(h,"newestReportBody");async function R(t){const e=t.indexOf("/");if(e<=0||!t.startsWith("reports/",e+1))return null;const n=await a(),r=await d(n,t.slice(0,e));if(r===null||r.type!=="node")return null;const i=await n.prepare("SELECT * FROM objects WHERE owner = ? AND type = 'document' AND name = ? AND deleted_at IS NULL").get(r.id,t.slice(e+1)),c=i===void 0?void 0:(await s(n,i))[0];if(c===void 0)return null;try{return u(c.body_hash)}catch{return null}}o(R,"reportBodyByName");export{D as hasReportDocuments,h as newestReportBody,N as newestReportName,R as reportBodyByName};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
var y=Object.defineProperty;var t=(e,r)=>y(e,"name",{value:r,configurable:!0});import{createHash as _}from"node:crypto";import{parseScope as g}from"@north-light/identity";import{openDb as o,withCanvasWrite as S}from"../canvas/db.js";import{isUnsandboxedMachine as T}from"../runtime/unsandboxed.js";const v=["not_started","pending","ready","failed","unavailable"],
|
|
1
|
+
var y=Object.defineProperty;var t=(e,r)=>y(e,"name",{value:r,configurable:!0});import{createHash as _}from"node:crypto";import{parseScope as g}from"@north-light/identity";import{openDb as o,withCanvasWrite as S}from"../canvas/db.js";import{isUnsandboxedMachine as T}from"../runtime/unsandboxed.js";const v=["not_started","pending","ready","failed","unavailable"],m=["ultra","strong","medium","light"];function p(e){if(!Array.isArray(e))throw new TypeError("grant scopes must be a list");return e.map(r=>{if(!r||typeof r!="object"||typeof r.scope!="string"||!["always","ask"].includes(r.mode))throw new TypeError("invalid grant scope entry");return{scope:r.scope,mode:r.mode}})}t(p,"entries");function O(e){if(!e||typeof e!="object"||Array.isArray(e))return null;const{state:r,message:a,next:i,step:n}=e;return typeof r!="string"||!v.includes(r)||a!==void 0&&typeof a!="string"||n!==void 0&&typeof n!="string"||typeof i!="string"||!i?null:{state:r,...a===void 0?{}:{message:a},next:i,...n===void 0?{}:{step:n}}}t(O,"dependencyOf");function E(e){if(!e||typeof e!="object"||Array.isArray(e))return{};const r={};for(const[a,i]of Object.entries(e)){const n=O(i);n&&(r[a]=n)}return r}t(E,"dependenciesOf");function w(e){if(!e||typeof e!="object"||Array.isArray(e))return null;const{base_url:r,rungs:a}=e;if(typeof r!="string"||!r||!a||typeof a!="object"||Array.isArray(a))return null;const i={};for(const n of m){const c=a[n];typeof c=="string"&&c&&(i[n]=c)}return Object.keys(i).length?{base_url:r.replace(/\/+$/,""),rungs:i}:null}t(w,"inferenceEndpointOf");function l(e){return{id:e.id,runtime:e.runtime,sub:e.sub,grantee:e.grantee,rev:e.rev,scopes:p(JSON.parse(e.scopes_json)),resolved_scopes:p(JSON.parse(e.resolved_scopes_json)),spend_cap:e.spend_cap,expires_at:e.expires_at,status:e.status,revoked_at:e.revoked_at,approved_at:e.approved_at,payer:e.payer,dependencies:E(JSON.parse(e.dependencies_json)),run_notice_url:e.run_notice_url??null,inference_endpoint:e.inference_endpoint_json?w(JSON.parse(e.inference_endpoint_json)):null,synced_at:e.synced_at}}t(l,"record");function u(e){if(!e||e.status!=="active")return null;try{return N(l(e))}catch(r){if(r instanceof TypeError||r instanceof SyntaxError)return null;throw r}}t(u,"active");function f(e){return e.grantee!=="app:terminal"&&T()}t(f,"mirrorOnly");async function M(){return(await x()).filter(e=>!f(e))}t(M,"localGrants");async function x(){return(await(await o()).prepare("SELECT * FROM grants").all()).flatMap(e=>{try{return[l(e)]}catch(r){if(r instanceof TypeError||r instanceof SyntaxError)return[];throw r}})}t(x,"allGrants");function R(e){return e.expires_at!==null&&!(Date.parse(e.expires_at)>Date.now())}t(R,"grantExpired");function N(e){if(e.status!=="active"||R(e))return null;try{const r=e.resolved_scopes.map(({scope:a})=>g(a));return{...e,resolved:e.resolved_scopes.flatMap(({mode:a},i)=>a==="always"?[r[i]]:[])}}catch(r){if(r instanceof TypeError||r instanceof SyntaxError)return null;throw r}}t(N,"activeRecord");function d(e){return Array.isArray(e)?`[${e.map(d).join(",")}]`:e&&typeof e=="object"?`{${Object.keys(e).sort().filter(r=>e[r]!==void 0).map(r=>`${JSON.stringify(r)}:${d(e[r])}`).join(",")}}`:JSON.stringify(e)??"null"}t(d,"canonicalJson");function j(e){const r={rev:e.rev,resolved_scopes:e.resolved_scopes,spend_cap:e.spend_cap,payer:e.payer,dependencies:e.dependencies??{},...e.inference_endpoint?{inference_endpoint:e.inference_endpoint}:{}};return _("sha256").update(d(r)).digest("base64url").slice(0,22)}t(j,"grantVersion");async function k(e){return!!await(await o()).prepare("SELECT 1 FROM grants WHERE id = ?").get(e)}t(k,"hasGrant");async function H(e){return await(await o()).prepare("SELECT rev, status FROM grants WHERE id = ?").get(e)??null}t(H,"grantSyncState");async function D(e,r){return await(await o()).prepare("SELECT rev, status FROM grants WHERE grantee = ? AND sub = ?").get(e,r)??null}t(D,"grantSyncStateFor");async function A(e){const r=await(await o()).prepare("SELECT * FROM grants WHERE id = ?").get(e);if(!r)return null;try{return l(r)}catch(a){if(a instanceof TypeError||a instanceof SyntaxError)return null;throw a}}t(A,"grantRecord");async function W(e){return(e?(await A(e))?.payer:null)??"user"}t(W,"payerOfGrant");async function G(e){return u(await(await o()).prepare("SELECT * FROM grants WHERE id = ?").get(e))}t(G,"activeGrant");async function J(e,r){return u(await(await o()).prepare("SELECT * FROM grants WHERE grantee = ? AND sub = ?").get(e,r))}t(J,"grantFor");async function I(e){if(f({grantee:e}))return null;const r=await(await o()).prepare("SELECT * FROM grants WHERE grantee = ? AND status = 'active'").all(e);if(r.length>1)throw new Error(`multiple active grants for ${e}`);return u(r[0])}t(I,"activeGrantForApp");async function U(e){const r=await(await o()).prepare("SELECT run_notice_url AS url, sub, grantee FROM grants WHERE id = ? AND status = 'active'").get(e);return r&&r.url&&!f(r)?{url:r.url,sub:r.sub,grantee:r.grantee}:null}t(U,"runNoticeTarget");async function $(){const e=await(await o()).prepare("SELECT * FROM grants WHERE grantee = 'app:terminal' AND status = 'active'").all();if(e.length>1)throw new Error("multiple active terminal grants");return u(e[0])}t($,"terminalGrant");async function V(){return(await(await o()).prepare("SELECT value FROM runtime_state WHERE key = 'grants_source'").get())?.value??null}t(V,"grantsSource");async function P(e){return(await(await o()).prepare("SELECT value FROM runtime_state WHERE key = 'grants_source'").get())?.value===e}t(P,"hasSyncedGrants");async function X(e){return(await e.prepare("SELECT value FROM runtime_state WHERE key = 'grants_source'").get())?.value!=="local"?0:(await e.prepare("DELETE FROM runtime_state WHERE key = 'grants_source'").run(),Number((await e.prepare("DELETE FROM grants").run()).changes))}t(X,"dropLocalGrantMirror");async function q(e,r,a){const i=new Set;for(const n of e){if(i.has(n.id)||!n.id||!n.runtime||!n.sub||!n.grantee||!Number.isInteger(n.rev)||!["active","revoked","removed"].includes(n.status))throw new TypeError("invalid grant sync response");i.add(n.id),p(n.scopes),p(n.resolved_scopes)}await S(async n=>{await n.exec("DELETE FROM grants");const c=n.prepare(`INSERT INTO grants
|
|
2
2
|
(id, runtime, sub, grantee, rev, scopes_json, resolved_scopes_json, spend_cap, expires_at,
|
|
3
3
|
status, revoked_at, approved_at, payer, dependencies_json, run_notice_url, inference_endpoint_json, synced_at)
|
|
4
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`);for(const s of e)await c.run(s.id,s.runtime,s.sub,s.grantee,s.rev,JSON.stringify(s.scopes),JSON.stringify(s.resolved_scopes),s.spend_cap,s.expires_at,s.status,s.revoked_at,s.approved_at,s.payer,JSON.stringify(E(s.dependencies)),s.run_notice_url??null,s.inference_endpoint?JSON.stringify(s.inference_endpoint):null,s.synced_at);await n.prepare("INSERT INTO runtime_state (key, value) VALUES ('grants_source', ?) ON CONFLICT(key) DO UPDATE SET value = excluded.value").run(a),await n.prepare("INSERT INTO runtime_state (key, value) VALUES ('grants_generation', '1') ON CONFLICT(key) DO UPDATE SET value = CAST(CAST(value AS INTEGER) + 1 AS TEXT)").run()})}t(q,"replaceGrants");async function z(){const e=await(await o()).prepare("SELECT value FROM runtime_state WHERE key = 'grants_generation'").get();return e?Number(e.value):0}t(z,"grantsGeneration");export{G as activeGrant,I as activeGrantForApp,N as activeRecord,x as allGrants,E as dependenciesOf,X as dropLocalGrantMirror,R as grantExpired,J as grantFor,A as grantRecord,H as grantSyncState,D as grantSyncStateFor,j as grantVersion,z as grantsGeneration,V as grantsSource,k as hasGrant,P as hasSyncedGrants,w as inferenceEndpointOf,M as localGrants,f as mirrorOnly,W as payerOfGrant,q as replaceGrants,U as runNoticeTarget,$ as terminalGrant};
|
|
4
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`);for(const s of e)await c.run(s.id,s.runtime,s.sub,s.grantee,s.rev,JSON.stringify(s.scopes),JSON.stringify(s.resolved_scopes),s.spend_cap,s.expires_at,s.status,s.revoked_at,s.approved_at,s.payer,JSON.stringify(E(s.dependencies)),s.run_notice_url??null,s.inference_endpoint?JSON.stringify(s.inference_endpoint):null,s.synced_at);await n.prepare("INSERT INTO runtime_state (key, value) VALUES ('grants_source', ?) ON CONFLICT(key) DO UPDATE SET value = excluded.value").run(a),await n.prepare("INSERT INTO runtime_state (key, value) VALUES ('grants_generation', '1') ON CONFLICT(key) DO UPDATE SET value = CAST(CAST(runtime_state.value AS INTEGER) + 1 AS TEXT)").run()})}t(q,"replaceGrants");async function z(){const e=await(await o()).prepare("SELECT value FROM runtime_state WHERE key = 'grants_generation'").get();return e?Number(e.value):0}t(z,"grantsGeneration");export{G as activeGrant,I as activeGrantForApp,N as activeRecord,x as allGrants,E as dependenciesOf,X as dropLocalGrantMirror,R as grantExpired,J as grantFor,A as grantRecord,H as grantSyncState,D as grantSyncStateFor,j as grantVersion,z as grantsGeneration,V as grantsSource,k as hasGrant,P as hasSyncedGrants,w as inferenceEndpointOf,M as localGrants,f as mirrorOnly,W as payerOfGrant,q as replaceGrants,U as runNoticeTarget,$ as terminalGrant};
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
var R=Object.defineProperty;var s=(n,t)=>R(n,"name",{value:t,configurable:!0});import{covers as S}from"@north-light/identity";import{objectPlace as O,runPlace as x,runsSeeEachOther as N}from"../runs/confinement.js";import{missingOwnMemoryScope as
|
|
2
|
-
SELECT owner, 1 FROM objects WHERE
|
|
1
|
+
var R=Object.defineProperty;var s=(n,t)=>R(n,"name",{value:t,configurable:!0});import{covers as S}from"@north-light/identity";import{objectPlace as O,runPlace as x,runsSeeEachOther as N}from"../runs/confinement.js";import{missingOwnMemoryScope as w}from"./spaces/own-memory.js";import{SPACES as g,identityOf as l}from"./spaces/index.js";import{insideRepo as L}from"./spaces/repo.js";async function C(n,t){return await n.prepare(`WITH RECURSIVE chain(id, depth) AS (
|
|
2
|
+
SELECT owner, 1 FROM objects WHERE id = ? AND owner IS NOT NULL
|
|
3
3
|
UNION ALL
|
|
4
|
-
SELECT o.owner, c.depth + 1 FROM objects o JOIN chain c ON o.
|
|
5
|
-
) SELECT o.* FROM chain c CROSS JOIN objects o WHERE o.
|
|
6
|
-
SELECT 1 FROM objects o JOIN documents d ON d.object = o.
|
|
7
|
-
WHERE o.owner = a.
|
|
8
|
-
ORDER BY a.name = 'crtr', a.name`).all()).filter(i=>f(n,t,i))}s(k,"toolApps");function f(n,t,a){return a.type==="app"}s(f,"mayUseTools");const T=s(n=>n.class!=="app"||n.place!==void 0,"isRun");async function A(n,t,a){const i=`${(await l(n,a)).external_id.replace(/^app:/,"")}:`;return t.some(e=>e.startsWith(i)&&!e.slice(i.length).includes(":"))}s(A,"holdsProviderGroup");async function I(n,t,a){return t.class==="person"?!0:t.class==="object"?t.owner.
|
|
4
|
+
SELECT o.owner, c.depth + 1 FROM objects o JOIN chain c ON o.id = c.id WHERE o.owner IS NOT NULL
|
|
5
|
+
) SELECT o.* FROM chain c CROSS JOIN objects o WHERE o.id = c.id ORDER BY c.depth`).all(t.id)}s(C,"ownerChain");async function P(n,t){return(await o(n,t)).space}s(P,"spaceOf");async function o(n,t){const a=await C(n,t),i=a.length?a[a.length-1]:t,e=g[i.type];if(!e)throw new Error(`${t.type} ${t.id} has no space: its owner chain ends at ${i.type} ${i.id}`);const p=a.length?[...a.slice(0,-1).reverse(),t]:[];return{space:i,path:p,impl:e}}s(o,"locate");async function y(n,t){return t.type!=="document"?!1:(await n.prepare("SELECT source_path FROM documents WHERE object = ?").get(t.id))?.source_path!=null}s(y,"isShipped");async function k(n,t){return(await n.prepare(`SELECT a.* FROM objects a WHERE a.type = 'app' AND a.deleted_at IS NULL AND EXISTS (
|
|
6
|
+
SELECT 1 FROM objects o JOIN documents d ON d.object = o.id
|
|
7
|
+
WHERE o.owner = a.id AND o.type = 'document' AND o.deleted_at IS NULL AND d.source_path IS NOT NULL)
|
|
8
|
+
ORDER BY a.name = 'crtr', a.name`).all()).filter(i=>f(n,t,i))}s(k,"toolApps");function f(n,t,a){return a.type==="app"}s(f,"mayUseTools");const T=s(n=>n.class!=="app"||n.place!==void 0,"isRun");async function A(n,t,a){const i=`${(await l(n,a)).external_id.replace(/^app:/,"")}:`;return t.some(e=>e.startsWith(i)&&!e.slice(i.length).includes(":"))}s(A,"holdsProviderGroup");async function I(n,t,a){return t.class==="person"?!0:t.class==="object"?t.owner.id===a.id:t.class==="app"?t.app.id===a.id||a.type==="profile"&&a.owner===t.app.id:t.app.id===a.id||a.type==="profile"&&t.profile?.id===a.id||a.type==="repo"&&await L(n,t,a,"rw")}s(I,"mayActAs");async function _(n,t,a){if(t.class!=="node"&&!(t.class==="app"&&t.place!==void 0))return!0;const i=t.class==="app"?t.place:await x(t.node.id,n);if(i===null)return!0;const e=await O(a.id,n);return e===null?!i.isolated:N(i,e)}s(_,"customReachable");const h=s(n=>n.type.includes("."),"isCustom");async function J(n,t,a){return await E(n,await o(n,t),t,a)}s(J,"objectsTargets");async function E(n,{space:t,path:a},i,e){const p=[];if(t.type==="person")p.push("user");else if(t.type==="app"&&a.length>0){const c=a[0];if(c.type==="profile")a.length>1&&p.push(`profile:${(await l(n,c)).external_id}`);else if(c.type==="node"||h(c)){const r=(await l(n,t)).external_id;r!==e&&p.push(r)}}return i.type==="node"&&p.push("node"),p}s(E,"targetsOf");async function u(n,t,a,i,e){if(t.class==="person"||t.scopes===null)return!1;const p=t.scopes;if(p.length===0||i.space.type==="app"&&t.app.id===i.space.id)return!1;const c=(await l(n,t.app)).external_id;return(await E(n,i,e,c)).some(r=>{const m=`crtr:objects:${a}:${r}`;return p.some(d=>S(d,m))})}s(u,"holdsInLocated");async function M(n,t,a,i){return t.class==="person"||t.scopes===null?!1:await u(n,t,a,await o(n,i),i)}s(M,"holdsObjectsScope");async function B(n,t,a,i,e){const p=i.owner===null?null:await n.prepareUncached("SELECT * FROM objects WHERE id = ?").get(i.owner)??null;if(p===null)return!1;const c={class:"app",app:t,scopes:a??[]};return await I(n,c,p)?a===null||await M(n,c,"link",e):!1}s(B,"linkAuthorizes");async function Y(n,t,a){return(await U(n,a))(t)}s(Y,"canRead");async function U(n,t){let a=null,i=null;return async e=>{if(e.class==="person")return!0;if(a??=await o(n,t),a.space.type==="app"&&a.path.length>0){if(i??=await y(n,t),i&&f(n,e,a.space))return!0;if(h(t)){if(e.app.id===a.space.id&&!await _(n,e,t))return!1;if(e.app.id!==a.space.id&&e.scopes!==null&&f(n,e,a.space)&&(t.privacy==="public"||T(e)&&await A(n,e.scopes,a.space)))return!0}}return await u(n,e,"read",a,t)||e.class==="object"&&h(e.object)&&await u(n,e,"watch",a,t)?!0:await a.impl.canRead(n,e,a.space,a.path,t)}}s(U,"readCheck");async function z(n,t,a){if(await y(n,a))return!1;const i=await o(n,a);if(await u(n,t,"write",i,a))return!0;const{space:e,path:p,impl:c}=i;return await c.canChange(n,t,e,p,a)}s(z,"canChange");async function G(n,t,a,i){if(t.class==="person")return null;const{space:e,path:p}=await o(n,a);return e.type==="app"&&t.app.id===e.id?await w(n,t,e,p,a,i):null}s(G,"missingMemoryScope");async function V(n,t,a,i){if(t.class==="person")return null;const e=await o(n,a),{space:p}=e;return p.type!=="app"||t.app.id!==p.id?null:await w(n,t,p,e.path.length===0?[a]:[...e.path],null,i)}s(V,"missingMemoryScopeUnder");export{z as canChange,Y as canRead,_ as customReachable,M as holdsObjectsScope,A as holdsProviderGroup,y as isShipped,B as linkAuthorizes,I as mayActAs,f as mayUseTools,G as missingMemoryScope,V as missingMemoryScopeUnder,J as objectsTargets,C as ownerChain,U as readCheck,P as spaceOf,k as toolApps};
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
var $=Object.defineProperty;var l=(e,t)=>$(e,"name",{value:t,configurable:!0});import{createHash as x,randomBytes as J,timingSafeEqual as P}from"node:crypto";import{CrtrError as j,usage as f}from"../errors.js";import{ExitCode as S}from"../../types.js";import{createObject as q,liveDocumentNamed as F}from"./objects.js";import{invalidateCustomKind as A}from"./kinds/registry.js";import{customReachable as D,mayActAs as k}from"./access.js";import{publish as O,HOP_LIMIT as M,HopLimitError as B}from"./events.js";import{checkoutsForCwd as N}from"./repo-sync/repos.js";import{onQueueSignal as K,signalQueue as b}from"./receivers.js";import{receiverEndpoint as V,isPublicReceiverAddress as G}from"./receiver-url.js";import{isIP as Q}from"node:net";import{KIND as L,LOCAL as H,MAX_KIND_EVENTS as Y,RESERVED_KIND_ROOTS as z,eventCatalogReasons as X}from"../plugin-objects-manifest.js";const Z=["public","friends","private"];function h(e,t){throw new j(e,t,S.GENERAL)}l(h,"conflict");function R(e){return x("sha256").update(e).digest("hex")}l(R,"hash");function I(){return`crtr_pub_${J(32).toString("base64url")}`}l(I,"issueToken");function ee(e){if(e==null)return null;if(e==="queue")return JSON.stringify(e);if(typeof e!="object"||Array.isArray(e))throw f("invalid custom receiver; expected queue, an https url, or argv and absolute cwd");if("url"in e&&typeof e.url=="string")try{const i=V(e.url).hostname.replace(/^\[|\]$/g,"");if(Q(i)&&!G(i))throw new Error("non-public IP address");return JSON.stringify({url:e.url})}catch(t){throw f(`invalid custom receiver: ${String(t)}`)}if("argv"in e&&Array.isArray(e.argv)&&e.argv.length>0&&e.argv.every(t=>typeof t=="string")&&typeof e.cwd=="string"&&e.cwd.startsWith("/"))return JSON.stringify(e);throw f("invalid custom receiver; url must be https and argv requires a command and absolute cwd")}l(ee,"receiverJson");async function
|
|
2
|
-
VALUES (?, ?, ?, ?)`).run(c.
|
|
3
|
-
WHERE destination_id = ? AND state = 'pending' AND canceled_at IS NULL`).run(c,c,
|
|
4
|
-
WHERE destination_id = ? AND state = 'pending' AND canceled_at IS NULL`).run(m==='"queue"'?null:c,c,
|
|
5
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, 1)`).run(i,n.
|
|
6
|
-
UNION ALL SELECT depth FROM message_causes WHERE message_id = ? LIMIT 1`).get(u,u);if(u!==null&&d===void 0)throw new j("unknown_cause",`no message ${u}`,S.USAGE);if(d&&d.depth>=M)throw new B(d.depth+1);const
|
|
7
|
-
`)[0],t.
|
|
1
|
+
var $=Object.defineProperty;var l=(e,t)=>$(e,"name",{value:t,configurable:!0});import{createHash as x,randomBytes as J,timingSafeEqual as P}from"node:crypto";import{CrtrError as j,usage as f}from"../errors.js";import{ExitCode as S}from"../../types.js";import{createObject as q,liveDocumentNamed as F}from"./objects.js";import{invalidateCustomKind as A}from"./kinds/registry.js";import{customReachable as D,mayActAs as k}from"./access.js";import{publish as O,HOP_LIMIT as M,HopLimitError as B}from"./events.js";import{checkoutsForCwd as N}from"./repo-sync/repos.js";import{onQueueSignal as K,signalQueue as b}from"./receivers.js";import{receiverEndpoint as V,isPublicReceiverAddress as G}from"./receiver-url.js";import{isIP as Q}from"node:net";import{KIND as L,LOCAL as H,MAX_KIND_EVENTS as Y,RESERVED_KIND_ROOTS as z,eventCatalogReasons as X}from"../plugin-objects-manifest.js";const Z=["public","friends","private"];function h(e,t){throw new j(e,t,S.GENERAL)}l(h,"conflict");function R(e){return x("sha256").update(e).digest("hex")}l(R,"hash");function I(){return`crtr_pub_${J(32).toString("base64url")}`}l(I,"issueToken");function ee(e){if(e==null)return null;if(e==="queue")return JSON.stringify(e);if(typeof e!="object"||Array.isArray(e))throw f("invalid custom receiver; expected queue, an https url, or argv and absolute cwd");if("url"in e&&typeof e.url=="string")try{const i=V(e.url).hostname.replace(/^\[|\]$/g,"");if(Q(i)&&!G(i))throw new Error("non-public IP address");return JSON.stringify({url:e.url})}catch(t){throw f(`invalid custom receiver: ${String(t)}`)}if("argv"in e&&Array.isArray(e.argv)&&e.argv.length>0&&e.argv.every(t=>typeof t=="string")&&typeof e.cwd=="string"&&e.cwd.startsWith("/"))return JSON.stringify(e);throw f("invalid custom receiver; url must be https and argv requires a command and absolute cwd")}l(ee,"receiverJson");async function Ee(e,t,i){const{kind:n,name:a,owner:s,description:o,events:u,receiver:d,rotateToken:w,privacy:p}=i;if(p!==void 0&&!Z.includes(p))throw f(`invalid privacy ${JSON.stringify(p)}`);if(await k(e,t,s)||h("forbidden",`cannot act as ${s.id}`),!L.test(n)||z.includes(n.split(".")[0]))throw f(`invalid or reserved kind ${n}`);if(!a.trim()||a!==a.trim()||a.includes("\0"))throw f(`invalid object name ${JSON.stringify(a)}`);const m=ee(d);if(d!=="queue"&&d!==null&&d!==void 0&&"argv"in d&&t.class!=="person"&&t.class!=="node"&&h("argv_forbidden","argv receiver requires a person or node principal"),u===void 0){const c=await e.prepare("SELECT source FROM object_kinds WHERE name = ?").get(n);if(c?.source!=="manifest"&&c?.source!=="peer")throw f("events is required unless the kind is declared by an installed plugin")}else if(Object.keys(u).length>Y||Object.entries(u).some(([c,_])=>!H.test(c)||!Number.isInteger(_?.level)||_.level<1||_.level>10||_.supersedes!==void 0&&typeof _.supersedes!="boolean"||_.ends_wait!==void 0&&typeof _.ends_wait!="boolean"))throw f("invalid custom event catalog");const r=await F(e,s.id,a);if(r&&!await D(e,t,r)&&h("forbidden",`cannot act as ${s.id}`),r&&t.class!=="person"&&t.class!=="node"){const c=(await e.prepare("SELECT receiver_json FROM custom_objects WHERE object = ?").get(r.id))?.receiver_json;c&&typeof JSON.parse(c)=="object"&&"argv"in JSON.parse(c)&&h("argv_forbidden","argv receiver requires a person or node principal")}r&&r.type!==n&&h("name_taken",`${s.name}/${a} is already held by ${r.id}`);const g=u===void 0?null:await te(e,{name:n,owner:s,description:o,events:u,read:null,source:"register"});if(!r){const c=await q(e,{type:n,kind:null,owner:s.id,privacy:p??"public",name:a,preview:""}),_=I();return await e.prepare(`INSERT INTO custom_objects (object, description, receiver_json, token_hash)
|
|
2
|
+
VALUES (?, ?, ?, ?)`).run(c.id,o,m,R(_)),t.class==="node"&&await e.prepare("UPDATE custom_objects SET registered_by = ? WHERE object = ?").run(t.node.id,c.id),m!==null&&await e.prepare("UPDATE objects SET reception = 2 WHERE id = ?").run(c.id),await O(e,{event:"created",object:c,actor:t.class==="object"?t.object:t.class==="person"?t.person:t.class==="app"?t.app:t.node,attrs:{}},async C=>await N(e,C)),{object:c,token:_,created:!0,changed:[]}}const v=await e.prepare("SELECT description, receiver_json FROM custom_objects WHERE object = ?").get(r.id);v||h("name_taken",`${s.name}/${a} is not a custom object`);const E=[];if(v.description!==o&&E.push("description"),v.receiver_json!==m&&E.push("receiver"),g?.changed.includes("events")&&E.push("events"),g?.changed.includes("description")&&!E.includes("description")&&E.push("description"),p!==void 0&&r.privacy!==p&&E.push("privacy"),w&&E.push("token"),E.length===0)return{object:r,created:!1,changed:E};const y=w?I():void 0,T=E.includes("privacy")?{...r,privacy:p}:r;if(T!==r&&await e.prepare("UPDATE objects SET privacy = ? WHERE id = ?").run(p,r.id),await e.prepare("UPDATE custom_objects SET description = ?, receiver_json = ?, token_hash = COALESCE(?, token_hash) WHERE object = ?").run(o,m,y===void 0?null:R(y),r.id),await e.prepare("UPDATE objects SET reception = ? WHERE id = ?").run(m===null?0:2,r.id),v.receiver_json!==m){const c=Date.now();if(m===null){const _=await e.prepare(`UPDATE deliveries SET canceled_at = ?, updated_at = ?
|
|
3
|
+
WHERE destination_id = ? AND state = 'pending' AND canceled_at IS NULL`).run(c,c,r.id);await e.prepare("UPDATE custom_objects SET dropped = dropped + ? WHERE object = ?").run(_.changes,r.id)}else await e.prepare(`UPDATE deliveries SET next_attempt_at = ?, updated_at = ?
|
|
4
|
+
WHERE destination_id = ? AND state = 'pending' AND canceled_at IS NULL`).run(m==='"queue"'?null:c,c,r.id);b(r.id)}return w&&b(r.id),await O(e,{event:"configured",object:T,actor:t.class==="object"?t.object:t.class==="person"?t.person:t.class==="app"?t.app:t.node,attrs:{changed:E.join(",")}},async c=>await N(e,c)),{object:T,...y===void 0?{}:{token:y},created:!1,changed:E}}l(Ee,"registerCustomObject");async function te(e,t){const{name:i,owner:n,description:a,events:s,read:o,source:u}=t;if(!L.test(i))throw f(`invalid kind ${i}`);if(X(s,i).length>0)throw f("invalid custom event catalog");const d=await e.prepare("SELECT owner, description, events_json, read_json, source, declared FROM object_kinds WHERE name = ?").get(i),w=W(s),p=u==="manifest"&&o!==null?JSON.stringify({command:o.command}):null,m=new Date().toISOString();if(!d)return await e.prepare(`INSERT INTO object_kinds (name, owner, description, events_json, created_at, updated_at, read_json, source, declared)
|
|
5
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, 1)`).run(i,n.id,a,w,m,m,p,u),A(e,i),{outcome:"inserted",changed:[]};const r=d.owner===n.id;if(u==="peer"){if(d.source!=="peer")return{outcome:"skipped",changed:[]}}else if(d.source!=="peer"&&(r||h("kind_owned",`${i} belongs to another owner`),u==="register"&&d.source==="manifest"))return{outcome:"skipped",changed:[]};const g=[];return W(JSON.parse(d.events_json))!==w&&g.push("events"),d.description!==a&&g.push("description"),(d.read_json??null)!==p&&g.push("read"),g.length===0&&r&&d.source===u&&d.declared===1?{outcome:"unchanged",changed:g}:(await e.prepare("UPDATE object_kinds SET owner = ?, description = ?, events_json = ?, read_json = ?, source = ?, declared = 1, updated_at = ? WHERE name = ?").run(n.id,a,w,p,u,m,i),A(e,i),{outcome:"updated",changed:g})}l(te,"upsertKind");async function _e(e,t,i,n){const a=await e.prepare("SELECT events_json FROM object_kinds WHERE name = ?").get(t.type);if(!a||t.deleted_at!==null)throw f(`${t.id} is not a live custom object`);const s=JSON.parse(a.events_json);if(!H.test(n.event)||!Object.hasOwn(s,n.event))throw new j("unknown_event",`${t.type} declares ${Object.keys(s).join(", ")}, not ${n.event}`,S.USAGE,{declared:Object.keys(s),event:n.event});if(typeof n.summary!="string")throw f("summary must be text");const o=n.state===void 0?null:JSON.stringify(n.state);if(n.state!==void 0&&o===void 0)throw f("state must be JSON-serializable");if(Buffer.byteLength(JSON.stringify({summary:n.summary,...n.state===void 0?{}:{state:n.state}}))>64*1024)throw new j("body_too_large","custom event summary and state exceed 64 KiB",S.USAGE);if(o!==null&&Buffer.byteLength(o)>64*1024)throw f("state exceeds 64 KiB");const u=n.cause??null,d=u===null?null:await e.prepare(`SELECT depth FROM messages WHERE message_id = ?
|
|
6
|
+
UNION ALL SELECT depth FROM message_causes WHERE message_id = ? LIMIT 1`).get(u,u);if(u!==null&&d===void 0)throw new j("unknown_cause",`no message ${u}`,S.USAGE);if(d&&d.depth>=M)throw new B(d.depth+1);const w=new Date().toISOString();return await e.prepare("UPDATE custom_objects SET summary = ?, state_json = ?, published_at = ? WHERE object = ?").run(n.summary,o,w,t.id),await e.prepare("UPDATE objects SET preview = ? WHERE id = ?").run(n.summary.split(`
|
|
7
|
+
`)[0],t.id),await O(e,{event:`${t.type}.${n.event}`,object:t,actor:i,attrs:{},messageBody:{summary:n.summary,...n.state===void 0?{}:{state:n.state}},...n.cause===void 0?{}:{cause:n.cause}},async p=>await N(e,p))}l(_e,"publishCustom");async function we(e,t,i){if(t.deleted_at!==null)return;await O(e,{event:"deleted",object:t,actor:i,attrs:{}},async a=>await N(e,a));const n=new Date().toISOString();await e.prepare("UPDATE objects SET deleted_at = ?, reception = 0 WHERE id = ?").run(n,t.id),await e.prepare("UPDATE deliveries SET canceled_at = ?, updated_at = ? WHERE destination_id = ? AND state = 'pending' AND canceled_at IS NULL").run(Date.now(),Date.now(),t.id),b(t.id)}l(we,"unregisterCustomObject");function W(e){return JSON.stringify(Object.fromEntries(Object.entries(e).sort(([t],[i])=>t.localeCompare(i)).map(([t,i])=>[t,{level:i.level,...i.supersedes===void 0?{}:{supersedes:i.supersedes},...i.ends_wait===void 0?{}:{ends_wait:i.ends_wait}}])))}l(W,"canonicalEvents");async function ge(e,t,i=0){return await U(e,t.id,i,"pending")}l(ge,"pendingFor");async function he(e,t){const i=await e.prepare("SELECT destination_id FROM deliveries WHERE delivery_id = ?").get(t);return i?(await U(e,i.destination_id,-1,"handed_off")).find(n=>n.delivery_id===t)??null:null}l(he,"pushLineFor");async function U(e,t,i,n){return(await e.prepare(`SELECT d.delivery_id, m.message_id, m.seq, m.event, m.level, m.object_id, m.actor_id, m.body_json, m.body_ref, m.depth, m.created_at,
|
|
8
8
|
o.type, o.name, owner.id AS owner_id
|
|
9
9
|
FROM deliveries d JOIN messages m ON m.message_id = d.message_id JOIN objects o ON o.id = m.object_id
|
|
10
|
-
LEFT JOIN objects owner ON owner.
|
|
11
|
-
WHERE d.destination_id = ? AND d.state = ? AND d.canceled_at IS NULL AND m.seq > ? ORDER BY m.seq`).all(t,n,i)).map(s=>{const o=s.body_json?JSON.parse(s.body_json):{};return{delivery_id:s.delivery_id,message_id:s.message_id,seq:s.seq,event:s.event,level:s.level,object:{id:s.object_id,type:s.type,name:s.name,owner:s.owner_id},actor:s.actor_id,attrs:o.push?.attrs??{},...o.summary===void 0?{}:{summary:o.summary},...o.state===void 0?{}:{state:o.state},...o.push?.pointer===void 0?{}:{pointer:o.push.pointer},depth:s.depth,created_at:s.created_at}})}l(U,"queueLines");async function ve(e,t,i){const n=Date.now(),
|
|
12
|
-
WHERE delivery_id = ? AND destination_id = ? AND state = 'pending' AND canceled_at IS NULL`).run(n,n,o,t.id);Number(u.changes)?s++:
|
|
10
|
+
LEFT JOIN objects owner ON owner.id = o.owner
|
|
11
|
+
WHERE d.destination_id = ? AND d.state = ? AND d.canceled_at IS NULL AND m.seq > ? ORDER BY m.seq`).all(t,n,i)).map(s=>{const o=s.body_json?JSON.parse(s.body_json):{};return{delivery_id:s.delivery_id,message_id:s.message_id,seq:s.seq,event:s.event,level:s.level,object:{id:s.object_id,type:s.type,name:s.name,owner:s.owner_id},actor:s.actor_id,attrs:o.push?.attrs??{},...o.summary===void 0?{}:{summary:o.summary},...o.state===void 0?{}:{state:o.state},...o.push?.pointer===void 0?{}:{pointer:o.push.pointer},depth:s.depth,created_at:s.created_at}})}l(U,"queueLines");async function ve(e,t,i){const n=Date.now(),a=[];let s=0;for(const o of i){const u=await e.prepare(`UPDATE deliveries SET state = 'acknowledged', acknowledged_at = ?, updated_at = ?
|
|
12
|
+
WHERE delivery_id = ? AND destination_id = ? AND state = 'pending' AND canceled_at IS NULL`).run(n,n,o,t.id);Number(u.changes)?s++:a.push(o)}return{acknowledged:s,...a.length?{unknown:a}:{}}}l(ve,"acknowledge");async function ye(e,t,i){const n=await e.prepare("SELECT token_hash FROM custom_objects WHERE object = ?").get(t.id),a=Buffer.from(n?.token_hash??"".padEnd(64,"0"),"hex"),s=Buffer.from(R(i),"hex");return i.startsWith("crtr_pub_")&&t.deleted_at===null&&a.length===s.length&&P(a,s)&&n?.token_hash!=null}l(ye,"verifyPublishToken");export{ve as acknowledge,D as customReachable,k as mayActAs,K as onQueueSignal,ge as pendingFor,_e as publishCustom,he as pushLineFor,Ee as registerCustomObject,we as unregisterCustomObject,te as upsertKind,ye as verifyPublishToken};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
var u=Object.defineProperty;var
|
|
2
|
-
WHERE i.scheme = 'profile' AND i.external_id = ? AND o.type = 'profile' AND o.deleted_at IS NULL`).get(t);return
|
|
3
|
-
SELECT
|
|
4
|
-
UNION SELECT o.
|
|
5
|
-
SELECT o.* FROM objects o JOIN sub ON sub.
|
|
6
|
-
WHERE e.type = 'links-to' AND e.dst = ? AND s.deleted_at IS NULL`);for(let
|
|
1
|
+
var u=Object.defineProperty;var r=(e,t)=>u(e,"name",{value:t,configurable:!0});import{hasUnreconciledWorktree as f}from"../canvas/worktrees.js";import{deleteDocument as O}from"./documents.js";import{publish as d}from"./events.js";import{getById as s}from"./objects.js";import{rememberDeletedIsolated as R}from"../runs/confinement.js";import{withCanvasWrite as c}from"../canvas/db.js";async function j(e,t){if(t.type!=="node")throw new Error(`deleteNodeWithOwned: ${t.id} is a ${t.type}, not a node`);if(await f(t.id))throw new Error(`refusing to delete node ${t.id}: its managed worktree is not reconciled`);await c(async()=>await m(e,t),{savepoint:!0})}r(j,"deleteNodeWithOwned");async function I(e,t){const i=await e.prepare(`SELECT o.* FROM identities i JOIN objects o ON o.id = i.object
|
|
2
|
+
WHERE i.scheme = 'profile' AND i.external_id = ? AND o.type = 'profile' AND o.deleted_at IS NULL`).get(t);return i?(await c(async()=>{await w(e,i),await e.prepare("UPDATE objects SET deleted_at = ?, name = ? WHERE id = ?").run(new Date().toISOString(),`${i.name}.deleted-${i.id}`,i.id),await d(e,{event:"deleted",object:await s(e,i.id),actor:null,attrs:{}}),await e.prepare("DELETE FROM watches WHERE object = ? OR watcher = ?").run(i.id,i.id)},{savepoint:!0}),!0):!1}r(I,"deleteProfileWithOwned");async function m(e,t){const i=await w(e,t);await e.prepare("UPDATE objects SET deleted_at = ? WHERE id = ?").run(i,t.id),await d(e,{event:"deleted",object:await s(e,t.id),actor:null,attrs:{}}),await e.prepare("DELETE FROM watches WHERE object = ? OR watcher = ?").run(t.id,t.id),await R(t.id,e),await e.prepare("UPDATE nodes SET run_id = NULL WHERE run_id = ? AND node_id != ? AND isolated = 0").run(t.id,t.id),await e.prepare("DELETE FROM nodes WHERE node_id = ?").run(t.id)}r(m,"deleteInside");async function w(e,t){const i=await e.prepare(`WITH RECURSIVE sub(id) AS (
|
|
3
|
+
SELECT id FROM objects WHERE owner = ?
|
|
4
|
+
UNION SELECT o.id FROM objects o JOIN sub ON o.owner = sub.id)
|
|
5
|
+
SELECT o.* FROM objects o JOIN sub ON sub.id = o.id WHERE o.deleted_at IS NULL`).all(t.id),o=new Set(i.map(a=>a.id)),l=e.prepare(`SELECT e.src FROM edges e JOIN objects s ON s.id = e.src
|
|
6
|
+
WHERE e.type = 'links-to' AND e.dst = ? AND s.deleted_at IS NULL`);for(let a=!0;a;){a=!1;for(const n of i)n.type!=="document"||!o.has(n.id)||(await l.all(n.id)).some(({src:p})=>!o.has(p))&&(o.delete(n.id),a=!0)}const E=new Date().toISOString();for(const a of i)if(o.has(a.id)){if(a.type==="document"){await O(e,null,a);continue}await e.prepare("UPDATE objects SET deleted_at = ? WHERE id = ?").run(E,a.id),await d(e,{event:"deleted",object:await s(e,a.id),actor:null,attrs:{}}),await e.prepare("DELETE FROM watches WHERE object = ? OR watcher = ?").run(a.id,a.id)}return E}r(w,"deleteOwned");export{j as deleteNodeWithOwned,I as deleteProfileWithOwned};
|
|
@@ -132,7 +132,7 @@ export declare function restoreDocument(db: CanvasDb, doc: ObjectRow, name: stri
|
|
|
132
132
|
* no other live document links to. Each one deleted re-checks what it linked to, so chains of
|
|
133
133
|
* kept documents collapse; a cycle of kept documents keeps itself. Call it after a document
|
|
134
134
|
* stops linking to `targets` — it was deleted, or an edit dropped the links. */
|
|
135
|
-
export declare function collectUnlinked(db: CanvasDb, targets: Iterable<
|
|
135
|
+
export declare function collectUnlinked(db: CanvasDb, targets: Iterable<string>, reposFn?: ReposFn): Promise<void>;
|
|
136
136
|
export interface ImportedRevision {
|
|
137
137
|
rev_id?: string;
|
|
138
138
|
body_hash: string;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
var oe=Object.defineProperty;var s=(
|
|
2
|
-
WHERE rp.child = ? ORDER BY p.rev_id`).all(n.
|
|
3
|
-
AND NOT EXISTS (SELECT 1 FROM revision_parents p WHERE p.parent = r.
|
|
4
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?) RETURNING *`).get(n.
|
|
1
|
+
var oe=Object.defineProperty;var s=(t,n)=>oe(t,"name",{value:n,configurable:!0});import{randomUUID as se}from"node:crypto";import{CrtrError as v,notFound as N,usage as p}from"../errors.js";import{ExitCode as R}from"../../types.js";import{canChange as j,canRead as P,missingMemoryScope as ce,missingMemoryScopeUnder as ue,ownerChain as we}from"./access.js";import{bodyOf as pe,get as le,put as B}from"./bodies.js";import{dropUnresolved as me,linksOf as de,recordActedOn as g,setLinks as G,setUnresolved as fe,unresolvedLinksCouldName as he}from"./edges.js";import{publish as x}from"./events.js";import{resolveName as ye}from"./names.js";import{createObject as Ee,getById as m}from"./objects.js";import{liveLookups as _e,readerForNode as ve,readerForObject as Ne}from"./reader.js";import{replaceRules as K,setRulesOwner as Re}from"./rules.js";import{recordWatch as I}from"./watches.js";import{withCanvasWrite as h}from"../canvas/db.js";import{filterAsync as q,forEachAsync as ge,mapAsync as S}from"../async-array.js";function E(t){return t.class==="node"?t.node:t.class==="app"?t.app:t.class==="object"?t.object:t.person}s(E,"actorOf");function Se(t,n){return new v("conflict",t,R.GENERAL,n)}s(Se,"conflict");function y(t){if(t.type!=="document")throw p(`${t.type} ${t.id} is not a document`)}s(y,"assertDocument");async function Y(t,n){const e=await we(t,n);return(e.length?e[e.length-1]:n).type}s(Y,"spaceType");async function $(t,n,e){if(e!=="public"&&await Y(t,n)==="repo")throw p(`a repo owns only public documents; ${n.name} cannot own a ${e} one`,{rule:"repo-public-only",next:"Write it as public, or give it another owner (your own documents can carry `if: {repo: <handle>}`)."})}s($,"assertPublicInRepo");async function H(t,n,e,i){if(e.trim()===""||e!==e.trim())throw p(`invalid document name ${JSON.stringify(e)}`);const a=await t.prepare("SELECT id FROM objects WHERE (type = 'document' OR strpos(type, '.') > 0) AND owner = ? AND name = ? AND deleted_at IS NULL AND home_machine IS NULL").get(n.id,e);if(a&&a.id!==i?.id)throw Se(`${n.name} already has a document named ${e}`,{name:e,holder:a.id})}s(H,"assertNameFree");async function U(t,n,e){if(!await P(t,n,e))throw N(`no document ${e.id}`)}s(U,"readable");function V(t){return new v("scope_missing",`missing scope ${t}`,R.GENERAL,{scope:t})}s(V,"scopeMissing");async function T(t,n,e){await U(t,n,e);const{source_path:i}=await O(t,e);if(i!==null)throw new v("forbidden",`${e.name} is a built-in document shipped by a package (served from ${i}); \`crtr doc\` cannot change it`,R.GENERAL,{id:e.id,next:"Edit it in the source repository of the package that ships it (for crtr's own documents, the crouter repo), not with `crtr doc`."});const a=await ce(t,n,e,"rw");if(a!==null)throw V(a);if(!await j(t,n,e))throw new v("forbidden",`you cannot change ${e.name}`,R.GENERAL,{id:e.id})}s(T,"changeable");async function X(t,n){const e=await t.prepare(`SELECT p.rev_id FROM revision_parents rp JOIN revisions p ON p.rev_id = rp.parent
|
|
2
|
+
WHERE rp.child = ? ORDER BY p.rev_id`).all(n.rev_id);return{rev_id:n.rev_id,seq:n.seq,number:n.number,body_hash:n.body_hash,author:n.author,rationale:n.rationale,verbatim:n.verbatim===1,created_at:n.created_at,parents:e.map(i=>i.rev_id)}}s(X,"toRevision");async function C(t,n){const e=await t.prepare(`SELECT * FROM revisions r WHERE r.document = ?
|
|
3
|
+
AND NOT EXISTS (SELECT 1 FROM revision_parents p WHERE p.parent = r.rev_id) ORDER BY r.number DESC, r.rev_id`).all(n.id);return await S(e,async i=>await X(t,i))}s(C,"heads");function Oe(t){return t.map(n=>n.rev_id).sort().join(",")}s(Oe,"headsKeyOf");async function O(t,n){const e=await t.prepare("SELECT * FROM documents WHERE object = ?").get(n.id);if(!e)throw N(`no document record for ${n.id}`);return{summary:e.summary,heads_key:e.heads_key,revision:e.revision,why_it_exists:e.why_it_exists,unlisted:e.unlisted===1,lint_ignore:e.lint_ignore_json===null?null:JSON.parse(e.lint_ignore_json),extensions:e.extensions_json===null?null:JSON.parse(e.extensions_json),source_path:e.source_path}}s(O,"documentRecord");async function A(t,n,e){const i=await t.prepare(`INSERT INTO revisions (document, rev_id, number, body_hash, author, rationale, verbatim, created_at)
|
|
4
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?) RETURNING *`).get(n.id,e.rev_id??se(),e.number,e.body_hash,e.author?.id??null,e.rationale,e.verbatim?1:0,e.created_at??new Date().toISOString()),a=t.prepare("INSERT INTO revision_parents (child, parent) VALUES (?, ?)");for(const r of e.parents)await a.run(i.rev_id,r);return i}s(A,"insertRevision");function De(t){const n=new Set;for(const e of t.matchAll(/\[\[([^[\]\n]+?)\]\]/g))n.add(e[1].trim());return[...n]}s(De,"linksIn");async function z(t,n,e){const i=[],a=[];for(const r of e){const o=await ye(t,n,r);"object"in o?i.push({written_as:r,dst:o.object}):"deleted"in o?i.push({written_as:r,dst:o.deleted}):"remote"in o||a.push(r)}return{links:i,unresolved:a}}s(z,"resolveLinks");async function Q(t,n,e,i){const{links:a,unresolved:r}=await z(t,n,De(i));return await ae(t,await G(t,e,a)),await fe(t,e,r),r}s(Q,"setRevisionLinks");async function W(t,n,e){const i=new Map;for(const{src:a,name:r}of await he(t,n.name,n.id))i.set(a,[...i.get(a)??[],r]);for(const[a,r]of i){const o=await m(t,a),c=o?.owner==null?null:await m(t,o.owner);if(!o||o.deleted_at||o.home_machine!==null||!c||c.deleted_at)continue;const u=c.type==="node"?await ve(t,c.id,e??(async()=>[]),_e(t),!0):await Ne(t,o,e),w=(await z(t,u,r)).links.filter(l=>l.dst.id===n.id);w.length!==0&&(await G(t,o,[...await de(t,o),...w]),await me(t,o,w.map(l=>l.written_as)))}}s(W,"linkNewlyNamed");async function ke(t,n,e){return n.type==="node"?n.id:await t.prepare(`SELECT 1 FROM objects o JOIN objects d ON d.owner = o.id
|
|
5
5
|
WHERE o.name = ? AND o.type <> ? AND o.type IN ('person','app','repo','profile')
|
|
6
|
-
AND d.type = 'document' AND d.name = ? AND d.deleted_at IS NULL LIMIT 1`).get(n.name,n.type,
|
|
7
|
-
WHERE e.type = 'links-to' AND e.src = ? AND e.written_as IS NOT NULL`).all(n.
|
|
8
|
-
WHERE d.
|
|
9
|
-
AND NOT EXISTS (SELECT 1 FROM edges e JOIN objects s ON s.
|
|
10
|
-
WHERE e.type = 'links-to' AND e.dst = d.
|
|
6
|
+
AND d.type = 'document' AND d.name = ? AND d.deleted_at IS NULL LIMIT 1`).get(n.name,n.type,e)?`${n.type}:${n.name}`:n.name}s(ke,"ownerPrefix");async function Z(t,n,e){const i=await t.prepare(`SELECT e.written_as, o.* FROM edges e JOIN objects o ON o.id = e.dst
|
|
7
|
+
WHERE e.type = 'links-to' AND e.src = ? AND e.written_as IS NOT NULL`).all(n.id);if(i.length===0)return e;const a=new Map;for(const r of i){if(r.deleted_at||r.written_as===r.id)continue;const o=!r.written_as.includes("/");if(o&&r.name===r.written_as)continue;const c=r.owner===null?null:await m(t,r.owner),u=c?`${await ke(t,c,r.name)}/${r.name}`:r.name,w=o&&r.owner===n.owner?r.name:u;w!==r.written_as&&a.set(r.written_as,w)}return a.size===0?e:e.replace(/\[\[([^[\]\n]+?)\]\]/g,(r,o)=>{const c=a.get(o.trim());return c===void 0?r:`[[${c}]]`})}s(Z,"withCurrentNames");async function M(t,n,e){if(e.preview!==void 0){if(e.preview.trim()==="")throw p("a document needs a preview",{field:"preview"});await t.prepare("UPDATE objects SET preview = ? WHERE id = ?").run(e.preview,n.id)}e.privacy!==void 0&&(await $(t,await m(t,n.owner),e.privacy),await t.prepare("UPDATE objects SET privacy = ? WHERE id = ?").run(e.privacy,n.id));const i=s(async(r,o)=>await t.prepareUncached(`UPDATE documents SET ${r} = ? WHERE object = ?`).run(o,n.id),"set");e.summary!==void 0&&await i("summary",e.summary),e.whyItExists!==void 0&&await i("why_it_exists",e.whyItExists),e.unlisted!==void 0&&await i("unlisted",e.unlisted?1:0),e.lintIgnore!==void 0&&await i("lint_ignore_json",e.lintIgnore===null?null:JSON.stringify(e.lintIgnore)),e.extensions!==void 0&&await i("extensions_json",e.extensions===null?null:JSON.stringify(e.extensions));const a=await m(t,n.id);return e.rules!==void 0&&await K(t,a,e.rules),a}s(M,"applyDocumentFields");async function b(t,n,e){if(n.owner.deleted_at)throw p(`${n.owner.name} is deleted`);if(n.preview.trim()==="")throw p("a document needs a preview",{field:"preview"});await $(t,n.owner,n.privacy),await H(t,n.owner,n.name);const i=await Ee(t,{...n.id?{id:n.id}:{},type:"document",kind:n.kind,owner:n.owner.id,privacy:n.privacy,name:n.name,preview:n.preview});await t.prepare("INSERT INTO documents (object, heads_key, revision) VALUES (?, '', 0)").run(i.id);const a=await M(t,i,{...n,preview:void 0,privacy:void 0,rules:n.rules??[]});return await W(t,a,e),a}s(b,"createDocument");async function F(t,n){const e=await C(t,n),i=Oe(e),a=Math.max(0,...e.map(r=>r.number));return await t.prepare("UPDATE documents SET heads_key = ?, revision = ? WHERE object = ?").run(i,a,n.id),{heads_key:i,revision:a,headCount:e.length}}s(F,"setHeads");async function Ke(t,n,e,i,a){const r=B(i);return await h(async()=>{const o=E(n),c=await ue(t,n,e.owner,"rw");if(c!==null)throw V(c);const u=await b(t,e,a),w=await A(t,u,{number:1,body_hash:r,author:o,rationale:null,parents:[]}),{heads_key:l}=await F(t,u);if(!await j(t,n,u))throw N(`no owner ${e.owner.name} you can write to`);const d=await Q(t,n,u,i);return await g(t,o,u),await I(t,o,u,"write",{readHeadsKey:l}),await x(t,{event:"created",object:u,actor:o,attrs:{revision:1},pointer:w.rev_id},a),{object:u,revision:1,unresolved:d}},{savepoint:!0})}s(Ke,"writeDocument");async function qe(t,n,e){return(await t.prepare("SELECT read_heads_key FROM watches WHERE watcher = ? AND object = ?").get(E(n).id,e.id))?.read_heads_key??null}s(qe,"readBase");function xe(t,n){let e=t;for(const[i,{old:a,new:r}]of n.entries()){if(a==="")throw p(`block ${i+1}: a replacement needs non-empty old text`,{field:"replace"});const o=e.indexOf(a);if(o<0)throw p(`block ${i+1}: old text not found: ${JSON.stringify(a.slice(0,120))}`,{field:"replace",old:a});if(e.indexOf(a,o+1)>=0)throw p(`block ${i+1}: old text occurs more than once: ${JSON.stringify(a.slice(0,120))}`,{field:"replace",old:a});e=e.slice(0,o)+r+e.slice(o+a.length)}return e}s(xe,"applyReplacements");async function Ye(t,n,e,i,a,r,o={},c){if(y(e),await T(t,n,e),e.deleted_at)throw p(`${e.name} is deleted`);if(r===null)throw new v("read_first",`read ${e.name} before editing it`,R.GENERAL,{id:e.id});if(a.trim()==="")throw p("an edit needs a rationale",{field:"rationale"});const u=await O(t,e);if(u.heads_key!==r)return{stale:{heads_key:u.heads_key,revision:u.revision}};const w=await C(t,e);let l;if("body"in i)l=i.body;else{if(w.length!==1)throw p(`${e.name} has ${w.length} heads and needs a merge; pass the whole merged body`,{heads:w.length});l=xe(await Z(t,e,le(w[0].body_hash)),i.replace)}const d=B(l);try{return await h(async()=>{const f=E(n),D=1+Math.max(0,...w.map(_=>_.number)),J=await A(t,e,{number:D,body_hash:d,author:f,rationale:a,verbatim:i.verbatim===!0,parents:w.map(_=>_.rev_id)}),L=J.rev_id,ie=await t.prepare("UPDATE documents SET heads_key = ?, revision = ? WHERE object = ? AND heads_key = ?").run(L,D,e.id,r);if(Number(ie.changes)===0){const _=await O(t,e);throw new ee(_.heads_key,_.revision)}const k=await M(t,e,o),re=await Q(t,n,k,l);return await g(t,f,k),await I(t,f,k,"write",{readHeadsKey:L}),await x(t,{event:"edited",object:k,actor:f,pointer:J.rev_id,attrs:{revision:D,from_revision:u.revision,rationale:a}},c),{revision:D,heads_key:L,unresolved:re}},{savepoint:!0})}catch(f){if(f instanceof ee)return{stale:{heads_key:f.heads_key,revision:f.revision}};throw f}}s(Ye,"editDocument");class ee extends Error{static{s(this,"StaleEdit")}heads_key;revision;constructor(n,e){super("stale"),this.heads_key=n,this.revision=e}}async function Ve(t,n,e,i){return y(e),n&&await T(t,n,e),await h(async()=>{const a=await M(t,e,i);return n&&await g(t,E(n),a),a},{savepoint:!0})}s(Ve,"setDocumentRecord");async function Te(t,n,e,i){const a=E(n),{heads_key:r}=await O(t,e);await I(t,a,e,"read",{readHeadsKey:r}),await x(t,{event:"read",object:e,actor:a,attrs:{}},i)}s(Te,"recordRead");async function Xe(t,n,e,i){return y(e),await U(t,n,e),await h(async()=>{const a=await O(t,e),r=await S(await C(t,e),async c=>({...c,body:await Z(t,e,pe(c.body_hash,a.source_path))})),o=(await q(await S(await t.prepare("SELECT dst, written_as FROM edges WHERE type = 'links-to' AND src = ? ORDER BY written_as").all(e.id),async c=>({written_as:c.written_as??"",object:await m(t,c.dst)})),async c=>c.object&&await P(t,n,c.object))).map(c=>({...c,deleted:c.object.deleted_at!==null}));return e.deleted_at||await Te(t,n,e,i),{object:e,record:a,heads:r,needsMerge:r.length>1,links:o}},{savepoint:!0})}s(Xe,"readDocument");async function ze(t,n,e){y(e),await U(t,n,e);const i=await t.prepare("SELECT * FROM revisions WHERE document = ? ORDER BY number DESC, created_at DESC, seq DESC").all(e.id);return await S(i,async a=>await X(t,a))}s(ze,"history");async function Qe(t,n,e,i,a){if(y(e),e.deleted_at)throw p(`${e.name} is deleted`);return n&&await T(t,n,e),await h(async()=>{const r=i.owner??await m(t,e.owner),o=i.name??e.name;await H(t,r,o,e),await $(t,r,e.privacy),await t.prepare("UPDATE objects SET name = ?, owner = ? WHERE id = ?").run(o,r.id,e.id);const c=await m(t,e.id);if(r.id!==e.owner&&(await Re(t,c),n&&!await j(t,n,c)))throw N(`no owner ${r.name} you can move documents to`);return n&&await g(t,E(n),c),(o!==e.name||r.id!==e.owner)&&await W(t,c,a),c},{savepoint:!0})}s(Qe,"moveDocument");async function Ze(t,n,e,i,a){return y(e),e.deleted_at?e:(n&&await T(t,n,e),await h(async()=>{const r=await te(t,n,e,i,a);return await ae(t,await ne(t,e.id),i),r},{savepoint:!0}))}s(Ze,"deleteDocument");async function be(t,n,e,i){return y(n),n.deleted_at?await h(async()=>{await H(t,await m(t,n.owner),e,n),await t.prepare("UPDATE objects SET deleted_at = NULL, name = ? WHERE id = ?").run(e,n.id);const a=await m(t,n.id);return await W(t,a,i),a},{savepoint:!0}):n}s(be,"restoreDocument");async function te(t,n,e,i,a){await t.prepare("UPDATE objects SET deleted_at = ? WHERE id = ?").run(a??new Date().toISOString(),e.id);const r=await m(t,e.id),o=n?E(n):null;return o&&await g(t,o,r),await x(t,{event:"deleted",object:r,actor:o,attrs:{}},i),await t.prepare("DELETE FROM watches WHERE object = ?").run(e.id),await K(t,r,[]),r}s(te,"markDeleted");async function ne(t,n){return(await t.prepare("SELECT dst FROM edges WHERE type = 'links-to' AND src = ?").all(n)).map(({dst:e})=>e)}s(ne,"linkTargets");async function ae(t,n,e){const i=t.prepare(`SELECT 1 FROM objects d JOIN objects w ON w.id = d.owner
|
|
8
|
+
WHERE d.id = ? AND d.type = 'document' AND d.deleted_at IS NULL AND w.deleted_at IS NOT NULL
|
|
9
|
+
AND NOT EXISTS (SELECT 1 FROM edges e JOIN objects s ON s.id = e.src
|
|
10
|
+
WHERE e.type = 'links-to' AND e.dst = d.id AND e.src != d.id AND s.deleted_at IS NULL)`),a=[...n];for(;a.length>0;){const r=a.pop();await i.get(r)!==void 0&&(await te(t,null,await m(t,r),e),a.push(...await ne(t,r)))}}s(ae,"collectUnlinked");async function et(t,n,e){if(n.revisions.length===0)throw p(`import of ${n.name}: no revisions`);return await h(async()=>{const i=await b(t,n,e);await t.prepare("UPDATE objects SET created_at = ? WHERE id = ?").run(n.revisions[0].created_at,i.id);let a=null;return await ge(n.revisions,async(r,o)=>{a=(await A(t,i,{...r,number:o+1,parents:a===null?[]:[a]})).rev_id}),await F(t,i),await m(t,i.id)},{savepoint:!0})}s(et,"importDocument");async function tt(t,n,e){if(y(n),n.privacy!=="public"&&await Y(t,n)==="repo")throw p(`a repo owns only public documents; refusing revisions of ${n.name}`);return await h(async()=>{const i=t.prepare("SELECT rev_id, number, document FROM revisions WHERE rev_id = ?");let a=await q(e,async c=>!await i.get(c.rev_id));for(;a.length>0;){const c=[];for(const u of a){const w=await S(u.parents,async d=>await i.get(d));if(w.some(d=>d===void 0)){c.push(u);continue}const l=w;if(l.some(d=>d.document!==n.id))throw p(`revision ${u.rev_id} names a parent of another document`);await A(t,n,{...u,author:null,number:1+Math.max(0,...l.map(d=>d.number)),parents:l.map(d=>d.rev_id)})}if(c.length===a.length)throw p(`revisions of ${n.name} name unknown parents: ${c.map(u=>u.rev_id).join(", ")}`);a=c}const{heads_key:r,headCount:o}=await F(t,n);return{heads_key:r,headCount:o}},{savepoint:!0})}s(tt,"insertImportedRevisions");async function nt(t,n){const e=await m(t,n);if(!e||e.type!=="document")throw N(`no document ${n}`);return e}s(nt,"documentById");export{E as actorOf,M as applyDocumentFields,xe as applyReplacements,ae as collectUnlinked,Ze as deleteDocument,nt as documentById,O as documentRecord,Ye as editDocument,C as heads,ze as history,et as importDocument,tt as insertImportedRevisions,De as linksIn,Qe as moveDocument,qe as readBase,Xe as readDocument,Te as recordRead,be as restoreDocument,Ve as setDocumentRecord,Q as setRevisionLinks,Z as withCurrentNames,Ke as writeDocument};
|