@kanonak-protocol/cli 5.3.0 → 5.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -18,6 +18,8 @@ import type { FetchLike } from './IssuanceClient.js';
18
18
  /** The discovery capability the flow needs (satisfied by {@link OAuthDiscovery}). */
19
19
  export interface EnrollmentMetadataSource {
20
20
  discover(host: string): Promise<OAuthServerMetadata | null>;
21
+ /** Resolve a Kanonak publisher to its authority issuer URL(s) via kanonak.json. */
22
+ discoverKanonakAuthorities(host: string): Promise<string[] | null>;
21
23
  }
22
24
  /** Just enough of {@link CredentialStore} to reuse a stored OAuth client_id. */
23
25
  export interface CredentialLookup {
@@ -58,7 +60,7 @@ export declare class EnrollmentFlow {
58
60
  private readonly fetchImpl;
59
61
  private readonly openBrowser;
60
62
  constructor(deps?: EnrollmentFlowDeps);
61
- enroll(host: string, opts: EnrollOptions): Promise<EnrollmentResult>;
63
+ enroll(publisher: string, opts: EnrollOptions): Promise<EnrollmentResult>;
62
64
  /** A stored OAuth client_id for the host, or a freshly dynamically-registered one. */
63
65
  private resolveClientId;
64
66
  /** Exchange an authorization code (PKCE) for the short-lived consent token. */
@@ -63,10 +63,15 @@ export declare class GenericCapabilityHandler {
63
63
  */
64
64
  private deployFromDoc;
65
65
  /**
66
- * On a "package not found" error, scan the publisher index for
67
- * approximate name matches and print up to 5 suggestions. Helps
68
- * users recover from typos and from passing a 3-segment URI to
69
- * `add` against an old CLI that lacked instance support.
66
+ * A publisher's OWN packages as pinned by its served `kanonak.lock` (keys
67
+ * under `<publisher>/`). The lock-derived package list there is no index
68
+ * enumeration. Empty when the publisher serves no lock.
69
+ */
70
+ private lockedOwnPackages;
71
+ /**
72
+ * On a "package not found" error, scan the publisher's pinned packages for
73
+ * approximate name matches and print up to 5 suggestions. Helps users recover
74
+ * from typos and from passing a 3-segment URI to `add`.
70
75
  */
71
76
  private printPackageSuggestions;
72
77
  remove(capability: LoadedCapability, name: string, options: Record<string, string>): Promise<void>;
@@ -0,0 +1,64 @@
1
+ import type { LockFile, LockEntry, PublisherConfig, DeviceEnrollmentRecord, AuthenticatedFetchFn } from '@kanonak-protocol/sdk';
2
+ /** The outcome of a connect, for a host (CLI / VS Code) to report. */
3
+ export interface ConnectResult {
4
+ connected: boolean;
5
+ enrolled: boolean;
6
+ installed: number;
7
+ /** A failure reason, or the sentinel `'aborted'` when the user declined the install. */
8
+ error?: string;
9
+ }
10
+ /**
11
+ * Injectable collaborators so `connect` runs identically across surfaces (CLI,
12
+ * VS Code) and is testable without network, a device, or stdin. Every field
13
+ * defaults to the real implementation.
14
+ */
15
+ export interface ConnectDeps {
16
+ fetchFn?: AuthenticatedFetchFn;
17
+ discovery?: {
18
+ discoverKanonakAuthorities(host: string): Promise<string[] | null>;
19
+ };
20
+ configResolver?: {
21
+ getConfig(host: string): Promise<PublisherConfig>;
22
+ };
23
+ deviceStore?: {
24
+ get(host: string): Promise<DeviceEnrollmentRecord | null>;
25
+ };
26
+ publisherIndex?: {
27
+ getLock(host: string): Promise<LockFile | null>;
28
+ };
29
+ /** Run device enrollment for a publisher (resolves its authority internally). */
30
+ enroll?: (publisher: string) => Promise<{
31
+ success: boolean;
32
+ thumbprint?: string;
33
+ error?: string;
34
+ }>;
35
+ /** Fetch + verify + cache one pinned package. */
36
+ installEntry?: (publisher: string, packageName: string, entry: LockEntry) => Promise<void>;
37
+ loadLock?: () => LockFile | null;
38
+ saveLock?: (lock: LockFile) => void;
39
+ /** Ask the user to confirm the install. The host supplies its own prompt. */
40
+ confirm?: (question: string) => Promise<boolean>;
41
+ /** Progress output sink. */
42
+ log?: (message: string) => void;
43
+ }
44
+ /**
45
+ * The `connect` orchestrator core (issue #9): given a publisher domain, discover
46
+ * it (kanonak.json → authorization_servers + featured_packages), enroll this
47
+ * device if the publisher is gated and not already enrolled with its authority,
48
+ * then install the featured packages and their pinned closures from the served
49
+ * kanonak.lock. Pure of process/stdout concerns — returns a {@link ConnectResult}
50
+ * and reports progress through `deps.log` — so the CLI and VS Code wrap it the
51
+ * same way. A public publisher (no authorization_servers) never enrolls.
52
+ */
53
+ export declare function connect(publisher: string, options: {
54
+ install?: boolean;
55
+ yes?: boolean;
56
+ }, deps?: ConnectDeps): Promise<ConnectResult>;
57
+ /**
58
+ * `kanonak connect <publisher>` — the CLI wrapper: console output, a stdin
59
+ * confirmation prompt, and a non-zero exit on failure.
60
+ */
61
+ export declare function connectCommand(publisher: string, options: {
62
+ install?: boolean;
63
+ yes?: boolean;
64
+ }): Promise<void>;
@@ -1,8 +1,33 @@
1
+ import { KanonakParser } from '@kanonak-protocol/sdk';
2
+ import type { AuthenticatedFetchFn } from '@kanonak-protocol/sdk';
3
+ import type { LockFile, LockEntry } from '@kanonak-protocol/sdk';
4
+ import { FileCache } from '../cache/FileCache.js';
1
5
  /**
2
6
  * Install a package and its transitive dependencies to the local cache.
3
7
  *
4
- * Usage: kanonak install kanonak.org/core-rdf@1.0.1
5
- * kanonak install kanonak.org/core-rdf (resolves latest compatible)
6
- * kanonak install (install from kanonak.lock)
8
+ * Resolution flows through the publisher's SERVED `kanonak.lock` — the
9
+ * authoritative, integrity-verified closure (one pinned version per package).
10
+ * Installing `publisher/package` installs exactly the version that lock pins
11
+ * plus the closure it pins, verifying every fetched file against the lock's
12
+ * sha256 before caching (the `npm ci` model). There is no version-range
13
+ * selection: the publisher's lock IS the resolution.
14
+ *
15
+ * Usage: kanonak install kanonak.org/core-rdf (install what the lock pins)
16
+ * kanonak install kanonak.org/core-rdf@1.0.1 (must match the pinned version)
17
+ * kanonak install (install from the local kanonak.lock)
7
18
  */
8
19
  export declare function installCommand(packageRef?: string): Promise<void>;
20
+ /**
21
+ * Ensure a pinned package is in the cache: a cache hit is verified against the
22
+ * lock's integrity; a miss is fetched from the entry's `resolved` URL, verified,
23
+ * identity-checked, then cached. Never caches bytes whose hash or namespace
24
+ * disagrees with the lock — a mismatch throws.
25
+ */
26
+ export declare function fetchVerifyCache(publisher: string, packageName: string, entry: LockEntry, fileCache: FileCache, parser: KanonakParser, fetchFn: AuthenticatedFetchFn): Promise<void>;
27
+ /**
28
+ * The keys of `rootKey` and every package reachable through its (transitive)
29
+ * `dependencies`, all resolved within `lock`. A dependency the lock references
30
+ * but does not pin is a broken lock — throw rather than silently install a
31
+ * partial closure.
32
+ */
33
+ export declare function collectClosure(rootKey: string, lock: LockFile): string[];