@kanonak-protocol/sdk 5.4.0 → 5.6.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.
@@ -33,7 +33,6 @@ export declare class SessionExchange {
33
33
  constructor(transport?: MtlsTransport);
34
34
  /** Exchange the device cert in `record` for a scoped session at `sessionEndpoint`. */
35
35
  exchange(sessionEndpoint: string, record: DeviceEnrollmentRecord, opts?: {
36
- scope?: string;
37
36
  nowMs?: number;
38
37
  }): Promise<ExchangedSession>;
39
38
  }
@@ -35,9 +35,7 @@ export declare class SessionManager {
35
35
  * {@link SessionError} with an actionable message if the host issues no
36
36
  * sessions or this device isn't enrolled there. For the explicit command path.
37
37
  */
38
- acquire(host: string, opts?: {
39
- scope?: string;
40
- }): Promise<SessionRecord>;
38
+ acquire(host: string): Promise<SessionRecord>;
41
39
  /**
42
40
  * A valid session for `host` — the cached one if still fresh, otherwise
43
41
  * re-exchanged from the device cert. Returns null (rather than throwing) when
package/dist/browser.js CHANGED
@@ -1 +1 @@
1
- import{a as B,b as H,c as L,d as Pe,e as ge,f as Ke,g as Ce,h as be,i as Ie,j as Ve}from"./chunk-VOJ6BGAR.js";import{a as Se}from"./chunk-EZSHR3CB.js";import"./chunk-QHABFCRC.js";import{a as m,b as u,c,d,f as y,g as R,h as f}from"./chunk-JYBKSBB5.js";import{a as p}from"./chunk-4NO7MHS7.js";import{a as G,b as w,c as _}from"./chunk-S6VSAKXB.js";import{a as q,b as F}from"./chunk-PEUTCG3B.js";import"./chunk-PEJALHXK.js";import"./chunk-SC5M74NM.js";import{A as fe,B as ke,K as xe,a as W,b as z,c as J,d as Q,f as X,g as Y,h as Z,i as $,k as ee,l as oe,m as te,n as re,o as ne,p as ae,q as ie,r as se,s as pe,t as le,u as me,v as ue,w as ce,x as de,y as ye,z as Re}from"./chunk-7K5TAJ44.js";import"./chunk-ITKOKDBG.js";import{a as g,c as E,h as T,i as M,l as A}from"./chunk-MX3DEXMV.js";import{a as l}from"./chunk-NJ3AZYQD.js";import{a as U}from"./chunk-ZP6P7HNU.js";import"./chunk-6U26UASC.js";import{a as N,b as v}from"./chunk-GZPLWII7.js";import{a as k,b as x,c as P,d as S,e as C,f as b,g as I,h as V,i as h,j,k as D,l as O}from"./chunk-7BHDZHJY.js";import{a as K}from"./chunk-FUUTGGJS.js";import{c as e,d as o,e as t,f as r,g as n,h as a,i,j as s}from"./chunk-2ACBWC7K.js";export{me as AmbiguousReferenceRule,h as BooleanStatement,Ie as CANONICAL_FORM_VERSION,T as Carrier,fe as ClassDefinitionRule,re as ClassHierarchyCycleRule,x as DefinedKanonak,H as EdgeType,g as EmbeddedKanonak,ee as EmbeddedKanonakTypeRule,D as EmbeddedStatement,L as GraphBuilder,f as HttpKanonakDocumentRepository,oe as ImportExistenceRule,p as InMemoryKanonakDocumentRepository,m as KANONAK_USER_AGENT,k as Kanonak,w as KanonakDocumentPositions,A as KanonakObjectParser,xe as KanonakObjectValidator,l as KanonakParser,K as KanonakUri,q as KanonakUriBuilder,O as ListStatement,ke as MarkdownLinkRule,E as MarkdownStatement,pe as NamespaceImportCycleRule,X as NamespacePrefixRule,B as NodeType,V as NumberStatement,ce as ObjectPropertyValueValidationRule,J as OntologyValidationError,W as OntologyValidationResult,de as PropertyDomainRule,ne as PropertyHierarchyCycleRule,ye as PropertyKindRangeConsistencyRule,G as PropertyMetadata,ue as PropertyRangeReferenceRule,ae as PropertyRangeRequiredRule,Z as PropertyTypeSpecificityRule,y as PublisherConfigResolver,R as PublisherIndex,S as ReferenceKanonak,j as ReferenceStatement,Re as ReservedNameShadowRule,Y as ResourceNamingRule,N as ResourceResolver,U as ResourceTypeClassifier,b as ScalarStatement,C as Statement,I as StringStatement,ie as SubClassOfReferenceRule,se as SubPropertyOfReferenceRule,P as SubjectKanonak,$ as SubjectKanonakTypeRequiredRule,v as TypeResolver,le as UnresolvedPredicateRule,te as UnresolvedReferenceRule,Q as ValidationContext,z as ValidationSeverity,Ve as buildOntologyModel,Ce as canonicalForm,be as canonicalHash,M as carrierOf,e as compareVersions,r as createVersion,Se as findDerivation,F as findInstancesByType,t as formatVersion,c as getKanonakUserAgent,ge as hasValidToken,a as isCompatibleVersion,Pe as isExpired,i as isMajorCompatible,d as kanonakFetch,Ke as normalizeHost,n as parseVersionString,_ as parseWithPositions,s as pickHighestDocument,u as setKanonakUserAgent,o as versionsEqual};
1
+ import{a as B,b as H,c as L,d as Pe,e as ge,f as Ke,g as Ce,h as be,i as Ie,j as Ve}from"./chunk-VOJ6BGAR.js";import{a as Se}from"./chunk-EZSHR3CB.js";import"./chunk-QHABFCRC.js";import{a as m,b as u,c,e as d,g as y,i as R,j as f}from"./chunk-XGTUVPR3.js";import{a as p}from"./chunk-4NO7MHS7.js";import{a as G,b as w,c as _}from"./chunk-S6VSAKXB.js";import{a as q,b as F}from"./chunk-PEUTCG3B.js";import"./chunk-PEJALHXK.js";import"./chunk-SC5M74NM.js";import{A as fe,B as ke,K as xe,a as W,b as z,c as J,d as Q,f as X,g as Y,h as Z,i as $,k as ee,l as oe,m as te,n as re,o as ne,p as ae,q as ie,r as se,s as pe,t as le,u as me,v as ue,w as ce,x as de,y as ye,z as Re}from"./chunk-7K5TAJ44.js";import"./chunk-ITKOKDBG.js";import{a as g,c as E,h as T,i as M,l as A}from"./chunk-MX3DEXMV.js";import{a as l}from"./chunk-NJ3AZYQD.js";import{a as U}from"./chunk-ZP6P7HNU.js";import"./chunk-6U26UASC.js";import{a as N,b as v}from"./chunk-GZPLWII7.js";import{a as k,b as x,c as P,d as S,e as C,f as b,g as I,h as V,i as h,j,k as D,l as O}from"./chunk-7BHDZHJY.js";import{a as K}from"./chunk-FUUTGGJS.js";import{c as e,d as o,e as t,f as r,g as n,h as a,i,j as s}from"./chunk-2ACBWC7K.js";export{me as AmbiguousReferenceRule,h as BooleanStatement,Ie as CANONICAL_FORM_VERSION,T as Carrier,fe as ClassDefinitionRule,re as ClassHierarchyCycleRule,x as DefinedKanonak,H as EdgeType,g as EmbeddedKanonak,ee as EmbeddedKanonakTypeRule,D as EmbeddedStatement,L as GraphBuilder,f as HttpKanonakDocumentRepository,oe as ImportExistenceRule,p as InMemoryKanonakDocumentRepository,m as KANONAK_USER_AGENT,k as Kanonak,w as KanonakDocumentPositions,A as KanonakObjectParser,xe as KanonakObjectValidator,l as KanonakParser,K as KanonakUri,q as KanonakUriBuilder,O as ListStatement,ke as MarkdownLinkRule,E as MarkdownStatement,pe as NamespaceImportCycleRule,X as NamespacePrefixRule,B as NodeType,V as NumberStatement,ce as ObjectPropertyValueValidationRule,J as OntologyValidationError,W as OntologyValidationResult,de as PropertyDomainRule,ne as PropertyHierarchyCycleRule,ye as PropertyKindRangeConsistencyRule,G as PropertyMetadata,ue as PropertyRangeReferenceRule,ae as PropertyRangeRequiredRule,Z as PropertyTypeSpecificityRule,y as PublisherConfigResolver,R as PublisherIndex,S as ReferenceKanonak,j as ReferenceStatement,Re as ReservedNameShadowRule,Y as ResourceNamingRule,N as ResourceResolver,U as ResourceTypeClassifier,b as ScalarStatement,C as Statement,I as StringStatement,ie as SubClassOfReferenceRule,se as SubPropertyOfReferenceRule,P as SubjectKanonak,$ as SubjectKanonakTypeRequiredRule,v as TypeResolver,le as UnresolvedPredicateRule,te as UnresolvedReferenceRule,Q as ValidationContext,z as ValidationSeverity,Ve as buildOntologyModel,Ce as canonicalForm,be as canonicalHash,M as carrierOf,e as compareVersions,r as createVersion,Se as findDerivation,F as findInstancesByType,t as formatVersion,c as getKanonakUserAgent,ge as hasValidToken,a as isCompatibleVersion,Pe as isExpired,i as isMajorCompatible,d as kanonakFetch,Ke as normalizeHost,n as parseVersionString,_ as parseWithPositions,s as pickHighestDocument,u as setKanonakUserAgent,o as versionsEqual};
@@ -1 +1 @@
1
- import{h as v}from"./chunk-JYBKSBB5.js";import{a as w}from"./chunk-4NO7MHS7.js";import{a as f}from"./chunk-NJ3AZYQD.js";import{c as A,d as R,g as b,h as F,i as S}from"./chunk-2ACBWC7K.js";import*as i from"fs/promises";import*as c from"path";import{pathToFileURL as x}from"url";import{VersionOperator as P}from"@kanonak-protocol/types/document/models/enums";var y=class{rootPath;recursive;parser;documentCache;filePathsByIdentifier;cacheInitialized=!1;cacheInitPromise=null;parsingErrors=new Map;constructor(e,t=!0,n){if(!e||e.trim().length===0)throw new Error("Root path cannot be null or empty");this.rootPath=c.resolve(e),this.recursive=t,this.parser=n??new f,this.documentCache=new Map,this.filePathsByIdentifier=new Map}async getAllDocumentsAsync(){await this.ensureCacheInitialized();let e=new Set(this.documentCache.values());return Array.from(e)}async getDocumentAsync(e){await this.ensureCacheInitialized();let t=this.documentCache.get(e);if(t)return t;let n=c.join(this.rootPath,e);if(t=this.documentCache.get(n),t)return t;for(let o of[".kan.yml",".yml",".yaml"])if(!e.endsWith(o)){let s=e+o;if(t=this.documentCache.get(s),t)return t;let a=c.join(this.rootPath,s);if(t=this.documentCache.get(a),t)return t}return null}async getDocumentsByNamespaceAsync(e,t){await this.ensureCacheInitialized();let n=new Set(this.documentCache.values());return Array.from(n).filter(o=>o.metadata.namespace_?.publisher===e&&o.metadata.namespace_?.package_===t)}async getHighestCompatibleVersionAsync(e,t){await this.ensureCacheInitialized();let n=new Set(this.documentCache.values()),o=Array.from(n).filter(a=>a.metadata?.namespace_?.publisher===e&&a.metadata?.namespace_?.package_===t.packageName&&a.metadata?.namespace_?.version!==void 0);if(o.length===0)return null;let s=o.filter(a=>{let r=a.metadata.namespace_.version;switch(t.versionOperator){case P.Exact:return R(r,t.version);case P.Compatible:return F(r,t.version);case P.Major:return S(r,t.version);case P.Any:return A(r,t.minVersion)>=0;default:return!1}});return s.length===0?null:(s.sort((a,r)=>{let m=a.metadata.namespace_.version,l=r.metadata.namespace_.version;return A(l,m)}),s[0])}async saveDocumentAsync(e,t){let n,o=e.metadata.namespace_?.toString();if(o&&o.includes("@")&&o.includes("/")){let m=o.split("/"),l=m[0],h=m[1].replace("@","@")+".kan.yml";n=c.join(this.rootPath,l,h)}else n=c.join(this.rootPath,t),!n.endsWith(".yml")&&!n.endsWith(".yaml")&&!n.endsWith(".kan.yml")&&(n+=".kan.yml");let s=c.dirname(n);await i.mkdir(s,{recursive:!0});let a=this.parser.save(e);await i.writeFile(n,a,"utf8"),o&&this.documentCache.set(o,e),this.documentCache.set(n,e);let r=c.relative(this.rootPath,n);this.documentCache.set(r,e)}async deleteDocumentAsync(e){let t=await this.getDocumentAsync(e);if(!t)return;let n=this.filePathsByIdentifier.get(e);if(!n)return;try{await i.unlink(n)}catch{}let o=t.metadata.namespace_?.toString();o&&this.documentCache.delete(o),this.documentCache.delete(e),this.documentCache.delete(n);let s=c.relative(this.rootPath,n);this.documentCache.delete(s)}async clearNamespaceAsync(e,t){await this.ensureCacheInitialized();let n=[];for(let[s,a]of this.documentCache.entries()){let r=a.metadata.namespace_?.toString()||"";r.includes(e)&&r.includes(t)&&n.push([s,a])}let o=c.join(this.rootPath,e);try{let s=await i.readdir(o);for(let a of s)a.includes(t)&&a.endsWith(".kan.yml")&&await i.unlink(c.join(o,a))}catch{}for(let[s]of n)this.documentCache.delete(s)}async getAllDocumentReferencesAsync(){await this.ensureCacheInitialized();let e=new Set(this.filePathsByIdentifier.values()),t=[];for(let n of e){let o=x(n).toString(),s;for(let[m,l]of this.documentCache.entries())if(this.filePathsByIdentifier.get(m)===n&&l.metadata.namespace_){s=l.metadata.namespace_.toString();break}let a=s??c.relative(this.rootPath,n),r=this.parsingErrors.has(n);t.push({identifier:a,uri:o,hasParseError:r})}return t}async getDocumentContentAsync(e){await this.ensureCacheInitialized();let t=this.filePathsByIdentifier.get(e);if(!t)try{await i.access(e),t=e}catch{let n=c.join(this.rootPath,e);try{await i.access(n),t=n}catch{return null}}try{return await i.readFile(t,"utf8")}catch{return null}}async getDocumentUriAsync(e){await this.ensureCacheInitialized();let t=this.filePathsByIdentifier.get(e);if(!t)try{await i.access(e),t=e}catch{let n=c.join(this.rootPath,e);try{await i.access(n),t=n}catch{return null}}return x(t).toString()}async refreshAsync(){this.documentCache.clear(),this.filePathsByIdentifier.clear(),this.parsingErrors.clear(),this.cacheInitialized=!1,this.cacheInitPromise=null,await this.ensureCacheInitialized()}async ensureCacheInitialized(){if(!this.cacheInitialized){if(this.cacheInitPromise){await this.cacheInitPromise;return}this.cacheInitPromise=this.loadDocuments(),await this.cacheInitPromise,this.cacheInitialized=!0}}async loadDocuments(){try{await i.mkdir(this.rootPath,{recursive:!0})}catch{}let t=(await this.findYamlFiles(this.rootPath,this.recursive)).map(async o=>{try{let s=await i.readFile(o,"utf8"),a=this.parser.parse(s);return{filePath:o,document:a,error:null}}catch(s){return{filePath:o,document:null,error:s instanceof Error?s.message:String(s)}}}),n=await Promise.all(t);for(let{filePath:o,document:s,error:a}of n){let r=c.relative(this.rootPath,o);if(s&&s.metadata.namespace_){let m=s.metadata.namespace_.toString();this.documentCache.set(m,s),this.documentCache.set(o,s),this.documentCache.set(r,s),this.filePathsByIdentifier.set(m,o),this.filePathsByIdentifier.set(o,o),this.filePathsByIdentifier.set(r,o)}else this.filePathsByIdentifier.set(o,o),this.filePathsByIdentifier.set(r,o);a&&this.parsingErrors.set(o,a)}}async findYamlFiles(e,t){let n=[];try{let o=await i.readdir(e,{withFileTypes:!0});for(let s of o){let a=c.join(e,s.name);if(s.isDirectory()&&t){let r=await this.findYamlFiles(a,t);n.push(...r)}else s.isFile()&&s.name.endsWith(".kan.yml")&&n.push(a)}}catch{}return n}};import*as g from"fs";var _=(n=>(n.NotFound="NotFound",n.Workspace="Workspace",n.Cache="Cache",n))(_||{}),k=class{cache;workspace;constructor(e,t,n){let o=n??new f;g.existsSync(e)||g.mkdirSync(e,{recursive:!0}),g.existsSync(t)||g.mkdirSync(t,{recursive:!0}),this.cache=new y(e,!0,o),this.workspace=new y(t,!0,o)}getCache(){return this.cache}getWorkspace(){return this.workspace}async getAllDocumentsAsync(){let e=await this.workspace.getAllDocumentsAsync(),t=await this.cache.getAllDocumentsAsync(),n=new Map;for(let o of t)if(o.metadata.namespace_){let s=o.metadata.namespace_.toString();n.set(s,o)}for(let o of e)if(o.metadata.namespace_){let s=o.metadata.namespace_.toString();n.set(s,o)}return Array.from(n.values())}async getDocumentAsync(e){let t=await this.workspace.getDocumentAsync(e);return t||await this.cache.getDocumentAsync(e)}async getDocumentsByNamespaceAsync(e,t){let n=await this.workspace.getDocumentsByNamespaceAsync(e,t),o=await this.cache.getDocumentsByNamespaceAsync(e,t),s=new Map;for(let a of o)if(a.metadata.namespace_?.version){let r=a.metadata.namespace_.version.toString();s.set(r,a)}for(let a of n)if(a.metadata.namespace_?.version){let r=a.metadata.namespace_.version.toString();s.set(r,a)}return Array.from(s.values())}async getHighestCompatibleVersionAsync(e,t){let n=await this.workspace.getHighestCompatibleVersionAsync(e,t);return n||await this.cache.getHighestCompatibleVersionAsync(e,t)}async saveDocumentAsync(e,t){await this.workspace.saveDocumentAsync(e,t)}async saveToCacheAsync(e,t){await this.cache.saveDocumentAsync(e,t)}async deleteDocumentAsync(e){await this.workspace.deleteDocumentAsync(e)}async clearNamespaceAsync(e,t){await this.workspace.clearNamespaceAsync(e,t)}async getAllDocumentReferencesAsync(){let e=await this.workspace.getAllDocumentReferencesAsync(),t=await this.cache.getAllDocumentReferencesAsync(),n=[];return n.push(...e),n.push(...t),n}async getDocumentContentAsync(e){let t=await this.workspace.getDocumentContentAsync(e);return t||await this.cache.getDocumentContentAsync(e)}async getDocumentUriAsync(e){let t=await this.workspace.getDocumentUriAsync(e);return t||await this.cache.getDocumentUriAsync(e)}async getDocumentLocationAsync(e){return await this.workspace.getDocumentAsync(e)?"Workspace":await this.cache.getDocumentAsync(e)?"Cache":"NotFound"}};import{homedir as $}from"os";import{join as B}from"path";function d(){let u=process.env.KANONAK_PACKAGE_CACHE;return u||B($(),".kanonak","packages")}var C=class u{static createComposite(e,t,n){let o=e??d(),s=t??".";return new k(o,s,n)}static createFromEnvironment(e){let t=d(),n=process.env.KANONAK_WORKSPACE_PATH??".";return u.createComposite(t,n,e)}};var D=class{repos;constructor(...e){this.repos=e}async getHighestCompatibleVersionAsync(e,t){for(let n of this.repos)try{let o=await n.getHighestCompatibleVersionAsync(e,t);if(o)return o}catch{}return null}async getAllDocumentsAsync(){let e=[],t=new Set;for(let n of this.repos)try{for(let o of await n.getAllDocumentsAsync()){let s=o.metadata?.namespace_,a=s?s.version?`${s.publisher}/${s.package_}@${s.version.major}.${s.version.minor}.${s.version.patch}`:`${s.publisher}/${s.package_}`:void 0;if(a!==void 0){if(t.has(a))continue;t.add(a)}e.push(o)}}catch{}return e}async getDocumentAsync(e){for(let t of this.repos)try{let n=await t.getDocumentAsync(e);if(n)return n}catch{}return null}async getDocumentsByNamespaceAsync(e,t){for(let n of this.repos)try{let o=await n.getDocumentsByNamespaceAsync(e,t);if(o.length>0)return o}catch{}return[]}async saveDocumentAsync(e,t){await this.repos[0].saveDocumentAsync(e,t)}async deleteDocumentAsync(e){await this.repos[0].deleteDocumentAsync(e)}async clearNamespaceAsync(e,t){await this.repos[0].clearNamespaceAsync(e,t)}async getAllDocumentReferencesAsync(){return this.repos[0].getAllDocumentReferencesAsync()}async getDocumentContentAsync(e){for(let t of this.repos)try{let n=await t.getDocumentContentAsync(e);if(n)return n}catch{}return null}async getDocumentUriAsync(e){for(let t of this.repos)try{let n=await t.getDocumentUriAsync(e);if(n)return n}catch{}return null}};import{VersionOperator as H}from"@kanonak-protocol/types/document/models/enums";var K=class{constructor(e,t){this.base=e;this.lock=t}base;lock;pinnedVersion(e,t){return this.lock.packages[`${e}/${t}`]?.version}async getHighestCompatibleVersionAsync(e,t){let n=this.pinnedVersion(e,t.packageName);if(n){let o=b(n);if(o){let s={...t,versionOperator:H.Exact,version:o};return this.base.getHighestCompatibleVersionAsync(e,s)}}return this.base.getHighestCompatibleVersionAsync(e,t)}async getDocumentsByNamespaceAsync(e,t){let n=await this.base.getDocumentsByNamespaceAsync(e,t),o=this.pinnedVersion(e,t);return o?n.filter(s=>{let a=s.metadata.namespace_?.version;return a?`${a.major}.${a.minor}.${a.patch}`===o:!1}):n}getAllDocumentsAsync(){return this.base.getAllDocumentsAsync()}getDocumentAsync(e){return this.base.getDocumentAsync(e)}saveDocumentAsync(e,t){return this.base.saveDocumentAsync(e,t)}deleteDocumentAsync(e){return this.base.deleteDocumentAsync(e)}clearNamespaceAsync(e,t){return this.base.clearNamespaceAsync(e,t)}getAllDocumentReferencesAsync(){return this.base.getAllDocumentReferencesAsync()}getDocumentContentAsync(e){return this.base.getDocumentContentAsync(e)}getDocumentUriAsync(e){return this.base.getDocumentUriAsync(e)}};import{readFileSync as V,readdirSync as j}from"fs";import{join as N}from"path";var E=new Set(["node_modules",".kanonak",".git","_site","build",".stage"]);function I(u,e=[]){for(let t of j(u,{withFileTypes:!0}))t.isDirectory()?E.has(t.name)||I(N(u,t.name),e):t.name.endsWith(".kan.yml")&&e.push(N(u,t.name));return e}async function z(u,e=new f,t={}){let n=new w(e);for(let m of I(u))try{let l=e.parse(V(m,"utf-8")),p=l.metadata?.namespace_,h=p?.version;p&&h&&await n.saveDocumentAsync(l,`${p.publisher}/${p.package_}@${h.major}.${h.minor}.${h.patch}`)}catch{}let o=new y(d(),!0,e),s=new Map,a=t.httpCache??{getFromCache:(m,l,p)=>s.get(`${m}|${l}|${p}`)??null,onFetch:(m,l,p,h)=>{s.set(`${m}|${l}|${p}`,h)}},r=new v({getFromCache:a.getFromCache,onFetch:a.onFetch});return new D(n,o,r)}export{y as a,_ as b,k as c,d,C as e,D as f,K as g,I as h,z as i};
1
+ import{j as v}from"./chunk-XGTUVPR3.js";import{a as w}from"./chunk-4NO7MHS7.js";import{a as f}from"./chunk-NJ3AZYQD.js";import{c as A,d as R,g as b,h as F,i as S}from"./chunk-2ACBWC7K.js";import*as i from"fs/promises";import*as c from"path";import{pathToFileURL as x}from"url";import{VersionOperator as P}from"@kanonak-protocol/types/document/models/enums";var y=class{rootPath;recursive;parser;documentCache;filePathsByIdentifier;cacheInitialized=!1;cacheInitPromise=null;parsingErrors=new Map;constructor(e,t=!0,n){if(!e||e.trim().length===0)throw new Error("Root path cannot be null or empty");this.rootPath=c.resolve(e),this.recursive=t,this.parser=n??new f,this.documentCache=new Map,this.filePathsByIdentifier=new Map}async getAllDocumentsAsync(){await this.ensureCacheInitialized();let e=new Set(this.documentCache.values());return Array.from(e)}async getDocumentAsync(e){await this.ensureCacheInitialized();let t=this.documentCache.get(e);if(t)return t;let n=c.join(this.rootPath,e);if(t=this.documentCache.get(n),t)return t;for(let o of[".kan.yml",".yml",".yaml"])if(!e.endsWith(o)){let s=e+o;if(t=this.documentCache.get(s),t)return t;let a=c.join(this.rootPath,s);if(t=this.documentCache.get(a),t)return t}return null}async getDocumentsByNamespaceAsync(e,t){await this.ensureCacheInitialized();let n=new Set(this.documentCache.values());return Array.from(n).filter(o=>o.metadata.namespace_?.publisher===e&&o.metadata.namespace_?.package_===t)}async getHighestCompatibleVersionAsync(e,t){await this.ensureCacheInitialized();let n=new Set(this.documentCache.values()),o=Array.from(n).filter(a=>a.metadata?.namespace_?.publisher===e&&a.metadata?.namespace_?.package_===t.packageName&&a.metadata?.namespace_?.version!==void 0);if(o.length===0)return null;let s=o.filter(a=>{let r=a.metadata.namespace_.version;switch(t.versionOperator){case P.Exact:return R(r,t.version);case P.Compatible:return F(r,t.version);case P.Major:return S(r,t.version);case P.Any:return A(r,t.minVersion)>=0;default:return!1}});return s.length===0?null:(s.sort((a,r)=>{let m=a.metadata.namespace_.version,l=r.metadata.namespace_.version;return A(l,m)}),s[0])}async saveDocumentAsync(e,t){let n,o=e.metadata.namespace_?.toString();if(o&&o.includes("@")&&o.includes("/")){let m=o.split("/"),l=m[0],h=m[1].replace("@","@")+".kan.yml";n=c.join(this.rootPath,l,h)}else n=c.join(this.rootPath,t),!n.endsWith(".yml")&&!n.endsWith(".yaml")&&!n.endsWith(".kan.yml")&&(n+=".kan.yml");let s=c.dirname(n);await i.mkdir(s,{recursive:!0});let a=this.parser.save(e);await i.writeFile(n,a,"utf8"),o&&this.documentCache.set(o,e),this.documentCache.set(n,e);let r=c.relative(this.rootPath,n);this.documentCache.set(r,e)}async deleteDocumentAsync(e){let t=await this.getDocumentAsync(e);if(!t)return;let n=this.filePathsByIdentifier.get(e);if(!n)return;try{await i.unlink(n)}catch{}let o=t.metadata.namespace_?.toString();o&&this.documentCache.delete(o),this.documentCache.delete(e),this.documentCache.delete(n);let s=c.relative(this.rootPath,n);this.documentCache.delete(s)}async clearNamespaceAsync(e,t){await this.ensureCacheInitialized();let n=[];for(let[s,a]of this.documentCache.entries()){let r=a.metadata.namespace_?.toString()||"";r.includes(e)&&r.includes(t)&&n.push([s,a])}let o=c.join(this.rootPath,e);try{let s=await i.readdir(o);for(let a of s)a.includes(t)&&a.endsWith(".kan.yml")&&await i.unlink(c.join(o,a))}catch{}for(let[s]of n)this.documentCache.delete(s)}async getAllDocumentReferencesAsync(){await this.ensureCacheInitialized();let e=new Set(this.filePathsByIdentifier.values()),t=[];for(let n of e){let o=x(n).toString(),s;for(let[m,l]of this.documentCache.entries())if(this.filePathsByIdentifier.get(m)===n&&l.metadata.namespace_){s=l.metadata.namespace_.toString();break}let a=s??c.relative(this.rootPath,n),r=this.parsingErrors.has(n);t.push({identifier:a,uri:o,hasParseError:r})}return t}async getDocumentContentAsync(e){await this.ensureCacheInitialized();let t=this.filePathsByIdentifier.get(e);if(!t)try{await i.access(e),t=e}catch{let n=c.join(this.rootPath,e);try{await i.access(n),t=n}catch{return null}}try{return await i.readFile(t,"utf8")}catch{return null}}async getDocumentUriAsync(e){await this.ensureCacheInitialized();let t=this.filePathsByIdentifier.get(e);if(!t)try{await i.access(e),t=e}catch{let n=c.join(this.rootPath,e);try{await i.access(n),t=n}catch{return null}}return x(t).toString()}async refreshAsync(){this.documentCache.clear(),this.filePathsByIdentifier.clear(),this.parsingErrors.clear(),this.cacheInitialized=!1,this.cacheInitPromise=null,await this.ensureCacheInitialized()}async ensureCacheInitialized(){if(!this.cacheInitialized){if(this.cacheInitPromise){await this.cacheInitPromise;return}this.cacheInitPromise=this.loadDocuments(),await this.cacheInitPromise,this.cacheInitialized=!0}}async loadDocuments(){try{await i.mkdir(this.rootPath,{recursive:!0})}catch{}let t=(await this.findYamlFiles(this.rootPath,this.recursive)).map(async o=>{try{let s=await i.readFile(o,"utf8"),a=this.parser.parse(s);return{filePath:o,document:a,error:null}}catch(s){return{filePath:o,document:null,error:s instanceof Error?s.message:String(s)}}}),n=await Promise.all(t);for(let{filePath:o,document:s,error:a}of n){let r=c.relative(this.rootPath,o);if(s&&s.metadata.namespace_){let m=s.metadata.namespace_.toString();this.documentCache.set(m,s),this.documentCache.set(o,s),this.documentCache.set(r,s),this.filePathsByIdentifier.set(m,o),this.filePathsByIdentifier.set(o,o),this.filePathsByIdentifier.set(r,o)}else this.filePathsByIdentifier.set(o,o),this.filePathsByIdentifier.set(r,o);a&&this.parsingErrors.set(o,a)}}async findYamlFiles(e,t){let n=[];try{let o=await i.readdir(e,{withFileTypes:!0});for(let s of o){let a=c.join(e,s.name);if(s.isDirectory()&&t){let r=await this.findYamlFiles(a,t);n.push(...r)}else s.isFile()&&s.name.endsWith(".kan.yml")&&n.push(a)}}catch{}return n}};import*as g from"fs";var _=(n=>(n.NotFound="NotFound",n.Workspace="Workspace",n.Cache="Cache",n))(_||{}),k=class{cache;workspace;constructor(e,t,n){let o=n??new f;g.existsSync(e)||g.mkdirSync(e,{recursive:!0}),g.existsSync(t)||g.mkdirSync(t,{recursive:!0}),this.cache=new y(e,!0,o),this.workspace=new y(t,!0,o)}getCache(){return this.cache}getWorkspace(){return this.workspace}async getAllDocumentsAsync(){let e=await this.workspace.getAllDocumentsAsync(),t=await this.cache.getAllDocumentsAsync(),n=new Map;for(let o of t)if(o.metadata.namespace_){let s=o.metadata.namespace_.toString();n.set(s,o)}for(let o of e)if(o.metadata.namespace_){let s=o.metadata.namespace_.toString();n.set(s,o)}return Array.from(n.values())}async getDocumentAsync(e){let t=await this.workspace.getDocumentAsync(e);return t||await this.cache.getDocumentAsync(e)}async getDocumentsByNamespaceAsync(e,t){let n=await this.workspace.getDocumentsByNamespaceAsync(e,t),o=await this.cache.getDocumentsByNamespaceAsync(e,t),s=new Map;for(let a of o)if(a.metadata.namespace_?.version){let r=a.metadata.namespace_.version.toString();s.set(r,a)}for(let a of n)if(a.metadata.namespace_?.version){let r=a.metadata.namespace_.version.toString();s.set(r,a)}return Array.from(s.values())}async getHighestCompatibleVersionAsync(e,t){let n=await this.workspace.getHighestCompatibleVersionAsync(e,t);return n||await this.cache.getHighestCompatibleVersionAsync(e,t)}async saveDocumentAsync(e,t){await this.workspace.saveDocumentAsync(e,t)}async saveToCacheAsync(e,t){await this.cache.saveDocumentAsync(e,t)}async deleteDocumentAsync(e){await this.workspace.deleteDocumentAsync(e)}async clearNamespaceAsync(e,t){await this.workspace.clearNamespaceAsync(e,t)}async getAllDocumentReferencesAsync(){let e=await this.workspace.getAllDocumentReferencesAsync(),t=await this.cache.getAllDocumentReferencesAsync(),n=[];return n.push(...e),n.push(...t),n}async getDocumentContentAsync(e){let t=await this.workspace.getDocumentContentAsync(e);return t||await this.cache.getDocumentContentAsync(e)}async getDocumentUriAsync(e){let t=await this.workspace.getDocumentUriAsync(e);return t||await this.cache.getDocumentUriAsync(e)}async getDocumentLocationAsync(e){return await this.workspace.getDocumentAsync(e)?"Workspace":await this.cache.getDocumentAsync(e)?"Cache":"NotFound"}};import{homedir as $}from"os";import{join as B}from"path";function d(){let u=process.env.KANONAK_PACKAGE_CACHE;return u||B($(),".kanonak","packages")}var C=class u{static createComposite(e,t,n){let o=e??d(),s=t??".";return new k(o,s,n)}static createFromEnvironment(e){let t=d(),n=process.env.KANONAK_WORKSPACE_PATH??".";return u.createComposite(t,n,e)}};var D=class{repos;constructor(...e){this.repos=e}async getHighestCompatibleVersionAsync(e,t){for(let n of this.repos)try{let o=await n.getHighestCompatibleVersionAsync(e,t);if(o)return o}catch{}return null}async getAllDocumentsAsync(){let e=[],t=new Set;for(let n of this.repos)try{for(let o of await n.getAllDocumentsAsync()){let s=o.metadata?.namespace_,a=s?s.version?`${s.publisher}/${s.package_}@${s.version.major}.${s.version.minor}.${s.version.patch}`:`${s.publisher}/${s.package_}`:void 0;if(a!==void 0){if(t.has(a))continue;t.add(a)}e.push(o)}}catch{}return e}async getDocumentAsync(e){for(let t of this.repos)try{let n=await t.getDocumentAsync(e);if(n)return n}catch{}return null}async getDocumentsByNamespaceAsync(e,t){for(let n of this.repos)try{let o=await n.getDocumentsByNamespaceAsync(e,t);if(o.length>0)return o}catch{}return[]}async saveDocumentAsync(e,t){await this.repos[0].saveDocumentAsync(e,t)}async deleteDocumentAsync(e){await this.repos[0].deleteDocumentAsync(e)}async clearNamespaceAsync(e,t){await this.repos[0].clearNamespaceAsync(e,t)}async getAllDocumentReferencesAsync(){return this.repos[0].getAllDocumentReferencesAsync()}async getDocumentContentAsync(e){for(let t of this.repos)try{let n=await t.getDocumentContentAsync(e);if(n)return n}catch{}return null}async getDocumentUriAsync(e){for(let t of this.repos)try{let n=await t.getDocumentUriAsync(e);if(n)return n}catch{}return null}};import{VersionOperator as H}from"@kanonak-protocol/types/document/models/enums";var K=class{constructor(e,t){this.base=e;this.lock=t}base;lock;pinnedVersion(e,t){return this.lock.packages[`${e}/${t}`]?.version}async getHighestCompatibleVersionAsync(e,t){let n=this.pinnedVersion(e,t.packageName);if(n){let o=b(n);if(o){let s={...t,versionOperator:H.Exact,version:o};return this.base.getHighestCompatibleVersionAsync(e,s)}}return this.base.getHighestCompatibleVersionAsync(e,t)}async getDocumentsByNamespaceAsync(e,t){let n=await this.base.getDocumentsByNamespaceAsync(e,t),o=this.pinnedVersion(e,t);return o?n.filter(s=>{let a=s.metadata.namespace_?.version;return a?`${a.major}.${a.minor}.${a.patch}`===o:!1}):n}getAllDocumentsAsync(){return this.base.getAllDocumentsAsync()}getDocumentAsync(e){return this.base.getDocumentAsync(e)}saveDocumentAsync(e,t){return this.base.saveDocumentAsync(e,t)}deleteDocumentAsync(e){return this.base.deleteDocumentAsync(e)}clearNamespaceAsync(e,t){return this.base.clearNamespaceAsync(e,t)}getAllDocumentReferencesAsync(){return this.base.getAllDocumentReferencesAsync()}getDocumentContentAsync(e){return this.base.getDocumentContentAsync(e)}getDocumentUriAsync(e){return this.base.getDocumentUriAsync(e)}};import{readFileSync as V,readdirSync as j}from"fs";import{join as N}from"path";var E=new Set(["node_modules",".kanonak",".git","_site","build",".stage"]);function I(u,e=[]){for(let t of j(u,{withFileTypes:!0}))t.isDirectory()?E.has(t.name)||I(N(u,t.name),e):t.name.endsWith(".kan.yml")&&e.push(N(u,t.name));return e}async function z(u,e=new f,t={}){let n=new w(e);for(let m of I(u))try{let l=e.parse(V(m,"utf-8")),p=l.metadata?.namespace_,h=p?.version;p&&h&&await n.saveDocumentAsync(l,`${p.publisher}/${p.package_}@${h.major}.${h.minor}.${h.patch}`)}catch{}let o=new y(d(),!0,e),s=new Map,a=t.httpCache??{getFromCache:(m,l,p)=>s.get(`${m}|${l}|${p}`)??null,onFetch:(m,l,p,h)=>{s.set(`${m}|${l}|${p}`,h)}},r=new v({getFromCache:a.getFromCache,onFetch:a.onFetch});return new D(n,o,r)}export{y as a,_ as b,k as c,d,C as e,D as f,K as g,I as h,z as i};
@@ -0,0 +1 @@
1
+ import{a as v}from"./chunk-SC5M74NM.js";import{a as C}from"./chunk-NJ3AZYQD.js";import{e as y,g as P}from"./chunk-2ACBWC7K.js";var x="@kanonak-protocol/sdk (+https://kanonak.org)",F=x;function K(o){F=o}function b(){return F}function p(o){let t;try{t=typeof o=="string"?new URL(o):o}catch{throw new Error(`Kanonak requires an absolute https:// URL \u2014 got an unparseable or relative URL: ${String(o)}`)}if(t.protocol!=="https:")throw new Error(`Kanonak requires HTTPS \u2014 refusing to fetch ${t.href} (only https:// is supported).`)}function g(o,t){p(o);let e=new Headers(t?.headers);return e.has("User-Agent")||e.set("User-Agent",F),fetch(o,{...t,headers:e})}var L="https://{publisher}/{package}/{version}.kan.yml",A={version:1};function T(){return{version:1}}var k=class{constructor(t){this.fetchFn=t}fetchFn;cache=new Map;getConfig(t){let e=this.cache.get(t);return e||(e=this.fetchConfig(t),this.cache.set(t,e),e.catch(()=>{this.cache.get(t)===e&&this.cache.delete(t)})),e}async fetchConfig(t){let e=`https://${t}/.well-known/kanonak.json`,n;try{n=await(this.fetchFn?this.fetchFn(e,t):g(e))}catch{return A}if(n.status===404)return A;if(!n.ok)throw new Error(`Failed to fetch publisher config: ${e} (${n.status} ${n.statusText})`);let r=await n.json();if(typeof r.version!="number")throw new Error(`Invalid publisher config at ${e}: missing or invalid "version" field`);let i={version:r.version};return typeof r.package_url_template=="string"&&(U(e,"package_url_template",r.package_url_template),i.package_url_template=r.package_url_template),Array.isArray(r.featured_packages)&&r.featured_packages.every(s=>typeof s=="string")&&(i.featured_packages=r.featured_packages),i}resolvePackageUrl(t,e,n,r){let i=r.package_url_template??L,s=E(i,{publisher:t,package:e,version:n});return p(s),s}};function U(o,t,e){if(!e.startsWith("https://"))throw new Error(`Invalid publisher config at ${o}: ${t} must be an absolute https:// URL template (got "${e}").`)}function E(o,t){let e=o;for(let[r,i]of Object.entries(t))e=e.replaceAll(`{${r}}`,i);let n=e.match(/\{[a-z]+\}/);if(n)throw new Error(`Unresolved variable ${n[0]} in URL template: ${o}`);return e}import D from"js-yaml";function R(o){let t=D.load(o);return!t||typeof t!="object"||t.version!=="1"?null:{version:"1",lastUpdated:t.lastUpdated??"",packages:t.packages??{}}}var m=class{configResolver;fetchFn;lockCache=new Map;constructor(t){this.configResolver=t?.configResolver??new k(t?.fetchFn),this.fetchFn=t?.fetchFn}getConfig(t){return this.configResolver.getConfig(t)}async getPackageUrl(t,e,n){let r=await this.configResolver.getConfig(t);return this.configResolver.resolvePackageUrl(t,e,n,r)}getLock(t){let e=this.lockCache.get(t);return e||(e=this.fetchLock(t),this.lockCache.set(t,e),e.catch(()=>{this.lockCache.get(t)===e&&this.lockCache.delete(t)})),e}async fetchLock(t){let e=`https://${t}/kanonak.lock`,n;try{n=this.fetchFn?await this.fetchFn(e,t):await g(e)}catch{return null}if(n.status===404)return null;if(!n.ok)throw new Error(`Failed to fetch publisher lock: ${e} (${n.status} ${n.statusText})`);return R(await n.text())}};import{VersionOperator as d}from"@kanonak-protocol/types/document/models/enums";function _(o,t){let e=P(o);if(!e)return!1;let n=t.version;switch(t.versionOperator){case d.Any:return!0;case d.Exact:return e.major===n.major&&e.minor===n.minor&&e.patch===n.patch;case d.Compatible:return e.major===n.major&&e.minor===n.minor&&e.patch>=n.patch;case d.Major:return e.major!==n.major?!1:e.minor!==n.minor?e.minor>n.minor:e.patch>=n.patch;default:return!1}}var $=class{parser=new C;publisherIndex;documents=new Map;contentCache=new Map;fetchFn;onFetch;getFromCache;constructor(t){this.onFetch=t?.onFetch,this.getFromCache=t?.getFromCache,this.fetchFn=t?.fetchFn,this.publisherIndex=t?.fetchFn?new m({fetchFn:t.fetchFn}):new m}async getHighestCompatibleVersionAsync(t,e){let r=(await this.publisherIndex.getLock(t))?.packages[`${t}/${e.packageName}`];return r?_(r.version,e)?this.fetchPinned(t,e.packageName,r):null:this.resolveByDirectFetch(t,e)}async fetchPinned(t,e,n){let r=n.version,i=`${t}/${e}@${r}`,s=this.documents.get(i);if(s)return s;let a=u=>{let f=this.parser.parse(u);return v(f,t,e,r),f};if(this.getFromCache){let u=this.getFromCache(t,e,r);if(u){let f=a(u);return this.documents.set(i,f),this.contentCache.set(i,u),f}}let l=n.resolved,c=this.fetchFn?await this.fetchFn(l,t):await g(l);if(!c.ok)throw new Error(`Failed to fetch Kanonak package: ${l} (${c.status} ${c.statusText})`);let h=await c.text(),w=a(h);return this.onFetch&&this.onFetch(t,e,r,h),this.documents.set(i,w),this.contentCache.set(i,h),w}async resolveByDirectFetch(t,e){let n=e.packageName,i=e.versionOperator===d.Exact?await this.publisherIndex.getPackageUrl(t,n,y(e.version)):`https://${t}/${n}.kan.yml`,s=await this.fetchFollowing(i,t);if(!s)return null;let a=this.parser.parse(s.content),l=a.metadata.namespace_;if(!l||!l.version)throw new Error(`Producer origin returned a package with no namespace/version for ${t}/${n}`);let c=y(l.version);v(a,t,n,c);let h=`${t}/${n}@${c}`;return this.onFetch&&this.onFetch(t,n,c,s.content),this.documents.set(h,a),this.contentCache.set(h,s.content),a}async fetchFollowing(t,e,n=4){let r=t;for(let i=0;i<n;i++){p(r);let s=this.fetchFn?await this.fetchFn(r,e):await g(r,{redirect:"manual"});if(s.status===301||s.status===302){let a=s.headers.get("location");if(!a)throw new Error(`Redirect with no Location header from ${r}`);r=new URL(a,r).toString();continue}if(s.status===404)return null;if(!s.ok)throw new Error(`Failed to fetch Kanonak package: ${r} (${s.status} ${s.statusText})`);return{url:r,content:await s.text()}}throw new Error(`Too many redirects resolving ${t}`)}async getAllDocumentsAsync(){return Array.from(this.documents.values())}async getDocumentAsync(t){return this.documents.get(t)??null}async getDocumentsByNamespaceAsync(t,e){return Array.from(this.documents.values()).filter(n=>{let r=n.metadata.namespace_;return r&&r.publisher===t&&r.package_===e})}async saveDocumentAsync(t,e){throw new Error("HttpKanonakDocumentRepository is read-only")}async deleteDocumentAsync(t){throw new Error("HttpKanonakDocumentRepository is read-only")}async clearNamespaceAsync(t,e){throw new Error("HttpKanonakDocumentRepository is read-only")}async getAllDocumentReferencesAsync(){return[]}async getDocumentContentAsync(t){return this.contentCache.get(t)??null}async getDocumentUriAsync(t){let e=t.match(/^(.+?)\/(.+?)@(.+)$/);if(!e)return null;let[,n,r,i]=e;return this.publisherIndex.getPackageUrl(n,r,i)}};export{x as a,K as b,b as c,p as d,g as e,T as f,k as g,R as h,m as i,$ as j};
@@ -34,8 +34,24 @@ export declare const KANONAK_USER_AGENT = "@kanonak-protocol/sdk (+https://kanon
34
34
  export declare function setKanonakUserAgent(ua: string): void;
35
35
  /** The User-Agent the SDK currently sends (the default, or a host override). */
36
36
  export declare function getKanonakUserAgent(): string;
37
+ /**
38
+ * Kanonak speaks HTTPS only. Throws unless `url` is an absolute `https://` URL.
39
+ *
40
+ * This is a hard protocol invariant, not a preference: every security guarantee
41
+ * — discovery-on-your-own-domain as proof of control (`.well-known/kanonak.json`),
42
+ * the `authorization_servers` pointer that drives enrollment, and the lock's
43
+ * integrity hashes — collapses if any hop is plain HTTP and tamperable. So an
44
+ * `http://` (or scheme-less) URL is refused, including on every redirect hop a
45
+ * follower resolves. The scheme must be explicit `https://` — we never imply it,
46
+ * because guessing a scheme is exactly the kind of silent behavior this guards
47
+ * against. There is no config switch to disable this; a consumer that genuinely
48
+ * needs another transport (tests, `http://localhost` dev) injects its own
49
+ * `fetchFn`, which owns the request and bypasses this default path entirely.
50
+ */
51
+ export declare function assertHttpsUrl(url: string | URL): void;
37
52
  /**
38
53
  * `fetch` with the SDK's User-Agent added — unless the caller already set one,
39
- * which is preserved. All other `init` fields pass through untouched.
54
+ * which is preserved. All other `init` fields pass through untouched. Rejects
55
+ * any non-https target up front via {@link assertHttpsUrl}.
40
56
  */
41
57
  export declare function kanonakFetch(input: string | URL, init?: RequestInit): Promise<Response>;
package/dist/index.d.ts CHANGED
@@ -23,7 +23,7 @@ export type { KanonakDocument, KanonakMetadata, Namespace, Import, Version, Docu
23
23
  export { VersionOperator } from '@kanonak-protocol/types/document/models/enums';
24
24
  export { CredentialStore, DeviceCertificateStore, SessionStore, sessionNeedsRefresh, OAuthDiscovery, DEFAULT_CONSENT_BINDING_PARAM, SessionExchange, SessionExchangeError, SessionManager, SessionError, CredentialResolver, createAuthenticatedFetch, generateDPoPKeyPair, createDPoPProof, serverSupportsDPoP, isExpired, hasValidToken, normalizeHost, } from './auth/index.js';
25
25
  export type { SecretBackend, CredentialBackend, StoredCredential, DeviceEnrollmentRecord, SessionRecord, SessionStoreDeps, OAuthServerMetadata, ExchangedSession, MtlsTransport, SessionManagerDeps, SessionDiscovery, DeviceStoreLike, ResolvedCredential, CredentialResolverDeps, DPoPKeyPair, AuthenticatedFetchFn, } from './auth/index.js';
26
- export { kanonakFetch, setKanonakUserAgent, getKanonakUserAgent, KANONAK_USER_AGENT, } from './http/kanonakFetch.js';
26
+ export { kanonakFetch, assertHttpsUrl, setKanonakUserAgent, getKanonakUserAgent, KANONAK_USER_AGENT, } from './http/kanonakFetch.js';
27
27
  export { loadLockFile, saveLockFile, computeIntegrity, } from './lock/index.js';
28
28
  export type { LockFile, LockEntry } from './lock/index.js';
29
29
  export { findDerivation } from './derivation/index.js';
package/dist/index.js CHANGED
@@ -1,12 +1,12 @@
1
- import{a as Rr,b as xr,c as Cr,d as Ar,e as ke}from"./chunk-TVSHIXLA.js";import{a as Sn,c as ve,e as je,h as Me,i as Ve,j as vn}from"./chunk-IHB7UVEH.js";import{a as Pr,b as br,c as Er,d as Z,e as Q,f as l,g as wn,h as we,i as Pn,j as bn}from"./chunk-VOJ6BGAR.js";import{a as kn}from"./chunk-EZSHR3CB.js";import"./chunk-QHABFCRC.js";import{a as Ot,b as Bt,c as jt,d as Mt,e as Vt,f as Jt,g as qt,h as Xt,i as Yt}from"./chunk-GMEPM2QQ.js";import{a as Lt,b as Ft,c as Ut,d as C,f as Ht,g as zt,h as Gt}from"./chunk-JYBKSBB5.js";import{a as Nt}from"./chunk-4NO7MHS7.js";import{a as Tr,b as _r,c as $r,d as Ir}from"./chunk-S6VSAKXB.js";import{a as Kr,b as Lr}from"./chunk-PEUTCG3B.js";import{a as Or}from"./chunk-PEJALHXK.js";import{a as Wt}from"./chunk-SC5M74NM.js";import{A as fn,B as hn,K as gn,a as Fr,b as Ur,c as Hr,d as zr,e as Wr,f as Gr,g as Jr,h as qr,i as Xr,j as Yr,k as Zr,l as Qr,m as en,n as tn,o as rn,p as nn,q as on,r as sn,s as an,t as cn,u as ln,v as dn,w as pn,x as un,y as mn,z as yn}from"./chunk-7K5TAJ44.js";import"./chunk-ITKOKDBG.js";import{a as D,b as tr,c as dr,h as mr,i as yr,j as Sr,k as vr,l as F}from"./chunk-MX3DEXMV.js";import{a as j}from"./chunk-NJ3AZYQD.js";import{a as wr,b as Se,c as Nr,d as w,e as Br,f as jr,g as Mr,h as Vr}from"./chunk-ZP6P7HNU.js";import{a as Be}from"./chunk-6U26UASC.js";import{a as pr,b as ur,c as L,d as fr,e as hr,g as gr,k as kr}from"./chunk-GZPLWII7.js";import{a as Zt,b as Qt,c as A,d as M,e as rr,f as nr,g as or,h as sr,i as ir,j as ar,k as cr,l as lr,r as Y,w as V,x as he,y as ge}from"./chunk-7BHDZHJY.js";import{a as er}from"./chunk-FUUTGGJS.js";import{a as At,b as fe,c as X,d as Dt,e as E,f as Tt,g as _t,h as $t,i as It,j as Kt}from"./chunk-2ACBWC7K.js";import{a as Dr}from"./chunk-ODIECDN7.js";import{VersionOperator as fa}from"@kanonak-protocol/types/document/models/enums";import{existsSync as zn,readFileSync as Wn}from"fs";import{homedir as Gn}from"os";import{join as Jn}from"path";import{execFile as En}from"child_process";import{promisify as Rn}from"util";var ee=Rn(En),xn="kanonak",te="/usr/bin/security",m=class{constructor(e=xn){this.service=e}service;async get(e){let t=l(e);try{let{stdout:r}=await ee(te,["find-generic-password","-s",this.service,"-a",t,"-w"],{timeout:1e4});try{return JSON.parse(r.trim())}catch{throw new Error(`Stored credential for '${t}' is corrupted (not valid JSON).
2
- Run 'kanonak logout ${t}' then 'kanonak login ${t}' to fix.`)}}catch(r){if(Le(r,44))return null;throw new Error(`macOS Keychain read failed for '${t}': ${re(r)}
1
+ import{a as xr,b as Cr,c as Ar,d as Dr,e as Se}from"./chunk-TVSHIXLA.js";import{a as vn,c as Pe,e as Me,h as Ve,i as Le,j as Pn}from"./chunk-IHB7UVEH.js";import{a as br,b as Er,c as Rr,d as Z,e as Y,f as c,g as wn,h as we,i as bn,j as En}from"./chunk-VOJ6BGAR.js";import{a as Sn}from"./chunk-EZSHR3CB.js";import"./chunk-QHABFCRC.js";import{a as Ot,b as Bt,c as jt,d as Mt,e as Vt,f as qt,g as Xt,h as Zt,i as Yt}from"./chunk-3BNJXSVZ.js";import{a as Lt,b as Ft,c as Ut,d as Ht,e as C,g as zt,h as he,i as Wt,j as Jt}from"./chunk-XGTUVPR3.js";import{a as Nt}from"./chunk-4NO7MHS7.js";import{a as $r,b as _r,c as Kr,d as Ir}from"./chunk-S6VSAKXB.js";import{a as Nr,b as Fr}from"./chunk-PEUTCG3B.js";import{a as Br}from"./chunk-PEJALHXK.js";import{a as Gt}from"./chunk-SC5M74NM.js";import{A as hn,B as gn,K as kn,a as Ur,b as Hr,c as zr,d as Wr,e as Gr,f as Jr,g as qr,h as Xr,i as Zr,j as Yr,k as Qr,l as en,m as tn,n as rn,o as nn,p as on,q as sn,r as an,s as cn,t as ln,u as dn,v as pn,w as un,x as mn,y as yn,z as fn}from"./chunk-7K5TAJ44.js";import"./chunk-ITKOKDBG.js";import{a as D,b as rr,c as pr,h as yr,i as fr,j as vr,k as Pr,l as L}from"./chunk-MX3DEXMV.js";import{a as B}from"./chunk-NJ3AZYQD.js";import{a as wr,b as ve,c as Or,d as P,e as jr,f as Mr,g as Vr,h as Lr}from"./chunk-ZP6P7HNU.js";import{a as je}from"./chunk-6U26UASC.js";import{a as ur,b as mr,c as V,d as hr,e as gr,g as kr,k as Sr}from"./chunk-GZPLWII7.js";import{a as Qt,b as er,c as A,d as j,e as nr,f as or,g as sr,h as ir,i as ar,j as cr,k as lr,l as dr,r as X,w as M,x as ge,y as ke}from"./chunk-7BHDZHJY.js";import{a as tr}from"./chunk-FUUTGGJS.js";import{a as At,b as fe,c as q,d as Dt,e as E,f as Tt,g as $t,h as _t,i as Kt,j as It}from"./chunk-2ACBWC7K.js";import{a as Tr}from"./chunk-ODIECDN7.js";import{VersionOperator as ka}from"@kanonak-protocol/types/document/models/enums";import{existsSync as Wn,readFileSync as Gn}from"fs";import{homedir as Jn}from"os";import{join as qn}from"path";import{execFile as Rn}from"child_process";import{promisify as xn}from"util";var Q=xn(Rn),Cn="kanonak",ee="/usr/bin/security",m=class{constructor(e=Cn){this.service=e}service;async get(e){let t=c(e);try{let{stdout:r}=await Q(ee,["find-generic-password","-s",this.service,"-a",t,"-w"],{timeout:1e4});try{return JSON.parse(r.trim())}catch{throw new Error(`Stored credential for '${t}' is corrupted (not valid JSON).
2
+ Run 'kanonak logout ${t}' then 'kanonak login ${t}' to fix.`)}}catch(r){if(Fe(r,44))return null;throw new Error(`macOS Keychain read failed for '${t}': ${te(r)}
3
3
  The Keychain may be locked or inaccessible.
4
- Try unlocking it via Keychain Access.app or running 'security unlock-keychain'.`)}}async store(e,t){let r=l(e),n=JSON.stringify(t);try{await ee(te,["add-generic-password","-s",this.service,"-a",r,"-U","-w",n],{timeout:1e4})}catch(s){throw new Error(`macOS Keychain write failed for '${r}': ${re(s)}
4
+ Try unlocking it via Keychain Access.app or running 'security unlock-keychain'.`)}}async store(e,t){let r=c(e),n=JSON.stringify(t);try{await Q(ee,["add-generic-password","-s",this.service,"-a",r,"-U","-w",n],{timeout:1e4})}catch(s){throw new Error(`macOS Keychain write failed for '${r}': ${te(s)}
5
5
  Ensure the Keychain is unlocked and the CLI has write permission.
6
- On managed devices, your IT policy may block credential storage.`)}}async remove(e){let t=l(e);try{await ee(te,["delete-generic-password","-s",this.service,"-a",t],{timeout:1e4})}catch(r){if(Le(r,44))return;console.warn(` Warning: macOS Keychain delete failed for '${t}': ${re(r)}
7
- The credential may not have been fully removed.`)}}async list(){try{let{stdout:e}=await ee(te,["dump-keychain"],{timeout:1e4}),t=[],r=!1;for(let n of e.split(`
8
- `))if(n.includes(`"svce"<blob>="${this.service}"`)&&(r=!0),r&&n.includes('"acct"<blob>=')){let s=n.match(/"acct"<blob>="([^"]+)"/);s&&t.push(s[1]),r=!1}return t}catch(e){return console.warn(` Warning: Could not enumerate Keychain entries: ${re(e)}`),[]}}};function Le(o,e){return typeof o=="object"&&o!==null&&"code"in o&&o.code===e}function re(o){return o instanceof Error?o.message:String(o)}import{execFile as Cn}from"child_process";import{promisify as An}from"util";var Dn=An(Cn),Tn="kanonak:",Fe=2560,y=class{constructor(e=Tn){this.targetPrefix=e}targetPrefix;async get(e){let t=this.targetPrefix+l(e),r=`
9
- ${oe}
6
+ On managed devices, your IT policy may block credential storage.`)}}async remove(e){let t=c(e);try{await Q(ee,["delete-generic-password","-s",this.service,"-a",t],{timeout:1e4})}catch(r){if(Fe(r,44))return;console.warn(` Warning: macOS Keychain delete failed for '${t}': ${te(r)}
7
+ The credential may not have been fully removed.`)}}async list(){try{let{stdout:e}=await Q(ee,["dump-keychain"],{timeout:1e4}),t=[],r=!1;for(let n of e.split(`
8
+ `))if(n.includes(`"svce"<blob>="${this.service}"`)&&(r=!0),r&&n.includes('"acct"<blob>=')){let s=n.match(/"acct"<blob>="([^"]+)"/);s&&t.push(s[1]),r=!1}return t}catch(e){return console.warn(` Warning: Could not enumerate Keychain entries: ${te(e)}`),[]}}};function Fe(o,e){return typeof o=="object"&&o!==null&&"code"in o&&o.code===e}function te(o){return o instanceof Error?o.message:String(o)}import{execFile as An}from"child_process";import{promisify as Dn}from"util";var Tn=Dn(An),$n="kanonak:",Ue=2560,y=class{constructor(e=$n){this.targetPrefix=e}targetPrefix;async get(e){let t=this.targetPrefix+c(e),r=`
9
+ ${ne}
10
10
  $target = $env:KANONAK_CRED_TARGET
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:n}=await ne(r,{KANONAK_CRED_TARGET:t}),s=n.trim();return s?JSON.parse(s):null}catch{return null}}async store(e,t){let r=this.targetPrefix+l(e),n=JSON.stringify(t),s=Buffer.byteLength(n,"utf16le");if(s>Fe)throw new Error(`Credential '${r}' is ${s} bytes (UTF-16), over the Windows Credential Manager limit of ${Fe} (CRED_MAX_CREDENTIAL_BLOB_SIZE). Keep only the secret here and store large/public material (certificates, chains) on disk.`);let i=`
22
- ${oe}
21
+ }`;try{let{stdout:n}=await re(r,{KANONAK_CRED_TARGET:t}),s=n.trim();return s?JSON.parse(s):null}catch{return null}}async store(e,t){let r=this.targetPrefix+c(e),n=JSON.stringify(t),s=Buffer.byteLength(n,"utf16le");if(s>Ue)throw new Error(`Credential '${r}' is ${s} bytes (UTF-16), over the Windows Credential Manager limit of ${Ue} (CRED_MAX_CREDENTIAL_BLOB_SIZE). Keep only the secret here and store large/public material (certificates, chains) on disk.`);let i=`
22
+ ${ne}
23
23
  $target = $env:KANONAK_CRED_TARGET
24
24
  $json = $env:KANONAK_CRED_JSON
25
25
  $bytes = [System.Text.Encoding]::Unicode.GetBytes($json)
@@ -35,11 +35,11 @@ try {
35
35
  if (-not $result) { throw "CredWrite failed (Win32 error $([System.Runtime.InteropServices.Marshal]::GetLastWin32Error()))" }
36
36
  } finally {
37
37
  [System.Runtime.InteropServices.Marshal]::FreeHGlobal($cred.CredentialBlob)
38
- }`;try{await ne(i,{KANONAK_CRED_TARGET:r,KANONAK_CRED_JSON:n})}catch(a){let c=a,d=c.stderr&&c.stderr.trim()||c.message||String(a);throw new Error(`Windows Credential Manager write failed: ${d}`)}}async remove(e){let t=this.targetPrefix+l(e),r=`
39
- ${oe}
38
+ }`;try{await re(i,{KANONAK_CRED_TARGET:r,KANONAK_CRED_JSON:n})}catch(a){let l=a,d=l.stderr&&l.stderr.trim()||l.message||String(a);throw new Error(`Windows Credential Manager write failed: ${d}`)}}async remove(e){let t=this.targetPrefix+c(e),r=`
39
+ ${ne}
40
40
  $target = $env:KANONAK_CRED_TARGET
41
- [CredMan]::CredDelete($target, 1, 0) | Out-Null`;try{await ne(r,{KANONAK_CRED_TARGET:t})}catch{}}async list(){let e=`
42
- ${oe}
41
+ [CredMan]::CredDelete($target, 1, 0) | Out-Null`;try{await re(r,{KANONAK_CRED_TARGET:t})}catch{}}async list(){let e=`
42
+ ${ne}
43
43
  ${_n}
44
44
  $prefix = $env:KANONAK_CRED_PREFIX
45
45
  $count = 0
@@ -57,8 +57,8 @@ if ([CredMan]::CredEnumerate(($prefix + "*"), 0, [ref]$count, [ref]$pCreds)) {
57
57
  }
58
58
  }
59
59
  [CredMan]::CredFree($pCreds)
60
- }`;try{let{stdout:t}=await ne(e,{KANONAK_CRED_PREFIX:this.targetPrefix});return t.trim().split(`
61
- `).map(r=>r.trim()).filter(Boolean)}catch{return[]}}};async function ne(o,e){let t=Buffer.from(o,"utf16le").toString("base64");for(let r of["pwsh","powershell"])try{return await Dn(r,["-NoProfile","-NonInteractive","-EncodedCommand",t],{timeout:15e3,...e&&{env:{...process.env,...e}}})}catch(n){if(r==="powershell")throw n}throw new Error("Neither pwsh nor powershell found")}var oe=`
60
+ }`;try{let{stdout:t}=await re(e,{KANONAK_CRED_PREFIX:this.targetPrefix});return t.trim().split(`
61
+ `).map(r=>r.trim()).filter(Boolean)}catch{return[]}}};async function re(o,e){let t=Buffer.from(o,"utf16le").toString("base64");for(let r of["pwsh","powershell"])try{return await Tn(r,["-NoProfile","-NonInteractive","-EncodedCommand",t],{timeout:15e3,...e&&{env:{...process.env,...e}}})}catch(n){if(r==="powershell")throw n}throw new Error("Neither pwsh nor powershell found")}var ne=`
62
62
  Add-Type -TypeDefinition @"
63
63
  using System;
64
64
  using System.Runtime.InteropServices;
@@ -89,15 +89,15 @@ public class CredMan {
89
89
  [DllImport("Advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
90
90
  public static extern bool CredEnumerate(string filter, int flags, out int count, out IntPtr credentials);
91
91
  }
92
- "@`,_n="";import{execFile as $n,spawn as In}from"child_process";import{promisify as Kn}from"util";var se=Kn($n),Nn="kanonak",f=class{constructor(e=Nn){this.service=e}service;async get(e){let t=l(e);try{let{stdout:r}=await se("secret-tool",["lookup","service",this.service,"publisher",t],{timeout:1e4}),n=r.trim();return n?JSON.parse(n):null}catch{return null}}async store(e,t){let r=l(e),n=JSON.stringify(t);await new Promise((s,i)=>{let a=In("secret-tool",["store","--label",`Kanonak: ${r}`,"service",this.service,"publisher",r],{stdio:["pipe","ignore","ignore"],timeout:1e4});a.stdin.write(n),a.stdin.end(),a.on("close",c=>{c===0?s():i(new Error(`secret-tool store exited with code ${c}`))}),a.on("error",i)})}async remove(e){let t=l(e);try{await se("secret-tool",["clear","service",this.service,"publisher",t],{timeout:1e4})}catch{}}async list(){try{let{stdout:e}=await se("secret-tool",["search","service",this.service],{timeout:1e4}),t=[];for(let r of e.split(`
93
- `)){let n=r.match(/attribute\.publisher\s*=\s*(.+)/);n&&t.push(n[1].trim())}return t}catch{return[]}}};async function R(){try{return await se("sh",["-c","command -v secret-tool"],{timeout:5e3}),!0}catch{return!1}}import{existsSync as Ue,mkdirSync as He,readFileSync as ze,writeFileSync as We}from"fs";import{createCipheriv as On,createDecipheriv as Bn,randomBytes as Ge}from"crypto";import{homedir as jn}from"os";import{join as Ee,dirname as Je}from"path";var Xe=Ee(jn(),".config","kanonak"),U=Ee(Xe,"keyring.key"),Mn=Ee(Xe,"credentials.enc"),qe="aes-256-gcm",Pe=32,T=12,be=16,h=class{constructor(e=Mn){this.secretsFile=e}secretsFile;async get(e){let t=this.loadStore(),r=l(e);return t[r]??null}async store(e,t){let r=this.loadStore(),n=l(e);r[n]=t,this.saveStore(r)}async remove(e){let t=this.loadStore(),r=l(e);delete t[r],this.saveStore(t)}async list(){let e=this.loadStore();return Object.keys(e)}loadStore(){if(!Ue(this.secretsFile))return{};try{let e=this.getOrCreateKey(),t=ze(this.secretsFile);if(t.length<T+be)return{};let r=t.subarray(0,T),n=t.subarray(T,T+be),s=t.subarray(T+be),i=Bn(qe,e,r);i.setAuthTag(n);let a=Buffer.concat([i.update(s),i.final()]);return JSON.parse(a.toString("utf-8"))}catch{return{}}}saveStore(e){let t=this.getOrCreateKey(),r=Ge(T),n=On(qe,t,r),s=Buffer.from(JSON.stringify(e),"utf-8"),i=Buffer.concat([n.update(s),n.final()]),a=n.getAuthTag(),c=Buffer.concat([r,a,i]);He(Je(this.secretsFile),{recursive:!0}),We(this.secretsFile,c,{mode:384})}getOrCreateKey(){if(Ue(U)){let t=ze(U);if(t.length!==Pe)throw new Error(`Credential keyring key is corrupted (expected ${Pe} bytes, got ${t.length}). Delete ${U} and re-authenticate.`);return t}let e=Ge(Pe);return He(Je(U),{recursive:!0}),We(U,e,{mode:384}),e}};import{execFile as Vn}from"child_process";import{promisify as Ln}from"util";var Fn=Ln(Vn),Ye=3e4,H=class{constructor(e){this.helperPath=e}helperPath;async get(e){let t=l(e);try{let n=(await this.runHelper("get",{publisher:t})).trim();return n?JSON.parse(n):null}catch(r){throw new Error(`Credential helper '${this.helperPath}' failed to read credential for '${t}': ${ie(r)}
92
+ "@`,_n="";import{execFile as Kn,spawn as In}from"child_process";import{promisify as Nn}from"util";var oe=Nn(Kn),On="kanonak",f=class{constructor(e=On){this.service=e}service;async get(e){let t=c(e);try{let{stdout:r}=await oe("secret-tool",["lookup","service",this.service,"publisher",t],{timeout:1e4}),n=r.trim();return n?JSON.parse(n):null}catch{return null}}async store(e,t){let r=c(e),n=JSON.stringify(t);await new Promise((s,i)=>{let a=In("secret-tool",["store","--label",`Kanonak: ${r}`,"service",this.service,"publisher",r],{stdio:["pipe","ignore","ignore"],timeout:1e4});a.stdin.write(n),a.stdin.end(),a.on("close",l=>{l===0?s():i(new Error(`secret-tool store exited with code ${l}`))}),a.on("error",i)})}async remove(e){let t=c(e);try{await oe("secret-tool",["clear","service",this.service,"publisher",t],{timeout:1e4})}catch{}}async list(){try{let{stdout:e}=await oe("secret-tool",["search","service",this.service],{timeout:1e4}),t=[];for(let r of e.split(`
93
+ `)){let n=r.match(/attribute\.publisher\s*=\s*(.+)/);n&&t.push(n[1].trim())}return t}catch{return[]}}};async function R(){try{return await oe("sh",["-c","command -v secret-tool"],{timeout:5e3}),!0}catch{return!1}}import{existsSync as He,mkdirSync as ze,readFileSync as We,writeFileSync as Ge}from"fs";import{createCipheriv as Bn,createDecipheriv as jn,randomBytes as Je}from"crypto";import{homedir as Mn}from"os";import{join as Re,dirname as qe}from"path";var Ze=Re(Mn(),".config","kanonak"),F=Re(Ze,"keyring.key"),Vn=Re(Ze,"credentials.enc"),Xe="aes-256-gcm",be=32,T=12,Ee=16,h=class{constructor(e=Vn){this.secretsFile=e}secretsFile;async get(e){let t=this.loadStore(),r=c(e);return t[r]??null}async store(e,t){let r=this.loadStore(),n=c(e);r[n]=t,this.saveStore(r)}async remove(e){let t=this.loadStore(),r=c(e);delete t[r],this.saveStore(t)}async list(){let e=this.loadStore();return Object.keys(e)}loadStore(){if(!He(this.secretsFile))return{};try{let e=this.getOrCreateKey(),t=We(this.secretsFile);if(t.length<T+Ee)return{};let r=t.subarray(0,T),n=t.subarray(T,T+Ee),s=t.subarray(T+Ee),i=jn(Xe,e,r);i.setAuthTag(n);let a=Buffer.concat([i.update(s),i.final()]);return JSON.parse(a.toString("utf-8"))}catch{return{}}}saveStore(e){let t=this.getOrCreateKey(),r=Je(T),n=Bn(Xe,t,r),s=Buffer.from(JSON.stringify(e),"utf-8"),i=Buffer.concat([n.update(s),n.final()]),a=n.getAuthTag(),l=Buffer.concat([r,a,i]);ze(qe(this.secretsFile),{recursive:!0}),Ge(this.secretsFile,l,{mode:384})}getOrCreateKey(){if(He(F)){let t=We(F);if(t.length!==be)throw new Error(`Credential keyring key is corrupted (expected ${be} bytes, got ${t.length}). Delete ${F} and re-authenticate.`);return t}let e=Je(be);return ze(qe(F),{recursive:!0}),Ge(F,e,{mode:384}),e}};import{execFile as Ln}from"child_process";import{promisify as Fn}from"util";var Un=Fn(Ln),Ye=3e4,U=class{constructor(e){this.helperPath=e}helperPath;async get(e){let t=c(e);try{let n=(await this.runHelper("get",{publisher:t})).trim();return n?JSON.parse(n):null}catch(r){throw new Error(`Credential helper '${this.helperPath}' failed to read credential for '${t}': ${se(r)}
94
94
  Verify the helper binary exists, is executable, and implements the Kanonak credential helper protocol.
95
- Check the 'credentialHelper' path in ~/.kanonak/config.json.`)}}async store(e,t){let r=l(e);try{await this.runHelper("store",{publisher:r,credential:t})}catch(n){throw new Error(`Credential helper '${this.helperPath}' failed to store credential for '${r}': ${ie(n)}
96
- Verify the helper binary supports the 'store' action.`)}}async remove(e){let t=l(e);try{await this.runHelper("erase",{publisher:t})}catch(r){console.warn(` Warning: Credential helper '${this.helperPath}' failed to erase credential for '${t}': ${ie(r)}`)}}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: ${ie(e)}`),[]}}async runHelper(e,t){try{let{stdout:r}=await Fn(this.helperPath,[e],{...t&&{input:JSON.stringify(t)},timeout:Ye});return r}catch(r){throw Un(r)?new Error(`Credential helper not found at '${this.helperPath}'.
97
- Check the 'credentialHelper' path in ~/.kanonak/config.json.`):Hn(r)?new Error(`Credential helper '${this.helperPath}' timed out after ${Ye/1e3}s on '${e}'.
98
- The helper may be waiting for authentication to an external vault.`):r}}};function ie(o){return o instanceof Error?o.message:String(o)}function Un(o){return o instanceof Error&&"code"in o&&o.code==="ENOENT"}function Hn(o){return o instanceof Error&&"killed"in o&&o.killed}var Re=Jn(Gn(),".kanonak","config.json"),ae=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 t=qn(e);if(t)return t;let n=await(await this.getBackend()).get(e);return!n||!Q(n)?null:n.accessToken??null}async getCredential(e){return(await this.getBackend()).get(e)}async store(e,t){return(await this.getBackend()).store(e,t)}async remove(e){return(await this.getBackend()).remove(e)}async list(){return(await this.getBackend()).list()}async resolveBackend(){let e=Xn();return e.credentialHelper?new H(e.credentialHelper):process.platform==="darwin"?new m:process.platform==="win32"?new y:await R()?new f:new h}};function qn(o){let t="KANONAK_TOKEN_"+l(o).replace(/[.\-]/g,"_").toUpperCase();return process.env[t]??null}function Xn(){if(!zn(Re))return{};try{return JSON.parse(Wn(Re,"utf-8"))}catch(o){let e=o instanceof Error?o.message:String(o);return console.warn(` Warning: Failed to parse ${Re}: ${e}
99
- Using default credential backend. Fix the JSON syntax or delete the file.`),{}}}import{homedir as tt}from"os";import{join as x}from"path";import{mkdir as Yn,writeFile as Ze,readFile as Qe,rm as et}from"fs/promises";var xe="kanonak-device",Zn=x(tt(),".config","kanonak","device-credentials.enc"),Qn=x(tt(),".kanonak","devices"),P=class{constructor(e={}){this.deps=e}deps;backend=null;backendReady=null;certDir(e){let t=l(e).replace(/[^a-zA-Z0-9._-]/g,"_");return x(this.deps.certBaseDir??Qn,t)}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 get(e){let t=await(await this.getBackend()).get(e);if(!t)return null;if(typeof t.certificatePem=="string"&&typeof t.chainPem=="string")return t;let r=this.certDir(e),n,s;try{n=await Qe(x(r,"cert.pem"),"utf-8"),s=await Qe(x(r,"chain.pem"),"utf-8")}catch{return null}return{...t,certificatePem:n,chainPem:s}}async store(e,t){let{certificatePem:r,chainPem:n,...s}=t,i=this.certDir(e);await Yn(i,{recursive:!0}),await Ze(x(i,"cert.pem"),r,"utf-8"),await Ze(x(i,"chain.pem"),n,"utf-8");try{await(await this.getBackend()).store(e,s)}catch(a){throw await et(i,{recursive:!0,force:!0}).catch(()=>{}),a}}async remove(e){await(await this.getBackend()).remove(e),await et(this.certDir(e),{recursive:!0,force:!0})}async list(){return(await this.getBackend()).list()}async resolveBackend(){return this.deps.backend?this.deps.backend:process.platform==="darwin"?new m(xe):process.platform==="win32"?new y(`${xe}:`):await R()?new f(xe):new h(Zn)}};import{homedir as eo}from"os";import{join as to}from"path";var Ce="kanonak-session",ro=to(eo(),".config","kanonak","session-credentials.enc"),_=class{constructor(e={}){this.deps=e}deps;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 get(e){return(await this.getBackend()).get(e)}async store(e,t){return(await this.getBackend()).store(e,t)}async remove(e){return(await this.getBackend()).remove(e)}async list(){return(await this.getBackend()).list()}async resolveBackend(){return this.deps.backend?this.deps.backend:process.platform==="darwin"?new m(Ce):process.platform==="win32"?new y(`${Ce}:`):await R()?new f(Ce):new h(ro)}};function ce(o,e=5*6e4,t=Date.now()){let r=Date.parse(o.expiresAt);return Number.isNaN(r)?!0:t>=r-e}var rt="key_thumbprint",b=class{cache=new Map;prCache=new Map;async discoverProtectedResource(e){let t=l(e);if(this.prCache.has(t))return this.prCache.get(t);let r=`https://${t}/.well-known/oauth-protected-resource`,n=await no(r),s=n&&Array.isArray(n.authorization_servers)?n.authorization_servers.filter(a=>typeof a=="string"):[],i=s.length>0?s:null;return this.prCache.set(t,i),i}async discover(e){let t=l(e);if(this.cache.has(t))return this.cache.get(t);let r=`https://${t}/.well-known/oauth-authorization-server`,n=await this.tryEndpoint(r);if(!n){let s=`https://${t}/.well-known/openid-configuration`;n=await this.tryEndpoint(s)}return this.cache.set(t,n),n}async supportsOAuth(e){return await this.discover(e)!==null}static supportsPkceS256(e){return e.codeChallengeMethodsSupported?.some(t=>t.toUpperCase()==="S256")??!1}static supportsDynamicRegistration(e){return!!e.registrationEndpoint}static supportsAuthorizationCode(e){return e.responseTypesSupported?.some(t=>t.toLowerCase()==="code")??!1}static supportsEnrollment(e){return!!e.enrollmentEndpoint}static supportsSession(e){return!!e.sessionEndpoint}async tryEndpoint(e){let t;try{t=await fetch(e)}catch(n){let s=n instanceof Error?n.message:String(n);return s.includes("ENOTFOUND")||s.includes("ECONNREFUSED")?(console.error(` OAuth discovery: ${e} \u2014 host unreachable (${s})`),console.error(" If the server is behind a VPN, ensure you are connected.")):s.includes("CERT")||s.includes("SSL")||s.includes("TLS")?(console.error(` OAuth discovery: ${e} \u2014 TLS error (${s})`),console.error(" If using a custom CA certificate, set NODE_EXTRA_CA_CERTS=/path/to/ca.pem")):console.error(` OAuth discovery: ${e} \u2014 network error: ${s}`),null}if(!t.ok)return t.status===404||(t.status===403?(console.error(` OAuth discovery: ${e} \u2014 HTTP 403 Forbidden`),console.error(" Access may be blocked by a firewall, proxy, or WAF.")):t.status>=500&&(console.error(` OAuth discovery: ${e} \u2014 HTTP ${t.status} server error`),console.error(" The authorization server returned an internal error. Contact your IDP administrator."))),null;let r;try{r=await t.json()}catch{return console.error(` OAuth discovery: ${e} \u2014 response is not valid JSON`),console.error(" The endpoint may be returning HTML instead of JSON. Check IDP configuration."),null}return{issuer:g(r.issuer),authorizationEndpoint:g(r.authorization_endpoint),tokenEndpoint:g(r.token_endpoint),registrationEndpoint:g(r.registration_endpoint),revocationEndpoint:g(r.revocation_endpoint),scopesSupported:k(r.scopes_supported),responseTypesSupported:k(r.response_types_supported),grantTypesSupported:k(r.grant_types_supported),codeChallengeMethodsSupported:k(r.code_challenge_methods_supported),tokenEndpointAuthMethodsSupported:k(r.token_endpoint_auth_methods_supported),dpopSigningAlgValuesSupported:k(r.dpop_signing_alg_values_supported),enrollmentEndpoint:g(r.enrollment_endpoint),enrollmentIssuanceProtocols:k(r.enrollment_issuance_protocols),enrollmentKeyTypes:k(r.enrollment_key_types),enrollmentScopesSupported:k(r.enrollment_scopes_supported),enrollmentConsentBindingParam:g(r.enrollment_consent_binding_param),sessionEndpoint:g(r.session_endpoint),sessionEndpointAuthMethod:g(r.session_endpoint_auth_method)}}};async function no(o){try{let e=await fetch(o);return e.ok?await e.json():null}catch{return null}}function g(o){return typeof o=="string"?o:null}function k(o){return Array.isArray(o)?o.filter(e=>typeof e=="string"):null}import*as nt from"https";import{createPrivateKey as oo}from"crypto";var so="client_credentials",S=class extends Error{},$=class{constructor(e=co){this.transport=e}transport;async exchange(e,t,r={}){let n=ao(t.keyMaterial),s=new URLSearchParams({grant_type:so});r.scope&&s.set("scope",r.scope);let i=s.toString(),a;try{a=await this.transport({url:e,certPem:io(t),keyPem:n,body:i,contentType:"application/x-www-form-urlencoded"})}catch(O){throw new S(`mTLS session exchange to ${e} failed: ${O.message}`)}if(a.status<200||a.status>=300)throw new S(`Session endpoint ${e} returned HTTP ${a.status}: ${a.body.slice(0,300)}`);let c;try{c=JSON.parse(a.body)}catch{throw new S(`Session endpoint returned a non-JSON response: ${a.body.slice(0,200)}`)}if(typeof c.access_token!="string"||!c.access_token)throw new S("Session response had no access_token.");let d=typeof c.expires_in=="number"?c.expires_in:0,p=r.nowMs??Date.now();return{token:c.access_token,tokenType:typeof c.token_type=="string"&&c.token_type?c.token_type:"Bearer",expiresAt:new Date(p+d*1e3).toISOString(),scope:typeof c.scope=="string"?c.scope:""}}};function io(o){let e=o.chainPem.trim();return e?`${o.certificatePem.replace(/\s+$/,"")}
95
+ Check the 'credentialHelper' path in ~/.kanonak/config.json.`)}}async store(e,t){let r=c(e);try{await this.runHelper("store",{publisher:r,credential:t})}catch(n){throw new Error(`Credential helper '${this.helperPath}' failed to store credential for '${r}': ${se(n)}
96
+ Verify the helper binary supports the 'store' action.`)}}async remove(e){let t=c(e);try{await this.runHelper("erase",{publisher:t})}catch(r){console.warn(` Warning: Credential helper '${this.helperPath}' failed to erase credential for '${t}': ${se(r)}`)}}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: ${se(e)}`),[]}}async runHelper(e,t){try{let{stdout:r}=await Un(this.helperPath,[e],{...t&&{input:JSON.stringify(t)},timeout:Ye});return r}catch(r){throw Hn(r)?new Error(`Credential helper not found at '${this.helperPath}'.
97
+ Check the 'credentialHelper' path in ~/.kanonak/config.json.`):zn(r)?new Error(`Credential helper '${this.helperPath}' timed out after ${Ye/1e3}s on '${e}'.
98
+ The helper may be waiting for authentication to an external vault.`):r}}};function se(o){return o instanceof Error?o.message:String(o)}function Hn(o){return o instanceof Error&&"code"in o&&o.code==="ENOENT"}function zn(o){return o instanceof Error&&"killed"in o&&o.killed}var xe=qn(Jn(),".kanonak","config.json"),ie=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 t=Xn(e);if(t)return t;let n=await(await this.getBackend()).get(e);return!n||!Y(n)?null:n.accessToken??null}async getCredential(e){return(await this.getBackend()).get(e)}async store(e,t){return(await this.getBackend()).store(e,t)}async remove(e){return(await this.getBackend()).remove(e)}async list(){return(await this.getBackend()).list()}async resolveBackend(){let e=Zn();return e.credentialHelper?new U(e.credentialHelper):process.platform==="darwin"?new m:process.platform==="win32"?new y:await R()?new f:new h}};function Xn(o){let t="KANONAK_TOKEN_"+c(o).replace(/[.\-]/g,"_").toUpperCase();return process.env[t]??null}function Zn(){if(!Wn(xe))return{};try{return JSON.parse(Gn(xe,"utf-8"))}catch(o){let e=o instanceof Error?o.message:String(o);return console.warn(` Warning: Failed to parse ${xe}: ${e}
99
+ Using default credential backend. Fix the JSON syntax or delete the file.`),{}}}import{homedir as rt}from"os";import{join as x}from"path";import{mkdir as Yn,writeFile as Qe,readFile as et,rm as tt}from"fs/promises";var Ce="kanonak-device",Qn=x(rt(),".config","kanonak","device-credentials.enc"),eo=x(rt(),".kanonak","devices"),w=class{constructor(e={}){this.deps=e}deps;backend=null;backendReady=null;certDir(e){let t=c(e).replace(/[^a-zA-Z0-9._-]/g,"_");return x(this.deps.certBaseDir??eo,t)}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 get(e){let t=await(await this.getBackend()).get(e);if(!t)return null;if(typeof t.certificatePem=="string"&&typeof t.chainPem=="string")return t;let r=this.certDir(e),n,s;try{n=await et(x(r,"cert.pem"),"utf-8"),s=await et(x(r,"chain.pem"),"utf-8")}catch{return null}return{...t,certificatePem:n,chainPem:s}}async store(e,t){let{certificatePem:r,chainPem:n,...s}=t,i=this.certDir(e);await Yn(i,{recursive:!0}),await Qe(x(i,"cert.pem"),r,"utf-8"),await Qe(x(i,"chain.pem"),n,"utf-8");try{await(await this.getBackend()).store(e,s)}catch(a){throw await tt(i,{recursive:!0,force:!0}).catch(()=>{}),a}}async remove(e){await(await this.getBackend()).remove(e),await tt(this.certDir(e),{recursive:!0,force:!0})}async list(){return(await this.getBackend()).list()}async resolveBackend(){return this.deps.backend?this.deps.backend:process.platform==="darwin"?new m(Ce):process.platform==="win32"?new y(`${Ce}:`):await R()?new f(Ce):new h(Qn)}};import{homedir as to}from"os";import{join as ro}from"path";var Ae="kanonak-session",no=ro(to(),".config","kanonak","session-credentials.enc"),$=class{constructor(e={}){this.deps=e}deps;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 get(e){return(await this.getBackend()).get(e)}async store(e,t){return(await this.getBackend()).store(e,t)}async remove(e){return(await this.getBackend()).remove(e)}async list(){return(await this.getBackend()).list()}async resolveBackend(){return this.deps.backend?this.deps.backend:process.platform==="darwin"?new m(Ae):process.platform==="win32"?new y(`${Ae}:`):await R()?new f(Ae):new h(no)}};function ae(o,e=5*6e4,t=Date.now()){let r=Date.parse(o.expiresAt);return Number.isNaN(r)?!0:t>=r-e}var nt="key_thumbprint",b=class{cache=new Map;prCache=new Map;async discoverProtectedResource(e){let t=c(e);if(this.prCache.has(t))return this.prCache.get(t);let r=`https://${t}/.well-known/oauth-protected-resource`,n=await oo(r),s=n&&Array.isArray(n.authorization_servers)?n.authorization_servers.filter(a=>typeof a=="string"):[],i=s.length>0?s:null;return this.prCache.set(t,i),i}async discover(e){let t=c(e);if(this.cache.has(t))return this.cache.get(t);let r=`https://${t}/.well-known/oauth-authorization-server`,n=await this.tryEndpoint(r);if(!n){let s=`https://${t}/.well-known/openid-configuration`;n=await this.tryEndpoint(s)}return this.cache.set(t,n),n}async supportsOAuth(e){return await this.discover(e)!==null}static supportsPkceS256(e){return e.codeChallengeMethodsSupported?.some(t=>t.toUpperCase()==="S256")??!1}static supportsDynamicRegistration(e){return!!e.registrationEndpoint}static supportsAuthorizationCode(e){return e.responseTypesSupported?.some(t=>t.toLowerCase()==="code")??!1}static supportsEnrollment(e){return!!e.enrollmentEndpoint}static supportsSession(e){return!!e.sessionEndpoint}async tryEndpoint(e){let t;try{t=await fetch(e)}catch(n){let s=n instanceof Error?n.message:String(n);return s.includes("ENOTFOUND")||s.includes("ECONNREFUSED")?(console.error(` OAuth discovery: ${e} \u2014 host unreachable (${s})`),console.error(" If the server is behind a VPN, ensure you are connected.")):s.includes("CERT")||s.includes("SSL")||s.includes("TLS")?(console.error(` OAuth discovery: ${e} \u2014 TLS error (${s})`),console.error(" If using a custom CA certificate, set NODE_EXTRA_CA_CERTS=/path/to/ca.pem")):console.error(` OAuth discovery: ${e} \u2014 network error: ${s}`),null}if(!t.ok)return t.status===404||(t.status===403?(console.error(` OAuth discovery: ${e} \u2014 HTTP 403 Forbidden`),console.error(" Access may be blocked by a firewall, proxy, or WAF.")):t.status>=500&&(console.error(` OAuth discovery: ${e} \u2014 HTTP ${t.status} server error`),console.error(" The authorization server returned an internal error. Contact your IDP administrator."))),null;let r;try{r=await t.json()}catch{return console.error(` OAuth discovery: ${e} \u2014 response is not valid JSON`),console.error(" The endpoint may be returning HTML instead of JSON. Check IDP configuration."),null}return{issuer:g(r.issuer),authorizationEndpoint:g(r.authorization_endpoint),tokenEndpoint:g(r.token_endpoint),registrationEndpoint:g(r.registration_endpoint),revocationEndpoint:g(r.revocation_endpoint),scopesSupported:k(r.scopes_supported),responseTypesSupported:k(r.response_types_supported),grantTypesSupported:k(r.grant_types_supported),codeChallengeMethodsSupported:k(r.code_challenge_methods_supported),tokenEndpointAuthMethodsSupported:k(r.token_endpoint_auth_methods_supported),dpopSigningAlgValuesSupported:k(r.dpop_signing_alg_values_supported),enrollmentEndpoint:g(r.enrollment_endpoint),enrollmentIssuanceProtocols:k(r.enrollment_issuance_protocols),enrollmentKeyTypes:k(r.enrollment_key_types),enrollmentScopesSupported:k(r.enrollment_scopes_supported),enrollmentConsentBindingParam:g(r.enrollment_consent_binding_param),sessionEndpoint:g(r.session_endpoint),sessionEndpointAuthMethod:g(r.session_endpoint_auth_method)}}};async function oo(o){try{let e=await fetch(o);return e.ok?await e.json():null}catch{return null}}function g(o){return typeof o=="string"?o:null}function k(o){return Array.isArray(o)?o.filter(e=>typeof e=="string"):null}import*as ot from"https";import{createPrivateKey as so}from"crypto";var S=class extends Error{},_=class{constructor(e=co){this.transport=e}transport;async exchange(e,t,r={}){let n=ao(t.keyMaterial),s="{}",i;try{i=await this.transport({url:e,certPem:io(t),keyPem:n,body:s,contentType:"application/json"})}catch(p){throw new S(`mTLS session exchange to ${e} failed: ${p.message}`)}if(i.status<200||i.status>=300){let p=i.status===401?" \u2014 the gateway did not accept the device client certificate (invalid_client)":"";throw new S(`Session endpoint ${e} returned HTTP ${i.status}${p}: ${i.body.slice(0,300)}`)}let a;try{a=JSON.parse(i.body)}catch{throw new S(`Session endpoint returned a non-JSON response: ${i.body.slice(0,200)}`)}if(typeof a.access_token!="string"||!a.access_token)throw new S("Session response had no access_token.");let l=typeof a.expires_in=="number"?a.expires_in:0,d=r.nowMs??Date.now();return{token:a.access_token,tokenType:typeof a.token_type=="string"&&a.token_type?a.token_type:"Bearer",expiresAt:new Date(d+l*1e3).toISOString(),scope:typeof a.scope=="string"?a.scope:""}}};function io(o){let e=o.chainPem.trim();return e?`${o.certificatePem.replace(/\s+$/,"")}
100
100
  ${e}
101
- `:o.certificatePem}function ao(o){try{return oo({key:o,format:"jwk"}).export({type:"pkcs8",format:"pem"})}catch(e){throw new S(`The device key is not an exportable software private key, so it cannot present mTLS in software (a future hardware key provider would do the handshake itself): ${e.message}`)}}var co=o=>new Promise((e,t)=>{let r=new URL(o.url),n=nt.request({method:"POST",hostname:r.hostname,port:r.port||443,path:r.pathname+r.search,cert:o.certPem,key:o.keyPem,headers:{"Content-Type":o.contentType,"Content-Length":Buffer.byteLength(o.body),Accept:"application/json"},timeout:3e4},s=>{let i=[];s.on("data",a=>i.push(a)),s.on("end",()=>e({status:s.statusCode??0,body:Buffer.concat(i).toString("utf-8")}))});n.on("error",t),n.on("timeout",()=>n.destroy(new Error("mTLS request timed out"))),n.write(o.body),n.end()});var I=class extends Error{},K=class{discovery;deviceStore;sessionStore;exchange;constructor(e={}){this.discovery=e.discovery??new b,this.deviceStore=e.deviceStore??new P,this.sessionStore=e.sessionStore??new _,this.exchange=e.exchange??new $}async acquire(e,t={}){let r=l(e),n=await this.sessionEndpoint(e);if(!n)throw new I(`'${r}' does not advertise a session endpoint \u2014 it issues no scoped sessions (public registries need no credential).`);let s=await this.deviceStore.get(e);if(!s)throw new I(`No device certificate enrolled for '${r}'. Run 'kanonak device enroll ${e}' first.`);let i=await this.exchange.exchange(n,s,t),a={token:i.token,tokenType:i.tokenType,expiresAt:i.expiresAt,scope:i.scope};return await this.sessionStore.store(r,a),a}async getValidSession(e){let t=l(e),r=await this.sessionStore.get(t);return r&&!ce(r)?r:!await this.sessionEndpoint(e)||!await this.deviceStore.get(e)?null:this.acquire(e)}async clear(e){await this.sessionStore.remove(l(e))}async sessionEndpoint(e){return(await this.discovery.discover(e))?.sessionEndpoint??null}};var le=class{discovery;sessions;devices;constructor(e={}){this.discovery=e.discovery??new b,this.sessions=e.sessionManager??new K({discovery:this.discovery}),this.devices=e.deviceStore??new P}async resolve(e){let t=await this.discovery.discoverProtectedResource(e);if(!t||t.length===0)return null;let r=t.map(lo).filter(i=>i!==void 0);for(let i of r){let a=await this.sessionFor(i);if(a)return a}let s=(await this.devices.list()).map(l).filter(i=>!r.includes(i));if(s.length===0)return null;for(let i of r){let a=(await this.discovery.discover(i))?.sessionEndpoint;if(a)for(let c of s){if((await this.discovery.discover(c))?.sessionEndpoint!==a)continue;let p=await this.sessionFor(c);if(p)return p}}return null}async sessionFor(e){let t=await this.sessions.getValidSession(e);return t?{authority:e,token:t.token,expiresAt:t.expiresAt,scope:t.scope}:null}};function lo(o){try{return new URL(o).host}catch{return}}import{createHash as po,createPrivateKey as uo,generateKeyPairSync as mo,randomUUID as yo,sign as fo}from"crypto";function st(){let{publicKey:o,privateKey:e}=mo("ec",{namedCurve:"P-256"});return{publicKey:o.export({format:"jwk"}),privateKey:e.export({format:"jwk"})}}function z(o,e,t,r,n,s){let i={alg:"ES256",typ:"dpop+jwt",jwk:{kty:e.kty,crv:e.crv,x:e.x,y:e.y}},a={jti:yo(),htm:t.toUpperCase(),htu:r,iat:Math.floor(Date.now()/1e3)};return n&&(a.ath=po("sha256").update(n).digest("base64url")),s&&(a.nonce=s),ho(i,a,o)}function it(o){return!o||o.length===0?!1:o.some(e=>e.toUpperCase()==="ES256")}function ho(o,e,t){let r=ot(JSON.stringify(o)),n=ot(JSON.stringify(e)),s=`${r}.${n}`,i=uo({key:t,format:"jwk"}),c=fo("SHA256",Buffer.from(s),{key:i,dsaEncoding:"ieee-p1363"}).toString("base64url");return`${s}.${c}`}function ot(o){return Buffer.from(o,"utf-8").toString("base64url")}function at(o){let e=new Map;return async(t,r,n="GET")=>{if(!o)return C(t,{method:n});let s=await o.getCredential(r);if(!s?.accessToken)return C(t,{method:n});Z(s)&&console.warn(` Warning: Access token for '${r}' is expired. Run 'kanonak login ${r}' to re-authenticate.`);let i={};if(s.dpopKeyPair){let c=e.get(r);try{let d=z(s.dpopKeyPair.privateKey,s.dpopKeyPair.publicKey,n,t,s.accessToken,c);i.Authorization=`DPoP ${s.accessToken}`,i.DPoP=d}catch(d){let p=d instanceof Error?d.message:String(d);console.error(` Error: Failed to create DPoP proof for '${r}': ${p}
102
- The stored key pair may be corrupted. Run 'kanonak login ${r}' to re-authenticate.`),i.Authorization=`Bearer ${s.accessToken}`}}else i.Authorization=`Bearer ${s.accessToken}`;let a=await C(t,{method:n,headers:i});if(a.status===401&&s.dpopKeyPair){let c=a.headers.get("DPoP-Nonce");if(c){e.set(r,c);try{let d=z(s.dpopKeyPair.privateKey,s.dpopKeyPair.publicKey,n,t,s.accessToken,c);i.DPoP=d,a=await C(t,{method:n,headers:i})}catch{}}}return a}}import{readFileSync as go,writeFileSync as ko,existsSync as So}from"fs";import{createHash as vo}from"crypto";import ct from"js-yaml";var lt="kanonak.lock",wo=`# This file is generated by Kanonak CLI. Do not edit manually.
103
- `;function dt(o=lt){if(!So(o))return null;let e=go(o,"utf-8"),t=ct.load(e);return!t||typeof t!="object"||t.version!=="1"?null:{version:"1",lastUpdated:t.lastUpdated??new Date().toISOString(),packages:t.packages??{}}}function pt(o,e=lt){o.lastUpdated=new Date().toISOString();let t={};for(let n of Object.keys(o.packages).sort())t[n]=o.packages[n];o.packages=t;let r=ct.dump(o,{lineWidth:-1,sortKeys:!1,quotingType:'"'});ko(e,wo+r,"utf-8")}function ut(o){return`sha256:${vo("sha256").update(o).digest("hex")}`}import*as Ae from"js-yaml";import{VersionOperator as mt}from"@kanonak-protocol/types/document/models/enums";var Po="0.0.0",N=class{constructor(e,t=new j,r){this.repository=e;this.parser=t;this.objectParser=r??new F(this.parser)}repository;parser;objectParser;imports(){return new W}serializeValue(e,t){return ht(e,t)}async buildContentAddressed(e){let t=e.book.toImports(),r=await this.hashBody(e.publisher,t,e.body),n=De(r),s={type:"EphemeralPackage",publisher:e.publisher,imports:t};e.contentHashProperty&&(s[e.contentHashProperty]=r),Object.assign(s,e.header??{}),s.imports=t;let i={[n]:s,...e.body},a=this.dump(i);return{yaml:a,byteCount:ft(a),contentHash:r,packageName:n,publisher:e.publisher,resourceCount:Object.keys(e.body).length}}async buildNamed(e){let t=e.book.toImports(),r={type:e.type??"Package",publisher:e.publisher,version:e.version,imports:t},n;e.contentHashProperty&&(n=await this.hashBody(e.publisher,t,e.body),r[e.contentHashProperty]=n),Object.assign(r,e.header??{}),r.imports=t;let s={[e.name]:r,...e.body},i=this.dump(s),a={yaml:i,byteCount:ft(i),packageName:e.name,publisher:e.publisher,resourceCount:Object.keys(e.body).length};return n!==void 0&&(a.contentHash=n),a}dump(e){return Ae.dump(e,{lineWidth:-1})}async hashBody(e,t,r){let n={[yt]:{type:"EphemeralPackage",publisher:e,imports:t},...r},s=this.parser.parse(Ae.dump(n,{lineWidth:-1})),i=s.metadata.namespace_?.toString(),c=(await this.objectParser.parseKanonaks(new Be(s,this.repository))).filter(d=>d instanceof A&&d.namespace===i&&d.name!==yt);for(let d of c)d.namespace="ephemeral";return we(c)}},yt="__pkgbuilder_probe__";function ft(o){return new TextEncoder().encode(o).length}function De(o){let e="sha256:",t=o.startsWith(e)?e.length:0;return`q-${o.slice(t,t+16)}`}var W=class{byKey=new Map;aliases=new Set;ensure(e,t,r,n,s=mt.Major){let i=`${e}/${t}@${r}`,a=this.byKey.get(i);if(a)return a.alias;let c=this.uniqueAlias(n);return this.byKey.set(i,{publisher:e,package_:t,version:r,alias:c,match:s}),c}ref(e){if(!e.version||typeof e.version.major!="number")throw new Error(`Cannot serialize a reference to ${e.publisher}/${e.package_}/${e.name} without a version.`);return`${this.ensure(e.publisher,e.package_,E(e.version),e.package_)}.${e.name}`}refLatest(e,t,r,n){return`${this.ensure(e,t,Po,n??t,mt.Any)}.${r}`}toImports(){let e=new Map;for(let r of this.byKey.values()){let n=e.get(r.publisher)??[];n.push(r),e.set(r.publisher,n)}return[...e.keys()].sort().map(r=>({publisher:r,packages:e.get(r).sort((n,s)=>n.package_<s.package_?-1:1).map(n=>({package:n.package_,match:fe(n.match),version:n.version,alias:n.alias}))}))}uniqueAlias(e){let t=G(e)||"pkg",r=t,n=2;for(;this.aliases.has(r);)r=`${t}${n++}`;return this.aliases.add(r),r}};function ht(o,e){if(o!=null){if(typeof o=="string"||typeof o=="number"||typeof o=="boolean")return o;if(o instanceof M)return e.ref(o.subject);if(Array.isArray(o)){let t=o.map(r=>ht(r,e)).filter(r=>r!==void 0);return t.length>0?t:void 0}if(o instanceof D)throw new Error("Embedded values are not yet supported by PackageBuilder. Produce a literal or a reference, or compose the embedded shape into the output class.");if(bo(o))throw new Error(`Value produced a bare URI without a version (${o.publisher}/${o.package_}/${o.name}); cannot serialize it as a reference.`)}}function G(o){return o.replace(/[^A-Za-z0-9-]/g,"-").replace(/-+/g,"-").replace(/^-|-$/g,"")}function bo(o){return typeof o=="object"&&o!==null&&typeof o.publisher=="string"&&typeof o.package_=="string"&&typeof o.name=="string"}var de=class{constructor(e){this.producers=e}producers;produced=new Map;producerFor(e,t){return this.producers.find(r=>r.canProduce(e,t))}async produceCached(e,t,r,n){let s=`${t}/${r}@${E(n)}`,i=this.produced.get(s);if(i)return i;let{document:a}=await e.produce(t,r,n);return this.produced.set(s,a),a}async getHighestCompatibleVersionAsync(e,t){let r=this.producerFor(e,t.packageName);if(!r)return null;let n={operator:t.versionOperator,version:t.version},s=await r.resolveVersion(e,t.packageName,n);return s?this.produceCached(r,e,t.packageName,s):null}async getDocumentAsync(e){let t;try{t=Se(e)}catch{return null}if(t.kind!=="package"||!t.version)return null;let r=this.producerFor(t.publisher,t.package_);return r?this.produceCached(r,t.publisher,t.package_,t.version):null}async getDocumentsByNamespaceAsync(e,t){return Array.from(this.produced.values()).filter(r=>{let n=r.metadata.namespace_;return n!=null&&n.publisher===e&&n.package_===t})}async getAllDocumentsAsync(){return Array.from(this.produced.values())}async saveDocumentAsync(e,t){throw new Error("ProducerRepository is read-only: a producer is a source, not a store.")}async deleteDocumentAsync(e){throw new Error("ProducerRepository is read-only: a producer is a source, not a store.")}async clearNamespaceAsync(e,t){throw new Error("ProducerRepository is read-only: a producer is a source, not a store.")}async getAllDocumentReferencesAsync(){return[]}async getDocumentContentAsync(e){return null}async getDocumentUriAsync(e){return null}};var Te={async authorize(){return{allowed:!0}}},_e={async record(){}},J=class extends Error{constructor(t,r){let n=`${t.publisher}/${t.package_}${t.version?`@${t.version.major}.${t.version.minor}.${t.version.patch}`:""}`;super(`Not entitled to produce ${n}${r?`: ${r}`:""}`);this.address=t;this.reason=r;this.name="EntitlementDeniedError"}address;reason},pe=class{inner;ctx;policy;meter;constructor(e,t,r=Te,n=_e){this.inner=e,this.ctx=t,this.policy=r,this.meter=n}canProduce(e,t){return this.inner.canProduce(e,t)}async resolveVersion(e,t,r){return await this.assertAllowed({publisher:e,package_:t,version:r.version}),this.inner.resolveVersion(e,t,r)}async produce(e,t,r){let n={publisher:e,package_:t,version:r};await this.assertAllowed(n);let s=await this.inner.produce(e,t,r);return await this.meter.record(this.ctx,n,s),s}async assertAllowed(e){let t=await this.policy.authorize(this.ctx,e);if(!t.allowed)throw new J(e,t.reason)}};var u="kanonak.org",v="view",gt="core-kanonak",Eo={publisher:u,package_:v,name:"rootView"},Ro={publisher:u,package_:v,name:"bind"},xo={publisher:u,package_:v,name:"produces"},Co={publisher:u,package_:v,name:"projections"},Ao={publisher:u,package_:v,name:"where"},Do={publisher:u,package_:v,name:"value"},To={publisher:u,package_:v,name:"as"},ue=class{constructor(e,t=new j){this.repository=e;this.parser=t;this.objectParser=new F(this.parser),this.builder=new N(this.repository,this.parser,this.objectParser)}repository;parser;objectParser;builder;async materialize(e,t={}){let r=await this.objectParser.parseKanonaks(this.repository),n=this.resolveView(r,e),s=V(n,Ro);if(!s)throw new Error(`View ${n.namespace}/${n.name} declares no view.bind; cannot materialize.`);let i=V(n,xo);if(!i)throw new Error(`View ${n.namespace}/${n.name} is a selection view (no view.produces). In-graph materialization of selection views is not yet supported \u2014 declare a view.produces output class to reshape the result.`);let a=_o(n),c=kt(r,u,gt),d=kt(r,u,v),p=this.builder.imports(),O=p.ensure(u,gt,c,"ck"),vt=p.ensure(u,v,d,"v"),wt=p.ref(i),Pt=new Ve(this.repository,this.parser,this.objectParser),$e=new je(Pt,r),bt=this.readProjections(r,n),Et=Ko(n,Ao),Rt=this.findInstances(r,s,await this.reason(t)),Ie={},xt=new Set;for(let q of Rt){if(!await this.passesWhere($e,r,Et,q))continue;let ye={type:wt};for(let Ne of bt){let Ct=await this.evaluateValue($e,r,Ne.value,q),Oe=this.builder.serializeValue(St(Ct),p);Oe!==void 0&&(ye[p.ref(Ne.as)]=Oe)}let Ke=w(q);Ke&&(ye[`${vt}.derivedFrom`]=p.ref(Ke)),Ie[this.rowName(q,xt)]=ye}let me={};t.resolvedAt&&(me[`${O}.resolvedAt`]=t.resolvedAt),t.invocationId&&(me[`${O}.id`]=t.invocationId);let B=await this.builder.buildContentAddressed({publisher:a,book:p,body:Ie,contentHashProperty:`${O}.contentHash`,header:me});return{yaml:B.yaml,contentHash:B.contentHash,packageName:B.packageName,publisher:B.publisher,rowCount:B.resourceCount}}resolveView(e,t){let r=Y(e,t);if(!r)throw new Error(`View ${t.publisher}/${t.package_}/${t.name} not found in the catalog.`);let n=V(r,Eo);if(n){let s=Y(e,n);if(!s)throw new Error(`ViewPackage ${t.name} names rootView ${n.name}, which is not in the catalog.`);return s}return r}readProjections(e,t){let r=[];for(let n of ge(t,Co)){let s=n instanceof D?n:n instanceof M?Y(e,n.subject):void 0;if(!s)continue;let i=he(s,Do),a=V(s,To);i&&a&&r.push({value:i,as:a})}return r}async reason(e){return new ke({profile:e.reasoningProfile??"owl-rl-classification"}).reason(this.repository)}findInstances(e,t,r){let n=Io(e),s=[],i=new Set;for(let a of r.getInstancesOfClass(t)){if(i.has(a))continue;i.add(a);let c=n.get(a);c&&s.push(c)}return s.sort((a,c)=>{let d=L(w(a)),p=L(w(c));return d<p?-1:d>p?1:0}),s}async passesWhere(e,t,r,n){for(let s of r){let i=await this.evaluateValue(e,t,s,n);if(!No(i))return!1}return!0}async evaluateValue(e,t,r,n){let s=Me(r,"view-projection",{catalog:t,depth:0}),i=new Map([["input",n]]);return e.evaluate(s,i)}rowName(e,t){let r=G(e.name)||"row",n=r,s=2;for(;t.has(n);)n=`${r}-${s++}`;return t.add(n),n}};function St(o){return ve(o)?o.value:Array.isArray(o)?o.map(St):o}function _o(o){let e=w(o);if(!e)throw new Error(`Could not derive a publisher from view ${o.namespace}/${o.name}.`);return e.publisher}function kt(o,e,t){let r=$o(o,e,t);if(!r)throw new Error(`Package ${e}/${t} is not in the catalog; it must be importable to materialize a view.`);return r}function $o(o,e,t){let r;for(let n of o){if(!(n instanceof A))continue;let s=w(n);!s||s.publisher!==e||s.package_!==t||!s.version||(!r||X(s.version,r)>0)&&(r=s.version)}return r?E(r):void 0}function Io(o){let e=new Map,t=new Map;for(let r of o){if(!(r instanceof A))continue;let n=w(r);if(!n||!n.version)continue;let s=L(n),i=t.get(s);(!i||X(n.version,i)>0)&&(t.set(s,n.version),e.set(s,r))}return e}function Ko(o,e){let t=he(o,e);return t?[t]:ge(o,e).filter(r=>r instanceof D)}function No(o){return o===!0?!0:o===!1||o===void 0||o===null?!1:typeof o=="string"?o.length>0:typeof o=="number"?o!==0:ve(o)?o.value.length>0:Array.isArray(o)?o.length>0:!!o}export{ln as AmbiguousReferenceRule,ir as BooleanStatement,Pn as CANONICAL_FORM_VERSION,mr as Carrier,fn as ClassDefinitionRule,tn as ClassHierarchyCycleRule,jt as CompositeKanonakDocumentRepository,le as CredentialResolver,ae as CredentialStore,rt as DEFAULT_CONSENT_BINDING_PARAM,Qt as DefinedKanonak,P as DeviceCertificateStore,Bt as DocumentLocation,br as EdgeType,D as EmbeddedKanonak,Zr as EmbeddedKanonakTypeRule,cr as EmbeddedStatement,J as EntitlementDeniedError,pe as EntitlementProducer,Ot as FileSystemKanonakDocumentRepository,Dr as GitIgnoreFilter,Er as GraphBuilder,Gt as HttpKanonakDocumentRepository,W as ImportBook,Qr as ImportExistenceRule,Nt as InMemoryKanonakDocumentRepository,Lt as KANONAK_USER_AGENT,Zt as Kanonak,_r as KanonakDocumentPositions,F as KanonakObjectParser,gn as KanonakObjectValidator,j as KanonakParser,er as KanonakUri,Kr as KanonakUriBuilder,Or as KanonakUrlResolver,kr as KanonakVocabulary,lr as ListStatement,tr as LiteralKanonak,Jt as LocalFirstRepository,qt as LockAwareRepository,vn as LookRenderer,hn as MarkdownLinkRule,dr as MarkdownStatement,an as NamespaceImportCycleRule,Gr as NamespacePrefixRule,Pr as NodeType,sr as NumberStatement,b as OAuthDiscovery,Cr as OWL_RL_CLASSIFICATION_RULES,pn as ObjectPropertyValueValidationRule,Hr as OntologyValidationError,Fr as OntologyValidationResult,N as PackageBuilder,Yr as PackageHeaderRule,de as ProducerRepository,un as PropertyDomainRule,rn as PropertyHierarchyCycleRule,mn as PropertyKindRangeConsistencyRule,Tr as PropertyMetadata,dn as PropertyRangeReferenceRule,nn as PropertyRangeRequiredRule,qr as PropertyTypeSpecificityRule,Ht as PublisherConfigResolver,zt as PublisherIndex,xr as RDFS_RULES,ke as Reasoner,Ar as ReasoningResult,M as ReferenceKanonak,ar as ReferenceStatement,Vt as RepositoryFactory,yn as ReservedNameShadowRule,Jr as ResourceNamingRule,pr as ResourceResolver,wr as ResourceTypeClassifier,nr as ScalarStatement,I as SessionError,$ as SessionExchange,S as SessionExchangeError,K as SessionManager,_ as SessionStore,rr as Statement,or as StringStatement,on as SubClassOfReferenceRule,sn as SubPropertyOfReferenceRule,A as SubjectKanonak,Xr as SubjectKanonakTypeRequiredRule,Rr as TripleStore,ur as TypeResolver,cn as UnresolvedPredicateRule,en as UnresolvedReferenceRule,Wr as ValidationCache,zr as ValidationContext,Ur as ValidationSeverity,fa as VersionOperator,ue as ViewMaterializer,Te as allowAllPolicy,Wt as assertPackageIdentity,Yt as buildLocalFirstRepository,bn as buildOntologyModel,wn as canonicalForm,we as canonicalHash,yr as carrierOf,Xt as collectKanonakFiles,X as compareVersions,ut as computeIntegrity,De as contentAddressedName,Vr as contextTypesOf,at as createAuthenticatedFetch,z as createDPoPProof,Tt as createVersion,vr as extractMarkdownLinks,kn as findDerivation,Lr as findInstancesByType,Sr as findMalformedReferences,Ir as findMarkdownLinkAt,Nr as formatKanonakAddress,E as formatVersion,st as generateDPoPKeyPair,Mt as getGlobalCachePath,Ut as getKanonakUserAgent,Q as hasValidToken,$t as isCompatibleVersion,Z as isExpired,It as isMajorCompatible,C as kanonakFetch,dt as loadLockFile,fr as makeUriKey,_e as noopMeter,l as normalizeHost,Se as parseKanonakAddress,_t as parseVersionString,$r as parseWithPositions,Kt as pickHighestDocument,jr as propertiesInScope,Sn as resolveDisplayValue,Mr as resolvePropertyStep,G as sanitizeName,pt as saveLockFile,it as serverSupportsDPoP,ce as sessionNeedsRefresh,Ft as setKanonakUserAgent,w as subjectUri,Br as superClassChain,hr as tripleKey,L as uriKey,gr as uriTriple,At as versionOperatorFromChar,fe as versionOperatorToChar,Dt as versionsEqual};
101
+ `:o.certificatePem}function ao(o){try{return so({key:o,format:"jwk"}).export({type:"pkcs8",format:"pem"})}catch(e){throw new S(`The device key is not an exportable software private key, so it cannot present mTLS in software (a future hardware key provider would do the handshake itself): ${e.message}`)}}var co=o=>new Promise((e,t)=>{let r=new URL(o.url),n=ot.request({method:"POST",hostname:r.hostname,port:r.port||443,path:r.pathname+r.search,cert:o.certPem,key:o.keyPem,headers:{"Content-Type":o.contentType,"Content-Length":Buffer.byteLength(o.body),Accept:"application/json"},timeout:3e4},s=>{let i=[];s.on("data",a=>i.push(a)),s.on("end",()=>e({status:s.statusCode??0,body:Buffer.concat(i).toString("utf-8")}))});n.on("error",t),n.on("timeout",()=>n.destroy(new Error("mTLS request timed out"))),n.write(o.body),n.end()});var K=class extends Error{},I=class{discovery;deviceStore;sessionStore;exchange;constructor(e={}){this.discovery=e.discovery??new b,this.deviceStore=e.deviceStore??new w,this.sessionStore=e.sessionStore??new $,this.exchange=e.exchange??new _}async acquire(e){let t=c(e),r=await this.sessionEndpoint(e);if(!r)throw new K(`'${t}' does not advertise a session endpoint \u2014 it issues no scoped sessions (public registries need no credential).`);let n=await this.deviceStore.get(e);if(!n)throw new K(`No device certificate enrolled for '${t}'. Run 'kanonak device enroll ${e}' first.`);let s=await this.exchange.exchange(r,n),i={token:s.token,tokenType:s.tokenType,expiresAt:s.expiresAt,scope:s.scope};return await this.sessionStore.store(t,i),i}async getValidSession(e){let t=c(e),r=await this.sessionStore.get(t);return r&&!ae(r)?r:!await this.sessionEndpoint(e)||!await this.deviceStore.get(e)?null:this.acquire(e)}async clear(e){await this.sessionStore.remove(c(e))}async sessionEndpoint(e){return(await this.discovery.discover(e))?.sessionEndpoint??null}};var ce=class{discovery;sessions;devices;constructor(e={}){this.discovery=e.discovery??new b,this.sessions=e.sessionManager??new I({discovery:this.discovery}),this.devices=e.deviceStore??new w}async resolve(e){let t=await this.discovery.discoverProtectedResource(e);if(!t||t.length===0)return null;let r=t.map(lo).filter(i=>i!==void 0);for(let i of r){let a=await this.sessionFor(i);if(a)return a}let s=(await this.devices.list()).map(c).filter(i=>!r.includes(i));if(s.length===0)return null;for(let i of r){let a=(await this.discovery.discover(i))?.sessionEndpoint;if(a)for(let l of s){if((await this.discovery.discover(l))?.sessionEndpoint!==a)continue;let p=await this.sessionFor(l);if(p)return p}}return null}async sessionFor(e){let t=await this.sessions.getValidSession(e);return t?{authority:e,token:t.token,expiresAt:t.expiresAt,scope:t.scope}:null}};function lo(o){try{return new URL(o).host}catch{return}}import{createHash as po,createPrivateKey as uo,generateKeyPairSync as mo,randomUUID as yo,sign as fo}from"crypto";function it(){let{publicKey:o,privateKey:e}=mo("ec",{namedCurve:"P-256"});return{publicKey:o.export({format:"jwk"}),privateKey:e.export({format:"jwk"})}}function H(o,e,t,r,n,s){let i={alg:"ES256",typ:"dpop+jwt",jwk:{kty:e.kty,crv:e.crv,x:e.x,y:e.y}},a={jti:yo(),htm:t.toUpperCase(),htu:r,iat:Math.floor(Date.now()/1e3)};return n&&(a.ath=po("sha256").update(n).digest("base64url")),s&&(a.nonce=s),ho(i,a,o)}function at(o){return!o||o.length===0?!1:o.some(e=>e.toUpperCase()==="ES256")}function ho(o,e,t){let r=st(JSON.stringify(o)),n=st(JSON.stringify(e)),s=`${r}.${n}`,i=uo({key:t,format:"jwk"}),l=fo("SHA256",Buffer.from(s),{key:i,dsaEncoding:"ieee-p1363"}).toString("base64url");return`${s}.${l}`}function st(o){return Buffer.from(o,"utf-8").toString("base64url")}function ct(o){let e=new Map;return async(t,r,n="GET")=>{if(!o)return C(t,{method:n});let s=await o.getCredential(r);if(!s?.accessToken)return C(t,{method:n});Z(s)&&console.warn(` Warning: Access token for '${r}' is expired. Run 'kanonak login ${r}' to re-authenticate.`);let i={};if(s.dpopKeyPair){let l=e.get(r);try{let d=H(s.dpopKeyPair.privateKey,s.dpopKeyPair.publicKey,n,t,s.accessToken,l);i.Authorization=`DPoP ${s.accessToken}`,i.DPoP=d}catch(d){let p=d instanceof Error?d.message:String(d);console.error(` Error: Failed to create DPoP proof for '${r}': ${p}
102
+ The stored key pair may be corrupted. Run 'kanonak login ${r}' to re-authenticate.`),i.Authorization=`Bearer ${s.accessToken}`}}else i.Authorization=`Bearer ${s.accessToken}`;let a=await C(t,{method:n,headers:i});if(a.status===401&&s.dpopKeyPair){let l=a.headers.get("DPoP-Nonce");if(l){e.set(r,l);try{let d=H(s.dpopKeyPair.privateKey,s.dpopKeyPair.publicKey,n,t,s.accessToken,l);i.DPoP=d,a=await C(t,{method:n,headers:i})}catch{}}}return a}}import{readFileSync as go,writeFileSync as ko,existsSync as So}from"fs";import{createHash as vo}from"crypto";import Po from"js-yaml";var lt="kanonak.lock",wo=`# This file is generated by Kanonak CLI. Do not edit manually.
103
+ `;function dt(o=lt){return So(o)?he(go(o,"utf-8")):null}function pt(o,e=lt){o.lastUpdated=new Date().toISOString();let t={};for(let n of Object.keys(o.packages).sort())t[n]=o.packages[n];o.packages=t;let r=Po.dump(o,{lineWidth:-1,sortKeys:!1,quotingType:'"'});ko(e,wo+r,"utf-8")}function ut(o){return`sha256:${vo("sha256").update(o).digest("hex")}`}import*as De from"js-yaml";import{VersionOperator as mt}from"@kanonak-protocol/types/document/models/enums";var bo="0.0.0",N=class{constructor(e,t=new B,r){this.repository=e;this.parser=t;this.objectParser=r??new L(this.parser)}repository;parser;objectParser;imports(){return new z}serializeValue(e,t){return ht(e,t)}async buildContentAddressed(e){let t=e.book.toImports(),r=await this.hashBody(e.publisher,t,e.body),n=Te(r),s={type:"EphemeralPackage",publisher:e.publisher,imports:t};e.contentHashProperty&&(s[e.contentHashProperty]=r),Object.assign(s,e.header??{}),s.imports=t;let i={[n]:s,...e.body},a=this.dump(i);return{yaml:a,byteCount:ft(a),contentHash:r,packageName:n,publisher:e.publisher,resourceCount:Object.keys(e.body).length}}async buildNamed(e){let t=e.book.toImports(),r={type:e.type??"Package",publisher:e.publisher,version:e.version,imports:t},n;e.contentHashProperty&&(n=await this.hashBody(e.publisher,t,e.body),r[e.contentHashProperty]=n),Object.assign(r,e.header??{}),r.imports=t;let s={[e.name]:r,...e.body},i=this.dump(s),a={yaml:i,byteCount:ft(i),packageName:e.name,publisher:e.publisher,resourceCount:Object.keys(e.body).length};return n!==void 0&&(a.contentHash=n),a}dump(e){return De.dump(e,{lineWidth:-1})}async hashBody(e,t,r){let n={[yt]:{type:"EphemeralPackage",publisher:e,imports:t},...r},s=this.parser.parse(De.dump(n,{lineWidth:-1})),i=s.metadata.namespace_?.toString(),l=(await this.objectParser.parseKanonaks(new je(s,this.repository))).filter(d=>d instanceof A&&d.namespace===i&&d.name!==yt);for(let d of l)d.namespace="ephemeral";return we(l)}},yt="__pkgbuilder_probe__";function ft(o){return new TextEncoder().encode(o).length}function Te(o){let e="sha256:",t=o.startsWith(e)?e.length:0;return`q-${o.slice(t,t+16)}`}var z=class{byKey=new Map;aliases=new Set;ensure(e,t,r,n,s=mt.Major){let i=`${e}/${t}@${r}`,a=this.byKey.get(i);if(a)return a.alias;let l=this.uniqueAlias(n);return this.byKey.set(i,{publisher:e,package_:t,version:r,alias:l,match:s}),l}ref(e){if(!e.version||typeof e.version.major!="number")throw new Error(`Cannot serialize a reference to ${e.publisher}/${e.package_}/${e.name} without a version.`);return`${this.ensure(e.publisher,e.package_,E(e.version),e.package_)}.${e.name}`}refLatest(e,t,r,n){return`${this.ensure(e,t,bo,n??t,mt.Any)}.${r}`}toImports(){let e=new Map;for(let r of this.byKey.values()){let n=e.get(r.publisher)??[];n.push(r),e.set(r.publisher,n)}return[...e.keys()].sort().map(r=>({publisher:r,packages:e.get(r).sort((n,s)=>n.package_<s.package_?-1:1).map(n=>({package:n.package_,match:fe(n.match),version:n.version,alias:n.alias}))}))}uniqueAlias(e){let t=W(e)||"pkg",r=t,n=2;for(;this.aliases.has(r);)r=`${t}${n++}`;return this.aliases.add(r),r}};function ht(o,e){if(o!=null){if(typeof o=="string"||typeof o=="number"||typeof o=="boolean")return o;if(o instanceof j)return e.ref(o.subject);if(Array.isArray(o)){let t=o.map(r=>ht(r,e)).filter(r=>r!==void 0);return t.length>0?t:void 0}if(o instanceof D)throw new Error("Embedded values are not yet supported by PackageBuilder. Produce a literal or a reference, or compose the embedded shape into the output class.");if(Eo(o))throw new Error(`Value produced a bare URI without a version (${o.publisher}/${o.package_}/${o.name}); cannot serialize it as a reference.`)}}function W(o){return o.replace(/[^A-Za-z0-9-]/g,"-").replace(/-+/g,"-").replace(/^-|-$/g,"")}function Eo(o){return typeof o=="object"&&o!==null&&typeof o.publisher=="string"&&typeof o.package_=="string"&&typeof o.name=="string"}var le=class{constructor(e){this.producers=e}producers;produced=new Map;producerFor(e,t){return this.producers.find(r=>r.canProduce(e,t))}async produceCached(e,t,r,n){let s=`${t}/${r}@${E(n)}`,i=this.produced.get(s);if(i)return i;let{document:a}=await e.produce(t,r,n);return this.produced.set(s,a),a}async getHighestCompatibleVersionAsync(e,t){let r=this.producerFor(e,t.packageName);if(!r)return null;let n={operator:t.versionOperator,version:t.version},s=await r.resolveVersion(e,t.packageName,n);return s?this.produceCached(r,e,t.packageName,s):null}async getDocumentAsync(e){let t;try{t=ve(e)}catch{return null}if(t.kind!=="package"||!t.version)return null;let r=this.producerFor(t.publisher,t.package_);return r?this.produceCached(r,t.publisher,t.package_,t.version):null}async getDocumentsByNamespaceAsync(e,t){return Array.from(this.produced.values()).filter(r=>{let n=r.metadata.namespace_;return n!=null&&n.publisher===e&&n.package_===t})}async getAllDocumentsAsync(){return Array.from(this.produced.values())}async saveDocumentAsync(e,t){throw new Error("ProducerRepository is read-only: a producer is a source, not a store.")}async deleteDocumentAsync(e){throw new Error("ProducerRepository is read-only: a producer is a source, not a store.")}async clearNamespaceAsync(e,t){throw new Error("ProducerRepository is read-only: a producer is a source, not a store.")}async getAllDocumentReferencesAsync(){return[]}async getDocumentContentAsync(e){return null}async getDocumentUriAsync(e){return null}};var $e={async authorize(){return{allowed:!0}}},_e={async record(){}},G=class extends Error{constructor(t,r){let n=`${t.publisher}/${t.package_}${t.version?`@${t.version.major}.${t.version.minor}.${t.version.patch}`:""}`;super(`Not entitled to produce ${n}${r?`: ${r}`:""}`);this.address=t;this.reason=r;this.name="EntitlementDeniedError"}address;reason},de=class{inner;ctx;policy;meter;constructor(e,t,r=$e,n=_e){this.inner=e,this.ctx=t,this.policy=r,this.meter=n}canProduce(e,t){return this.inner.canProduce(e,t)}async resolveVersion(e,t,r){return await this.assertAllowed({publisher:e,package_:t,version:r.version}),this.inner.resolveVersion(e,t,r)}async produce(e,t,r){let n={publisher:e,package_:t,version:r};await this.assertAllowed(n);let s=await this.inner.produce(e,t,r);return await this.meter.record(this.ctx,n,s),s}async assertAllowed(e){let t=await this.policy.authorize(this.ctx,e);if(!t.allowed)throw new G(e,t.reason)}};var u="kanonak.org",v="view",gt="core-kanonak",Ro={publisher:u,package_:v,name:"rootView"},xo={publisher:u,package_:v,name:"bind"},Co={publisher:u,package_:v,name:"produces"},Ao={publisher:u,package_:v,name:"projections"},Do={publisher:u,package_:v,name:"where"},To={publisher:u,package_:v,name:"value"},$o={publisher:u,package_:v,name:"as"},pe=class{constructor(e,t=new B){this.repository=e;this.parser=t;this.objectParser=new L(this.parser),this.builder=new N(this.repository,this.parser,this.objectParser)}repository;parser;objectParser;builder;async materialize(e,t={}){let r=await this.objectParser.parseKanonaks(this.repository),n=this.resolveView(r,e),s=M(n,xo);if(!s)throw new Error(`View ${n.namespace}/${n.name} declares no view.bind; cannot materialize.`);let i=M(n,Co);if(!i)throw new Error(`View ${n.namespace}/${n.name} is a selection view (no view.produces). In-graph materialization of selection views is not yet supported \u2014 declare a view.produces output class to reshape the result.`);let a=_o(n),l=kt(r,u,gt),d=kt(r,u,v),p=this.builder.imports(),ue=p.ensure(u,gt,l,"ck"),vt=p.ensure(u,v,d,"v"),Pt=p.ref(i),wt=new Le(this.repository,this.parser,this.objectParser),Ke=new Me(wt,r),bt=this.readProjections(r,n),Et=No(n,Do),Rt=this.findInstances(r,s,await this.reason(t)),Ie={},xt=new Set;for(let J of Rt){if(!await this.passesWhere(Ke,r,Et,J))continue;let ye={type:Pt};for(let Oe of bt){let Ct=await this.evaluateValue(Ke,r,Oe.value,J),Be=this.builder.serializeValue(St(Ct),p);Be!==void 0&&(ye[p.ref(Oe.as)]=Be)}let Ne=P(J);Ne&&(ye[`${vt}.derivedFrom`]=p.ref(Ne)),Ie[this.rowName(J,xt)]=ye}let me={};t.resolvedAt&&(me[`${ue}.resolvedAt`]=t.resolvedAt),t.invocationId&&(me[`${ue}.id`]=t.invocationId);let O=await this.builder.buildContentAddressed({publisher:a,book:p,body:Ie,contentHashProperty:`${ue}.contentHash`,header:me});return{yaml:O.yaml,contentHash:O.contentHash,packageName:O.packageName,publisher:O.publisher,rowCount:O.resourceCount}}resolveView(e,t){let r=X(e,t);if(!r)throw new Error(`View ${t.publisher}/${t.package_}/${t.name} not found in the catalog.`);let n=M(r,Ro);if(n){let s=X(e,n);if(!s)throw new Error(`ViewPackage ${t.name} names rootView ${n.name}, which is not in the catalog.`);return s}return r}readProjections(e,t){let r=[];for(let n of ke(t,Ao)){let s=n instanceof D?n:n instanceof j?X(e,n.subject):void 0;if(!s)continue;let i=ge(s,To),a=M(s,$o);i&&a&&r.push({value:i,as:a})}return r}async reason(e){return new Se({profile:e.reasoningProfile??"owl-rl-classification"}).reason(this.repository)}findInstances(e,t,r){let n=Io(e),s=[],i=new Set;for(let a of r.getInstancesOfClass(t)){if(i.has(a))continue;i.add(a);let l=n.get(a);l&&s.push(l)}return s.sort((a,l)=>{let d=V(P(a)),p=V(P(l));return d<p?-1:d>p?1:0}),s}async passesWhere(e,t,r,n){for(let s of r){let i=await this.evaluateValue(e,t,s,n);if(!Oo(i))return!1}return!0}async evaluateValue(e,t,r,n){let s=Ve(r,"view-projection",{catalog:t,depth:0}),i=new Map([["input",n]]);return e.evaluate(s,i)}rowName(e,t){let r=W(e.name)||"row",n=r,s=2;for(;t.has(n);)n=`${r}-${s++}`;return t.add(n),n}};function St(o){return Pe(o)?o.value:Array.isArray(o)?o.map(St):o}function _o(o){let e=P(o);if(!e)throw new Error(`Could not derive a publisher from view ${o.namespace}/${o.name}.`);return e.publisher}function kt(o,e,t){let r=Ko(o,e,t);if(!r)throw new Error(`Package ${e}/${t} is not in the catalog; it must be importable to materialize a view.`);return r}function Ko(o,e,t){let r;for(let n of o){if(!(n instanceof A))continue;let s=P(n);!s||s.publisher!==e||s.package_!==t||!s.version||(!r||q(s.version,r)>0)&&(r=s.version)}return r?E(r):void 0}function Io(o){let e=new Map,t=new Map;for(let r of o){if(!(r instanceof A))continue;let n=P(r);if(!n||!n.version)continue;let s=V(n),i=t.get(s);(!i||q(n.version,i)>0)&&(t.set(s,n.version),e.set(s,r))}return e}function No(o,e){let t=ge(o,e);return t?[t]:ke(o,e).filter(r=>r instanceof D)}function Oo(o){return o===!0?!0:o===!1||o===void 0||o===null?!1:typeof o=="string"?o.length>0:typeof o=="number"?o!==0:Pe(o)?o.value.length>0:Array.isArray(o)?o.length>0:!!o}export{dn as AmbiguousReferenceRule,ar as BooleanStatement,bn as CANONICAL_FORM_VERSION,yr as Carrier,hn as ClassDefinitionRule,rn as ClassHierarchyCycleRule,jt as CompositeKanonakDocumentRepository,ce as CredentialResolver,ie as CredentialStore,nt as DEFAULT_CONSENT_BINDING_PARAM,er as DefinedKanonak,w as DeviceCertificateStore,Bt as DocumentLocation,Er as EdgeType,D as EmbeddedKanonak,Qr as EmbeddedKanonakTypeRule,lr as EmbeddedStatement,G as EntitlementDeniedError,de as EntitlementProducer,Ot as FileSystemKanonakDocumentRepository,Tr as GitIgnoreFilter,Rr as GraphBuilder,Jt as HttpKanonakDocumentRepository,z as ImportBook,en as ImportExistenceRule,Nt as InMemoryKanonakDocumentRepository,Lt as KANONAK_USER_AGENT,Qt as Kanonak,_r as KanonakDocumentPositions,L as KanonakObjectParser,kn as KanonakObjectValidator,B as KanonakParser,tr as KanonakUri,Nr as KanonakUriBuilder,Br as KanonakUrlResolver,Sr as KanonakVocabulary,dr as ListStatement,rr as LiteralKanonak,qt as LocalFirstRepository,Xt as LockAwareRepository,Pn as LookRenderer,gn as MarkdownLinkRule,pr as MarkdownStatement,cn as NamespaceImportCycleRule,Jr as NamespacePrefixRule,br as NodeType,ir as NumberStatement,b as OAuthDiscovery,Ar as OWL_RL_CLASSIFICATION_RULES,un as ObjectPropertyValueValidationRule,zr as OntologyValidationError,Ur as OntologyValidationResult,N as PackageBuilder,Yr as PackageHeaderRule,le as ProducerRepository,mn as PropertyDomainRule,nn as PropertyHierarchyCycleRule,yn as PropertyKindRangeConsistencyRule,$r as PropertyMetadata,pn as PropertyRangeReferenceRule,on as PropertyRangeRequiredRule,Xr as PropertyTypeSpecificityRule,zt as PublisherConfigResolver,Wt as PublisherIndex,Cr as RDFS_RULES,Se as Reasoner,Dr as ReasoningResult,j as ReferenceKanonak,cr as ReferenceStatement,Vt as RepositoryFactory,fn as ReservedNameShadowRule,qr as ResourceNamingRule,ur as ResourceResolver,wr as ResourceTypeClassifier,or as ScalarStatement,K as SessionError,_ as SessionExchange,S as SessionExchangeError,I as SessionManager,$ as SessionStore,nr as Statement,sr as StringStatement,sn as SubClassOfReferenceRule,an as SubPropertyOfReferenceRule,A as SubjectKanonak,Zr as SubjectKanonakTypeRequiredRule,xr as TripleStore,mr as TypeResolver,ln as UnresolvedPredicateRule,tn as UnresolvedReferenceRule,Gr as ValidationCache,Wr as ValidationContext,Hr as ValidationSeverity,ka as VersionOperator,pe as ViewMaterializer,$e as allowAllPolicy,Ht as assertHttpsUrl,Gt as assertPackageIdentity,Yt as buildLocalFirstRepository,En as buildOntologyModel,wn as canonicalForm,we as canonicalHash,fr as carrierOf,Zt as collectKanonakFiles,q as compareVersions,ut as computeIntegrity,Te as contentAddressedName,Lr as contextTypesOf,ct as createAuthenticatedFetch,H as createDPoPProof,Tt as createVersion,Pr as extractMarkdownLinks,Sn as findDerivation,Fr as findInstancesByType,vr as findMalformedReferences,Ir as findMarkdownLinkAt,Or as formatKanonakAddress,E as formatVersion,it as generateDPoPKeyPair,Mt as getGlobalCachePath,Ut as getKanonakUserAgent,Y as hasValidToken,_t as isCompatibleVersion,Z as isExpired,Kt as isMajorCompatible,C as kanonakFetch,dt as loadLockFile,hr as makeUriKey,_e as noopMeter,c as normalizeHost,ve as parseKanonakAddress,$t as parseVersionString,Kr as parseWithPositions,It as pickHighestDocument,Mr as propertiesInScope,vn as resolveDisplayValue,Vr as resolvePropertyStep,W as sanitizeName,pt as saveLockFile,at as serverSupportsDPoP,ae as sessionNeedsRefresh,Ft as setKanonakUserAgent,P as subjectUri,jr as superClassChain,gr as tripleKey,V as uriKey,kr as uriTriple,At as versionOperatorFromChar,fe as versionOperatorToChar,Dt as versionsEqual};
@@ -9,6 +9,15 @@ export interface LockFile {
9
9
  lastUpdated: string;
10
10
  packages: Record<string, LockEntry>;
11
11
  }
12
- export declare function loadLockFile(path?: string): LockFile | null;
13
- export declare function saveLockFile(lock: LockFile, path?: string): void;
14
- export declare function computeIntegrity(content: string): string;
12
+ /**
13
+ * Parse a lockfile from its YAML source. Used both for the on-disk workspace
14
+ * lock (see `LockFileIO.loadLockFile`) and for a publisher's lock fetched over
15
+ * HTTP (the authoritative served resolution source). Returns null for
16
+ * absent/unversioned content.
17
+ *
18
+ * Browser-safe by design — this module pulls only `js-yaml`, no `node:` builtins
19
+ * — so the HTTP repository (which resolves through a served lock) can be bundled
20
+ * for the browser. Filesystem I/O and sha256 integrity live in `LockFileIO.ts`,
21
+ * which is Node-only.
22
+ */
23
+ export declare function parseLockFile(raw: string): LockFile | null;
@@ -0,0 +1,4 @@
1
+ import { type LockFile } from './LockFile.js';
2
+ export declare function loadLockFile(path?: string): LockFile | null;
3
+ export declare function saveLockFile(lock: LockFile, path?: string): void;
4
+ export declare function computeIntegrity(content: string): string;
@@ -1,2 +1,3 @@
1
- export { loadLockFile, saveLockFile, computeIntegrity, } from './LockFile.js';
1
+ export { loadLockFile, saveLockFile, computeIntegrity, } from './LockFileIO.js';
2
+ export { parseLockFile } from './LockFile.js';
2
3
  export type { LockFile, LockEntry } from './LockFile.js';
@@ -16,18 +16,28 @@ export declare class HttpKanonakDocumentRepository implements IKanonakDocumentRe
16
16
  });
17
17
  getHighestCompatibleVersionAsync(publisher: string, import_: Import): Promise<KanonakDocument | null>;
18
18
  /**
19
- * Resolve against a live producer origin (`config.resolveByRedirect`): fetch
20
- * the package source and follow the latest→pinned redirect, instead of
21
- * downloading and filtering an index. An exact pin fetches the pinned URL;
22
- * any range fetches the bare-name "latest" pointer (`/{package}.kan.yml`),
23
- * which the origin 302s to the resolved pinned source. The resolved version
24
- * is read from the returned document.
19
+ * Fetch a package at the version the served lock pins. The `resolved` URL
20
+ * recorded in the lock is used verbatim (https-guarded by the fetch layer),
21
+ * and the bytes are identity-checked (namespace must match) before caching.
22
+ * Cryptographic integrity verification against the lock's hash happens Node-
23
+ * side at install time (where bytes are persisted and the local lock written);
24
+ * this resolution path stays browser-bundleable and relies on the identity
25
+ * guard plus the integrity-verified install that populated the cache.
26
+ */
27
+ private fetchPinned;
28
+ /**
29
+ * The not-in-lock fallback: a package the publisher's lock doesn't pin is a
30
+ * dynamic / producer origin (e.g. a snapshot feed). Fetch the package source
31
+ * and follow the self-describing latest→pinned redirect — no config flag, the
32
+ * HTTP 302 is the signal. An exact pin fetches the pinned URL; any range
33
+ * fetches the bare-name "latest" pointer (`/{package}.kan.yml`), which the
34
+ * origin 302s to the resolved pinned source. The resolved version is read
35
+ * from the returned document.
25
36
  *
26
37
  * A range resolves to the origin's LATEST — correct for a snapshot feed,
27
- * where `^`/`~` are inert on the time axis; range-constrained resolution
28
- * over redirect would need the range encoded in the request (future work).
38
+ * where `^`/`~` are inert on the time axis.
29
39
  */
30
- private resolveByRedirect;
40
+ private resolveByDirectFetch;
31
41
  /**
32
42
  * Fetch a URL following 301/302 redirects explicitly — so an authenticated
33
43
  * `fetchFn` re-signs each hop (and plain fetch doesn't transparently swallow
@@ -1,54 +1,68 @@
1
1
  import type { AuthenticatedFetchFn } from '../auth/index.js';
2
+ /**
3
+ * The publisher's self-describing discovery document, served at
4
+ * `.well-known/kanonak.json`. It is PURE PACKAGE BOOTSTRAP — Kanonak identity
5
+ * plus the package inventory, and nothing else:
6
+ *
7
+ * - presence of the document = "this IS a Kanonak publisher" (the gate);
8
+ * - `featured_packages` = the entry points — what `connect` installs;
9
+ * - `package_url_template` = where my raw source bytes live, if not my own domain.
10
+ *
11
+ * It carries NO authentication pointer. The auth bootstrap ("where do I
12
+ * authenticate") is the always-public RFC 9728 `oauth-protected-resource`
13
+ * document, NOT this one — because for a gated publisher this whole document is
14
+ * itself behind auth (anonymous → 401), so it structurally cannot deliver the
15
+ * authority to a client that needs it precisely in order to authenticate. The
16
+ * document's visibility equals the publisher's: public publisher → public doc;
17
+ * gated publisher → the whole doc requires auth.
18
+ *
19
+ * The wire shape and this TS interface are deliberately IDENTICAL — snake_case,
20
+ * same field names, no mapping layer. `package_url_template` MUST be https.
21
+ *
22
+ * Every field except `version` is OPTIONAL and present only when non-default: a
23
+ * public, self-hosted publisher serving at the canonical path needs just
24
+ * `version` + `featured_packages`.
25
+ */
2
26
  export interface PublisherConfig {
27
+ /** The config document's own format version (currently 1). */
3
28
  version: number;
4
- index?: string;
5
- package?: string;
6
- auth?: 'none' | 'oauth' | 'bearer';
7
29
  /**
8
- * Optional render contract: the look-stack packages each a
9
- * `publisher/package[@version]` address a consumer must include in the
10
- * render closure to STYLE this publisher's resources. ABSENT means "use the
11
- * universal kanonak.org render base" (see `resolveRenderContract`). The look
12
- * stack is discovered ambiently by the renderer, not via import edges, so
13
- * declaring it here is how a publisher makes that dependency EXPLICIT — and
14
- * how it overrides the universal base with its own look. Each entry is parsed
15
- * through `parseKanonakAddress`, not string-matched.
30
+ * Full URL template for fetching a package's raw source. Filled with
31
+ * `{publisher}`, `{package}`, `{version}` it yields a URL whose body is the
32
+ * package's source YAML and that is the ONLY contract (host, path layout,
33
+ * separators, and extension are all free). Optional; absent →
34
+ * {@link DEFAULT_PACKAGE_URL_TEMPLATE}. Present only when a publisher delegates
35
+ * source hosting (e.g. to a CDN). MUST be an `https://` template.
16
36
  */
