@north-light/cli 0.3.518 → 0.3.519

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.
@@ -3,7 +3,7 @@ import { type Envelope } from './envelope.js';
3
3
  import { type TokenCache } from './token.js';
4
4
  /** One attempt's budget. The hosting router gives an envelope-bearing request a 120 s header deadline; a cold wake must finish inside it. */
5
5
  export declare const PEER_CALL_TIMEOUT_MS = 120000;
6
- /** How long a `503 runtime_starting` is retried before the machine counts as unreachable. */
6
+ /** How long a `503 runtime_starting`, or a repeatable request's `503 runtime_unreachable` with `Retry-After`, is retried before the machine counts as unreachable. */
7
7
  export declare const RUNTIME_STARTING_RETRY_BUDGET_MS = 60000;
8
8
  /** First and longest wait between `runtime_starting` retries (doubling). */
9
9
  export declare const RUNTIME_STARTING_BACKOFF_MS: {
@@ -57,5 +57,5 @@ export interface PeerDeps {
57
57
  }
58
58
  export declare function createPeerCall(deps: PeerDeps): (machineId: string, request: PeerRequest, options?: PeerOptions) => Promise<PeerResult>;
59
59
  /** Call a machine of this account. Resolves reach through the directory (cached 5 min), authenticates with a peer call token for the callee's URL,
60
- * and retries `503 runtime_starting`. See the module header for the two kinds of result. */
60
+ * and retries `503 runtime_starting` (and, for GET/PUT/DELETE, `503 runtime_unreachable` carrying `Retry-After`). See the module header for the two kinds of result. */
61
61
  export declare const peerCall: (machineId: string, request: PeerRequest, options?: PeerOptions) => Promise<PeerResult>;
@@ -1 +1 @@
1
- var M=Object.defineProperty;var c=(e,r)=>M(e,"name",{value:r,configurable:!0});import{crtrVersion as S}from"../../shared/crtr-version.js";import{directory as $,directoryIssuer as v,normalizeMachineId as T}from"./directory.js";import{ENVELOPE_HEADER as N,encodeEnvelope as O}from"./envelope.js";import{peerTokens as x}from"./token.js";import{PEER_VERSION_FLOOR as d,PEER_VERSION_HEADER as A,peerVersionRefusal as k}from"./version.js";const P=12e4,U=6e4,w={first:1e3,max:8e3},b=16*1024*1024,H=c(e=>"unreachable"in e,"isUnreachable"),i=c((e,r)=>({unreachable:{reason:e,message:r}}),"unreachable");function B(e){const r=e?.error;if(typeof r=="string")return r;const s=r?.code;return typeof s=="string"?s:null}c(B,"errorCode");async function I(e){if(Number(e.headers.get("content-length")??"0")>b)throw new RangeError("the peer answer is too large");const s=new Uint8Array(await e.arrayBuffer());if(s.byteLength>b)throw new RangeError("the peer answer is too large");const o=new TextDecoder().decode(s);if(o==="")return null;try{return JSON.parse(o)}catch{return o}}c(I,"readBody");function L(e,r){const s=new URL(`${e.url}${r.path.startsWith("/")?"":"/"}${r.path}`),o=r.query instanceof URLSearchParams?r.query:Object.entries(r.query??{});for(const[u,l]of o instanceof URLSearchParams?o.entries():o)l!==void 0&&s.searchParams.append(u,String(l));return s.toString()}c(L,"targetUrl");function C(e){return c(async function(s,o,u={}){const l=e.issuer();if(l===null)return i("no_directory","this machine is not joined to a Northlight account, so it has no peers");let t;try{t=await e.directory.reach(s)}catch(a){return i("directory_unreachable",a instanceof Error?a.message:String(a))}if(t===null)return i("unknown_machine",`No machine ${T(s)} on your account.`);if(t.kind==="device"&&u.device!==!0)return i("not_a_crtr_peer",`${t.name} is a device, not a crtr peer.`);const h=t.crtr_version===null?null:k(t.crtr_version,d,e.version());if(h!==null)return{status:426,headers:{},body:{error:{code:h.code,message:`${t.name} runs crtr ${t.crtr_version}; peers below ${d} cannot take part. Update it with \`crtr sys update\`.`,details:{peer_version:t.crtr_version,floor:d,receiver_version:e.version()}}}};const R=L(t,o),_=e.now();let m=w.first,E=!1,g=!1;for(;;){let a;try{const n=await e.tokens.get(l,t.url);a=await e.fetch(R,{method:o.method,redirect:"manual",headers:{authorization:`Bearer ${n}`,[A]:e.version(),...u.envelope?{[N]:O(u.envelope)}:{},...o.body===void 0?{}:{"content-type":"application/json"}},...o.body===void 0?{}:{body:JSON.stringify(o.body)},signal:AbortSignal.any([AbortSignal.timeout(g?Math.max(1e3,Math.min(e.timeoutMs,e.startingBudgetMs-(e.now()-_))):e.timeoutMs),...u.signal?[u.signal]:[]])})}catch(n){return n instanceof Error&&(n.name==="TimeoutError"||n.name==="AbortError")?i("timeout",`${t.name} did not answer within ${Math.round(e.timeoutMs/1e3)} s.`):n instanceof Error&&/directory/.test(n.message)?i("directory_unreachable",n.message):i("network",`${t.name} could not be reached: ${n instanceof Error?n.message:String(n)}`)}let f;try{f=await I(a)}catch(n){return n instanceof Error&&(n.name==="TimeoutError"||n.name==="AbortError")?i("timeout",`${t.name} did not finish its answer within ${Math.round(e.timeoutMs/1e3)} s.`):i("network",`${t.name}'s answer could not be read: ${n instanceof Error?n.message:String(n)}`)}const y=B(f),p=Object.fromEntries(a.headers.entries());if(a.status===401&&!E){E=!0,e.tokens.drop(l,t.url);continue}if(a.status===503&&y==="machine_offline")return i("machine_offline",`${t.name} is offline.`);if(a.status===504)return i("timeout",`${t.name} did not answer in time.`);if(a.status===503&&y==="runtime_starting"){if(e.now()-_+m>e.startingBudgetMs)return i("runtime_starting",`${t.name} is still starting.`);await e.sleep(m),m=Math.min(m*2,w.max),g=!0;continue}return{status:a.status,headers:p,body:f}}},"peerCall")}c(C,"createPeerCall");const J=C({issuer:v,directory:$,tokens:x,fetch:c((e,r)=>fetch(e,r),"fetch"),sleep:c(e=>new Promise(r=>setTimeout(r,e)),"sleep"),now:Date.now,version:S,timeoutMs:P,startingBudgetMs:U});export{b as MAX_PEER_RESPONSE_BYTES,P as PEER_CALL_TIMEOUT_MS,w as RUNTIME_STARTING_BACKOFF_MS,U as RUNTIME_STARTING_RETRY_BUDGET_MS,C as createPeerCall,H as isUnreachable,J as peerCall};
1
+ var T=Object.defineProperty;var c=(e,r)=>T(e,"name",{value:r,configurable:!0});import{crtrVersion as $}from"../../shared/crtr-version.js";import{directory as p,directoryIssuer as v,normalizeMachineId as A}from"./directory.js";import{ENVELOPE_HEADER as N,encodeEnvelope as O}from"./envelope.js";import{peerTokens as P}from"./token.js";import{PEER_VERSION_FLOOR as y,PEER_VERSION_HEADER as x,peerVersionRefusal as U}from"./version.js";const k=12e4,B=6e4,S={first:1e3,max:8e3},M=16*1024*1024,L=new Set(["GET","PUT","DELETE"]),Y=c(e=>"unreachable"in e,"isUnreachable"),i=c((e,r)=>({unreachable:{reason:e,message:r}}),"unreachable");function I(e){const r=e?.error;if(typeof r=="string")return r;const s=r?.code;return typeof s=="string"?s:null}c(I,"errorCode");async function D(e){if(Number(e.headers.get("content-length")??"0")>M)throw new RangeError("the peer answer is too large");const s=new Uint8Array(await e.arrayBuffer());if(s.byteLength>M)throw new RangeError("the peer answer is too large");const o=new TextDecoder().decode(s);if(o==="")return null;try{return JSON.parse(o)}catch{return o}}c(D,"readBody");function C(e,r){const s=new URL(`${e.url}${r.path.startsWith("/")?"":"/"}${r.path}`),o=r.query instanceof URLSearchParams?r.query:Object.entries(r.query??{});for(const[u,l]of o instanceof URLSearchParams?o.entries():o)l!==void 0&&s.searchParams.append(u,String(l));return s.toString()}c(C,"targetUrl");function V(e){return c(async function(s,o,u={}){const l=e.issuer();if(l===null)return i("no_directory","this machine is not joined to a Northlight account, so it has no peers");let t;try{t=await e.directory.reach(s)}catch(a){return i("directory_unreachable",a instanceof Error?a.message:String(a))}if(t===null)return i("unknown_machine",`No machine ${A(s)} on your account.`);if(t.kind==="device"&&u.device!==!0)return i("not_a_crtr_peer",`${t.name} is a device, not a crtr peer.`);const w=t.crtr_version===null?null:U(t.crtr_version,y,e.version());if(w!==null)return{status:426,headers:{},body:{error:{code:w.code,message:`${t.name} runs crtr ${t.crtr_version}; peers below ${y} cannot take part. Update it with \`crtr sys update\`.`,details:{peer_version:t.crtr_version,floor:y,receiver_version:e.version()}}}};const R=C(t,o),h=e.now();let f=S.first,b=!1,d=!1;for(;;){let a;try{const n=await e.tokens.get(l,t.url);a=await e.fetch(R,{method:o.method,redirect:"manual",headers:{authorization:`Bearer ${n}`,[x]:e.version(),...u.envelope?{[N]:O(u.envelope)}:{},...o.body===void 0?{}:{"content-type":"application/json"}},...o.body===void 0?{}:{body:JSON.stringify(o.body)},signal:AbortSignal.any([AbortSignal.timeout(d?Math.max(1e3,Math.min(e.timeoutMs,e.startingBudgetMs-(e.now()-h))):e.timeoutMs),...u.signal?[u.signal]:[]])})}catch(n){return n instanceof Error&&(n.name==="TimeoutError"||n.name==="AbortError")?i("timeout",`${t.name} did not answer within ${Math.round(e.timeoutMs/1e3)} s.`):n instanceof Error&&/directory/.test(n.message)?i("directory_unreachable",n.message):i("network",`${t.name} could not be reached: ${n instanceof Error?n.message:String(n)}`)}let E;try{E=await D(a)}catch(n){return n instanceof Error&&(n.name==="TimeoutError"||n.name==="AbortError")?i("timeout",`${t.name} did not finish its answer within ${Math.round(e.timeoutMs/1e3)} s.`):i("network",`${t.name}'s answer could not be read: ${n instanceof Error?n.message:String(n)}`)}const _=I(E),g=Object.fromEntries(a.headers.entries());if(a.status===401&&!b){b=!0,e.tokens.drop(l,t.url);continue}if(a.status===503&&_==="machine_offline")return i("machine_offline",`${t.name} is offline.`);if(a.status===504)return i("timeout",`${t.name} did not answer in time.`);if(a.status===503&&_==="runtime_starting"){if(e.now()-h+f>e.startingBudgetMs)return i("runtime_starting",`${t.name} is still starting.`);await e.sleep(f),f=Math.min(f*2,S.max),d=!0;continue}const m=Number(g["retry-after"]);if(a.status===503&&_==="runtime_unreachable"&&L.has(o.method)&&g["retry-after"]!==void 0&&Number.isFinite(m)&&m>=0&&e.now()-h+m*1e3<=e.startingBudgetMs){await e.sleep(m*1e3),d=!0;continue}return{status:a.status,headers:g,body:E}}},"peerCall")}c(V,"createPeerCall");const K=V({issuer:v,directory:p,tokens:P,fetch:c((e,r)=>fetch(e,r),"fetch"),sleep:c(e=>new Promise(r=>setTimeout(r,e)),"sleep"),now:Date.now,version:$,timeoutMs:k,startingBudgetMs:B});export{M as MAX_PEER_RESPONSE_BYTES,k as PEER_CALL_TIMEOUT_MS,S as RUNTIME_STARTING_BACKOFF_MS,B as RUNTIME_STARTING_RETRY_BUDGET_MS,V as createPeerCall,Y as isUnreachable,K as peerCall};
@@ -1 +1 @@
1
- var re=Object.defineProperty;var u=(t,e)=>re(t,"name",{value:e,configurable:!0});import{prepared as P}from"../../../core/sqlite-statements.js";import{ApiError as _}from"../../../api/errors.js";import{DOC_KINDS as q,DOC_UNSET_FIELDS as H}from"../../../api/dto/docs.js";import{PRIVACY_LEVELS_DTO as U}from"../../../api/dto/objects.js";import{withCanvasWrite as k}from"../../../core/canvas/db.js";import{CrtrError as ie}from"../../../core/errors.js";import{emitEvent as se}from"../../../core/events/emit.js";import{canChange as V,spaceOf as ae}from"../../../core/graph/access.js";import{get as A}from"../../../core/graph/bodies.js";import{deleteDocument as ce,documentRecord as F,editDocument as de,heads as I,history as ue,linksIn as K,moveDocument as fe,readBase as me,setDocumentRecord as le,withCurrentNames as pe,writeDocument as he}from"../../../core/graph/documents.js";import{resolveName as X}from"../../../core/graph/names.js";import{getByRowid as x}from"../../../core/graph/objects.js";import{noteRepoDocumentsChanged as we}from"../../../core/graph/repo-sync/index.js";import{checkoutsForCwd as ye}from"../../../core/graph/repo-sync/repos.js";import{lintRules as ve,rulesOf as ge}from"../../../core/graph/rules.js";import{unifiedDiff as _e}from"../../../core/graph/diff.js";import{ownerFromFlag as L,readerFor as E,resolveRef as z}from"../reader.js";function v(t,e,n,o,s={}){return new _(t,e,n,{...s,error:e,message:n,next:o})}u(v,"refuse");const b=u((t,e)=>new _(400,"invalid_request",t,e),"invalid");function R(t){const e=t.body;if(e===void 0)return{};if(typeof e!="object"||e===null||Array.isArray(e))throw b("the request body must be a JSON object");return e}u(R,"bodyOf");const M=u(t=>e=>ye(t,e),"reposFnFor");function S(t,e){if(t instanceof ie){const n=t.details;if(t.code==="read_first")throw v(409,"read_first",t.message,`Read it first with \`crtr canvas read ${e?.id??"<ref>"}\`, then rerun the edit.`,n??{});if(t.code==="conflict")throw new _(409,"name_taken",t.message,n);if(t.code==="forbidden")throw new _(403,"forbidden",t.message,n);if(t.code==="scope_missing")throw v(403,"scope_missing",t.message,`Launch the run with \`${String(n?.scope)}\` in its scopes list.`,n??{});if(n?.rule==="repo-public-only")throw v(422,"repo_documents_are_public",t.message,'Own it as `user` and add a rule with `if: {"repo": "<handle>"}` so it loads only in that repo.')}throw t}u(S,"mapGraphError");function W(t,e,n){const o=z(t,e,decodeURIComponent(n));if("remote"in o)throw v(404,"not_found",G(o.remote),"Check the name with `crtr canvas search`.");if("deleted"in o)throw new _(404,"not_found",`${o.deleted.name} is deleted`,{id:o.deleted.id,deleted:!0});if(o.type!=="document")throw b(`${n} is a ${o.type}, not a document`);return o}u(W,"refDocument");function G(t){return`no object named ${t} on this runtime; it may be on another runtime, or the name may be misspelled`}u(G,"remoteMessage");function be(t,e){const n=e.owner===null?null:x(t,e.owner);return n?n.type==="node"?n.id:n.name:""}u(be,"ownerHandle");function j(t,e){const n=be(t,e);return n?`${n}/${e.name}`:e.name}u(j,"canonicalName");function ke(t,e){const n=e.owner===null?null:x(t,e.owner),o=n?{id:n.id,type:n.type,handle:n.type==="node"?n.id:n.name}:null;return{id:e.id,type:e.type,kind:e.kind,owner:o,privacy:e.privacy,name:e.name,preview:e.preview??"",created_at:e.created_at,deleted_at:e.deleted_at}}u(ke,"objectDTO");function Ee(t,e){const n=e.owner===null?null:x(t,e.owner);return n?.type==="repo"?n:null}u(Ee,"repoOwner");function C(t,e,n,o){const s=[...new Map(n.flatMap(f=>{const i=Ee(t,f);return i?[[i.id,i]]:[]})).values()],a=e.class==="node"?e.cwd:o,r=e.class==="node"?[...e.checkouts,...e.projectCheckouts].map(f=>f.root):[];return{repos:s,dirs:[...new Set([...a!==void 0?[a]:[],...r])]}}u(C,"repoChange");function N(t){for(const e of t.repos)try{we(e,t.dirs)}catch(n){se({level:"warn",event:"repo_sync.failed",outcome:"failed",error:n,fields:{repo:e.name,step:"export",reason:n instanceof Error?n.message:String(n)}})}}u(N,"syncChanged");const Y=/^[A-Za-z0-9_-]+(\/[A-Za-z0-9_-]+)*$/;function $e(t,e){if(t===void 0)return;if(!Array.isArray(t)){e.push("`rules` must be a list");return}const n=t.map(s=>{if(typeof s!="object"||s===null||Array.isArray(s))return s;const{match_frontmatter:a,...r}=s;return"matchFrontmatter"in r?{...r,match_frontmatter:r.matchFrontmatter}:a===void 0?r:{...r,matchFrontmatter:a}}),o=ve(n);if(o){e.push(o.replaceAll("matchFrontmatter","match_frontmatter"));return}return n}u($e,"rulesFromDTO");function Z(t,e){const n={},o=u(i=>{const c=t[i];if(c!==void 0){if(typeof c!="string"){e.push(`\`${i}\` must be a string`);return}return c}},"str"),s=o("preview");s!==void 0&&(s.trim()===""||/[\r\n]/.test(s)?e.push("`preview` must be one non-empty line"):n.preview=s);const a=o("summary");a!==void 0&&(n.summary=a);const r=o("why_it_exists");if(r!==void 0&&(n.whyItExists=r),t.privacy!==void 0&&(U.includes(t.privacy)?n.privacy=t.privacy:e.push(`\`privacy\` must be one of ${U.join(", ")}`)),t.unlisted!==void 0&&(typeof t.unlisted!="boolean"?e.push("`unlisted` must be a boolean"):n.unlisted=t.unlisted),t.lint_ignore!==void 0){const i=t.lint_ignore;!Array.isArray(i)||i.some(c=>typeof c!="string")?e.push("`lint_ignore` must be a list of strings"):n.lintIgnore=i}if(t.extensions!==void 0){const i=t.extensions;typeof i!="object"||i===null||Array.isArray(i)||Object.values(i).some(c=>typeof c!="object"||c===null||Array.isArray(c))?e.push("`extensions` must map each plugin to an object of fields"):n.extensions=i}const f=$e(t.rules,e);return f!==void 0&&(n.rules=f),n}u(Z,"fieldsFrom");function J(t){if(t.length>0)throw b(t.join("; "),{errors:t})}u(J,"failOn");function Q(t,e,n,o){const s=K(n).filter(a=>"remote"in X(t,e,a));return{...o.length>0?{unresolved_links:o}:{},...s.length>0?{remote_links:s}:{}}}u(Q,"linkReport");function Oe(t){const e=R(t),n=[],o=e.name;(typeof o!="string"||!Y.test(o))&&n.push("`name` must be segments of letters, digits, `_` or `-` joined by `/`"),typeof e.body!="string"&&n.push("`body` must be a string"),typeof e.preview!="string"&&n.push("`preview` is required");const s=e.kind??"knowledge";q.includes(s)||n.push(s==="report"?"reports are written only by `crtr push`":`\`kind\` must be one of ${q.join(", ")}`);const a=Z(e,n);e.cwd!==void 0&&typeof e.cwd!="string"&&n.push("`cwd` must be a string"),J(n);const r=e,{dto:f,change:i}=k(c=>{const h=E(c,t),d=L(c,h,r.owner,r.cwd);if(!V(c,h,d))throw new _(404,"not_found",`no owner ${d.name} you can write to`);try{const{object:p,unresolved:m}=he(c,h,{...a,owner:d,name:r.name,kind:s,preview:a.preview,privacy:a.privacy??"public"},r.body,M(c));return{dto:{id:p.id,name:j(c,p),...Q(c,h,r.body,m)},change:C(c,h,[p],r.cwd)}}catch(p){S(p)}});return N(i),f}u(Oe,"write");function Ae(t,e){let n=t;e.forEach(({old:o,new:s},a)=>{const r=o===""?-1:n.indexOf(o);if(r<0)throw v(422,"replace_no_match",`replace[${a}]: old text not found in the revision you read`,"Copy the old text exactly from your last read and rerun.",{index:a});if(n.indexOf(o,r+1)>=0)throw v(422,"replace_ambiguous",`replace[${a}]: old text occurs more than once`,"Include more surrounding text so the old text matches once, and rerun.",{index:a});n=n.slice(0,r)+s+n.slice(r+o.length)})}u(Ae,"checkReplacements");function je(t){const e=R(t),n=[],o=e.body!==void 0,s=e.replace!==void 0;o&&s&&n.push("give `body` or `replace`, not both"),o&&typeof e.body!="string"&&n.push("`body` must be a string");const a=e.replace;s&&(!Array.isArray(a)||a.length===0||a.some(d=>typeof d!="object"||d===null||typeof d.old!="string"||typeof d.new!="string"))&&n.push("`replace` must be a non-empty list of {old, new} strings"),(typeof e.rationale!="string"||e.rationale.trim()==="")&&n.push("`rationale` is required"),e.verbatim!==void 0&&typeof e.verbatim!="boolean"&&n.push("`verbatim` must be a boolean"),e.base!==void 0&&(typeof e.base!="string"||e.base==="")&&n.push("`base` must be a non-empty heads key"),e.base!==void 0&&!o&&!s&&n.push("`base` applies only to a `body` or `replace` edit");const r=Z(e,n),f=e.unset??[];if(!Array.isArray(f)||f.some(d=>!H.includes(d)))n.push(`\`unset\` takes only ${H.join(", ")}`);else for(const d of f)d==="summary"&&(r.summary=null),d==="why_it_exists"&&(r.whyItExists=null),d==="unlisted"&&(r.unlisted=!1),d==="lint_ignore"&&(r.lintIgnore=null),d==="extensions"&&(r.extensions=null),d==="rules"&&(r.rules=[]);n.length===0&&!o&&!s&&Object.keys(r).length===0&&n.push("nothing to change: give `body`, `replace`, or a field"),J(n);const i=e,{dto:c,synced:h}=k(d=>{const p=E(d,t),m=W(d,p,t.params.ref),g=j(d,m),O=C(d,p,[m]);try{if(!o&&!s)return le(d,p,m,r),{dto:{id:m.id,name:g,revision:F(d,m).revision},synced:O};const w=i.base??me(d,p,m);if(s&&w!==null){const oe=F(d,m),B=I(d,m);oe.heads_key===w&&B.length===1&&Ae(pe(d,m,A(B[0].body_hash)),i.replace)}const D=i.verbatim===!0,l=o?{body:i.body,verbatim:D}:{replace:i.replace,verbatim:D},y=de(d,p,m,l,i.rationale,w,r,M(d));if("stale"in y)throw v(409,"stale_revision",`${g} changed after your read; it is now at revision ${y.stale.revision}`,`Read it again with \`crtr canvas read ${g}\`, then redo your change on the current text.`,{stale:y.stale});const T=A(I(d,m)[0].body_hash);return{dto:{id:m.id,name:g,revision:y.revision,...Q(d,p,T,y.unresolved)},synced:O}}catch(w){S(w,m)}});return N(h),c}u(je,"edit");function De(t){const e=R(t);if(e.new_name===void 0&&e.owner===void 0)throw b("give a new name, an owner, or both");if(e.new_name!==void 0&&(typeof e.new_name!="string"||!Y.test(e.new_name)))throw b("`new_name` must be segments of letters, digits, `_` or `-` joined by `/`");const{dto:n,change:o}=k(s=>{const a=E(s,t),r=W(s,a,t.params.ref),f=e.owner===void 0?void 0:L(s,a,e.owner,e.cwd);try{const i=fe(s,a,r,{...e.new_name!==void 0?{name:e.new_name}:{},...f?{owner:f}:{}});return{dto:{id:i.id,name:j(s,i)},change:C(s,a,[r,i],e.cwd)}}catch(i){S(i,r)}});return N(o),n}u(De,"move");function Re(t){const{dto:e,change:n}=k(o=>{const s=E(o,t),a=W(o,s,t.params.ref),r=j(o,a),f=C(o,s,[a]);try{ce(o,s,a,M(o))}catch(i){S(i,a)}return{dto:{id:a.id,name:r},change:f}});return N(n),e}u(Re,"remove");function Se(t){const e=t.query.get("diff"),n=e===null?void 0:Number(e);if(n!==void 0&&!(Number.isInteger(n)&&n>0))throw b("`diff` must be a revision number");return k(o=>{const s=E(o,t),a=z(o,s,decodeURIComponent(t.params.ref));if("remote"in a)throw v(404,"not_found",G(a.remote),"Check the name with `crtr canvas search`.");const r="deleted"in a?a.deleted:a;if(r.type!=="document")throw b(`${r.name} is a ${r.type}, not a document`);const f=ue(o,s,r),i={object:ke(o,r),revisions:f.map(c=>({rev_id:c.rev_id,number:c.number,author_id:c.author,rationale:c.rationale,verbatim:c.verbatim,created_at:c.created_at,parents:c.parents}))};if(n!==void 0){const c=f.find(d=>d.number===n);if(!c)throw new _(404,"not_found",`${r.name} has no revision ${n}`);const h=c.parents[0]===void 0?void 0:f.find(d=>d.rev_id===c.parents[0]);i.diff=_e(h?A(h.body_hash):"",A(c.body_hash))}return i})}u(Se,"revisionHistory");const ee=1e3,ne=1e3,te=3e3,Ce=/^When\b.+\bbecause\b.+/,Ne=u(t=>{const e=t.trim();return e===""?0:e.split(/\s+/).length},"words");function Te(t,e){if(t.some(o=>o.on==="boot"&&o.deliver==="content")&&e>ee)return`body is ${e} words, over the ${ee}-word cap for a boot rule at content (the whole body enters every node's context). Keep the core here and move separate subjects into [[linked]] documents.`;const n=[...new Set(t.filter(o=>o.on!=="boot"&&o.deliver==="content").map(o=>o.on))];return n.length>0&&e>ne?`body is ${e} words, over the ${ne}-word cap for a content rule on ${n.join("/")}. Keep the core here and move separate subjects into [[linked]] documents.`:t.some(o=>o.on==="boot"&&o.deliver==="preview")&&e>te?`body is ${e} words, over the ${te}-word cap for a boot rule at preview. Keep the core here and move separate subjects into [[linked]] documents.`:null}u(Te,"lengthFinding");function Fe(t){const e=R(t);return k(n=>{const o=E(n,t),s=e.owner===void 0?null:L(n,o,e.owner,e.cwd),a=P(n,"SELECT * FROM objects WHERE type = 'document' AND deleted_at IS NULL AND home_machine IS NULL AND kind != 'report' ORDER BY name").all(),r=[],f=new Map;for(const i of a){if(s&&i.owner!==s.rowid||!V(n,o,i))continue;const c=F(n,i),h=new Set(c.lint_ignore??[]),d=j(n,i),p=u((l,y,T)=>{h.has(l)||r.push({name:d,severity:y,rule:l,message:T})},"add"),m=ge(n,i),g=I(n,i)[0],O=g?A(g.body_hash):"",w=Te(m,Ne(O));w&&p("length","error",w),m.some(l=>l.deliver==="preview")&&!Ce.test(i.preview??"")&&p("preview-shape","error",`a rule delivers this document at preview, so the preview must read "When <situation in the reader's work>, read this because <what the reader gains>"`);const D=new Set(P(n,"SELECT written_as FROM edges WHERE type = 'links-to' AND src = ?").all(i.rowid).map(l=>l.written_as));for(const l of K(O))D.has(l)||"remote"in X(n,o,l)||p("links","warning",`[[${l}]] names no object in your view`);if(m.some(l=>l.on==="workspace-open"&&l.deliver==="content")){const l=ae(n,i);l.type==="repo"&&!h.has("workspace-open")&&f.set(l.name,[...f.get(l.name)??[],d])}}for(const[i,c]of f)if(!(c.length<2))for(const h of c)r.push({name:h,severity:"warning",rule:"workspace-open",message:`repo ${i} has ${c.length} documents delivered at content on workspace-open (${c.join(", ")}); keep one and link the rest from it`});return{findings:r}})}u(Fe,"lint");const $=u((t,e=200)=>n=>({status:e,body:t(n)}),"ok"),Qe=[{method:"POST",pattern:"/v1/docs",handler:$(Oe,201)},{method:"PATCH",pattern:"/v1/docs/:ref",handler:$(je)},{method:"POST",pattern:"/v1/docs/:ref/move",handler:$(De)},{method:"DELETE",pattern:"/v1/docs/:ref",handler:$(Re)},{method:"GET",pattern:"/v1/docs/:ref/history",handler:$(Se)},{method:"POST",pattern:"/v1/docs/lint",handler:$(Fe)}];export{j as canonicalName,Qe as docRoutes,C as repoChange,N as syncChanged};
1
+ var re=Object.defineProperty;var u=(t,e)=>re(t,"name",{value:e,configurable:!0});import{prepared as P}from"../../../core/sqlite-statements.js";import{ApiError as _}from"../../../api/errors.js";import{DOC_KINDS as q,DOC_UNSET_FIELDS as H}from"../../../api/dto/docs.js";import{PRIVACY_LEVELS_DTO as U}from"../../../api/dto/objects.js";import{withCanvasWrite as k}from"../../../core/canvas/db.js";import{CrtrError as ie}from"../../../core/errors.js";import{emitEvent as se}from"../../../core/events/emit.js";import{canChange as V,spaceOf as ae}from"../../../core/graph/access.js";import{get as A}from"../../../core/graph/bodies.js";import{deleteDocument as ce,documentRecord as F,editDocument as de,heads as I,history as ue,linksIn as K,moveDocument as fe,readBase as me,setDocumentRecord as le,withCurrentNames as pe,writeDocument as he}from"../../../core/graph/documents.js";import{resolveName as X}from"../../../core/graph/names.js";import{getByRowid as x}from"../../../core/graph/objects.js";import{noteRepoDocumentsChanged as we}from"../../../core/graph/repo-sync/index.js";import{checkoutsForCwd as ye}from"../../../core/graph/repo-sync/repos.js";import{lintRules as ve,rulesOf as ge}from"../../../core/graph/rules.js";import{unifiedDiff as _e}from"../../../core/graph/diff.js";import{ownerFromFlag as L,readerFor as E,resolveRef as z}from"../reader.js";function v(t,e,n,o,s={}){return new _(t,e,n,{...s,error:e,message:n,next:o})}u(v,"refuse");const b=u((t,e)=>new _(400,"invalid_request",t,e),"invalid");function R(t){const e=t.body;if(e===void 0)return{};if(typeof e!="object"||e===null||Array.isArray(e))throw b("the request body must be a JSON object");return e}u(R,"bodyOf");const M=u(t=>e=>ye(t,e),"reposFnFor");function S(t,e){if(t instanceof ie){const n=t.details;if(t.code==="read_first")throw v(409,"read_first",t.message,`Read it first with \`crtr canvas read ${e?.id??"<ref>"}\`, then rerun the edit.`,n??{});if(t.code==="conflict")throw new _(409,"name_taken",t.message,n);if(t.code==="forbidden")throw new _(403,"forbidden",t.message,n);if(t.code==="scope_missing")throw v(403,"scope_missing",t.message,`Launch the run with \`${String(n?.scope)}\` in its scopes list.`,n??{});if(n?.rule==="repo-public-only")throw v(422,"repo_documents_are_public",t.message,'Own it as `user` and add a rule with `if: {"repo": "<handle>"}` so it loads only in that repo.')}throw t}u(S,"mapGraphError");function W(t,e,n){const o=z(t,e,decodeURIComponent(n));if("remote"in o)throw v(404,"not_found",G(o.remote),"Check the name with `crtr canvas search`.");if("deleted"in o)throw new _(404,"not_found",`${o.deleted.name} is deleted`,{id:o.deleted.id,deleted:!0});if(o.type!=="document")throw b(`${n} is a ${o.type}, not a document`);return o}u(W,"refDocument");function G(t){return`no object named ${t} on this runtime; it may be on another runtime, or the name may be misspelled`}u(G,"remoteMessage");function be(t,e){const n=e.owner===null?null:x(t,e.owner);return n?n.type==="node"?n.id:n.name:""}u(be,"ownerHandle");function j(t,e){const n=be(t,e);return n?`${n}/${e.name}`:e.name}u(j,"canonicalName");function ke(t,e){const n=e.owner===null?null:x(t,e.owner),o=n?{id:n.id,type:n.type,handle:n.type==="node"?n.id:n.name}:null;return{id:e.id,type:e.type,kind:e.kind,owner:o,privacy:e.privacy,name:e.name,preview:e.preview??"",created_at:e.created_at,deleted_at:e.deleted_at}}u(ke,"objectDTO");function Ee(t,e){const n=e.owner===null?null:x(t,e.owner);return n?.type==="repo"?n:null}u(Ee,"repoOwner");function C(t,e,n,o){const s=[...new Map(n.flatMap(f=>{const i=Ee(t,f);return i?[[i.id,i]]:[]})).values()],a=e.class==="node"?e.cwd:o,r=e.class==="node"?[...e.checkouts,...e.projectCheckouts].map(f=>f.root):[];return{repos:s,dirs:[...new Set([...a!==void 0?[a]:[],...r])]}}u(C,"repoChange");function N(t){for(const e of t.repos)try{we(e,t.dirs)}catch(n){se({level:"warn",event:"repo_sync.failed",outcome:"failed",error:n,fields:{repo:e.name,step:"export",reason:n instanceof Error?n.message:String(n)}})}}u(N,"syncChanged");const Y=/^[A-Za-z0-9_-]+(\/[A-Za-z0-9_-]+)*$/;function $e(t,e){if(t===void 0)return;if(!Array.isArray(t)){e.push("`rules` must be a list");return}const n=t.map(s=>{if(typeof s!="object"||s===null||Array.isArray(s))return s;const{match_frontmatter:a,...r}=s;return"matchFrontmatter"in r?{...r,match_frontmatter:r.matchFrontmatter}:a===void 0?r:{...r,matchFrontmatter:a}}),o=ve(n);if(o){e.push(o.replaceAll("matchFrontmatter","match_frontmatter"));return}return n}u($e,"rulesFromDTO");function Z(t,e){const n={},o=u(i=>{const c=t[i];if(c!==void 0){if(typeof c!="string"){e.push(`\`${i}\` must be a string`);return}return c}},"str"),s=o("preview");s!==void 0&&(s.trim()===""||/[\r\n]/.test(s)?e.push("`preview` must be one non-empty line"):n.preview=s);const a=o("summary");a!==void 0&&(n.summary=a);const r=o("why_it_exists");if(r!==void 0&&(n.whyItExists=r),t.privacy!==void 0&&(U.includes(t.privacy)?n.privacy=t.privacy:e.push(`\`privacy\` must be one of ${U.join(", ")}`)),t.unlisted!==void 0&&(typeof t.unlisted!="boolean"?e.push("`unlisted` must be a boolean"):n.unlisted=t.unlisted),t.lint_ignore!==void 0){const i=t.lint_ignore;!Array.isArray(i)||i.some(c=>typeof c!="string")?e.push("`lint_ignore` must be a list of strings"):n.lintIgnore=i}if(t.extensions!==void 0){const i=t.extensions;typeof i!="object"||i===null||Array.isArray(i)||Object.values(i).some(c=>typeof c!="object"||c===null||Array.isArray(c))?e.push("`extensions` must map each plugin to an object of fields"):n.extensions=i}const f=$e(t.rules,e);return f!==void 0&&(n.rules=f),n}u(Z,"fieldsFrom");function J(t){if(t.length>0)throw b(t.join("; "),{errors:t})}u(J,"failOn");function Q(t,e,n,o){const s=K(n).filter(a=>"remote"in X(t,e,a));return{...o.length>0?{unresolved_links:o}:{},...s.length>0?{remote_links:s}:{}}}u(Q,"linkReport");function Oe(t){const e=R(t),n=[],o=e.name;(typeof o!="string"||!Y.test(o))&&n.push("`name` must be segments of letters, digits, `_` or `-` joined by `/`"),typeof e.body!="string"&&n.push("`body` must be a string"),typeof e.preview!="string"&&n.push("`preview` is required");const s=e.kind??"knowledge";q.includes(s)||n.push(s==="report"?"reports are written only by `crtr push`":`\`kind\` must be one of ${q.join(", ")}`);const a=Z(e,n);e.cwd!==void 0&&typeof e.cwd!="string"&&n.push("`cwd` must be a string"),J(n);const r=e,{dto:f,change:i}=k(c=>{const h=E(c,t),d=L(c,h,r.owner,r.cwd);if(!V(c,h,d))throw new _(404,"not_found",`no owner ${d.name} you can write to`);try{const{object:p,unresolved:m}=he(c,h,{...a,owner:d,name:r.name,kind:s,preview:a.preview,privacy:a.privacy??"public"},r.body,M(c));return{dto:{id:p.id,name:j(c,p),...Q(c,h,r.body,m)},change:C(c,h,[p],r.cwd)}}catch(p){S(p)}});return N(i),f}u(Oe,"write");function Ae(t,e){let n=t;e.forEach(({old:o,new:s},a)=>{const r=o===""?-1:n.indexOf(o);if(r<0)throw v(422,"replace_no_match",`replace[${a}]: old text not found in the revision you read`,"Copy the old text exactly from your last read and rerun.",{index:a});if(n.indexOf(o,r+1)>=0)throw v(422,"replace_ambiguous",`replace[${a}]: old text occurs more than once`,"Include more surrounding text so the old text matches once, and rerun.",{index:a});n=n.slice(0,r)+s+n.slice(r+o.length)})}u(Ae,"checkReplacements");function je(t){const e=R(t),n=[],o=e.body!==void 0,s=e.replace!==void 0;o&&s&&n.push("give `body` or `replace`, not both"),o&&typeof e.body!="string"&&n.push("`body` must be a string");const a=e.replace;s&&(!Array.isArray(a)||a.length===0||a.some(d=>typeof d!="object"||d===null||typeof d.old!="string"||typeof d.new!="string"))&&n.push("`replace` must be a non-empty list of {old, new} strings"),(typeof e.rationale!="string"||e.rationale.trim()==="")&&n.push("`rationale` is required"),e.verbatim!==void 0&&typeof e.verbatim!="boolean"&&n.push("`verbatim` must be a boolean"),e.base!==void 0&&(typeof e.base!="string"||e.base==="")&&n.push("`base` must be a non-empty heads key"),e.base!==void 0&&!o&&!s&&n.push("`base` applies only to a `body` or `replace` edit");const r=Z(e,n),f=e.unset??[];if(!Array.isArray(f)||f.some(d=>!H.includes(d)))n.push(`\`unset\` takes only ${H.join(", ")}`);else for(const d of f)d==="summary"&&(r.summary=null),d==="why_it_exists"&&(r.whyItExists=null),d==="unlisted"&&(r.unlisted=!1),d==="lint_ignore"&&(r.lintIgnore=null),d==="extensions"&&(r.extensions=null),d==="rules"&&(r.rules=[]);n.length===0&&!o&&!s&&Object.keys(r).length===0&&n.push("nothing to change: give `body`, `replace`, or a field"),J(n);const i=e,{dto:c,synced:h}=k(d=>{const p=E(d,t),m=W(d,p,t.params.ref),g=j(d,m),O=C(d,p,[m]);try{if(!o&&!s)return le(d,p,m,r),{dto:{id:m.id,name:g,revision:F(d,m).revision},synced:O};const y=i.base??me(d,p,m);if(s&&y!==null){const oe=F(d,m),B=I(d,m);oe.heads_key===y&&B.length===1&&Ae(pe(d,m,A(B[0].body_hash)),i.replace)}const D=i.verbatim===!0,l=o?{body:i.body,verbatim:D}:{replace:i.replace,verbatim:D},w=de(d,p,m,l,i.rationale,y,r,M(d));if("stale"in w)throw v(409,"stale_revision",`${g} changed after your read; it is now at revision ${w.stale.revision}`,`Read it again with \`crtr canvas read ${g}\`, then redo your change on the current text.`,{stale:w.stale});const T=A(I(d,m)[0].body_hash);return{dto:{id:m.id,name:g,revision:w.revision,...Q(d,p,T,w.unresolved)},synced:O}}catch(y){S(y,m)}});return N(h),c}u(je,"edit");function De(t){const e=R(t);if(e.new_name===void 0&&e.owner===void 0)throw b("give a new name, an owner, or both");if(e.new_name!==void 0&&(typeof e.new_name!="string"||!Y.test(e.new_name)))throw b("`new_name` must be segments of letters, digits, `_` or `-` joined by `/`");const{dto:n,change:o}=k(s=>{const a=E(s,t),r=W(s,a,t.params.ref),f=e.owner===void 0?void 0:L(s,a,e.owner,e.cwd);try{const i=fe(s,a,r,{...e.new_name!==void 0?{name:e.new_name}:{},...f?{owner:f}:{}});return{dto:{id:i.id,name:j(s,i)},change:C(s,a,[r,i],e.cwd)}}catch(i){S(i,r)}});return N(o),n}u(De,"move");function Re(t){const{dto:e,change:n}=k(o=>{const s=E(o,t),a=W(o,s,t.params.ref),r=j(o,a),f=C(o,s,[a]);try{ce(o,s,a,M(o))}catch(i){S(i,a)}return{dto:{id:a.id,name:r},change:f}});return N(n),e}u(Re,"remove");function Se(t){const e=t.query.get("diff"),n=e===null?void 0:Number(e);if(n!==void 0&&!(Number.isInteger(n)&&n>0))throw b("`diff` must be a revision number");return k(o=>{const s=E(o,t),a=z(o,s,decodeURIComponent(t.params.ref));if("remote"in a)throw v(404,"not_found",G(a.remote),"Check the name with `crtr canvas search`.");const r="deleted"in a?a.deleted:a;if(r.type!=="document")throw b(`${r.name} is a ${r.type}, not a document`);const f=ue(o,s,r),i={object:ke(o,r),revisions:f.map(c=>({rev_id:c.rev_id,number:c.number,author_id:c.author,rationale:c.rationale,verbatim:c.verbatim,created_at:c.created_at,parents:c.parents}))};if(n!==void 0){const c=f.find(d=>d.number===n);if(!c)throw new _(404,"not_found",`${r.name} has no revision ${n}`);const h=c.parents[0]===void 0?void 0:f.find(d=>d.rev_id===c.parents[0]);i.diff=_e(h?A(h.body_hash):"",A(c.body_hash))}return i})}u(Se,"revisionHistory");const ee=1e3,ne=1e3,te=3e3,Ce=/^When\b.+\bbecause\b.+/,Ne=u(t=>{const e=t.trim();return e===""?0:e.split(/\s+/).length},"words");function Te(t,e){if(t.some(o=>o.on==="boot"&&o.deliver==="content")&&e>ee)return`body is ${e} words, over the ${ee}-word cap for a boot rule at content (the whole body enters every node's context). Keep the core here and move separate subjects into [[linked]] documents.`;const n=[...new Set(t.filter(o=>o.on!=="boot"&&o.deliver==="content").map(o=>o.on))];return n.length>0&&e>ne?`body is ${e} words, over the ${ne}-word cap for a content rule on ${n.join("/")}. Keep the core here and move separate subjects into [[linked]] documents.`:t.some(o=>o.on==="boot"&&o.deliver==="preview")&&e>te?`body is ${e} words, over the ${te}-word cap for a boot rule at preview. Keep the core here and move separate subjects into [[linked]] documents.`:null}u(Te,"lengthFinding");function Fe(t){const e=R(t);return k(n=>{const o=E(n,t),s=e.owner===void 0?null:L(n,o,e.owner,e.cwd),a=P(n,"SELECT * FROM objects WHERE type = 'document' AND deleted_at IS NULL AND home_machine IS NULL AND kind != 'report' ORDER BY name").all(),r=[],f=new Map;for(const i of a){if(s&&i.owner!==s.rowid||!V(n,o,i))continue;const c=F(n,i),h=new Set(c.lint_ignore??[]),d=j(n,i),p=u((l,w,T)=>{h.has(l)||r.push({name:d,severity:w,rule:l,message:T})},"add"),m=ge(n,i),g=I(n,i)[0],O=g?A(g.body_hash):"",y=Te(m,Ne(O));y&&p("length","error",y),m.some(l=>l.deliver==="preview")&&!Ce.test(i.preview??"")&&p("preview-shape","error",`a rule delivers this document at preview, so the preview must read "When <situation in the reader's work>, read this because <what the reader gains>"`);const D=new Set(P(n,"SELECT written_as FROM edges WHERE type = 'links-to' AND src = ?").all(i.rowid).map(l=>l.written_as));for(const l of K(O)){if(D.has(l))continue;const w=X(n,o,l);"remote"in w||"object"in w||"deleted"in w||p("links","warning",`[[${l}]] names no object in your view`)}if(m.some(l=>l.on==="workspace-open"&&l.deliver==="content")){const l=ae(n,i);l.type==="repo"&&!h.has("workspace-open")&&f.set(l.name,[...f.get(l.name)??[],d])}}for(const[i,c]of f)if(!(c.length<2))for(const h of c)r.push({name:h,severity:"warning",rule:"workspace-open",message:`repo ${i} has ${c.length} documents delivered at content on workspace-open (${c.join(", ")}); keep one and link the rest from it`});return{findings:r}})}u(Fe,"lint");const $=u((t,e=200)=>n=>({status:e,body:t(n)}),"ok"),Qe=[{method:"POST",pattern:"/v1/docs",handler:$(Oe,201)},{method:"PATCH",pattern:"/v1/docs/:ref",handler:$(je)},{method:"POST",pattern:"/v1/docs/:ref/move",handler:$(De)},{method:"DELETE",pattern:"/v1/docs/:ref",handler:$(Re)},{method:"GET",pattern:"/v1/docs/:ref/history",handler:$(Se)},{method:"POST",pattern:"/v1/docs/lint",handler:$(Fe)}];export{j as canonicalName,Qe as docRoutes,C as repoChange,N as syncChanged};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@north-light/cli",
3
- "version": "0.3.518",
3
+ "version": "0.3.519",
4
4
  "description": "crtr — agent runtime with memory, plugins, and marketplaces",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -139,7 +139,7 @@
139
139
  },
