@kanonak-protocol/sdk 4.20.0 → 5.1.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.
@@ -0,0 +1,42 @@
1
+ import type { SessionRecord } from './SessionStore.js';
2
+ /**
3
+ * The durable host→credential primitive (issue #72): given any registry/repo
4
+ * host, resolve a freshly-valid credential, or decline. This is the engine the
5
+ * git credential helper is one consumer of; any other client (or a downstream
6
+ * package-manager adapter) builds on the same primitive instead of reimplementing
7
+ * the auth.
8
+ *
9
+ * Fully discovery-driven, per host:
10
+ * host --RFC 9728 protected-resource metadata--> authorization server(s)
11
+ * authority --device session (refreshed from the cert)--> a fresh token
12
+ * The session is keyed by the AUTHORITY and reused across every resource host
13
+ * that points at it. Returns null when the host advertises no authority (not a
14
+ * Kanonak resource) or its authority isn't enrolled on this device.
15
+ */
16
+ /** A resolved registry credential. `token` is the credential (presented as a
17
+ * Bearer token, or as the HTTP Basic password); there is no identity here. */
18
+ export interface ResolvedCredential {
19
+ /** The authorization-server host the credential is scoped to. */
20
+ authority: string;
21
+ /** The session token — the credential. */
22
+ token: string;
23
+ /** ISO timestamp the underlying session expires. */
24
+ expiresAt: string;
25
+ /** Space-delimited consented scope. */
26
+ scope: string;
27
+ }
28
+ export interface CredentialResolverDeps {
29
+ discovery?: {
30
+ discoverProtectedResource(host: string): Promise<string[] | null>;
31
+ };
32
+ sessionManager?: {
33
+ getValidSession(host: string): Promise<SessionRecord | null>;
34
+ };
35
+ }
36
+ export declare class CredentialResolver {
37
+ private readonly discovery;
38
+ private readonly sessions;
39
+ constructor(deps?: CredentialResolverDeps);
40
+ /** Resolve a fresh credential for `host`, or null to decline. */
41
+ resolve(host: string): Promise<ResolvedCredential | null>;
42
+ }
@@ -0,0 +1,68 @@
1
+ /**
2
+ * OAuth 2.0 Authorization Server Metadata (RFC 8414).
3
+ */
4
+ export interface OAuthServerMetadata {
5
+ issuer?: string | null;
6
+ authorizationEndpoint?: string | null;
7
+ tokenEndpoint?: string | null;
8
+ registrationEndpoint?: string | null;
9
+ revocationEndpoint?: string | null;
10
+ scopesSupported?: string[] | null;
11
+ responseTypesSupported?: string[] | null;
12
+ grantTypesSupported?: string[] | null;
13
+ codeChallengeMethodsSupported?: string[] | null;
14
+ tokenEndpointAuthMethodsSupported?: string[] | null;
15
+ dpopSigningAlgValuesSupported?: string[] | null;
16
+ /** Endpoint that signs a submitted CSR after consent. */
17
+ enrollmentEndpoint?: string | null;
18
+ /** Issuance protocols the endpoint speaks, e.g. `["native"]`, `["est"]`, `["acme"]`. */
19
+ enrollmentIssuanceProtocols?: string[] | null;
20
+ /** Device key types accepted, e.g. `["ec-p256"]`. */
21
+ enrollmentKeyTypes?: string[] | null;
22
+ /** Scopes grantable to a device certificate. */
23
+ enrollmentScopesSupported?: string[] | null;
24
+ /**
25
+ * Authorization-request parameter that carries the CSR key's RFC 7638
26
+ * thumbprint to bind consent to that key (anti-substitution). Defaults to
27
+ * `key_thumbprint` when the server advertises enrollment without naming it.
28
+ */
29
+ enrollmentConsentBindingParam?: string | null;
30
+ /** Endpoint that exchanges a presented device cert for a scoped session token. */
31
+ sessionEndpoint?: string | null;
32
+ /**
33
+ * Client-auth method for `sessionEndpoint`. `tls_client_auth` (RFC 8705) means
34
+ * the exchange is an mTLS hop presenting the enrolled device cert.
35
+ */
36
+ sessionEndpointAuthMethod?: string | null;
37
+ }
38
+ /** Default authorization-request parameter for the consent↔key binding. */
39
+ export declare const DEFAULT_CONSENT_BINDING_PARAM = "key_thumbprint";
40
+ /**
41
+ * Discovers OAuth server metadata using RFC 8414.
42
+ * Falls back to OpenID Connect discovery.
43
+ * Port of C# OAuthDiscoveryService.
44
+ */
45
+ export declare class OAuthDiscovery {
46
+ private readonly cache;
47
+ private readonly prCache;
48
+ /**
49
+ * RFC 9728 (OAuth 2.0 Protected Resource Metadata): the authorization
50
+ * server(s) that protect a resource host. The git credential helper uses this
51
+ * to resolve a git/registry host → its Kanonak authority (issuer URLs in
52
+ * `authorization_servers`); RFC 8414 on that authority then yields the session
53
+ * endpoint. Returns null when the host advertises no protected-resource
54
+ * metadata — i.e. it isn't a Kanonak-credentialed host, so the helper declines
55
+ * and git falls through. Quiet on misses (the helper probes every host git
56
+ * asks about, most of which won't be Kanonak resources).
57
+ */
58
+ discoverProtectedResource(resourceHost: string): Promise<string[] | null>;
59
+ discover(host: string): Promise<OAuthServerMetadata | null>;
60
+ supportsOAuth(host: string): Promise<boolean>;
61
+ static supportsPkceS256(m: OAuthServerMetadata): boolean;
62
+ static supportsDynamicRegistration(m: OAuthServerMetadata): boolean;
63
+ static supportsAuthorizationCode(m: OAuthServerMetadata): boolean;
64
+ static supportsEnrollment(m: OAuthServerMetadata): boolean;
65
+ /** True when the server exchanges a device cert for a scoped session (#72). */
66
+ static supportsSession(m: OAuthServerMetadata): boolean;
67
+ private tryEndpoint;
68
+ }
@@ -0,0 +1,39 @@
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
+ scope?: string;
37
+ nowMs?: number;
38
+ }): Promise<ExchangedSession>;
39
+ }
@@ -0,0 +1,52 @@
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, opts?: {
39
+ scope?: string;
40
+ }): Promise<SessionRecord>;
41
+ /**
42
+ * A valid session for `host` — the cached one if still fresh, otherwise
43
+ * re-exchanged from the device cert. Returns null (rather than throwing) when
44
+ * the host issues no sessions or this device isn't enrolled there, so callers
45
+ * can attach a credential only where one exists (public hosts get none). A
46
+ * refresh that genuinely fails (network/server) propagates.
47
+ */
48
+ getValidSession(host: string): Promise<SessionRecord | null>;
49
+ /** Forget the cached session for `host`. */
50
+ clear(host: string): Promise<void>;
51
+ private sessionEndpoint;
52
+ }
@@ -0,0 +1,51 @@
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 };
@@ -3,6 +3,16 @@ export { isExpired, hasValidToken, normalizeHost } from './CredentialBackend.js'
3
3
  export { CredentialStore } from './CredentialStore.js';
4
4
  export { DeviceCertificateStore } from './DeviceCertificateStore.js';
5
5
  export type { DeviceEnrollmentRecord } from './DeviceCertificateStore.js';
6
+ export { SessionStore, sessionNeedsRefresh } from './SessionStore.js';
7
+ export type { SessionRecord, SessionStoreDeps } from './SessionStore.js';
8
+ export { OAuthDiscovery, DEFAULT_CONSENT_BINDING_PARAM } from './OAuthDiscovery.js';
9
+ export type { OAuthServerMetadata } from './OAuthDiscovery.js';
10
+ export { SessionExchange, SessionExchangeError } from './SessionExchange.js';
11
+ export type { ExchangedSession, MtlsTransport } from './SessionExchange.js';
12
+ export { SessionManager, SessionError } from './SessionManager.js';
13
+ export type { SessionManagerDeps, SessionDiscovery, DeviceStoreLike } from './SessionManager.js';
14
+ export { CredentialResolver } from './CredentialResolver.js';
15
+ export type { ResolvedCredential, CredentialResolverDeps } from './CredentialResolver.js';
6
16
  export type { AuthenticatedFetchFn } from './AuthenticatedFetch.js';
7
17
  export { createAuthenticatedFetch } from './AuthenticatedFetch.js';
8
18
  export { generateDPoPKeyPair, createDPoPProof, serverSupportsDPoP } from './DPoP.js';
package/dist/browser.d.ts CHANGED
@@ -29,8 +29,8 @@ export { findDerivation } from './derivation/index.js';
29
29
  export type { DerivationEntityUri, TransformationReferenceTuple, DerivationLookupResult, } from './derivation/index.js';
30
30
  export { buildOntologyModel } from './introspection/index.js';
31
31
  export type { OntologyModel, ClassDef, PropertyDef, ClassRef, TypeRef, BuildOntologyModelOptions, } from './introspection/index.js';
32
- export { BrowserCredentialBackend, BrowserOAuthFlow, generateBrowserDPoPKeys, generateBrowserDPoPKeyPair, importDPoPKeys, createBrowserDPoPProof, browserServerSupportsDPoP, isExpired, hasValidToken, normalizeHost, } from './auth/browser.js';
33
- export type { BrowserDPoPKeys, BrowserOAuthResult, CredentialBackend, StoredCredential, DPoPKeyPair, } from './auth/browser.js';
32
+ export { isExpired, hasValidToken, normalizeHost } from './auth/CredentialBackend.js';
33
+ export type { CredentialBackend, StoredCredential, DPoPKeyPair } from './auth/CredentialBackend.js';
34
34
  export { kanonakFetch, setKanonakUserAgent, getKanonakUserAgent, KANONAK_USER_AGENT, } from './http/kanonakFetch.js';
35
35
  export type { IKanonakDocumentRepository } from '@kanonak-protocol/types/document/models';
36
36
  export type { IKanonakParser } from '@kanonak-protocol/types/document/parsing';