17
- render?: string[];
37
+ package_url_template?: string;
18
38
  /**
19
- * When true, this is a LIVE producer origin: it resolves version ranges
20
- * server-side and 302-redirects a "latest" request to the pinned source,
21
- * rather than publishing an enumerable `index.txt`. A consumer then resolves
22
- * by fetching the package URL and following the redirect, instead of
23
- * downloading and filtering the index — essential for a snapshot feed whose
24
- * version history is unbounded. ABSENT/false means an ordinary static
25
- * publisher (resolve via `index.txt`), which is the unchanged default.
39
+ * The publisher's entry-point packages what `kanonak connect` installs and
40
+ * the front door into its graph (everything else is discovered from these via
41
+ * the import graph, or installed directly by name). Bare package names of
42
+ * THIS publisher; version-agnostic (the served `kanonak.lock` pins versions).
26
43
  */
27
- resolveByRedirect?: boolean;
44
+ featured_packages?: string[];
28
45
  }
29
46
  /**
30
- * The explicit, self-describing config a publisher advertises at
31
- * `.well-known/kanonak.json`. `index` and `package` are FULL URLs (publisher
32
- * domain baked in; `{package}`/`{version}` stay as the placeholders a client
33
- * substitutes). Encoding the actual values — rather than omitting them and
34
- * relying on defaults — lets any consumer (AI, the universal browser, another
35
- * publisher) see exactly where the catalog and package sources live.
36
- *
37
- * Why full URLs (not relative paths): the trust/control anchor is THIS file's
38
- * location `https://<publisher>/.well-known/kanonak.json`, which only the
39
- * publisher can serve. So whatever it declares is the publisher's authentic,
40
- * authorized choice, INCLUDING delegating index/package hosting to a different
41
- * endpoint (e.g. a CDN: `https://cdn.example.com/...`). Discovery-on-own-domain
42
- * is the proof of control; full URLs are what make delegation possible. A
43
- * misconfigured scheme/host only breaks the publisher's own resolution.
47
+ * The canonical package-source URL when a publisher serves from its own domain
48
+ * at the protocol's URL hierarchy. `package_url_template` overrides it only to
49
+ * delegate elsewhere.
50
+ */
51
+ export declare const DEFAULT_PACKAGE_URL_TEMPLATE = "https://{publisher}/{package}/{version}.kan.yml";
52
+ /**
53
+ * The config a publisher advertises at `.well-known/kanonak.json`. Minimal by
54
+ * design: a self-hosted publisher serving at the canonical path needs only
55
+ * `version`. `package_url_template` is emitted only when delegating source
56
+ * bytes, `authorization_servers` only when gated, and `featured_packages` is
57
+ * the publisher's declared entry points (wired where the publisher declares
58
+ * them; absent here means none declared yet).
44
59
  */