140
140
  "license": "UNLICENSED",
141
141
  "dependencies": {
142
- "@north-light/identity": "0.3.518",
142
+ "@north-light/identity": "0.3.519",
143
143
  "@earendil-works/pi-agent-core": "1.1.0",
144
144
  "@earendil-works/pi-ai": "1.1.0",
145
145
  "@earendil-works/pi-coding-agent": "1.1.0",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@north-light/identity",
3
- "version": "0.3.518",
3
+ "version": "0.3.519",
4
4
  "description": "Northlight access-token verification and scope rules",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
package/runtime.lock.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@north-light/cli",
3
- "version": "0.3.518",
3
+ "version": "0.3.519",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@north-light/cli",
9
- "version": "0.3.518",
9
+ "version": "0.3.519",
10
10
  "hasInstallScript": true,
11
11
  "license": "UNLICENSED",
12
12
  "workspaces": [
@@ -24,7 +24,7 @@
24
24
  "@milkdown/preset-gfm": "^7.22.3",
25
25
  "@milkdown/prose": "^7.22.3",
26
26
  "@milkdown/utils": "^7.22.3",
27
- "@north-light/identity": "0.3.518",
27
+ "@north-light/identity": "0.3.519",
28
28
  "cron-parser": "^5.6.0",
29
29
  "esbuild": "^0.27.7",
30
30
  "jose": "^6.2.12",
@@ -12468,17 +12468,17 @@
12468
12468
  },
12469
12469
  "packages/crouter-api": {
12470
12470
  "name": "@north-light/api",
12471
- "version": "0.3.518",
12471
+ "version": "0.3.519",
12472
12472
  "license": "UNLICENSED"
12473
12473
  },
12474
12474
  "packages/crouter-env-docker": {
12475
12475
  "name": "@north-light/env-docker",
12476
- "version": "0.3.518",
12476
+ "version": "0.3.519",
12477
12477
  "license": "UNLICENSED"
12478
12478
  },
12479
12479
  "packages/crouter-identity": {
12480
12480
  "name": "@north-light/identity",
12481
- "version": "0.3.518",
12481
+ "version": "0.3.519",
12482
12482
  "license": "UNLICENSED",
12483
12483
  "dependencies": {
12484
12484
  "jose": "^6.2.1"
@@ -12486,20 +12486,20 @@
12486
12486
  },
12487
12487
  "packages/crouter-plugin": {
12488
12488
  "name": "@north-light/plugin",
12489
- "version": "0.3.518",
12489
+ "version": "0.3.519",
12490
12490
  "license": "UNLICENSED",
12491
12491
  "dependencies": {
12492
- "@north-light/api": "0.3.518",
12493
- "@north-light/identity": "0.3.518"
12492
+ "@north-light/api": "0.3.519",
12493
+ "@north-light/identity": "0.3.519"
12494
12494
  }
12495
12495
  },
12496
12496
  "packages/crouter-sdk": {
12497
12497
  "name": "@north-light/sdk",
12498
- "version": "0.3.518",
12498
+ "version": "0.3.519",
12499
12499
  "license": "UNLICENSED",
12500
12500
  "dependencies": {
12501
- "@north-light/api": "0.3.518",
12502
- "@north-light/identity": "0.3.518",
12501
+ "@north-light/api": "0.3.519",
12502
+ "@north-light/identity": "0.3.519",
12503
12503
  "jose": "^6.2.1"
12504
12504
  },
12505
12505
  "bin": {