package/dist/browser.js CHANGED
@@ -1,2 +1 @@
1
- import{a as we,b as ke,c as he,d as E,e as v,f as d,g as er}from"./chunk-EBH5WSSY.js";import{a as Ze}from"./chunk-EZSHR3CB.js";import"./chunk-QHABFCRC.js";import{a as F,b as W,c as G,d as w,f as Q,g as X,h as Y}from"./chunk-JYBKSBB5.js";import{a as q}from"./chunk-4NO7MHS7.js";import{a as Ke,b as be,c as xe}from"./chunk-S6VSAKXB.js";import{a as Se,b as Re}from"./chunk-PEUTCG3B.js";import"./chunk-PEJALHXK.js";import"./chunk-SC5M74NM.js";import{A as Qe,B as Xe,K as Ye,a as De,b as Be,c as Ce,d as Ee,f as ve,g as _e,h as Ae,i as je,k as Te,l as Ie,m as Oe,n as Ue,o as Ve,p as $e,q as Me,r as Ne,s as ze,t as Je,u as He,v as qe,w as Le,x as Fe,y as We,z as Ge}from"./chunk-FPUQEPYK.js";import{a as te,c as ye,l as me}from"./chunk-MX3DEXMV.js";import{a as L}from"./chunk-NJ3AZYQD.js";import{a as Pe}from"./chunk-ZP6P7HNU.js";import"./chunk-6U26UASC.js";import{a as ge,b as fe}from"./chunk-GZPLWII7.js";import{a as Z,b as ee,c as re,d as oe,e as se,f as ie,g as ae,h as ce,i as le,j as ue,k as de,l as pe}from"./chunk-7BHDZHJY.js";import{a as ne}from"./chunk-FUUTGGJS.js";import{c as U,d as V,e as $,f as M,g as N,h as z,i as J,j as H}from"./chunk-2ACBWC7K.js";var _="kanonak-credentials",u="credentials",rr=1,f=class{async get(r){let e=d(r),t=await h();return new Promise((o,a)=>{let s=t.transaction(u,"readonly"),i=s.objectStore(u).get(e);i.onsuccess=()=>o(i.result??null),i.onerror=()=>a(new Error(`IndexedDB read failed for '${e}': ${i.error?.message}`)),s.oncomplete=()=>t.close()})}async store(r,e){let t=d(r),o=await h();return new Promise((a,s)=>{let l=o.transaction(u,"readwrite"),c=l.objectStore(u).put(e,t);c.onsuccess=()=>a(),c.onerror=()=>s(new Error(`IndexedDB write failed for '${t}': ${c.error?.message}`)),l.oncomplete=()=>o.close()})}async remove(r){let e=d(r),t=await h();return new Promise((o,a)=>{let s=t.transaction(u,"readwrite"),i=s.objectStore(u).delete(e);i.onsuccess=()=>o(),i.onerror=()=>a(new Error(`IndexedDB delete failed for '${e}': ${i.error?.message}`)),s.oncomplete=()=>t.close()})}async list(){let r=await h();return new Promise((e,t)=>{let o=r.transaction(u,"readonly"),s=o.objectStore(u).getAllKeys();s.onsuccess=()=>e(s.result??[]),s.onerror=()=>t(new Error(`IndexedDB list failed: ${s.error?.message}`)),o.oncomplete=()=>r.close()})}};function h(){return new Promise((n,r)=>{let e=indexedDB.open(_,rr);e.onupgradeneeded=()=>{let t=e.result;t.objectStoreNames.contains(u)||t.createObjectStore(u)},e.onsuccess=()=>n(e.result),e.onerror=()=>r(new Error(`Failed to open IndexedDB '${_}': ${e.error?.message}
2
- Credential storage requires IndexedDB support in your browser.`))})}async function j(){let n=await crypto.subtle.generateKey({name:"ECDSA",namedCurve:"P-256"},!1,["sign"]),r=await crypto.subtle.exportKey("jwk",n.publicKey);return{signingKey:n.privateKey,publicKeyJwk:r}}async function K(){let n=await crypto.subtle.generateKey({name:"ECDSA",namedCurve:"P-256"},!0,["sign"]),r=await crypto.subtle.exportKey("jwk",n.publicKey),e=await crypto.subtle.exportKey("jwk",n.privateKey);return{keys:{signingKey:n.privateKey,publicKeyJwk:r},dpopKeyPair:{publicKey:r,privateKey:e}}}async function b(n){return{signingKey:await crypto.subtle.importKey("jwk",n.privateKey,{name:"ECDSA",namedCurve:"P-256"},!1,["sign"]),publicKeyJwk:n.publicKey}}async function x(n,r,e,t,o){let a={alg:"ES256",typ:"dpop+jwt",jwk:{kty:n.publicKeyJwk.kty,crv:n.publicKeyJwk.crv,x:n.publicKeyJwk.x,y:n.publicKeyJwk.y}},s={jti:crypto.randomUUID(),htm:r.toUpperCase(),htu:e,iat:Math.floor(Date.now()/1e3)};return t&&(s.ath=await nr(t)),o&&(s.nonce=o),await tr(a,s,n.signingKey)}function S(n){return!n||n.length===0?!1:n.some(r=>r.toUpperCase()==="ES256")}async function tr(n,r,e){let t=A(JSON.stringify(n)),o=A(JSON.stringify(r)),a=new TextEncoder().encode(`${t}.${o}`),s=await crypto.subtle.sign({name:"ECDSA",hash:"SHA-256"},e,a),l=B(s);return`${t}.${o}.${l}`}async function nr(n){let r=new TextEncoder().encode(n),e=await crypto.subtle.digest("SHA-256",r);return B(e)}function A(n){let r=new TextEncoder().encode(n);return B(r.buffer)}function B(n){let r=new Uint8Array(n),e="";for(let t=0;t<r.length;t++)e+=String.fromCharCode(r[t]);return btoa(e).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"")}var or=300*1e3,R=class{credentialBackend;callbackUrl;constructor(r){this.credentialBackend=new f,this.callbackUrl=r??`${window.location.origin}/browser/callback.html`}async authorize(r){let e=d(r),t=await this.discover(e);if(!t)return{success:!1,error:`No OAuth discovery endpoint found for '${e}'.`};if(!t.authorizationEndpoint||!t.tokenEndpoint)return{success:!1,error:`OAuth metadata incomplete for '${e}'.`};let o=S(t.dpopSigningAlgValuesSupported),a=null,s=null;if(o){let g=await K();a=g.keys,s=g.dpopKeyPair}let l=await this.credentialBackend.get(e),i=l?.clientId??null,c=l?.clientSecret??null;if(!i&&t.registrationEndpoint){let g=await this.registerClient(t.registrationEndpoint);if(!g)return{success:!1,error:`Dynamic client registration failed for '${e}'.`};i=g.clientId,c=g.clientSecret??null}if(!i)return{success:!1,error:`No OAuth client credentials for '${e}'.`};let m=sr(),p=await ir(m),D=ar(),I=cr(t.authorizationEndpoint,i,this.callbackUrl,D,p),y=await this.openAuthPopup(I,D);if(!y)return{success:!1,error:"Authorization timed out or was cancelled."};if(y.error)return{success:!1,error:`Authorization failed: ${y.error}`};if(!y.code)return{success:!1,error:"No authorization code received."};if(y.state!==D)return{success:!1,error:"State mismatch \u2014 possible CSRF attack."};let P=await this.exchangeCode(t.tokenEndpoint,i,c,y.code,this.callbackUrl,m,a);if(!P)return{success:!1,error:"Token exchange failed."};let O={clientId:i,clientSecret:c,accessToken:P.accessToken??null,refreshToken:P.refreshToken??null,expiresAt:P.expiresIn?new Date(Date.now()+P.expiresIn*1e3).toISOString():null,tokenEndpoint:t.tokenEndpoint,dpopKeyPair:s};return await this.credentialBackend.store(e,O),{success:!0,host:e}}async getCredentialWithKeys(r){let e=await this.credentialBackend.get(r);if(!e)return null;let t=null;return e.dpopKeyPair&&(t=await b(e.dpopKeyPair)),{credential:e,dpopKeys:t}}async logout(r){let e=d(r);return await this.credentialBackend.remove(e),{success:!0,host:e}}async listAuthenticated(){return this.credentialBackend.list()}async discover(r){for(let e of[`https://${r}/.well-known/oauth-authorization-server`,`https://${r}/.well-known/openid-configuration`])try{let t=await w(e);if(!t.ok)continue;let o=await t.json();return{issuer:k(o.issuer),authorizationEndpoint:k(o.authorization_endpoint),tokenEndpoint:k(o.token_endpoint),registrationEndpoint:k(o.registration_endpoint),revocationEndpoint:k(o.revocation_endpoint),dpopSigningAlgValuesSupported:T(o.dpop_signing_alg_values_supported),codeChallengeMethodsSupported:T(o.code_challenge_methods_supported)}}catch{continue}return null}async registerClient(r){try{let e=await w(r,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({client_name:"Kanonak Browser",redirect_uris:[this.callbackUrl],grant_types:["authorization_code","refresh_token"],response_types:["code"],token_endpoint_auth_method:"none"})});if(!e.ok)return null;let t=await e.json(),o=t.client_id;return o?{clientId:o,clientSecret:t.client_secret}:null}catch{return null}}openAuthPopup(r,e){return new Promise(t=>{let o=window.open(r,"kanonak-auth","width=500,height=700,menubar=no,toolbar=no,location=yes,status=no");if(!o){t(null);return}let a=setTimeout(()=>{i(),t(null)},or),s=c=>{c.origin===window.location.origin&&(!c.data||c.data.type!=="kanonak-auth-callback"||(i(),t({code:c.data.code??void 0,state:c.data.state??void 0,error:c.data.error??void 0})))},l=setInterval(()=>{o.closed&&(i(),t(null))},500),i=()=>{clearTimeout(a),clearInterval(l),window.removeEventListener("message",s);try{o.close()}catch{}};window.addEventListener("message",s)})}async exchangeCode(r,e,t,o,a,s,l){let i=new URLSearchParams({grant_type:"authorization_code",client_id:e,code:o,redirect_uri:a,code_verifier:s});t&&i.set("client_secret",t);let c={"Content-Type":"application/x-www-form-urlencoded"};l&&(c.DPoP=await x(l,"POST",r));try{let m=await w(r,{method:"POST",headers:c,body:i.toString()});if(!m.ok)return null;let p=await m.json();return{accessToken:p.access_token,refreshToken:p.refresh_token,expiresIn:typeof p.expires_in=="number"?p.expires_in:void 0}}catch{return null}}};function sr(){let n=new Uint8Array(32);return crypto.getRandomValues(n),C(n.buffer)}async function ir(n){let r=new TextEncoder().encode(n),e=await crypto.subtle.digest("SHA-256",r);return C(e)}function ar(){let n=new Uint8Array(16);return crypto.getRandomValues(n),C(n.buffer)}function cr(n,r,e,t,o){let a=new URLSearchParams({client_id:r,response_type:"code",redirect_uri:e,state:t,code_challenge:o,code_challenge_method:"S256"});return`${n}?${a}`}function C(n){let r=new Uint8Array(n),e="";for(let t=0;t<r.length;t++)e+=String.fromCharCode(r[t]);return btoa(e).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"")}function k(n){return typeof n=="string"?n:null}function T(n){return Array.isArray(n)?n.filter(r=>typeof r=="string"):null}export{He as AmbiguousReferenceRule,le as BooleanStatement,f as BrowserCredentialBackend,R as BrowserOAuthFlow,Qe as ClassDefinitionRule,Ue as ClassHierarchyCycleRule,ee as DefinedKanonak,ke as EdgeType,te as EmbeddedKanonak,Te as EmbeddedKanonakTypeRule,de as EmbeddedStatement,he as GraphBuilder,Y as HttpKanonakDocumentRepository,Ie as ImportExistenceRule,q as InMemoryKanonakDocumentRepository,F as KANONAK_USER_AGENT,Z as Kanonak,be as KanonakDocumentPositions,me as KanonakObjectParser,Ye as KanonakObjectValidator,L as KanonakParser,ne as KanonakUri,Se as KanonakUriBuilder,pe as ListStatement,Xe as MarkdownLinkRule,ye as MarkdownStatement,ze as NamespaceImportCycleRule,ve as NamespacePrefixRule,we as NodeType,ce as NumberStatement,Le as ObjectPropertyValueValidationRule,Ce as OntologyValidationError,De as OntologyValidationResult,Fe as PropertyDomainRule,Ve as PropertyHierarchyCycleRule,We as PropertyKindRangeConsistencyRule,Ke as PropertyMetadata,qe as PropertyRangeReferenceRule,$e as PropertyRangeRequiredRule,Ae as PropertyTypeSpecificityRule,Q as PublisherConfigResolver,X as PublisherIndex,oe as ReferenceKanonak,ue as ReferenceStatement,Ge as ReservedNameShadowRule,_e as ResourceNamingRule,ge as ResourceResolver,Pe as ResourceTypeClassifier,ie as ScalarStatement,se as Statement,ae as StringStatement,Me as SubClassOfReferenceRule,Ne as SubPropertyOfReferenceRule,re as SubjectKanonak,je as SubjectKanonakTypeRequiredRule,fe as TypeResolver,Je as UnresolvedPredicateRule,Oe as UnresolvedReferenceRule,Ee as ValidationContext,Be as ValidationSeverity,S as browserServerSupportsDPoP,er as buildOntologyModel,U as compareVersions,x as createBrowserDPoPProof,M as createVersion,Ze as findDerivation,Re as findInstancesByType,$ as formatVersion,K as generateBrowserDPoPKeyPair,j as generateBrowserDPoPKeys,G as getKanonakUserAgent,v as hasValidToken,b as importDPoPKeys,z as isCompatibleVersion,E as isExpired,J as isMajorCompatible,w as kanonakFetch,d as normalizeHost,N as parseVersionString,xe as parseWithPositions,H as pickHighestDocument,W as setKanonakUserAgent,V as versionsEqual};
1
+ import{a as U,b as B,c as A,d as ke,e as xe,f as Pe,g as Ke}from"./chunk-EBH5WSSY.js";import{a as ge}from"./chunk-EZSHR3CB.js";import"./chunk-QHABFCRC.js";import{a as m,b as u,c as d,d as c,f as y,g as R,h as f}from"./chunk-JYBKSBB5.js";import{a as p}from"./chunk-4NO7MHS7.js";import{a as G,b as H,c as L}from"./chunk-S6VSAKXB.js";import{a as w,b as q}from"./chunk-PEUTCG3B.js";import"./chunk-PEJALHXK.js";import"./chunk-SC5M74NM.js";import{A as ye,B as Re,K as fe,a as W,b as _,c as z,d as F,f as J,g as Q,h as X,i as Y,k as Z,l as $,m as ee,n as oe,o as te,p as re,q as ne,r as ae,s as ie,t as se,u as pe,v as le,w as me,x as ue,y as de,z as ce}from"./chunk-FPUQEPYK.js";import{a as g,c as E,l as N}from"./chunk-MX3DEXMV.js";import{a as l}from"./chunk-NJ3AZYQD.js";import{a as M}from"./chunk-ZP6P7HNU.js";import"./chunk-6U26UASC.js";import{a as v,b as T}from"./chunk-GZPLWII7.js";import{a as k,b as x,c as P,d as S,e as b,f as D,g as h,h as C,i as V,j,k as I,l as O}from"./chunk-7BHDZHJY.js";import{a as K}from"./chunk-FUUTGGJS.js";import{c as e,d as o,e as t,f as r,g as n,h as a,i,j as s}from"./chunk-2ACBWC7K.js";export{pe as AmbiguousReferenceRule,V as BooleanStatement,ye as ClassDefinitionRule,oe as ClassHierarchyCycleRule,x as DefinedKanonak,B as EdgeType,g as EmbeddedKanonak,Z as EmbeddedKanonakTypeRule,I as EmbeddedStatement,A as GraphBuilder,f as HttpKanonakDocumentRepository,$ as ImportExistenceRule,p as InMemoryKanonakDocumentRepository,m as KANONAK_USER_AGENT,k as Kanonak,H as KanonakDocumentPositions,N as KanonakObjectParser,fe as KanonakObjectValidator,l as KanonakParser,K as KanonakUri,w as KanonakUriBuilder,O as ListStatement,Re as MarkdownLinkRule,E as MarkdownStatement,ie as NamespaceImportCycleRule,J as NamespacePrefixRule,U as NodeType,C as NumberStatement,me as ObjectPropertyValueValidationRule,z as OntologyValidationError,W as OntologyValidationResult,ue as PropertyDomainRule,te as PropertyHierarchyCycleRule,de as PropertyKindRangeConsistencyRule,G as PropertyMetadata,le as PropertyRangeReferenceRule,re as PropertyRangeRequiredRule,X as PropertyTypeSpecificityRule,y as PublisherConfigResolver,R as PublisherIndex,S as ReferenceKanonak,j as ReferenceStatement,ce as ReservedNameShadowRule,Q as ResourceNamingRule,v as ResourceResolver,M as ResourceTypeClassifier,D as ScalarStatement,b as Statement,h as StringStatement,ne as SubClassOfReferenceRule,ae as SubPropertyOfReferenceRule,P as SubjectKanonak,Y as SubjectKanonakTypeRequiredRule,T as TypeResolver,se as UnresolvedPredicateRule,ee as UnresolvedReferenceRule,F as ValidationContext,_ as ValidationSeverity,Ke as buildOntologyModel,e as compareVersions,r as createVersion,ge as findDerivation,q as findInstancesByType,t as formatVersion,d as getKanonakUserAgent,xe as hasValidToken,a as isCompatibleVersion,ke as isExpired,i as isMajorCompatible,c as kanonakFetch,Pe as normalizeHost,n as parseVersionString,L as parseWithPositions,s as pickHighestDocument,u as setKanonakUserAgent,o as versionsEqual};
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 { CredentialStore, DeviceCertificateStore, createAuthenticatedFetch, generateDPoPKeyPair, createDPoPProof, serverSupportsDPoP, isExpired, hasValidToken, normalizeHost, } from './auth/index.js';
25
- export type { SecretBackend, CredentialBackend, StoredCredential, DeviceEnrollmentRecord, DPoPKeyPair, AuthenticatedFetchFn, } from './auth/index.js';
24
+ export { CredentialStore, DeviceCertificateStore, SessionStore, sessionNeedsRefresh, OAuthDiscovery, DEFAULT_CONSENT_BINDING_PARAM, SessionExchange, SessionExchangeError, SessionManager, SessionError, CredentialResolver, createAuthenticatedFetch, generateDPoPKeyPair, createDPoPProof, serverSupportsDPoP, isExpired, hasValidToken, normalizeHost, } from './auth/index.js';
25
+ export type { SecretBackend, CredentialBackend, StoredCredential, DeviceEnrollmentRecord, SessionRecord, SessionStoreDeps, OAuthServerMetadata, ExchangedSession, MtlsTransport, SessionManagerDeps, SessionDiscovery, DeviceStoreLike, ResolvedCredential, CredentialResolverDeps, DPoPKeyPair, AuthenticatedFetchFn, } from './auth/index.js';
26
26
  export { kanonakFetch, 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,12 +1,12 @@
1
- import{a as wr,b as Sr,c as Rr,d as Er,e as be}from"./chunk-TVSHIXLA.js";import{a as yn,c as we,e as Fe,h as Ue,i as Le,j as gn}from"./chunk-IHB7UVEH.js";import{a as kr,b as br,c as Pr,d as M,e as H,f as l,g as hn}from"./chunk-EBH5WSSY.js";import{a as fn}from"./chunk-EZSHR3CB.js";import"./chunk-QHABFCRC.js";import{a as Mt,b as Ht,c as zt,d as Wt,e as Gt,f as tr,g as rr,h as nr,i as or}from"./chunk-GMEPM2QQ.js";import{a as Jt,b as qt,c as Xt,d as E,f as Zt,g as Yt,h as er}from"./chunk-JYBKSBB5.js";import{a as Lt}from"./chunk-4NO7MHS7.js";import{a as Cr,b as xr,c as Ir,d as Kr}from"./chunk-S6VSAKXB.js";import{a as $r,b as Br}from"./chunk-PEUTCG3B.js";import{a as Dr}from"./chunk-PEJALHXK.js";import{a as Qt}from"./chunk-SC5M74NM.js";import{A as pn,B as dn,K as mn,a as Or,b as Vr,c as Fr,d as Ur,e as Lr,f as Mr,g as Hr,h as zr,i as Wr,j as Gr,k as Jr,l as qr,m as Xr,n as Zr,o as Yr,p as Qr,q as en,r as tn,s as rn,t as nn,u as on,v as an,w as sn,x as cn,y as ln,z as un}from"./chunk-FPUQEPYK.js";import{a as y,b as le,c as cr,h as L,i as Oe,j as yr,k as gr,l as A}from"./chunk-MX3DEXMV.js";import{a as I}from"./chunk-NJ3AZYQD.js";import{a as hr,b as Pe,c as Ar,d as g,e as Tr,f as jr,g as _r,h as Nr}from"./chunk-ZP6P7HNU.js";import{a as Ve}from"./chunk-6U26UASC.js";import{a as lr,b as ur,c as $,d as pr,e as dr,g as mr,k as fr}from"./chunk-GZPLWII7.js";import{a as ir,b as ce,c as f,d as k,e as sr,f as ue,g as pe,h as de,i as me,j as fe,k as ye,l as ge,r as U,w as K,x as he,y as ke}from"./chunk-7BHDZHJY.js";import{a as ar}from"./chunk-FUUTGGJS.js";import{a as _t,b as se,c as F,d as Nt,e as h,f as Bt,g as Ot,h as Vt,i as Ft,j as Ut}from"./chunk-2ACBWC7K.js";import{a as vr}from"./chunk-ODIECDN7.js";import{VersionOperator as La}from"@kanonak-protocol/types/document/models/enums";import{existsSync as Vn,readFileSync as Fn}from"fs";import{homedir as Un}from"os";import{join as Ln}from"path";import{execFile as kn}from"child_process";import{promisify as bn}from"util";var z=bn(kn),Pn="kanonak",W="/usr/bin/security",b=class{constructor(e=Pn){this.service=e}service;async get(e){let t=l(e);try{let{stdout:n}=await z(W,["find-generic-password","-s",this.service,"-a",t,"-w"],{timeout:1e4});try{return JSON.parse(n.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(n){if(Me(n,44))return null;throw new Error(`macOS Keychain read failed for '${t}': ${G(n)}
1
+ import{a as _r,b as Nr,c as jr,d as Or,e as Ie}from"./chunk-TVSHIXLA.js";import{a as An,c as De,e as Ye,h as Ze,i as Qe,j as In}from"./chunk-IHB7UVEH.js";import{a as Dr,b as $r,c as Tr,d as Q,e as ee,f as l,g as Kn}from"./chunk-EBH5WSSY.js";import{a as xn}from"./chunk-EZSHR3CB.js";import"./chunk-QHABFCRC.js";import{a as rr,b as nr,c as or,d as ir,e as sr,f as fr,g as yr,h as hr,i as gr}from"./chunk-GMEPM2QQ.js";import{a as ar,b as cr,c as lr,d as I,f as pr,g as dr,h as mr}from"./chunk-JYBKSBB5.js";import{a as tr}from"./chunk-4NO7MHS7.js";import{a as Mr,b as Vr,c as Lr,d as Ur}from"./chunk-S6VSAKXB.js";import{a as Fr,b as Xr}from"./chunk-PEUTCG3B.js";import{a as zr}from"./chunk-PEJALHXK.js";import{a as ur}from"./chunk-SC5M74NM.js";import{A as Rn,B as En,K as Cn,a as Yr,b as Zr,c as Qr,d as en,e as tn,f as rn,g as nn,h as on,i as sn,j as an,k as cn,l as ln,m as pn,n as dn,o as un,p as mn,q as fn,r as yn,s as hn,t as gn,u as kn,v as Sn,w as wn,x as bn,y as Pn,z as vn}from"./chunk-FPUQEPYK.js";import{a as P,b as Se,c as br,h as Z,i as qe,j as Ar,k as Ir,l as U}from"./chunk-MX3DEXMV.js";import{a as M}from"./chunk-NJ3AZYQD.js";import{a as Kr,b as Ke,c as Hr,d as v,e as Wr,f as Gr,g as Jr,h as qr}from"./chunk-ZP6P7HNU.js";import{a as Xe}from"./chunk-6U26UASC.js";import{a as Pr,b as vr,c as L,d as Rr,e as Er,g as Cr,k as xr}from"./chunk-GZPLWII7.js";import{a as kr,b as ke,c as b,d as C,e as wr,f as we,g as be,h as Pe,i as ve,j as Re,k as Ee,l as Ce,r as Y,w as V,x as xe,y as Ae}from"./chunk-7BHDZHJY.js";import{a as Sr}from"./chunk-FUUTGGJS.js";import{a as Jt,b as ge,c as X,d as qt,e as E,f as Xt,g as Yt,h as Zt,i as Qt,j as er}from"./chunk-2ACBWC7K.js";import{a as Br}from"./chunk-ODIECDN7.js";import{VersionOperator as Oa}from"@kanonak-protocol/types/document/models/enums";import{existsSync as Zn,readFileSync as Qn}from"fs";import{homedir as eo}from"os";import{join as to}from"path";import{execFile as Dn}from"child_process";import{promisify as $n}from"util";var te=$n(Dn),Tn="kanonak",re="/usr/bin/security",m=class{constructor(e=Tn){this.service=e}service;async get(e){let t=l(e);try{let{stdout:n}=await te(re,["find-generic-password","-s",this.service,"-a",t,"-w"],{timeout:1e4});try{return JSON.parse(n.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(n){if(et(n,44))return null;throw new Error(`macOS Keychain read failed for '${t}': ${ne(n)}
3
3
  The Keychain may be locked or inaccessible.
4
- Try unlocking it via Keychain Access.app or running 'security unlock-keychain'.`)}}async store(e,t){let n=l(e),o=JSON.stringify(t);try{await z(W,["add-generic-password","-s",this.service,"-a",n,"-U","-w",o],{timeout:1e4})}catch(i){throw new Error(`macOS Keychain write failed for '${n}': ${G(i)}
4
+ Try unlocking it via Keychain Access.app or running 'security unlock-keychain'.`)}}async store(e,t){let n=l(e),o=JSON.stringify(t);try{await te(re,["add-generic-password","-s",this.service,"-a",n,"-U","-w",o],{timeout:1e4})}catch(i){throw new Error(`macOS Keychain write failed for '${n}': ${ne(i)}
5
5
  Ensure the Keychain is unlocked and the CLI has write permission.
6
- On managed devices, your IT policy may block credential storage.`)}}async remove(e){let t=l(e);try{await z(W,["delete-generic-password","-s",this.service,"-a",t],{timeout:1e4})}catch(n){if(Me(n,44))return;console.warn(` Warning: macOS Keychain delete failed for '${t}': ${G(n)}
7
- The credential may not have been fully removed.`)}}async list(){try{let{stdout:e}=await z(W,["dump-keychain"],{timeout:1e4}),t=[],n=!1;for(let o of e.split(`
8
- `))if(o.includes(`"svce"<blob>="${this.service}"`)&&(n=!0),n&&o.includes('"acct"<blob>=')){let i=o.match(/"acct"<blob>="([^"]+)"/);i&&t.push(i[1]),n=!1}return t}catch(e){return console.warn(` Warning: Could not enumerate Keychain entries: ${G(e)}`),[]}}};function Me(r,e){return typeof r=="object"&&r!==null&&"code"in r&&r.code===e}function G(r){return r instanceof Error?r.message:String(r)}import{execFile as wn}from"child_process";import{promisify as Sn}from"util";var Rn=Sn(wn),En="kanonak:",He=2560,P=class{constructor(e=En){this.targetPrefix=e}targetPrefix;async get(e){let t=this.targetPrefix+l(e),n=`
9
- ${q}
6
+ On managed devices, your IT policy may block credential storage.`)}}async remove(e){let t=l(e);try{await te(re,["delete-generic-password","-s",this.service,"-a",t],{timeout:1e4})}catch(n){if(et(n,44))return;console.warn(` Warning: macOS Keychain delete failed for '${t}': ${ne(n)}
7
+ The credential may not have been fully removed.`)}}async list(){try{let{stdout:e}=await te(re,["dump-keychain"],{timeout:1e4}),t=[],n=!1;for(let o of e.split(`
8
+ `))if(o.includes(`"svce"<blob>="${this.service}"`)&&(n=!0),n&&o.includes('"acct"<blob>=')){let i=o.match(/"acct"<blob>="([^"]+)"/);i&&t.push(i[1]),n=!1}return t}catch(e){return console.warn(` Warning: Could not enumerate Keychain entries: ${ne(e)}`),[]}}};function et(r,e){return typeof r=="object"&&r!==null&&"code"in r&&r.code===e}function ne(r){return r instanceof Error?r.message:String(r)}import{execFile as _n}from"child_process";import{promisify as Nn}from"util";var jn=Nn(_n),On="kanonak:",tt=2560,f=class{constructor(e=On){this.targetPrefix=e}targetPrefix;async get(e){let t=this.targetPrefix+l(e),n=`
9
+ ${ie}
10
10
  $target = $env:KANONAK_CRED_TARGET
11
11
  $ptr = [IntPtr]::Zero
12
12
  $result = [CredMan]::CredRead($target, 1, 0, [ref]$ptr)
@@ -18,8 +18,8 @@ try {
18
18
  [System.Text.Encoding]::Unicode.GetString($bytes)
19
19
  } finally {
20
20
  [CredMan]::CredFree($ptr)
21
- }`;try{let{stdout:o}=await J(n,{KANONAK_CRED_TARGET:t}),i=o.trim();return i?JSON.parse(i):null}catch{return null}}async store(e,t){let n=this.targetPrefix+l(e),o=JSON.stringify(t),i=Buffer.byteLength(o,"utf16le");if(i>He)throw new Error(`Credential '${n}' is ${i} bytes (UTF-16), over the Windows Credential Manager limit of ${He} (CRED_MAX_CREDENTIAL_BLOB_SIZE). Keep only the secret here and store large/public material (certificates, chains) on disk.`);let a=`
22
- ${q}
21
+ }`;try{let{stdout:o}=await oe(n,{KANONAK_CRED_TARGET:t}),i=o.trim();return i?JSON.parse(i):null}catch{return null}}async store(e,t){let n=this.targetPrefix+l(e),o=JSON.stringify(t),i=Buffer.byteLength(o,"utf16le");if(i>tt)throw new Error(`Credential '${n}' is ${i} bytes (UTF-16), over the Windows Credential Manager limit of ${tt} (CRED_MAX_CREDENTIAL_BLOB_SIZE). Keep only the secret here and store large/public material (certificates, chains) on disk.`);let s=`
22
+ ${ie}
23
23
  $target = $env:KANONAK_CRED_TARGET
24
24
  $json = $env:KANONAK_CRED_JSON
25
25
  $bytes = [System.Text.Encoding]::Unicode.GetBytes($json)
@@ -35,12 +35,12 @@ try {
35
35
  if (-not $result) { throw "CredWrite failed (Win32 error $([System.Runtime.InteropServices.Marshal]::GetLastWin32Error()))" }
36
36
  } finally {
37
37
  [System.Runtime.InteropServices.Marshal]::FreeHGlobal($cred.CredentialBlob)
38
- }`;try{await J(a,{KANONAK_CRED_TARGET:n,KANONAK_CRED_JSON:o})}catch(s){let c=s,u=c.stderr&&c.stderr.trim()||c.message||String(s);throw new Error(`Windows Credential Manager write failed: ${u}`)}}async remove(e){let t=this.targetPrefix+l(e),n=`
39
- ${q}
38
+ }`;try{await oe(s,{KANONAK_CRED_TARGET:n,KANONAK_CRED_JSON:o})}catch(a){let c=a,p=c.stderr&&c.stderr.trim()||c.message||String(a);throw new Error(`Windows Credential Manager write failed: ${p}`)}}async remove(e){let t=this.targetPrefix+l(e),n=`
39
+ ${ie}
40
40
  $target = $env:KANONAK_CRED_TARGET
41
- [CredMan]::CredDelete($target, 1, 0) | Out-Null`;try{await J(n,{KANONAK_CRED_TARGET:t})}catch{}}async list(){let e=`
42
- ${q}
43
- ${vn}
41
+ [CredMan]::CredDelete($target, 1, 0) | Out-Null`;try{await oe(n,{KANONAK_CRED_TARGET:t})}catch{}}async list(){let e=`
42
+ ${ie}
43
+ ${Bn}
44
44
  $prefix = $env:KANONAK_CRED_PREFIX
45
45
  $count = 0
46
46
  $pCreds = [IntPtr]::Zero
@@ -57,8 +57,8 @@ if ([CredMan]::CredEnumerate(($prefix + "*"), 0, [ref]$count, [ref]$pCreds)) {
57
57
  }
58
58
  }
59
59
  [CredMan]::CredFree($pCreds)
60
- }`;try{let{stdout:t}=await J(e,{KANONAK_CRED_PREFIX:this.targetPrefix});return t.trim().split(`
61
- `).map(n=>n.trim()).filter(Boolean)}catch{return[]}}};async function J(r,e){let t=Buffer.from(r,"utf16le").toString("base64");for(let n of["pwsh","powershell"])try{return await Rn(n,["-NoProfile","-NonInteractive","-EncodedCommand",t],{timeout:15e3,...e&&{env:{...process.env,...e}}})}catch(o){if(n==="powershell")throw o}throw new Error("Neither pwsh nor powershell found")}var q=`
60
+ }`;try{let{stdout:t}=await oe(e,{KANONAK_CRED_PREFIX:this.targetPrefix});return t.trim().split(`
61
+ `).map(n=>n.trim()).filter(Boolean)}catch{return[]}}};async function oe(r,e){let t=Buffer.from(r,"utf16le").toString("base64");for(let n of["pwsh","powershell"])try{return await jn(n,["-NoProfile","-NonInteractive","-EncodedCommand",t],{timeout:15e3,...e&&{env:{...process.env,...e}}})}catch(o){if(n==="powershell")throw o}throw new Error("Neither pwsh nor powershell found")}var ie=`
62
62
  Add-Type -TypeDefinition @"
63
63
  using System;
64
64
  using System.Runtime.InteropServices;
@@ -89,13 +89,15 @@ public class CredMan {
89
89
  [DllImport("Advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
90
90
  public static extern bool CredEnumerate(string filter, int flags, out int count, out IntPtr credentials);
91
91
  }
92
- "@`,vn="";import{execFile as Cn,spawn as xn}from"child_process";import{promisify as In}from"util";var X=In(Cn),Kn="kanonak",w=class{constructor(e=Kn){this.service=e}service;async get(e){let t=l(e);try{let{stdout:n}=await X("secret-tool",["lookup","service",this.service,"publisher",t],{timeout:1e4}),o=n.trim();return o?JSON.parse(o):null}catch{return null}}async store(e,t){let n=l(e),o=JSON.stringify(t);await new Promise((i,a)=>{let s=xn("secret-tool",["store","--label",`Kanonak: ${n}`,"service",this.service,"publisher",n],{stdio:["pipe","ignore","ignore"],timeout:1e4});s.stdin.write(o),s.stdin.end(),s.on("close",c=>{c===0?i():a(new Error(`secret-tool store exited with code ${c}`))}),s.on("error",a)})}async remove(e){let t=l(e);try{await X("secret-tool",["clear","service",this.service,"publisher",t],{timeout:1e4})}catch{}}async list(){try{let{stdout:e}=await X("secret-tool",["search","service",this.service],{timeout:1e4}),t=[];for(let n of e.split(`
93
- `)){let o=n.match(/attribute\.publisher\s*=\s*(.+)/);o&&t.push(o[1].trim())}return t}catch{return[]}}};async function D(){try{return await X("sh",["-c","command -v secret-tool"],{timeout:5e3}),!0}catch{return!1}}import{existsSync as ze,mkdirSync as We,readFileSync as Ge,writeFileSync as Je}from"fs";import{createCipheriv as $n,createDecipheriv as An,randomBytes as qe}from"crypto";import{homedir as Dn}from"os";import{join as Ee,dirname as Xe}from"path";var Ye=Ee(Dn(),".config","kanonak"),T=Ee(Ye,"keyring.key"),Tn=Ee(Ye,"credentials.enc"),Ze="aes-256-gcm",Se=32,v=12,Re=16,S=class{constructor(e=Tn){this.secretsFile=e}secretsFile;async get(e){let t=this.loadStore(),n=l(e);return t[n]??null}async store(e,t){let n=this.loadStore(),o=l(e);n[o]=t,this.saveStore(n)}async remove(e){let t=this.loadStore(),n=l(e);delete t[n],this.saveStore(t)}async list(){let e=this.loadStore();return Object.keys(e)}loadStore(){if(!ze(this.secretsFile))return{};try{let e=this.getOrCreateKey(),t=Ge(this.secretsFile);if(t.length<v+Re)return{};let n=t.subarray(0,v),o=t.subarray(v,v+Re),i=t.subarray(v+Re),a=An(Ze,e,n);a.setAuthTag(o);let s=Buffer.concat([a.update(i),a.final()]);return JSON.parse(s.toString("utf-8"))}catch{return{}}}saveStore(e){let t=this.getOrCreateKey(),n=qe(v),o=$n(Ze,t,n),i=Buffer.from(JSON.stringify(e),"utf-8"),a=Buffer.concat([o.update(i),o.final()]),s=o.getAuthTag(),c=Buffer.concat([n,s,a]);We(Xe(this.secretsFile),{recursive:!0}),Je(this.secretsFile,c,{mode:384})}getOrCreateKey(){if(ze(T)){let t=Ge(T);if(t.length!==Se)throw new Error(`Credential keyring key is corrupted (expected ${Se} bytes, got ${t.length}). Delete ${T} and re-authenticate.`);return t}let e=qe(Se);return We(Xe(T),{recursive:!0}),Je(T,e,{mode:384}),e}};import{execFile as jn}from"child_process";import{promisify as _n}from"util";var Nn=_n(jn),Qe=3e4,j=class{constructor(e){this.helperPath=e}helperPath;async get(e){let t=l(e);try{let o=(await this.runHelper("get",{publisher:t})).trim();return o?JSON.parse(o):null}catch(n){throw new Error(`Credential helper '${this.helperPath}' failed to read credential for '${t}': ${Z(n)}
92
+ "@`,Bn="";import{execFile as Mn,spawn as Vn}from"child_process";import{promisify as Ln}from"util";var se=Ln(Mn),Un="kanonak",y=class{constructor(e=Un){this.service=e}service;async get(e){let t=l(e);try{let{stdout:n}=await se("secret-tool",["lookup","service",this.service,"publisher",t],{timeout:1e4}),o=n.trim();return o?JSON.parse(o):null}catch{return null}}async store(e,t){let n=l(e),o=JSON.stringify(t);await new Promise((i,s)=>{let a=Vn("secret-tool",["store","--label",`Kanonak: ${n}`,"service",this.service,"publisher",n],{stdio:["pipe","ignore","ignore"],timeout:1e4});a.stdin.write(o),a.stdin.end(),a.on("close",c=>{c===0?i():s(new Error(`secret-tool store exited with code ${c}`))}),a.on("error",s)})}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 n of e.split(`
93
+ `)){let o=n.match(/attribute\.publisher\s*=\s*(.+)/);o&&t.push(o[1].trim())}return t}catch{return[]}}};async function x(){try{return await se("sh",["-c","command -v secret-tool"],{timeout:5e3}),!0}catch{return!1}}import{existsSync as rt,mkdirSync as nt,readFileSync as ot,writeFileSync as it}from"fs";import{createCipheriv as Fn,createDecipheriv as Hn,randomBytes as st}from"crypto";import{homedir as zn}from"os";import{join as _e,dirname as at}from"path";var lt=_e(zn(),".config","kanonak"),F=_e(lt,"keyring.key"),Wn=_e(lt,"credentials.enc"),ct="aes-256-gcm",$e=32,K=12,Te=16,h=class{constructor(e=Wn){this.secretsFile=e}secretsFile;async get(e){let t=this.loadStore(),n=l(e);return t[n]??null}async store(e,t){let n=this.loadStore(),o=l(e);n[o]=t,this.saveStore(n)}async remove(e){let t=this.loadStore(),n=l(e);delete t[n],this.saveStore(t)}async list(){let e=this.loadStore();return Object.keys(e)}loadStore(){if(!rt(this.secretsFile))return{};try{let e=this.getOrCreateKey(),t=ot(this.secretsFile);if(t.length<K+Te)return{};let n=t.subarray(0,K),o=t.subarray(K,K+Te),i=t.subarray(K+Te),s=Hn(ct,e,n);s.setAuthTag(o);let a=Buffer.concat([s.update(i),s.final()]);return JSON.parse(a.toString("utf-8"))}catch{return{}}}saveStore(e){let t=this.getOrCreateKey(),n=st(K),o=Fn(ct,t,n),i=Buffer.from(JSON.stringify(e),"utf-8"),s=Buffer.concat([o.update(i),o.final()]),a=o.getAuthTag(),c=Buffer.concat([n,a,s]);nt(at(this.secretsFile),{recursive:!0}),it(this.secretsFile,c,{mode:384})}getOrCreateKey(){if(rt(F)){let t=ot(F);if(t.length!==$e)throw new Error(`Credential keyring key is corrupted (expected ${$e} bytes, got ${t.length}). Delete ${F} and re-authenticate.`);return t}let e=st($e);return nt(at(F),{recursive:!0}),it(F,e,{mode:384}),e}};import{execFile as Gn}from"child_process";import{promisify as Jn}from"util";var qn=Jn(Gn),pt=3e4,H=class{constructor(e){this.helperPath=e}helperPath;async get(e){let t=l(e);try{let o=(await this.runHelper("get",{publisher:t})).trim();return o?JSON.parse(o):null}catch(n){throw new Error(`Credential helper '${this.helperPath}' failed to read credential for '${t}': ${ae(n)}
94
94
  Verify the helper binary exists, is executable, and implements the Kanonak credential helper protocol.
95
- Check the 'credentialHelper' path in ~/.kanonak/config.json.`)}}async store(e,t){let n=l(e);try{await this.runHelper("store",{publisher:n,credential:t})}catch(o){throw new Error(`Credential helper '${this.helperPath}' failed to store credential for '${n}': ${Z(o)}
96
- Verify the helper binary supports the 'store' action.`)}}async remove(e){let t=l(e);try{await this.runHelper("erase",{publisher:t})}catch(n){console.warn(` Warning: Credential helper '${this.helperPath}' failed to erase credential for '${t}': ${Z(n)}`)}}async list(){try{let e=await this.runHelper("list",void 0);return JSON.parse(e.trim())}catch(e){return console.warn(` Warning: Credential helper '${this.helperPath}' failed to list credentials: ${Z(e)}`),[]}}async runHelper(e,t){try{let{stdout:n}=await Nn(this.helperPath,[e],{...t&&{input:JSON.stringify(t)},timeout:Qe});return n}catch(n){throw Bn(n)?new Error(`Credential helper not found at '${this.helperPath}'.
97
- Check the 'credentialHelper' path in ~/.kanonak/config.json.`):On(n)?new Error(`Credential helper '${this.helperPath}' timed out after ${Qe/1e3}s on '${e}'.
98
- The helper may be waiting for authentication to an external vault.`):n}}};function Z(r){return r instanceof Error?r.message:String(r)}function Bn(r){return r instanceof Error&&"code"in r&&r.code==="ENOENT"}function On(r){return r instanceof Error&&"killed"in r&&r.killed}var ve=Ln(Un(),".kanonak","config.json"),Y=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=Mn(e);if(t)return t;let o=await(await this.getBackend()).get(e);return!o||!H(o)?null:o.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=Hn();return e.credentialHelper?new j(e.credentialHelper):process.platform==="darwin"?new b:process.platform==="win32"?new P:await D()?new w:new S}};function Mn(r){let t="KANONAK_TOKEN_"+l(r).replace(/[.\-]/g,"_").toUpperCase();return process.env[t]??null}function Hn(){if(!Vn(ve))return{};try{return JSON.parse(Fn(ve,"utf-8"))}catch(r){let e=r instanceof Error?r.message:String(r);return console.warn(` Warning: Failed to parse ${ve}: ${e}
99
- Using default credential backend. Fix the JSON syntax or delete the file.`),{}}}import{homedir as nt}from"os";import{join as R}from"path";import{mkdir as zn,writeFile as et,readFile as tt,rm as rt}from"fs/promises";var Ce="kanonak-device",Wn=R(nt(),".config","kanonak","device-credentials.enc"),Gn=R(nt(),".kanonak","devices"),Q=class{constructor(e={}){this.deps=e}deps;backend=null;backendReady=null;certDir(e){let t=l(e).replace(/[^a-zA-Z0-9._-]/g,"_");return R(this.deps.certBaseDir??Gn,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 n=this.certDir(e),o,i;try{o=await tt(R(n,"cert.pem"),"utf-8"),i=await tt(R(n,"chain.pem"),"utf-8")}catch{return null}return{...t,certificatePem:o,chainPem:i}}async store(e,t){let{certificatePem:n,chainPem:o,...i}=t,a=this.certDir(e);await zn(a,{recursive:!0}),await et(R(a,"cert.pem"),n,"utf-8"),await et(R(a,"chain.pem"),o,"utf-8");try{await(await this.getBackend()).store(e,i)}catch(s){throw await rt(a,{recursive:!0,force:!0}).catch(()=>{}),s}}async remove(e){await(await this.getBackend()).remove(e),await rt(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 b(Ce):process.platform==="win32"?new P(`${Ce}:`):await D()?new w(Ce):new S(Wn)}};import{createHash as Jn,createPrivateKey as qn,generateKeyPairSync as Xn,randomUUID as Zn,sign as Yn}from"crypto";function it(){let{publicKey:r,privateKey:e}=Xn("ec",{namedCurve:"P-256"});return{publicKey:r.export({format:"jwk"}),privateKey:e.export({format:"jwk"})}}function _(r,e,t,n,o,i){let a={alg:"ES256",typ:"dpop+jwt",jwk:{kty:e.kty,crv:e.crv,x:e.x,y:e.y}},s={jti:Zn(),htm:t.toUpperCase(),htu:n,iat:Math.floor(Date.now()/1e3)};return o&&(s.ath=Jn("sha256").update(o).digest("base64url")),i&&(s.nonce=i),Qn(a,s,r)}function at(r){return!r||r.length===0?!1:r.some(e=>e.toUpperCase()==="ES256")}function Qn(r,e,t){let n=ot(JSON.stringify(r)),o=ot(JSON.stringify(e)),i=`${n}.${o}`,a=qn({key:t,format:"jwk"}),c=Yn("SHA256",Buffer.from(i),{key:a,dsaEncoding:"ieee-p1363"}).toString("base64url");return`${i}.${c}`}function ot(r){return Buffer.from(r,"utf-8").toString("base64url")}function st(r){let e=new Map;return async(t,n,o="GET")=>{if(!r)return E(t,{method:o});let i=await r.getCredential(n);if(!i?.accessToken)return E(t,{method:o});M(i)&&console.warn(` Warning: Access token for '${n}' is expired. Run 'kanonak login ${n}' to re-authenticate.`);let a={};if(i.dpopKeyPair){let c=e.get(n);try{let u=_(i.dpopKeyPair.privateKey,i.dpopKeyPair.publicKey,o,t,i.accessToken,c);a.Authorization=`DPoP ${i.accessToken}`,a.DPoP=u}catch(u){let p=u instanceof Error?u.message:String(u);console.error(` Error: Failed to create DPoP proof for '${n}': ${p}
100
- The stored key pair may be corrupted. Run 'kanonak login ${n}' to re-authenticate.`),a.Authorization=`Bearer ${i.accessToken}`}}else a.Authorization=`Bearer ${i.accessToken}`;let s=await E(t,{method:o,headers:a});if(s.status===401&&i.dpopKeyPair){let c=s.headers.get("DPoP-Nonce");if(c){e.set(n,c);try{let u=_(i.dpopKeyPair.privateKey,i.dpopKeyPair.publicKey,o,t,i.accessToken,c);a.DPoP=u,s=await E(t,{method:o,headers:a})}catch{}}}return s}}import{readFileSync as eo,writeFileSync as to,existsSync as ro}from"fs";import{createHash as no}from"crypto";import ct from"js-yaml";var lt="kanonak.lock",oo=`# This file is generated by Kanonak CLI. Do not edit manually.
101
- `;function ut(r=lt){if(!ro(r))return null;let e=eo(r,"utf-8"),t=ct.load(e);return!t||typeof t!="object"||t.version!=="1"?null:{version:"1",lastUpdated:t.lastUpdated??new Date().toISOString(),packages:t.packages??{}}}function pt(r,e=lt){r.lastUpdated=new Date().toISOString();let t={};for(let o of Object.keys(r.packages).sort())t[o]=r.packages[o];r.packages=t;let n=ct.dump(r,{lineWidth:-1,sortKeys:!1,quotingType:'"'});to(e,oo+n,"utf-8")}function dt(r){return`sha256:${no("sha256").update(r).digest("hex")}`}import*as Ke from"js-yaml";import{canonicalForm as io,canonicalHash as ao}from"@kanonak-protocol/canonical";function xe(r){return typeof r=="object"&&r!==null&&Array.isArray(r.subjects)}import{CANONICAL_FORM_VERSION as bt}from"@kanonak-protocol/canonical";function mt(r){return io(xe(r)?r:ft(r))}function ee(r){return ao(xe(r)?r:ft(r))}function ft(r){let e=[];for(let t of r)t instanceof f&&e.push({uri:uo(t),statements:Ie(t.statement)});return{subjects:e}}function Ie(r){let e=[];for(let t of r){let n=lo(t);if(!n)continue;let o=so(t);o&&e.push({predicate:n,value:o})}return e}function so(r){if(r instanceof ue&&r.carrier)return{lit:r.lexical??String(r.object),datatype:gt(r.carrier)};if(r instanceof pe)return{raw:r.object};if(r instanceof de)return{raw:r.lexical??String(r.object)};if(r instanceof me)return{raw:r.lexical??String(r.object)};if(r instanceof fe)return{ref:ht(r.object)};if(r instanceof ye)return yt(r.object);if(r instanceof ge)return{list:r.object.map(co)}}function yt(r){let e=Ie(r.statement);return r.name&&r.name.length>0?{embed:{name:r.name,statements:e}}:{embed:{statements:e}}}function co(r){if(r instanceof k)return{ref:ht(r)};if(r instanceof y)return yt(r);if(r instanceof le){if(r.carrier)return{lit:r.lexical??String(r.value),datatype:gt(r.carrier)};let e=r.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(r instanceof ce)return{embed:{statements:Ie(r.statement)}};throw new Error(`canonicalForm: list item of unrecognized kind (${r.constructor?.name??typeof r}); add canonicalization support before hashing data that contains it`)}function gt(r){return r===L.LangString?"kanonak.org/core-rdf/langString":`kanonak.org/core-xsd/${r}`}function lo(r){let e=r.predicate;if(e)return kt(e.subject)}function uo(r){let e=r.namespace??"",t=r.name??"";return`${e}/${t}`}function ht(r){return kt(r.subject)}function kt(r){let e=r.version;return e&&typeof e.major=="number"?`${r.publisher}/${r.package_}@${e.major}.${e.minor}.${e.patch}/${r.name}`:`${r.publisher}/${r.package_}/${r.name}`}import{VersionOperator as Pt}from"@kanonak-protocol/types/document/models/enums";var po="0.0.0",C=class{constructor(e,t=new I,n){this.repository=e;this.parser=t;this.objectParser=n??new A(this.parser)}repository;parser;objectParser;imports(){return new N}serializeValue(e,t){return Rt(e,t)}async buildContentAddressed(e){let t=e.book.toImports(),n=await this.hashBody(e.publisher,t,e.body),o=$e(n),i={type:"EphemeralPackage",publisher:e.publisher,imports:t};e.contentHashProperty&&(i[e.contentHashProperty]=n),Object.assign(i,e.header??{}),i.imports=t;let a={[o]:i,...e.body},s=this.dump(a);return{yaml:s,byteCount:St(s),contentHash:n,packageName:o,publisher:e.publisher,resourceCount:Object.keys(e.body).length}}async buildNamed(e){let t=e.book.toImports(),n={type:e.type??"Package",publisher:e.publisher,version:e.version,imports:t},o;e.contentHashProperty&&(o=await this.hashBody(e.publisher,t,e.body),n[e.contentHashProperty]=o),Object.assign(n,e.header??{}),n.imports=t;let i={[e.name]:n,...e.body},a=this.dump(i),s={yaml:a,byteCount:St(a),packageName:e.name,publisher:e.publisher,resourceCount:Object.keys(e.body).length};return o!==void 0&&(s.contentHash=o),s}dump(e){return Ke.dump(e,{lineWidth:-1})}async hashBody(e,t,n){let o={[wt]:{type:"EphemeralPackage",publisher:e,imports:t},...n},i=this.parser.parse(Ke.dump(o,{lineWidth:-1})),a=i.metadata.namespace_?.toString(),c=(await this.objectParser.parseKanonaks(new Ve(i,this.repository))).filter(u=>u instanceof f&&u.namespace===a&&u.name!==wt);for(let u of c)u.namespace="ephemeral";return ee(c)}},wt="__pkgbuilder_probe__";function St(r){return new TextEncoder().encode(r).length}function $e(r){let e="sha256:",t=r.startsWith(e)?e.length:0;return`q-${r.slice(t,t+16)}`}var N=class{byKey=new Map;aliases=new Set;ensure(e,t,n,o,i=Pt.Major){let a=`${e}/${t}@${n}`,s=this.byKey.get(a);if(s)return s.alias;let c=this.uniqueAlias(o);return this.byKey.set(a,{publisher:e,package_:t,version:n,alias:c,match:i}),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_,h(e.version),e.package_)}.${e.name}`}refLatest(e,t,n,o){return`${this.ensure(e,t,po,o??t,Pt.Any)}.${n}`}toImports(){let e=new Map;for(let n of this.byKey.values()){let o=e.get(n.publisher)??[];o.push(n),e.set(n.publisher,o)}return[...e.keys()].sort().map(n=>({publisher:n,packages:e.get(n).sort((o,i)=>o.package_<i.package_?-1:1).map(o=>({package:o.package_,match:se(o.match),version:o.version,alias:o.alias}))}))}uniqueAlias(e){let t=B(e)||"pkg",n=t,o=2;for(;this.aliases.has(n);)n=`${t}${o++}`;return this.aliases.add(n),n}};function Rt(r,e){if(r!=null){if(typeof r=="string"||typeof r=="number"||typeof r=="boolean")return r;if(r instanceof k)return e.ref(r.subject);if(Array.isArray(r)){let t=r.map(n=>Rt(n,e)).filter(n=>n!==void 0);return t.length>0?t:void 0}if(r instanceof y)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(mo(r))throw new Error(`Value produced a bare URI without a version (${r.publisher}/${r.package_}/${r.name}); cannot serialize it as a reference.`)}}function B(r){return r.replace(/[^A-Za-z0-9-]/g,"-").replace(/-+/g,"-").replace(/^-|-$/g,"")}function mo(r){return typeof r=="object"&&r!==null&&typeof r.publisher=="string"&&typeof r.package_=="string"&&typeof r.name=="string"}var te=class{constructor(e){this.producers=e}producers;produced=new Map;producerFor(e,t){return this.producers.find(n=>n.canProduce(e,t))}async produceCached(e,t,n,o){let i=`${t}/${n}@${h(o)}`,a=this.produced.get(i);if(a)return a;let{document:s}=await e.produce(t,n,o);return this.produced.set(i,s),s}async getHighestCompatibleVersionAsync(e,t){let n=this.producerFor(e,t.packageName);if(!n)return null;let o={operator:t.versionOperator,version:t.version},i=await n.resolveVersion(e,t.packageName,o);return i?this.produceCached(n,e,t.packageName,i):null}async getDocumentAsync(e){let t;try{t=Pe(e)}catch{return null}if(t.kind!=="package"||!t.version)return null;let n=this.producerFor(t.publisher,t.package_);return n?this.produceCached(n,t.publisher,t.package_,t.version):null}async getDocumentsByNamespaceAsync(e,t){return Array.from(this.produced.values()).filter(n=>{let o=n.metadata.namespace_;return o!=null&&o.publisher===e&&o.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 Ae={async authorize(){return{allowed:!0}}},De={async record(){}},O=class extends Error{constructor(t,n){let o=`${t.publisher}/${t.package_}${t.version?`@${t.version.major}.${t.version.minor}.${t.version.patch}`:""}`;super(`Not entitled to produce ${o}${n?`: ${n}`:""}`);this.address=t;this.reason=n;this.name="EntitlementDeniedError"}address;reason},re=class{inner;ctx;policy;meter;constructor(e,t,n=Ae,o=De){this.inner=e,this.ctx=t,this.policy=n,this.meter=o}canProduce(e,t){return this.inner.canProduce(e,t)}async resolveVersion(e,t,n){return await this.assertAllowed({publisher:e,package_:t,version:n.version}),this.inner.resolveVersion(e,t,n)}async produce(e,t,n){let o={publisher:e,package_:t,version:n};await this.assertAllowed(o);let i=await this.inner.produce(e,t,n);return await this.meter.record(this.ctx,o,i),i}async assertAllowed(e){let t=await this.policy.authorize(this.ctx,e);if(!t.allowed)throw new O(e,t.reason)}};var d="kanonak.org",m="view",Et="core-kanonak",fo={publisher:d,package_:m,name:"rootView"},yo={publisher:d,package_:m,name:"bind"},go={publisher:d,package_:m,name:"produces"},ho={publisher:d,package_:m,name:"projections"},ko={publisher:d,package_:m,name:"where"},bo={publisher:d,package_:m,name:"value"},Po={publisher:d,package_:m,name:"as"},ne=class{constructor(e,t=new I){this.repository=e;this.parser=t;this.objectParser=new A(this.parser),this.builder=new C(this.repository,this.parser,this.objectParser)}repository;parser;objectParser;builder;async materialize(e,t={}){let n=await this.objectParser.parseKanonaks(this.repository),o=this.resolveView(n,e),i=K(o,yo);if(!i)throw new Error(`View ${o.namespace}/${o.name} declares no view.bind; cannot materialize.`);let a=K(o,go);if(!a)throw new Error(`View ${o.namespace}/${o.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=wo(o),c=vt(n,d,Et),u=vt(n,d,m),p=this.builder.imports(),oe=p.ensure(d,Et,c,"ck"),xt=p.ensure(d,m,u,"v"),It=p.ref(a),Kt=new Le(this.repository,this.parser,this.objectParser),Te=new Fe(Kt,n),$t=this.readProjections(n,o),At=Eo(o,ko),Dt=this.findInstances(n,i,await this.reason(t)),je={},Tt=new Set;for(let V of Dt){if(!await this.passesWhere(Te,n,At,V))continue;let ae={type:It};for(let Ne of $t){let jt=await this.evaluateValue(Te,n,Ne.value,V),Be=this.builder.serializeValue(Ct(jt),p);Be!==void 0&&(ae[p.ref(Ne.as)]=Be)}let _e=g(V);_e&&(ae[`${xt}.derivedFrom`]=p.ref(_e)),je[this.rowName(V,Tt)]=ae}let ie={};t.resolvedAt&&(ie[`${oe}.resolvedAt`]=t.resolvedAt),t.invocationId&&(ie[`${oe}.id`]=t.invocationId);let x=await this.builder.buildContentAddressed({publisher:s,book:p,body:je,contentHashProperty:`${oe}.contentHash`,header:ie});return{yaml:x.yaml,contentHash:x.contentHash,packageName:x.packageName,publisher:x.publisher,rowCount:x.resourceCount}}resolveView(e,t){let n=U(e,t);if(!n)throw new Error(`View ${t.publisher}/${t.package_}/${t.name} not found in the catalog.`);let o=K(n,fo);if(o){let i=U(e,o);if(!i)throw new Error(`ViewPackage ${t.name} names rootView ${o.name}, which is not in the catalog.`);return i}return n}readProjections(e,t){let n=[];for(let o of ke(t,ho)){let i=o instanceof y?o:o instanceof k?U(e,o.subject):void 0;if(!i)continue;let a=he(i,bo),s=K(i,Po);a&&s&&n.push({value:a,as:s})}return n}async reason(e){return new be({profile:e.reasoningProfile??"owl-rl-classification"}).reason(this.repository)}findInstances(e,t,n){let o=Ro(e),i=[],a=new Set;for(let s of n.getInstancesOfClass(t)){if(a.has(s))continue;a.add(s);let c=o.get(s);c&&i.push(c)}return i.sort((s,c)=>{let u=$(g(s)),p=$(g(c));return u<p?-1:u>p?1:0}),i}async passesWhere(e,t,n,o){for(let i of n){let a=await this.evaluateValue(e,t,i,o);if(!vo(a))return!1}return!0}async evaluateValue(e,t,n,o){let i=Ue(n,"view-projection",{catalog:t,depth:0}),a=new Map([["input",o]]);return e.evaluate(i,a)}rowName(e,t){let n=B(e.name)||"row",o=n,i=2;for(;t.has(o);)o=`${n}-${i++}`;return t.add(o),o}};function Ct(r){return we(r)?r.value:Array.isArray(r)?r.map(Ct):r}function wo(r){let e=g(r);if(!e)throw new Error(`Could not derive a publisher from view ${r.namespace}/${r.name}.`);return e.publisher}function vt(r,e,t){let n=So(r,e,t);if(!n)throw new Error(`Package ${e}/${t} is not in the catalog; it must be importable to materialize a view.`);return n}function So(r,e,t){let n;for(let o of r){if(!(o instanceof f))continue;let i=g(o);!i||i.publisher!==e||i.package_!==t||!i.version||(!n||F(i.version,n)>0)&&(n=i.version)}return n?h(n):void 0}function Ro(r){let e=new Map,t=new Map;for(let n of r){if(!(n instanceof f))continue;let o=g(n);if(!o||!o.version)continue;let i=$(o),a=t.get(i);(!a||F(o.version,a)>0)&&(t.set(i,o.version),e.set(i,n))}return e}function Eo(r,e){let t=he(r,e);return t?[t]:ke(r,e).filter(n=>n instanceof y)}function vo(r){return r===!0?!0:r===!1||r===void 0||r===null?!1:typeof r=="string"?r.length>0:typeof r=="number"?r!==0:we(r)?r.value.length>0:Array.isArray(r)?r.length>0:!!r}export{on as AmbiguousReferenceRule,me as BooleanStatement,bt as CANONICAL_FORM_VERSION,L as Carrier,pn as ClassDefinitionRule,Zr as ClassHierarchyCycleRule,zt as CompositeKanonakDocumentRepository,Y as CredentialStore,ce as DefinedKanonak,Q as DeviceCertificateStore,Ht as DocumentLocation,br as EdgeType,y as EmbeddedKanonak,Jr as EmbeddedKanonakTypeRule,ye as EmbeddedStatement,O as EntitlementDeniedError,re as EntitlementProducer,Mt as FileSystemKanonakDocumentRepository,vr as GitIgnoreFilter,Pr as GraphBuilder,er as HttpKanonakDocumentRepository,N as ImportBook,qr as ImportExistenceRule,Lt as InMemoryKanonakDocumentRepository,Jt as KANONAK_USER_AGENT,ir as Kanonak,xr as KanonakDocumentPositions,A as KanonakObjectParser,mn as KanonakObjectValidator,I as KanonakParser,ar as KanonakUri,$r as KanonakUriBuilder,Dr as KanonakUrlResolver,fr as KanonakVocabulary,ge as ListStatement,le as LiteralKanonak,tr as LocalFirstRepository,rr as LockAwareRepository,gn as LookRenderer,dn as MarkdownLinkRule,cr as MarkdownStatement,rn as NamespaceImportCycleRule,Mr as NamespacePrefixRule,kr as NodeType,de as NumberStatement,Rr as OWL_RL_CLASSIFICATION_RULES,sn as ObjectPropertyValueValidationRule,Fr as OntologyValidationError,Or as OntologyValidationResult,C as PackageBuilder,Gr as PackageHeaderRule,te as ProducerRepository,cn as PropertyDomainRule,Yr as PropertyHierarchyCycleRule,ln as PropertyKindRangeConsistencyRule,Cr as PropertyMetadata,an as PropertyRangeReferenceRule,Qr as PropertyRangeRequiredRule,zr as PropertyTypeSpecificityRule,Zt as PublisherConfigResolver,Yt as PublisherIndex,Sr as RDFS_RULES,be as Reasoner,Er as ReasoningResult,k as ReferenceKanonak,fe as ReferenceStatement,Gt as RepositoryFactory,un as ReservedNameShadowRule,Hr as ResourceNamingRule,lr as ResourceResolver,hr as ResourceTypeClassifier,ue as ScalarStatement,sr as Statement,pe as StringStatement,en as SubClassOfReferenceRule,tn as SubPropertyOfReferenceRule,f as SubjectKanonak,Wr as SubjectKanonakTypeRequiredRule,wr as TripleStore,ur as TypeResolver,nn as UnresolvedPredicateRule,Xr as UnresolvedReferenceRule,Lr as ValidationCache,Ur as ValidationContext,Vr as ValidationSeverity,La as VersionOperator,ne as ViewMaterializer,Ae as allowAllPolicy,Qt as assertPackageIdentity,or as buildLocalFirstRepository,hn as buildOntologyModel,mt as canonicalForm,ee as canonicalHash,Oe as carrierOf,nr as collectKanonakFiles,F as compareVersions,dt as computeIntegrity,$e as contentAddressedName,Nr as contextTypesOf,st as createAuthenticatedFetch,_ as createDPoPProof,Bt as createVersion,gr as extractMarkdownLinks,fn as findDerivation,Br as findInstancesByType,yr as findMalformedReferences,Kr as findMarkdownLinkAt,Ar as formatKanonakAddress,h as formatVersion,it as generateDPoPKeyPair,Wt as getGlobalCachePath,Xt as getKanonakUserAgent,H as hasValidToken,Vt as isCompatibleVersion,M as isExpired,Ft as isMajorCompatible,E as kanonakFetch,ut as loadLockFile,pr as makeUriKey,De as noopMeter,l as normalizeHost,Pe as parseKanonakAddress,Ot as parseVersionString,Ir as parseWithPositions,Ut as pickHighestDocument,jr as propertiesInScope,yn as resolveDisplayValue,_r as resolvePropertyStep,B as sanitizeName,pt as saveLockFile,at as serverSupportsDPoP,qt as setKanonakUserAgent,g as subjectUri,Tr as superClassChain,dr as tripleKey,$ as uriKey,mr as uriTriple,_t as versionOperatorFromChar,se as versionOperatorToChar,Nt as versionsEqual};
95
+ Check the 'credentialHelper' path in ~/.kanonak/config.json.`)}}async store(e,t){let n=l(e);try{await this.runHelper("store",{publisher:n,credential:t})}catch(o){throw new Error(`Credential helper '${this.helperPath}' failed to store credential for '${n}': ${ae(o)}
96
+ Verify the helper binary supports the 'store' action.`)}}async remove(e){let t=l(e);try{await this.runHelper("erase",{publisher:t})}catch(n){console.warn(` Warning: Credential helper '${this.helperPath}' failed to erase credential for '${t}': ${ae(n)}`)}}async list(){try{let e=await this.runHelper("list",void 0);return JSON.parse(e.trim())}catch(e){return console.warn(` Warning: Credential helper '${this.helperPath}' failed to list credentials: ${ae(e)}`),[]}}async runHelper(e,t){try{let{stdout:n}=await qn(this.helperPath,[e],{...t&&{input:JSON.stringify(t)},timeout:pt});return n}catch(n){throw Xn(n)?new Error(`Credential helper not found at '${this.helperPath}'.
97
+ Check the 'credentialHelper' path in ~/.kanonak/config.json.`):Yn(n)?new Error(`Credential helper '${this.helperPath}' timed out after ${pt/1e3}s on '${e}'.
98
+ The helper may be waiting for authentication to an external vault.`):n}}};function ae(r){return r instanceof Error?r.message:String(r)}function Xn(r){return r instanceof Error&&"code"in r&&r.code==="ENOENT"}function Yn(r){return r instanceof Error&&"killed"in r&&r.killed}var Ne=to(eo(),".kanonak","config.json"),ce=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=ro(e);if(t)return t;let o=await(await this.getBackend()).get(e);return!o||!ee(o)?null:o.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=no();return e.credentialHelper?new H(e.credentialHelper):process.platform==="darwin"?new m:process.platform==="win32"?new f:await x()?new y:new h}};function ro(r){let t="KANONAK_TOKEN_"+l(r).replace(/[.\-]/g,"_").toUpperCase();return process.env[t]??null}function no(){if(!Zn(Ne))return{};try{return JSON.parse(Qn(Ne,"utf-8"))}catch(r){let e=r instanceof Error?r.message:String(r);return console.warn(` Warning: Failed to parse ${Ne}: ${e}
99
+ Using default credential backend. Fix the JSON syntax or delete the file.`),{}}}import{homedir as ft}from"os";import{join as A}from"path";import{mkdir as oo,writeFile as dt,readFile as ut,rm as mt}from"fs/promises";var je="kanonak-device",io=A(ft(),".config","kanonak","device-credentials.enc"),so=A(ft(),".kanonak","devices"),D=class{constructor(e={}){this.deps=e}deps;backend=null;backendReady=null;certDir(e){let t=l(e).replace(/[^a-zA-Z0-9._-]/g,"_");return A(this.deps.certBaseDir??so,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 n=this.certDir(e),o,i;try{o=await ut(A(n,"cert.pem"),"utf-8"),i=await ut(A(n,"chain.pem"),"utf-8")}catch{return null}return{...t,certificatePem:o,chainPem:i}}async store(e,t){let{certificatePem:n,chainPem:o,...i}=t,s=this.certDir(e);await oo(s,{recursive:!0}),await dt(A(s,"cert.pem"),n,"utf-8"),await dt(A(s,"chain.pem"),o,"utf-8");try{await(await this.getBackend()).store(e,i)}catch(a){throw await mt(s,{recursive:!0,force:!0}).catch(()=>{}),a}}async remove(e){await(await this.getBackend()).remove(e),await mt(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(je):process.platform==="win32"?new f(`${je}:`):await x()?new y(je):new h(io)}};import{homedir as ao}from"os";import{join as co}from"path";var Oe="kanonak-session",lo=co(ao(),".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(Oe):process.platform==="win32"?new f(`${Oe}:`):await x()?new y(Oe):new h(lo)}};function le(r,e=5*6e4,t=Date.now()){let n=Date.parse(r.expiresAt);return Number.isNaN(n)?!0:t>=n-e}var yt="key_thumbprint",R=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 n=`https://${t}/.well-known/oauth-protected-resource`,o=await po(n),i=o&&Array.isArray(o.authorization_servers)?o.authorization_servers.filter(a=>typeof a=="string"):[],s=i.length>0?i:null;return this.prCache.set(t,s),s}async discover(e){let t=l(e);if(this.cache.has(t))return this.cache.get(t);let n=`https://${t}/.well-known/oauth-authorization-server`,o=await this.tryEndpoint(n);if(!o){let i=`https://${t}/.well-known/openid-configuration`;o=await this.tryEndpoint(i)}return this.cache.set(t,o),o}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(o){let i=o instanceof Error?o.message:String(o);return i.includes("ENOTFOUND")||i.includes("ECONNREFUSED")?(console.error(` OAuth discovery: ${e} \u2014 host unreachable (${i})`),console.error(" If the server is behind a VPN, ensure you are connected.")):i.includes("CERT")||i.includes("SSL")||i.includes("TLS")?(console.error(` OAuth discovery: ${e} \u2014 TLS error (${i})`),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: ${i}`),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 n;try{n=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(n.issuer),authorizationEndpoint:g(n.authorization_endpoint),tokenEndpoint:g(n.token_endpoint),registrationEndpoint:g(n.registration_endpoint),revocationEndpoint:g(n.revocation_endpoint),scopesSupported:k(n.scopes_supported),responseTypesSupported:k(n.response_types_supported),grantTypesSupported:k(n.grant_types_supported),codeChallengeMethodsSupported:k(n.code_challenge_methods_supported),tokenEndpointAuthMethodsSupported:k(n.token_endpoint_auth_methods_supported),dpopSigningAlgValuesSupported:k(n.dpop_signing_alg_values_supported),enrollmentEndpoint:g(n.enrollment_endpoint),enrollmentIssuanceProtocols:k(n.enrollment_issuance_protocols),enrollmentKeyTypes:k(n.enrollment_key_types),enrollmentScopesSupported:k(n.enrollment_scopes_supported),enrollmentConsentBindingParam:g(n.enrollment_consent_binding_param),sessionEndpoint:g(n.session_endpoint),sessionEndpointAuthMethod:g(n.session_endpoint_auth_method)}}};async function po(r){try{let e=await fetch(r);return e.ok?await e.json():null}catch{return null}}function g(r){return typeof r=="string"?r:null}function k(r){return Array.isArray(r)?r.filter(e=>typeof e=="string"):null}import*as ht from"https";import{createPrivateKey as uo}from"crypto";var mo="client_credentials",S=class extends Error{},T=class{constructor(e=ho){this.transport=e}transport;async exchange(e,t,n={}){let o=yo(t.keyMaterial),i=new URLSearchParams({grant_type:mo});n.scope&&i.set("scope",n.scope);let s=i.toString(),a;try{a=await this.transport({url:e,certPem:fo(t),keyPem:o,body:s,contentType:"application/x-www-form-urlencoded"})}catch(O){throw new S(`mTLS session exchange to ${e} failed: ${O.message}`)}if(a.status<200||a.status>=300)throw new S(`Session endpoint ${e} returned HTTP ${a.status}: ${a.body.slice(0,300)}`);let c;try{c=JSON.parse(a.body)}catch{throw new S(`Session endpoint returned a non-JSON response: ${a.body.slice(0,200)}`)}if(typeof c.access_token!="string"||!c.access_token)throw new S("Session response had no access_token.");let p=typeof c.expires_in=="number"?c.expires_in:0,d=n.nowMs??Date.now();return{token:c.access_token,tokenType:typeof c.token_type=="string"&&c.token_type?c.token_type:"Bearer",expiresAt:new Date(d+p*1e3).toISOString(),scope:typeof c.scope=="string"?c.scope:""}}};function fo(r){let e=r.chainPem.trim();return e?`${r.certificatePem.replace(/\s+$/,"")}
100
+ ${e}
101
+ `:r.certificatePem}function yo(r){try{return uo({key:r,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 ho=r=>new Promise((e,t)=>{let n=new URL(r.url),o=ht.request({method:"POST",hostname:n.hostname,port:n.port||443,path:n.pathname+n.search,cert:r.certPem,key:r.keyPem,headers:{"Content-Type":r.contentType,"Content-Length":Buffer.byteLength(r.body),Accept:"application/json"},timeout:3e4},i=>{let s=[];i.on("data",a=>s.push(a)),i.on("end",()=>e({status:i.statusCode??0,body:Buffer.concat(s).toString("utf-8")}))});o.on("error",t),o.on("timeout",()=>o.destroy(new Error("mTLS request timed out"))),o.write(r.body),o.end()});var _=class extends Error{},N=class{discovery;deviceStore;sessionStore;exchange;constructor(e={}){this.discovery=e.discovery??new R,this.deviceStore=e.deviceStore??new D,this.sessionStore=e.sessionStore??new $,this.exchange=e.exchange??new T}async acquire(e,t={}){let n=l(e),o=await this.sessionEndpoint(e);if(!o)throw new _(`'${n}' does not advertise a session endpoint \u2014 it issues no scoped sessions (public registries need no credential).`);let i=await this.deviceStore.get(e);if(!i)throw new _(`No device certificate enrolled for '${n}'. Run 'kanonak device enroll ${e}' first.`);let s=await this.exchange.exchange(o,i,t),a={token:s.token,tokenType:s.tokenType,expiresAt:s.expiresAt,scope:s.scope};return await this.sessionStore.store(n,a),a}async getValidSession(e){let t=l(e),n=await this.sessionStore.get(t);return n&&!le(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 pe=class{discovery;sessions;constructor(e={}){this.discovery=e.discovery??new R,this.sessions=e.sessionManager??new N}async resolve(e){let t=await this.discovery.discoverProtectedResource(e);if(!t||t.length===0)return null;for(let n of t){let o=go(n);if(!o)continue;let i=await this.sessions.getValidSession(o);if(i)return{authority:o,token:i.token,expiresAt:i.expiresAt,scope:i.scope}}return null}};function go(r){try{return new URL(r).host}catch{return}}import{createHash as ko,createPrivateKey as So,generateKeyPairSync as wo,randomUUID as bo,sign as Po}from"crypto";function kt(){let{publicKey:r,privateKey:e}=wo("ec",{namedCurve:"P-256"});return{publicKey:r.export({format:"jwk"}),privateKey:e.export({format:"jwk"})}}function z(r,e,t,n,o,i){let s={alg:"ES256",typ:"dpop+jwt",jwk:{kty:e.kty,crv:e.crv,x:e.x,y:e.y}},a={jti:bo(),htm:t.toUpperCase(),htu:n,iat:Math.floor(Date.now()/1e3)};return o&&(a.ath=ko("sha256").update(o).digest("base64url")),i&&(a.nonce=i),vo(s,a,r)}function St(r){return!r||r.length===0?!1:r.some(e=>e.toUpperCase()==="ES256")}function vo(r,e,t){let n=gt(JSON.stringify(r)),o=gt(JSON.stringify(e)),i=`${n}.${o}`,s=So({key:t,format:"jwk"}),c=Po("SHA256",Buffer.from(i),{key:s,dsaEncoding:"ieee-p1363"}).toString("base64url");return`${i}.${c}`}function gt(r){return Buffer.from(r,"utf-8").toString("base64url")}function wt(r){let e=new Map;return async(t,n,o="GET")=>{if(!r)return I(t,{method:o});let i=await r.getCredential(n);if(!i?.accessToken)return I(t,{method:o});Q(i)&&console.warn(` Warning: Access token for '${n}' is expired. Run 'kanonak login ${n}' to re-authenticate.`);let s={};if(i.dpopKeyPair){let c=e.get(n);try{let p=z(i.dpopKeyPair.privateKey,i.dpopKeyPair.publicKey,o,t,i.accessToken,c);s.Authorization=`DPoP ${i.accessToken}`,s.DPoP=p}catch(p){let d=p instanceof Error?p.message:String(p);console.error(` Error: Failed to create DPoP proof for '${n}': ${d}
102
+ The stored key pair may be corrupted. Run 'kanonak login ${n}' to re-authenticate.`),s.Authorization=`Bearer ${i.accessToken}`}}else s.Authorization=`Bearer ${i.accessToken}`;let a=await I(t,{method:o,headers:s});if(a.status===401&&i.dpopKeyPair){let c=a.headers.get("DPoP-Nonce");if(c){e.set(n,c);try{let p=z(i.dpopKeyPair.privateKey,i.dpopKeyPair.publicKey,o,t,i.accessToken,c);s.DPoP=p,a=await I(t,{method:o,headers:s})}catch{}}}return a}}import{readFileSync as Ro,writeFileSync as Eo,existsSync as Co}from"fs";import{createHash as xo}from"crypto";import bt from"js-yaml";var Pt="kanonak.lock",Ao=`# This file is generated by Kanonak CLI. Do not edit manually.
103
+ `;function vt(r=Pt){if(!Co(r))return null;let e=Ro(r,"utf-8"),t=bt.load(e);return!t||typeof t!="object"||t.version!=="1"?null:{version:"1",lastUpdated:t.lastUpdated??new Date().toISOString(),packages:t.packages??{}}}function Rt(r,e=Pt){r.lastUpdated=new Date().toISOString();let t={};for(let o of Object.keys(r.packages).sort())t[o]=r.packages[o];r.packages=t;let n=bt.dump(r,{lineWidth:-1,sortKeys:!1,quotingType:'"'});Eo(e,Ao+n,"utf-8")}function Et(r){return`sha256:${xo("sha256").update(r).digest("hex")}`}import*as Ve from"js-yaml";import{canonicalForm as Io,canonicalHash as Ko}from"@kanonak-protocol/canonical";function Be(r){return typeof r=="object"&&r!==null&&Array.isArray(r.subjects)}import{CANONICAL_FORM_VERSION as $t}from"@kanonak-protocol/canonical";function Ct(r){return Io(Be(r)?r:xt(r))}function de(r){return Ko(Be(r)?r:xt(r))}function xt(r){let e=[];for(let t of r)t instanceof b&&e.push({uri:_o(t),statements:Me(t.statement)});return{subjects:e}}function Me(r){let e=[];for(let t of r){let n=To(t);if(!n)continue;let o=Do(t);o&&e.push({predicate:n,value:o})}return e}function Do(r){if(r instanceof we&&r.carrier)return{lit:r.lexical??String(r.object),datatype:It(r.carrier)};if(r instanceof be)return{raw:r.object};if(r instanceof Pe)return{raw:r.lexical??String(r.object)};if(r instanceof ve)return{raw:r.lexical??String(r.object)};if(r instanceof Re)return{ref:Kt(r.object)};if(r instanceof Ee)return At(r.object);if(r instanceof Ce)return{list:r.object.map($o)}}function At(r){let e=Me(r.statement);return r.name&&r.name.length>0?{embed:{name:r.name,statements:e}}:{embed:{statements:e}}}function $o(r){if(r instanceof C)return{ref:Kt(r)};if(r instanceof P)return At(r);if(r instanceof Se){if(r.carrier)return{lit:r.lexical??String(r.value),datatype:It(r.carrier)};let e=r.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(r instanceof ke)return{embed:{statements:Me(r.statement)}};throw new Error(`canonicalForm: list item of unrecognized kind (${r.constructor?.name??typeof r}); add canonicalization support before hashing data that contains it`)}function It(r){return r===Z.LangString?"kanonak.org/core-rdf/langString":`kanonak.org/core-xsd/${r}`}function To(r){let e=r.predicate;if(e)return Dt(e.subject)}function _o(r){let e=r.namespace??"",t=r.name??"";return`${e}/${t}`}function Kt(r){return Dt(r.subject)}function Dt(r){let e=r.version;return e&&typeof e.major=="number"?`${r.publisher}/${r.package_}@${e.major}.${e.minor}.${e.patch}/${r.name}`:`${r.publisher}/${r.package_}/${r.name}`}import{VersionOperator as Tt}from"@kanonak-protocol/types/document/models/enums";var No="0.0.0",j=class{constructor(e,t=new M,n){this.repository=e;this.parser=t;this.objectParser=n??new U(this.parser)}repository;parser;objectParser;imports(){return new W}serializeValue(e,t){return jt(e,t)}async buildContentAddressed(e){let t=e.book.toImports(),n=await this.hashBody(e.publisher,t,e.body),o=Le(n),i={type:"EphemeralPackage",publisher:e.publisher,imports:t};e.contentHashProperty&&(i[e.contentHashProperty]=n),Object.assign(i,e.header??{}),i.imports=t;let s={[o]:i,...e.body},a=this.dump(s);return{yaml:a,byteCount:Nt(a),contentHash:n,packageName:o,publisher:e.publisher,resourceCount:Object.keys(e.body).length}}async buildNamed(e){let t=e.book.toImports(),n={type:e.type??"Package",publisher:e.publisher,version:e.version,imports:t},o;e.contentHashProperty&&(o=await this.hashBody(e.publisher,t,e.body),n[e.contentHashProperty]=o),Object.assign(n,e.header??{}),n.imports=t;let i={[e.name]:n,...e.body},s=this.dump(i),a={yaml:s,byteCount:Nt(s),packageName:e.name,publisher:e.publisher,resourceCount:Object.keys(e.body).length};return o!==void 0&&(a.contentHash=o),a}dump(e){return Ve.dump(e,{lineWidth:-1})}async hashBody(e,t,n){let o={[_t]:{type:"EphemeralPackage",publisher:e,imports:t},...n},i=this.parser.parse(Ve.dump(o,{lineWidth:-1})),s=i.metadata.namespace_?.toString(),c=(await this.objectParser.parseKanonaks(new Xe(i,this.repository))).filter(p=>p instanceof b&&p.namespace===s&&p.name!==_t);for(let p of c)p.namespace="ephemeral";return de(c)}},_t="__pkgbuilder_probe__";function Nt(r){return new TextEncoder().encode(r).length}function Le(r){let e="sha256:",t=r.startsWith(e)?e.length:0;return`q-${r.slice(t,t+16)}`}var W=class{byKey=new Map;aliases=new Set;ensure(e,t,n,o,i=Tt.Major){let s=`${e}/${t}@${n}`,a=this.byKey.get(s);if(a)return a.alias;let c=this.uniqueAlias(o);return this.byKey.set(s,{publisher:e,package_:t,version:n,alias:c,match:i}),c}ref(e){if(!e.version||typeof e.version.major!="number")throw new Error(`Cannot serialize a reference to ${e.publisher}/${e.package_}/${e.name} without a version.`);return`${this.ensure(e.publisher,e.package_,E(e.version),e.package_)}.${e.name}`}refLatest(e,t,n,o){return`${this.ensure(e,t,No,o??t,Tt.Any)}.${n}`}toImports(){let e=new Map;for(let n of this.byKey.values()){let o=e.get(n.publisher)??[];o.push(n),e.set(n.publisher,o)}return[...e.keys()].sort().map(n=>({publisher:n,packages:e.get(n).sort((o,i)=>o.package_<i.package_?-1:1).map(o=>({package:o.package_,match:ge(o.match),version:o.version,alias:o.alias}))}))}uniqueAlias(e){let t=G(e)||"pkg",n=t,o=2;for(;this.aliases.has(n);)n=`${t}${o++}`;return this.aliases.add(n),n}};function jt(r,e){if(r!=null){if(typeof r=="string"||typeof r=="number"||typeof r=="boolean")return r;if(r instanceof C)return e.ref(r.subject);if(Array.isArray(r)){let t=r.map(n=>jt(n,e)).filter(n=>n!==void 0);return t.length>0?t:void 0}if(r instanceof P)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(jo(r))throw new Error(`Value produced a bare URI without a version (${r.publisher}/${r.package_}/${r.name}); cannot serialize it as a reference.`)}}function G(r){return r.replace(/[^A-Za-z0-9-]/g,"-").replace(/-+/g,"-").replace(/^-|-$/g,"")}function jo(r){return typeof r=="object"&&r!==null&&typeof r.publisher=="string"&&typeof r.package_=="string"&&typeof r.name=="string"}var ue=class{constructor(e){this.producers=e}producers;produced=new Map;producerFor(e,t){return this.producers.find(n=>n.canProduce(e,t))}async produceCached(e,t,n,o){let i=`${t}/${n}@${E(o)}`,s=this.produced.get(i);if(s)return s;let{document:a}=await e.produce(t,n,o);return this.produced.set(i,a),a}async getHighestCompatibleVersionAsync(e,t){let n=this.producerFor(e,t.packageName);if(!n)return null;let o={operator:t.versionOperator,version:t.version},i=await n.resolveVersion(e,t.packageName,o);return i?this.produceCached(n,e,t.packageName,i):null}async getDocumentAsync(e){let t;try{t=Ke(e)}catch{return null}if(t.kind!=="package"||!t.version)return null;let n=this.producerFor(t.publisher,t.package_);return n?this.produceCached(n,t.publisher,t.package_,t.version):null}async getDocumentsByNamespaceAsync(e,t){return Array.from(this.produced.values()).filter(n=>{let o=n.metadata.namespace_;return o!=null&&o.publisher===e&&o.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 Ue={async authorize(){return{allowed:!0}}},Fe={async record(){}},J=class extends Error{constructor(t,n){let o=`${t.publisher}/${t.package_}${t.version?`@${t.version.major}.${t.version.minor}.${t.version.patch}`:""}`;super(`Not entitled to produce ${o}${n?`: ${n}`:""}`);this.address=t;this.reason=n;this.name="EntitlementDeniedError"}address;reason},me=class{inner;ctx;policy;meter;constructor(e,t,n=Ue,o=Fe){this.inner=e,this.ctx=t,this.policy=n,this.meter=o}canProduce(e,t){return this.inner.canProduce(e,t)}async resolveVersion(e,t,n){return await this.assertAllowed({publisher:e,package_:t,version:n.version}),this.inner.resolveVersion(e,t,n)}async produce(e,t,n){let o={publisher:e,package_:t,version:n};await this.assertAllowed(o);let i=await this.inner.produce(e,t,n);return await this.meter.record(this.ctx,o,i),i}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",w="view",Ot="core-kanonak",Oo={publisher:u,package_:w,name:"rootView"},Bo={publisher:u,package_:w,name:"bind"},Mo={publisher:u,package_:w,name:"produces"},Vo={publisher:u,package_:w,name:"projections"},Lo={publisher:u,package_:w,name:"where"},Uo={publisher:u,package_:w,name:"value"},Fo={publisher:u,package_:w,name:"as"},fe=class{constructor(e,t=new M){this.repository=e;this.parser=t;this.objectParser=new U(this.parser),this.builder=new j(this.repository,this.parser,this.objectParser)}repository;parser;objectParser;builder;async materialize(e,t={}){let n=await this.objectParser.parseKanonaks(this.repository),o=this.resolveView(n,e),i=V(o,Bo);if(!i)throw new Error(`View ${o.namespace}/${o.name} declares no view.bind; cannot materialize.`);let s=V(o,Mo);if(!s)throw new Error(`View ${o.namespace}/${o.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=Ho(o),c=Bt(n,u,Ot),p=Bt(n,u,w),d=this.builder.imports(),O=d.ensure(u,Ot,c,"ck"),Vt=d.ensure(u,w,p,"v"),Lt=d.ref(s),Ut=new Qe(this.repository,this.parser,this.objectParser),He=new Ye(Ut,n),Ft=this.readProjections(n,o),Ht=Go(o,Lo),zt=this.findInstances(n,i,await this.reason(t)),ze={},Wt=new Set;for(let q of zt){if(!await this.passesWhere(He,n,Ht,q))continue;let he={type:Lt};for(let Ge of Ft){let Gt=await this.evaluateValue(He,n,Ge.value,q),Je=this.builder.serializeValue(Mt(Gt),d);Je!==void 0&&(he[d.ref(Ge.as)]=Je)}let We=v(q);We&&(he[`${Vt}.derivedFrom`]=d.ref(We)),ze[this.rowName(q,Wt)]=he}let ye={};t.resolvedAt&&(ye[`${O}.resolvedAt`]=t.resolvedAt),t.invocationId&&(ye[`${O}.id`]=t.invocationId);let B=await this.builder.buildContentAddressed({publisher:a,book:d,body:ze,contentHashProperty:`${O}.contentHash`,header:ye});return{yaml:B.yaml,contentHash:B.contentHash,packageName:B.packageName,publisher:B.publisher,rowCount:B.resourceCount}}resolveView(e,t){let n=Y(e,t);if(!n)throw new Error(`View ${t.publisher}/${t.package_}/${t.name} not found in the catalog.`);let o=V(n,Oo);if(o){let i=Y(e,o);if(!i)throw new Error(`ViewPackage ${t.name} names rootView ${o.name}, which is not in the catalog.`);return i}return n}readProjections(e,t){let n=[];for(let o of Ae(t,Vo)){let i=o instanceof P?o:o instanceof C?Y(e,o.subject):void 0;if(!i)continue;let s=xe(i,Uo),a=V(i,Fo);s&&a&&n.push({value:s,as:a})}return n}async reason(e){return new Ie({profile:e.reasoningProfile??"owl-rl-classification"}).reason(this.repository)}findInstances(e,t,n){let o=Wo(e),i=[],s=new Set;for(let a of n.getInstancesOfClass(t)){if(s.has(a))continue;s.add(a);let c=o.get(a);c&&i.push(c)}return i.sort((a,c)=>{let p=L(v(a)),d=L(v(c));return p<d?-1:p>d?1:0}),i}async passesWhere(e,t,n,o){for(let i of n){let s=await this.evaluateValue(e,t,i,o);if(!Jo(s))return!1}return!0}async evaluateValue(e,t,n,o){let i=Ze(n,"view-projection",{catalog:t,depth:0}),s=new Map([["input",o]]);return e.evaluate(i,s)}rowName(e,t){let n=G(e.name)||"row",o=n,i=2;for(;t.has(o);)o=`${n}-${i++}`;return t.add(o),o}};function Mt(r){return De(r)?r.value:Array.isArray(r)?r.map(Mt):r}function Ho(r){let e=v(r);if(!e)throw new Error(`Could not derive a publisher from view ${r.namespace}/${r.name}.`);return e.publisher}function Bt(r,e,t){let n=zo(r,e,t);if(!n)throw new Error(`Package ${e}/${t} is not in the catalog; it must be importable to materialize a view.`);return n}function zo(r,e,t){let n;for(let o of r){if(!(o instanceof b))continue;let i=v(o);!i||i.publisher!==e||i.package_!==t||!i.version||(!n||X(i.version,n)>0)&&(n=i.version)}return n?E(n):void 0}function Wo(r){let e=new Map,t=new Map;for(let n of r){if(!(n instanceof b))continue;let o=v(n);if(!o||!o.version)continue;let i=L(o),s=t.get(i);(!s||X(o.version,s)>0)&&(t.set(i,o.version),e.set(i,n))}return e}function Go(r,e){let t=xe(r,e);return t?[t]:Ae(r,e).filter(n=>n instanceof P)}function Jo(r){return r===!0?!0:r===!1||r===void 0||r===null?!1:typeof r=="string"?r.length>0:typeof r=="number"?r!==0:De(r)?r.value.length>0:Array.isArray(r)?r.length>0:!!r}export{kn as AmbiguousReferenceRule,ve as BooleanStatement,$t as CANONICAL_FORM_VERSION,Z as Carrier,Rn as ClassDefinitionRule,dn as ClassHierarchyCycleRule,or as CompositeKanonakDocumentRepository,pe as CredentialResolver,ce as CredentialStore,yt as DEFAULT_CONSENT_BINDING_PARAM,ke as DefinedKanonak,D as DeviceCertificateStore,nr as DocumentLocation,$r as EdgeType,P as EmbeddedKanonak,cn as EmbeddedKanonakTypeRule,Ee as EmbeddedStatement,J as EntitlementDeniedError,me as EntitlementProducer,rr as FileSystemKanonakDocumentRepository,Br as GitIgnoreFilter,Tr as GraphBuilder,mr as HttpKanonakDocumentRepository,W as ImportBook,ln as ImportExistenceRule,tr as InMemoryKanonakDocumentRepository,ar as KANONAK_USER_AGENT,kr as Kanonak,Vr as KanonakDocumentPositions,U as KanonakObjectParser,Cn as KanonakObjectValidator,M as KanonakParser,Sr as KanonakUri,Fr as KanonakUriBuilder,zr as KanonakUrlResolver,xr as KanonakVocabulary,Ce as ListStatement,Se as LiteralKanonak,fr as LocalFirstRepository,yr as LockAwareRepository,In as LookRenderer,En as MarkdownLinkRule,br as MarkdownStatement,hn as NamespaceImportCycleRule,rn as NamespacePrefixRule,Dr as NodeType,Pe as NumberStatement,R as OAuthDiscovery,jr as OWL_RL_CLASSIFICATION_RULES,wn as ObjectPropertyValueValidationRule,Qr as OntologyValidationError,Yr as OntologyValidationResult,j as PackageBuilder,an as PackageHeaderRule,ue as ProducerRepository,bn as PropertyDomainRule,un as PropertyHierarchyCycleRule,Pn as PropertyKindRangeConsistencyRule,Mr as PropertyMetadata,Sn as PropertyRangeReferenceRule,mn as PropertyRangeRequiredRule,on as PropertyTypeSpecificityRule,pr as PublisherConfigResolver,dr as PublisherIndex,Nr as RDFS_RULES,Ie as Reasoner,Or as ReasoningResult,C as ReferenceKanonak,Re as ReferenceStatement,sr as RepositoryFactory,vn as ReservedNameShadowRule,nn as ResourceNamingRule,Pr as ResourceResolver,Kr as ResourceTypeClassifier,we as ScalarStatement,_ as SessionError,T as SessionExchange,S as SessionExchangeError,N as SessionManager,$ as SessionStore,wr as Statement,be as StringStatement,fn as SubClassOfReferenceRule,yn as SubPropertyOfReferenceRule,b as SubjectKanonak,sn as SubjectKanonakTypeRequiredRule,_r as TripleStore,vr as TypeResolver,gn as UnresolvedPredicateRule,pn as UnresolvedReferenceRule,tn as ValidationCache,en as ValidationContext,Zr as ValidationSeverity,Oa as VersionOperator,fe as ViewMaterializer,Ue as allowAllPolicy,ur as assertPackageIdentity,gr as buildLocalFirstRepository,Kn as buildOntologyModel,Ct as canonicalForm,de as canonicalHash,qe as carrierOf,hr as collectKanonakFiles,X as compareVersions,Et as computeIntegrity,Le as contentAddressedName,qr as contextTypesOf,wt as createAuthenticatedFetch,z as createDPoPProof,Xt as createVersion,Ir as extractMarkdownLinks,xn as findDerivation,Xr as findInstancesByType,Ar as findMalformedReferences,Ur as findMarkdownLinkAt,Hr as formatKanonakAddress,E as formatVersion,kt as generateDPoPKeyPair,ir as getGlobalCachePath,lr as getKanonakUserAgent,ee as hasValidToken,Zt as isCompatibleVersion,Q as isExpired,Qt as isMajorCompatible,I as kanonakFetch,vt as loadLockFile,Rr as makeUriKey,Fe as noopMeter,l as normalizeHost,Ke as parseKanonakAddress,Yt as parseVersionString,Lr as parseWithPositions,er as pickHighestDocument,Gr as propertiesInScope,An as resolveDisplayValue,Jr as resolvePropertyStep,G as sanitizeName,Rt as saveLockFile,St as serverSupportsDPoP,le as sessionNeedsRefresh,cr as setKanonakUserAgent,v as subjectUri,Wr as superClassChain,Er as tripleKey,L as uriKey,Cr as uriTriple,Jt as versionOperatorFromChar,ge as versionOperatorToChar,qt as versionsEqual};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kanonak-protocol/sdk",
3
- "version": "4.20.0",
3
+ "version": "5.1.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": "^4.20.0",
129
+ "@kanonak-protocol/types": "^5.1.0",
130
130
  "ignore": "^7.0.5",
131
131
  "js-yaml": "^4.1.0",
132
132
  "yaml": "^2.7.0"
@@ -1,14 +0,0 @@
1
- import type { CredentialBackend, StoredCredential } from './CredentialBackend.js';
2
- /**
3
- * Browser credential storage using IndexedDB.
4
- *
5
- * Stores StoredCredential objects per publisher hostname.
6
- * IndexedDB is browser-managed, not accessible as files on disk,
7
- * and survives page reloads and browser restarts.
8
- */
9
- export declare class BrowserCredentialBackend implements CredentialBackend {
10
- get(publisher: string): Promise<StoredCredential | null>;
11
- store(publisher: string, credential: StoredCredential): Promise<void>;
12
- remove(publisher: string): Promise<void>;
13
- list(): Promise<string[]>;
14
- }
@@ -1,42 +0,0 @@
1
- import type { DPoPKeyPair } from './CredentialBackend.js';
2
- /**
3
- * Browser-native DPoP implementation using Web Crypto API (RFC 9449).
4
- *
5
- * Key advantage over Node.js implementation: private keys can be
6
- * non-extractable, meaning even XSS cannot read the key material —
7
- * it can only be used for signing operations.
8
- *
9
- * All operations are async (Web Crypto requirement).
10
- */
11
- /** CryptoKey pair stored alongside the JWK public key for DPoP proofs */
12
- export interface BrowserDPoPKeys {
13
- /** CryptoKey for signing (may be non-extractable) */
14
- signingKey: CryptoKey;
15
- /** JWK of the public key (included in DPoP proof header) */
16
- publicKeyJwk: JsonWebKey;
17
- }
18
- /**
19
- * Generate an EC P-256 key pair for DPoP using Web Crypto.
20
- * The private key is marked non-extractable for maximum security.
21
- */
22
- export declare function generateBrowserDPoPKeys(): Promise<BrowserDPoPKeys>;
23
- /**
24
- * Generate an extractable key pair that can be serialized to StoredCredential.
25
- * Used when credentials need to persist across sessions in IndexedDB.
26
- */
27
- export declare function generateBrowserDPoPKeyPair(): Promise<{
28
- keys: BrowserDPoPKeys;
29
- dpopKeyPair: DPoPKeyPair;
30
- }>;
31
- /**
32
- * Import a DPoPKeyPair (from IndexedDB/StoredCredential) back into CryptoKey.
33
- */
34
- export declare function importDPoPKeys(dpopKeyPair: DPoPKeyPair): Promise<BrowserDPoPKeys>;
35
- /**
36
- * Create a DPoP proof JWT using Web Crypto (async).
37
- */
38
- export declare function createBrowserDPoPProof(keys: BrowserDPoPKeys, method: string, url: string, accessToken?: string, nonce?: string): Promise<string>;
39
- /**
40
- * Check if a server supports DPoP from its metadata.
41
- */
42
- export declare function browserServerSupportsDPoP(dpopSigningAlgValues?: string[] | null): boolean;
@@ -1,55 +0,0 @@
1
- import type { StoredCredential } from './CredentialBackend.js';
2
- import type { BrowserDPoPKeys } from './BrowserDPoP.js';
3
- /**
4
- * OAuth server metadata (RFC 8414).
5
- * Reuses the same shape as the CLI's OAuthDiscovery.
6
- */
7
- export interface OAuthServerMetadata {
8
- issuer?: string | null;
9
- authorizationEndpoint?: string | null;
10
- tokenEndpoint?: string | null;
11
- registrationEndpoint?: string | null;
12
- revocationEndpoint?: string | null;
13
- dpopSigningAlgValuesSupported?: string[] | null;
14
- codeChallengeMethodsSupported?: string[] | null;
15
- }
16
- export interface BrowserOAuthResult {
17
- success: boolean;
18
- host?: string;
19
- error?: string;
20
- }
21
- /**
22
- * Browser-native OAuth 2.0 flow with DCR, PKCE, and DPoP.
23
- *
24
- * Uses popup window + postMessage for the authorization redirect,
25
- * avoiding full-page redirect which would lose application state.
26
- *
27
- * The callback page (callback.html) relays the auth code back
28
- * to the opener window via postMessage.
29
- */
30
- export declare class BrowserOAuthFlow {
31
- private readonly credentialBackend;
32
- private readonly callbackUrl;
33
- /**
34
- * @param callbackUrl — URL of the callback.html page that relays auth codes.
35
- * Defaults to `${window.location.origin}/browser/callback.html`
36
- */
37
- constructor(callbackUrl?: string);
38
- /**
39
- * Full OAuth authorization flow via popup window.
40
- */
41
- authorize(host: string): Promise<BrowserOAuthResult>;
42
- /**
43
- * Get stored credential and prepare DPoP keys for authenticated fetch.
44
- */
45
- getCredentialWithKeys(publisher: string): Promise<{
46
- credential: StoredCredential;
47
- dpopKeys: BrowserDPoPKeys | null;
48
- } | null>;
49
- logout(host: string): Promise<BrowserOAuthResult>;
50
- listAuthenticated(): Promise<string[]>;
51
- private discover;
52
- private registerClient;
53
- private openAuthPopup;
54
- private exchangeCode;
55
- }
@@ -1,13 +0,0 @@
1
- /**
2
- * Browser-native auth module for Kanonak Protocol SDK.
3
- *
4
- * Uses Web Crypto API for DPoP, IndexedDB for credential storage,
5
- * and popup-based OAuth flow for authentication.
6
- */
7
- export { BrowserCredentialBackend } from './BrowserCredentialBackend.js';
8
- export { generateBrowserDPoPKeys, generateBrowserDPoPKeyPair, importDPoPKeys, createBrowserDPoPProof, browserServerSupportsDPoP, } from './BrowserDPoP.js';
9
- export type { BrowserDPoPKeys } from './BrowserDPoP.js';
10
- export { BrowserOAuthFlow } from './BrowserOAuthFlow.js';
11
- export type { BrowserOAuthResult, OAuthServerMetadata } from './BrowserOAuthFlow.js';
12
- export type { CredentialBackend, StoredCredential, DPoPKeyPair } from './CredentialBackend.js';
13
- export { isExpired, hasValidToken, normalizeHost } from './CredentialBackend.js';