45
- export declare function defaultPublisherConfig(publisher: string): PublisherConfig;
60
+ export declare function defaultPublisherConfig(): PublisherConfig;
46
61
  export declare class PublisherConfigResolver {
47
62
  private readonly fetchFn?;
48
63
  private readonly cache;
49
64
  constructor(fetchFn?: AuthenticatedFetchFn | undefined);
50
65
  getConfig(publisher: string): Promise<PublisherConfig>;
51
66
  private fetchConfig;
52
- resolveIndexUrl(publisher: string, config: PublisherConfig): string;
53
67
  resolvePackageUrl(publisher: string, packageName: string, version: string, config: PublisherConfig): string;
54
68
  }
@@ -1,45 +1,33 @@
1
- import type { Import } from '@kanonak-protocol/types/document/models/types';
2
1
  import { PublisherConfigResolver, type PublisherConfig } from './PublisherConfig.js';
3
2
  import type { AuthenticatedFetchFn } from '../auth/index.js';
3
+ import { type LockFile } from '../lock/LockFile.js';
4
+ /**
5
+ * The client for a publisher's SERVED metadata: its `.well-known/kanonak.json`
6
+ * discovery config, its `kanonak.lock` (the authoritative resolution + integrity
7
+ * source), and the URLs of its raw package sources. There is no version
8
+ * enumeration here — resolution flows through the served lock, not a downloaded
9
+ * index. (The name is legacy from the deleted index.txt mechanism; a rename to
10
+ * something like `PublisherSource` is a pending cleanup.)
11
+ */
4
12
  export declare class PublisherIndex {
5
- private readonly indexCache;
6
13
  private readonly configResolver;
7
14
  private readonly fetchFn;
15
+ private readonly lockCache;
8
16
  constructor(options?: {
9
17
  configResolver?: PublisherConfigResolver;
10
18
  fetchFn?: AuthenticatedFetchFn;
11
19
  });
12
- resolveVersion(publisher: string, import_: Import): Promise<string | null>;
13
- getHighestVersion(publisher: string, packageName: string): Promise<string | null>;
14
- /**
15
- * Returns the highest published version of every package in the
16
- * publisher's index.
17
- *
18
- * Used by tooling that wants to enumerate a publisher's catalogue —
19
- * e.g. building a per-publisher reasoning corpus, or implementing a
20
- * `kanonak search <publisher>` browse command.
21
- */
22
- listLatestPackages(publisher: string): Promise<{
23
- packageName: string;
24
- version: string;
25
- }[]>;
26
- getPackageUrl(publisher: string, packageName: string, version: string): Promise<string>;
27
- /** The publisher's `.well-known` config — e.g. to check `resolveByRedirect`. */
20
+ /** The publisher's `.well-known/kanonak.json` discovery config. */
28
21
  getConfig(publisher: string): Promise<PublisherConfig>;
29
- private getPackageVersions;
22
+ /** The full URL of a package's raw source (via the publisher's url template). */
23
+ getPackageUrl(publisher: string, packageName: string, version: string): Promise<string>;
30
24
  /**
31
- * Resolve the publisher's index, de-duplicating concurrent fetches by
32
- * memoizing the in-flight promise. Evicts on failure so a transient error
33
- * doesn't poison the cache for the process lifetime.
25
+ * The publisher's served `kanonak.lock` the authoritative resolution +
26
+ * integrity source (one pinned version per package, with sha256 integrity and
27
+ * a resolved URL). Fetched once and memoized. Returns null when the publisher
28
+ * serves no lock (404 / unparseable), which means it pins no closure — callers
29
+ * then resolve such packages by direct fetch.
34
30
  */
35
- private getIndex;
36
- private fetchIndex;
37
- static parseIndex(text: string): Map<string, string[]>;
38
- private isVersionCompatible;
39
- static parseVersion(str: string): {
40
- major: number;
41
- minor: number;
42
- patch: number;
43
- } | null;
44
- private compareVersionStrings;
31
+ getLock(publisher: string): Promise<LockFile | null>;
32
+ private fetchLock;
45
33
  }
