@kanonak-protocol/sdk 5.4.0 → 5.5.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.
- package/dist/auth/CredentialResolver.d.ts +2 -0
- package/dist/auth/OAuthDiscovery.d.ts +12 -0
- package/dist/auth/SessionExchange.d.ts +0 -1
- package/dist/auth/SessionManager.d.ts +1 -3
- package/dist/browser.js +1 -1
- package/dist/{chunk-GMEPM2QQ.js → chunk-5E2QVDAW.js} +1 -1
- package/dist/chunk-HYTQC73A.js +1 -0
- package/dist/http/kanonakFetch.d.ts +17 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +26 -26
- package/dist/lock/LockFile.d.ts +12 -3
- package/dist/lock/LockFileIO.d.ts +4 -0
- package/dist/lock/index.d.ts +2 -1
- package/dist/repositories/HttpKanonakDocumentRepository.d.ts +19 -9
- package/dist/repositories/PublisherConfig.d.ts +52 -36
- package/dist/repositories/PublisherIndex.d.ts +20 -32
- package/dist/repositories/browser.js +1 -1
- package/dist/repositories/index.js +1 -1
- package/dist/server/assembleModel.d.ts +2 -0
- package/dist/server/index.js +11 -13
- package/dist/server/renderStack.d.ts +14 -19
- package/dist/server/types.d.ts +16 -0
- package/package.json +2 -2
- package/dist/chunk-JYBKSBB5.js +0 -2
|
@@ -37,6 +37,8 @@ export interface ResolvedCredential {
|
|
|
37
37
|
export interface CredentialResolverDeps {
|
|
38
38
|
discovery?: {
|
|
39
39
|
discoverProtectedResource(host: string): Promise<string[] | null>;
|
|
40
|
+
/** Kanonak-native authority pointer (kanonak.json `authorization_servers`). */
|
|
41
|
+
discoverKanonakAuthorities(host: string): Promise<string[] | null>;
|
|
40
42
|
/** RFC 8414 metadata — the `session_endpoint` proves trust-plane identity (#75). */
|
|
41
43
|
discover(host: string): Promise<OAuthServerMetadata | null>;
|
|
42
44
|
};
|
|
@@ -45,6 +45,18 @@ export declare const DEFAULT_CONSENT_BINDING_PARAM = "key_thumbprint";
|
|
|
45
45
|
export declare class OAuthDiscovery {
|
|
46
46
|
private readonly cache;
|
|
47
47
|
private readonly prCache;
|
|
48
|
+
private readonly kanCache;
|
|
49
|
+
/**
|
|
50
|
+
* The authorization server(s) a KANONAK PUBLISHER advertises in its
|
|
51
|
+
* `.well-known/kanonak.json` (`authorization_servers`, RFC 9728-shaped). This
|
|
52
|
+
* is the Kanonak-native authority pointer: the presence of `kanonak.json` is
|
|
53
|
+
* the proof the host is a Kanonak publisher, and `authorization_servers` names
|
|
54
|
+
* who protects it. Returns the issuer URLs, or null when the host serves no
|
|
55
|
+
* `kanonak.json` or advertises no authorities (a public publisher needing no
|
|
56
|
+
* credential). The Kanonak-first counterpart to {@link discoverProtectedResource}
|
|
57
|
+
* (the IETF-standard fallback for arbitrary, non-Kanonak hosts).
|
|
58
|
+
*/
|
|
59
|
+
discoverKanonakAuthorities(host: string): Promise<string[] | null>;
|
|
48
60
|
/**
|
|
49
61
|
* RFC 9728 (OAuth 2.0 Protected Resource Metadata): the authorization
|
|
50
62
|
* server(s) that protect a resource host. The git credential helper uses this
|
|
@@ -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
|
|
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,
|
|
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-HYTQC73A.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-HYTQC73A.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(s){F=s}function b(){return F}function u(s){let t;try{t=typeof s=="string"?new URL(s):s}catch{throw new Error(`Kanonak requires an absolute https:// URL \u2014 got an unparseable or relative URL: ${String(s)}`)}if(t.protocol!=="https:")throw new Error(`Kanonak requires HTTPS \u2014 refusing to fetch ${t.href} (only https:// is supported).`)}function l(s,t){u(s);let e=new Headers(t?.headers);return e.has("User-Agent")||e.set("User-Agent",F),fetch(s,{...t,headers:e})}var _="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):l(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};if(typeof r.package_url_template=="string"&&(L(e,"package_url_template",r.package_url_template),i.package_url_template=r.package_url_template),Array.isArray(r.authorization_servers)&&r.authorization_servers.every(o=>typeof o=="string")){let o=r.authorization_servers;for(let a of o)try{u(a)}catch(c){throw new Error(`Invalid publisher config at ${e}: authorization_servers entry is not https \u2014 ${c.message}`)}i.authorization_servers=o}return Array.isArray(r.featured_packages)&&r.featured_packages.every(o=>typeof o=="string")&&(i.featured_packages=r.featured_packages),i}resolvePackageUrl(t,e,n,r){let i=r.package_url_template??_,o=E(i,{publisher:t,package:e,version:n});return u(o),o}};function L(s,t,e){if(!e.startsWith("https://"))throw new Error(`Invalid publisher config at ${s}: ${t} must be an absolute https:// URL template (got "${e}").`)}function E(s,t){let e=s;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: ${s}`);return e}import U from"js-yaml";function $(s){let t=U.load(s);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 l(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 $(await n.text())}};import{VersionOperator as d}from"@kanonak-protocol/types/document/models/enums";function D(s,t){let e=P(s);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 R=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?D(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}`,o=this.documents.get(i);if(o)return o;let a=f=>{let p=this.parser.parse(f);return v(p,t,e,r),p};if(this.getFromCache){let f=this.getFromCache(t,e,r);if(f){let p=a(f);return this.documents.set(i,p),this.contentCache.set(i,f),p}}let c=n.resolved,h=this.fetchFn?await this.fetchFn(c,t):await l(c);if(!h.ok)throw new Error(`Failed to fetch Kanonak package: ${c} (${h.status} ${h.statusText})`);let g=await h.text(),w=a(g);return this.onFetch&&this.onFetch(t,e,r,g),this.documents.set(i,w),this.contentCache.set(i,g),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`,o=await this.fetchFollowing(i,t);if(!o)return null;let a=this.parser.parse(o.content),c=a.metadata.namespace_;if(!c||!c.version)throw new Error(`Producer origin returned a package with no namespace/version for ${t}/${n}`);let h=y(c.version);v(a,t,n,h);let g=`${t}/${n}@${h}`;return this.onFetch&&this.onFetch(t,n,h,o.content),this.documents.set(g,a),this.contentCache.set(g,o.content),a}async fetchFollowing(t,e,n=4){let r=t;for(let i=0;i<n;i++){u(r);let o=this.fetchFn?await this.fetchFn(r,e):await l(r,{redirect:"manual"});if(o.status===301||o.status===302){let a=o.headers.get("location");if(!a)throw new Error(`Redirect with no Location header from ${r}`);r=new URL(a,r).toString();continue}if(o.status===404)return null;if(!o.ok)throw new Error(`Failed to fetch Kanonak package: ${r} (${o.status} ${o.statusText})`);return{url:r,content:await o.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,u as d,l as e,T as f,k as g,$ as h,m as i,R 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
|
|
2
|
-
Run 'kanonak logout ${t}' then 'kanonak login ${t}' to fix.`)}}catch(r){if(
|
|
1
|
+
import{a as Cr,b as Ar,c as Dr,d as Tr,e as Se}from"./chunk-TVSHIXLA.js";import{a as wn,c as we,e as Me,h as Ve,i as Le,j as Pn}from"./chunk-IHB7UVEH.js";import{a as Er,b as Rr,c as xr,d as Z,e as Y,f as c,g as bn,h as Pe,i as En,j as Rn}from"./chunk-VOJ6BGAR.js";import{a as vn}from"./chunk-EZSHR3CB.js";import"./chunk-QHABFCRC.js";import{a as Bt,b as jt,c as Mt,d as Vt,e as Lt,f as Xt,g as Zt,h as Yt,i as Qt}from"./chunk-5E2QVDAW.js";import{a as Ft,b as Ut,c as Ht,d as zt,e as C,g as Wt,h as fe,i as Gt,j as qt}from"./chunk-HYTQC73A.js";import{a as Ot}from"./chunk-4NO7MHS7.js";import{a as _r,b as Kr,c as Ir,d as Nr}from"./chunk-S6VSAKXB.js";import{a as Or,b as Ur}from"./chunk-PEUTCG3B.js";import{a as jr}from"./chunk-PEJALHXK.js";import{a as Jt}from"./chunk-SC5M74NM.js";import{A as gn,B as kn,K as Sn,a as Hr,b as zr,c as Wr,d as Gr,e as Jr,f as qr,g as Xr,h as Zr,i as Yr,j as Qr,k as en,l as tn,m as rn,n as nn,o as on,p as sn,q as an,r as cn,s as ln,t as dn,u as pn,v as un,w as mn,x as yn,y as hn,z as fn}from"./chunk-7K5TAJ44.js";import"./chunk-ITKOKDBG.js";import{a as D,b as nr,c as ur,h as hr,i as fr,j as wr,k as Pr,l as L}from"./chunk-MX3DEXMV.js";import{a as B}from"./chunk-NJ3AZYQD.js";import{a as br,b as ve,c as Br,d as w,e as Mr,f as Vr,g as Lr,h as Fr}from"./chunk-ZP6P7HNU.js";import{a as je}from"./chunk-6U26UASC.js";import{a as mr,b as yr,c as V,d as gr,e as kr,g as Sr,k as vr}from"./chunk-GZPLWII7.js";import{a as er,b as tr,c as A,d as j,e as or,f as sr,g as ir,h as ar,i as cr,j as lr,k as dr,l as pr,r as X,w as M,x as ge,y as ke}from"./chunk-7BHDZHJY.js";import{a as rr}from"./chunk-FUUTGGJS.js";import{a as Dt,b as he,c as q,d as Tt,e as E,f as $t,g as _t,h as Kt,i as It,j as Nt}from"./chunk-2ACBWC7K.js";import{a as $r}from"./chunk-ODIECDN7.js";import{VersionOperator as ka}from"@kanonak-protocol/types/document/models/enums";import{existsSync as Gn,readFileSync as Jn}from"fs";import{homedir as qn}from"os";import{join as Xn}from"path";import{execFile as xn}from"child_process";import{promisify as Cn}from"util";var Q=Cn(xn),An="kanonak",ee="/usr/bin/security",m=class{constructor(e=An){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=
|
|
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=
|
|
7
|
-
The credential may not have been fully removed.`)}}async list(){try{let{stdout:e}=await ee
|
|
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: ${
|
|
9
|
-
${
|
|
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 Dn}from"child_process";import{promisify as Tn}from"util";var $n=Tn(Dn),_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
|
|
22
|
-
${
|
|
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,12 +35,12 @@ 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
|
|
39
|
-
${
|
|
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
|
|
42
|
-
${
|
|
43
|
-
${
|
|
41
|
+
[CredMan]::CredDelete($target, 1, 0) | Out-Null`;try{await re(r,{KANONAK_CRED_TARGET:t})}catch{}}async list(){let e=`
|
|
42
|
+
${ne}
|
|
43
|
+
${Kn}
|
|
44
44
|
$prefix = $env:KANONAK_CRED_PREFIX
|
|
45
45
|
$count = 0
|
|
46
46
|
$pCreds = [IntPtr]::Zero
|
|
@@ -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
|
|
61
|
-
`).map(r=>r.trim()).filter(Boolean)}catch{return[]}}};async function
|
|
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 $n(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
|
-
"@`,
|
|
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
|
|
92
|
+
"@`,Kn="";import{execFile as In,spawn as Nn}from"child_process";import{promisify as On}from"util";var oe=On(In),Bn="kanonak",h=class{constructor(e=Bn){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=Nn("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 jn,createDecipheriv as Mn,randomBytes as Je}from"crypto";import{homedir as Vn}from"os";import{join as Re,dirname as qe}from"path";var Ze=Re(Vn(),".config","kanonak"),F=Re(Ze,"keyring.key"),Ln=Re(Ze,"credentials.enc"),Xe="aes-256-gcm",be=32,T=12,Ee=16,f=class{constructor(e=Ln){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=Mn(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=jn(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 Fn}from"child_process";import{promisify as Un}from"util";var Hn=Un(Fn),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=
|
|
96
|
-
Verify the helper binary supports the 'store' action.`)}}async remove(e){let t=
|
|
97
|
-
Check the 'credentialHelper' path in ~/.kanonak/config.json.`):
|
|
98
|
-
The helper may be waiting for authentication to an external vault.`):r}}};function
|
|
99
|
-
Using default credential backend. Fix the JSON syntax or delete the file.`),{}}}import{homedir as
|
|
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 Hn(this.helperPath,[e],{...t&&{input:JSON.stringify(t)},timeout:Ye});return r}catch(r){throw zn(r)?new Error(`Credential helper not found at '${this.helperPath}'.
|
|
97
|
+
Check the 'credentialHelper' path in ~/.kanonak/config.json.`):Wn(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 zn(o){return o instanceof Error&&"code"in o&&o.code==="ENOENT"}function Wn(o){return o instanceof Error&&"killed"in o&&o.killed}var xe=Xn(qn(),".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=Zn(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=Yn();return e.credentialHelper?new U(e.credentialHelper):process.platform==="darwin"?new m:process.platform==="win32"?new y:await R()?new h:new f}};function Zn(o){let t="KANONAK_TOKEN_"+c(o).replace(/[.\-]/g,"_").toUpperCase();return process.env[t]??null}function Yn(){if(!Gn(xe))return{};try{return JSON.parse(Jn(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 Qn,writeFile as Qe,readFile as et,rm as tt}from"fs/promises";var Ce="kanonak-device",eo=x(rt(),".config","kanonak","device-credentials.enc"),to=x(rt(),".kanonak","devices"),P=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??to,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 Qn(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 h(Ce):new f(eo)}};import{homedir as ro}from"os";import{join as no}from"path";var Ae="kanonak-session",oo=no(ro(),".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 h(Ae):new f(oo)}};function ae(o,e=5*6e4,t=Date.now()){let r=Date.parse(o.expiresAt);return Number.isNaN(r)?!0:t>=r-e}var ot="key_thumbprint",b=class{cache=new Map;prCache=new Map;kanCache=new Map;async discoverKanonakAuthorities(e){let t=c(e);if(this.kanCache.has(t))return this.kanCache.get(t);let r=`https://${t}/.well-known/kanonak.json`,n=await nt(r),s=n&&Array.isArray(n.authorization_servers)?n.authorization_servers.filter(a=>typeof a=="string"):[],i=s.length>0?s:null;return this.kanCache.set(t,i),i}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 nt(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 nt(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 st 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
|
|
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
|
|
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=st.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 P,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 P}async resolve(e){let t=await this.discovery.discoverKanonakAuthorities(e)??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 ho}from"crypto";function at(){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),fo(i,a,o)}function ct(o){return!o||o.length===0?!1:o.some(e=>e.toUpperCase()==="ES256")}function fo(o,e,t){let r=it(JSON.stringify(o)),n=it(JSON.stringify(e)),s=`${r}.${n}`,i=uo({key:t,format:"jwk"}),l=ho("SHA256",Buffer.from(s),{key:i,dsaEncoding:"ieee-p1363"}).toString("base64url");return`${s}.${l}`}function it(o){return Buffer.from(o,"utf-8").toString("base64url")}function lt(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 wo from"js-yaml";var dt="kanonak.lock",Po=`# This file is generated by Kanonak CLI. Do not edit manually.
|
|
103
|
+
`;function pt(o=dt){return So(o)?fe(go(o,"utf-8")):null}function ut(o,e=dt){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=wo.dump(o,{lineWidth:-1,sortKeys:!1,quotingType:'"'});ko(e,Po+r,"utf-8")}function mt(o){return`sha256:${vo("sha256").update(o).digest("hex")}`}import*as De from"js-yaml";import{VersionOperator as yt}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 gt(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={[ht]:{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!==ht);for(let d of l)d.namespace="ephemeral";return Pe(l)}},ht="__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=yt.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,yt.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:he(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 gt(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=>gt(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",kt="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=St(r,u,kt),d=St(r,u,v),p=this.builder.imports(),ue=p.ensure(u,kt,l,"ck"),wt=p.ensure(u,v,d,"v"),Pt=p.ref(i),bt=new Le(this.repository,this.parser,this.objectParser),Ke=new Me(bt,r),Et=this.readProjections(r,n),Rt=No(n,Do),xt=this.findInstances(r,s,await this.reason(t)),Ie={},Ct=new Set;for(let J of xt){if(!await this.passesWhere(Ke,r,Rt,J))continue;let ye={type:Pt};for(let Oe of Et){let At=await this.evaluateValue(Ke,r,Oe.value,J),Be=this.builder.serializeValue(vt(At),p);Be!==void 0&&(ye[p.ref(Oe.as)]=Be)}let Ne=w(J);Ne&&(ye[`${wt}.derivedFrom`]=p.ref(Ne)),Ie[this.rowName(J,Ct)]=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(w(a)),p=V(w(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 vt(o){return we(o)?o.value:Array.isArray(o)?o.map(vt):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 St(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=w(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=w(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:we(o)?o.value.length>0:Array.isArray(o)?o.length>0:!!o}export{pn as AmbiguousReferenceRule,cr as BooleanStatement,En as CANONICAL_FORM_VERSION,hr as Carrier,gn as ClassDefinitionRule,nn as ClassHierarchyCycleRule,Mt as CompositeKanonakDocumentRepository,ce as CredentialResolver,ie as CredentialStore,ot as DEFAULT_CONSENT_BINDING_PARAM,tr as DefinedKanonak,P as DeviceCertificateStore,jt as DocumentLocation,Rr as EdgeType,D as EmbeddedKanonak,en as EmbeddedKanonakTypeRule,dr as EmbeddedStatement,G as EntitlementDeniedError,de as EntitlementProducer,Bt as FileSystemKanonakDocumentRepository,$r as GitIgnoreFilter,xr as GraphBuilder,qt as HttpKanonakDocumentRepository,z as ImportBook,tn as ImportExistenceRule,Ot as InMemoryKanonakDocumentRepository,Ft as KANONAK_USER_AGENT,er as Kanonak,Kr as KanonakDocumentPositions,L as KanonakObjectParser,Sn as KanonakObjectValidator,B as KanonakParser,rr as KanonakUri,Or as KanonakUriBuilder,jr as KanonakUrlResolver,vr as KanonakVocabulary,pr as ListStatement,nr as LiteralKanonak,Xt as LocalFirstRepository,Zt as LockAwareRepository,Pn as LookRenderer,kn as MarkdownLinkRule,ur as MarkdownStatement,ln as NamespaceImportCycleRule,qr as NamespacePrefixRule,Er as NodeType,ar as NumberStatement,b as OAuthDiscovery,Dr as OWL_RL_CLASSIFICATION_RULES,mn as ObjectPropertyValueValidationRule,Wr as OntologyValidationError,Hr as OntologyValidationResult,N as PackageBuilder,Qr as PackageHeaderRule,le as ProducerRepository,yn as PropertyDomainRule,on as PropertyHierarchyCycleRule,hn as PropertyKindRangeConsistencyRule,_r as PropertyMetadata,un as PropertyRangeReferenceRule,sn as PropertyRangeRequiredRule,Zr as PropertyTypeSpecificityRule,Wt as PublisherConfigResolver,Gt as PublisherIndex,Ar as RDFS_RULES,Se as Reasoner,Tr as ReasoningResult,j as ReferenceKanonak,lr as ReferenceStatement,Lt as RepositoryFactory,fn as ReservedNameShadowRule,Xr as ResourceNamingRule,mr as ResourceResolver,br as ResourceTypeClassifier,sr as ScalarStatement,K as SessionError,_ as SessionExchange,S as SessionExchangeError,I as SessionManager,$ as SessionStore,or as Statement,ir as StringStatement,an as SubClassOfReferenceRule,cn as SubPropertyOfReferenceRule,A as SubjectKanonak,Yr as SubjectKanonakTypeRequiredRule,Cr as TripleStore,yr as TypeResolver,dn as UnresolvedPredicateRule,rn as UnresolvedReferenceRule,Jr as ValidationCache,Gr as ValidationContext,zr as ValidationSeverity,ka as VersionOperator,pe as ViewMaterializer,$e as allowAllPolicy,zt as assertHttpsUrl,Jt as assertPackageIdentity,Qt as buildLocalFirstRepository,Rn as buildOntologyModel,bn as canonicalForm,Pe as canonicalHash,fr as carrierOf,Yt as collectKanonakFiles,q as compareVersions,mt as computeIntegrity,Te as contentAddressedName,Fr as contextTypesOf,lt as createAuthenticatedFetch,H as createDPoPProof,$t as createVersion,Pr as extractMarkdownLinks,vn as findDerivation,Ur as findInstancesByType,wr as findMalformedReferences,Nr as findMarkdownLinkAt,Br as formatKanonakAddress,E as formatVersion,at as generateDPoPKeyPair,Vt as getGlobalCachePath,Ht as getKanonakUserAgent,Y as hasValidToken,Kt as isCompatibleVersion,Z as isExpired,It as isMajorCompatible,C as kanonakFetch,pt as loadLockFile,gr as makeUriKey,_e as noopMeter,c as normalizeHost,ve as parseKanonakAddress,_t as parseVersionString,Ir as parseWithPositions,Nt as pickHighestDocument,Vr as propertiesInScope,wn as resolveDisplayValue,Lr as resolvePropertyStep,W as sanitizeName,ut as saveLockFile,ct as serverSupportsDPoP,ae as sessionNeedsRefresh,Ut as setKanonakUserAgent,w as subjectUri,Mr as superClassChain,kr as tripleKey,V as uriKey,Sr as uriTriple,Dt as versionOperatorFromChar,he as versionOperatorToChar,Tt as versionsEqual};
|
package/dist/lock/LockFile.d.ts
CHANGED
|
@@ -9,6 +9,15 @@ export interface LockFile {
|
|
|
9
9
|
lastUpdated: string;
|
|
10
10
|
packages: Record<string, LockEntry>;
|
|
11
11
|
}
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
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;
|
package/dist/lock/index.d.ts
CHANGED
|
@@ -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
|
-
*
|
|
20
|
-
* the
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
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
|
|
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
|
|
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,70 @@
|
|
|
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 BOOTSTRAP — every field answers a
|
|
5
|
+
* "where / who" question a consumer needs before it can do anything else, and
|
|
6
|
+
* nothing here is rendering or resolution policy:
|
|
7
|
+
*
|
|
8
|
+
* - presence of the document itself = "this IS a Kanonak publisher" (the gate);
|
|
9
|
+
* - `authorization_servers` = who protects me (RFC 9728), if anyone;
|
|
10
|
+
* - `featured_packages` = the entry points — what `connect` installs;
|
|
11
|
+
* - `package_url_template` = where my raw source bytes live, if not my own domain.
|
|
12
|
+
*
|
|
13
|
+
* The wire shape and this TS interface are deliberately IDENTICAL — snake_case,
|
|
14
|
+
* same field names, no mapping layer. This is a wire DTO; what you read in the
|
|
15
|
+
* file is what you hold in code. Every URL-bearing field MUST be https (Kanonak
|
|
16
|
+
* speaks https only); a non-https value is rejected at parse time.
|
|
17
|
+
*
|
|
18
|
+
* Every field except `version` is OPTIONAL and present only when non-default: a
|
|
19
|
+
* public, self-hosted publisher serving at the canonical path needs just
|
|
20
|
+
* `version` + `featured_packages`.
|
|
21
|
+
*/
|
|
2
22
|
export interface PublisherConfig {
|
|
23
|
+
/** The config document's own format version (currently 1). */
|
|
3
24
|
version: number;
|
|
4
|
-
index?: string;
|
|
5
|
-
package?: string;
|
|
6
|
-
auth?: 'none' | 'oauth' | 'bearer';
|
|
7
25
|
/**
|
|
8
|
-
*
|
|
9
|
-
* `publisher
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
* how it overrides the universal base with its own look. Each entry is parsed
|
|
15
|
-
* through `parseKanonakAddress`, not string-matched.
|
|
26
|
+
* Full URL template for fetching a package's raw source. Filled with
|
|
27
|
+
* `{publisher}`, `{package}`, `{version}` it yields a URL whose body is the
|
|
28
|
+
* package's source YAML — and that is the ONLY contract (host, path layout,
|
|
29
|
+
* separators, and extension are all free). Optional; absent →
|
|
30
|
+
* {@link DEFAULT_PACKAGE_URL_TEMPLATE}. Present only when a publisher delegates
|
|
31
|
+
* source hosting (e.g. to a CDN). MUST be an `https://` template.
|
|
16
32
|
*/
|
|
17
|
-
|
|
33
|
+
package_url_template?: string;
|
|
18
34
|
/**
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
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.
|
|
35
|
+
* RFC 9728 authorization-server issuer URL(s) that protect this publisher.
|
|
36
|
+
* Present → OAuth-gated (enroll / mint a session at that authority); absent →
|
|
37
|
+
* a public publisher needing no credential. Each MUST be an `https://` URL.
|
|
26
38
|
*/
|
|
27
|
-
|
|
39
|
+
authorization_servers?: string[];
|
|
40
|
+
/**
|
|
41
|
+
* The publisher's entry-point packages — what `kanonak connect` installs and
|
|
42
|
+
* the front door into its graph (everything else is discovered from these via
|
|
43
|
+
* the import graph, or installed directly by name). Bare package names of
|
|
44
|
+
* THIS publisher; version-agnostic (the served `kanonak.lock` pins versions).
|
|
45
|
+
*/
|
|
46
|
+
featured_packages?: string[];
|
|
28
47
|
}
|
|
29
48
|
/**
|
|
30
|
-
* The
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
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.
|
|
49
|
+
* The canonical package-source URL when a publisher serves from its own domain
|
|
50
|
+
* at the protocol's URL hierarchy. `package_url_template` overrides it only to
|
|
51
|
+
* delegate elsewhere.
|
|
52
|
+
*/
|
|
53
|
+
export declare const DEFAULT_PACKAGE_URL_TEMPLATE = "https://{publisher}/{package}/{version}.kan.yml";
|
|
54
|
+
/**
|
|
55
|
+
* The config a publisher advertises at `.well-known/kanonak.json`. Minimal by
|
|
56
|
+
* design: a self-hosted publisher serving at the canonical path needs only
|
|
57
|
+
* `version`. `package_url_template` is emitted only when delegating source
|
|
58
|
+
* bytes, `authorization_servers` only when gated, and `featured_packages` is
|
|
59
|
+
* the publisher's declared entry points (wired where the publisher declares
|
|
60
|
+
* them; absent here means none declared yet).
|
|
44
61
|
*/
|
|
45
|
-
export declare function defaultPublisherConfig(
|
|
62
|
+
export declare function defaultPublisherConfig(): PublisherConfig;
|
|
46
63
|
export declare class PublisherConfigResolver {
|
|
47
64
|
private readonly fetchFn?;
|
|
48
65
|
private readonly cache;
|
|
49
66
|
constructor(fetchFn?: AuthenticatedFetchFn | undefined);
|
|
50
67
|
getConfig(publisher: string): Promise<PublisherConfig>;
|
|
51
68
|
private fetchConfig;
|
|
52
|
-
resolveIndexUrl(publisher: string, config: PublisherConfig): string;
|
|
53
69
|
resolvePackageUrl(publisher: string, packageName: string, version: string, config: PublisherConfig): string;
|
|
54
70
|
}
|
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
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
|
-
|
|
36
|
-
private
|
|
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{
|
|
1
|
+
import{g as e,i as r,j as n}from"../chunk-HYTQC73A.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-
|
|
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-5E2QVDAW.js";import{f as g,g as h,i,j}from"../chunk-HYTQC73A.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};
|
package/dist/server/index.js
CHANGED
|
@@ -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,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")}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
|
-
`),
|
|
3
|
-
`),
|
|
4
|
-
`),
|
|
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-5E2QVDAW.js";import{e as ke,f as ye,i as G,j as X}from"../chunk-HYTQC73A.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,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")}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: ${
|
|
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">${
|
|
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
|
-
${
|
|
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
|
-
${
|
|
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
|
-
${
|
|
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
|
-
${
|
|
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,
|
|
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
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
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
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
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
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
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(
|
|
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). */
|
package/dist/server/types.d.ts
CHANGED
|
@@ -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.
|
|
3
|
+
"version": "5.5.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.
|
|
129
|
+
"@kanonak-protocol/types": "^5.5.0",
|
|
130
130
|
"ignore": "^7.0.5",
|
|
131
131
|
"js-yaml": "^4.1.0",
|
|
132
132
|
"yaml": "^2.7.0"
|
package/dist/chunk-JYBKSBB5.js
DELETED
|
@@ -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};
|