@kanonak-protocol/sdk 3.59.0 → 3.61.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/README.md +4 -117
  2. package/dist/browser.js +1 -1
  3. package/dist/chunk-2ACBWC7K.js +1 -0
  4. package/dist/{chunk-CYDDQF6S.js → chunk-7JZUJ2K4.js} +1 -1
  5. package/dist/chunk-CA2EATJR.js +1 -0
  6. package/dist/chunk-IL6VHYRU.js +148 -0
  7. package/dist/{chunk-IIODYDKS.js → chunk-IUCHSPLQ.js} +1 -1
  8. package/dist/{chunk-WDQONH3P.js → chunk-KSTGTV35.js} +1 -1
  9. package/dist/{chunk-BSJ6PEKE.js → chunk-OIVACCMQ.js} +9 -9
  10. package/dist/chunk-ORFSMEMM.js +1 -0
  11. package/dist/chunk-PEJALHXK.js +1 -0
  12. package/dist/{chunk-VJT6YUWK.js → chunk-Q6QTQWR2.js} +1 -1
  13. package/dist/{chunk-SD5QKNBC.js → chunk-QHJ6EY3Y.js} +1 -1
  14. package/dist/chunk-RSIZQAFL.js +2 -0
  15. package/dist/index.d.ts +1 -1
  16. package/dist/index.js +20 -20
  17. package/dist/look/LookRenderer.d.ts +35 -0
  18. package/dist/parsing/KanonakParser.d.ts +10 -1
  19. package/dist/parsing/index.js +1 -1
  20. package/dist/reasoning/index.js +1 -1
  21. package/dist/repositories/PublisherConfig.d.ts +11 -0
  22. package/dist/repositories/browser.js +1 -1
  23. package/dist/repositories/index.js +1 -1
  24. package/dist/resolution/KanonakUrlResolver.d.ts +8 -0
  25. package/dist/resolution/VersionUtils.d.ts +12 -0
  26. package/dist/resolution/index.d.ts +1 -1
  27. package/dist/resolution/index.js +1 -1
  28. package/dist/search/index.js +1 -1
  29. package/dist/server/assembleModel.d.ts +21 -0
  30. package/dist/server/index.d.ts +6 -0
  31. package/dist/server/index.js +2 -2
  32. package/dist/server/loadResourceModel.d.ts +26 -0
  33. package/dist/server/renderStack.d.ts +42 -0
  34. package/dist/server/requestRouter.d.ts +53 -0
  35. package/dist/transformations/index.js +1 -1
  36. package/dist/validation/index.js +1 -1
  37. package/package.json +6 -4
  38. package/dist/chunk-4FZUKBBE.js +0 -2
  39. package/dist/chunk-7CUTGGH3.js +0 -1
  40. package/dist/chunk-7RAM5KZZ.js +0 -1
  41. package/dist/chunk-ESYVKB25.js +0 -148
  42. package/dist/chunk-FQHALFRR.js +0 -1
  43. package/dist/chunk-NIGFQYVA.js +0 -1
package/dist/index.js CHANGED
@@ -1,12 +1,12 @@
1
- import{a as lt,b as dt,c as ut,d as pt,e as mt}from"./chunk-SD5QKNBC.js";import{a as ar,c as ir}from"./chunk-ESYVKB25.js";import{a as it,b as st,c as ct,d as b,e as S,f as i}from"./chunk-WDQONH3P.js";import{a as or}from"./chunk-IIODYDKS.js";import"./chunk-3NEUHF7E.js";import{a as Te,b as je,c as Le,d as Fe,e as De,f as Ve,g as He,h as Me}from"./chunk-7RAM5KZZ.js";import{a as Ie,c as Ne,d as Oe,e as Ue}from"./chunk-4FZUKBBE.js";import{a as yt,b as gt,c as ht,d as kt}from"./chunk-CYDDQF6S.js";import{a as bt,b as vt}from"./chunk-PEUTCG3B.js";import{a as Pt}from"./chunk-NIGFQYVA.js";import{a as Ae}from"./chunk-SC5M74NM.js";import{A as er,B as tr,C as rr,E as nr,a as Et,b as Kt,c as It,d as Bt,e as Tt,f as jt,g as Lt,h as Ft,i as Dt,j as Nt,k as Ot,l as At,m as Ut,n as Vt,o as Ht,p as Mt,q as _t,r as zt,s as Gt,t as Wt,u as Jt,v as qt,w as Yt,x as Xt,y as Zt,z as Qt}from"./chunk-BSJ6PEKE.js";import{a as rt,b as nt,c as ot}from"./chunk-VJT6YUWK.js";import{a as F,b as N,c as Je}from"./chunk-H2LEQLVD.js";import{a as Be}from"./chunk-7CUTGGH3.js";import{a as at,b as St,c as Ct,d as Rt,e as wt,f as xt,g as $t}from"./chunk-N224PFBI.js";import"./chunk-Q4DKP5DO.js";import{a as Pe,b as Re,c as we,d as xe,e as $e,f as ve,g as Ee,h as Ke}from"./chunk-FQHALFRR.js";import{b as qe,c as Ye,d as Xe,e as Ze,f as Qe,h as et,j as tt}from"./chunk-64TVBQFR.js";import{a as _e,b as j,c as L,d as D,e as Ge,f as We,g as O,h as A,i as U,j as V,k as H,l as M}from"./chunk-W6T7MOKY.js";import{a as ze}from"./chunk-FUUTGGJS.js";import{a as ft}from"./chunk-ODIECDN7.js";import{VersionOperator as go}from"@kanonak-protocol/types/document/models/enums";import{existsSync as wr,readFileSync as xr}from"fs";import{homedir as $r}from"os";import{join as vr}from"path";import{execFile as sr}from"child_process";import{promisify as cr}from"util";var C=cr(sr),P="kanonak",R="/usr/bin/security",p=class{async get(e){let r=i(e);try{let{stdout:n}=await C(R,["find-generic-password","-s",P,"-a",r,"-w"],{timeout:1e4});try{return JSON.parse(n.trim())}catch{throw new Error(`Stored credential for '${r}' is corrupted (not valid JSON).
1
+ import{a as ut,b as pt,c as mt,d as ft,e as yt}from"./chunk-QHJ6EY3Y.js";import{a as sr,c as cr}from"./chunk-IL6VHYRU.js";import{a as ct,b as lt,c as dt,d as b,e as S,f as i}from"./chunk-KSTGTV35.js";import{a as ir}from"./chunk-IUCHSPLQ.js";import"./chunk-3NEUHF7E.js";import{a as Le,b as Fe,c as De,d as Ne,e as Oe,f as Me,g as _e,h as ze}from"./chunk-CA2EATJR.js";import{a as Te,c as Ae,d as Ue,e as He}from"./chunk-RSIZQAFL.js";import{a as ht,b as kt,c as bt,d as St}from"./chunk-7JZUJ2K4.js";import{a as Ct,b as Kt}from"./chunk-PEUTCG3B.js";import{a as wt}from"./chunk-PEJALHXK.js";import{a as Ve}from"./chunk-SC5M74NM.js";import{A as rr,B as nr,C as or,E as ar,a as It,b as Bt,c as Tt,d as jt,e as Lt,f as Ft,g as Dt,h as Nt,i as Ot,j as At,k as Ut,l as Vt,m as Ht,n as Mt,o as _t,p as zt,q as Gt,r as Wt,s as Jt,t as qt,u as Yt,v as Xt,w as Zt,x as Qt,y as er,z as tr}from"./chunk-OIVACCMQ.js";import{a as ot,b as at,c as it}from"./chunk-Q6QTQWR2.js";import{a as F,b as N,c as Ye}from"./chunk-H2LEQLVD.js";import{a as je}from"./chunk-ORFSMEMM.js";import{a as st,b as Pt,c as Rt,d as xt,e as vt,f as $t,g as Et}from"./chunk-N224PFBI.js";import"./chunk-Q4DKP5DO.js";import{b as Xe,c as Ze,d as Qe,e as et,f as tt,h as rt,j as nt}from"./chunk-64TVBQFR.js";import{a as Ge,b as j,c as L,d as D,e as Je,f as qe,g as O,h as A,i as U,j as V,k as H,l as M}from"./chunk-W6T7MOKY.js";import{a as We}from"./chunk-FUUTGGJS.js";import{a as Pe,b as Re,c as we,d as xe,e as ve,f as $e,g as Ee,h as Ke,i as Ie,j as Be}from"./chunk-2ACBWC7K.js";import{a as gt}from"./chunk-ODIECDN7.js";import{VersionOperator as ko}from"@kanonak-protocol/types/document/models/enums";import{existsSync as vr,readFileSync as $r}from"fs";import{homedir as Er}from"os";import{join as Kr}from"path";import{execFile as lr}from"child_process";import{promisify as dr}from"util";var C=dr(lr),P="kanonak",R="/usr/bin/security",p=class{async get(e){let r=i(e);try{let{stdout:n}=await C(R,["find-generic-password","-s",P,"-a",r,"-w"],{timeout:1e4});try{return JSON.parse(n.trim())}catch{throw new Error(`Stored credential for '${r}' is corrupted (not valid JSON).
2
2
  Run 'kanonak logout ${r}' then 'kanonak login ${r}' to fix.`)}}catch(n){if(X(n,44))return null;throw new Error(`macOS Keychain read failed for '${r}': ${w(n)}
3
3
  The Keychain may be locked or inaccessible.
4
4
  Try unlocking it via Keychain Access.app or running 'security unlock-keychain'.`)}}async store(e,r){let n=i(e),o=JSON.stringify(r);try{await C(R,["add-generic-password","-s",P,"-a",n,"-U","-w",o],{timeout:1e4})}catch(a){throw new Error(`macOS Keychain write failed for '${n}': ${w(a)}
5
5
  Ensure the Keychain is unlocked and the CLI has write permission.
6
6
  On managed devices, your IT policy may block credential storage.`)}}async remove(e){let r=i(e);try{await C(R,["delete-generic-password","-s",P,"-a",r],{timeout:1e4})}catch(n){if(X(n,44))return;console.warn(` Warning: macOS Keychain delete failed for '${r}': ${w(n)}
7
7
  The credential may not have been fully removed.`)}}async list(){try{let{stdout:e}=await C(R,["dump-keychain"],{timeout:1e4}),r=[],n=!1;for(let o of e.split(`
8
- `))if(o.includes(`"svce"<blob>="${P}"`)&&(n=!0),n&&o.includes('"acct"<blob>=')){let a=o.match(/"acct"<blob>="([^"]+)"/);a&&r.push(a[1]),n=!1}return r}catch(e){return console.warn(` Warning: Could not enumerate Keychain entries: ${w(e)}`),[]}}};function X(t,e){return typeof t=="object"&&t!==null&&"code"in t&&t.code===e}function w(t){return t instanceof Error?t.message:String(t)}import{execFile as lr}from"child_process";import{promisify as dr}from"util";var ur=dr(lr),x="kanonak:",m=class{async get(e){let r=x+i(e),n=`
9
- ${v}
8
+ `))if(o.includes(`"svce"<blob>="${P}"`)&&(n=!0),n&&o.includes('"acct"<blob>=')){let a=o.match(/"acct"<blob>="([^"]+)"/);a&&r.push(a[1]),n=!1}return r}catch(e){return console.warn(` Warning: Could not enumerate Keychain entries: ${w(e)}`),[]}}};function X(t,e){return typeof t=="object"&&t!==null&&"code"in t&&t.code===e}function w(t){return t instanceof Error?t.message:String(t)}import{execFile as ur}from"child_process";import{promisify as pr}from"util";var mr=pr(ur),x="kanonak:",m=class{async get(e){let r=x+i(e),n=`
9
+ ${$}
10
10
  $target = [Console]::In.ReadLine()
11
11
  $ptr = [IntPtr]::Zero
12
12
  $result = [CredMan]::CredRead($target, 1, 0, [ref]$ptr)
@@ -18,8 +18,8 @@ try {
18
18
  [System.Text.Encoding]::Unicode.GetString($bytes)
19
19
  } finally {
20
20
  [CredMan]::CredFree($ptr)
21
- }`;try{let{stdout:o}=await $(n,r),a=o.trim();return a?JSON.parse(a):null}catch{return null}}async store(e,r){let n=x+i(e),o=JSON.stringify(r),a=`
22
- ${v}
21
+ }`;try{let{stdout:o}=await v(n,r),a=o.trim();return a?JSON.parse(a):null}catch{return null}}async store(e,r){let n=x+i(e),o=JSON.stringify(r),a=`
22
+ ${$}
23
23
  $target = [Console]::In.ReadLine()
24
24
  $json = [Console]::In.ReadLine()
25
25
  $bytes = [System.Text.Encoding]::Unicode.GetBytes($json)
@@ -35,13 +35,13 @@ try {
35
35
  if (-not $result) { throw "CredWrite failed" }
36
36
  } finally {
37
37
  [System.Runtime.InteropServices.Marshal]::FreeHGlobal($cred.CredentialBlob)
38
- }`;try{await $(a,`${n}
38
+ }`;try{await v(a,`${n}
39
39
  ${o}`)}catch(s){throw new Error(`Windows Credential Manager write failed: ${String(s)}`)}}async remove(e){let r=x+i(e),n=`
40
- ${v}
40
+ ${$}
41
41
  $target = [Console]::In.ReadLine()
42
- [CredMan]::CredDelete($target, 1, 0) | Out-Null`;try{await $(n,r)}catch{}}async list(){let e=`
43
- ${v}
44
- ${pr}
42
+ [CredMan]::CredDelete($target, 1, 0) | Out-Null`;try{await v(n,r)}catch{}}async list(){let e=`
43
+ ${$}
44
+ ${fr}
45
45
  $prefix = [Console]::In.ReadLine()
46
46
  $count = 0
47
47
  $pCreds = [IntPtr]::Zero
@@ -55,8 +55,8 @@ if ([CredMan]::CredEnumerate($null, 0, [ref]$count, [ref]$pCreds)) {
55
55
  }
56
56
  }
57
57
  [CredMan]::CredFree($pCreds)
58
- }`;try{let{stdout:r}=await $(e,x);return r.trim().split(`
59
- `).map(n=>n.trim()).filter(Boolean)}catch{return[]}}};async function $(t,e){for(let r of["pwsh","powershell"])try{return await ur(r,["-NoProfile","-NonInteractive","-Command",t],{timeout:15e3,...e!==void 0&&{input:e}})}catch(n){if(r==="powershell")throw n}throw new Error("Neither pwsh nor powershell found")}var v=`
58
+ }`;try{let{stdout:r}=await v(e,x);return r.trim().split(`
59
+ `).map(n=>n.trim()).filter(Boolean)}catch{return[]}}};async function v(t,e){for(let r of["pwsh","powershell"])try{return await mr(r,["-NoProfile","-NonInteractive","-Command",t],{timeout:15e3,...e!==void 0&&{input:e}})}catch(n){if(r==="powershell")throw n}throw new Error("Neither pwsh nor powershell found")}var $=`
60
60
  Add-Type -TypeDefinition @"