@@ -1 +1 @@
1
- import{f as e,g as r,h as n}from"../chunk-JYBKSBB5.js";import{a as o}from"../chunk-4NO7MHS7.js";import"../chunk-SC5M74NM.js";import"../chunk-NJ3AZYQD.js";import"../chunk-2ACBWC7K.js";export{n as HttpKanonakDocumentRepository,o as InMemoryKanonakDocumentRepository,e as PublisherConfigResolver,r as PublisherIndex};
1
+ import{g as e,i as r,j as n}from"../chunk-XGTUVPR3.js";import{a as o}from"../chunk-4NO7MHS7.js";import"../chunk-SC5M74NM.js";import"../chunk-NJ3AZYQD.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,i as n}from"../chunk-GMEPM2QQ.js";import{e as g,f as h,g as i,h as j}from"../chunk-JYBKSBB5.js";import{a}from"../chunk-4NO7MHS7.js";import"../chunk-SC5M74NM.js";import"../chunk-NJ3AZYQD.js";import"../chunk-2ACBWC7K.js";export{d as CompositeKanonakDocumentRepository,c as DocumentLocation,b as FileSystemKanonakDocumentRepository,j as HttpKanonakDocumentRepository,a as InMemoryKanonakDocumentRepository,k as LocalFirstRepository,l as LockAwareRepository,h as PublisherConfigResolver,i as PublisherIndex,f as RepositoryFactory,n as buildLocalFirstRepository,m 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,i as n}from"../chunk-3BNJXSVZ.js";import{f as g,g as h,i,j}from"../chunk-XGTUVPR3.js";import{a}from"../chunk-4NO7MHS7.js";import"../chunk-SC5M74NM.js";import"../chunk-NJ3AZYQD.js";import"../chunk-2ACBWC7K.js";export{d as CompositeKanonakDocumentRepository,c as DocumentLocation,b as FileSystemKanonakDocumentRepository,j as HttpKanonakDocumentRepository,a as InMemoryKanonakDocumentRepository,k as LocalFirstRepository,l as LockAwareRepository,h as PublisherConfigResolver,i as PublisherIndex,f as RepositoryFactory,n as buildLocalFirstRepository,m as collectKanonakFiles,g as defaultPublisherConfig,e as getGlobalCachePath};
@@ -22,4 +22,6 @@ export declare function assembleServerModel(params: {
22
22
  rawByNsKey: Map<string, string>;
23
23
  renderStack: RenderStackReport;
24
24
  producers?: readonly IPackageProducer[];
25
+ lockSource?: string;
26
+ configSource?: string;
25
27
  }): ServerModel;
