@kanonak-protocol/cli 5.4.0 → 5.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -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(
|
|
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
|
-
*
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
|
|
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
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
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[];
|