61
61
  using System;
62
62
  using System.Runtime.InteropServices;
@@ -87,13 +87,13 @@ public class CredMan {
87
87
  [DllImport("Advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
88
88
  public static extern bool CredEnumerate(string filter, int flags, out int count, out IntPtr credentials);
89
89
  }
90
- "@`,pr="";import{execFile as mr,spawn as fr}from"child_process";import{promisify as yr}from"util";var K=yr(mr),E="kanonak",f=class{async get(e){let r=i(e);try{let{stdout:n}=await K("secret-tool",["lookup","service",E,"publisher",r],{timeout:1e4}),o=n.trim();return o?JSON.parse(o):null}catch{return null}}async store(e,r){let n=i(e),o=JSON.stringify(r);await new Promise((a,s)=>{let c=fr("secret-tool",["store","--label",`Kanonak: ${n}`,"service",E,"publisher",n],{stdio:["pipe","ignore","ignore"],timeout:1e4});c.stdin.write(o),c.stdin.end(),c.on("close",l=>{l===0?a():s(new Error(`secret-tool store exited with code ${l}`))}),c.on("error",s)})}async remove(e){let r=i(e);try{await K("secret-tool",["clear","service",E,"publisher",r],{timeout:1e4})}catch{}}async list(){try{let{stdout:e}=await K("secret-tool",["search","service",E],{timeout:1e4}),r=[];for(let n of e.split(`
91
- `)){let o=n.match(/attribute\.publisher\s*=\s*(.+)/);o&&r.push(o[1].trim())}return r}catch{return[]}}};async function _(){try{return await K("sh",["-c","command -v secret-tool"],{timeout:5e3}),!0}catch{return!1}}import{existsSync as Z,mkdirSync as Q,readFileSync as ee,writeFileSync as te}from"fs";import{createCipheriv as gr,createDecipheriv as hr,randomBytes as re}from"crypto";import{homedir as kr}from"os";import{join as W,dirname as ne}from"path";var ae=W(kr(),".config","kanonak"),y=W(ae,"keyring.key"),I=W(ae,"credentials.enc"),oe="aes-256-gcm",z=32,u=12,G=16,g=class{async get(e){let r=this.loadStore(),n=i(e);return r[n]??null}async store(e,r){let n=this.loadStore(),o=i(e);n[o]=r,this.saveStore(n)}async remove(e){let r=this.loadStore(),n=i(e);delete r[n],this.saveStore(r)}async list(){let e=this.loadStore();return Object.keys(e)}loadStore(){if(!Z(I))return{};try{let e=this.getOrCreateKey(),r=ee(I);if(r.length<u+G)return{};let n=r.subarray(0,u),o=r.subarray(u,u+G),a=r.subarray(u+G),s=hr(oe,e,n);s.setAuthTag(o);let c=Buffer.concat([s.update(a),s.final()]);return JSON.parse(c.toString("utf-8"))}catch{return{}}}saveStore(e){let r=this.getOrCreateKey(),n=re(u),o=gr(oe,r,n),a=Buffer.from(JSON.stringify(e),"utf-8"),s=Buffer.concat([o.update(a),o.final()]),c=o.getAuthTag(),l=Buffer.concat([n,c,s]);Q(ne(I),{recursive:!0}),te(I,l,{mode:384})}getOrCreateKey(){if(Z(y)){let r=ee(y);if(r.length!==z)throw new Error(`Credential keyring key is corrupted (expected ${z} bytes, got ${r.length}). Delete ${y} and re-authenticate.`);return r}let e=re(z);return Q(ne(y),{recursive:!0}),te(y,e,{mode:384}),e}};import{execFile as br}from"child_process";import{promisify as Sr}from"util";var Cr=Sr(br),ie=3e4,h=class{constructor(e){this.helperPath=e}helperPath;async get(e){let r=i(e);try{let o=(await this.runHelper("get",{publisher:r})).trim();return o?JSON.parse(o):null}catch(n){throw new Error(`Credential helper '${this.helperPath}' failed to read credential for '${r}': ${B(n)}
90
+ "@`,fr="";import{execFile as yr,spawn as gr}from"child_process";import{promisify as hr}from"util";var K=hr(yr),E="kanonak",f=class{async get(e){let r=i(e);try{let{stdout:n}=await K("secret-tool",["lookup","service",E,"publisher",r],{timeout:1e4}),o=n.trim();return o?JSON.parse(o):null}catch{return null}}async store(e,r){let n=i(e),o=JSON.stringify(r);await new Promise((a,s)=>{let c=gr("secret-tool",["store","--label",`Kanonak: ${n}`,"service",E,"publisher",n],{stdio:["pipe","ignore","ignore"],timeout:1e4});c.stdin.write(o),c.stdin.end(),c.on("close",l=>{l===0?a():s(new Error(`secret-tool store exited with code ${l}`))}),c.on("error",s)})}async remove(e){let r=i(e);try{await K("secret-tool",["clear","service",E,"publisher",r],{timeout:1e4})}catch{}}async list(){try{let{stdout:e}=await K("secret-tool",["search","service",E],{timeout:1e4}),r=[];for(let n of e.split(`
91
+ `)){let o=n.match(/attribute\.publisher\s*=\s*(.+)/);o&&r.push(o[1].trim())}return r}catch{return[]}}};async function _(){try{return await K("sh",["-c","command -v secret-tool"],{timeout:5e3}),!0}catch{return!1}}import{existsSync as Z,mkdirSync as Q,readFileSync as ee,writeFileSync as te}from"fs";import{createCipheriv as kr,createDecipheriv as br,randomBytes as re}from"crypto";import{homedir as Sr}from"os";import{join as W,dirname as ne}from"path";var ae=W(Sr(),".config","kanonak"),y=W(ae,"keyring.key"),I=W(ae,"credentials.enc"),oe="aes-256-gcm",z=32,u=12,G=16,g=class{async get(e){let r=this.loadStore(),n=i(e);return r[n]??null}async store(e,r){let n=this.loadStore(),o=i(e);n[o]=r,this.saveStore(n)}async remove(e){let r=this.loadStore(),n=i(e);delete r[n],this.saveStore(r)}async list(){let e=this.loadStore();return Object.keys(e)}loadStore(){if(!Z(I))return{};try{let e=this.getOrCreateKey(),r=ee(I);if(r.length<u+G)return{};let n=r.subarray(0,u),o=r.subarray(u,u+G),a=r.subarray(u+G),s=br(oe,e,n);s.setAuthTag(o);let c=Buffer.concat([s.update(a),s.final()]);return JSON.parse(c.toString("utf-8"))}catch{return{}}}saveStore(e){let r=this.getOrCreateKey(),n=re(u),o=kr(oe,r,n),a=Buffer.from(JSON.stringify(e),"utf-8"),s=Buffer.concat([o.update(a),o.final()]),c=o.getAuthTag(),l=Buffer.concat([n,c,s]);Q(ne(I),{recursive:!0}),te(I,l,{mode:384})}getOrCreateKey(){if(Z(y)){let r=ee(y);if(r.length!==z)throw new Error(`Credential keyring key is corrupted (expected ${z} bytes, got ${r.length}). Delete ${y} and re-authenticate.`);return r}let e=re(z);return Q(ne(y),{recursive:!0}),te(y,e,{mode:384}),e}};import{execFile as Cr}from"child_process";import{promisify as Pr}from"util";var Rr=Pr(Cr),ie=3e4,h=class{constructor(e){this.helperPath=e}helperPath;async get(e){let r=i(e);try{let o=(await this.runHelper("get",{publisher:r})).trim();return o?JSON.parse(o):null}catch(n){throw new Error(`Credential helper '${this.helperPath}' failed to read credential for '${r}': ${B(n)}
92
92
  Verify the helper binary exists, is executable, and implements the Kanonak credential helper protocol.
93
93
  Check the 'credentialHelper' path in ~/.kanonak/config.json.`)}}async store(e,r){let n=i(e);try{await this.runHelper("store",{publisher:n,credential:r})}catch(o){throw new Error(`Credential helper '${this.helperPath}' failed to store credential for '${n}': ${B(o)}
94
- Verify the helper binary supports the 'store' action.`)}}async remove(e){let r=i(e);try{await this.runHelper("erase",{publisher:r})}catch(n){console.warn(` Warning: Credential helper '${this.helperPath}' failed to erase credential for '${r}': ${B(n)}`)}}async list(){try{let e=await this.runHelper("list",void 0);return JSON.parse(e.trim())}catch(e){return console.warn(` Warning: Credential helper '${this.helperPath}' failed to list credentials: ${B(e)}`),[]}}async runHelper(e,r){try{let{stdout:n}=await Cr(this.helperPath,[e],{...r&&{input:JSON.stringify(r)},timeout:ie});return n}catch(n){throw Pr(n)?new Error(`Credential helper not found at '${this.helperPath}'.
95
- Check the 'credentialHelper' path in ~/.kanonak/config.json.`):Rr(n)?new Error(`Credential helper '${this.helperPath}' timed out after ${ie/1e3}s on '${e}'.
96
- The helper may be waiting for authentication to an external vault.`):n}}};function B(t){return t instanceof Error?t.message:String(t)}function Pr(t){return t instanceof Error&&"code"in t&&t.code==="ENOENT"}function Rr(t){return t instanceof Error&&"killed"in t&&t.killed}var J=vr($r(),".kanonak","config.json"),T=class{backend=null;backendReady=null;async getBackend(){if(this.backend)return this.backend;if(this.backendReady)return this.backendReady;this.backendReady=this.resolveBackend();try{return this.backend=await this.backendReady,this.backend}catch(e){throw this.backendReady=null,e}}async getToken(e){let r=Er(e);if(r)return r;let o=await(await this.getBackend()).get(e);return!o||!S(o)?null:o.accessToken??null}async getCredential(e){return(await this.getBackend()).get(e)}async store(e,r){return(await this.getBackend()).store(e,r)}async remove(e){return(await this.getBackend()).remove(e)}async list(){return(await this.getBackend()).list()}async resolveBackend(){let e=Kr();return e.credentialHelper?new h(e.credentialHelper):process.platform==="darwin"?new p:process.platform==="win32"?new m:await _()?new f:new g}};function Er(t){let r="KANONAK_TOKEN_"+i(t).replace(/[.\-]/g,"_").toUpperCase();return process.env[r]??null}function Kr(){if(!wr(J))return{};try{return JSON.parse(xr(J,"utf-8"))}catch(t){let e=t instanceof Error?t.message:String(t);return console.warn(` Warning: Failed to parse ${J}: ${e}
97
- Using default credential backend. Fix the JSON syntax or delete the file.`),{}}}import{createHash as Ir,createPrivateKey as Br,generateKeyPairSync as Tr,randomUUID as jr,sign as Lr}from"crypto";function ce(){let{publicKey:t,privateKey:e}=Tr("ec",{namedCurve:"P-256"});return{publicKey:t.export({format:"jwk"}),privateKey:e.export({format:"jwk"})}}function k(t,e,r,n,o,a){let s={alg:"ES256",typ:"dpop+jwt",jwk:{kty:e.kty,crv:e.crv,x:e.x,y:e.y}},c={jti:jr(),htm:r.toUpperCase(),htu:n,iat:Math.floor(Date.now()/1e3)};return o&&(c.ath=Ir("sha256").update(o).digest("base64url")),a&&(c.nonce=a),Fr(s,c,t)}function le(t){return!t||t.length===0?!1:t.some(e=>e.toUpperCase()==="ES256")}function Fr(t,e,r){let n=se(JSON.stringify(t)),o=se(JSON.stringify(e)),a=`${n}.${o}`,s=Br({key:r,format:"jwk"}),l=Lr("SHA256",Buffer.from(a),{key:s,dsaEncoding:"ieee-p1363"}).toString("base64url");return`${a}.${l}`}function se(t){return Buffer.from(t,"utf-8").toString("base64url")}function de(t){let e=new Map;return async(r,n,o="GET")=>{if(!t)return fetch(r,{method:o});let a=await t.getCredential(n);if(!a?.accessToken)return fetch(r,{method:o});b(a)&&console.warn(` Warning: Access token for '${n}' is expired. Run 'kanonak login ${n}' to re-authenticate.`);let s={};if(a.dpopKeyPair){let l=e.get(n);try{let d=k(a.dpopKeyPair.privateKey,a.dpopKeyPair.publicKey,o,r,a.accessToken,l);s.Authorization=`DPoP ${a.accessToken}`,s.DPoP=d}catch(d){let Ce=d instanceof Error?d.message:String(d);console.error(` Error: Failed to create DPoP proof for '${n}': ${Ce}
98
- The stored key pair may be corrupted. Run 'kanonak login ${n}' to re-authenticate.`),s.Authorization=`Bearer ${a.accessToken}`}}else s.Authorization=`Bearer ${a.accessToken}`;let c=await fetch(r,{method:o,headers:s});if(c.status===401&&a.dpopKeyPair){let l=c.headers.get("DPoP-Nonce");if(l){e.set(n,l);try{let d=k(a.dpopKeyPair.privateKey,a.dpopKeyPair.publicKey,o,r,a.accessToken,l);s.DPoP=d,c=await fetch(r,{method:o,headers:s})}catch{}}}return c}}import{readFileSync as Dr,writeFileSync as Nr,existsSync as Or}from"fs";import{createHash as Ar}from"crypto";import ue from"js-yaml";var pe="kanonak.lock",Ur=`# This file is generated by Kanonak CLI. Do not edit manually.
99
- `;function me(t=pe){if(!Or(t))return null;let e=Dr(t,"utf-8"),r=ue.load(e);return!r||typeof r!="object"||r.version!=="1"?null:{version:"1",lastUpdated:r.lastUpdated??new Date().toISOString(),packages:r.packages??{}}}function fe(t,e=pe){t.lastUpdated=new Date().toISOString();let r={};for(let o of Object.keys(t.packages).sort())r[o]=t.packages[o];t.packages=r;let n=ue.dump(t,{lineWidth:-1,sortKeys:!1,quotingType:'"'});Nr(e,Ur+n,"utf-8")}function ye(t){return`sha256:${Ar("sha256").update(t).digest("hex")}`}import{createHash as Vr}from"crypto";function q(t){let e=[];for(let n of t)n instanceof L&&e.push(Hr(n));return e.sort((n,o)=>n.uri<o.uri?-1:n.uri>o.uri?1:0),JSON.stringify({subjects:e})}function ge(t){let e=q(t);return`sha256:${Vr("sha256").update(e,"utf8").digest("hex")}`}function Hr(t){let e=Jr(t),r=Y(t.statement);return{uri:e,statements:r}}function Y(t){let e=[];for(let r of t){let n=Mr(r);n&&e.push(n)}return e.sort((r,n)=>r.predicate<n.predicate?-1:r.predicate>n.predicate?1:0),e}function Mr(t){let e=Wr(t);if(!e)return;let r=_r(t);if(r)return Gr(e,r)}function _r(t){if(t instanceof O)return{type:"string",value:t.object};if(t instanceof A)return{type:"number",value:Se(t.object)};if(t instanceof U)return{type:"boolean",value:t.object};if(t instanceof V)return{type:"ref",value:ke(t.object)};if(t instanceof H){let e=t.object;return he(e)}if(t instanceof M)return{type:"list",items:t.object.map(zr)}}function he(t){let e=Y(t.statement);return t.name&&t.name.length>0?{type:"embedded",name:t.name,statements:e}:{type:"embedded",statements:e}}function zr(t){if(t instanceof D)return{type:"ref",value:ke(t)};if(t instanceof F)return he(t);if(t instanceof N){let e=t.value;if(typeof e=="string")return{type:"string",value:e};if(typeof e=="number")return{type:"number",value:Se(e)};if(typeof e=="boolean")return{type:"boolean",value:e}}if(t instanceof j)return{type:"embedded",statements:Y(t.statement)};throw new Error(`canonicalForm: list item of unrecognized kind (${t.constructor?.name??typeof t}); add canonicalization support before hashing data that contains it`)}function Gr(t,e){switch(e.type){case"string":return{predicate:t,type:"string",value:e.value};case"number":return{predicate:t,type:"number",value:e.value};case"boolean":return{predicate:t,type:"boolean",value:e.value};case"ref":return{predicate:t,type:"ref",value:e.value};case"embedded":return e.name!==void 0?{predicate:t,type:"embedded",name:e.name,statements:e.statements}:{predicate:t,type:"embedded",statements:e.statements};case"list":return{predicate:t,type:"list",items:e.items}}}function Wr(t){let e=t.predicate;if(e)return be(e.subject)}function Jr(t){let e=t.namespace??"",r=t.name??"";return`${e}/${r}`}function ke(t){return be(t.subject)}function be(t){let e=t.version;return e&&typeof e.major=="number"?`${t.publisher}/${t.package_}@${e.major}.${e.minor}.${e.patch}/${t.name}`:`${t.publisher}/${t.package_}/${t.name}`}function Se(t){if(Number.isNaN(t))throw new Error("canonicalForm: NaN cannot be canonicalized");if(!Number.isFinite(t))throw new Error("canonicalForm: \xB1Infinity cannot be canonicalized");return Object.is(t,-0)?"0":String(t)}export{qt as AmbiguousReferenceRule,U as BooleanStatement,tr as ClassDefinitionRule,Ut as ClassHierarchyCycleRule,Le as CompositeKanonakDocumentRepository,T as CredentialStore,j as DefinedKanonak,Wt as DefinitionPropertyReferenceRule,je as DocumentLocation,st as EdgeType,F as EmbeddedKanonak,Nt as EmbeddedKanonakTypeRule,H as EmbeddedStatement,Te as FileSystemKanonakDocumentRepository,ft as GitIgnoreFilter,ct as GraphBuilder,Ue as HttpKanonakDocumentRepository,Ot as ImportExistenceRule,Ie as InMemoryKanonakDocumentRepository,Gt as InstancePropertyReferenceRule,_e as Kanonak,gt as KanonakDocumentPositions,ot as KanonakObjectParser,nr as KanonakObjectValidator,Be as KanonakParser,ze as KanonakUri,bt as KanonakUriBuilder,Pt as KanonakUrlResolver,tt as KanonakVocabulary,M as ListStatement,N as LiteralKanonak,Ve as LocalFirstRepository,ir as LookRenderer,rr as MarkdownLinkRule,Je as MarkdownStatement,zt as NamespaceImportCycleRule,jt as NamespacePrefixRule,it as NodeType,A as NumberStatement,ut as OWL_RL_CLASSIFICATION_RULES,Xt as ObjectPropertyImportRule,Zt as ObjectPropertyValueValidationRule,It as OntologyValidationError,Et as OntologyValidationResult,Qt as PropertyDomainRule,Vt as PropertyHierarchyCycleRule,yt as PropertyMetadata,Yt as PropertyRangeReferenceRule,Ht as PropertyRangeRequiredRule,Ft as PropertyTypeSpecificityRule,er as PropertyValueTypeRule,Ne as PublisherConfigResolver,Oe as PublisherIndex,dt as RDFS_RULES,mt as Reasoner,pt as ReasoningResult,D as ReferenceKanonak,V as ReferenceStatement,De as RepositoryFactory,Lt as ResourceNamingRule,qe as ResourceResolver,at as ResourceTypeClassifier,We as ScalarStatement,Ge as Statement,O as StringStatement,Mt as SubClassOfReferenceRule,_t as SubPropertyOfReferenceRule,L as SubjectKanonak,Dt as SubjectKanonakTypeRequiredRule,lt as TripleStore,Ye as TypeResolver,At as UnresolvedReferenceRule,Tt as ValidationCache,Bt as ValidationContext,Kt as ValidationSeverity,go as VersionOperator,Jt as XsdImportRule,Ae as assertPackageIdentity,Me as buildLocalFirstRepository,q as canonicalForm,ge as canonicalHash,He as collectKanonakFiles,Pe as compareVersions,ye as computeIntegrity,$t as contextTypesOf,de as createAuthenticatedFetch,k as createDPoPProof,xe as createVersion,nt as extractMarkdownLinks,or as findDerivation,vt as findInstancesByType,rt as findMalformedReferences,kt as findMarkdownLinkAt,Ct as formatKanonakAddress,we as formatVersion,ce as generateDPoPKeyPair,Fe as getGlobalCachePath,S as hasValidToken,ve as isCompatibleVersion,b as isExpired,Ee as isMajorCompatible,me as loadLockFile,Ze as makeUriKey,i as normalizeHost,St as parseKanonakAddress,$e as parseVersionString,ht as parseWithPositions,Ke as pickHighestDocument,wt as propertiesInScope,ar as resolveDisplayValue,xt as resolvePropertyStep,fe as saveLockFile,le as serverSupportsDPoP,Rt as subjectUri,Qe as tripleKey,Xe as uriKey,et as uriTriple,Re as versionsEqual};
94
+ Verify the helper binary supports the 'store' action.`)}}async remove(e){let r=i(e);try{await this.runHelper("erase",{publisher:r})}catch(n){console.warn(` Warning: Credential helper '${this.helperPath}' failed to erase credential for '${r}': ${B(n)}`)}}async list(){try{let e=await this.runHelper("list",void 0);return JSON.parse(e.trim())}catch(e){return console.warn(` Warning: Credential helper '${this.helperPath}' failed to list credentials: ${B(e)}`),[]}}async runHelper(e,r){try{let{stdout:n}=await Rr(this.helperPath,[e],{...r&&{input:JSON.stringify(r)},timeout:ie});return n}catch(n){throw wr(n)?new Error(`Credential helper not found at '${this.helperPath}'.
95
+ Check the 'credentialHelper' path in ~/.kanonak/config.json.`):xr(n)?new Error(`Credential helper '${this.helperPath}' timed out after ${ie/1e3}s on '${e}'.
96
+ The helper may be waiting for authentication to an external vault.`):n}}};function B(t){return t instanceof Error?t.message:String(t)}function wr(t){return t instanceof Error&&"code"in t&&t.code==="ENOENT"}function xr(t){return t instanceof Error&&"killed"in t&&t.killed}var J=Kr(Er(),".kanonak","config.json"),T=class{backend=null;backendReady=null;async getBackend(){if(this.backend)return this.backend;if(this.backendReady)return this.backendReady;this.backendReady=this.resolveBackend();try{return this.backend=await this.backendReady,this.backend}catch(e){throw this.backendReady=null,e}}async getToken(e){let r=Ir(e);if(r)return r;let o=await(await this.getBackend()).get(e);return!o||!S(o)?null:o.accessToken??null}async getCredential(e){return(await this.getBackend()).get(e)}async store(e,r){return(await this.getBackend()).store(e,r)}async remove(e){return(await this.getBackend()).remove(e)}async list(){return(await this.getBackend()).list()}async resolveBackend(){let e=Br();return e.credentialHelper?new h(e.credentialHelper):process.platform==="darwin"?new p:process.platform==="win32"?new m:await _()?new f:new g}};function Ir(t){let r="KANONAK_TOKEN_"+i(t).replace(/[.\-]/g,"_").toUpperCase();return process.env[r]??null}function Br(){if(!vr(J))return{};try{return JSON.parse($r(J,"utf-8"))}catch(t){let e=t instanceof Error?t.message:String(t);return console.warn(` Warning: Failed to parse ${J}: ${e}
97
+ Using default credential backend. Fix the JSON syntax or delete the file.`),{}}}import{createHash as Tr,createPrivateKey as jr,generateKeyPairSync as Lr,randomUUID as Fr,sign as Dr}from"crypto";function ce(){let{publicKey:t,privateKey:e}=Lr("ec",{namedCurve:"P-256"});return{publicKey:t.export({format:"jwk"}),privateKey:e.export({format:"jwk"})}}function k(t,e,r,n,o,a){let s={alg:"ES256",typ:"dpop+jwt",jwk:{kty:e.kty,crv:e.crv,x:e.x,y:e.y}},c={jti:Fr(),htm:r.toUpperCase(),htu:n,iat:Math.floor(Date.now()/1e3)};return o&&(c.ath=Tr("sha256").update(o).digest("base64url")),a&&(c.nonce=a),Nr(s,c,t)}function le(t){return!t||t.length===0?!1:t.some(e=>e.toUpperCase()==="ES256")}function Nr(t,e,r){let n=se(JSON.stringify(t)),o=se(JSON.stringify(e)),a=`${n}.${o}`,s=jr({key:r,format:"jwk"}),l=Dr("SHA256",Buffer.from(a),{key:s,dsaEncoding:"ieee-p1363"}).toString("base64url");return`${a}.${l}`}function se(t){return Buffer.from(t,"utf-8").toString("base64url")}function de(t){let e=new Map;return async(r,n,o="GET")=>{if(!t)return fetch(r,{method:o});let a=await t.getCredential(n);if(!a?.accessToken)return fetch(r,{method:o});b(a)&&console.warn(` Warning: Access token for '${n}' is expired. Run 'kanonak login ${n}' to re-authenticate.`);let s={};if(a.dpopKeyPair){let l=e.get(n);try{let d=k(a.dpopKeyPair.privateKey,a.dpopKeyPair.publicKey,o,r,a.accessToken,l);s.Authorization=`DPoP ${a.accessToken}`,s.DPoP=d}catch(d){let Ce=d instanceof Error?d.message:String(d);console.error(` Error: Failed to create DPoP proof for '${n}': ${Ce}
98
+ The stored key pair may be corrupted. Run 'kanonak login ${n}' to re-authenticate.`),s.Authorization=`Bearer ${a.accessToken}`}}else s.Authorization=`Bearer ${a.accessToken}`;let c=await fetch(r,{method:o,headers:s});if(c.status===401&&a.dpopKeyPair){let l=c.headers.get("DPoP-Nonce");if(l){e.set(n,l);try{let d=k(a.dpopKeyPair.privateKey,a.dpopKeyPair.publicKey,o,r,a.accessToken,l);s.DPoP=d,c=await fetch(r,{method:o,headers:s})}catch{}}}return c}}import{readFileSync as Or,writeFileSync as Ar,existsSync as Ur}from"fs";import{createHash as Vr}from"crypto";import ue from"js-yaml";var pe="kanonak.lock",Hr=`# This file is generated by Kanonak CLI. Do not edit manually.
99
+ `;function me(t=pe){if(!Ur(t))return null;let e=Or(t,"utf-8"),r=ue.load(e);return!r||typeof r!="object"||r.version!=="1"?null:{version:"1",lastUpdated:r.lastUpdated??new Date().toISOString(),packages:r.packages??{}}}function fe(t,e=pe){t.lastUpdated=new Date().toISOString();let r={};for(let o of Object.keys(t.packages).sort())r[o]=t.packages[o];t.packages=r;let n=ue.dump(t,{lineWidth:-1,sortKeys:!1,quotingType:'"'});Ar(e,Hr+n,"utf-8")}function ye(t){return`sha256:${Vr("sha256").update(t).digest("hex")}`}import{createHash as Mr}from"crypto";function q(t){let e=[];for(let n of t)n instanceof L&&e.push(_r(n));return e.sort((n,o)=>n.uri<o.uri?-1:n.uri>o.uri?1:0),JSON.stringify({subjects:e})}function ge(t){let e=q(t);return`sha256:${Mr("sha256").update(e,"utf8").digest("hex")}`}function _r(t){let e=Yr(t),r=Y(t.statement);return{uri:e,statements:r}}function Y(t){let e=[];for(let r of t){let n=zr(r);n&&e.push(n)}return e.sort((r,n)=>r.predicate<n.predicate?-1:r.predicate>n.predicate?1:0),e}function zr(t){let e=qr(t);if(!e)return;let r=Gr(t);if(r)return Jr(e,r)}function Gr(t){if(t instanceof O)return{type:"string",value:t.object};if(t instanceof A)return{type:"number",value:Se(t.object)};if(t instanceof U)return{type:"boolean",value:t.object};if(t instanceof V)return{type:"ref",value:ke(t.object)};if(t instanceof H){let e=t.object;return he(e)}if(t instanceof M)return{type:"list",items:t.object.map(Wr)}}function he(t){let e=Y(t.statement);return t.name&&t.name.length>0?{type:"embedded",name:t.name,statements:e}:{type:"embedded",statements:e}}function Wr(t){if(t instanceof D)return{type:"ref",value:ke(t)};if(t instanceof F)return he(t);if(t instanceof N){let e=t.value;if(typeof e=="string")return{type:"string",value:e};if(typeof e=="number")return{type:"number",value:Se(e)};if(typeof e=="boolean")return{type:"boolean",value:e}}if(t instanceof j)return{type:"embedded",statements:Y(t.statement)};throw new Error(`canonicalForm: list item of unrecognized kind (${t.constructor?.name??typeof t}); add canonicalization support before hashing data that contains it`)}function Jr(t,e){switch(e.type){case"string":return{predicate:t,type:"string",value:e.value};case"number":return{predicate:t,type:"number",value:e.value};case"boolean":return{predicate:t,type:"boolean",value:e.value};case"ref":return{predicate:t,type:"ref",value:e.value};case"embedded":return e.name!==void 0?{predicate:t,type:"embedded",name:e.name,statements:e.statements}:{predicate:t,type:"embedded",statements:e.statements};case"list":return{predicate:t,type:"list",items:e.items}}}function qr(t){let e=t.predicate;if(e)return be(e.subject)}function Yr(t){let e=t.namespace??"",r=t.name??"";return`${e}/${r}`}function ke(t){return be(t.subject)}function be(t){let e=t.version;return e&&typeof e.major=="number"?`${t.publisher}/${t.package_}@${e.major}.${e.minor}.${e.patch}/${t.name}`:`${t.publisher}/${t.package_}/${t.name}`}function Se(t){if(Number.isNaN(t))throw new Error("canonicalForm: NaN cannot be canonicalized");if(!Number.isFinite(t))throw new Error("canonicalForm: \xB1Infinity cannot be canonicalized");return Object.is(t,-0)?"0":String(t)}export{Xt as AmbiguousReferenceRule,U as BooleanStatement,nr as ClassDefinitionRule,Ht as ClassHierarchyCycleRule,De as CompositeKanonakDocumentRepository,T as CredentialStore,j as DefinedKanonak,qt as DefinitionPropertyReferenceRule,Fe as DocumentLocation,lt as EdgeType,F as EmbeddedKanonak,At as EmbeddedKanonakTypeRule,H as EmbeddedStatement,Le as FileSystemKanonakDocumentRepository,gt as GitIgnoreFilter,dt as GraphBuilder,He as HttpKanonakDocumentRepository,Ut as ImportExistenceRule,Te as InMemoryKanonakDocumentRepository,Jt as InstancePropertyReferenceRule,Ge as Kanonak,kt as KanonakDocumentPositions,it as KanonakObjectParser,ar as KanonakObjectValidator,je as KanonakParser,We as KanonakUri,Ct as KanonakUriBuilder,wt as KanonakUrlResolver,nt as KanonakVocabulary,M as ListStatement,N as LiteralKanonak,Me as LocalFirstRepository,cr as LookRenderer,or as MarkdownLinkRule,Ye as MarkdownStatement,Wt as NamespaceImportCycleRule,Ft as NamespacePrefixRule,ct as NodeType,A as NumberStatement,mt as OWL_RL_CLASSIFICATION_RULES,Qt as ObjectPropertyImportRule,er as ObjectPropertyValueValidationRule,Tt as OntologyValidationError,It as OntologyValidationResult,tr as PropertyDomainRule,Mt as PropertyHierarchyCycleRule,ht as PropertyMetadata,Zt as PropertyRangeReferenceRule,_t as PropertyRangeRequiredRule,Nt as PropertyTypeSpecificityRule,rr as PropertyValueTypeRule,Ae as PublisherConfigResolver,Ue as PublisherIndex,pt as RDFS_RULES,yt as Reasoner,ft as ReasoningResult,D as ReferenceKanonak,V as ReferenceStatement,Oe as RepositoryFactory,Dt as ResourceNamingRule,Xe as ResourceResolver,st as ResourceTypeClassifier,qe as ScalarStatement,Je as Statement,O as StringStatement,zt as SubClassOfReferenceRule,Gt as SubPropertyOfReferenceRule,L as SubjectKanonak,Ot as SubjectKanonakTypeRequiredRule,ut as TripleStore,Ze as TypeResolver,Vt as UnresolvedReferenceRule,Lt as ValidationCache,jt as ValidationContext,Bt as ValidationSeverity,ko as VersionOperator,Yt as XsdImportRule,Ve as assertPackageIdentity,ze as buildLocalFirstRepository,q as canonicalForm,ge as canonicalHash,_e as collectKanonakFiles,we as compareVersions,ye as computeIntegrity,Et as contextTypesOf,de as createAuthenticatedFetch,k as createDPoPProof,$e as createVersion,at as extractMarkdownLinks,ir as findDerivation,Kt as findInstancesByType,ot as findMalformedReferences,St as findMarkdownLinkAt,Rt as formatKanonakAddress,ve as formatVersion,ce as generateDPoPKeyPair,Ne as getGlobalCachePath,S as hasValidToken,Ke as isCompatibleVersion,b as isExpired,Ie as isMajorCompatible,me as loadLockFile,et as makeUriKey,i as normalizeHost,Pt as parseKanonakAddress,Ee as parseVersionString,bt as parseWithPositions,Be as pickHighestDocument,vt as propertiesInScope,sr as resolveDisplayValue,$t as resolvePropertyStep,fe as saveLockFile,le as serverSupportsDPoP,xt as subjectUri,tt as tripleKey,Qe as uriKey,rt as uriTriple,Pe as versionOperatorFromChar,Re as versionOperatorToChar,xe as versionsEqual};
@@ -40,6 +40,41 @@ export interface ResolvedLook {
40
40
  export declare class LookRenderer {
41
41
  private readonly catalog;
42
42
  constructor(catalog: Kanonak[]);
43
+ /**
44
+ * Link style for emitted `<a href>`s — a RENDERING-CONTEXT concern, NOT part
45
+ * of the protocol (only YAML packages are). The axis is whether a single
46
+ * publisher is pinned:
47
+ *
48
+ * - `single-publisher` (default) — the output is fronted by ONE publisher
49
+ * domain (static `publish`, or `serve --publisher X`). We can only link
50
+ * within that publisher: same-publisher links are root-anchored
51
+ * (`/pkg/ver/name`); cross-publisher refs render as plain text, because the
52
+ * protocol does NOT guarantee another publisher serves a rendered page at
53
+ * any particular URL — only that its YAML is fetchable.
54
+ *
55
+ * - `open-world` — no single publisher is pinned (local multi-publisher dev,
56
+ * request-driven `serve`, the Kanonak Browser). You are the only consumer
57
+ * of your own world, so link freely: EVERY resource is a publisher-first
58
+ * path (`/{publisher}/pkg/ver/name`) the local resolver renders by fetching
59
+ * that publisher's YAML on demand — like a web browser fetching a new page
60
+ * and its assets, but for packages.
61
+ */
62
+ private linkMode;
63
+ /** Set the link style (see {@link linkMode}). Returns `this` for chaining. */
64
+ setLinkMode(mode: 'single-publisher' | 'open-world'): this;
65
+ /** Whether links are emitted publisher-first (open-world consumer mode). */
66
+ private get publisherFirst();
67
+ /** Root-anchored link prefix for `publisher`: `/{publisher}` open-world, else ``. */
68
+ private linkBase;
69
+ /**
70
+ * THE resource link — used by every reference, card, timeline node, markdown
71
+ * link, breadcrumb, and nav entry that points at a Kanonak resource.
72
+ */
73
+ private resourceHref;
74
+ /** Link to a package overview page (`/pkg` or `/pkg/version`). */
75
+ private packageHref;
76
+ /** Link to a publisher's root page (`/` single-publisher, `/{publisher}/` open-world). */
77
+ private publisherHref;
43
78
  /** Lazily-built syntax highlighter, sourced from the catalog's grammars. */
44
79
  private _codeHighlighter?;
45
80
  /**
@@ -1,4 +1,4 @@
1
- import type { KanonakDocument, ParseResult } from '@kanonak-protocol/types/document/models/types';
1
+ import type { KanonakDocument, Import, ParseResult } from '@kanonak-protocol/types/document/models/types';
2
2
  import type { IKanonakParser } from '@kanonak-protocol/types/document/parsing';
3
3
  export declare class KanonakParser implements IKanonakParser {
4
4
  parse(yamlText: string): KanonakDocument;
@@ -14,6 +14,15 @@ export declare class KanonakParser implements IKanonakParser {
14
14
  private parseImportsV3;
15
15
  private parseImportsLegacy;
16
16
  private parseImportFromEmbeddedObject;
17
+ /**
18
+ * Build a single {@link Import} from its parts — the canonical way to
19
+ * construct one OUTSIDE parsing a document (e.g. to request a seed package
20
+ * by address in request-driven rendering). Delegates to the same logic that
21
+ * parses an authored import, so the operator, version, and the computed
22
+ * `minVersion`/`maxVersion` are identical to a parsed import. `operator` is
23
+ * the character form (`= ~ ^ *`); `version` is a `major.minor.patch` string.
24
+ */
25
+ buildImport(packageName: string, operator: string, version: string, publisher?: string): Import;
17
26
  private parseImport;
18
27
  private parseVersionOperator;
19
28
  private calculateMaxVersion;
@@ -1 +1 @@
1
- import{a as c,b as d,c as e,d as f}from"../chunk-CYDDQF6S.js";import{c as b}from"../chunk-VJT6YUWK.js";import"../chunk-H2LEQLVD.js";import{a}from"../chunk-7CUTGGH3.js";import"../chunk-64TVBQFR.js";import"../chunk-W6T7MOKY.js";import"../chunk-FUUTGGJS.js";export{d as KanonakDocumentPositions,b as KanonakObjectParser,a as KanonakParser,c as PropertyMetadata,f as findMarkdownLinkAt,e as parseWithPositions};
1
+ import{a as c,b as d,c as e,d as f}from"../chunk-7JZUJ2K4.js";import{c as b}from"../chunk-Q6QTQWR2.js";import"../chunk-H2LEQLVD.js";import{a}from"../chunk-ORFSMEMM.js";import"../chunk-64TVBQFR.js";import"../chunk-W6T7MOKY.js";import"../chunk-FUUTGGJS.js";import"../chunk-2ACBWC7K.js";export{d as KanonakDocumentPositions,b as KanonakObjectParser,a as KanonakParser,c as PropertyMetadata,f as findMarkdownLinkAt,e as parseWithPositions};
@@ -1 +1 @@
1
- import{a as g,b as h,c as i,d as j,e as k}from"../chunk-SD5QKNBC.js";import"../chunk-VJT6YUWK.js";import"../chunk-H2LEQLVD.js";import"../chunk-7CUTGGH3.js";import{d as a,e as b,f as c,h as d,i as e,j as f}from"../chunk-64TVBQFR.js";import"../chunk-W6T7MOKY.js";import"../chunk-FUUTGGJS.js";export{f as KanonakVocabulary,i as OWL_RL_CLASSIFICATION_RULES,h as RDFS_RULES,k as Reasoner,j as ReasoningResult,g as TripleStore,e as canonicalizeBuiltinUri,b as makeUriKey,c as tripleKey,a as uriKey,d as uriTriple};
1
+ import{a as g,b as h,c as i,d as j,e as k}from"../chunk-QHJ6EY3Y.js";import"../chunk-Q6QTQWR2.js";import"../chunk-H2LEQLVD.js";import"../chunk-ORFSMEMM.js";import{d as a,e as b,f as c,h as d,i as e,j as f}from"../chunk-64TVBQFR.js";import"../chunk-W6T7MOKY.js";import"../chunk-FUUTGGJS.js";import"../chunk-2ACBWC7K.js";export{f as KanonakVocabulary,i as OWL_RL_CLASSIFICATION_RULES,h as RDFS_RULES,k as Reasoner,j as ReasoningResult,g as TripleStore,e as canonicalizeBuiltinUri,b as makeUriKey,c as tripleKey,a as uriKey,d as uriTriple};
@@ -3,6 +3,17 @@ export interface PublisherConfig {
3
3
  index?: string;
4
4
  package?: string;
5
5
  auth?: 'none' | 'oauth' | 'bearer';
6
+ /**
7
+ * Optional render contract: the look-stack packages — each a
8
+ * `publisher/package[@version]` address — a consumer must include in the
9
+ * render closure to STYLE this publisher's resources. ABSENT means "use the
10
+ * universal kanonak.org render base" (see `resolveRenderContract`). The look
11
+ * stack is discovered ambiently by the renderer, not via import edges, so
12
+ * declaring it here is how a publisher makes that dependency EXPLICIT — and
13
+ * how it overrides the universal base with its own look. Each entry is parsed
14
+ * through `parseKanonakAddress`, not string-matched.
15
+ */
16
+ render?: string[];
6
17
  }
7
18
  /**
8
19
  * The explicit, self-describing config a publisher advertises at
@@ -1 +1 @@
1
- import{a as o,c as e,d as r,e as n}from"../chunk-4FZUKBBE.js";import"../chunk-SC5M74NM.js";import"../chunk-7CUTGGH3.js";import"../chunk-FQHALFRR.js";export{n as HttpKanonakDocumentRepository,o as InMemoryKanonakDocumentRepository,e as PublisherConfigResolver,r as PublisherIndex};
1
+ import{a as o,c as e,d as r,e as n}from"../chunk-RSIZQAFL.js";import"../chunk-SC5M74NM.js";import"../chunk-ORFSMEMM.js";import"../chunk-2ACBWC7K.js";export{n as HttpKanonakDocumentRepository,o as InMemoryKanonakDocumentRepository,e as PublisherConfigResolver,r as PublisherIndex};
@@ -1 +1 @@
1
- import{a as b,b as c,c as d,d as e,e as f,f as k,g as l,h as m}from"../chunk-7RAM5KZZ.js";import{a,b as g,c as h,d as i,e as j}from"../chunk-4FZUKBBE.js";import"../chunk-SC5M74NM.js";import"../chunk-7CUTGGH3.js";import"../chunk-FQHALFRR.js";export{d as CompositeKanonakDocumentRepository,c as DocumentLocation,b as FileSystemKanonakDocumentRepository,j as HttpKanonakDocumentRepository,a as InMemoryKanonakDocumentRepository,k as LocalFirstRepository,h as PublisherConfigResolver,i as PublisherIndex,f as RepositoryFactory,m as buildLocalFirstRepository,l as collectKanonakFiles,g as defaultPublisherConfig,e as getGlobalCachePath};
1
+ import{a as b,b as c,c as d,d as e,e as f,f as k,g as l,h as m}from"../chunk-CA2EATJR.js";import{a,b as g,c as h,d as i,e as j}from"../chunk-RSIZQAFL.js";import"../chunk-SC5M74NM.js";import"../chunk-ORFSMEMM.js";import"../chunk-2ACBWC7K.js";export{d as CompositeKanonakDocumentRepository,c as DocumentLocation,b as FileSystemKanonakDocumentRepository,j as HttpKanonakDocumentRepository,a as InMemoryKanonakDocumentRepository,k as LocalFirstRepository,h as PublisherConfigResolver,i as PublisherIndex,f as RepositoryFactory,m as buildLocalFirstRepository,l as collectKanonakFiles,g as defaultPublisherConfig,e as getGlobalCachePath};
@@ -82,10 +82,17 @@ export declare class KanonakUrlResolver {
82
82
  *
83
83
  * Default: full URL with `https://` scheme. Pass `pathOnly: true` to
84
84
  * get the path component only — useful for same-publisher links.
85
+ *
86
+ * `publisherFirst: true` emits a PUBLISHER-FIRST path
87
+ * (`/{publisher}/{package}/{version}/{name}`) instead — the form a
88
+ * request-driven consumer (the Kanonak Browser, request-driven `serve`)
89
+ * uses so EVERY resource, same- or cross-publisher, resolves back through
90
+ * one local origin. It takes precedence over `pathOnly`/`scheme`.
85
91
  */
86
92
  static format(address: UrlAddress, opts?: {
87
93
  scheme?: 'https' | 'http';
88
94
  pathOnly?: boolean;
95
+ publisherFirst?: boolean;
89
96
  }): string;
90
97
  /**
91
98
  * Format a pinned resource reference as a URL with a specific
@@ -110,5 +117,6 @@ export declare class KanonakUrlResolver {
110
117
  }, urlForm: UrlForm, opts?: {
111
118
  scheme?: 'https' | 'http';
112
119
  contextPublisher?: string;
120
+ publisherFirst?: boolean;
113
121
  }): string;
114
122
  }
@@ -1,4 +1,16 @@
1
1
  import type { Version, KanonakDocument } from '@kanonak-protocol/types/document/models/types';
2
+ import { VersionOperator } from '@kanonak-protocol/types/document/models/enums';
3
+ /**
4
+ * The canonical mapping between an import's operator character (`= ~ ^ *`) and
5
+ * its {@link VersionOperator}. This is the ONE source of truth for that
6
+ * correspondence: the parser uses it to read operators and to serialize them
7
+ * back, so no code switches on raw enum numbers or indexes a positional array
8
+ * (the historical source of an enum-name/value mismatch). An unknown character
9
+ * falls back to `Compatible` (`~`), the parser's long-standing default.
10
+ */
11
+ export declare function versionOperatorFromChar(op: string): VersionOperator;
12
+ /** The inverse of {@link versionOperatorFromChar}: operator → its character. */
13
+ export declare function versionOperatorToChar(op: VersionOperator): string;
2
14
  export declare function compareVersions(a: Version, b: Version): number;
3
15
  export declare function versionsEqual(a: Version, b: Version): boolean;
4
16
  export declare function formatVersion(v: Version): string;
@@ -14,5 +14,5 @@ export type { PropertyDescriptor, PropertyKind, StepResolution } from './TypeDir
14
14
  export { ResourceTypeClassifier } from './ResourceTypeClassifier.js';
15
15
  export { findInstancesByType } from './InstanceSearch.js';
16
16
  export type { InstanceSearchResult } from './InstanceSearch.js';
17
- export { compareVersions, versionsEqual, formatVersion, parseVersionString, createVersion, isCompatibleVersion, isMajorCompatible, pickHighestDocument, } from './VersionUtils.js';
17
+ export { compareVersions, versionsEqual, formatVersion, parseVersionString, createVersion, isCompatibleVersion, isMajorCompatible, pickHighestDocument, versionOperatorFromChar, versionOperatorToChar, } from './VersionUtils.js';
18
18
  export type { DocumentVersionPick } from './VersionUtils.js';
@@ -1 +1 @@
1
- import{a as n,b as v}from"../chunk-PEUTCG3B.js";import{a as q}from"../chunk-NIGFQYVA.js";import{a as i}from"../chunk-SC5M74NM.js";import{a as m,b as o,c as p,d as r,e as s,f as t,g as u}from"../chunk-N224PFBI.js";import"../chunk-Q4DKP5DO.js";import{a,b,c,d,e,f,g,h}from"../chunk-FQHALFRR.js";import{b as k,c as l}from"../chunk-64TVBQFR.js";import"../chunk-W6T7MOKY.js";import{a as j}from"../chunk-FUUTGGJS.js";export{j as KanonakUri,n as KanonakUriBuilder,q as KanonakUrlResolver,k as ResourceResolver,m as ResourceTypeClassifier,l as TypeResolver,i as assertPackageIdentity,a as compareVersions,u as contextTypesOf,d as createVersion,v as findInstancesByType,p as formatKanonakAddress,c as formatVersion,f as isCompatibleVersion,g as isMajorCompatible,o as parseKanonakAddress,e as parseVersionString,h as pickHighestDocument,s as propertiesInScope,t as resolvePropertyStep,r as subjectUri,b as versionsEqual};
1
+ import{a as p,b as x}from"../chunk-PEUTCG3B.js";import{a as s}from"../chunk-PEJALHXK.js";import{a as k}from"../chunk-SC5M74NM.js";import{a as o,b as q,c as r,d as t,e as u,f as v,g as w}from"../chunk-N224PFBI.js";import"../chunk-Q4DKP5DO.js";import{b as m,c as n}from"../chunk-64TVBQFR.js";import"../chunk-W6T7MOKY.js";import{a as l}from"../chunk-FUUTGGJS.js";import{a,b,c,d,e,f,g,h,i,j}from"../chunk-2ACBWC7K.js";export{l as KanonakUri,p as KanonakUriBuilder,s as KanonakUrlResolver,m as ResourceResolver,o as ResourceTypeClassifier,n as TypeResolver,k as assertPackageIdentity,c as compareVersions,w as contextTypesOf,f as createVersion,x as findInstancesByType,r as formatKanonakAddress,e as formatVersion,h as isCompatibleVersion,i as isMajorCompatible,q as parseKanonakAddress,g as parseVersionString,j as pickHighestDocument,u as propertiesInScope,v as resolvePropertyStep,t as subjectUri,a as versionOperatorFromChar,b as versionOperatorToChar,d as versionsEqual};
@@ -1,4 +1,4 @@
1
- import{a as p}from"../chunk-ESYVKB25.js";import"../chunk-3NEUHF7E.js";import"../chunk-PEUTCG3B.js";import"../chunk-NIGFQYVA.js";import"../chunk-SC5M74NM.js";import"../chunk-H2LEQLVD.js";import{d as m,g as x}from"../chunk-N224PFBI.js";import{a as d,f as S}from"../chunk-Q4DKP5DO.js";import{a as v}from"../chunk-FQHALFRR.js";import"../chunk-64TVBQFR.js";import{c as j}from"../chunk-W6T7MOKY.js";import"../chunk-FUUTGGJS.js";import{homedir as P}from"os";import{join as k}from"path";import{existsSync as B,mkdirSync as C,readFileSync as D,writeFileSync as O}from"fs";import{createHash as z}from"crypto";var f="Xenova/all-MiniLM-L6-v2",w="q8",b=32,g=null;async function K(){return g||(g=(async()=>{let t;try{t=await import("@huggingface/transformers")}catch(i){throw new Error(`Semantic search requires the embedding runtime, which is an optional dependency.
1
+ import{a as p}from"../chunk-IL6VHYRU.js";import"../chunk-3NEUHF7E.js";import"../chunk-PEUTCG3B.js";import"../chunk-PEJALHXK.js";import"../chunk-SC5M74NM.js";import"../chunk-H2LEQLVD.js";import{d as m,g as x}from"../chunk-N224PFBI.js";import{a as d,f as S}from"../chunk-Q4DKP5DO.js";import"../chunk-64TVBQFR.js";import{c as j}from"../chunk-W6T7MOKY.js";import"../chunk-FUUTGGJS.js";import{c as v}from"../chunk-2ACBWC7K.js";import{homedir as P}from"os";import{join as k}from"path";import{existsSync as B,mkdirSync as C,readFileSync as D,writeFileSync as O}from"fs";import{createHash as z}from"crypto";var f="Xenova/all-MiniLM-L6-v2",w="q8",b=32,g=null;async function K(){return g||(g=(async()=>{let t;try{t=await import("@huggingface/transformers")}catch(i){throw new Error(`Semantic search requires the embedding runtime, which is an optional dependency.
2
2
  Install it with:
3
3
  npm install @huggingface/transformers
4
4
  (underlying import error: ${i.message})`)}let{pipeline:r,env:n}=t;n.cacheDir=k(P(),".kanonak","models");let e=await r("feature-extraction",f,{dtype:w});return async i=>(await e(i,{pooling:"mean",normalize:!0})).tolist()})()),g}function H(t,r){let n=0;for(let e=0;e<t.length;e++)n+=t[e]*r[e];return n}function U(t,r){return r?t.version?r.version?v(t.version,r.version)>0:!0:!1:!0}function F(t,r){let n=p(t,r),e=[n.label],i=x(r);if(i.length>0){let s=S(t,i[0]),c=s?p(t,s).label:i[0].name;c&&e.push(`\u2014 a ${c}.`)}return n.summary&&e.push(n.summary),e.join(" ")}function M(t){let r=new Map;for(let n of t){if(!(n instanceof j))continue;let e=m(n);if(!e)continue;let i=d(e),s=r.get(i);(!s||U(e,m(s)))&&r.set(i,n)}return[...r.values()].sort((n,e)=>{let i=m(n)?d(m(n)):n.name,s=m(e)?d(m(e)):e.name;return i.localeCompare(s)})}var y=class{entries=[];get size(){return this.entries.length}async build(r,n={}){let e=M(r);if(n.include&&(e=e.filter(n.include)),e.length===0)return this.entries=[],{size:0,cached:!1};let i=e.map(o=>F(r,o)),s=n.cacheDir,c;if(s){let o=z("sha256").update(f+"|"+w+`
@@ -0,0 +1,21 @@
1
+ import type { Kanonak } from '../kanonaks/index.js';
2
+ import type { LookRenderer } from '../look/index.js';
3
+ import type { ServerModel } from './types.js';
4
+ /**
5
+ * Build the route-facing indexes for a {@link ServerModel} from an already-built
6
+ * catalog + `LookRenderer`, scoped to the served publisher's `localNamespaces`.
7
+ *
8
+ * This is the half of model-building that is identical whether the seed came
9
+ * from a workspace scan (`loadServerModel`) or an address fetched over HTTP
10
+ * (`loadResourceModel`): given the catalog, the renderer, which namespaces the
11
+ * served publisher owns, and their raw sources, it produces `bySubject` /
12
+ * `pkgVersions` / `pkgSelfByVer`. Pure — no I/O.
13
+ */
14
+ export declare function assembleServerModel(params: {
15
+ publisher: string;
16
+ availablePublishers: string[];
17
+ catalog: Kanonak[];
18
+ lookRenderer: LookRenderer;
19
+ localNamespaces: Set<string>;
20
+ rawByNsKey: Map<string, string>;
21
+ }): ServerModel;
@@ -1,4 +1,10 @@
1
1
  export { loadServerModel } from './loadServerModel.js';
2
+ export { loadResourceModel } from './loadResourceModel.js';
3
+ export type { LoadResourceModelOptions } from './loadResourceModel.js';
2
4
  export { route } from './route.js';
5
+ export { RequestRouter, landingPage } from './requestRouter.js';
6
+ export type { RequestRouterOptions } from './requestRouter.js';
3
7
  export { deriveImportClosure, ClosureScopedRepository } from './closure.js';
8
+ export { UNIVERSAL_RENDER_BASE, resolveRenderContract, renderRefKey, } from './renderStack.js';
9
+ export type { RenderPackageRef } from './renderStack.js';
4
10
  export type { ServerModel, RouteResponse, LoadServerModelOptions, PackageVersion, } from './types.js';
@@ -1,3 +1,3 @@
1
- import{c as z}from"../chunk-ESYVKB25.js";import"../chunk-3NEUHF7E.js";import{a as W,d as _,f as U,g as G}from"../chunk-7RAM5KZZ.js";import{a as L,b as B,d as H,e as T}from"../chunk-4FZUKBBE.js";import{a as J}from"../chunk-NIGFQYVA.js";import"../chunk-SC5M74NM.js";import{c as q}from"../chunk-VJT6YUWK.js";import"../chunk-H2LEQLVD.js";import{a as O}from"../chunk-7CUTGGH3.js";import"../chunk-Q4DKP5DO.js";import{a as P,e as E}from"../chunk-FQHALFRR.js";import"../chunk-64TVBQFR.js";import{c as Y}from"../chunk-W6T7MOKY.js";import"../chunk-FUUTGGJS.js";import{readFileSync as ne,existsSync as te,readdirSync as re,writeFileSync as oe,mkdirSync as se}from"fs";import{join as C}from"path";function Q(o){let e=o.metadata?.namespace_;return e?`${e.publisher}/${e.package_}`:void 0}async function V(o,e){let t=new Set,r=[...o];for(;r.length>0;){let s=r.shift(),d=Q(s);if(!d||t.has(d))continue;t.add(d);let m=s.metadata?.imports;if(m)for(let[u,w]of Object.entries(m))for(let b of w)try{let i=await e.getHighestCompatibleVersionAsync(u,b);i&&r.push(i)}catch{}}return t}var $=class{constructor(e,t){this.inner=e;this.scope=t}inner;scope;async getAllDocumentsAsync(){return(await this.inner.getAllDocumentsAsync()).filter(t=>{let r=Q(t);return r!==void 0&&this.scope.has(r)})}getDocumentAsync(e){return this.inner.getDocumentAsync(e)}getDocumentsByNamespaceAsync(e,t){return this.inner.getDocumentsByNamespaceAsync(e,t)}getHighestCompatibleVersionAsync(e,t){return this.inner.getHighestCompatibleVersionAsync(e,t)}saveDocumentAsync(e,t){return this.inner.saveDocumentAsync(e,t)}deleteDocumentAsync(e){return this.inner.deleteDocumentAsync(e)}clearNamespaceAsync(e,t){return this.inner.clearNamespaceAsync(e,t)}getAllDocumentReferencesAsync(){return this.inner.getAllDocumentReferencesAsync()}getDocumentContentAsync(e){return this.inner.getDocumentContentAsync(e)}getDocumentUriAsync(e){return this.inner.getDocumentUriAsync(e)}};var X=["core-kanonak","site","link","look-tokens","look-styles","look","universal-look"];async function ie(o,e={}){let t=new O,r=new L(t),s=[],d=[];for(let n of G(o)){let p;try{p=ne(n,"utf-8")}catch{continue}let a;try{a=t.parse(p).metadata?.namespace_}catch{continue}if(!a?.version)continue;let k=a.version;d.push({publisher:a.publisher,package_:a.package_,verStr:`${k.major}.${k.minor}.${k.patch}`,version:k,source:p})}d.sort((n,p)=>P(p.version,n.version));for(let n of d)await r.saveDocumentAsync(t.parse(n.source),`${n.publisher}/${n.package_}@${n.verStr}`),s.push({publisher:n.publisher,package_:n.package_,verStr:n.verStr,source:n.source});let m=[...new Set(s.map(n=>n.publisher))].sort(),u=e.publisher;if(u){if(!m.includes(u))throw new Error(`Publisher "${u}" not found in workspace. Available: ${m.join(", ")||"(none)"}`)}else if(m.length===1)u=m[0];else throw m.length===0?new Error(`No Kanonak packages found under ${o}`):new Error(`Workspace has multiple publishers (${m.join(", ")}). Pass --publisher <domain> to choose which one to serve.`);let w=new Set,b=new Map;for(let n of s)n.publisher===u&&(w.add(`${n.publisher}/${n.package_}@${n.verStr}`),b.set(`${n.package_}@${n.verStr}`,n.source));let i=new W(_(),!0,t),c=e.repository??new U(r,i,new T(e.httpCache?{getFromCache:e.httpCache.getFromCache,onFetch:e.httpCache.onFetch}:void 0));if(!e.repository){let n=_(),p=h=>C(n,h),a=h=>{let v=p(h);return te(v)?new Set(re(v).filter(K=>K.endsWith(".kan.yml")).map(K=>K.split("@")[0])):new Set},k=h=>s.some(v=>v.publisher==="kanonak.org"&&v.package_===h),R=new H,x=a("kanonak.org");for(let h of X)if(!(x.has(h)||k(h)))try{let v=await R.getHighestVersion("kanonak.org",h);if(!v)continue;let K=await R.getPackageUrl("kanonak.org",h,v),I=await fetch(K);if(!I.ok)continue;let ee=await I.text(),F=C(n,"kanonak.org");se(F,{recursive:!0}),oe(C(F,`${h}@${v}.kan.yml`),ee,"utf-8")}catch{}}let l=c;if(!e.repository){let n=(await r.getAllDocumentsAsync()).filter(a=>a.metadata.namespace_?.publisher===u),p=await V(n,c);for(let a of X)p.add(`kanonak.org/${a}`);l=new $(c,p)}let y=await new q(t).parseKanonaks(l),D=new z(y),j=new Map,A=new Map,N=new Map,M=new Set;for(let n of y){if(!(n instanceof Y))continue;let p=n.namespace||"";if(!w.has(p))continue;j.set(`${p}/${n.name}`,n);let a=p.split("/")[1]??"",[k,R]=a.split("@");if(!k||!R)continue;let x=E(R);x&&(M.has(a)||(M.add(a),A.has(k)||A.set(k,[]),A.get(k).push({verStr:R,version:x})),n.name===k&&N.set(a,n))}for(let n of A.values())n.sort((p,a)=>P(a.version,p.version));return{publisher:u,availablePublishers:m,catalog:y,lookRenderer:D,localNamespaces:w,rawByNsKey:b,bySubject:j,pkgVersions:A,pkgSelfByVer:N}}var g={".html":"text/html; charset=utf-8",".css":"text/css; charset=utf-8",".svg":"image/svg+xml",".md":"text/markdown; charset=utf-8",".kan.yml":"application/yaml; charset=utf-8",".txt":"text/plain; charset=utf-8",".json":"application/json; charset=utf-8"},f=(o,e,t,r)=>({status:o,headers:{"Content-Type":e,...r||{}},body:t}),S=o=>f(404,g[".html"],`<!doctype html><meta charset=utf-8><title>404</title><h1>404</h1><p>Not found: ${o}</p>`),ce=o=>({status:301,headers:{Location:o},body:""});function Z(o,e,t){let r=o.pkgVersions.get(e);if(!r||r.length===0)return null;switch(t.kind){case"any":return r[0].verStr;case"major-pin":return r.find(s=>s.version.major===t.major)?.verStr??null;case"minor-pin":return r.find(s=>s.version.major===t.major&&s.version.minor===t.minor)?.verStr??null;case"exact":return r.find(s=>s.version.major===t.major&&s.version.minor===t.minor&&s.version.patch===t.patch)?.verStr??null;default:return null}}function ae(o,e,t=""){let{lookRenderer:r,publisher:s}=o;if(e==="/.well-known/kanonak.json")return f(200,g[".json"],JSON.stringify(B(s),null,2));if(e==="/index.txt"){let c=[...o.localNamespaces].map(l=>l.split("/")[1].replace("@","/")).sort();return f(200,g[".txt"],c.join(`
1
+ import{c as L}from"../chunk-IL6VHYRU.js";import"../chunk-3NEUHF7E.js";import{a as J,d as K,f as X,g as Z}from"../chunk-CA2EATJR.js";import{a as Y,b as z,c as Q,d as F,e as V}from"../chunk-RSIZQAFL.js";import"../chunk-PEUTCG3B.js";import{a as re}from"../chunk-PEJALHXK.js";import"../chunk-SC5M74NM.js";import{c as N}from"../chunk-Q6QTQWR2.js";import"../chunk-H2LEQLVD.js";import{a as C}from"../chunk-ORFSMEMM.js";import{b as I}from"../chunk-N224PFBI.js";import"../chunk-Q4DKP5DO.js";import"../chunk-64TVBQFR.js";import{c as ee}from"../chunk-W6T7MOKY.js";import"../chunk-FUUTGGJS.js";import{c as M,g as G}from"../chunk-2ACBWC7K.js";import{readFileSync as ce,existsSync as le,readdirSync as pe,writeFileSync as ue,mkdirSync as de}from"fs";import{join as H}from"path";function te(s){let e=s.metadata?.namespace_;return e?`${e.publisher}/${e.package_}`:void 0}async function j(s,e){let n=new Set,r=[...s];for(;r.length>0;){let t=r.shift(),d=te(t);if(!d||n.has(d))continue;n.add(d);let m=t.metadata?.imports;if(m)for(let[l,g]of Object.entries(m))for(let y of g)try{let p=await e.getHighestCompatibleVersionAsync(l,y);p&&r.push(p)}catch{}}return n}var $=class{constructor(e,n){this.inner=e;this.scope=n}inner;scope;async getAllDocumentsAsync(){return(await this.inner.getAllDocumentsAsync()).filter(n=>{let r=te(n);return r!==void 0&&this.scope.has(r)})}getDocumentAsync(e){return this.inner.getDocumentAsync(e)}getDocumentsByNamespaceAsync(e,n){return this.inner.getDocumentsByNamespaceAsync(e,n)}getHighestCompatibleVersionAsync(e,n){return this.inner.getHighestCompatibleVersionAsync(e,n)}saveDocumentAsync(e,n){return this.inner.saveDocumentAsync(e,n)}deleteDocumentAsync(e){return this.inner.deleteDocumentAsync(e)}clearNamespaceAsync(e,n){return this.inner.clearNamespaceAsync(e,n)}getAllDocumentReferencesAsync(){return this.inner.getAllDocumentReferencesAsync()}getDocumentContentAsync(e){return this.inner.getDocumentContentAsync(e)}getDocumentUriAsync(e){return this.inner.getDocumentUriAsync(e)}};var ne=[{publisher:"kanonak.org",package_:"core-kanonak"},{publisher:"kanonak.org",package_:"site"},{publisher:"kanonak.org",package_:"link"},{publisher:"kanonak.org",package_:"look-tokens"},{publisher:"kanonak.org",package_:"look-styles"},{publisher:"kanonak.org",package_:"look"},{publisher:"kanonak.org",package_:"universal-look"}];function A(s){let e=s?.render;if(e&&e.length>0){let n=[];for(let r of e)try{let t=I(r);t.kind==="package"?n.push({publisher:t.publisher,package_:t.package_}):t.kind==="resource"&&n.push({publisher:t.uri.publisher,package_:t.uri.package_})}catch{}if(n.length>0)return n}return ne}function B(s){return`${s.publisher}/${s.package_}`}function E(s){let{publisher:e,availablePublishers:n,catalog:r,lookRenderer:t,localNamespaces:d,rawByNsKey:m}=s,l=new Map,g=new Map,y=new Map,p=new Set;for(let c of r){if(!(c instanceof ee))continue;let u=c.namespace||"";if(!d.has(u))continue;l.set(`${u}/${c.name}`,c);let h=u.split("/")[1]??"",[v,x]=h.split("@");if(!v||!x)continue;let a=G(x);a&&(p.has(h)||(p.add(h),g.has(v)||g.set(v,[]),g.get(v).push({verStr:x,version:a})),c.name===v&&y.set(h,c))}for(let c of g.values())c.sort((u,h)=>M(h.version,u.version));return{publisher:e,availablePublishers:n,catalog:r,lookRenderer:t,localNamespaces:d,rawByNsKey:m,bySubject:l,pkgVersions:g,pkgSelfByVer:y}}async function q(s,e={}){let n=new C,r=new Y(n),t=[],d=[];for(let a of Z(s)){let w;try{w=ce(a,"utf-8")}catch{continue}let b;try{b=n.parse(w).metadata?.namespace_}catch{continue}if(!b?.version)continue;let _=b.version;d.push({publisher:b.publisher,package_:b.package_,verStr:`${_.major}.${_.minor}.${_.patch}`,version:_,source:w})}d.sort((a,w)=>M(w.version,a.version));for(let a of d)await r.saveDocumentAsync(n.parse(a.source),`${a.publisher}/${a.package_}@${a.verStr}`),t.push({publisher:a.publisher,package_:a.package_,verStr:a.verStr,source:a.source});let m=[...new Set(t.map(a=>a.publisher))].sort(),l=e.publisher;if(l){if(!m.includes(l))throw new Error(`Publisher "${l}" not found in workspace. Available: ${m.join(", ")||"(none)"}`)}else if(m.length===1)l=m[0];else throw m.length===0?new Error(`No Kanonak packages found under ${s}`):new Error(`Workspace has multiple publishers (${m.join(", ")}). Pass --publisher <domain> to choose which one to serve.`);let g=new Set,y=new Map;for(let a of t)a.publisher===l&&(g.add(`${a.publisher}/${a.package_}@${a.verStr}`),y.set(`${a.package_}@${a.verStr}`,a.source));let p=new J(K(),!0,n),c=e.repository??new X(r,p,new V(e.httpCache?{getFromCache:e.httpCache.getFromCache,onFetch:e.httpCache.onFetch}:void 0)),u=A(void 0);if(!e.repository){let a=K(),w=o=>{let f=H(a,o);return le(f)?new Set(pe(f).filter(k=>k.endsWith(".kan.yml")).map(k=>k.split("@")[0])):new Set},b=(o,f)=>t.some(k=>k.publisher===o&&k.package_===f),_=new F,i=new Map;for(let o of u)if(i.has(o.publisher)||i.set(o.publisher,w(o.publisher)),!(i.get(o.publisher).has(o.package_)||b(o.publisher,o.package_)))try{let f=await _.getHighestVersion(o.publisher,o.package_);if(!f)continue;let k=await _.getPackageUrl(o.publisher,o.package_,f),D=await fetch(k);if(!D.ok)continue;let ie=await D.text(),W=H(a,o.publisher);de(W,{recursive:!0}),ue(H(W,`${o.package_}@${f}.kan.yml`),ie,"utf-8")}catch{}}let h=c;if(!e.repository){let a=(await r.getAllDocumentsAsync()).filter(b=>b.metadata.namespace_?.publisher===l),w=await j(a,c);for(let b of u)w.add(B(b));h=new $(c,w)}let v=await new N(n).parseKanonaks(h),x=new L(v);return E({publisher:l,availablePublishers:m,catalog:v,lookRenderer:x,localNamespaces:g,rawByNsKey:y})}import{existsSync as me,readFileSync as ge,writeFileSync as fe,mkdirSync as he}from"fs";import{join as oe}from"path";async function O(s,e={}){let n=new C,r=I(s),t=r.kind==="resource"?r.uri.publisher:r.publisher,d=e.cacheRoot??K(),m=(i,o,f)=>oe(d,i,`${o}@${f}.kan.yml`),l=new V({getFromCache:(i,o,f)=>{let k=m(i,o,f);return me(k)?ge(k,"utf-8"):null},onFetch:(i,o,f,k)=>{let D=oe(d,i);he(D,{recursive:!0}),fe(m(i,o,f),k,"utf-8")},...e.fetchFn?{fetchFn:e.fetchFn}:{}}),g=new F(e.fetchFn?{fetchFn:e.fetchFn}:void 0),y;if(r.kind==="resource"){let i=r.uri.version;y=[i?{package_:r.uri.package_,version:`${i.major}.${i.minor}.${i.patch}`}:{package_:r.uri.package_}]}else if(r.kind==="package"){let i=r.version;y=[i?{package_:r.package_,version:`${i.major}.${i.minor}.${i.patch}`}:{package_:r.package_}]}else y=(await g.listLatestPackages(t)).map(o=>({package_:o.packageName}));let p=async(i,o,f)=>{try{let k=f?n.buildImport(o,"=",f,i):n.buildImport(o,"*","0.0.0",i);return await l.getHighestCompatibleVersionAsync(i,k)}catch{return null}},c=[];for(let i of y){let o=await p(t,i.package_,i.version);o&&c.push(o)}if(c.length===0)throw new Error(`Could not fetch any package for address "${s}" from publisher "${t}".`);let u=await new Q().getConfig(t).catch(()=>{}),h=[];for(let i of A(u)){let o=await p(i.publisher,i.package_,void 0);o&&h.push(o)}let v=await j([...c,...h],l),x=new $(l,v),a=await new N(n).parseKanonaks(x),w=new L(a),b=new Set,_=new Map;for(let i of await l.getAllDocumentsAsync()){let o=i.metadata.namespace_;if(!o||o.publisher!==t)continue;let f=`${o.version.major}.${o.version.minor}.${o.version.patch}`,k=`${o.publisher}/${o.package_}@${f}`;b.add(k);let D=await l.getDocumentContentAsync(k);D!==null&&_.set(`${o.package_}@${f}`,D)}return E({publisher:t,availablePublishers:[t],catalog:a,lookRenderer:w,localNamespaces:b,rawByNsKey:_})}var R={".html":"text/html; charset=utf-8",".css":"text/css; charset=utf-8",".svg":"image/svg+xml",".md":"text/markdown; charset=utf-8",".kan.yml":"application/yaml; charset=utf-8",".txt":"text/plain; charset=utf-8",".json":"application/json; charset=utf-8"},S=(s,e,n,r)=>({status:s,headers:{"Content-Type":e,...r||{}},body:n}),P=s=>S(404,R[".html"],`<!doctype html><meta charset=utf-8><title>404</title><h1>404</h1><p>Not found: ${s}</p>`),ke=s=>({status:301,headers:{Location:s},body:""});function se(s,e,n){let r=s.pkgVersions.get(e);if(!r||r.length===0)return null;switch(n.kind){case"any":return r[0].verStr;case"major-pin":return r.find(t=>t.version.major===n.major)?.verStr??null;case"minor-pin":return r.find(t=>t.version.major===n.major&&t.version.minor===n.minor)?.verStr??null;case"exact":return r.find(t=>t.version.major===n.major&&t.version.minor===n.minor&&t.version.patch===n.patch)?.verStr??null;default:return null}}function T(s,e,n=""){let{lookRenderer:r,publisher:t}=s;if(e==="/.well-known/kanonak.json")return S(200,R[".json"],JSON.stringify(z(t),null,2));if(e==="/index.txt"){let c=[...s.localNamespaces].map(u=>u.split("/")[1].replace("@","/")).sort();return S(200,R[".txt"],c.join(`
2
2
  `)+`
3
- `)}if(e==="/"||e==="/index.html"||e==="/index.css"){let c=r.publisherSubject(s);return e==="/index.css"?f(200,g[".css"],r.renderStylesheet(c)):f(200,g[".html"],r.renderDocument(c,{rootIndex:!0}))}let d=".html",m=!1,u=e;for(let c of[".kan.yml",".css",".svg",".md",".html"])if(e.endsWith(c)){d=c,m=!0,u=e.slice(0,-c.length);break}let w=!m&&/application\/yaml|text\/yaml/i.test(t),b=u.endsWith("/");b&&u!=="/"&&(u=u.slice(0,-1));let i=J.parse(u,s);if(!i)return S(e);if(i.kind==="package"){let c=Z(o,i.package_,i.versionSpec);if(!c)return S(e);if(d===".kan.yml"||w){let D=o.rawByNsKey.get(`${i.package_}@${c}`);return D!==void 0?f(200,g[".kan.yml"],D):S(e)}let l=o.pkgSelfByVer.get(`${i.package_}@${c}`);if(!l)return S(e);if(d===".css")return f(200,g[".css"],r.renderStylesheet(l));if(!b)return ce(u+"/");let y=i.versionSpec.kind==="any";if(y&&!r.hasDeclaredView(l)){let D=(o.pkgVersions.get(i.package_)||[]).map(j=>j.verStr);return f(200,g[".html"],r.renderPackageVersionList(i.package_,D,l))}return f(200,g[".html"],r.renderDocument(l,y?{bareOverview:!0}:void 0))}if(i.kind==="resource"){let c=Z(o,i.package_,i.versionSpec);if(!c)return S(e);let l=o.bySubject.get(`${s}/${i.package_}@${c}/${i.name}`);if(!l)return S(e);switch(d){case".css":return f(200,g[".css"],r.renderStylesheet(l));case".svg":return f(200,g[".svg"],r.renderSvg(l));case".md":{let y=r.renderRawMarkdown(l);return y===void 0?S(e):f(200,g[".md"],y)}default:return f(200,g[".html"],r.renderDocument(l))}}return S(e)}export{$ as ClosureScopedRepository,V as deriveImportClosure,ie as loadServerModel,ae as route};
3
+ `)}if(e==="/"||e==="/index.html"||e==="/index.css"){let c=r.publisherSubject(t);return e==="/index.css"?S(200,R[".css"],r.renderStylesheet(c)):S(200,R[".html"],r.renderDocument(c,{rootIndex:!0}))}let d=".html",m=!1,l=e;for(let c of[".kan.yml",".css",".svg",".md",".html"])if(e.endsWith(c)){d=c,m=!0,l=e.slice(0,-c.length);break}let g=!m&&/application\/yaml|text\/yaml/i.test(n),y=l.endsWith("/");y&&l!=="/"&&(l=l.slice(0,-1));let p=re.parse(l,t);if(!p)return P(e);if(p.kind==="package"){let c=se(s,p.package_,p.versionSpec);if(!c)return P(e);if(d===".kan.yml"||g){let v=s.rawByNsKey.get(`${p.package_}@${c}`);return v!==void 0?S(200,R[".kan.yml"],v):P(e)}let u=s.pkgSelfByVer.get(`${p.package_}@${c}`);if(!u)return P(e);if(d===".css")return S(200,R[".css"],r.renderStylesheet(u));if(!y)return ke(l+"/");let h=p.versionSpec.kind==="any";if(h&&!r.hasDeclaredView(u)){let v=(s.pkgVersions.get(p.package_)||[]).map(x=>x.verStr);return S(200,R[".html"],r.renderPackageVersionList(p.package_,v,u))}return S(200,R[".html"],r.renderDocument(u,h?{bareOverview:!0}:void 0))}if(p.kind==="resource"){let c=se(s,p.package_,p.versionSpec);if(!c)return P(e);let u=s.bySubject.get(`${t}/${p.package_}@${c}/${p.name}`);if(!u)return P(e);switch(d){case".css":return S(200,R[".css"],r.renderStylesheet(u));case".svg":return S(200,R[".svg"],r.renderSvg(u));case".md":{let h=r.renderRawMarkdown(u);return h===void 0?P(e):S(200,R[".md"],h)}default:return S(200,R[".html"],r.renderDocument(u))}}return P(e)}var U=class{constructor(e={}){this.options=e}options;models=new Map;clearCache(){this.models.clear()}async modelFor(e){let n=this.models.get(e);if(n)return n;let r=this.options.fetchFn?{fetchFn:this.options.fetchFn}:{},t;if(this.options.root!==void 0)try{t=await q(this.options.root,{publisher:e})}catch(d){if(!/not found in workspace/i.test(d.message))throw d;t=await O(e,r)}else t=await O(e,r);return t.lookRenderer.setLinkMode("open-world"),this.models.set(e,t),t}async handle(e,n=""){let r=e.split("/").filter(Boolean);if(r.length===0)return{status:200,headers:{"Content-Type":"text/html; charset=utf-8"},body:ae()};let t=r[0];if(!t.includes("."))return{status:404,headers:{"Content-Type":"text/html; charset=utf-8"},body:"<!doctype html><meta charset=utf-8><title>404</title><h1>404</h1><p>Expected a publisher domain as the first path segment: <code>/{publisher}/{package}/{version}/{resource}</code></p>"};let d=await this.modelFor(t),m=e.endsWith("/")&&r.length>1?"/":"",l="/"+r.slice(1).join("/")+m,g=T(d,l,n);return g.headers.Location?{...g,headers:{...g.headers,Location:`/${t}${g.headers.Location}`}}:g}};function ae(){return'<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Kanonak origin</title></head><body style="font-family:system-ui;max-width:40rem;margin:4rem auto;padding:0 1rem"><h1>Kanonak request-driven origin</h1><p>Open a resource by its address:</p><p><code>/{publisher}/{package}/{version}/{resource}</code></p><p>e.g. <code>/kanonak.org/capabilities/2.0.0/Capability</code></p></body></html>'}export{$ as ClosureScopedRepository,U as RequestRouter,ne as UNIVERSAL_RENDER_BASE,j as deriveImportClosure,ae as landingPage,O as loadResourceModel,q as loadServerModel,B as renderRefKey,A as resolveRenderContract,T as route};
@@ -0,0 +1,26 @@
1
+ import type { AuthenticatedFetchFn } from '../auth/index.js';
2
+ import type { ServerModel } from './types.js';
3
+ export interface LoadResourceModelOptions {
4
+ /** Authenticated fetch used for every HTTP request (config, index, package). */
5
+ fetchFn?: AuthenticatedFetchFn;
6
+ /** Override the global cache directory (the untrusted download accelerator). */
7
+ cacheRoot?: string;
8
+ }
9
+ /**
10
+ * Build a {@link ServerModel} seeded from a single Kanonak ADDRESS, fetching
11
+ * the resource's import closure over HTTP — the request-driven counterpart of
12
+ * `loadServerModel` (which seeds from a workspace on disk). A render is a pure
13
+ * function of `(the resource + its closure)`, and the address carries both: its
14
+ * first segment is the publisher, and the package's `imports:` give the
15
+ * transitive closure. So no `--publisher` flag and no workspace are needed.
16
+ *
17
+ * The pipeline reuses every #42 primitive: the HTTP repo fetches each package
18
+ * from its OWN publisher's config-driven endpoints (the closure may span
19
+ * publishers), verifying identity (`assertPackageIdentity`, inside the repo)
20
+ * before the global cache — an untrusted accelerator — keeps a raw copy;
21
+ * `deriveImportClosure` + `ClosureScopedRepository` scope the catalog so a
22
+ * polluted cache can't leak in; the look stack comes from the publisher's
23
+ * render contract (its `.well-known` override, else the universal kanonak.org
24
+ * base). The result is the same `ServerModel` shape `route` already consumes.
25
+ */
26
+ export declare function loadResourceModel(address: string, options?: LoadResourceModelOptions): Promise<ServerModel>;
@@ -0,0 +1,42 @@
1
+ import type { PublisherConfig } from '../repositories/index.js';
2
+ /** A render-stack package by canonical (publisher, package). */
3
+ export interface RenderPackageRef {
4
+ readonly publisher: string;
5
+ readonly package_: string;
6
+ }
7
+ /**
8
+ * The universal render base: the kanonak.org "look stack" the `LookRenderer`
9
+ * needs (the base stylesheet, the `--kan-*` design tokens, the `rdfs.Resource`
10
+ * look floor) but which NO document imports — the renderer discovers it
11
+ * ambiently by scanning the catalog. Every render closure includes this set so
12
+ * ANY publisher's pages render styled, exactly as a browser fetches a page's
13
+ * linked stylesheet. kanonak.org is the trust anchor for the base look
14
+ * contract, and it now publishes the whole stack over HTTP, so a request-driven
15
+ * render can fetch a fully-styled closure from the real origin.
16
+ *
17
+ * A publisher MAY override this by declaring its own `render` list in
18
+ * `.well-known/kanonak.json` (see {@link resolveRenderContract}) — the hybrid
19
+ * that keeps zero-config styling for normal publishers while making the stack
20
+ * explicit and overridable. This constant is the universal DEFAULT of that
21
+ * contract, not a hidden hardcode: it replaces the former implicit
22
+ * `WELL_KNOWN_RENDER_PACKAGES` list.
23
+ */
24
+ export declare const UNIVERSAL_RENDER_BASE: readonly RenderPackageRef[];
25
+ /**
26
+ * Resolve the render contract for a publisher from its fetched config. Returns
27
+ * the publisher's declared `render` list when present (each entry parsed
28
+ * through {@link parseKanonakAddress}, never string-sliced), else the
29
+ * {@link UNIVERSAL_RENDER_BASE}. This is the ONE place the "which look packages
30
+ * does a render need" decision is made — both the workspace builder
31
+ * (`loadServerModel`) and the request-driven builder (`loadResourceModel`)
32
+ * route through it.
33
+ *
34
+ * Render entries are package-level; a `@version` is accepted but the closure is
35
+ * version-agnostic (it resolves the highest compatible), so the version only
36
+ * documents intent for now. Publisher- or resource-kind entries are ignored
37
+ * (the render stack is packages). A malformed entry is skipped, never thrown —
38
+ * a bad render line must not break rendering.
39
+ */
40
+ export declare function resolveRenderContract(config: PublisherConfig | undefined): readonly RenderPackageRef[];
41
+ /** The closure-set key (`publisher/package`) for a render-stack ref. */
42
+ export declare function renderRefKey(ref: RenderPackageRef): string;
@@ -0,0 +1,53 @@
1
+ import type { ServerModel, RouteResponse } from './types.js';
2
+ import type { AuthenticatedFetchFn } from '../auth/index.js';
3
+ export interface RequestRouterOptions {
4
+ /**
5
+ * Workspace root, for publishers that are LOCAL (served from disk with live
6
+ * edits). Omit for a pure remote router that fetches every publisher over
7
+ * HTTP.
8
+ */
9
+ root?: string;
10
+ /** Authenticated fetch for remote publisher fetches (auth / testing). */
11
+ fetchFn?: AuthenticatedFetchFn;
12
+ }
13
+ /**
14
+ * The request-driven routing engine: maps a publisher-FIRST path
15
+ * (`/{publisher}/{package}/{version}/{resource}`) to a response by deriving the
16
+ * publisher from the first path segment and building a per-publisher
17
+ * {@link ServerModel} on demand — from the workspace if that publisher is local
18
+ * (when `root` is set), else fetched over HTTP via {@link loadResourceModel}.
19
+ * One model is cached per publisher.
20
+ *
21
+ * This is the canonical request-driven engine shared by `kanonak serve`
22
+ * (request-driven mode) and the VS Code extension's `EmbeddedServer`: both are
23
+ * thin HTTP listeners over it, exactly as they already share `route` and
24
+ * `loadServerModel`. It is pure of transport concerns — CORS, logging, the
25
+ * choice of status code for an upstream failure — which belong to the listener.
26
+ */
27
+ export declare class RequestRouter {
28
+ private readonly options;
29
+ private readonly models;
30
+ constructor(options?: RequestRouterOptions);
31
+ /** Drop cached models — e.g. after a workspace `.kan.yml` change. */
32
+ clearCache(): void;
33
+ /**
34
+ * The model for one publisher, built on first use and cached. A local
35
+ * workspace publisher is served from disk; any other publisher is fetched
36
+ * over HTTP (its latest catalogue). Throws if neither resolves.
37
+ */
38
+ modelFor(publisher: string): Promise<ServerModel>;
39
+ /**
40
+ * Route one publisher-first path:
41
+ * - `/` → a landing page (no single publisher to show);
42
+ * - a first segment that isn't a domain → 404;
43
+ * - otherwise → the resource rendered via {@link route} against the
44
+ * publisher's model, with any redirect `Location` re-prefixed with the
45
+ * publisher so navigation stays under `/{publisher}/…`.
46
+ *
47
+ * Throws only when a publisher's model can't be built (unreachable / no such
48
+ * publisher); the listener decides how to surface that (e.g. a 502).
49
+ */
50
+ handle(pathname: string, accept?: string): Promise<RouteResponse>;
51
+ }
52
+ /** Minimal landing for the request-driven root, which has no single publisher. */
53
+ export declare function landingPage(): string;