@@ -1,7 +1,7 @@
1
- import{j as ee}from"../chunk-IHB7UVEH.js";import"../chunk-QHABFCRC.js";import{a as he,d as z,f as ye,h as J}from"../chunk-GMEPM2QQ.js";import{d as me,e as fe,f as ke,g as L,h as Y}from"../chunk-JYBKSBB5.js";import{a as ge}from"../chunk-4NO7MHS7.js";import"../chunk-PEUTCG3B.js";import{a as ve}from"../chunk-PEJALHXK.js";import"../chunk-SC5M74NM.js";import{a as O,b as T}from"../chunk-ITKOKDBG.js";import{l as X}from"../chunk-MX3DEXMV.js";import{a as E}from"../chunk-NJ3AZYQD.js";import{b as Z}from"../chunk-ZP6P7HNU.js";import"../chunk-6U26UASC.js";import"../chunk-GZPLWII7.js";import{c as be,s as Q}from"../chunk-7BHDZHJY.js";import"../chunk-FUUTGGJS.js";import{c as V,e as D,f as B,g as ue}from"../chunk-2ACBWC7K.js";import{readFileSync as Pe,writeFileSync as _e,mkdirSync as je}from"fs";import{join as $e}from"path";var Se=[{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 W(t){let e=t?.render;if(e&&e.length>0){let s=[];for(let r of e)try{let o=Z(r);o.kind==="package"?s.push({publisher:o.publisher,package_:o.package_}):o.kind==="resource"&&s.push({publisher:o.uri.publisher,package_:o.uri.package_})}catch{}if(s.length>0)return s}return Se}function F(t){return`${t.publisher}/${t.package_}`}function H(t){let e={"kanonak.org/look-styles":"pages render UNSTYLED \u2014 generated CSS stops at the :root token block","kanonak.org/look-tokens":"the :root block loses the universal design-token floor (colors, fonts, spacing)","kanonak.org/universal-look":"resources without their own look render as an empty HTML comment","kanonak.org/look":"band vocabulary (Hero, PropertyList, \u2026) is unresolvable \u2014 declared looks cannot render","kanonak.org/site":"the site vocabulary (content, navigation) is unresolvable \u2014 the base stylesheet cannot bind","kanonak.org/core-kanonak":"the Package/Publisher classes are unresolvable \u2014 package and publisher pages degrade","kanonak.org/link":"link vocabulary is unresolvable \u2014 cross-reference styling degrades"},s=[];for(let r of t)if(r.origin==="missing"){let o=F(r),i=e[o]??"whatever this package contributes to rendering is lost";s.push(`Render-stack package ${o} is MISSING (${r.reason??"unknown reason"}) \u2014 ${i}. Fix: kanonak install ${o} (as the user running the render), or restore network access to ${r.publisher}.`)}else r.resolvedButNotInCatalog&&s.push(`Render-stack package ${F(r)} resolved (${r.origin}) but is NOT in the parsed catalog \u2014 this is a closure-scoping bug; please report it.`);return s}function re(t){let{publisher:e,availablePublishers:s,catalog:r,lookRenderer:o,localNamespaces:i,rawByNsKey:f,renderStack:p,producers:b}=t,d=new Map,u=new Map,n=new Map,h=new Set;for(let k of r){if(!(k instanceof be))continue;let y=k.namespace||"";if(!i.has(y))continue;d.set(`${y}/${k.name}`,k);let w=y.split("/")[1]??"",[$,j]=w.split("@");if(!$||!j)continue;let M=ue(j);M&&(h.has(w)||(h.add(w),u.has($)||u.set($,[]),u.get($).push({verStr:j,version:M})),k.name===$&&n.set(w,k))}for(let k of u.values())k.sort((y,w)=>V(w.version,y.version));return{publisher:e,availablePublishers:s,catalog:r,lookRenderer:o,localNamespaces:i,rawByNsKey:f,bySubject:d,pkgVersions:u,pkgSelfByVer:n,renderStack:p,...b?{producers:b}:{}}}async function se(t,e={}){let s=new E,r=new ge(s),o=[],i=[];for(let c of J(t)){let l;try{l=Pe(c,"utf-8")}catch{continue}let v;try{v=s.parse(l).metadata?.namespace_}catch{continue}if(!v?.version)continue;let I=v.version;i.push({publisher:v.publisher,package_:v.package_,verStr:D(I),version:I,source:l})}i.sort((c,l)=>V(l.version,c.version));for(let c of i)await r.saveDocumentAsync(s.parse(c.source),`${c.publisher}/${c.package_}@${c.verStr}`),o.push({publisher:c.publisher,package_:c.package_,verStr:c.verStr,source:c.source});let f=[...new Set(o.map(c=>c.publisher))].sort(),p=e.publisher;if(p){if(!f.includes(p))throw new Error(`Publisher "${p}" not found in workspace. Available: ${f.join(", ")||"(none)"}`)}else if(f.length===1)p=f[0];else throw f.length===0?new Error(`No Kanonak packages found under ${t}`):new Error(`Workspace has multiple publishers (${f.join(", ")}). Pass --publisher <domain> to choose which one to serve.`);let b=new Set,d=new Map;for(let c of o)c.publisher===p&&(b.add(`${c.publisher}/${c.package_}@${c.verStr}`),d.set(`${c.package_}@${c.verStr}`,c.source));let u=z(),n=new he(u,!0,s),h={};e.httpCache&&(h.getFromCache=e.httpCache.getFromCache,h.onFetch=e.httpCache.onFetch),e.fetchFn&&(h.fetchFn=e.fetchFn);let k=e.repository??new ye(r,n,new Y(h)),y=e.log??(()=>{}),w=W(void 0),$=[],j=c=>c.map(l=>l.metadata.namespace_?.version).filter(l=>l!==void 0).sort((l,v)=>V(v,l)).map(D);if(!e.repository){y(`[render-stack] resolving ${w.length} ambient look-stack package(s); cache: ${u}`);let c=e.fetchFn?new L({fetchFn:e.fetchFn}):new L;for(let l of w){let v=F(l),I=await r.getDocumentsByNamespaceAsync(l.publisher,l.package_);if(I.length>0){let S=j(I);$.push({...l,origin:"workspace",versions:S}),y(`[render-stack] ${v} \u2014 workspace (${S.join(", ")})`);continue}let U=await n.getDocumentsByNamespaceAsync(l.publisher,l.package_);if(U.length>0){let S=j(U);$.push({...l,origin:"cache",versions:S}),y(`[render-stack] ${v} \u2014 cache (${S.join(", ")})`);continue}try{let S=await c.getHighestVersion(l.publisher,l.package_);if(!S){let m=`publisher ${l.publisher} reachable but its index does not list ${l.package_}`;$.push({...l,origin:"missing",reason:m}),y(`[render-stack] ${v} \u2014 MISSING: ${m}`);continue}let C=await c.getPackageUrl(l.publisher,l.package_,S),a=await(e.fetchFn?e.fetchFn(C,l.publisher):me(C));if(!a.ok){let m=`fetch ${C} failed: HTTP ${a.status} ${a.statusText}`;$.push({...l,origin:"missing",reason:m}),y(`[render-stack] ${v} \u2014 MISSING: ${m}`);continue}let g=await a.text();await r.saveDocumentAsync(s.parse(g),`${l.publisher}/${l.package_}@${S}`);try{let m=$e(u,l.publisher);je(m,{recursive:!0}),_e($e(m,`${l.package_}@${S}.kan.yml`),g,"utf-8"),$.push({...l,origin:"fetched",versions:[S]}),y(`[render-stack] ${v}@${S} \u2014 fetched from ${C}, installed to cache`)}catch(m){$.push({...l,origin:"fetched",versions:[S]}),y(`[render-stack] ${v}@${S} \u2014 fetched from ${C}, but cache ${u} is NOT WRITABLE (${m.message}); usable for this load only \u2014 every load will re-fetch it`)}}catch(S){let C=`fetch failed: ${S.message}`;$.push({...l,origin:"missing",reason:C}),y(`[render-stack] ${v} \u2014 MISSING: ${C}`)}}}let M=k;if(!e.repository){let c=(await r.getAllDocumentsAsync()).filter(v=>v.metadata.namespace_?.publisher===p),l=await O(c,k);for(let v of w)l.add(F(v));M=new T(k,l)}let A=await new X(s).parseKanonaks(M),oe=new ee(A),G=(c,l)=>Q(A,{publisher:c,package_:l,name:l}).length>0,N;if(e.repository){N=[];for(let c of w){let l=await k.getDocumentsByNamespaceAsync(c.publisher,c.package_);N.push(l.length>0?{...c,origin:"repository",versions:j(l)}:{...c,origin:"missing",reason:"not present in the caller-supplied repository"})}}else N=$.map(c=>c.origin==="missing"||G(c.publisher,c.package_)?c:{...c,resolvedButNotInCatalog:!0});let q=H(N);for(let c of q)y(`[render-stack] WARNING: ${c}`);return re({publisher:p,availablePublishers:f,catalog:A,lookRenderer:oe,localNamespaces:b,rawByNsKey:d,renderStack:{contractSource:"universal-default",cachePath:u,packages:N,warnings:q}})}import{existsSync as Ce,readFileSync as Fe,writeFileSync as Ne,mkdirSync as Me}from"fs";import{join as we}from"path";async function ae(t,e={}){let s=new E,r=Z(t),o=r.kind==="resource"?r.uri.publisher:r.publisher,i=e.log??(()=>{}),f=e.cacheRoot??z(),p=(a,g,m)=>we(f,a,`${g}@${m}.kan.yml`),b=new Set,d=new Set,u=new Map,n=new Y({getFromCache:(a,g,m)=>{let _=p(a,g,m),R=Ce(_)?Fe(_,"utf-8"):null;return R!==null&&b.add(`${a}/${g}`),R},onFetch:(a,g,m,_)=>{d.add(`${a}/${g}`);try{let R=we(f,a);Me(R,{recursive:!0}),Ne(p(a,g,m),_,"utf-8")}catch(R){u.set(`${a}/${g}`,R.message),i(`[render] fetched ${a}/${g}@${m} but cache ${f} is NOT WRITABLE (${R.message}); usable for this load only \u2014 every load will re-fetch it`)}},...e.fetchFn?{fetchFn:e.fetchFn}:{}}),h=new L(e.fetchFn?{fetchFn:e.fetchFn}:void 0),k;if(r.kind==="resource"){let a=r.uri.version;k=[a?{package_:r.uri.package_,version:`${a.major}.${a.minor}.${a.patch}`}:{package_:r.uri.package_}]}else if(r.kind==="package"){let a=r.version;k=[a?{package_:r.package_,version:`${a.major}.${a.minor}.${a.patch}`}:{package_:r.package_}]}else k=(await h.listLatestPackages(o)).map(g=>({package_:g.packageName}));let y=async(a,g,m)=>{try{let _=m?s.buildImport(g,"=",m,a):s.buildImport(g,"*","0.0.0",a),R=await n.getHighestCompatibleVersionAsync(a,_);return R?{doc:R}:{doc:null,error:`${a} did not resolve ${g}${m?`@${m}`:""} (not in its index, or unreachable)`}}catch(_){return{doc:null,error:_.message}}},w=[],$=[];for(let a of k){let{doc:g,error:m}=await y(o,a.package_,a.version);g?w.push(g):m&&$.push(m)}if(w.length===0)throw new Error(`Could not fetch any package for address "${t}" from publisher "${o}".`+($.length>0?` Reasons: ${$.join("; ")}`:""));let j=await new ke(e.fetchFn).getConfig(o).catch(()=>{}),M=W(j),A=j?.render&&j.render.length>0?"publisher-well-known":"universal-default",oe=a=>a.map(g=>g.metadata.namespace_?.version).filter(g=>g!==void 0).sort((g,m)=>V(m,g)).map(D);i(`[render-stack] resolving ${M.length} ambient look-stack package(s) (contract: ${A}); cache: ${f}`);let G=[],N=[];for(let a of M){let g=F(a),{doc:m,error:_}=await y(a.publisher,a.package_,void 0);if(m){G.push(m);let R=oe([m]),pe=d.has(g)?"fetched":b.has(g)?"cache":"fetched";N.push({...a,origin:pe,versions:R}),i(`[render-stack] ${g} \u2014 ${pe} (${R.join(", ")})`+(u.has(g)?" [cache write FAILED \u2014 will re-fetch next load]":""))}else N.push({...a,origin:"missing",reason:_??"unresolved"}),i(`[render-stack] ${g} \u2014 MISSING: ${_??"unresolved"}`)}let q=await O([...w,...G],n),de=new T(n,q),c=await new X(s).parseKanonaks(de),l=new ee(c),v=N.map(a=>a.origin==="missing"||Q(c,{publisher:a.publisher,package_:a.package_,name:a.package_}).length>0?a:{...a,resolvedButNotInCatalog:!0}),I=H(v);for(let a of I)i(`[render-stack] WARNING: ${a}`);let U={contractSource:A,cachePath:f,packages:v,warnings:I},S=new Set,C=new Map;for(let a of await n.getAllDocumentsAsync()){let g=a.metadata.namespace_;if(!g?.version||g.publisher!==o)continue;let m=D(g.version),_=`${g.publisher}/${g.package_}@${m}`;S.add(_);let R=await n.getDocumentContentAsync(_);R!==null&&C.set(`${g.package_}@${m}`,R)}return re({publisher:o,availablePublishers:[o],catalog:c,lookRenderer:l,localNamespaces:S,rawByNsKey:C,renderStack:U})}import{VersionOperator as ne}from"@kanonak-protocol/types/document/models/enums";function te(t){let{lookRenderer:e,publisher:s,renderStack:r,catalog:o}=t,i=e.explainStylesheet(e.publisherSubject(s)),f=[...i.tokens.entries()].map(([n,h])=>({name:n,value:h.value,source:`${h.sourceNamespace}/${h.sourceName}`,level:h.level})),p=i.baseStylesheet,b={present:p.css!==void 0,...p.sourceNamespace!==void 0?{source:p.sourceNamespace}:{},...p.scope!==void 0?{scope:p.scope}:{},...p.css!==void 0?{bytes:p.css.length}:{},...p.problem!==void 0?{problem:p.problem}:{},candidates:p.candidates},d=new Map;for(let n of o){let h=n.namespace;h&&d.set(h,(d.get(h)??0)+1)}let u=[...d.entries()].map(([n,h])=>({namespace:n,resources:h})).sort((n,h)=>n.namespace.localeCompare(h.namespace));return{publisher:s,renderStack:{contractSource:r.contractSource,cachePath:r.cachePath,packages:r.packages.map(n=>({package_:F(n),origin:n.origin,...n.versions!==void 0?{versions:n.versions}:{},...n.reason!==void 0?{reason:n.reason}:{},...n.resolvedButNotInCatalog!==void 0?{resolvedButNotInCatalog:n.resolvedButNotInCatalog}:{}}))},stylesheet:{tokens:f,baseStylesheet:b,...i.look?{look:{sourceClass:`${i.look.sourceClass.publisher}/${i.look.sourceClass.package_}/${i.look.sourceClass.name}`}}:{}},catalog:u,warnings:[...r.warnings,...i.warnings.filter(n=>!r.warnings.includes(n))]}}function Ie(t){return t.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#39;")}function ie(t){let e=Ie,s=t.warnings.length===0,r=t.warnings.length===0?'<p class="ok">\u2713 No problems detected \u2014 the render stack is fully resolved and pages should be styled.</p>':t.warnings.map(d=>`<div class="warn">\u26A0 ${e(d)}</div>`).join(`
2
- `),o=t.renderStack.packages.map(d=>{let u=d.origin!=="missing"&&!d.resolvedButNotInCatalog,n=d.origin==="missing"?'<span class="bad">MISSING</span>':d.resolvedButNotInCatalog?`<span class="bad">${e(d.origin)} (not in catalog)</span>`:`<span class="good">${e(d.origin)}</span>`,h=d.reason?e(d.reason):e((d.versions??[]).join(", "));return`<tr class="${u?"":"row-bad"}"><td><code>${e(d.package_)}</code></td><td>${n}</td><td>${h}</td></tr>`}).join(`
3
- `),i=t.stylesheet.baseStylesheet,f=i.present?`<p><span class="good">\u2713 present</span> \u2014 <code>${e(i.source??"")}</code> (${i.bytes} bytes, ${e(i.scope??"")})</p>`:`<p><span class="bad">\u2717 MISSING</span>${i.problem?` \u2014 ${e(i.problem)}`:""}${i.candidates.length>0?`<br>candidates considered: ${i.candidates.map(d=>`<code>${e(d)}</code>`).join(", ")}`:""}</p><p>Without the base stylesheet, generated CSS stops at the <code>:root</code> token block and pages appear unstyled.</p>`,p=t.stylesheet.tokens.map(d=>`<tr><td><code>--kan-${e(d.name)}</code></td><td><code>${e(d.value)}</code></td><td><code>${e(d.source)}</code></td><td>${e(d.level)}</td></tr>`).join(`
4
- `),b=t.catalog.map(d=>`<tr><td><code>${e(d.namespace)}</code></td><td>${d.resources}</td></tr>`).join(`
1
+ import{j as te}from"../chunk-IHB7UVEH.js";import"../chunk-QHABFCRC.js";import{a as fe,d as Q,f as be,h as Z}from"../chunk-3BNJXSVZ.js";import{e as ke,f as ye,i as G,j as X}from"../chunk-XGTUVPR3.js";import{a as me}from"../chunk-4NO7MHS7.js";import"../chunk-PEUTCG3B.js";import{a as $e}from"../chunk-PEJALHXK.js";import"../chunk-SC5M74NM.js";import{a as q,b as z}from"../chunk-ITKOKDBG.js";import{l as re}from"../chunk-MX3DEXMV.js";import{a as O}from"../chunk-NJ3AZYQD.js";import{b as Se}from"../chunk-ZP6P7HNU.js";import"../chunk-6U26UASC.js";import"../chunk-GZPLWII7.js";import{c as ve,s as ee}from"../chunk-7BHDZHJY.js";import"../chunk-FUUTGGJS.js";import{c as B,e as D,f as H,g as he}from"../chunk-2ACBWC7K.js";import{readFileSync as ie,writeFileSync as _e,mkdirSync as je}from"fs";import{join as ne}from"path";var we=[{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 U(t){return we}function F(t){return`${t.publisher}/${t.package_}`}function Y(t){let e={"kanonak.org/look-styles":"pages render UNSTYLED \u2014 generated CSS stops at the :root token block","kanonak.org/look-tokens":"the :root block loses the universal design-token floor (colors, fonts, spacing)","kanonak.org/universal-look":"resources without their own look render as an empty HTML comment","kanonak.org/look":"band vocabulary (Hero, PropertyList, \u2026) is unresolvable \u2014 declared looks cannot render","kanonak.org/site":"the site vocabulary (content, navigation) is unresolvable \u2014 the base stylesheet cannot bind","kanonak.org/core-kanonak":"the Package/Publisher classes are unresolvable \u2014 package and publisher pages degrade","kanonak.org/link":"link vocabulary is unresolvable \u2014 cross-reference styling degrades"},a=[];for(let r of t)if(r.origin==="missing"){let i=F(r),n=e[i]??"whatever this package contributes to rendering is lost";a.push(`Render-stack package ${i} is MISSING (${r.reason??"unknown reason"}) \u2014 ${n}. Fix: kanonak install ${i} (as the user running the render), or restore network access to ${r.publisher}.`)}else r.resolvedButNotInCatalog&&a.push(`Render-stack package ${F(r)} resolved (${r.origin}) but is NOT in the parsed catalog \u2014 this is a closure-scoping bug; please report it.`);return a}function oe(t){let{publisher:e,availablePublishers:a,catalog:r,lookRenderer:i,localNamespaces:n,rawByNsKey:m,renderStack:u,producers:k,lockSource:p,configSource:h}=t,o=new Map,g=new Map,w=new Map,v=new Set;for(let $ of r){if(!($ instanceof ve))continue;let R=$.namespace||"";if(!n.has(R))continue;o.set(`${R}/${$.name}`,$);let _=R.split("/")[1]??"",[j,M]=_.split("@");if(!j||!M)continue;let K=he(M);K&&(v.has(_)||(v.add(_),g.has(j)||g.set(j,[]),g.get(j).push({verStr:M,version:K})),$.name===j&&w.set(_,$))}for(let $ of g.values())$.sort((R,_)=>B(_.version,R.version));return{publisher:e,availablePublishers:a,catalog:r,lookRenderer:i,localNamespaces:n,rawByNsKey:m,bySubject:o,pkgVersions:g,pkgSelfByVer:w,renderStack:u,...k?{producers:k}:{},...p?{lockSource:p}:{},...h?{configSource:h}:{}}}async function ce(t,e={}){let a=new O,r=new me(a),i=[],n=[];for(let c of Z(t)){let d;try{d=ie(c,"utf-8")}catch{continue}let y;try{y=a.parse(d).metadata?.namespace_}catch{continue}if(!y?.version)continue;let I=y.version;n.push({publisher:y.publisher,package_:y.package_,verStr:D(I),version:I,source:d})}n.sort((c,d)=>B(d.version,c.version));for(let c of n)await r.saveDocumentAsync(a.parse(c.source),`${c.publisher}/${c.package_}@${c.verStr}`),i.push({publisher:c.publisher,package_:c.package_,verStr:c.verStr,source:c.source});let m=[...new Set(i.map(c=>c.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 ${t}`):new Error(`Workspace has multiple publishers (${m.join(", ")}). Pass --publisher <domain> to choose which one to serve.`);let k=new Set,p=new Map;for(let c of i)c.publisher===u&&(k.add(`${c.publisher}/${c.package_}@${c.verStr}`),p.set(`${c.package_}@${c.verStr}`,c.source));let h=Q(),o=new fe(h,!0,a),g={};e.httpCache&&(g.getFromCache=e.httpCache.getFromCache,g.onFetch=e.httpCache.onFetch),e.fetchFn&&(g.fetchFn=e.fetchFn);let w=e.repository??new be(r,o,new X(g)),v=e.log??(()=>{}),$=U(void 0),R=[],_=c=>c.map(d=>d.metadata.namespace_?.version).filter(d=>d!==void 0).sort((d,y)=>B(y,d)).map(D);if(!e.repository){v(`[render-stack] resolving ${$.length} ambient look-stack package(s); cache: ${h}`);let c=e.fetchFn?new G({fetchFn:e.fetchFn}):new G;for(let d of $){let y=F(d),I=await r.getDocumentsByNamespaceAsync(d.publisher,d.package_);if(I.length>0){let l=_(I);R.push({...d,origin:"workspace",versions:l}),v(`[render-stack] ${y} \u2014 workspace (${l.join(", ")})`);continue}let s=await o.getDocumentsByNamespaceAsync(d.publisher,d.package_);if(s.length>0){let l=_(s);R.push({...d,origin:"cache",versions:l}),v(`[render-stack] ${y} \u2014 cache (${l.join(", ")})`);continue}try{let f=(await c.getLock(d.publisher))?.packages[`${d.publisher}/${d.package_}`];if(!f){let C=`publisher ${d.publisher} reachable but its lock does not pin ${d.package_}`;R.push({...d,origin:"missing",reason:C}),v(`[render-stack] ${y} \u2014 MISSING: ${C}`);continue}let S=f.version,b=f.resolved,E=await(e.fetchFn?e.fetchFn(b,d.publisher):ke(b));if(!E.ok){let C=`fetch ${b} failed: HTTP ${E.status} ${E.statusText}`;R.push({...d,origin:"missing",reason:C}),v(`[render-stack] ${y} \u2014 MISSING: ${C}`);continue}let ge=await E.text();await r.saveDocumentAsync(a.parse(ge),`${d.publisher}/${d.package_}@${S}`);try{let C=ne(h,d.publisher);je(C,{recursive:!0}),_e(ne(C,`${d.package_}@${S}.kan.yml`),ge,"utf-8"),R.push({...d,origin:"fetched",versions:[S]}),v(`[render-stack] ${y}@${S} \u2014 fetched from ${b}, installed to cache`)}catch(C){R.push({...d,origin:"fetched",versions:[S]}),v(`[render-stack] ${y}@${S} \u2014 fetched from ${b}, but cache ${h} is NOT WRITABLE (${C.message}); usable for this load only \u2014 every load will re-fetch it`)}}catch(l){let f=`fetch failed: ${l.message}`;R.push({...d,origin:"missing",reason:f}),v(`[render-stack] ${y} \u2014 MISSING: ${f}`)}}}let j=w;if(!e.repository){let c=(await r.getAllDocumentsAsync()).filter(y=>y.metadata.namespace_?.publisher===u),d=await q(c,w);for(let y of $)d.add(F(y));j=new z(w,d)}let M=await new re(a).parseKanonaks(j),K=new te(M),T=(c,d)=>ee(M,{publisher:c,package_:d,name:d}).length>0,V;if(e.repository){V=[];for(let c of $){let d=await w.getDocumentsByNamespaceAsync(c.publisher,c.package_);V.push(d.length>0?{...c,origin:"repository",versions:_(d)}:{...c,origin:"missing",reason:"not present in the caller-supplied repository"})}}else V=R.map(c=>c.origin==="missing"||T(c.publisher,c.package_)?c:{...c,resolvedButNotInCatalog:!0});let J=Y(V);for(let c of J)v(`[render-stack] WARNING: ${c}`);let W={contractSource:"universal-default",cachePath:h,packages:V,warnings:J},L;try{L=ie(ne(t,"kanonak.lock"),"utf-8")}catch{L=void 0}let A;try{A=ie(ne(t,".well-known","kanonak.json"),"utf-8")}catch{A=void 0}return oe({publisher:u,availablePublishers:m,catalog:M,lookRenderer:K,localNamespaces:k,rawByNsKey:p,renderStack:W,...L?{lockSource:L}:{},...A?{configSource:A}:{}})}import{existsSync as Ce,readFileSync as Fe,writeFileSync as Me,mkdirSync as Ne}from"fs";import{join as Re}from"path";async function le(t,e={}){let a=new O,r=Se(t),i=r.kind==="resource"?r.uri.publisher:r.publisher,n=e.log??(()=>{}),m=e.cacheRoot??Q(),u=(s,l,f)=>Re(m,s,`${l}@${f}.kan.yml`),k=new Set,p=new Set,h=new Map,o=new X({getFromCache:(s,l,f)=>{let S=u(s,l,f),b=Ce(S)?Fe(S,"utf-8"):null;return b!==null&&k.add(`${s}/${l}`),b},onFetch:(s,l,f,S)=>{p.add(`${s}/${l}`);try{let b=Re(m,s);Ne(b,{recursive:!0}),Me(u(s,l,f),S,"utf-8")}catch(b){h.set(`${s}/${l}`,b.message),n(`[render] fetched ${s}/${l}@${f} but cache ${m} is NOT WRITABLE (${b.message}); usable for this load only \u2014 every load will re-fetch it`)}},...e.fetchFn?{fetchFn:e.fetchFn}:{}}),g=new G(e.fetchFn?{fetchFn:e.fetchFn}:void 0),w;if(r.kind==="resource"){let s=r.uri.version;w=[s?{package_:r.uri.package_,version:`${s.major}.${s.minor}.${s.patch}`}:{package_:r.uri.package_}]}else if(r.kind==="package"){let s=r.version;w=[s?{package_:r.package_,version:`${s.major}.${s.minor}.${s.patch}`}:{package_:r.package_}]}else w=((await g.getConfig(i)).featured_packages??[]).map(l=>({package_:l}));let v=async(s,l,f)=>{try{let S=f?a.buildImport(l,"=",f,s):a.buildImport(l,"*","0.0.0",s),b=await o.getHighestCompatibleVersionAsync(s,S);return b?{doc:b}:{doc:null,error:`${s} did not resolve ${l}${f?`@${f}`:""} (not in its index, or unreachable)`}}catch(S){return{doc:null,error:S.message}}},$=[],R=[];for(let s of w){let{doc:l,error:f}=await v(i,s.package_,s.version);l?$.push(l):f&&R.push(f)}if($.length===0)throw new Error(`Could not fetch any package for address "${t}" from publisher "${i}".`+(R.length>0?` Reasons: ${R.join("; ")}`:""));let _=U(),j="universal-default",M=s=>s.map(l=>l.metadata.namespace_?.version).filter(l=>l!==void 0).sort((l,f)=>B(f,l)).map(D);n(`[render-stack] resolving ${_.length} ambient look-stack package(s) (contract: ${j}); cache: ${m}`);let K=[],T=[];for(let s of _){let l=F(s),{doc:f,error:S}=await v(s.publisher,s.package_,void 0);if(f){K.push(f);let b=M([f]),E=p.has(l)?"fetched":k.has(l)?"cache":"fetched";T.push({...s,origin:E,versions:b}),n(`[render-stack] ${l} \u2014 ${E} (${b.join(", ")})`+(h.has(l)?" [cache write FAILED \u2014 will re-fetch next load]":""))}else T.push({...s,origin:"missing",reason:S??"unresolved"}),n(`[render-stack] ${l} \u2014 MISSING: ${S??"unresolved"}`)}let V=await q([...$,...K],o),J=new z(o,V),W=await new re(a).parseKanonaks(J),L=new te(W),A=T.map(s=>s.origin==="missing"||ee(W,{publisher:s.publisher,package_:s.package_,name:s.package_}).length>0?s:{...s,resolvedButNotInCatalog:!0}),c=Y(A);for(let s of c)n(`[render-stack] WARNING: ${s}`);let d={contractSource:j,cachePath:m,packages:A,warnings:c},y=new Set,I=new Map;for(let s of await o.getAllDocumentsAsync()){let l=s.metadata.namespace_;if(!l?.version||l.publisher!==i)continue;let f=D(l.version),S=`${l.publisher}/${l.package_}@${f}`;y.add(S);let b=await o.getDocumentContentAsync(S);b!==null&&I.set(`${l.package_}@${f}`,b)}return oe({publisher:i,availablePublishers:[i],catalog:W,lookRenderer:L,localNamespaces:y,rawByNsKey:I,renderStack:d})}import{VersionOperator as ae}from"@kanonak-protocol/types/document/models/enums";function se(t){let{lookRenderer:e,publisher:a,renderStack:r,catalog:i}=t,n=e.explainStylesheet(e.publisherSubject(a)),m=[...n.tokens.entries()].map(([o,g])=>({name:o,value:g.value,source:`${g.sourceNamespace}/${g.sourceName}`,level:g.level})),u=n.baseStylesheet,k={present:u.css!==void 0,...u.sourceNamespace!==void 0?{source:u.sourceNamespace}:{},...u.scope!==void 0?{scope:u.scope}:{},...u.css!==void 0?{bytes:u.css.length}:{},...u.problem!==void 0?{problem:u.problem}:{},candidates:u.candidates},p=new Map;for(let o of i){let g=o.namespace;g&&p.set(g,(p.get(g)??0)+1)}let h=[...p.entries()].map(([o,g])=>({namespace:o,resources:g})).sort((o,g)=>o.namespace.localeCompare(g.namespace));return{publisher:a,renderStack:{contractSource:r.contractSource,cachePath:r.cachePath,packages:r.packages.map(o=>({package_:F(o),origin:o.origin,...o.versions!==void 0?{versions:o.versions}:{},...o.reason!==void 0?{reason:o.reason}:{},...o.resolvedButNotInCatalog!==void 0?{resolvedButNotInCatalog:o.resolvedButNotInCatalog}:{}}))},stylesheet:{tokens:m,baseStylesheet:k,...n.look?{look:{sourceClass:`${n.look.sourceClass.publisher}/${n.look.sourceClass.package_}/${n.look.sourceClass.name}`}}:{}},catalog:h,warnings:[...r.warnings,...n.warnings.filter(o=>!r.warnings.includes(o))]}}function Ie(t){return t.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#39;")}function de(t){let e=Ie,a=t.warnings.length===0,r=t.warnings.length===0?'<p class="ok">\u2713 No problems detected \u2014 the render stack is fully resolved and pages should be styled.</p>':t.warnings.map(p=>`<div class="warn">\u26A0 ${e(p)}</div>`).join(`
2
+ `),i=t.renderStack.packages.map(p=>{let h=p.origin!=="missing"&&!p.resolvedButNotInCatalog,o=p.origin==="missing"?'<span class="bad">MISSING</span>':p.resolvedButNotInCatalog?`<span class="bad">${e(p.origin)} (not in catalog)</span>`:`<span class="good">${e(p.origin)}</span>`,g=p.reason?e(p.reason):e((p.versions??[]).join(", "));return`<tr class="${h?"":"row-bad"}"><td><code>${e(p.package_)}</code></td><td>${o}</td><td>${g}</td></tr>`}).join(`
3
+ `),n=t.stylesheet.baseStylesheet,m=n.present?`<p><span class="good">\u2713 present</span> \u2014 <code>${e(n.source??"")}</code> (${n.bytes} bytes, ${e(n.scope??"")})</p>`:`<p><span class="bad">\u2717 MISSING</span>${n.problem?` \u2014 ${e(n.problem)}`:""}${n.candidates.length>0?`<br>candidates considered: ${n.candidates.map(p=>`<code>${e(p)}</code>`).join(", ")}`:""}</p><p>Without the base stylesheet, generated CSS stops at the <code>:root</code> token block and pages appear unstyled.</p>`,u=t.stylesheet.tokens.map(p=>`<tr><td><code>--kan-${e(p.name)}</code></td><td><code>${e(p.value)}</code></td><td><code>${e(p.source)}</code></td><td>${e(p.level)}</td></tr>`).join(`
4
+ `),k=t.catalog.map(p=>`<tr><td><code>${e(p.namespace)}</code></td><td>${p.resources}</td></tr>`).join(`
5
5
  `);return`<!doctype html>
6
6
  <html lang="en">
7
7
  <head>
@@ -21,12 +21,12 @@ import{j as ee}from"../chunk-IHB7UVEH.js";import"../chunk-QHABFCRC.js";import{a
21
21
  .row-bad td { background: #fff5f5; }
22
22
  .meta { color: #666; font-size: .85rem; }
23
23
  .status-banner { font-size: 1.1rem; padding: .5rem 1rem; border-radius: 6px; display: inline-block; margin-bottom: 1rem;
24
- background: ${s?"#ecfdf3":"#fef2f2"}; border: 1px solid ${s?"#0a7d33":"#b91c1c"}; }
24
+ background: ${a?"#ecfdf3":"#fef2f2"}; border: 1px solid ${a?"#0a7d33":"#b91c1c"}; }
25
25
  </style>
26
26
  </head>
27
27
  <body>
28
28
  <h1>Render diagnostics \u2014 ${e(t.publisher)}</h1>
29
- <p class="status-banner">${s?"\u2713 Healthy":`\u2717 ${t.warnings.length} problem(s) found`}</p>
29
+ <p class="status-banner">${a?"\u2713 Healthy":`\u2717 ${t.warnings.length} problem(s) found`}</p>
30
30
  <p class="meta">Machine-readable version: <a href="/.well-known/kanonak-render.json"><code>/.well-known/kanonak-render.json</code></a></p>
31
31
 
32
32
  <h2>Problems</h2>
@@ -37,18 +37,18 @@ ${r}
37
37
  Contract: <code>${e(t.renderStack.contractSource)}</code> \xB7 Package cache: <code>${e(t.renderStack.cachePath)}</code></p>
38
38
  <table>
39
39
  <tr><th>Package</th><th>Origin</th><th>Versions / reason</th></tr>
40
- ${o}
40
+ ${i}
41
41
  </table>
42
42
 
43
43
  <h2>Base stylesheet</h2>
44
44
  <p class="meta">Everything after the <code>:root</code> block in generated CSS comes from a <code>look-styles/base-stylesheet</code> asset in the render catalog.</p>
45
- ${f}
45
+ ${m}
46
46
 
47
47
  <h2>Design tokens (:root)</h2>
48
48
  <p class="meta">Resolved for the publisher landing page. Each token shows which resource in the cascade supplied it.</p>
49
49
  ${t.stylesheet.tokens.length===0?'<p><span class="bad">\u2717 No tokens resolved</span></p>':`<table>
50
50
  <tr><th>Token</th><th>Value</th><th>Declared by</th><th>Cascade level</th></tr>
51
- ${p}
51
+ ${u}
52
52
  </table>`}
53
53
 
54
54
  <h2>Look (page body)</h2>
@@ -58,9 +58,7 @@ ${t.stylesheet.look?`<p><span class="good">\u2713</span> Bands resolve from <cod
58
58
  <p class="meta">Everything the renderer can see for this publisher \u2014 the served packages, their import closure, and the ambient render stack.</p>
59
59
  <table>
60
60
  <tr><th>Package version</th><th>Resources</th></tr>
61
- ${b}
61
+ ${k}
62
62
  </table>
63
63
  </body>
64
- </html>`}var x={".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"},P=(t,e,s,r)=>({status:t,headers:{"Content-Type":e,...r||{}},body:s}),K=t=>P(404,x[".html"],`<!doctype html><meta charset=utf-8><title>404</title><h1>404</h1><p>Not found: ${t}</p>`),De=t=>({status:301,headers:{Location:t},body:""}),Ke=t=>({status:302,headers:{Location:t},body:""});function Ve(t){switch(t.kind){case"exact":return{operator:ne.Exact,version:B(t.major,t.minor,t.patch)};case"minor-pin":return{operator:ne.Compatible,version:B(t.major,t.minor,0)};case"major-pin":return{operator:ne.Major,version:B(t.major,0,0)};default:return{operator:ne.Any,version:B(0,0,0)}}}async function Ae(t,e,s,r){if(!r)return null;let o=t.producers?.find(b=>b.canProduce(t.publisher,e));if(!o)return null;let i=await o.resolveVersion(t.publisher,e,Ve(s));if(!i)return null;let f=D(i);if(s.kind!=="exact")return Ke(`/${e}/${f}.kan.yml`);let{source:p}=await o.produce(t.publisher,e,i);return P(200,x[".kan.yml"],p)}function Re(t,e,s){let r=t.pkgVersions.get(e);if(!r||r.length===0)return null;switch(s.kind){case"any":return r[0].verStr;case"major-pin":return r.find(o=>o.version.major===s.major)?.verStr??null;case"minor-pin":return r.find(o=>o.version.major===s.major&&o.version.minor===s.minor)?.verStr??null;case"exact":return r.find(o=>o.version.major===s.major&&o.version.minor===s.minor&&o.version.patch===s.patch)?.verStr??null;default:return null}}async function ce(t,e,s=""){let{lookRenderer:r,publisher:o}=t;if(e==="/.well-known/kanonak.json"){let n=fe(o);return t.producers&&t.producers.length>0&&(n.resolveByRedirect=!0),P(200,x[".json"],JSON.stringify(n,null,2))}if(e==="/index.txt"){let n=[...t.localNamespaces].map(h=>h.split("/")[1].replace("@","/")).sort();return P(200,x[".txt"],n.join(`
65
- `)+`
66
- `)}if(e==="/.well-known/kanonak-render.json")return P(200,x[".json"],JSON.stringify(te(t),null,2));if(e==="/.well-known/kanonak-render")return P(200,x[".html"],ie(te(t)));if(e==="/"||e==="/index.html"||e==="/index.css"){let n=r.publisherSubject(o);return e==="/index.css"?P(200,x[".css"],r.renderStylesheet(n)):P(200,x[".html"],await r.renderDocument(n,{rootIndex:!0}))}let i=".html",f=!1,p=e;for(let n of[".kan.yml",".css",".svg",".md",".html"])if(e.endsWith(n)){i=n,f=!0,p=e.slice(0,-n.length);break}let b=!f&&/application\/yaml|text\/yaml/i.test(s),d=p.endsWith("/");d&&p!=="/"&&(p=p.slice(0,-1));let u=ve.parse(p,o);if(!u)return K(e);if(u.kind==="package"){let n=Re(t,u.package_,u.versionSpec);if(!n)return await Ae(t,u.package_,u.versionSpec,i===".kan.yml"||b)??K(e);if(i===".kan.yml"||b){let y=t.rawByNsKey.get(`${u.package_}@${n}`);return y!==void 0?P(200,x[".kan.yml"],y):K(e)}let h=t.pkgSelfByVer.get(`${u.package_}@${n}`);if(!h)return K(e);if(i===".css")return P(200,x[".css"],r.renderStylesheet(h));if(!d)return De(p+"/");let k=u.versionSpec.kind==="any";if(k&&!r.hasDeclaredView(h)){let y=(t.pkgVersions.get(u.package_)||[]).map(w=>w.verStr);return P(200,x[".html"],r.renderPackageVersionList(u.package_,y,h))}return P(200,x[".html"],await r.renderDocument(h,k?{bareOverview:!0}:void 0))}if(u.kind==="resource"){let n=Re(t,u.package_,u.versionSpec);if(!n)return K(e);let h=t.bySubject.get(`${o}/${u.package_}@${n}/${u.name}`);if(!h)return K(e);switch(i){case".css":return P(200,x[".css"],r.renderStylesheet(h));case".svg":return P(200,x[".svg"],await r.renderSvg(h));case".md":{let k=r.renderRawMarkdown(h);return k===void 0?K(e):P(200,x[".md"],k)}default:return P(200,x[".html"],await r.renderDocument(h))}}return K(e)}import{readFileSync as Ee}from"fs";var le=class{constructor(e={}){this.options=e}options;models=new Map;workspaceIndex;clearCache(){this.models.clear(),this.workspaceIndex=void 0}getWorkspaceIndex(){if(this.workspaceIndex)return this.workspaceIndex;let e=new Set,s=new Set;if(this.options.root!==void 0){let r=new E;for(let o of J(this.options.root))try{let i=r.parse(Ee(o,"utf-8")).metadata?.namespace_;if(!i?.version)continue;let f=i.version;e.add(`${i.publisher}/${i.package_}@${f.major}.${f.minor}.${f.patch}`),s.add(`${i.publisher}/${i.package_}`)}catch{}}return this.workspaceIndex={exact:e,pkgs:s},this.workspaceIndex}async modelFor(e,s,r){let o=this.getWorkspaceIndex(),i={...this.options.fetchFn?{fetchFn:this.options.fetchFn}:{},...this.options.log?{log:this.options.log}:{}},f=s?r?o.exact.has(`${e}/${s}@${r}`):o.pkgs.has(`${e}/${s}`):[...o.pkgs].some(n=>n.startsWith(`${e}/`)),p,b;if(f&&this.options.root!==void 0){let n=this.options.root;p=`ws:${e}`,b=()=>se(n,{publisher:e,...this.options.log?{log:this.options.log}:{}})}else{let n=s?r?`${e}/${s}@${r}`:`${e}/${s}`:e;p=`rm:${n}`,b=()=>ae(n,i)}let d=this.models.get(p);if(d)return d;let u=await b();return u.lookRenderer.setLinkMode("open-world"),this.models.set(p,u),u}async handle(e,s=""){let r=e.split("/").filter(Boolean);if(r.length===0)return{status:200,headers:{"Content-Type":"text/html; charset=utf-8"},body:xe()};let o=r[0];if(!o.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 i=r.length>=2&&(r[1]==="index.html"||r[1]==="index.css"||r[1]==="index.txt"||r[1]===".well-known"),f=!i&&r.length>=2?r[1]:void 0,p=!i&&r.length>=3&&/^\d+\.\d+\.\d+$/.test(r[2])?r[2]:void 0,b=await this.modelFor(o,f,p),d=e.endsWith("/")&&r.length>1?"/":"",u="/"+r.slice(1).join("/")+d,n=await ce(b,u,s);return n.headers.Location?{...n,headers:{...n.headers,Location:`/${o}${n.headers.Location}`}}:n}};function xe(){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{T as ClosureScopedRepository,le as RequestRouter,Se as UNIVERSAL_RENDER_BASE,te as buildRenderDiagnostics,H as buildRenderStackWarnings,O as deriveImportClosure,xe as landingPage,ae as loadResourceModel,se as loadServerModel,ie as renderDiagnosticsHtml,F as renderRefKey,W as resolveRenderContract,ce as route};
64
+ </html>`}var x={".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"},P=(t,e,a,r)=>({status:t,headers:{"Content-Type":e,...r||{}},body:a}),N=t=>P(404,x[".html"],`<!doctype html><meta charset=utf-8><title>404</title><h1>404</h1><p>Not found: ${t}</p>`),De=t=>({status:301,headers:{Location:t},body:""}),Ke=t=>({status:302,headers:{Location:t},body:""});function Ve(t){switch(t.kind){case"exact":return{operator:ae.Exact,version:H(t.major,t.minor,t.patch)};case"minor-pin":return{operator:ae.Compatible,version:H(t.major,t.minor,0)};case"major-pin":return{operator:ae.Major,version:H(t.major,0,0)};default:return{operator:ae.Any,version:H(0,0,0)}}}async function Ae(t,e,a,r){if(!r)return null;let i=t.producers?.find(k=>k.canProduce(t.publisher,e));if(!i)return null;let n=await i.resolveVersion(t.publisher,e,Ve(a));if(!n)return null;let m=D(n);if(a.kind!=="exact")return Ke(`/${e}/${m}.kan.yml`);let{source:u}=await i.produce(t.publisher,e,n);return P(200,x[".kan.yml"],u)}function xe(t,e,a){let r=t.pkgVersions.get(e);if(!r||r.length===0)return null;switch(a.kind){case"any":return r[0].verStr;case"major-pin":return r.find(i=>i.version.major===a.major)?.verStr??null;case"minor-pin":return r.find(i=>i.version.major===a.major&&i.version.minor===a.minor)?.verStr??null;case"exact":return r.find(i=>i.version.major===a.major&&i.version.minor===a.minor&&i.version.patch===a.patch)?.verStr??null;default:return null}}async function pe(t,e,a=""){let{lookRenderer:r,publisher:i}=t;if(e==="/.well-known/kanonak.json")return t.configSource?P(200,x[".json"],t.configSource):P(200,x[".json"],JSON.stringify(ye(),null,2));if(e==="/kanonak.lock")return t.lockSource?P(200,x[".kan.yml"],t.lockSource):N(e);if(e==="/.well-known/kanonak-render.json")return P(200,x[".json"],JSON.stringify(se(t),null,2));if(e==="/.well-known/kanonak-render")return P(200,x[".html"],de(se(t)));if(e==="/"||e==="/index.html"||e==="/index.css"){let o=r.publisherSubject(i);return e==="/index.css"?P(200,x[".css"],r.renderStylesheet(o)):P(200,x[".html"],await r.renderDocument(o,{rootIndex:!0}))}let n=".html",m=!1,u=e;for(let o of[".kan.yml",".css",".svg",".md",".html"])if(e.endsWith(o)){n=o,m=!0,u=e.slice(0,-o.length);break}let k=!m&&/application\/yaml|text\/yaml/i.test(a),p=u.endsWith("/");p&&u!=="/"&&(u=u.slice(0,-1));let h=$e.parse(u,i);if(!h)return N(e);if(h.kind==="package"){let o=xe(t,h.package_,h.versionSpec);if(!o)return await Ae(t,h.package_,h.versionSpec,n===".kan.yml"||k)??N(e);if(n===".kan.yml"||k){let v=t.rawByNsKey.get(`${h.package_}@${o}`);return v!==void 0?P(200,x[".kan.yml"],v):N(e)}let g=t.pkgSelfByVer.get(`${h.package_}@${o}`);if(!g)return N(e);if(n===".css")return P(200,x[".css"],r.renderStylesheet(g));if(!p)return De(u+"/");let w=h.versionSpec.kind==="any";if(w&&!r.hasDeclaredView(g)){let v=(t.pkgVersions.get(h.package_)||[]).map($=>$.verStr);return P(200,x[".html"],r.renderPackageVersionList(h.package_,v,g))}return P(200,x[".html"],await r.renderDocument(g,w?{bareOverview:!0}:void 0))}if(h.kind==="resource"){let o=xe(t,h.package_,h.versionSpec);if(!o)return N(e);let g=t.bySubject.get(`${i}/${h.package_}@${o}/${h.name}`);if(!g)return N(e);switch(n){case".css":return P(200,x[".css"],r.renderStylesheet(g));case".svg":return P(200,x[".svg"],await r.renderSvg(g));case".md":{let w=r.renderRawMarkdown(g);return w===void 0?N(e):P(200,x[".md"],w)}default:return P(200,x[".html"],await r.renderDocument(g))}}return N(e)}import{readFileSync as Ee}from"fs";var ue=class{constructor(e={}){this.options=e}options;models=new Map;workspaceIndex;clearCache(){this.models.clear(),this.workspaceIndex=void 0}getWorkspaceIndex(){if(this.workspaceIndex)return this.workspaceIndex;let e=new Set,a=new Set;if(this.options.root!==void 0){let r=new O;for(let i of Z(this.options.root))try{let n=r.parse(Ee(i,"utf-8")).metadata?.namespace_;if(!n?.version)continue;let m=n.version;e.add(`${n.publisher}/${n.package_}@${m.major}.${m.minor}.${m.patch}`),a.add(`${n.publisher}/${n.package_}`)}catch{}}return this.workspaceIndex={exact:e,pkgs:a},this.workspaceIndex}async modelFor(e,a,r){let i=this.getWorkspaceIndex(),n={...this.options.fetchFn?{fetchFn:this.options.fetchFn}:{},...this.options.log?{log:this.options.log}:{}},m=a?r?i.exact.has(`${e}/${a}@${r}`):i.pkgs.has(`${e}/${a}`):[...i.pkgs].some(o=>o.startsWith(`${e}/`)),u,k;if(m&&this.options.root!==void 0){let o=this.options.root;u=`ws:${e}`,k=()=>ce(o,{publisher:e,...this.options.log?{log:this.options.log}:{}})}else{let o=a?r?`${e}/${a}@${r}`:`${e}/${a}`:e;u=`rm:${o}`,k=()=>le(o,n)}let p=this.models.get(u);if(p)return p;let h=await k();return h.lookRenderer.setLinkMode("open-world"),this.models.set(u,h),h}async handle(e,a=""){let r=e.split("/").filter(Boolean);if(r.length===0)return{status:200,headers:{"Content-Type":"text/html; charset=utf-8"},body:Pe()};let i=r[0];if(!i.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 n=r.length>=2&&(r[1]==="index.html"||r[1]==="index.css"||r[1]==="index.txt"||r[1]===".well-known"),m=!n&&r.length>=2?r[1]:void 0,u=!n&&r.length>=3&&/^\d+\.\d+\.\d+$/.test(r[2])?r[2]:void 0,k=await this.modelFor(i,m,u),p=e.endsWith("/")&&r.length>1?"/":"",h="/"+r.slice(1).join("/")+p,o=await pe(k,h,a);return o.headers.Location?{...o,headers:{...o.headers,Location:`/${i}${o.headers.Location}`}}:o}};function Pe(){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{z as ClosureScopedRepository,ue as RequestRouter,we as UNIVERSAL_RENDER_BASE,se as buildRenderDiagnostics,Y as buildRenderStackWarnings,q as deriveImportClosure,Pe as landingPage,le as loadResourceModel,ce as loadServerModel,de as renderDiagnosticsHtml,F as renderRefKey,U as resolveRenderContract,pe as route};
@@ -14,30 +14,25 @@ export interface RenderPackageRef {
14
14
  * contract, and it now publishes the whole stack over HTTP, so a request-driven
15
15
  * render can fetch a fully-styled closure from the real origin.
16
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.
17
+ * A publisher overrides this simply by INSTALLING its own look packages — list
18
+ * them in `featured_packages` so `connect` pulls them into the closure, and the
19
+ * renderer discovers them ambiently and the look cascade applies them per class.
20
+ * There is no separate render declaration: presence in the closure is the whole
21
+ * mechanism. This constant is the universal base every render closure includes.
23
22
  */
24
23
  export declare const UNIVERSAL_RENDER_BASE: readonly RenderPackageRef[];
25
24
  /**
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.
25
+ * The render contract is always the {@link UNIVERSAL_RENDER_BASE}. A publisher's
26
+ * OWN look is not declared here it travels in the closure: listing a look
27
+ * package in `featured_packages` installs it, and the renderer discovers what's
28
+ * present and applies it via the look cascade. So this is the universal floor
29
+ * every render closure includes; the publisher override is additive-by-presence.
33
30
  *
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.
31
+ * The `config` parameter is retained for call-site stability (both
32
+ * `loadServerModel` and `loadResourceModel` pass it) but no longer shapes the
33
+ * contract the override moved from config to closure presence.
39
34
  */
40
- export declare function resolveRenderContract(config: PublisherConfig | undefined): readonly RenderPackageRef[];
35
+ export declare function resolveRenderContract(_config?: PublisherConfig): readonly RenderPackageRef[];
41
36
  /** The closure-set key (`publisher/package`) for a render-stack ref. */
42
37
  export declare function renderRefKey(ref: RenderPackageRef): string;
43
38
  /** How one render-stack package became available to the render catalog (or didn't). */
@@ -47,6 +47,22 @@ export interface ServerModel {
47
47
  * `EntitlementProducer` here for a gated origin.
48
48
  */
49
49
  readonly producers?: readonly IPackageProducer[];
50
+ /**
51
+ * The served publisher's `kanonak.lock` source (verbatim YAML), when present
52
+ * in the workspace. Served at `/kanonak.lock` as the authoritative resolution
53
+ * + integrity source a consumer resolves through. Absent → this publisher
54
+ * pins no closure (the lock endpoint 404s).
55
+ */
56
+ readonly lockSource?: string;
57
+ /**
58
+ * The served publisher's authored `.well-known/kanonak.json` source (verbatim),
59
+ * when present in the workspace. This is how a publisher DECLARES its bootstrap
60
+ * config — `featured_packages` (the entry points `connect` installs),
61
+ * `authorization_servers`, `package_url_template`. Served verbatim at
62
+ * `/.well-known/kanonak.json`; absent → `route` emits the generated minimal
63
+ * default (`{version:1}`). The consumer validates it on read (https checks).
64
+ */
65
+ readonly configSource?: string;
50
66
  /**
51
67
  * How the ambient render stack (look-styles, look-tokens, …) resolved when
52
68
  * this model was loaded — per-package origin, captured failure reasons, and
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kanonak-protocol/sdk",
3
- "version": "5.4.0",
3
+ "version": "5.6.0",
4
4
  "description": "TypeScript SDK for the Kanonak Protocol — parse, resolve, validate, reason over, and render .kan.yml packages.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -126,7 +126,7 @@
126
126
  ],
127
127
  "dependencies": {
128
128
  "@kanonak-protocol/canonical": "^0.1.1",
129
- "@kanonak-protocol/types": "^5.4.0",
129
+ "@kanonak-protocol/types": "^5.6.0",
130
130
  "ignore": "^7.0.5",
131
131
  "js-yaml": "^4.1.0",
132
132
  "yaml": "^2.7.0"
@@ -1,2 +0,0 @@
1
- import{a as f}from"./chunk-SC5M74NM.js";import{a as w}from"./chunk-NJ3AZYQD.js";import{e as v}from"./chunk-2ACBWC7K.js";var R="@kanonak-protocol/sdk (+https://kanonak.org)",y=R;function b(a){y=a}function N(){return y}function h(a,e){let t=new Headers(e?.headers);return t.has("User-Agent")||t.set("User-Agent",y),fetch(a,{...e,headers:t})}var P="https://{publisher}/index.txt",C="https://{publisher}/{package}/{version}.kan.yml",F={version:1};function E(a){return{version:1,index:P.replaceAll("{publisher}",a),package:C.replaceAll("{publisher}",a),auth:"none"}}var m=class{constructor(e){this.fetchFn=e}fetchFn;cache=new Map;getConfig(e){let t=this.cache.get(e);return t||(t=this.fetchConfig(e),this.cache.set(e,t),t.catch(()=>{this.cache.get(e)===t&&this.cache.delete(e)})),t}async fetchConfig(e){let t=`https://${e}/.well-known/kanonak.json`,r;try{r=await(this.fetchFn?this.fetchFn(t,e):h(t))}catch{return F}if(r.status===404)return F;if(!r.ok)throw new Error(`Failed to fetch publisher config: ${t} (${r.status} ${r.statusText})`);let n=await r.json();if(typeof n.version!="number")throw new Error(`Invalid publisher config at ${t}: missing or invalid "version" field`);let s={version:n.version};return typeof n.index=="string"&&(s.index=n.index),typeof n.package=="string"&&(s.package=n.package),(n.auth==="none"||n.auth==="oauth"||n.auth==="bearer")&&(s.auth=n.auth),Array.isArray(n.render)&&n.render.every(o=>typeof o=="string")&&(s.render=n.render),typeof n.resolveByRedirect=="boolean"&&(s.resolveByRedirect=n.resolveByRedirect),s}resolveIndexUrl(e,t){let r=t.index??P;return x(r,{publisher:e})}resolvePackageUrl(e,t,r,n){let s=n.package??C;return x(s,{publisher:e,package:t,version:r})}};function x(a,e){let t=a;for(let[n,s]of Object.entries(e))t=t.replaceAll(`{${n}}`,s);let r=t.match(/\{[a-z]+\}/);if(r)throw new Error(`Unresolved variable ${r[0]} in URL template: ${a}`);return t}import{VersionOperator as p}from"@kanonak-protocol/types/document/models/enums";var u=class a{indexCache=new Map;configResolver;fetchFn;constructor(e){this.configResolver=e?.configResolver??new m(e?.fetchFn),this.fetchFn=e?.fetchFn}async resolveVersion(e,t){let r=await this.getPackageVersions(e,t.packageName);if(r.length===0)return null;let n=r.filter(s=>this.isVersionCompatible(s,t.version,t.versionOperator));return n.length===0?null:(n.sort((s,o)=>this.compareVersionStrings(o,s)),n[0])}async getHighestVersion(e,t){let r=await this.getPackageVersions(e,t);return r.length===0?null:[...r].sort((s,o)=>this.compareVersionStrings(o,s))[0]}async listLatestPackages(e){let t=await this.getIndex(e),r=[];for(let[n,s]of t){if(s.length===0)continue;let o=[...s].sort((i,c)=>this.compareVersionStrings(c,i));r.push({packageName:n,version:o[0]})}return r.sort((n,s)=>n.packageName.localeCompare(s.packageName)),r}async getPackageUrl(e,t,r){let n=await this.configResolver.getConfig(e);return this.configResolver.resolvePackageUrl(e,t,r,n)}getConfig(e){return this.configResolver.getConfig(e)}async getPackageVersions(e,t){return(await this.getIndex(e)).get(t)??[]}getIndex(e){let t=this.indexCache.get(e);return t||(t=this.fetchIndex(e),this.indexCache.set(e,t),t.catch(()=>{this.indexCache.get(e)===t&&this.indexCache.delete(e)})),t}async fetchIndex(e){let t=await this.configResolver.getConfig(e),r=this.configResolver.resolveIndexUrl(e,t),n=this.fetchFn?await this.fetchFn(r,e):await h(r);if(!n.ok)throw new Error(`Failed to fetch publisher index: ${r} (${n.status} ${n.statusText})`);let s=await n.text();return a.parseIndex(s)}static parseIndex(e){let t=new Map;for(let r of e.split(`
2
- `)){let n=r.trim();if(!n||n.startsWith("#"))continue;let s=n.indexOf("/");if(s===-1)continue;let o=n.substring(0,s),i=n.substring(s+1);if(!o||!i)continue;let c=t.get(o);c?c.push(i):t.set(o,[i])}return t}isVersionCompatible(e,t,r){let n=a.parseVersion(e);if(!n)return!1;switch(r){case p.Any:return!0;case p.Exact:return n.major===t.major&&n.minor===t.minor&&n.patch===t.patch;case p.Compatible:return n.major===t.major&&n.minor===t.minor&&n.patch>=t.patch;case p.Major:return n.major!==t.major?!1:n.minor>t.minor?!0:n.minor===t.minor?n.patch>=t.patch:!1;default:return!1}}static parseVersion(e){let t=e.split(".");if(t.length<2)return null;let r=parseInt(t[0],10),n=parseInt(t[1],10),s=t.length>=3?parseInt(t[2],10):0;return isNaN(r)||isNaN(n)||isNaN(s)?null:{major:r,minor:n,patch:s}}compareVersionStrings(e,t){let r=a.parseVersion(e),n=a.parseVersion(t);return!r&&!n?0:r?n?r.major!==n.major?r.major-n.major:r.minor!==n.minor?r.minor-n.minor:r.patch-n.patch:1:-1}};import{VersionOperator as I}from"@kanonak-protocol/types/document/models/enums";var A=class{parser=new w;publisherIndex;documents=new Map;contentCache=new Map;fetchFn;onFetch;getFromCache;constructor(e){this.onFetch=e?.onFetch,this.getFromCache=e?.getFromCache,this.fetchFn=e?.fetchFn,this.publisherIndex=e?.fetchFn?new u({fetchFn:e.fetchFn}):new u}async getHighestCompatibleVersionAsync(e,t){if((await this.publisherIndex.getConfig(e)).resolveByRedirect)return this.resolveByRedirect(e,t);let n=await this.publisherIndex.resolveVersion(e,t);if(!n)return null;let s=`${e}/${t.packageName}@${n}`,o=this.documents.get(s);if(o)return o;if(this.getFromCache){let d=this.getFromCache(e,t.packageName,n);if(d){let k=this.parser.parse(d);return f(k,e,t.packageName,n),this.documents.set(s,k),this.contentCache.set(s,d),k}}let i=await this.publisherIndex.getPackageUrl(e,t.packageName,n),c=this.fetchFn?await this.fetchFn(i,e):await h(i);if(!c.ok)throw new Error(`Failed to fetch Kanonak package: ${i} (${c.status} ${c.statusText})`);let g=await c.text(),l=this.parser.parse(g);return f(l,e,t.packageName,n),this.onFetch&&this.onFetch(e,t.packageName,n,g),this.documents.set(s,l),this.contentCache.set(s,g),l}async resolveByRedirect(e,t){let r=t.packageName,s=t.versionOperator===I.Exact?await this.publisherIndex.getPackageUrl(e,r,v(t.version)):`https://${e}/${r}.kan.yml`,o=await this.fetchFollowing(s,e);if(!o)return null;let i=this.parser.parse(o.content),c=i.metadata.namespace_;if(!c||!c.version)throw new Error(`Producer origin returned a package with no namespace/version for ${e}/${r}`);let g=v(c.version);f(i,e,r,g);let l=`${e}/${r}@${g}`;return this.onFetch&&this.onFetch(e,r,g,o.content),this.documents.set(l,i),this.contentCache.set(l,o.content),i}async fetchFollowing(e,t,r=4){let n=e;for(let s=0;s<r;s++){let o=this.fetchFn?await this.fetchFn(n,t):await h(n,{redirect:"manual"});if(o.status===301||o.status===302){let i=o.headers.get("location");if(!i)throw new Error(`Redirect with no Location header from ${n}`);n=new URL(i,n).toString();continue}if(o.status===404)return null;if(!o.ok)throw new Error(`Failed to fetch Kanonak package: ${n} (${o.status} ${o.statusText})`);return{url:n,content:await o.text()}}throw new Error(`Too many redirects resolving ${e}`)}async getAllDocumentsAsync(){return Array.from(this.documents.values())}async getDocumentAsync(e){return this.documents.get(e)??null}async getDocumentsByNamespaceAsync(e,t){return Array.from(this.documents.values()).filter(r=>{let n=r.metadata.namespace_;return n&&n.publisher===e&&n.package_===t})}async saveDocumentAsync(e,t){throw new Error("HttpKanonakDocumentRepository is read-only")}async deleteDocumentAsync(e){throw new Error("HttpKanonakDocumentRepository is read-only")}async clearNamespaceAsync(e,t){throw new Error("HttpKanonakDocumentRepository is read-only")}async getAllDocumentReferencesAsync(){return[]}async getDocumentContentAsync(e){return this.contentCache.get(e)??null}async getDocumentUriAsync(e){let t=e.match(/^(.+?)\/(.+?)@(.+)$/);if(!t)return null;let[,r,n,s]=t;return this.publisherIndex.getPackageUrl(r,n,s)}};export{R as a,b,N as c,h as d,E as e,m as f,u as g,A as h};