@kanonak-protocol/sdk 5.9.0 → 5.11.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/CredentialProvider.d.ts +65 -0
- package/dist/auth/TokenCredentialProvider.d.ts +29 -0
- package/dist/auth/credentialedFetch.d.ts +29 -0
- package/dist/auth/hosts.d.ts +6 -0
- package/dist/auth/index.d.ts +6 -21
- package/dist/browser.d.ts +3 -2
- package/dist/browser.js +1 -1
- package/dist/chunk-CZXHGAJV.js +2 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -102
- package/package.json +2 -2
- package/dist/auth/AuthenticatedFetch.d.ts +0 -11
- package/dist/auth/CredentialBackend.d.ts +0 -40
- package/dist/auth/CredentialHelperBackend.d.ts +0 -17
- package/dist/auth/CredentialResolver.d.ts +0 -65
- package/dist/auth/CredentialStore.d.ts +0 -29
- package/dist/auth/DPoP.d.ts +0 -28
- package/dist/auth/DeviceCertificateStore.d.ts +0 -80
- package/dist/auth/EncryptedFileBackend.d.ts +0 -22
- package/dist/auth/KeychainBackend.d.ts +0 -15
- package/dist/auth/SecretServiceBackend.d.ts +0 -25
- package/dist/auth/SessionExchange.d.ts +0 -38
- package/dist/auth/SessionManager.d.ts +0 -57
- package/dist/auth/SessionStore.d.ts +0 -51
- package/dist/auth/WinCredBackend.d.ts +0 -23
- package/dist/chunk-VOJ6BGAR.js +0 -2
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The credential seam between the open protocol layer and a platform's identity
|
|
3
|
+
* mechanism (see ideas/protocol-vs-platform-auth-split.md).
|
|
4
|
+
*
|
|
5
|
+
* The protocol layer's entire knowledge of credentials is this interface: given
|
|
6
|
+
* an authority (and any server challenge), a provider returns headers to attach
|
|
7
|
+
* to a request, or declines. How the credential was minted, stored, or proven
|
|
8
|
+
* never crosses this boundary — that is the platform's business.
|
|
9
|
+
*/
|
|
10
|
+
/** A fetch that authenticates a request to a publisher/resource host. The
|
|
11
|
+
* consumption transport produced by {@link createCredentialedFetch} has this
|
|
12
|
+
* shape; repositories and the server accept it so a host can inject auth. */
|
|
13
|
+
export type AuthenticatedFetchFn = (url: string, publisher: string, method?: string) => Promise<Response>;
|
|
14
|
+
/**
|
|
15
|
+
* What a provider contributes to an outgoing request — scheme-agnostic across
|
|
16
|
+
* header-based credentials (Bearer, DPoP-bound, Basic-wrapped JWT). The protocol
|
|
17
|
+
* layer merges `headers` verbatim and never inspects how they were formed.
|
|
18
|
+
*
|
|
19
|
+
* Transport-level mTLS is deliberately NOT expressible here: a client cert is
|
|
20
|
+
* presented in the TLS handshake, not a header. mTLS is an acquisition mechanism
|
|
21
|
+
* (cert → token); consumption uses the minted, header-based credential.
|
|
22
|
+
*/
|
|
23
|
+
export interface RequestCredential {
|
|
24
|
+
/** Headers to merge onto the request (e.g. Authorization, plus any proof
|
|
25
|
+
* header such as an RFC 9449 DPoP proof). */
|
|
26
|
+
headers: Record<string, string>;
|
|
27
|
+
/** Validity of the underlying session credential (NOT the per-request proof
|
|
28
|
+
* header), so the consumer can pre-empt re-acquisition before a 401. */
|
|
29
|
+
expiresAt?: string;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* A server's authorization challenge, parsed from a 401/403 and forwarded to the
|
|
33
|
+
* provider verbatim. The protocol layer stays dumb: it parses and relays; the
|
|
34
|
+
* provider decides how to satisfy it (bind a nonce, step up, or re-mint).
|
|
35
|
+
*/
|
|
36
|
+
export interface AuthChallenge {
|
|
37
|
+
/** The raw WWW-Authenticate header value. */
|
|
38
|
+
wwwAuthenticate: string;
|
|
39
|
+
/** RFC 9449 server-supplied DPoP nonce, if present, to bind the next proof. */
|
|
40
|
+
nonce?: string;
|
|
41
|
+
/** RFC 9470 required assurance (acr_values), if the server demands step-up. */
|
|
42
|
+
acrValues?: string;
|
|
43
|
+
}
|
|
44
|
+
export interface ResolveOptions {
|
|
45
|
+
/** The HTTP method of the request being authenticated (for per-request proofs). */
|
|
46
|
+
method?: string;
|
|
47
|
+
/** The URL being authenticated (for per-request proofs). */
|
|
48
|
+
url?: string;
|
|
49
|
+
/** Re-mint after a server-side revocation — a *stale* credential. */
|
|
50
|
+
forceRefresh?: boolean;
|
|
51
|
+
/** The server's challenge from a prior 401/403 on this request. */
|
|
52
|
+
challenge?: AuthChallenge;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* The credential seam. A platform implements this; the protocol layer only calls
|
|
56
|
+
* it. Returns null to decline (anonymous / not this provider's authority).
|
|
57
|
+
*
|
|
58
|
+
* `forceRefresh` ("the credential is stale — mint the same kind") is distinct
|
|
59
|
+
* from a `challenge` carrying `acrValues` ("the credential is insufficient —
|
|
60
|
+
* acquire a stronger one"). Keeping them separate lets the provider tell those
|
|
61
|
+
* apart; a binary drop-and-retry cannot.
|
|
62
|
+
*/
|
|
63
|
+
export interface CredentialProvider {
|
|
64
|
+
resolve(authority: string, opts?: ResolveOptions): Promise<RequestCredential | null>;
|
|
65
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { CredentialProvider, RequestCredential, ResolveOptions } from './CredentialProvider.js';
|
|
2
|
+
/**
|
|
3
|
+
* Reference / BYO-token credential provider — the open layer's minimal way to
|
|
4
|
+
* consume a gated package without any platform tooling. It reads a token from
|
|
5
|
+
* configuration and presents it as `Authorization: Bearer`.
|
|
6
|
+
*
|
|
7
|
+
* `Bearer` here is only the *transport* of whatever the issuer minted — its
|
|
8
|
+
* security properties are the issuer's choice, not the protocol's. A platform
|
|
9
|
+
* ships a stronger, sender-constrained provider (e.g. a DPoP-bound JWT minted
|
|
10
|
+
* from a device cert); this one keeps the open SDK/CLI usable standalone, e.g.
|
|
11
|
+
* for an enterprise pointing at its own OAuth-issued token, or for CI.
|
|
12
|
+
*
|
|
13
|
+
* Token sources, in precedence order, per authority host:
|
|
14
|
+
* 1. an explicit `tokens` map
|
|
15
|
+
* 2. env `KANONAK_TOKEN_<AUTHORITY>` (host upper-cased, non-alphanumeric → `_`)
|
|
16
|
+
* 3. env `KANONAK_TOKEN` (applies to any authority)
|
|
17
|
+
*/
|
|
18
|
+
export interface TokenCredentialProviderOptions {
|
|
19
|
+
/** Explicit authority-host → token map (highest precedence). */
|
|
20
|
+
tokens?: Record<string, string>;
|
|
21
|
+
/** Environment to read from; defaults to `process.env` when available. */
|
|
22
|
+
env?: Record<string, string | undefined>;
|
|
23
|
+
}
|
|
24
|
+
export declare class TokenCredentialProvider implements CredentialProvider {
|
|
25
|
+
private readonly tokens;
|
|
26
|
+
private readonly env;
|
|
27
|
+
constructor(opts?: TokenCredentialProviderOptions);
|
|
28
|
+
resolve(authority: string, _opts?: ResolveOptions): Promise<RequestCredential | null>;
|
|
29
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { AuthenticatedFetchFn, AuthChallenge, CredentialProvider } from './CredentialProvider.js';
|
|
2
|
+
/**
|
|
3
|
+
* Parse a server's authorization challenge from a 401/403 response. Returns
|
|
4
|
+
* undefined when the response carries no challenge (a plain unauthorized).
|
|
5
|
+
*/
|
|
6
|
+
export declare function parseAuthChallenge(res: Response): AuthChallenge | undefined;
|
|
7
|
+
export interface CredentialedFetchDeps {
|
|
8
|
+
discovery?: {
|
|
9
|
+
discoverProtectedResource(host: string): Promise<string[] | null>;
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* The protocol's consumption transport. Given a {@link CredentialProvider}, it:
|
|
14
|
+
*
|
|
15
|
+
* 1. Discovers whether a host is gated and, if so, its authority (RFC 9728).
|
|
16
|
+
* 2. Asks the provider for a credential for that authority and attaches the
|
|
17
|
+
* returned headers. A public host, or a provider that declines, → anonymous.
|
|
18
|
+
* 3. Never blind-follows a gated redirect (`redirect: 'manual'`), which would
|
|
19
|
+
* otherwise loop into a login.
|
|
20
|
+
* 4. On a 401/403 to an authenticated request, parses the server challenge
|
|
21
|
+
* and re-resolves: with a `challenge` the provider binds a nonce or steps
|
|
22
|
+
* up; with no challenge the credential is treated as stale and re-minted
|
|
23
|
+
* (`forceRefresh`). Retries once, then surfaces the failure.
|
|
24
|
+
*
|
|
25
|
+
* Without a provider it runs fully anonymous (public packages still resolve).
|
|
26
|
+
* Discovery results and credentials are cached per host/authority so one
|
|
27
|
+
* install/connect doesn't re-discover or re-mint for every package in a closure.
|
|
28
|
+
*/
|
|
29
|
+
export declare function createCredentialedFetch(provider?: CredentialProvider, deps?: CredentialedFetchDeps): AuthenticatedFetchFn;
|
package/dist/auth/index.d.ts
CHANGED
|
@@ -1,23 +1,8 @@
|
|
|
1
|
-
export
|
|
2
|
-
export { isExpired, hasValidToken, normalizeHost } from './CredentialBackend.js';
|
|
3
|
-
export { CredentialStore } from './CredentialStore.js';
|
|
4
|
-
export { DeviceCertificateStore } from './DeviceCertificateStore.js';
|
|
5
|
-
export type { DeviceEnrollmentRecord } from './DeviceCertificateStore.js';
|
|
6
|
-
export { SessionStore, sessionNeedsRefresh } from './SessionStore.js';
|
|
7
|
-
export type { SessionRecord, SessionStoreDeps } from './SessionStore.js';
|
|
1
|
+
export { normalizeHost } from './hosts.js';
|
|
8
2
|
export { OAuthDiscovery, DEFAULT_CONSENT_BINDING_PARAM } from './OAuthDiscovery.js';
|
|
9
3
|
export type { OAuthServerMetadata } from './OAuthDiscovery.js';
|
|
10
|
-
export {
|
|
11
|
-
export
|
|
12
|
-
export {
|
|
13
|
-
export
|
|
14
|
-
export {
|
|
15
|
-
export type { ResolvedCredential, CredentialResolverDeps } from './CredentialResolver.js';
|
|
16
|
-
export type { AuthenticatedFetchFn } from './AuthenticatedFetch.js';
|
|
17
|
-
export { createAuthenticatedFetch } from './AuthenticatedFetch.js';
|
|
18
|
-
export { generateDPoPKeyPair, createDPoPProof, serverSupportsDPoP } from './DPoP.js';
|
|
19
|
-
export { KeychainBackend } from './KeychainBackend.js';
|
|
20
|
-
export { WinCredBackend } from './WinCredBackend.js';
|
|
21
|
-
export { SecretServiceBackend, hasSecretTool } from './SecretServiceBackend.js';
|
|
22
|
-
export { EncryptedFileBackend } from './EncryptedFileBackend.js';
|
|
23
|
-
export { CredentialHelperBackend } from './CredentialHelperBackend.js';
|
|
4
|
+
export type { AuthenticatedFetchFn, CredentialProvider, RequestCredential, AuthChallenge, ResolveOptions, } from './CredentialProvider.js';
|
|
5
|
+
export { createCredentialedFetch, parseAuthChallenge } from './credentialedFetch.js';
|
|
6
|
+
export type { CredentialedFetchDeps } from './credentialedFetch.js';
|
|
7
|
+
export { TokenCredentialProvider } from './TokenCredentialProvider.js';
|
|
8
|
+
export type { TokenCredentialProviderOptions } from './TokenCredentialProvider.js';
|
package/dist/browser.d.ts
CHANGED
|
@@ -31,8 +31,9 @@ export { canonicalForm, canonicalHash, CANONICAL_FORM_VERSION, Carrier, carrierO
|
|
|
31
31
|
export type { CanonicalInput, CanonicalInputSubject, CanonicalInputStatement, CanonicalInputValue, } from './canonical/index.js';
|
|
32
32
|
export { buildOntologyModel } from './introspection/index.js';
|
|
33
33
|
export type { OntologyModel, ClassDef, PropertyDef, ClassRef, TypeRef, BuildOntologyModelOptions, } from './introspection/index.js';
|
|
34
|
-
export {
|
|
35
|
-
export
|
|
34
|
+
export { normalizeHost } from './auth/hosts.js';
|
|
35
|
+
export { OAuthDiscovery, createCredentialedFetch, parseAuthChallenge, TokenCredentialProvider, } from './auth/index.js';
|
|
36
|
+
export type { AuthenticatedFetchFn, CredentialProvider, RequestCredential, AuthChallenge, ResolveOptions, } from './auth/index.js';
|
|
36
37
|
export { kanonakFetch, setKanonakUserAgent, getKanonakUserAgent, KANONAK_USER_AGENT, } from './http/kanonakFetch.js';
|
|
37
38
|
export type { IKanonakDocumentRepository } from '@kanonak-protocol/types/document/models';
|
|
38
39
|
export type { IKanonakParser } from '@kanonak-protocol/types/document/parsing';
|
package/dist/browser.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{a as
|
|
1
|
+
import{a as F,b as H,c as L,d as Pe,f as ge,g as Ce,h as he,i as Ke,j as be,k as Ie,l as Oe,m as je}from"./chunk-CZXHGAJV.js";import{a as Se}from"./chunk-EZSHR3CB.js";import"./chunk-QHABFCRC.js";import{a as m,b as u,c,e as d,h as R,j as y,k as f}from"./chunk-UXYCUGSF.js";import{a as p}from"./chunk-4NO7MHS7.js";import{a as B,b as G,c as q}from"./chunk-S6VSAKXB.js";import{a as w,b as _}from"./chunk-PEUTCG3B.js";import"./chunk-PEJALHXK.js";import"./chunk-SC5M74NM.js";import{A as fe,B as xe,K as ke,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 Re,z as ye}from"./chunk-7K5TAJ44.js";import"./chunk-ITKOKDBG.js";import{a as g,c as v,h as T,i as A,l as M}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 E,b as N}from"./chunk-GZPLWII7.js";import{a as x,b as k,c as P,d as h,e as K,f as S,g as b,h as I,i as O,j,k as D,l as V}from"./chunk-7BHDZHJY.js";import{a as C}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,O as BooleanStatement,Oe as CANONICAL_FORM_VERSION,T as Carrier,fe as ClassDefinitionRule,re as ClassHierarchyCycleRule,k 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,x as Kanonak,G as KanonakDocumentPositions,M as KanonakObjectParser,ke as KanonakObjectValidator,l as KanonakParser,C as KanonakUri,w as KanonakUriBuilder,V as ListStatement,xe as MarkdownLinkRule,v as MarkdownStatement,pe as NamespaceImportCycleRule,X as NamespacePrefixRule,F as NodeType,I as NumberStatement,ge as OAuthDiscovery,ce as ObjectPropertyValueValidationRule,J as OntologyValidationError,W as OntologyValidationResult,de as PropertyDomainRule,ne as PropertyHierarchyCycleRule,Re as PropertyKindRangeConsistencyRule,B as PropertyMetadata,ue as PropertyRangeReferenceRule,ae as PropertyRangeRequiredRule,Z as PropertyTypeSpecificityRule,R as PublisherConfigResolver,y as PublisherIndex,h as ReferenceKanonak,j as ReferenceStatement,ye as ReservedNameShadowRule,Y as ResourceNamingRule,E as ResourceResolver,U as ResourceTypeClassifier,S as ScalarStatement,K as Statement,b as StringStatement,ie as SubClassOfReferenceRule,se as SubPropertyOfReferenceRule,P as SubjectKanonak,$ as SubjectKanonakTypeRequiredRule,Ke as TokenCredentialProvider,N as TypeResolver,le as UnresolvedPredicateRule,te as UnresolvedReferenceRule,Q as ValidationContext,z as ValidationSeverity,je as buildOntologyModel,be as canonicalForm,Ie as canonicalHash,A as carrierOf,e as compareVersions,he as createCredentialedFetch,r as createVersion,Se as findDerivation,_ as findInstancesByType,t as formatVersion,c as getKanonakUserAgent,a as isCompatibleVersion,i as isMajorCompatible,d as kanonakFetch,Pe as normalizeHost,Ce as parseAuthChallenge,n as parseVersionString,q as parseWithPositions,s as pickHighestDocument,u as setKanonakUserAgent,o as versionsEqual};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{e as U}from"./chunk-UXYCUGSF.js";import{H as de,I as fe}from"./chunk-7K5TAJ44.js";import{a as Q,b as A,c as ie,h as G,l as $}from"./chunk-MX3DEXMV.js";import{a as h,d as K,e as le,f as ue}from"./chunk-ZP6P7HNU.js";import{b as J,c as E,d as R,f as ee,g as ne,h as te,i as re,j as oe,k as se,l as ae,m as I,r as F,t as ce,v as N,w as pe,y as L}from"./chunk-7BHDZHJY.js";import{a as Z}from"./chunk-FUUTGGJS.js";import{d as Y}from"./chunk-2ACBWC7K.js";var me=(a=>(a.Class="Class",a.DatatypeProperty="DatatypeProperty",a.ObjectProperty="ObjectProperty",a.AnnotationProperty="AnnotationProperty",a.Instance="Instance",a.Datatype="Datatype",a.Unknown="Unknown",a))(me||{}),he=(i=>(i.InstanceOf="instanceOf",i.SubClassOf="subClassOf",i.Domain="domain",i.Range="range",i.ObjectRelationship="objectRelationship",i.SubPropertyOf="subPropertyOf",i.PropertyValue="propertyValue",i.EmbeddedLink="embeddedLink",i))(he||{}),V=class{static async buildFromRepository(n){let r=await new $().parseKanonaks(n),o=await n.getAllDocumentsAsync(),s=[],p=[],a=new Set,i=new Set,g=new Map;for(let c of r){let u=c;u.name&&(h.isClassType(u)&&a.add(u.name),(h.isObjectPropertyType(u)||h.isGenericPropertyType(u))&&i.add(u.name))}for(let c of o)for(let[u,f]of Object.entries(c.body))i.has(u)&&f?.range&&typeof f.range=="string"&&g.set(u,f.range);let d=new Map;for(let c of r){let u=c;u.name&&d.set(u.name,u)}for(let c of o){let u=c.metadata.namespace_,f=u?`${u.publisher}/${u.package_}`:"",l=u?.version?`${u.version.major}.${u.version.minor}.${u.version.patch}`:"",y=ge(c);for(let[k,m]of Object.entries(c.body)){if(!m||typeof m!="object")continue;let C=d.get(k),b="Unknown";if(C){let S=C;h.isClassType(S)?b="Class":h.isObjectPropertyType(S)?b="ObjectProperty":h.isDatatypePropertyType(S)?b="DatatypeProperty":h.isAnnotationPropertyType(S)?b="AnnotationProperty":h.isDatatypeType(S)?b="Datatype":h.isGenericPropertyType(S)?b="ObjectProperty":h.isInstanceOfKnownClass(S,a)&&(b="Instance")}let P=f&&l?`${f}/${k}@${l}`:k,X={};for(let[S,M]of Object.entries(m))S!=="type"&&(typeof M!="object"||M===null)&&(X[S]=M);s.push({id:P,label:m.label??k,type:b,namespace:f,properties:X}),ye(P,m,b,a,i,p,f,l,y),z(P,m,i,g,s,p,f,l,y),xe(P,C,p)}}return{nodes:s,edges:p}}static buildFromDocument(n){let t=[],r=[],o=n.metadata.namespace_,s=o?.version?`${o.version.major}.${o.version.minor}.${o.version.patch}`:"",p=o?`${o.publisher}/${o.package_}`:"",a=new Set,i=new Set,g=new Map,d=ge(n);for(let[f,l]of Object.entries(n.body)){let y=l?.type;y&&(Ne(y,d)&&a.add(f),$e(y,d)&&(i.add(f),l.range&&typeof l.range=="string"&&g.set(f,l.range)))}for(let[f,l]of Object.entries(n.body)){if(!l||typeof l!="object")continue;let y=l.type,k=Ke(y,f,a,d),m=p&&s?`${p}/${f}@${s}`:f,C={};for(let[b,P]of Object.entries(l))b!=="type"&&(typeof P!="object"||P===null)&&(C[b]=P);t.push({id:m,label:l.label??f,type:k,namespace:p,properties:C}),ye(m,l,k,a,i,r,p,s,d),z(m,l,i,g,t,r,p,s,d)}let c=new Set(t.map(f=>f.id)),u=r.filter(f=>c.has(f.source)&&c.has(f.target));return{nodes:t,edges:u}}};function ge(e,n){let t=new Map;if(e.metadata?.imports)for(let[r,o]of Object.entries(e.metadata.imports))for(let s of o){let p=s.alias??s.packageName,a=s.version,i=`${a.major}.${a.minor}.${a.patch}`;t.set(p,{publisher:r,package_:s.packageName,version:i})}return t}var ke={"kanonak.org/core-rdf/Class":"Class","kanonak.org/core-owl/Class":"Class","kanonak.org/core-rdfs/Class":"Class","kanonak.org/core-owl/ObjectProperty":"ObjectProperty","kanonak.org/core-owl/DatatypeProperty":"DatatypeProperty","kanonak.org/core-owl/AnnotationProperty":"AnnotationProperty","kanonak.org/core-rdf/Property":"ObjectProperty","kanonak.org/core-rdfs/Datatype":"Datatype"},Ie=new Set(["kanonak.org/core-owl/ObjectProperty","kanonak.org/core-owl/DatatypeProperty","kanonak.org/core-owl/AnnotationProperty","kanonak.org/core-rdf/Property"]);function B(e,n){if(e.includes(".")){let t=e.indexOf("."),r=e.substring(0,t),o=e.substring(t+1),s=n.get(r);if(s)return`${s.publisher}/${s.package_}/${o}`}return null}function Ne(e,n){let t=B(e,n);return t?ke[t]==="Class":!1}function $e(e,n){let t=B(e,n);return t?Ie.has(t):!1}function Ke(e,n,t,r){if(!e||e==="Package")return"Unknown";let o=B(e,r);if(o){let p=ke[o];if(p)return p;let a=o.split("/").pop()?.split("@")[0]??"";return t.has(a)?"Instance":"Unknown"}let s=e.split(".").pop()??e;return t.has(s)?"Instance":"Unknown"}var be=new Set(["type","label","comment","version","publisher","imports","license","match","alias","package"]);function ye(e,n,t,r,o,s,p,a,i){let g=n.type,d=n.subClassOf;if(d){let l=Array.isArray(d)?d:[d];for(let y of l)typeof y=="string"&&s.push({source:e,target:w(y,p,a,i),type:"subClassOf",label:"subClassOf"})}let c=n.subPropertyOf;if(c){let l=Array.isArray(c)?c:[c];for(let y of l)typeof y=="string"&&s.push({source:e,target:w(y,p,a,i),type:"subPropertyOf",label:"subPropertyOf"})}if(t==="Instance"&&g){let l=g.split(".").pop()??g;s.push({source:e,target:w(l,p,a,i),type:"instanceOf",label:"type"})}if(t==="Instance")for(let[l,y]of Object.entries(n)){if(be.has(l)||!o.has(l))continue;let k=Array.isArray(y)?y:[y];for(let m of k)typeof m=="string"&&De(m)&&s.push({source:e,target:w(m,p,a,i),type:"propertyValue",label:l,propertyId:w(l,p,a,i)})}let u=t==="ObjectProperty"||t==="DatatypeProperty",f=n.domain&&n.range;if((u||f)&&n.domain&&n.range){let l=typeof n.domain=="string"?n.domain:null,y=typeof n.range=="string"?n.range:null;l&&y&&s.push({source:w(l,p,a,i),target:w(y,p,a,i),type:"objectRelationship",label:n.label??e.split("/").pop()??"",propertyId:e})}}function z(e,n,t,r,o,s,p,a,i){for(let[g,d]of Object.entries(n)){if(be.has(g)||typeof d!="object"||d===null||Array.isArray(d))continue;let c=d,u=`${e}/${g}`,f=r.get(g),l=f?f.split(".").pop()??f:"Unknown",y={};for(let[m,C]of Object.entries(c))(typeof C!="object"||C===null)&&(y[m]=C);o.push({id:u,label:`${l} (embedded)`,type:"Instance",namespace:p,properties:y});let k=p&&a?`${p}/${g}@${a}`:g;s.push({source:e,target:u,type:"propertyValue",label:g,propertyId:t.has(g)?k:void 0}),f&&s.push({source:u,target:w(l,p,a,i),type:"instanceOf",label:"type (inferred)"}),z(u,c,t,r,o,s,p,a,i)}}function xe(e,n,t){let r=n?.statement;if(Array.isArray(r))for(let o of r){if(!(o instanceof ie))continue;let s=o.predicate?.subject?.name??"";for(let p of o.links){let a=p.target?.subject;if(!a)continue;let i=a.version,g=i&&typeof i.major=="number"?`@${i.major}.${i.minor}.${i.patch}`:"";t.push({source:e,target:`${a.publisher}/${a.package_}/${a.name}${g}`,type:"embeddedLink",label:s})}}}function De(e){return!(!e||e.includes(" ")||e.includes(`
|
|
2
|
+
`)||e.startsWith("http://")||e.startsWith("https://")||/^\d{4}-\d{2}/.test(e)||/^\d+(\.\d+)?$/.test(e))}function w(e,n,t,r){if(e.includes("@")&&e.includes("/"))return e;if(e.includes(".")){let o=e.indexOf("."),s=e.substring(0,o),p=e.substring(o+1);if(r){let a=r.get(s);if(a)return`${a.publisher}/${a.package_}/${p}@${a.version}`}return n&&t?`${n}/${p}@${t}`:p}return n&&t?`${n}/${e}@${t}`:e}function T(e){let n=e.replace(/^https?:\/\//,"").replace(/^git:\/\//,"").replace(/\/+$/,"").trim();if(!n)throw new Error("Publisher host cannot be empty");return n}var Me="key_thumbprint",_=class{cache=new Map;prCache=new Map;async discoverProtectedResource(n){let t=T(n);if(this.prCache.has(t))return this.prCache.get(t);let r=`https://${t}/.well-known/oauth-protected-resource`,o=await Ue(r),s=o&&Array.isArray(o.authorization_servers)?o.authorization_servers.filter(a=>typeof a=="string"):[],p=s.length>0?s:null;return this.prCache.set(t,p),p}async discover(n){let t=T(n);if(this.cache.has(t))return this.cache.get(t);let r=`https://${t}/.well-known/oauth-authorization-server`,o=await this.tryEndpoint(r);if(!o){let s=`https://${t}/.well-known/openid-configuration`;o=await this.tryEndpoint(s)}return this.cache.set(t,o),o}async supportsOAuth(n){return await this.discover(n)!==null}static supportsPkceS256(n){return n.codeChallengeMethodsSupported?.some(t=>t.toUpperCase()==="S256")??!1}static supportsDynamicRegistration(n){return!!n.registrationEndpoint}static supportsAuthorizationCode(n){return n.responseTypesSupported?.some(t=>t.toLowerCase()==="code")??!1}static supportsEnrollment(n){return!!n.enrollmentEndpoint}static supportsSession(n){return!!n.sessionEndpoint}async tryEndpoint(n){let t;try{t=await fetch(n)}catch(o){let s=o instanceof Error?o.message:String(o);return s.includes("ENOTFOUND")||s.includes("ECONNREFUSED")?(console.error(` OAuth discovery: ${n} \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: ${n} \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: ${n} \u2014 network error: ${s}`),null}if(!t.ok)return t.status===404||(t.status===403?(console.error(` OAuth discovery: ${n} \u2014 HTTP 403 Forbidden`),console.error(" Access may be blocked by a firewall, proxy, or WAF.")):t.status>=500&&(console.error(` OAuth discovery: ${n} \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: ${n} \u2014 response is not valid JSON`),console.error(" The endpoint may be returning HTML instead of JSON. Check IDP configuration."),null}return{issuer:v(r.issuer),authorizationEndpoint:v(r.authorization_endpoint),tokenEndpoint:v(r.token_endpoint),registrationEndpoint:v(r.registration_endpoint),revocationEndpoint:v(r.revocation_endpoint),scopesSupported:O(r.scopes_supported),responseTypesSupported:O(r.response_types_supported),grantTypesSupported:O(r.grant_types_supported),codeChallengeMethodsSupported:O(r.code_challenge_methods_supported),tokenEndpointAuthMethodsSupported:O(r.token_endpoint_auth_methods_supported),dpopSigningAlgValuesSupported:O(r.dpop_signing_alg_values_supported),enrollmentEndpoint:v(r.enrollment_endpoint),enrollmentIssuanceProtocols:O(r.enrollment_issuance_protocols),enrollmentKeyTypes:O(r.enrollment_key_types),enrollmentScopesSupported:O(r.enrollment_scopes_supported),enrollmentConsentBindingParam:v(r.enrollment_consent_binding_param),sessionEndpoint:v(r.session_endpoint),sessionEndpointAuthMethod:v(r.session_endpoint_auth_method)}}};async function Ue(e){try{let n=await fetch(e);return n.ok?await n.json():null}catch{return null}}function v(e){return typeof e=="string"?e:null}function O(e){return Array.isArray(e)?e.filter(n=>typeof n=="string"):null}function Ce(e){let n=e.headers.get("WWW-Authenticate")??void 0,t=e.headers.get("DPoP-Nonce")??void 0;if(!n&&!t)return;let r={wwwAuthenticate:n??""};if(t&&(r.nonce=t),n){let o=n.match(/acr_values\s*=\s*"([^"]*)"/i);o&&(r.acrValues=o[1])}return r}function Fe(e){try{return new URL(e).host}catch{return null}}function Le(e,n={}){let t=n.discovery??new _,r=new Map,o=new Map,s=async i=>{let g=r.get(i);if(g!==void 0)return g;let d=null,c=await t.discoverProtectedResource(i).catch(()=>null);return c&&c.length>0&&(d=Fe(c[0])),r.set(i,d),d},p=async(i,g)=>{if(!e)return null;if(!(g.forceRefresh||g.challenge)&&o.has(i))return o.get(i);let c=await e.resolve(i,g).catch(()=>null);return o.set(i,c),c},a=async(i,g,d,c)=>{let u=await s(g);if(!u)return{res:await U(i,{method:d,redirect:"manual"}),authed:!1};let f=await p(u,{method:d,url:i,...c}),l=f?.headers??{};return{res:await U(i,{method:d,redirect:"manual",headers:l}),authed:!!f}};return async(i,g,d="GET")=>{let c=await a(i,g,d,{});if((c.res.status===401||c.res.status===403)&&c.authed){let u=Ce(c.res),f={forceRefresh:u===void 0};return u&&(f.challenge=u),(await a(i,g,d,f)).res}return c.res}}var Se="KANONAK_TOKEN";function Ge(){return typeof process<"u"&&process.env?process.env:{}}function Ve(e){return`${Se}_${e.toUpperCase().replace(/[^A-Z0-9]+/g,"_")}`}var H=class{tokens;env;constructor(n={}){this.tokens=n.tokens??{},this.env=n.env??Ge()}async resolve(n,t){let r=T(n),o=this.tokens[r]??this.env[Ve(r)]??this.env[Se];return o?{headers:{Authorization:`Bearer ${o}`}}:null}};import{canonicalForm as ze,canonicalHash as Be}from"@kanonak-protocol/canonical";function q(e){return typeof e=="object"&&e!==null&&Array.isArray(e.subjects)}import{CANONICAL_FORM_VERSION as Qe}from"@kanonak-protocol/canonical";function He(e){return ze(q(e)?e:ve(e))}function qe(e){return Be(q(e)?e:ve(e))}function ve(e){let n=[];for(let t of e)t instanceof E&&n.push({uri:Je(t),statements:W(t.statement)});return{subjects:n}}function W(e){let n=[];for(let t of e){let r=Ye(t);if(!r)continue;let o=We(t);o&&n.push({predicate:r,value:o})}return n}function We(e){if(e instanceof ee&&e.carrier)return{lit:e.lexical??String(e.object),datatype:Pe(e.carrier)};if(e instanceof ne)return{raw:e.object};if(e instanceof te)return{raw:e.lexical??String(e.object)};if(e instanceof re)return{raw:e.lexical??String(e.object)};if(e instanceof oe)return{ref:we(e.object)};if(e instanceof se)return Oe(e.object);if(e instanceof ae)return{list:e.object.map(Xe)}}function Oe(e){let n=W(e.statement);return e.name&&e.name.length>0?{embed:{name:e.name,statements:n}}:{embed:{statements:n}}}function Xe(e){if(e instanceof R)return{ref:we(e)};if(e instanceof Q)return Oe(e);if(e instanceof A){if(e.carrier)return{lit:e.lexical??String(e.value),datatype:Pe(e.carrier)};let n=e.value;if(typeof n=="string")return{raw:n};if(typeof n=="number")return{raw:String(n)};if(typeof n=="boolean")return{raw:String(n)}}if(e instanceof J)return{embed:{statements:W(e.statement)}};throw new Error(`canonicalForm: list item of unrecognized kind (${e.constructor?.name??typeof e}); add canonicalization support before hashing data that contains it`)}function Pe(e){return e===G.LangString?"kanonak.org/core-rdf/langString":`kanonak.org/core-xsd/${e}`}function Ye(e){let n=e.predicate;if(n)return je(n.subject)}function Je(e){let n=e.namespace??"",t=e.name??"";return`${n}/${t}`}function we(e){return je(e.subject)}function je(e){let n=e.version;return n&&typeof n.major=="number"?`${e.publisher}/${e.package_}@${n.major}.${n.minor}.${n.patch}/${e.name}`:`${e.publisher}/${e.package_}/${e.name}`}var j="kanonak.org",D="core-rdf",Re="core-xsd",Te={publisher:j,package_:D,name:"subClassOf"},_e={publisher:j,package_:D,name:"label"},Ze={publisher:j,package_:D,name:"comment"},Ee={publisher:j,package_:"core-owl",name:"oneOf"},Ae=e=>e;function en(e){let n=pe(e,Te);if(n)return[n];let t=[];for(let r of L(e,Te))r instanceof R&&t.push(r.subject);return t}function nn(e,n,t){if(n.publisher===j&&n.package_===D&&n.name==="Literal")return{kind:"datatype",uri:n};let o=F(e,n);if(o){let s=Ae(o);if(h.isDatatypeType(s))return{kind:"datatype",uri:n};if(h.isClassType(s))return{kind:"class",uri:K(o)??n,localName:o.name}}return n.publisher===j&&n.package_===Re?{kind:"datatype",uri:n}:t==="datatype"?{kind:"datatype",uri:n}:{kind:"class",uri:n,localName:n.name}}function tn(e,n,t){if(!n.range)throw new Error(`Property ${n.uri.publisher}/${n.uri.package_}/${n.uri.name} has no rdfs.range; every property must declare a range. Validate the ontology before introspecting it.`);let r=nn(e,n.range,n.kind),o=n.kind==="object"?"object":n.kind==="datatype"?"datatype":r.kind==="class"?"object":"datatype";return{uri:n.uri,localName:n.uri.name,kind:o,range:r,...n.label!==void 0?{label:n.label}:{},...n.comment!==void 0?{comment:n.comment}:{},...t??{}}}var x=e=>new Z(j,Re,e);function rn(e){return typeof e=="boolean"?x("boolean"):typeof e=="number"?Number.isInteger(e)?x("integer"):x("decimal"):x("string")}function on(e,n){let t=[];for(let r of L(n,Ee))if(r instanceof R){let o=F(e,r.subject),s=(o?K(o):void 0)??r.subject,p=o?N(o,_e):void 0;t.push({kind:"individual",uri:s,localName:s.name,...p!==void 0?{label:p}:{}})}else r instanceof A&&t.push({kind:"literal",value:r.value,datatype:rn(r.value)});return t}function sn(e,n,t,r){let o=le(e,n),s=I(n);return ue(e,n).filter(a=>t?!0:a.domains.some(i=>I(i)===s)).map(a=>tn(e,a,fe(r,o,a.uri)))}async function an(e,n,t){let r=e.metadata?.namespace_;if(!r)throw new Error("buildOntologyModel: document has no namespace (publisher/package/version).");let o=t?.includeInherited??!1,s=await new $().parseKanonaks(n),p=de(s),a=[],i=[],g=new Set;for(let d of s){if(!(d instanceof E)||!h.isClassType(Ae(d)))continue;let c=K(d);if(!c||c.publisher!==r.publisher||c.package_!==r.package_||c.version&&r.version&&!Y(c.version,r.version))continue;let u=I(c);if(g.has(u))continue;g.add(u);let f=en(d).map(k=>({uri:k,localName:k.name})),l=N(d,_e),y=N(d,Ze);a.push({uri:c,localName:c.name,superClasses:f,properties:sn(s,c,o,p),...l!==void 0?{label:l}:{},...y!==void 0?{comment:y}:{}}),ce(d,Ee)&&i.push({uri:c,localName:c.name,members:on(s,d),...l!==void 0?{label:l}:{},...y!==void 0?{comment:y}:{}})}return{classes:a,enums:i}}export{me as a,he as b,V as c,T as d,Me as e,_ as f,Ce as g,Le as h,H as i,He as j,qe as k,Qe as l,an as m};
|
package/dist/index.d.ts
CHANGED
|
@@ -21,8 +21,8 @@ export type { IKanonakDocumentRepository } from '@kanonak-protocol/types/documen
|
|
|
21
21
|
export type { IKanonakParser } from '@kanonak-protocol/types/document/parsing';
|
|
22
22
|
export type { KanonakDocument, KanonakMetadata, Namespace, Import, Version, DocumentReference, ParseResult, ParseError } from '@kanonak-protocol/types/document/models/types';
|
|
23
23
|
export { VersionOperator } from '@kanonak-protocol/types/document/models/enums';
|
|
24
|
-
export {
|
|
25
|
-
export type {
|
|
24
|
+
export { OAuthDiscovery, DEFAULT_CONSENT_BINDING_PARAM, normalizeHost, createCredentialedFetch, parseAuthChallenge, TokenCredentialProvider, } from './auth/index.js';
|
|
25
|
+
export type { OAuthServerMetadata, AuthenticatedFetchFn, CredentialProvider, RequestCredential, AuthChallenge, ResolveOptions, CredentialedFetchDeps, TokenCredentialProviderOptions, } from './auth/index.js';
|
|
26
26
|
export { kanonakFetch, assertHttpsUrl, setKanonakFetchRetries, 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';
|
package/dist/index.js
CHANGED
|
@@ -1,102 +1 @@
|
|
|
1
|
-
import{a as Er,b as xr,c as Cr,d as Ar,e as ke}from"./chunk-TVSHIXLA.js";import{a as je,b as Me,c as Ve}from"./chunk-L2KE7B3K.js";import{a as Sn,c as ve,e as Le,h as Ue,i as Fe,j as vn}from"./chunk-IHB7UVEH.js";import{a as wr,b as br,c as Rr,d as Y,e as Q,f as l,g as Pn,h as Pe,i as wn,j as bn}from"./chunk-VOJ6BGAR.js";import{a as kn}from"./chunk-EZSHR3CB.js";import"./chunk-QHABFCRC.js";import{a as It,b as Nt,c as Bt,d as Ot,e as jt,f as Jt,g as qt,h as Xt,i as Zt}from"./chunk-CC44JAOT.js";import{a as Mt,b as Vt,c as Lt,d as Ut,e as A,f as Ft,h as Ht,j as zt,k as Gt}from"./chunk-UXYCUGSF.js";import{a as Kt}from"./chunk-4NO7MHS7.js";import{a as Tr,b as $r,c as _r,d as Kr}from"./chunk-S6VSAKXB.js";import{a as Ir,b as Lr}from"./chunk-PEUTCG3B.js";import{a as Br}from"./chunk-PEJALHXK.js";import{a as Wt}from"./chunk-SC5M74NM.js";import{A as yn,B as hn,K as gn,a as Ur,b as Fr,c as Hr,d as zr,e as Wr,f as Gr,g as Jr,h as qr,i as Xr,j as Zr,k as Yr,l as Qr,m as en,n as tn,o as rn,p as nn,q as on,r as sn,s as an,t as cn,u as ln,v as dn,w as pn,x as un,y as mn,z as fn}from"./chunk-7K5TAJ44.js";import"./chunk-ITKOKDBG.js";import{a as T,b as tr,c as dr,h as mr,i as fr,j as Sr,k as vr,l as U}from"./chunk-MX3DEXMV.js";import{a as j}from"./chunk-NJ3AZYQD.js";import{a as Pr,b as Se,c as Nr,d as P,e as Or,f as jr,g as Mr,h as Vr}from"./chunk-ZP6P7HNU.js";import{a as Oe}from"./chunk-6U26UASC.js";import{a as pr,b as ur,c as L,d as yr,e as hr,g as gr,k as kr}from"./chunk-GZPLWII7.js";import{a as Yt,b as Qt,c as D,d as M,e as rr,f as nr,g as or,h as sr,i as ir,j as ar,k as cr,l as lr,r as Z,w as V,x as he,y as ge}from"./chunk-7BHDZHJY.js";import{a as er}from"./chunk-FUUTGGJS.js";import{a as xt,b as ye,c as X,d as Ct,e as R,f as At,g as Dt,h as Tt,i as $t,j as _t}from"./chunk-2ACBWC7K.js";import{a as Dr}from"./chunk-ODIECDN7.js";import{VersionOperator as aa}from"@kanonak-protocol/types/document/models/enums";import{existsSync as zn,readFileSync as Wn}from"fs";import{homedir as Gn}from"os";import{join as Jn}from"path";import{execFile as Rn}from"child_process";import{promisify as En}from"util";var ee=En(Rn),xn="kanonak",te="/usr/bin/security",m=class{constructor(e=xn){this.service=e}service;async get(e){let t=l(e);try{let{stdout:r}=await ee(te,["find-generic-password","-s",this.service,"-a",t,"-w"],{timeout:1e4});try{return JSON.parse(r.trim())}catch{throw new Error(`Stored credential for '${t}' is corrupted (not valid JSON).
|
|
2
|
-
Run 'kanonak logout ${t}' then 'kanonak login ${t}' to fix.`)}}catch(r){if(He(r,44))return null;throw new Error(`macOS Keychain read failed for '${t}': ${re(r)}
|
|
3
|
-
The Keychain may be locked or inaccessible.
|
|
4
|
-
Try unlocking it via Keychain Access.app or running 'security unlock-keychain'.`)}}async store(e,t){let r=l(e),n=JSON.stringify(t);try{await ee(te,["add-generic-password","-s",this.service,"-a",r,"-U","-w",n],{timeout:1e4})}catch(s){throw new Error(`macOS Keychain write failed for '${r}': ${re(s)}
|
|
5
|
-
Ensure the Keychain is unlocked and the CLI has write permission.
|
|
6
|
-
On managed devices, your IT policy may block credential storage.`)}}async remove(e){let t=l(e);try{await ee(te,["delete-generic-password","-s",this.service,"-a",t],{timeout:1e4})}catch(r){if(He(r,44))return;console.warn(` Warning: macOS Keychain delete failed for '${t}': ${re(r)}
|
|
7
|
-
The credential may not have been fully removed.`)}}async list(){try{let{stdout:e}=await ee(te,["dump-keychain"],{timeout:1e4}),t=[],r=!1;for(let n of e.split(`
|
|
8
|
-
`))if(n.includes(`"svce"<blob>="${this.service}"`)&&(r=!0),r&&n.includes('"acct"<blob>=')){let s=n.match(/"acct"<blob>="([^"]+)"/);s&&t.push(s[1]),r=!1}return t}catch(e){return console.warn(` Warning: Could not enumerate Keychain entries: ${re(e)}`),[]}}};function He(o,e){return typeof o=="object"&&o!==null&&"code"in o&&o.code===e}function re(o){return o instanceof Error?o.message:String(o)}import{execFile as Cn}from"child_process";import{promisify as An}from"util";var Dn=An(Cn),Tn="kanonak:",ze=2560,f=class{constructor(e=Tn){this.targetPrefix=e}targetPrefix;async get(e){let t=this.targetPrefix+l(e),r=`
|
|
9
|
-
${oe}
|
|
10
|
-
$target = $env:KANONAK_CRED_TARGET
|
|
11
|
-
$ptr = [IntPtr]::Zero
|
|
12
|
-
$result = [CredMan]::CredRead($target, 1, 0, [ref]$ptr)
|
|
13
|
-
if (-not $result) { exit 1 }
|
|
14
|
-
try {
|
|
15
|
-
$cred = [System.Runtime.InteropServices.Marshal]::PtrToStructure($ptr, [Type][CredMan+CREDENTIAL])
|
|
16
|
-
$bytes = New-Object byte[] $cred.CredentialBlobSize
|
|
17
|
-
[System.Runtime.InteropServices.Marshal]::Copy($cred.CredentialBlob, $bytes, 0, $cred.CredentialBlobSize)
|
|
18
|
-
[System.Text.Encoding]::Unicode.GetString($bytes)
|
|
19
|
-
} finally {
|
|
20
|
-
[CredMan]::CredFree($ptr)
|
|
21
|
-
}`;try{let{stdout:n}=await ne(r,{KANONAK_CRED_TARGET:t}),s=n.trim();return s?JSON.parse(s):null}catch{return null}}async store(e,t){let r=this.targetPrefix+l(e),n=JSON.stringify(t),s=Buffer.byteLength(n,"utf16le");if(s>ze)throw new Error(`Credential '${r}' is ${s} bytes (UTF-16), over the Windows Credential Manager limit of ${ze} (CRED_MAX_CREDENTIAL_BLOB_SIZE). Keep only the secret here and store large/public material (certificates, chains) on disk.`);let i=`
|
|
22
|
-
${oe}
|
|
23
|
-
$target = $env:KANONAK_CRED_TARGET
|
|
24
|
-
$json = $env:KANONAK_CRED_JSON
|
|
25
|
-
$bytes = [System.Text.Encoding]::Unicode.GetBytes($json)
|
|
26
|
-
$cred = New-Object CredMan+CREDENTIAL
|
|
27
|
-
$cred.Type = 1
|
|
28
|
-
$cred.TargetName = $target
|
|
29
|
-
$cred.CredentialBlobSize = $bytes.Length
|
|
30
|
-
$cred.CredentialBlob = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($bytes.Length)
|
|
31
|
-
try {
|
|
32
|
-
[System.Runtime.InteropServices.Marshal]::Copy($bytes, 0, $cred.CredentialBlob, $bytes.Length)
|
|
33
|
-
$cred.Persist = 2
|
|
34
|
-
$result = [CredMan]::CredWrite([ref]$cred, 0)
|
|
35
|
-
if (-not $result) { throw "CredWrite failed (Win32 error $([System.Runtime.InteropServices.Marshal]::GetLastWin32Error()))" }
|
|
36
|
-
} finally {
|
|
37
|
-
[System.Runtime.InteropServices.Marshal]::FreeHGlobal($cred.CredentialBlob)
|
|
38
|
-
}`;try{await ne(i,{KANONAK_CRED_TARGET:r,KANONAK_CRED_JSON:n})}catch(a){let c=a,d=c.stderr&&c.stderr.trim()||c.message||String(a);throw new Error(`Windows Credential Manager write failed: ${d}`)}}async remove(e){let t=this.targetPrefix+l(e),r=`
|
|
39
|
-
${oe}
|
|
40
|
-
$target = $env:KANONAK_CRED_TARGET
|
|
41
|
-
[CredMan]::CredDelete($target, 1, 0) | Out-Null`;try{await ne(r,{KANONAK_CRED_TARGET:t})}catch{}}async list(){let e=`
|
|
42
|
-
${oe}
|
|
43
|
-
${$n}
|
|
44
|
-
$prefix = $env:KANONAK_CRED_PREFIX
|
|
45
|
-
$count = 0
|
|
46
|
-
$pCreds = [IntPtr]::Zero
|
|
47
|
-
# Filter by the namespace prefix as a wildcard (CredEnumerate flags=0). A $null
|
|
48
|
-
# filter would need CRED_ENUMERATE_ALL_CREDENTIALS, but PowerShell marshals a
|
|
49
|
-
# null string as "" so the API rejects it (ERROR_INVALID_FLAGS, 1004).
|
|
50
|
-
if ([CredMan]::CredEnumerate(($prefix + "*"), 0, [ref]$count, [ref]$pCreds)) {
|
|
51
|
-
$ptrSize = [System.Runtime.InteropServices.Marshal]::SizeOf([Type][IntPtr])
|
|
52
|
-
for ($i = 0; $i -lt $count; $i++) {
|
|
53
|
-
$credPtr = [System.Runtime.InteropServices.Marshal]::ReadIntPtr($pCreds, $i * $ptrSize)
|
|
54
|
-
$cred = [System.Runtime.InteropServices.Marshal]::PtrToStructure($credPtr, [Type][CredMan+CREDENTIAL])
|
|
55
|
-
if ($cred.TargetName -and $cred.TargetName.StartsWith($prefix)) {
|
|
56
|
-
$cred.TargetName.Substring($prefix.Length)
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
[CredMan]::CredFree($pCreds)
|
|
60
|
-
}`;try{let{stdout:t}=await ne(e,{KANONAK_CRED_PREFIX:this.targetPrefix});return t.trim().split(`
|
|
61
|
-
`).map(r=>r.trim()).filter(Boolean)}catch{return[]}}};async function ne(o,e){let t=Buffer.from(o,"utf16le").toString("base64");for(let r of["pwsh","powershell"])try{return await Dn(r,["-NoProfile","-NonInteractive","-EncodedCommand",t],{timeout:15e3,...e&&{env:{...process.env,...e}}})}catch(n){if(r==="powershell")throw n}throw new Error("Neither pwsh nor powershell found")}var oe=`
|
|
62
|
-
Add-Type -TypeDefinition @"
|
|
63
|
-
using System;
|
|
64
|
-
using System.Runtime.InteropServices;
|
|
65
|
-
public class CredMan {
|
|
66
|
-
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
|
|
67
|
-
public struct CREDENTIAL {
|
|
68
|
-
public int Flags;
|
|
69
|
-
public int Type;
|
|
70
|
-
public string TargetName;
|
|
71
|
-
public string Comment;
|
|
72
|
-
public long LastWritten;
|
|
73
|
-
public int CredentialBlobSize;
|
|
74
|
-
public IntPtr CredentialBlob;
|
|
75
|
-
public int Persist;
|
|
76
|
-
public int AttributeCount;
|
|
77
|
-
public IntPtr Attributes;
|
|
78
|
-
public string TargetAlias;
|
|
79
|
-
public string UserName;
|
|
80
|
-
}
|
|
81
|
-
[DllImport("Advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
|
|
82
|
-
public static extern bool CredRead(string target, int type, int flags, out IntPtr credential);
|
|
83
|
-
[DllImport("Advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
|
|
84
|
-
public static extern bool CredWrite(ref CREDENTIAL credential, int flags);
|
|
85
|
-
[DllImport("Advapi32.dll", SetLastError = true)]
|
|
86
|
-
public static extern bool CredDelete(string target, int type, int flags);
|
|
87
|
-
[DllImport("Advapi32.dll", SetLastError = true)]
|
|
88
|
-
public static extern void CredFree(IntPtr buffer);
|
|
89
|
-
[DllImport("Advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
|
|
90
|
-
public static extern bool CredEnumerate(string filter, int flags, out int count, out IntPtr credentials);
|
|
91
|
-
}
|
|
92
|
-
"@`,$n="";import{execFile as _n,spawn as Kn}from"child_process";import{promisify as In}from"util";var se=In(_n),Nn="kanonak",y=class{constructor(e=Nn){this.service=e}service;async get(e){let t=l(e);try{let{stdout:r}=await se("secret-tool",["lookup","service",this.service,"publisher",t],{timeout:1e4}),n=r.trim();return n?JSON.parse(n):null}catch{return null}}async store(e,t){let r=l(e),n=JSON.stringify(t);await new Promise((s,i)=>{let a=Kn("secret-tool",["store","--label",`Kanonak: ${r}`,"service",this.service,"publisher",r],{stdio:["pipe","ignore","ignore"],timeout:1e4});a.stdin.write(n),a.stdin.end(),a.on("close",c=>{c===0?s():i(new Error(`secret-tool store exited with code ${c}`))}),a.on("error",i)})}async remove(e){let t=l(e);try{await se("secret-tool",["clear","service",this.service,"publisher",t],{timeout:1e4})}catch{}}async list(){try{let{stdout:e}=await se("secret-tool",["search","service",this.service],{timeout:1e4}),t=[];for(let r of e.split(`
|
|
93
|
-
`)){let n=r.match(/attribute\.publisher\s*=\s*(.+)/);n&&t.push(n[1].trim())}return t}catch{return[]}}};async function E(){try{return await se("sh",["-c","command -v secret-tool"],{timeout:5e3}),!0}catch{return!1}}import{existsSync as We,mkdirSync as Ge,readFileSync as Je,writeFileSync as qe}from"fs";import{createCipheriv as Bn,createDecipheriv as On,randomBytes as Xe}from"crypto";import{homedir as jn}from"os";import{join as Re,dirname as Ze}from"path";var Qe=Re(jn(),".config","kanonak"),F=Re(Qe,"keyring.key"),Mn=Re(Qe,"credentials.enc"),Ye="aes-256-gcm",we=32,$=12,be=16,h=class{constructor(e=Mn){this.secretsFile=e}secretsFile;async get(e){let t=this.loadStore(),r=l(e);return t[r]??null}async store(e,t){let r=this.loadStore(),n=l(e);r[n]=t,this.saveStore(r)}async remove(e){let t=this.loadStore(),r=l(e);delete t[r],this.saveStore(t)}async list(){let e=this.loadStore();return Object.keys(e)}loadStore(){if(!We(this.secretsFile))return{};try{let e=this.getOrCreateKey(),t=Je(this.secretsFile);if(t.length<$+be)return{};let r=t.subarray(0,$),n=t.subarray($,$+be),s=t.subarray($+be),i=On(Ye,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=Xe($),n=Bn(Ye,t,r),s=Buffer.from(JSON.stringify(e),"utf-8"),i=Buffer.concat([n.update(s),n.final()]),a=n.getAuthTag(),c=Buffer.concat([r,a,i]);Ge(Ze(this.secretsFile),{recursive:!0}),qe(this.secretsFile,c,{mode:384})}getOrCreateKey(){if(We(F)){let t=Je(F);if(t.length!==we)throw new Error(`Credential keyring key is corrupted (expected ${we} bytes, got ${t.length}). Delete ${F} and re-authenticate.`);return t}let e=Xe(we);return Ge(Ze(F),{recursive:!0}),qe(F,e,{mode:384}),e}};import{execFile as Vn}from"child_process";import{promisify as Ln}from"util";var Un=Ln(Vn),et=3e4,H=class{constructor(e){this.helperPath=e}helperPath;async get(e){let t=l(e);try{let n=(await this.runHelper("get",{publisher:t})).trim();return n?JSON.parse(n):null}catch(r){throw new Error(`Credential helper '${this.helperPath}' failed to read credential for '${t}': ${ie(r)}
|
|
94
|
-
Verify the helper binary exists, is executable, and implements the Kanonak credential helper protocol.
|
|
95
|
-
Check the 'credentialHelper' path in ~/.kanonak/config.json.`)}}async store(e,t){let r=l(e);try{await this.runHelper("store",{publisher:r,credential:t})}catch(n){throw new Error(`Credential helper '${this.helperPath}' failed to store credential for '${r}': ${ie(n)}
|
|
96
|
-
Verify the helper binary supports the 'store' action.`)}}async remove(e){let t=l(e);try{await this.runHelper("erase",{publisher:t})}catch(r){console.warn(` Warning: Credential helper '${this.helperPath}' failed to erase credential for '${t}': ${ie(r)}`)}}async list(){try{let e=await this.runHelper("list",void 0);return JSON.parse(e.trim())}catch(e){return console.warn(` Warning: Credential helper '${this.helperPath}' failed to list credentials: ${ie(e)}`),[]}}async runHelper(e,t){try{let{stdout:r}=await Un(this.helperPath,[e],{...t&&{input:JSON.stringify(t)},timeout:et});return r}catch(r){throw Fn(r)?new Error(`Credential helper not found at '${this.helperPath}'.
|
|
97
|
-
Check the 'credentialHelper' path in ~/.kanonak/config.json.`):Hn(r)?new Error(`Credential helper '${this.helperPath}' timed out after ${et/1e3}s on '${e}'.
|
|
98
|
-
The helper may be waiting for authentication to an external vault.`):r}}};function ie(o){return o instanceof Error?o.message:String(o)}function Fn(o){return o instanceof Error&&"code"in o&&o.code==="ENOENT"}function Hn(o){return o instanceof Error&&"killed"in o&&o.killed}var Ee=Jn(Gn(),".kanonak","config.json"),ae=class{backend=null;backendReady=null;async getBackend(){if(this.backend)return this.backend;if(this.backendReady)return this.backendReady;this.backendReady=this.resolveBackend();try{return this.backend=await this.backendReady,this.backend}catch(e){throw this.backendReady=null,e}}async getToken(e){let t=qn(e);if(t)return t;let n=await(await this.getBackend()).get(e);return!n||!Q(n)?null:n.accessToken??null}async getCredential(e){return(await this.getBackend()).get(e)}async store(e,t){return(await this.getBackend()).store(e,t)}async remove(e){return(await this.getBackend()).remove(e)}async list(){return(await this.getBackend()).list()}async resolveBackend(){let e=Xn();return e.credentialHelper?new H(e.credentialHelper):process.platform==="darwin"?new m:process.platform==="win32"?new f:await E()?new y:new h}};function qn(o){let t="KANONAK_TOKEN_"+l(o).replace(/[.\-]/g,"_").toUpperCase();return process.env[t]??null}function Xn(){if(!zn(Ee))return{};try{return JSON.parse(Wn(Ee,"utf-8"))}catch(o){let e=o instanceof Error?o.message:String(o);return console.warn(` Warning: Failed to parse ${Ee}: ${e}
|
|
99
|
-
Using default credential backend. Fix the JSON syntax or delete the file.`),{}}}import{homedir as ot}from"os";import{join as x}from"path";import{mkdir as Zn,writeFile as tt,readFile as rt,rm as nt}from"fs/promises";var xe="kanonak-device",Yn=x(ot(),".config","kanonak","device-credentials.enc"),Qn=x(ot(),".kanonak","devices"),w=class{constructor(e={}){this.deps=e}deps;backend=null;backendReady=null;certDir(e){let t=l(e).replace(/[^a-zA-Z0-9._-]/g,"_");return x(this.deps.certBaseDir??Qn,t)}async getBackend(){if(this.backend)return this.backend;if(this.backendReady)return this.backendReady;this.backendReady=this.resolveBackend();try{return this.backend=await this.backendReady,this.backend}catch(e){throw this.backendReady=null,e}}async get(e){let t=await(await this.getBackend()).get(e);if(!t)return null;if(typeof t.certificatePem=="string"&&typeof t.chainPem=="string")return t;let r=this.certDir(e),n,s;try{n=await rt(x(r,"cert.pem"),"utf-8"),s=await rt(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 Zn(i,{recursive:!0}),await tt(x(i,"cert.pem"),r,"utf-8"),await tt(x(i,"chain.pem"),n,"utf-8");try{await(await this.getBackend()).store(e,s)}catch(a){throw await nt(i,{recursive:!0,force:!0}).catch(()=>{}),a}}async remove(e){await(await this.getBackend()).remove(e),await nt(this.certDir(e),{recursive:!0,force:!0})}async list(){return(await this.getBackend()).list()}async resolveBackend(){return this.deps.backend?this.deps.backend:process.platform==="darwin"?new m(xe):process.platform==="win32"?new f(`${xe}:`):await E()?new y(xe):new h(Yn)}};import{homedir as eo}from"os";import{join as to}from"path";var Ce="kanonak-session",ro=to(eo(),".config","kanonak","session-credentials.enc"),_=class{constructor(e={}){this.deps=e}deps;backend=null;backendReady=null;async getBackend(){if(this.backend)return this.backend;if(this.backendReady)return this.backendReady;this.backendReady=this.resolveBackend();try{return this.backend=await this.backendReady,this.backend}catch(e){throw this.backendReady=null,e}}async get(e){return(await this.getBackend()).get(e)}async store(e,t){return(await this.getBackend()).store(e,t)}async remove(e){return(await this.getBackend()).remove(e)}async list(){return(await this.getBackend()).list()}async resolveBackend(){return this.deps.backend?this.deps.backend:process.platform==="darwin"?new m(Ce):process.platform==="win32"?new f(`${Ce}:`):await E()?new y(Ce):new h(ro)}};function ce(o,e=5*6e4,t=Date.now()){let r=Date.parse(o.expiresAt);return Number.isNaN(r)?!0:t>=r-e}var st="key_thumbprint",b=class{cache=new Map;prCache=new Map;async discoverProtectedResource(e){let t=l(e);if(this.prCache.has(t))return this.prCache.get(t);let r=`https://${t}/.well-known/oauth-protected-resource`,n=await no(r),s=n&&Array.isArray(n.authorization_servers)?n.authorization_servers.filter(a=>typeof a=="string"):[],i=s.length>0?s:null;return this.prCache.set(t,i),i}async discover(e){let t=l(e);if(this.cache.has(t))return this.cache.get(t);let r=`https://${t}/.well-known/oauth-authorization-server`,n=await this.tryEndpoint(r);if(!n){let s=`https://${t}/.well-known/openid-configuration`;n=await this.tryEndpoint(s)}return this.cache.set(t,n),n}async supportsOAuth(e){return await this.discover(e)!==null}static supportsPkceS256(e){return e.codeChallengeMethodsSupported?.some(t=>t.toUpperCase()==="S256")??!1}static supportsDynamicRegistration(e){return!!e.registrationEndpoint}static supportsAuthorizationCode(e){return e.responseTypesSupported?.some(t=>t.toLowerCase()==="code")??!1}static supportsEnrollment(e){return!!e.enrollmentEndpoint}static supportsSession(e){return!!e.sessionEndpoint}async tryEndpoint(e){let t;try{t=await fetch(e)}catch(n){let s=n instanceof Error?n.message:String(n);return s.includes("ENOTFOUND")||s.includes("ECONNREFUSED")?(console.error(` OAuth discovery: ${e} \u2014 host unreachable (${s})`),console.error(" If the server is behind a VPN, ensure you are connected.")):s.includes("CERT")||s.includes("SSL")||s.includes("TLS")?(console.error(` OAuth discovery: ${e} \u2014 TLS error (${s})`),console.error(" If using a custom CA certificate, set NODE_EXTRA_CA_CERTS=/path/to/ca.pem")):console.error(` OAuth discovery: ${e} \u2014 network error: ${s}`),null}if(!t.ok)return t.status===404||(t.status===403?(console.error(` OAuth discovery: ${e} \u2014 HTTP 403 Forbidden`),console.error(" Access may be blocked by a firewall, proxy, or WAF.")):t.status>=500&&(console.error(` OAuth discovery: ${e} \u2014 HTTP ${t.status} server error`),console.error(" The authorization server returned an internal error. Contact your IDP administrator."))),null;let r;try{r=await t.json()}catch{return console.error(` OAuth discovery: ${e} \u2014 response is not valid JSON`),console.error(" The endpoint may be returning HTML instead of JSON. Check IDP configuration."),null}return{issuer:g(r.issuer),authorizationEndpoint:g(r.authorization_endpoint),tokenEndpoint:g(r.token_endpoint),registrationEndpoint:g(r.registration_endpoint),revocationEndpoint:g(r.revocation_endpoint),scopesSupported:k(r.scopes_supported),responseTypesSupported:k(r.response_types_supported),grantTypesSupported:k(r.grant_types_supported),codeChallengeMethodsSupported:k(r.code_challenge_methods_supported),tokenEndpointAuthMethodsSupported:k(r.token_endpoint_auth_methods_supported),dpopSigningAlgValuesSupported:k(r.dpop_signing_alg_values_supported),enrollmentEndpoint:g(r.enrollment_endpoint),enrollmentIssuanceProtocols:k(r.enrollment_issuance_protocols),enrollmentKeyTypes:k(r.enrollment_key_types),enrollmentScopesSupported:k(r.enrollment_scopes_supported),enrollmentConsentBindingParam:g(r.enrollment_consent_binding_param),sessionEndpoint:g(r.session_endpoint),sessionEndpointAuthMethod:g(r.session_endpoint_auth_method)}}};async function no(o){try{let e=await fetch(o);return e.ok?await e.json():null}catch{return null}}function g(o){return typeof o=="string"?o:null}function k(o){return Array.isArray(o)?o.filter(e=>typeof e=="string"):null}import*as it from"https";import{createPrivateKey as oo}from"crypto";var S=class extends Error{},K=class{constructor(e=ao){this.transport=e}transport;async exchange(e,t,r={}){let n=io(t.keyMaterial),s="{}",i;try{i=await this.transport({url:e,certPem:so(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 c=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+c*1e3).toISOString(),scope:typeof a.scope=="string"?a.scope:""}}};function so(o){let e=o.chainPem.trim();return e?`${o.certificatePem.replace(/\s+$/,"")}
|
|
100
|
-
${e}
|
|
101
|
-
`:o.certificatePem}function io(o){try{return oo({key:o,format:"jwk"}).export({type:"pkcs8",format:"pem"})}catch(e){throw new S(`The device key is not an exportable software private key, so it cannot present mTLS in software (a future hardware key provider would do the handshake itself): ${e.message}`)}}var ao=o=>new Promise((e,t)=>{let r=new URL(o.url),n=it.request({method:"POST",hostname:r.hostname,port:r.port||443,path:r.pathname+r.search,cert:o.certPem,key:o.keyPem,headers:{"Content-Type":o.contentType,"Content-Length":Buffer.byteLength(o.body),Accept:"application/json"},timeout:3e4},s=>{let i=[];s.on("data",a=>i.push(a)),s.on("end",()=>e({status:s.statusCode??0,body:Buffer.concat(i).toString("utf-8")}))});n.on("error",t),n.on("timeout",()=>n.destroy(new Error("mTLS request timed out"))),n.write(o.body),n.end()});var I=class extends Error{},N=class{discovery;deviceStore;sessionStore;exchange;constructor(e={}){this.discovery=e.discovery??new b,this.deviceStore=e.deviceStore??new w,this.sessionStore=e.sessionStore??new _,this.exchange=e.exchange??new K}async acquire(e){let t=l(e),r=await this.sessionEndpoint(e);if(!r)throw new I(`'${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 I(`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,t={}){let r=l(e),n=await this.sessionStore.get(r);return!t.forceRefresh&&n&&!ce(n)?n:!await this.sessionEndpoint(e)||!await this.deviceStore.get(e)?null:this.acquire(e)}async clear(e){await this.sessionStore.remove(l(e))}async sessionEndpoint(e){return(await this.discovery.discover(e))?.sessionEndpoint??null}};var le=class{discovery;sessions;devices;constructor(e={}){this.discovery=e.discovery??new b,this.sessions=e.sessionManager??new N({discovery:this.discovery}),this.devices=e.deviceStore??new w}async resolve(e,t={}){let r=await this.discovery.discoverProtectedResource(e);if(!r||r.length===0)return null;let n=r.map(co).filter(a=>a!==void 0);for(let a of n){let c=await this.sessionFor(a,t.forceRefresh);if(c)return c}let i=(await this.devices.list()).map(l).filter(a=>!n.includes(a));if(i.length===0)return null;for(let a of n){let c=(await this.discovery.discover(a))?.sessionEndpoint;if(c)for(let d of i){if((await this.discovery.discover(d))?.sessionEndpoint!==c)continue;let C=await this.sessionFor(d,t.forceRefresh);if(C)return C}}return null}async sessionFor(e,t=!1){let r=await this.sessions.getValidSession(e,{forceRefresh:t});return r?{authority:e,token:r.token,expiresAt:r.expiresAt,scope:r.scope}:null}};function co(o){try{return new URL(o).host}catch{return}}import{createHash as lo,createPrivateKey as po,generateKeyPairSync as uo,randomUUID as mo,sign as fo}from"crypto";function ct(){let{publicKey:o,privateKey:e}=uo("ec",{namedCurve:"P-256"});return{publicKey:o.export({format:"jwk"}),privateKey:e.export({format:"jwk"})}}function z(o,e,t,r,n,s){let i={alg:"ES256",typ:"dpop+jwt",jwk:{kty:e.kty,crv:e.crv,x:e.x,y:e.y}},a={jti:mo(),htm:t.toUpperCase(),htu:r,iat:Math.floor(Date.now()/1e3)};return n&&(a.ath=lo("sha256").update(n).digest("base64url")),s&&(a.nonce=s),yo(i,a,o)}function lt(o){return!o||o.length===0?!1:o.some(e=>e.toUpperCase()==="ES256")}function yo(o,e,t){let r=at(JSON.stringify(o)),n=at(JSON.stringify(e)),s=`${r}.${n}`,i=po({key:t,format:"jwk"}),c=fo("SHA256",Buffer.from(s),{key:i,dsaEncoding:"ieee-p1363"}).toString("base64url");return`${s}.${c}`}function at(o){return Buffer.from(o,"utf-8").toString("base64url")}function dt(o){let e=new Map;return async(t,r,n="GET")=>{if(!o)return A(t,{method:n});let s=await o.getCredential(r);if(!s?.accessToken)return A(t,{method:n});Y(s)&&console.warn(` Warning: Access token for '${r}' is expired. Run 'kanonak login ${r}' to re-authenticate.`);let i={};if(s.dpopKeyPair){let c=e.get(r);try{let d=z(s.dpopKeyPair.privateKey,s.dpopKeyPair.publicKey,n,t,s.accessToken,c);i.Authorization=`DPoP ${s.accessToken}`,i.DPoP=d}catch(d){let p=d instanceof Error?d.message:String(d);console.error(` Error: Failed to create DPoP proof for '${r}': ${p}
|
|
102
|
-
The stored key pair may be corrupted. Run 'kanonak login ${r}' to re-authenticate.`),i.Authorization=`Bearer ${s.accessToken}`}}else i.Authorization=`Bearer ${s.accessToken}`;let a=await A(t,{method:n,headers:i});if(a.status===401&&s.dpopKeyPair){let c=a.headers.get("DPoP-Nonce");if(c){e.set(r,c);try{let d=z(s.dpopKeyPair.privateKey,s.dpopKeyPair.publicKey,n,t,s.accessToken,c);i.DPoP=d,a=await A(t,{method:n,headers:i})}catch{}}}return a}}import*as Ae from"js-yaml";import{VersionOperator as pt}from"@kanonak-protocol/types/document/models/enums";var ho="0.0.0",B=class{constructor(e,t=new j,r){this.repository=e;this.parser=t;this.objectParser=r??new U(this.parser)}repository;parser;objectParser;imports(){return new W}serializeValue(e,t){return ft(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:mt(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:mt(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={[ut]:{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 Oe(s,this.repository))).filter(d=>d instanceof D&&d.namespace===i&&d.name!==ut);for(let d of c)d.namespace="ephemeral";return Pe(c)}},ut="__pkgbuilder_probe__";function mt(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=pt.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_,R(e.version),e.package_)}.${e.name}`}refLatest(e,t,r,n){return`${this.ensure(e,t,ho,n??t,pt.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:ye(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 ft(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=>ft(r,e)).filter(r=>r!==void 0);return t.length>0?t:void 0}if(o instanceof T)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(go(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 go(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}@${R(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",yt="core-kanonak",ko={publisher:u,package_:v,name:"rootView"},So={publisher:u,package_:v,name:"bind"},vo={publisher:u,package_:v,name:"produces"},Po={publisher:u,package_:v,name:"projections"},wo={publisher:u,package_:v,name:"where"},bo={publisher:u,package_:v,name:"value"},Ro={publisher:u,package_:v,name:"as"},ue=class{constructor(e,t=new j){this.repository=e;this.parser=t;this.objectParser=new U(this.parser),this.builder=new B(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,So);if(!s)throw new Error(`View ${n.namespace}/${n.name} declares no view.bind; cannot materialize.`);let i=V(n,vo);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=Eo(n),c=ht(r,u,yt),d=ht(r,u,v),p=this.builder.imports(),C=p.ensure(u,yt,c,"ck"),kt=p.ensure(u,v,d,"v"),St=p.ref(i),vt=new Fe(this.repository,this.parser,this.objectParser),_e=new Le(vt,r),Pt=this.readProjections(r,n),wt=Ao(n,wo),bt=this.findInstances(r,s,await this.reason(t)),Ke={},Rt=new Set;for(let q of bt){if(!await this.passesWhere(_e,r,wt,q))continue;let fe={type:St};for(let Ne of Pt){let Et=await this.evaluateValue(_e,r,Ne.value,q),Be=this.builder.serializeValue(gt(Et),p);Be!==void 0&&(fe[p.ref(Ne.as)]=Be)}let Ie=P(q);Ie&&(fe[`${kt}.derivedFrom`]=p.ref(Ie)),Ke[this.rowName(q,Rt)]=fe}let me={};t.resolvedAt&&(me[`${C}.resolvedAt`]=t.resolvedAt),t.invocationId&&(me[`${C}.id`]=t.invocationId);let O=await this.builder.buildContentAddressed({publisher:a,book:p,body:Ke,contentHashProperty:`${C}.contentHash`,header:me});return{yaml:O.yaml,contentHash:O.contentHash,packageName:O.packageName,publisher:O.publisher,rowCount:O.resourceCount}}resolveView(e,t){let r=Z(e,t);if(!r)throw new Error(`View ${t.publisher}/${t.package_}/${t.name} not found in the catalog.`);let n=V(r,ko);if(n){let s=Z(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,Po)){let s=n instanceof T?n:n instanceof M?Z(e,n.subject):void 0;if(!s)continue;let i=he(s,bo),a=V(s,Ro);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=Co(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(P(a)),p=L(P(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(!Do(i))return!1}return!0}async evaluateValue(e,t,r,n){let s=Ue(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 gt(o){return ve(o)?o.value:Array.isArray(o)?o.map(gt):o}function Eo(o){let e=P(o);if(!e)throw new Error(`Could not derive a publisher from view ${o.namespace}/${o.name}.`);return e.publisher}function ht(o,e,t){let r=xo(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 xo(o,e,t){let r;for(let n of o){if(!(n instanceof D))continue;let s=P(n);!s||s.publisher!==e||s.package_!==t||!s.version||(!r||X(s.version,r)>0)&&(r=s.version)}return r?R(r):void 0}function Co(o){let e=new Map,t=new Map;for(let r of o){if(!(r instanceof D))continue;let n=P(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 Ao(o,e){let t=he(o,e);return t?[t]:ge(o,e).filter(r=>r instanceof T)}function Do(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,wn as CANONICAL_FORM_VERSION,mr as Carrier,yn as ClassDefinitionRule,tn as ClassHierarchyCycleRule,Bt as CompositeKanonakDocumentRepository,le as CredentialResolver,ae as CredentialStore,st as DEFAULT_CONSENT_BINDING_PARAM,Qt as DefinedKanonak,w as DeviceCertificateStore,Nt as DocumentLocation,br as EdgeType,T as EmbeddedKanonak,Yr as EmbeddedKanonakTypeRule,cr as EmbeddedStatement,J as EntitlementDeniedError,pe as EntitlementProducer,It as FileSystemKanonakDocumentRepository,Dr as GitIgnoreFilter,Rr as GraphBuilder,Gt as HttpKanonakDocumentRepository,W as ImportBook,Qr as ImportExistenceRule,Kt as InMemoryKanonakDocumentRepository,Mt as KANONAK_USER_AGENT,Yt as Kanonak,$r as KanonakDocumentPositions,U as KanonakObjectParser,gn as KanonakObjectValidator,j as KanonakParser,er as KanonakUri,Ir as KanonakUriBuilder,Br 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,wr as NodeType,sr as NumberStatement,b as OAuthDiscovery,Cr as OWL_RL_CLASSIFICATION_RULES,pn as ObjectPropertyValueValidationRule,Hr as OntologyValidationError,Ur as OntologyValidationResult,B as PackageBuilder,Zr 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,jt as RepositoryFactory,fn as ReservedNameShadowRule,Jr as ResourceNamingRule,pr as ResourceResolver,Pr as ResourceTypeClassifier,nr as ScalarStatement,I as SessionError,K as SessionExchange,S as SessionExchangeError,N as SessionManager,_ as SessionStore,rr as Statement,or as StringStatement,on as SubClassOfReferenceRule,sn as SubPropertyOfReferenceRule,D as SubjectKanonak,Xr as SubjectKanonakTypeRequiredRule,Er as TripleStore,ur as TypeResolver,cn as UnresolvedPredicateRule,en as UnresolvedReferenceRule,Wr as ValidationCache,zr as ValidationContext,Fr as ValidationSeverity,aa as VersionOperator,ue as ViewMaterializer,Te as allowAllPolicy,Ut as assertHttpsUrl,Wt as assertPackageIdentity,Zt as buildLocalFirstRepository,bn as buildOntologyModel,Pn as canonicalForm,Pe as canonicalHash,fr as carrierOf,Xt as collectKanonakFiles,X as compareVersions,Ve as computeIntegrity,De as contentAddressedName,Vr as contextTypesOf,dt as createAuthenticatedFetch,z as createDPoPProof,At as createVersion,vr as extractMarkdownLinks,kn as findDerivation,Lr as findInstancesByType,Sr as findMalformedReferences,Kr as findMarkdownLinkAt,Nr as formatKanonakAddress,R as formatVersion,ct as generateDPoPKeyPair,Ot as getGlobalCachePath,Lt as getKanonakUserAgent,Q as hasValidToken,Tt as isCompatibleVersion,Y as isExpired,$t as isMajorCompatible,A as kanonakFetch,je as loadLockFile,yr as makeUriKey,$e as noopMeter,l as normalizeHost,Se as parseKanonakAddress,Dt as parseVersionString,_r as parseWithPositions,_t as pickHighestDocument,jr as propertiesInScope,Sn as resolveDisplayValue,Mr as resolvePropertyStep,G as sanitizeName,Me as saveLockFile,lt as serverSupportsDPoP,ce as sessionNeedsRefresh,Ft as setKanonakFetchRetries,Vt as setKanonakUserAgent,P as subjectUri,Or as superClassChain,hr as tripleKey,L as uriKey,gr as uriTriple,xt as versionOperatorFromChar,ye as versionOperatorToChar,Ct as versionsEqual};
|
|
1
|
+
import{a as br,b as Rr,c as wr,d as Er,e as N}from"./chunk-TVSHIXLA.js";import{a as Y,b as ee,c as re}from"./chunk-L2KE7B3K.js";import{a as bn,c as B,e as ne,h as te,i as oe,j as Rn}from"./chunk-IHB7UVEH.js";import{a as gr,b as hr,c as Pr,d as mn,e as yn,f as fn,g as kn,h as gn,i as hn,j as wn,k as F,l as En,m as xn}from"./chunk-CZXHGAJV.js";import{a as Pn}from"./chunk-EZSHR3CB.js";import"./chunk-QHABFCRC.js";import{a as Ve,b as je,c as Ae,d as Ce,e as Se,f as Te,g as ze,h as He,i as We}from"./chunk-CC44JAOT.js";import{a as De,b as Ue,c as Oe,d as _e,e as Me,f as $e,h as Ne,j as Le,k as Fe}from"./chunk-UXYCUGSF.js";import{a as ve}from"./chunk-4NO7MHS7.js";import{a as Kr,b as Ir,c as vr,d as Vr}from"./chunk-S6VSAKXB.js";import{a as jr,b as _r}from"./chunk-PEUTCG3B.js";import{a as Cr}from"./chunk-PEJALHXK.js";import{a as Be}from"./chunk-SC5M74NM.js";import{A as un,B as ln,K as dn,a as Mr,b as $r,c as Nr,d as Lr,e as Br,f as Fr,g as Tr,h as zr,i as Hr,j as Wr,k as qr,l as Gr,m as Jr,n as Zr,o as Qr,p as Xr,q as Yr,r as en,s as rn,t as nn,u as tn,v as on,w as an,x as sn,y as cn,z as pn}from"./chunk-7K5TAJ44.js";import"./chunk-ITKOKDBG.js";import{a as k,b as Ze,c as ar,h as cr,i as pr,j as yr,k as fr,l as E}from"./chunk-MX3DEXMV.js";import{a as P}from"./chunk-NJ3AZYQD.js";import{a as kr,b as L,c as Ar,d as m,e as Sr,f as Dr,g as Ur,h as Or}from"./chunk-ZP6P7HNU.js";import{a as X}from"./chunk-6U26UASC.js";import{a as ir,b as sr,c as w,d as ur,e as lr,g as dr,k as mr}from"./chunk-GZPLWII7.js";import{a as qe,b as Ge,c as f,d as b,e as Qe,f as Xe,g as Ye,h as er,i as rr,j as nr,k as tr,l as or,r as j,w as R,x as M,y as $}from"./chunk-7BHDZHJY.js";import{a as Je}from"./chunk-FUUTGGJS.js";import{a as be,b as _,c as V,d as Re,e as y,f as we,g as Ee,h as xe,i as Ke,j as Ie}from"./chunk-2ACBWC7K.js";import{a as xr}from"./chunk-ODIECDN7.js";import{VersionOperator as _t}from"@kanonak-protocol/types/document/models/enums";import*as T from"js-yaml";import{VersionOperator as ae}from"@kanonak-protocol/types/document/models/enums";var Kn="0.0.0",g=class{constructor(e,r=new P,n){this.repository=e;this.parser=r;this.objectParser=n??new E(this.parser)}repository;parser;objectParser;imports(){return new x}serializeValue(e,r){return ce(e,r)}async buildContentAddressed(e){let r=e.book.toImports(),n=await this.hashBody(e.publisher,r,e.body),t=z(n),a={type:"EphemeralPackage",publisher:e.publisher,imports:r};e.contentHashProperty&&(a[e.contentHashProperty]=n),Object.assign(a,e.header??{}),a.imports=r;let i={[t]:a,...e.body},s=this.dump(i);return{yaml:s,byteCount:se(s),contentHash:n,packageName:t,publisher:e.publisher,resourceCount:Object.keys(e.body).length}}async buildNamed(e){let r=e.book.toImports(),n={type:e.type??"Package",publisher:e.publisher,version:e.version,imports:r},t;e.contentHashProperty&&(t=await this.hashBody(e.publisher,r,e.body),n[e.contentHashProperty]=t),Object.assign(n,e.header??{}),n.imports=r;let a={[e.name]:n,...e.body},i=this.dump(a),s={yaml:i,byteCount:se(i),packageName:e.name,publisher:e.publisher,resourceCount:Object.keys(e.body).length};return t!==void 0&&(s.contentHash=t),s}dump(e){return T.dump(e,{lineWidth:-1})}async hashBody(e,r,n){let t={[ie]:{type:"EphemeralPackage",publisher:e,imports:r},...n},a=this.parser.parse(T.dump(t,{lineWidth:-1})),i=a.metadata.namespace_?.toString(),c=(await this.objectParser.parseKanonaks(new X(a,this.repository))).filter(u=>u instanceof f&&u.namespace===i&&u.name!==ie);for(let u of c)u.namespace="ephemeral";return F(c)}},ie="__pkgbuilder_probe__";function se(o){return new TextEncoder().encode(o).length}function z(o){let e="sha256:",r=o.startsWith(e)?e.length:0;return`q-${o.slice(r,r+16)}`}var x=class{byKey=new Map;aliases=new Set;ensure(e,r,n,t,a=ae.Major){let i=`${e}/${r}@${n}`,s=this.byKey.get(i);if(s)return s.alias;let c=this.uniqueAlias(t);return this.byKey.set(i,{publisher:e,package_:r,version:n,alias:c,match:a}),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_,y(e.version),e.package_)}.${e.name}`}refLatest(e,r,n,t){return`${this.ensure(e,r,Kn,t??r,ae.Any)}.${n}`}toImports(){let e=new Map;for(let n of this.byKey.values()){let t=e.get(n.publisher)??[];t.push(n),e.set(n.publisher,t)}return[...e.keys()].sort().map(n=>({publisher:n,packages:e.get(n).sort((t,a)=>t.package_<a.package_?-1:1).map(t=>({package:t.package_,match:_(t.match),version:t.version,alias:t.alias}))}))}uniqueAlias(e){let r=K(e)||"pkg",n=r,t=2;for(;this.aliases.has(n);)n=`${r}${t++}`;return this.aliases.add(n),n}};function ce(o,e){if(o!=null){if(typeof o=="string"||typeof o=="number"||typeof o=="boolean")return o;if(o instanceof b)return e.ref(o.subject);if(Array.isArray(o)){let r=o.map(n=>ce(n,e)).filter(n=>n!==void 0);return r.length>0?r:void 0}if(o instanceof k)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(In(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 K(o){return o.replace(/[^A-Za-z0-9-]/g,"-").replace(/-+/g,"-").replace(/^-|-$/g,"")}function In(o){return typeof o=="object"&&o!==null&&typeof o.publisher=="string"&&typeof o.package_=="string"&&typeof o.name=="string"}var A=class{constructor(e){this.producers=e}producers;produced=new Map;producerFor(e,r){return this.producers.find(n=>n.canProduce(e,r))}async produceCached(e,r,n,t){let a=`${r}/${n}@${y(t)}`,i=this.produced.get(a);if(i)return i;let{document:s}=await e.produce(r,n,t);return this.produced.set(a,s),s}async getHighestCompatibleVersionAsync(e,r){let n=this.producerFor(e,r.packageName);if(!n)return null;let t={operator:r.versionOperator,version:r.version},a=await n.resolveVersion(e,r.packageName,t);return a?this.produceCached(n,e,r.packageName,a):null}async getDocumentAsync(e){let r;try{r=L(e)}catch{return null}if(r.kind!=="package"||!r.version)return null;let n=this.producerFor(r.publisher,r.package_);return n?this.produceCached(n,r.publisher,r.package_,r.version):null}async getDocumentsByNamespaceAsync(e,r){return Array.from(this.produced.values()).filter(n=>{let t=n.metadata.namespace_;return t!=null&&t.publisher===e&&t.package_===r})}async getAllDocumentsAsync(){return Array.from(this.produced.values())}async saveDocumentAsync(e,r){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,r){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 H={async authorize(){return{allowed:!0}}},W={async record(){}},I=class extends Error{constructor(r,n){let t=`${r.publisher}/${r.package_}${r.version?`@${r.version.major}.${r.version.minor}.${r.version.patch}`:""}`;super(`Not entitled to produce ${t}${n?`: ${n}`:""}`);this.address=r;this.reason=n;this.name="EntitlementDeniedError"}address;reason},C=class{inner;ctx;policy;meter;constructor(e,r,n=H,t=W){this.inner=e,this.ctx=r,this.policy=n,this.meter=t}canProduce(e,r){return this.inner.canProduce(e,r)}async resolveVersion(e,r,n){return await this.assertAllowed({publisher:e,package_:r,version:n.version}),this.inner.resolveVersion(e,r,n)}async produce(e,r,n){let t={publisher:e,package_:r,version:n};await this.assertAllowed(t);let a=await this.inner.produce(e,r,n);return await this.meter.record(this.ctx,t,a),a}async assertAllowed(e){let r=await this.policy.authorize(this.ctx,e);if(!r.allowed)throw new I(e,r.reason)}};var p="kanonak.org",d="view",pe="core-kanonak",vn={publisher:p,package_:d,name:"rootView"},Vn={publisher:p,package_:d,name:"bind"},jn={publisher:p,package_:d,name:"produces"},An={publisher:p,package_:d,name:"projections"},Cn={publisher:p,package_:d,name:"where"},Sn={publisher:p,package_:d,name:"value"},Dn={publisher:p,package_:d,name:"as"},S=class{constructor(e,r=new P){this.repository=e;this.parser=r;this.objectParser=new E(this.parser),this.builder=new g(this.repository,this.parser,this.objectParser)}repository;parser;objectParser;builder;async materialize(e,r={}){let n=await this.objectParser.parseKanonaks(this.repository),t=this.resolveView(n,e),a=R(t,Vn);if(!a)throw new Error(`View ${t.namespace}/${t.name} declares no view.bind; cannot materialize.`);let i=R(t,jn);if(!i)throw new Error(`View ${t.namespace}/${t.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 s=Un(t),c=ue(n,p,pe),u=ue(n,p,d),l=this.builder.imports(),D=l.ensure(p,pe,c,"ck"),de=l.ensure(p,d,u,"v"),me=l.ref(i),ye=new oe(this.repository,this.parser,this.objectParser),q=new ne(ye,n),fe=this.readProjections(n,t),ke=Mn(t,Cn),ge=this.findInstances(n,a,await this.reason(r)),G={},he=new Set;for(let v of ge){if(!await this.passesWhere(q,n,ke,v))continue;let O={type:me};for(let Z of fe){let Pe=await this.evaluateValue(q,n,Z.value,v),Q=this.builder.serializeValue(le(Pe),l);Q!==void 0&&(O[l.ref(Z.as)]=Q)}let J=m(v);J&&(O[`${de}.derivedFrom`]=l.ref(J)),G[this.rowName(v,he)]=O}let U={};r.resolvedAt&&(U[`${D}.resolvedAt`]=r.resolvedAt),r.invocationId&&(U[`${D}.id`]=r.invocationId);let h=await this.builder.buildContentAddressed({publisher:s,book:l,body:G,contentHashProperty:`${D}.contentHash`,header:U});return{yaml:h.yaml,contentHash:h.contentHash,packageName:h.packageName,publisher:h.publisher,rowCount:h.resourceCount}}resolveView(e,r){let n=j(e,r);if(!n)throw new Error(`View ${r.publisher}/${r.package_}/${r.name} not found in the catalog.`);let t=R(n,vn);if(t){let a=j(e,t);if(!a)throw new Error(`ViewPackage ${r.name} names rootView ${t.name}, which is not in the catalog.`);return a}return n}readProjections(e,r){let n=[];for(let t of $(r,An)){let a=t instanceof k?t:t instanceof b?j(e,t.subject):void 0;if(!a)continue;let i=M(a,Sn),s=R(a,Dn);i&&s&&n.push({value:i,as:s})}return n}async reason(e){return new N({profile:e.reasoningProfile??"owl-rl-classification"}).reason(this.repository)}findInstances(e,r,n){let t=_n(e),a=[],i=new Set;for(let s of n.getInstancesOfClass(r)){if(i.has(s))continue;i.add(s);let c=t.get(s);c&&a.push(c)}return a.sort((s,c)=>{let u=w(m(s)),l=w(m(c));return u<l?-1:u>l?1:0}),a}async passesWhere(e,r,n,t){for(let a of n){let i=await this.evaluateValue(e,r,a,t);if(!$n(i))return!1}return!0}async evaluateValue(e,r,n,t){let a=te(n,"view-projection",{catalog:r,depth:0}),i=new Map([["input",t]]);return e.evaluate(a,i)}rowName(e,r){let n=K(e.name)||"row",t=n,a=2;for(;r.has(t);)t=`${n}-${a++}`;return r.add(t),t}};function le(o){return B(o)?o.value:Array.isArray(o)?o.map(le):o}function Un(o){let e=m(o);if(!e)throw new Error(`Could not derive a publisher from view ${o.namespace}/${o.name}.`);return e.publisher}function ue(o,e,r){let n=On(o,e,r);if(!n)throw new Error(`Package ${e}/${r} is not in the catalog; it must be importable to materialize a view.`);return n}function On(o,e,r){let n;for(let t of o){if(!(t instanceof f))continue;let a=m(t);!a||a.publisher!==e||a.package_!==r||!a.version||(!n||V(a.version,n)>0)&&(n=a.version)}return n?y(n):void 0}function _n(o){let e=new Map,r=new Map;for(let n of o){if(!(n instanceof f))continue;let t=m(n);if(!t||!t.version)continue;let a=w(t),i=r.get(a);(!i||V(t.version,i)>0)&&(r.set(a,t.version),e.set(a,n))}return e}function Mn(o,e){let r=M(o,e);return r?[r]:$(o,e).filter(n=>n instanceof k)}function $n(o){return o===!0?!0:o===!1||o===void 0||o===null?!1:typeof o=="string"?o.length>0:typeof o=="number"?o!==0:B(o)?o.value.length>0:Array.isArray(o)?o.length>0:!!o}export{tn as AmbiguousReferenceRule,rr as BooleanStatement,En as CANONICAL_FORM_VERSION,cr as Carrier,un as ClassDefinitionRule,Zr as ClassHierarchyCycleRule,Ae as CompositeKanonakDocumentRepository,yn as DEFAULT_CONSENT_BINDING_PARAM,Ge as DefinedKanonak,je as DocumentLocation,hr as EdgeType,k as EmbeddedKanonak,qr as EmbeddedKanonakTypeRule,tr as EmbeddedStatement,I as EntitlementDeniedError,C as EntitlementProducer,Ve as FileSystemKanonakDocumentRepository,xr as GitIgnoreFilter,Pr as GraphBuilder,Fe as HttpKanonakDocumentRepository,x as ImportBook,Gr as ImportExistenceRule,ve as InMemoryKanonakDocumentRepository,De as KANONAK_USER_AGENT,qe as Kanonak,Ir as KanonakDocumentPositions,E as KanonakObjectParser,dn as KanonakObjectValidator,P as KanonakParser,Je as KanonakUri,jr as KanonakUriBuilder,Cr as KanonakUrlResolver,mr as KanonakVocabulary,or as ListStatement,Ze as LiteralKanonak,Te as LocalFirstRepository,ze as LockAwareRepository,Rn as LookRenderer,ln as MarkdownLinkRule,ar as MarkdownStatement,rn as NamespaceImportCycleRule,Fr as NamespacePrefixRule,gr as NodeType,er as NumberStatement,fn as OAuthDiscovery,wr as OWL_RL_CLASSIFICATION_RULES,an as ObjectPropertyValueValidationRule,Nr as OntologyValidationError,Mr as OntologyValidationResult,g as PackageBuilder,Wr as PackageHeaderRule,A as ProducerRepository,sn as PropertyDomainRule,Qr as PropertyHierarchyCycleRule,cn as PropertyKindRangeConsistencyRule,Kr as PropertyMetadata,on as PropertyRangeReferenceRule,Xr as PropertyRangeRequiredRule,zr as PropertyTypeSpecificityRule,Ne as PublisherConfigResolver,Le as PublisherIndex,Rr as RDFS_RULES,N as Reasoner,Er as ReasoningResult,b as ReferenceKanonak,nr as ReferenceStatement,Se as RepositoryFactory,pn as ReservedNameShadowRule,Tr as ResourceNamingRule,ir as ResourceResolver,kr as ResourceTypeClassifier,Xe as ScalarStatement,Qe as Statement,Ye as StringStatement,Yr as SubClassOfReferenceRule,en as SubPropertyOfReferenceRule,f as SubjectKanonak,Hr as SubjectKanonakTypeRequiredRule,hn as TokenCredentialProvider,br as TripleStore,sr as TypeResolver,nn as UnresolvedPredicateRule,Jr as UnresolvedReferenceRule,Br as ValidationCache,Lr as ValidationContext,$r as ValidationSeverity,_t as VersionOperator,S as ViewMaterializer,H as allowAllPolicy,_e as assertHttpsUrl,Be as assertPackageIdentity,We as buildLocalFirstRepository,xn as buildOntologyModel,wn as canonicalForm,F as canonicalHash,pr as carrierOf,He as collectKanonakFiles,V as compareVersions,re as computeIntegrity,z as contentAddressedName,Or as contextTypesOf,gn as createCredentialedFetch,we as createVersion,fr as extractMarkdownLinks,Pn as findDerivation,_r as findInstancesByType,yr as findMalformedReferences,Vr as findMarkdownLinkAt,Ar as formatKanonakAddress,y as formatVersion,Ce as getGlobalCachePath,Oe as getKanonakUserAgent,xe as isCompatibleVersion,Ke as isMajorCompatible,Me as kanonakFetch,Y as loadLockFile,ur as makeUriKey,W as noopMeter,mn as normalizeHost,kn as parseAuthChallenge,L as parseKanonakAddress,Ee as parseVersionString,vr as parseWithPositions,Ie as pickHighestDocument,Dr as propertiesInScope,bn as resolveDisplayValue,Ur as resolvePropertyStep,K as sanitizeName,ee as saveLockFile,$e as setKanonakFetchRetries,Ue as setKanonakUserAgent,m as subjectUri,Sr as superClassChain,lr as tripleKey,w as uriKey,dr as uriTriple,be as versionOperatorFromChar,_ as versionOperatorToChar,Re as versionsEqual};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kanonak-protocol/sdk",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.11.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.11.0",
|
|
130
130
|
"ignore": "^7.0.5",
|
|
131
131
|
"js-yaml": "^4.1.0",
|
|
132
132
|
"yaml": "^2.7.0"
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import type { CredentialStore } from './CredentialStore.js';
|
|
2
|
-
/**
|
|
3
|
-
* A fetch function that adds authentication headers for a publisher.
|
|
4
|
-
* Accepts an optional method parameter for correct DPoP proof generation.
|
|
5
|
-
*/
|
|
6
|
-
export type AuthenticatedFetchFn = (url: string, publisher: string, method?: string) => Promise<Response>;
|
|
7
|
-
/**
|
|
8
|
-
* Create an authenticated fetch function that adds Bearer or DPoP
|
|
9
|
-
* authorization headers based on stored credentials.
|
|
10
|
-
*/
|
|
11
|
-
export declare function createAuthenticatedFetch(credentialStore?: CredentialStore): AuthenticatedFetchFn;
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Pluggable secure-storage backend: JSON values of type `T` keyed by a
|
|
3
|
-
* normalized host, in a platform-specific secure store (OS keychain, encrypted
|
|
4
|
-
* file, enterprise vault). The same backend implementations serve different
|
|
5
|
-
* record types under different namespaces — OAuth credentials
|
|
6
|
-
* ({@link StoredCredential}) and device enrollments — so the storage mechanism
|
|
7
|
-
* is written once and reused.
|
|
8
|
-
*/
|
|
9
|
-
export interface SecretBackend<T> {
|
|
10
|
-
get(publisher: string): Promise<T | null>;
|
|
11
|
-
store(publisher: string, value: T): Promise<void>;
|
|
12
|
-
remove(publisher: string): Promise<void>;
|
|
13
|
-
list(): Promise<string[]>;
|
|
14
|
-
}
|
|
15
|
-
/**
|
|
16
|
-
* The OAuth credential storage backend — a {@link SecretBackend} whose records
|
|
17
|
-
* are {@link StoredCredential}. Kept as a named alias so existing consumers and
|
|
18
|
-
* the `CredentialStore` are unchanged.
|
|
19
|
-
*/
|
|
20
|
-
export type CredentialBackend = SecretBackend<StoredCredential>;
|
|
21
|
-
/**
|
|
22
|
-
* OAuth credential stored per publisher host.
|
|
23
|
-
* Matches the OAuthCredentialStore types from @kanonak-protocol/types.
|
|
24
|
-
*/
|
|
25
|
-
export interface StoredCredential {
|
|
26
|
-
clientId?: string | null;
|
|
27
|
-
clientSecret?: string | null;
|
|
28
|
-
accessToken?: string | null;
|
|
29
|
-
refreshToken?: string | null;
|
|
30
|
-
expiresAt?: string | null;
|
|
31
|
-
tokenEndpoint?: string | null;
|
|
32
|
-
dpopKeyPair?: DPoPKeyPair | null;
|
|
33
|
-
}
|
|
34
|
-
export interface DPoPKeyPair {
|
|
35
|
-
publicKey: Record<string, unknown>;
|
|
36
|
-
privateKey: Record<string, unknown>;
|
|
37
|
-
}
|
|
38
|
-
export declare function isExpired(credential: StoredCredential): boolean;
|
|
39
|
-
export declare function hasValidToken(credential: StoredCredential): boolean;
|
|
40
|
-
export declare function normalizeHost(host: string): string;
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import type { SecretBackend, StoredCredential } from './CredentialBackend.js';
|
|
2
|
-
/**
|
|
3
|
-
* External credential helper backend.
|
|
4
|
-
* Delegates to an enterprise-configured binary using a stdin/stdout JSON protocol.
|
|
5
|
-
*
|
|
6
|
-
* Configure in ~/.kanonak/config.json:
|
|
7
|
-
* { "credentialHelper": "/usr/local/bin/kanonak-credential-vault" }
|
|
8
|
-
*/
|
|
9
|
-
export declare class CredentialHelperBackend<T = StoredCredential> implements SecretBackend<T> {
|
|
10
|
-
private readonly helperPath;
|
|
11
|
-
constructor(helperPath: string);
|
|
12
|
-
get(publisher: string): Promise<T | null>;
|
|
13
|
-
store(publisher: string, value: T): Promise<void>;
|
|
14
|
-
remove(publisher: string): Promise<void>;
|
|
15
|
-
list(): Promise<string[]>;
|
|
16
|
-
private runHelper;
|
|
17
|
-
}
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
import { type OAuthServerMetadata } from './OAuthDiscovery.js';
|
|
2
|
-
import type { SessionRecord } from './SessionStore.js';
|
|
3
|
-
/**
|
|
4
|
-
* The durable host→credential primitive (issue #72): given any registry/repo
|
|
5
|
-
* host, resolve a freshly-valid credential, or decline. This is the engine the
|
|
6
|
-
* git credential helper is one consumer of; any other client (or a downstream
|
|
7
|
-
* package-manager adapter) builds on the same primitive instead of reimplementing
|
|
8
|
-
* the auth.
|
|
9
|
-
*
|
|
10
|
-
* Fully discovery-driven, per host:
|
|
11
|
-
* host --RFC 9728 protected-resource metadata--> authorization server(s)
|
|
12
|
-
* authority --device session (refreshed from the cert)--> a fresh token
|
|
13
|
-
* The session is keyed by the AUTHORITY and reused across every resource host
|
|
14
|
-
* that points at it. When the advertised authority itself isn't enrolled, an
|
|
15
|
-
* enrollment in the same trust plane still serves it (issue #75): per-account
|
|
16
|
-
* authority hosts (`oauth--{account}.{tenant}`) are consent surfaces over one
|
|
17
|
-
* tenant-level trust plane, and that identity is proven by the servers' own
|
|
18
|
-
* RFC 8414 documents — an advertised authority whose `session_endpoint` equals
|
|
19
|
-
* an enrolled authority's `session_endpoint` mints at the same place with the
|
|
20
|
-
* same CA-signed cert, so the enrollment applies. No host-string heuristics:
|
|
21
|
-
* a different tenant advertises a different `session_endpoint`, so enrolling
|
|
22
|
-
* per tenant remains the trust boundary. Returns null when the host advertises
|
|
23
|
-
* no authority (not a Kanonak resource) or no enrollment serves its authority.
|
|
24
|
-
*/
|
|
25
|
-
/** A resolved registry credential. `token` is the credential (presented as a
|
|
26
|
-
* Bearer token, or as the HTTP Basic password); there is no identity here. */
|
|
27
|
-
export interface ResolvedCredential {
|
|
28
|
-
/** The authorization-server host the credential is scoped to. */
|
|
29
|
-
authority: string;
|
|
30
|
-
/** The session token — the credential. */
|
|
31
|
-
token: string;
|
|
32
|
-
/** ISO timestamp the underlying session expires. */
|
|
33
|
-
expiresAt: string;
|
|
34
|
-
/** Space-delimited consented scope. */
|
|
35
|
-
scope: string;
|
|
36
|
-
}
|
|
37
|
-
export interface CredentialResolverDeps {
|
|
38
|
-
discovery?: {
|
|
39
|
-
discoverProtectedResource(host: string): Promise<string[] | null>;
|
|
40
|
-
/** RFC 8414 metadata — the `session_endpoint` proves trust-plane identity (#75). */
|
|
41
|
-
discover(host: string): Promise<OAuthServerMetadata | null>;
|
|
42
|
-
};
|
|
43
|
-
sessionManager?: {
|
|
44
|
-
getValidSession(host: string, opts?: {
|
|
45
|
-
forceRefresh?: boolean;
|
|
46
|
-
}): Promise<SessionRecord | null>;
|
|
47
|
-
};
|
|
48
|
-
/** The enrolled-authority hosts on this device — the trust-plane candidates (#75). */
|
|
49
|
-
deviceStore?: {
|
|
50
|
-
list(): Promise<string[]>;
|
|
51
|
-
};
|
|
52
|
-
}
|
|
53
|
-
export declare class CredentialResolver {
|
|
54
|
-
private readonly discovery;
|
|
55
|
-
private readonly sessions;
|
|
56
|
-
private readonly devices;
|
|
57
|
-
constructor(deps?: CredentialResolverDeps);
|
|
58
|
-
/** Resolve a fresh credential for `host`, or null to decline. `forceRefresh`
|
|
59
|
-
* re-mints the session from the cert (recovery when a cached token was revoked
|
|
60
|
-
* server-side — a caller learns this from a 401 on a resource read). */
|
|
61
|
-
resolve(host: string, opts?: {
|
|
62
|
-
forceRefresh?: boolean;
|
|
63
|
-
}): Promise<ResolvedCredential | null>;
|
|
64
|
-
private sessionFor;
|
|
65
|
-
}
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import type { CredentialBackend, StoredCredential } from './CredentialBackend.js';
|
|
2
|
-
/**
|
|
3
|
-
* Credential store orchestrator.
|
|
4
|
-
* Selects the appropriate backend based on platform and configuration.
|
|
5
|
-
*
|
|
6
|
-
* Resolution order:
|
|
7
|
-
* 1. KANONAK_TOKEN_{PUBLISHER} environment variable (CI/CD)
|
|
8
|
-
* 2. Credential helper binary (enterprise vaults)
|
|
9
|
-
* 3. OS credential store (macOS Keychain / Windows CredMan / Linux Secret Service)
|
|
10
|
-
* 4. Encrypted file fallback (headless Linux / containers)
|
|
11
|
-
*/
|
|
12
|
-
export declare class CredentialStore {
|
|
13
|
-
private backend;
|
|
14
|
-
private backendReady;
|
|
15
|
-
getBackend(): Promise<CredentialBackend>;
|
|
16
|
-
/**
|
|
17
|
-
* Get an access token for a publisher.
|
|
18
|
-
* Checks env vars first, then the credential backend.
|
|
19
|
-
*/
|
|
20
|
-
getToken(publisher: string): Promise<string | null>;
|
|
21
|
-
/**
|
|
22
|
-
* Get the full stored credential (including DPoP key pair).
|
|
23
|
-
*/
|
|
24
|
-
getCredential(publisher: string): Promise<StoredCredential | null>;
|
|
25
|
-
store(publisher: string, credential: StoredCredential): Promise<void>;
|
|
26
|
-
remove(publisher: string): Promise<void>;
|
|
27
|
-
list(): Promise<string[]>;
|
|
28
|
-
private resolveBackend;
|
|
29
|
-
}
|
package/dist/auth/DPoP.d.ts
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import type { DPoPKeyPair } from './CredentialBackend.js';
|
|
2
|
-
/**
|
|
3
|
-
* DPoP (Demonstrating Proof-of-Possession) implementation per RFC 9449.
|
|
4
|
-
* Binds access tokens to a cryptographic key pair so stolen tokens
|
|
5
|
-
* are unusable without the private key.
|
|
6
|
-
*
|
|
7
|
-
* All crypto uses Node.js built-in modules — no external dependencies.
|
|
8
|
-
*/
|
|
9
|
-
/**
|
|
10
|
-
* Generate an ephemeral EC P-256 key pair for DPoP.
|
|
11
|
-
* Returns keys in JWK format for storage in the credential store.
|
|
12
|
-
*/
|
|
13
|
-
export declare function generateDPoPKeyPair(): DPoPKeyPair;
|
|
14
|
-
/**
|
|
15
|
-
* Create a DPoP proof JWT for an HTTP request.
|
|
16
|
-
*
|
|
17
|
-
* @param privateKeyJwk - The private key in JWK format
|
|
18
|
-
* @param publicKeyJwk - The public key in JWK format (included in JWT header)
|
|
19
|
-
* @param method - HTTP method (e.g., "GET", "POST")
|
|
20
|
-
* @param url - Target URL
|
|
21
|
-
* @param accessToken - If present, the access token hash is included (ath claim)
|
|
22
|
-
* @param nonce - Server-provided DPoP nonce (from DPoP-Nonce header)
|
|
23
|
-
*/
|
|
24
|
-
export declare function createDPoPProof(privateKeyJwk: Record<string, unknown>, publicKeyJwk: Record<string, unknown>, method: string, url: string, accessToken?: string, nonce?: string): string;
|
|
25
|
-
/**
|
|
26
|
-
* Check if an OAuth server supports DPoP by inspecting its metadata.
|
|
27
|
-
*/
|
|
28
|
-
export declare function serverSupportsDPoP(dpopSigningAlgValues?: string[] | null): boolean;
|
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
import type { SecretBackend } from './CredentialBackend.js';
|
|
2
|
-
import { normalizeHost } from './CredentialBackend.js';
|
|
3
|
-
/**
|
|
4
|
-
* A device certificate enrollment, persisted per registry host (issue #67).
|
|
5
|
-
*
|
|
6
|
-
* The record holds the device-held key material, the CA-signed certificate, and
|
|
7
|
-
* the consent context. In v1 the key is a software key (its private JWK lives in
|
|
8
|
-
* `keyMaterial`); a future hardware {@link KeyProvider} stores an opaque handle
|
|
9
|
-
* here instead, so the secure store never holds an exportable key. Either way the
|
|
10
|
-
* record is opaque JSON to the storage backend.
|
|
11
|
-
*/
|
|
12
|
-
export interface DeviceEnrollmentRecord {
|
|
13
|
-
/** Software provider: the private key JWK. Hardware provider: an opaque key handle. */
|
|
14
|
-
keyMaterial: Record<string, unknown>;
|
|
15
|
-
/** RFC 7638 JWK SHA-256 thumbprint of the device public key — the consent-bound identity. */
|
|
16
|
-
thumbprint: string;
|
|
17
|
-
/** The CA-signed leaf certificate (PEM). */
|
|
18
|
-
certificatePem: string;
|
|
19
|
-
/** The issuing chain (PEM, possibly empty). */
|
|
20
|
-
chainPem: string;
|
|
21
|
-
/** ISO timestamp the certificate was issued/installed. */
|
|
22
|
-
issuedAt: string;
|
|
23
|
-
/** ISO timestamp the certificate expires, or null if unknown. */
|
|
24
|
-
expiresAt: string | null;
|
|
25
|
-
/** The scopes consented at enrollment. */
|
|
26
|
-
scopes: string[];
|
|
27
|
-
/** A human-facing device label shown on the consent screen. */
|
|
28
|
-
deviceName?: string;
|
|
29
|
-
/**
|
|
30
|
-
* The PUBLISHER the user connected/enrolled through (e.g. `paul.kanonak.com`).
|
|
31
|
-
* Enrollments are keyed by the AUTHORITY (e.g. `oauth--paul.kanonak.com`), but
|
|
32
|
-
* users only know the publisher — this records it so `device list`/`show`/
|
|
33
|
-
* `remove` can be publisher-centric (display it, and resolve a publisher to its
|
|
34
|
-
* enrollment locally without a network round-trip). Optional: records written
|
|
35
|
-
* before this field, or by a non-publisher enroll, won't carry it.
|
|
36
|
-
*/
|
|
37
|
-
publisher?: string;
|
|
38
|
-
}
|
|
39
|
-
/**
|
|
40
|
-
* The portion of a {@link DeviceEnrollmentRecord} kept in the platform-secure
|
|
41
|
-
* backend: the device KEY material and small metadata — everything EXCEPT the
|
|
42
|
-
* certificate + chain PEMs. Those are PUBLIC (not secrets) and large (a leaf +
|
|
43
|
-
* two CA PEMs ≈ 3–5 KB of text, ≈ 6–10 KB UTF-16), which overflows the Windows
|
|
44
|
-
* Credential Manager `CRED_MAX_CREDENTIAL_BLOB_SIZE` (2560 bytes) — so they go to
|
|
45
|
-
* disk instead (#69). cert/chain are typed optional only to read records written
|
|
46
|
-
* by the pre-split layout (backward compatibility); `store` never writes them.
|
|
47
|
-
*/
|
|
48
|
-
type StoredDeviceRecord = Omit<DeviceEnrollmentRecord, 'certificatePem' | 'chainPem'> & Partial<Pick<DeviceEnrollmentRecord, 'certificatePem' | 'chainPem'>>;
|
|
49
|
-
/** Test seam: inject an in-memory backend and a scratch cert dir. */
|
|
50
|
-
export interface DeviceCertificateStoreDeps {
|
|
51
|
-
backend?: SecretBackend<StoredDeviceRecord>;
|
|
52
|
-
certBaseDir?: string;
|
|
53
|
-
}
|
|
54
|
-
/**
|
|
55
|
-
* Persists {@link DeviceEnrollmentRecord}s in the same platform-secure stores as
|
|
56
|
-
* OAuth credentials, but under a separate `kanonak-device` namespace so the two
|
|
57
|
-
* never collide (separate Keychain service / Credential Manager target prefix /
|
|
58
|
-
* Secret Service attribute / encrypted file). Mirrors {@link CredentialStore}'s
|
|
59
|
-
* backend selection; the external credential-helper backend is intentionally not
|
|
60
|
-
* used for device certs in v1 (device enrollment is a first-party flow).
|
|
61
|
-
*
|
|
62
|
-
* This is a Node-only module (it reaches OS keystores) and is deliberately not
|
|
63
|
-
* exported from the SDK browser entry.
|
|
64
|
-
*/
|
|
65
|
-
export declare class DeviceCertificateStore {
|
|
66
|
-
private readonly deps;
|
|
67
|
-
private backend;
|
|
68
|
-
private backendReady;
|
|
69
|
-
constructor(deps?: DeviceCertificateStoreDeps);
|
|
70
|
-
/** Per-host on-disk directory for the (public) certificate + chain PEMs. */
|
|
71
|
-
private certDir;
|
|
72
|
-
getBackend(): Promise<SecretBackend<StoredDeviceRecord>>;
|
|
73
|
-
get(host: string): Promise<DeviceEnrollmentRecord | null>;
|
|
74
|
-
store(host: string, record: DeviceEnrollmentRecord): Promise<void>;
|
|
75
|
-
remove(host: string): Promise<void>;
|
|
76
|
-
list(): Promise<string[]>;
|
|
77
|
-
private resolveBackend;
|
|
78
|
-
}
|
|
79
|
-
/** Re-exported for callers that namespace device records themselves. */
|
|
80
|
-
export { normalizeHost };
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import type { SecretBackend, StoredCredential } from './CredentialBackend.js';
|
|
2
|
-
/**
|
|
3
|
-
* Encrypted file secret backend.
|
|
4
|
-
* Fallback for headless Linux, containers, and CI environments
|
|
5
|
-
* where no OS keyring is available. The secrets file is namespaced (OAuth
|
|
6
|
-
* credentials in `credentials.enc`, device enrollments in `device-credentials.enc`)
|
|
7
|
-
* so the two stores never collide; both are sealed with the same per-user key.
|
|
8
|
-
*
|
|
9
|
-
* - Key: ~/.config/kanonak/keyring.key (random 32 bytes, mode 0600)
|
|
10
|
-
* - Secrets: a per-namespace AES-256-GCM encrypted JSON file
|
|
11
|
-
*/
|
|
12
|
-
export declare class EncryptedFileBackend<T = StoredCredential> implements SecretBackend<T> {
|
|
13
|
-
private readonly secretsFile;
|
|
14
|
-
constructor(secretsFile?: string);
|
|
15
|
-
get(publisher: string): Promise<T | null>;
|
|
16
|
-
store(publisher: string, value: T): Promise<void>;
|
|
17
|
-
remove(publisher: string): Promise<void>;
|
|
18
|
-
list(): Promise<string[]>;
|
|
19
|
-
private loadStore;
|
|
20
|
-
private saveStore;
|
|
21
|
-
private getOrCreateKey;
|
|
22
|
-
}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import type { SecretBackend, StoredCredential } from './CredentialBackend.js';
|
|
2
|
-
/**
|
|
3
|
-
* macOS Keychain secret backend.
|
|
4
|
-
* Stores records via the `security` CLI tool (no native modules). The Keychain
|
|
5
|
-
* `service` namespaces the store, so OAuth credentials (`kanonak`) and device
|
|
6
|
-
* enrollments (`kanonak-device`) live side by side without colliding.
|
|
7
|
-
*/
|
|
8
|
-
export declare class KeychainBackend<T = StoredCredential> implements SecretBackend<T> {
|
|
9
|
-
private readonly service;
|
|
10
|
-
constructor(service?: string);
|
|
11
|
-
get(publisher: string): Promise<T | null>;
|
|
12
|
-
store(publisher: string, value: T): Promise<void>;
|
|
13
|
-
remove(publisher: string): Promise<void>;
|
|
14
|
-
list(): Promise<string[]>;
|
|
15
|
-
}
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import type { SecretBackend, StoredCredential } from './CredentialBackend.js';
|
|
2
|
-
/**
|
|
3
|
-
* Linux Secret Service backend (GNOME Keyring / KDE Wallet).
|
|
4
|
-
* Uses the `secret-tool` CLI from libsecret-tools.
|
|
5
|
-
*
|
|
6
|
-
* Each record is stored with attributes:
|
|
7
|
-
* service = the namespace ("kanonak" for OAuth, "kanonak-device" for device certs)
|
|
8
|
-
* publisher = normalized publisher host
|
|
9
|
-
*
|
|
10
|
-
* All interactions use execFile (no shell) to prevent command injection.
|
|
11
|
-
* The store() method uses spawn with stdin piping since secret-tool
|
|
12
|
-
* reads the secret value from stdin.
|
|
13
|
-
*/
|
|
14
|
-
export declare class SecretServiceBackend<T = StoredCredential> implements SecretBackend<T> {
|
|
15
|
-
private readonly service;
|
|
16
|
-
constructor(service?: string);
|
|
17
|
-
get(publisher: string): Promise<T | null>;
|
|
18
|
-
store(publisher: string, value: T): Promise<void>;
|
|
19
|
-
remove(publisher: string): Promise<void>;
|
|
20
|
-
list(): Promise<string[]>;
|
|
21
|
-
}
|
|
22
|
-
/**
|
|
23
|
-
* Check if secret-tool is available on the system.
|
|
24
|
-
*/
|
|
25
|
-
export declare function hasSecretTool(): Promise<boolean>;
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import type { DeviceEnrollmentRecord } from './DeviceCertificateStore.js';
|
|
2
|
-
/** A cert→session exchange result, normalized (the OAuth token response). */
|
|
3
|
-
export interface ExchangedSession {
|
|
4
|
-
token: string;
|
|
5
|
-
tokenType: string;
|
|
6
|
-
/** ISO timestamp the session expires (now + expires_in). */
|
|
7
|
-
expiresAt: string;
|
|
8
|
-
scope: string;
|
|
9
|
-
}
|
|
10
|
-
/**
|
|
11
|
-
* mTLS transport: POST `body` to `url` presenting the client cert/key.
|
|
12
|
-
* `certPem` is the full client chain (leaf first, then any issuing
|
|
13
|
-
* intermediates) ready to hand to the TLS stack; the server certificate is
|
|
14
|
-
* verified against the platform's default trust store (issue #74 — the client
|
|
15
|
-
* issuance chain must never be used as the server-verification CA).
|
|
16
|
-
* Injectable so the exchange unit-tests without a live mTLS endpoint —
|
|
17
|
-
* the same seam {@link NativeIssuanceClient} uses for the enrollment HTTP.
|
|
18
|
-
*/
|
|
19
|
-
export type MtlsTransport = (req: {
|
|
20
|
-
url: string;
|
|
21
|
-
certPem: string;
|
|
22
|
-
keyPem: string;
|
|
23
|
-
body: string;
|
|
24
|
-
contentType: string;
|
|
25
|
-
}) => Promise<{
|
|
26
|
-
status: number;
|
|
27
|
-
body: string;
|
|
28
|
-
}>;
|
|
29
|
-
export declare class SessionExchangeError extends Error {
|
|
30
|
-
}
|
|
31
|
-
export declare class SessionExchange {
|
|
32
|
-
private readonly transport;
|
|
33
|
-
constructor(transport?: MtlsTransport);
|
|
34
|
-
/** Exchange the device cert in `record` for a scoped session at `sessionEndpoint`. */
|
|
35
|
-
exchange(sessionEndpoint: string, record: DeviceEnrollmentRecord, opts?: {
|
|
36
|
-
nowMs?: number;
|
|
37
|
-
}): Promise<ExchangedSession>;
|
|
38
|
-
}
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
import { type DeviceEnrollmentRecord } from './DeviceCertificateStore.js';
|
|
2
|
-
import { SessionStore, type SessionRecord } from './SessionStore.js';
|
|
3
|
-
import { type OAuthServerMetadata } from './OAuthDiscovery.js';
|
|
4
|
-
import { SessionExchange } from './SessionExchange.js';
|
|
5
|
-
/**
|
|
6
|
-
* Owns the device-cert → scoped-session lifecycle (issue #72): discover the
|
|
7
|
-
* `session_endpoint`, exchange the enrolled cert for a session over mTLS, cache
|
|
8
|
-
* it, and refresh it from the cert (the durable credential) as it nears expiry —
|
|
9
|
-
* the AWS-STS auto-refresh model. Everything is per registry host; a public host
|
|
10
|
-
* advertises no `session_endpoint`, so {@link getValidSession} returns null for
|
|
11
|
-
* it and nothing is attached.
|
|
12
|
-
*/
|
|
13
|
-
export interface SessionDiscovery {
|
|
14
|
-
discover(host: string): Promise<OAuthServerMetadata | null>;
|
|
15
|
-
}
|
|
16
|
-
export interface DeviceStoreLike {
|
|
17
|
-
get(host: string): Promise<DeviceEnrollmentRecord | null>;
|
|
18
|
-
}
|
|
19
|
-
export interface SessionManagerDeps {
|
|
20
|
-
discovery?: SessionDiscovery;
|
|
21
|
-
deviceStore?: DeviceStoreLike;
|
|
22
|
-
sessionStore?: SessionStore;
|
|
23
|
-
exchange?: SessionExchange;
|
|
24
|
-
}
|
|
25
|
-
export declare class SessionError extends Error {
|
|
26
|
-
}
|
|
27
|
-
export declare class SessionManager {
|
|
28
|
-
private readonly discovery;
|
|
29
|
-
private readonly deviceStore;
|
|
30
|
-
private readonly sessionStore;
|
|
31
|
-
private readonly exchange;
|
|
32
|
-
constructor(deps?: SessionManagerDeps);
|
|
33
|
-
/**
|
|
34
|
-
* Obtain a fresh session for `host`: discover → mTLS exchange → store. Throws a
|
|
35
|
-
* {@link SessionError} with an actionable message if the host issues no
|
|
36
|
-
* sessions or this device isn't enrolled there. For the explicit command path.
|
|
37
|
-
*/
|
|
38
|
-
acquire(host: string): Promise<SessionRecord>;
|
|
39
|
-
/**
|
|
40
|
-
* A valid session for `host` — the cached one if still fresh, otherwise
|
|
41
|
-
* re-exchanged from the device cert. Returns null (rather than throwing) when
|
|
42
|
-
* the host issues no sessions or this device isn't enrolled there, so callers
|
|
43
|
-
* can attach a credential only where one exists (public hosts get none). A
|
|
44
|
-
* refresh that genuinely fails (network/server) propagates.
|
|
45
|
-
*
|
|
46
|
-
* `forceRefresh` skips the local cache and re-mints from the cert — the
|
|
47
|
-
* recovery path when a cached token isn't expired but the SERVER has revoked
|
|
48
|
-
* it (e.g. re-enrollment, deleted certs), which a caller learns only from a
|
|
49
|
-
* 401 on a resource read.
|
|
50
|
-
*/
|
|
51
|
-
getValidSession(host: string, opts?: {
|
|
52
|
-
forceRefresh?: boolean;
|
|
53
|
-
}): Promise<SessionRecord | null>;
|
|
54
|
-
/** Forget the cached session for `host`. */
|
|
55
|
-
clear(host: string): Promise<void>;
|
|
56
|
-
private sessionEndpoint;
|
|
57
|
-
}
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
import type { SecretBackend } from './CredentialBackend.js';
|
|
2
|
-
import { normalizeHost } from './CredentialBackend.js';
|
|
3
|
-
/**
|
|
4
|
-
* A scoped session obtained by exchanging an enrolled device certificate at a
|
|
5
|
-
* registry's `session_endpoint` (issue #72). AWS-STS-shaped: the device cert is
|
|
6
|
-
* the durable credential, this is the short-lived, scoped, refreshable one. The
|
|
7
|
-
* `token` is the universal registry credential — presented as a Bearer token or
|
|
8
|
-
* as the password half of HTTP Basic, depending on the package manager.
|
|
9
|
-
*/
|
|
10
|
-
export interface SessionRecord {
|
|
11
|
-
/** The session token — the universal registry credential. */
|
|
12
|
-
token: string;
|
|
13
|
-
/** OAuth `token_type`, e.g. "Bearer". */
|
|
14
|
-
tokenType: string;
|
|
15
|
-
/** ISO timestamp the session expires. */
|
|
16
|
-
expiresAt: string;
|
|
17
|
-
/** Space-delimited consented scope, as the exchange returned it. */
|
|
18
|
-
scope: string;
|
|
19
|
-
}
|
|
20
|
-
/** Test seam: inject an in-memory backend. */
|
|
21
|
-
export interface SessionStoreDeps {
|
|
22
|
-
backend?: SecretBackend<SessionRecord>;
|
|
23
|
-
}
|
|
24
|
-
/**
|
|
25
|
-
* Persists {@link SessionRecord}s per registry host in the same platform-secure
|
|
26
|
-
* stores as OAuth credentials and device enrollments, under a separate
|
|
27
|
-
* `kanonak-session` namespace so the three never collide. A session is small
|
|
28
|
-
* (a token + metadata), so unlike the device cert it needs no on-disk split.
|
|
29
|
-
*
|
|
30
|
-
* Node-only (it reaches OS keystores); deliberately not exported from the SDK
|
|
31
|
-
* browser entry.
|
|
32
|
-
*/
|
|
33
|
-
export declare class SessionStore {
|
|
34
|
-
private readonly deps;
|
|
35
|
-
private backend;
|
|
36
|
-
private backendReady;
|
|
37
|
-
constructor(deps?: SessionStoreDeps);
|
|
38
|
-
getBackend(): Promise<SecretBackend<SessionRecord>>;
|
|
39
|
-
get(host: string): Promise<SessionRecord | null>;
|
|
40
|
-
store(host: string, record: SessionRecord): Promise<void>;
|
|
41
|
-
remove(host: string): Promise<void>;
|
|
42
|
-
list(): Promise<string[]>;
|
|
43
|
-
private resolveBackend;
|
|
44
|
-
}
|
|
45
|
-
/**
|
|
46
|
-
* True when a session is expired or within `skewMs` of expiry — i.e. it should
|
|
47
|
-
* be refreshed from the device cert before use. Default skew: 5 minutes.
|
|
48
|
-
*/
|
|
49
|
-
export declare function sessionNeedsRefresh(record: SessionRecord, skewMs?: number, nowMs?: number): boolean;
|
|
50
|
-
/** Re-exported for callers that namespace session records themselves. */
|
|
51
|
-
export { normalizeHost };
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import type { SecretBackend, StoredCredential } from './CredentialBackend.js';
|
|
2
|
-
/**
|
|
3
|
-
* Windows Credential Manager backend.
|
|
4
|
-
* Uses PowerShell P/Invoke to Advapi32.dll for CredRead/CredWrite/CredDelete.
|
|
5
|
-
* cmdkey cannot read passwords back, so P/Invoke is required.
|
|
6
|
-
*
|
|
7
|
-
* Each record is stored as a generic credential with:
|
|
8
|
-
* target = "{prefix}{normalized_publisher}"
|
|
9
|
-
* credential blob = JSON-serialized record (UTF-16)
|
|
10
|
-
*
|
|
11
|
-
* The `target` prefix namespaces the store, so OAuth credentials (`kanonak:`)
|
|
12
|
-
* and device enrollments (`kanonak-device:`) do not collide. Data is passed to
|
|
13
|
-
* PowerShell via stdin to prevent injection attacks; no user-supplied values
|
|
14
|
-
* are interpolated into PowerShell code.
|
|
15
|
-
*/
|
|
16
|
-
export declare class WinCredBackend<T = StoredCredential> implements SecretBackend<T> {
|
|
17
|
-
private readonly targetPrefix;
|
|
18
|
-
constructor(targetPrefix?: string);
|
|
19
|
-
get(publisher: string): Promise<T | null>;
|
|
20
|
-
store(publisher: string, value: T): Promise<void>;
|
|
21
|
-
remove(publisher: string): Promise<void>;
|
|
22
|
-
list(): Promise<string[]>;
|
|
23
|
-
}
|
package/dist/chunk-VOJ6BGAR.js
DELETED
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{H as sn,I as cn}from"./chunk-7K5TAJ44.js";import{a as z,b as K,c as en,h as U,l as N}from"./chunk-MX3DEXMV.js";import{a as k,d as $,e as on,f as an}from"./chunk-ZP6P7HNU.js";import{b as H,c as O,d as T,f as q,g as W,h as X,i as J,j as Q,k as Z,l as nn,m as w,r as v,t as tn,v as x,w as rn,y as _}from"./chunk-7BHDZHJY.js";import{a as Y}from"./chunk-FUUTGGJS.js";import{d as B}from"./chunk-2ACBWC7K.js";var ln=(r=>(r.Class="Class",r.DatatypeProperty="DatatypeProperty",r.ObjectProperty="ObjectProperty",r.AnnotationProperty="AnnotationProperty",r.Instance="Instance",r.Datatype="Datatype",r.Unknown="Unknown",r))(ln||{}),fn=(c=>(c.InstanceOf="instanceOf",c.SubClassOf="subClassOf",c.Domain="domain",c.Range="range",c.ObjectRelationship="objectRelationship",c.SubPropertyOf="subPropertyOf",c.PropertyValue="propertyValue",c.EmbeddedLink="embeddedLink",c))(fn||{}),M=class{static async buildFromRepository(e){let a=await new N().parseKanonaks(e),o=await e.getAllDocumentsAsync(),i=[],s=[],r=new Set,c=new Set,g=new Map;for(let l of a){let u=l;u.name&&(k.isClassType(u)&&r.add(u.name),(k.isObjectPropertyType(u)||k.isGenericPropertyType(u))&&c.add(u.name))}for(let l of o)for(let[u,f]of Object.entries(l.body))c.has(u)&&f?.range&&typeof f.range=="string"&&g.set(u,f.range);let y=new Map;for(let l of a){let u=l;u.name&&y.set(u.name,u)}for(let l of o){let u=l.metadata.namespace_,f=u?`${u.publisher}/${u.package_}`:"",p=u?.version?`${u.version.major}.${u.version.minor}.${u.version.patch}`:"",d=pn(l);for(let[b,m]of Object.entries(l.body)){if(!m||typeof m!="object")continue;let C=y.get(b),h="Unknown";if(C){let j=C;k.isClassType(j)?h="Class":k.isObjectPropertyType(j)?h="ObjectProperty":k.isDatatypePropertyType(j)?h="DatatypeProperty":k.isAnnotationPropertyType(j)?h="AnnotationProperty":k.isDatatypeType(j)?h="Datatype":k.isGenericPropertyType(j)?h="ObjectProperty":k.isInstanceOfKnownClass(j,r)&&(h="Instance")}let S=f&&p?`${f}/${b}@${p}`:b,F={};for(let[j,E]of Object.entries(m))j!=="type"&&(typeof E!="object"||E===null)&&(F[j]=E);i.push({id:S,label:m.label??b,type:h,namespace:f,properties:F}),un(S,m,h,r,c,s,f,p,d),A(S,m,c,g,i,s,f,p,d),xn(S,C,s)}}return{nodes:i,edges:s}}static buildFromDocument(e){let t=[],a=[],o=e.metadata.namespace_,i=o?.version?`${o.version.major}.${o.version.minor}.${o.version.patch}`:"",s=o?`${o.publisher}/${o.package_}`:"",r=new Set,c=new Set,g=new Map,y=pn(e);for(let[f,p]of Object.entries(e.body)){let d=p?.type;d&&(On(d,y)&&r.add(f),Kn(d,y)&&(c.add(f),p.range&&typeof p.range=="string"&&g.set(f,p.range)))}for(let[f,p]of Object.entries(e.body)){if(!p||typeof p!="object")continue;let d=p.type,b=wn(d,f,r,y),m=s&&i?`${s}/${f}@${i}`:f,C={};for(let[h,S]of Object.entries(p))h!=="type"&&(typeof S!="object"||S===null)&&(C[h]=S);t.push({id:m,label:p.label??f,type:b,namespace:s,properties:C}),un(m,p,b,r,c,a,s,i,y),A(m,p,c,g,t,a,s,i,y)}let l=new Set(t.map(f=>f.id)),u=a.filter(f=>l.has(f.source)&&l.has(f.target));return{nodes:t,edges:u}}};function pn(n,e){let t=new Map;if(n.metadata?.imports)for(let[a,o]of Object.entries(n.metadata.imports))for(let i of o){let s=i.alias??i.packageName,r=i.version,c=`${r.major}.${r.minor}.${r.patch}`;t.set(s,{publisher:a,package_:i.packageName,version:c})}return t}var dn={"kanonak.org/core-rdf/Class":"Class","kanonak.org/core-owl/Class":"Class","kanonak.org/core-rdfs/Class":"Class","kanonak.org/core-owl/ObjectProperty":"ObjectProperty","kanonak.org/core-owl/DatatypeProperty":"DatatypeProperty","kanonak.org/core-owl/AnnotationProperty":"AnnotationProperty","kanonak.org/core-rdf/Property":"ObjectProperty","kanonak.org/core-rdfs/Datatype":"Datatype"},Tn=new Set(["kanonak.org/core-owl/ObjectProperty","kanonak.org/core-owl/DatatypeProperty","kanonak.org/core-owl/AnnotationProperty","kanonak.org/core-rdf/Property"]);function L(n,e){if(n.includes(".")){let t=n.indexOf("."),a=n.substring(0,t),o=n.substring(t+1),i=e.get(a);if(i)return`${i.publisher}/${i.package_}/${o}`}return null}function On(n,e){let t=L(n,e);return t?dn[t]==="Class":!1}function Kn(n,e){let t=L(n,e);return t?Tn.has(t):!1}function wn(n,e,t,a){if(!n||n==="Package")return"Unknown";let o=L(n,a);if(o){let s=dn[o];if(s)return s;let r=o.split("/").pop()?.split("@")[0]??"";return t.has(r)?"Instance":"Unknown"}let i=n.split(".").pop()??n;return t.has(i)?"Instance":"Unknown"}var yn=new Set(["type","label","comment","version","publisher","imports","license","match","alias","package"]);function un(n,e,t,a,o,i,s,r,c){let g=e.type,y=e.subClassOf;if(y){let p=Array.isArray(y)?y:[y];for(let d of p)typeof d=="string"&&i.push({source:n,target:P(d,s,r,c),type:"subClassOf",label:"subClassOf"})}let l=e.subPropertyOf;if(l){let p=Array.isArray(l)?l:[l];for(let d of p)typeof d=="string"&&i.push({source:n,target:P(d,s,r,c),type:"subPropertyOf",label:"subPropertyOf"})}if(t==="Instance"&&g){let p=g.split(".").pop()??g;i.push({source:n,target:P(p,s,r,c),type:"instanceOf",label:"type"})}if(t==="Instance")for(let[p,d]of Object.entries(e)){if(yn.has(p)||!o.has(p))continue;let b=Array.isArray(d)?d:[d];for(let m of b)typeof m=="string"&&Nn(m)&&i.push({source:n,target:P(m,s,r,c),type:"propertyValue",label:p,propertyId:P(p,s,r,c)})}let u=t==="ObjectProperty"||t==="DatatypeProperty",f=e.domain&&e.range;if((u||f)&&e.domain&&e.range){let p=typeof e.domain=="string"?e.domain:null,d=typeof e.range=="string"?e.range:null;p&&d&&i.push({source:P(p,s,r,c),target:P(d,s,r,c),type:"objectRelationship",label:e.label??n.split("/").pop()??"",propertyId:n})}}function A(n,e,t,a,o,i,s,r,c){for(let[g,y]of Object.entries(e)){if(yn.has(g)||typeof y!="object"||y===null||Array.isArray(y))continue;let l=y,u=`${n}/${g}`,f=a.get(g),p=f?f.split(".").pop()??f:"Unknown",d={};for(let[m,C]of Object.entries(l))(typeof C!="object"||C===null)&&(d[m]=C);o.push({id:u,label:`${p} (embedded)`,type:"Instance",namespace:s,properties:d});let b=s&&r?`${s}/${g}@${r}`:g;i.push({source:n,target:u,type:"propertyValue",label:g,propertyId:t.has(g)?b:void 0}),f&&i.push({source:u,target:P(p,s,r,c),type:"instanceOf",label:"type (inferred)"}),A(u,l,t,a,o,i,s,r,c)}}function xn(n,e,t){let a=e?.statement;if(Array.isArray(a))for(let o of a){if(!(o instanceof en))continue;let i=o.predicate?.subject?.name??"";for(let s of o.links){let r=s.target?.subject;if(!r)continue;let c=r.version,g=c&&typeof c.major=="number"?`@${c.major}.${c.minor}.${c.patch}`:"";t.push({source:n,target:`${r.publisher}/${r.package_}/${r.name}${g}`,type:"embeddedLink",label:i})}}}function Nn(n){return!(!n||n.includes(" ")||n.includes(`
|
|
2
|
-
`)||n.startsWith("http://")||n.startsWith("https://")||/^\d{4}-\d{2}/.test(n)||/^\d+(\.\d+)?$/.test(n))}function P(n,e,t,a){if(n.includes("@")&&n.includes("/"))return n;if(n.includes(".")){let o=n.indexOf("."),i=n.substring(0,o),s=n.substring(o+1);if(a){let r=a.get(i);if(r)return`${r.publisher}/${r.package_}/${s}@${r.version}`}return e&&t?`${e}/${s}@${t}`:s}return e&&t?`${e}/${n}@${t}`:n}function $n(n){if(!n.expiresAt)return!1;let e=new Date(n.expiresAt),t=300*1e3;return e.getTime()<=Date.now()+t}function te(n){return!!n.accessToken&&!$n(n)}function re(n){let e=n.replace(/^https?:\/\//,"").replace(/^git:\/\//,"").replace(/\/+$/,"").trim();if(!e)throw new Error("Publisher host cannot be empty");return e}import{canonicalForm as Dn,canonicalHash as Rn}from"@kanonak-protocol/canonical";function G(n){return typeof n=="object"&&n!==null&&Array.isArray(n.subjects)}import{CANONICAL_FORM_VERSION as Ln}from"@kanonak-protocol/canonical";function En(n){return Dn(G(n)?n:gn(n))}function vn(n){return Rn(G(n)?n:gn(n))}function gn(n){let e=[];for(let t of n)t instanceof O&&e.push({uri:An(t),statements:V(t.statement)});return{subjects:e}}function V(n){let e=[];for(let t of n){let a=Mn(t);if(!a)continue;let o=_n(t);o&&e.push({predicate:a,value:o})}return e}function _n(n){if(n instanceof q&&n.carrier)return{lit:n.lexical??String(n.object),datatype:kn(n.carrier)};if(n instanceof W)return{raw:n.object};if(n instanceof X)return{raw:n.lexical??String(n.object)};if(n instanceof J)return{raw:n.lexical??String(n.object)};if(n instanceof Q)return{ref:bn(n.object)};if(n instanceof Z)return mn(n.object);if(n instanceof nn)return{list:n.object.map(Un)}}function mn(n){let e=V(n.statement);return n.name&&n.name.length>0?{embed:{name:n.name,statements:e}}:{embed:{statements:e}}}function Un(n){if(n instanceof T)return{ref:bn(n)};if(n instanceof z)return mn(n);if(n instanceof K){if(n.carrier)return{lit:n.lexical??String(n.value),datatype:kn(n.carrier)};let e=n.value;if(typeof e=="string")return{raw:e};if(typeof e=="number")return{raw:String(e)};if(typeof e=="boolean")return{raw:String(e)}}if(n instanceof H)return{embed:{statements:V(n.statement)}};throw new Error(`canonicalForm: list item of unrecognized kind (${n.constructor?.name??typeof n}); add canonicalization support before hashing data that contains it`)}function kn(n){return n===U.LangString?"kanonak.org/core-rdf/langString":`kanonak.org/core-xsd/${n}`}function Mn(n){let e=n.predicate;if(e)return hn(e.subject)}function An(n){let e=n.namespace??"",t=n.name??"";return`${e}/${t}`}function bn(n){return hn(n.subject)}function hn(n){let e=n.version;return e&&typeof e.major=="number"?`${n.publisher}/${n.package_}@${e.major}.${e.minor}.${e.patch}/${n.name}`:`${n.publisher}/${n.package_}/${n.name}`}var I="kanonak.org",R="core-rdf",jn="core-xsd",Cn={publisher:I,package_:R,name:"subClassOf"},Sn={publisher:I,package_:R,name:"label"},Gn={publisher:I,package_:R,name:"comment"},Pn={publisher:I,package_:"core-owl",name:"oneOf"},In=n=>n;function Vn(n){let e=rn(n,Cn);if(e)return[e];let t=[];for(let a of _(n,Cn))a instanceof T&&t.push(a.subject);return t}function Fn(n,e,t){if(e.publisher===I&&e.package_===R&&e.name==="Literal")return{kind:"datatype",uri:e};let o=v(n,e);if(o){let i=In(o);if(k.isDatatypeType(i))return{kind:"datatype",uri:e};if(k.isClassType(i))return{kind:"class",uri:$(o)??e,localName:o.name}}return e.publisher===I&&e.package_===jn?{kind:"datatype",uri:e}:t==="datatype"?{kind:"datatype",uri:e}:{kind:"class",uri:e,localName:e.name}}function Bn(n,e,t){if(!e.range)throw new Error(`Property ${e.uri.publisher}/${e.uri.package_}/${e.uri.name} has no rdfs.range; every property must declare a range. Validate the ontology before introspecting it.`);let a=Fn(n,e.range,e.kind),o=e.kind==="object"?"object":e.kind==="datatype"?"datatype":a.kind==="class"?"object":"datatype";return{uri:e.uri,localName:e.uri.name,kind:o,range:a,...e.label!==void 0?{label:e.label}:{},...e.comment!==void 0?{comment:e.comment}:{},...t??{}}}var D=n=>new Y(I,jn,n);function Hn(n){return typeof n=="boolean"?D("boolean"):typeof n=="number"?Number.isInteger(n)?D("integer"):D("decimal"):D("string")}function zn(n,e){let t=[];for(let a of _(e,Pn))if(a instanceof T){let o=v(n,a.subject),i=(o?$(o):void 0)??a.subject,s=o?x(o,Sn):void 0;t.push({kind:"individual",uri:i,localName:i.name,...s!==void 0?{label:s}:{}})}else a instanceof K&&t.push({kind:"literal",value:a.value,datatype:Hn(a.value)});return t}function Yn(n,e,t,a){let o=on(n,e),i=w(e);return an(n,e).filter(r=>t?!0:r.domains.some(c=>w(c)===i)).map(r=>Bn(n,r,cn(a,o,r.uri)))}async function qn(n,e,t){let a=n.metadata?.namespace_;if(!a)throw new Error("buildOntologyModel: document has no namespace (publisher/package/version).");let o=t?.includeInherited??!1,i=await new N().parseKanonaks(e),s=sn(i),r=[],c=[],g=new Set;for(let y of i){if(!(y instanceof O)||!k.isClassType(In(y)))continue;let l=$(y);if(!l||l.publisher!==a.publisher||l.package_!==a.package_||l.version&&a.version&&!B(l.version,a.version))continue;let u=w(l);if(g.has(u))continue;g.add(u);let f=Vn(y).map(b=>({uri:b,localName:b.name})),p=x(y,Sn),d=x(y,Gn);r.push({uri:l,localName:l.name,superClasses:f,properties:Yn(i,l,o,s),...p!==void 0?{label:p}:{},...d!==void 0?{comment:d}:{}}),tn(y,Pn)&&c.push({uri:l,localName:l.name,members:zn(i,y),...p!==void 0?{label:p}:{},...d!==void 0?{comment:d}:{}})}return{classes:r,enums:c}}export{ln as a,fn as b,M as c,$n as d,te as e,re as f,En as g,vn as h,Ln as i,qn as j};
|