@stigmer/plugin-package 3.18.0-dev.20260918103812 → 3.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/client.ts CHANGED
@@ -15,13 +15,20 @@
15
15
  * order the CLI's original walk produced them;
16
16
  * - the archive and its digest (`archive.ts`): the deterministic zip and
17
17
  * the SHA-256 the server records;
18
+ * - the preparation (`prepare.ts`): select, read, refuse, archive, digest,
19
+ * once, for a tree on disk, on a host, or in a browser's memory;
18
20
  * - the grammars (`refs.ts`): an install ref and a GitHub marketplace
19
21
  * source, with their refusal sentences;
22
+ * - the built-in sources (`builtin.ts`): the official catalogue and the
23
+ * three vendors', listed by every client without configuration;
24
+ * - the release predicate (`release.ts`): which server versions the
25
+ * catalogue is published for;
26
+ * - the re-rooting rule (`reroot.ts`): a zipped folder reads as the folder;
20
27
  * - the vocabulary (`vocabulary.ts`): the labels both surfaces print.
21
28
  *
22
29
  * Nothing here touches the filesystem, the network or any `node:*` module.
23
- * A client's edge (a directory walk, a fetch) produces the candidates and
24
- * the bytes; this entry decides what becomes of them.
30
+ * A client's edge (a directory walk, a fetch, a file pick) produces the
31
+ * candidates and the bytes; this entry decides what becomes of them.
25
32
  */
26
33
 
27
34
  export { DEFAULT_PATTERNS } from "./client/ignore/defaults.js";
@@ -49,6 +56,23 @@ export {
49
56
  selectPluginFiles,
50
57
  } from "./client/select.js";
51
58
  export { DETERMINISTIC_ZIP_MTIME, archivePlugin, digestArchive } from "./client/archive.js";
59
+ export {
60
+ type LazyCandidate,
61
+ type PrepareArchiveOutcome,
62
+ type PrepareFromTreeOptions,
63
+ type PreparePluginOutcome,
64
+ type PreparedPlugin,
65
+ preparePluginArchive,
66
+ preparePluginFromTree,
67
+ } from "./client/prepare.js";
68
+ export {
69
+ type BuiltInMarketplace,
70
+ BUILT_IN_MARKETPLACES,
71
+ builtInSourceRefusal,
72
+ isBuiltInMarketplaceName,
73
+ } from "./client/builtin.js";
74
+ export { isReleaseVersion } from "./client/release.js";
75
+ export { rerootSingleDirectory, stripDirectoryPrefix } from "./client/reroot.js";
52
76
  export {
53
77
  type GitHubMarketplaceSource,
54
78
  type GitHubSourceOutcome,
package/src/index.ts CHANGED
@@ -54,7 +54,7 @@ export type {
54
54
  MarketplaceReadOutcome,
55
55
  MarketplaceWarningKind,
56
56
  } from "./marketplace/outcome.js";
57
- export { hasMarketplaceFile, readMarketplace } from "./marketplace/read-marketplace.js";
57
+ export { hasMarketplaceFile, readMarketplace, readMarketplaceFile } from "./marketplace/read-marketplace.js";
58
58
  export { readPluginPackage } from "./read-plugin-package.js";
59
59
  export type {
60
60
  IgnoredComponent,
@@ -25,6 +25,13 @@
25
25
  * `readPluginPackage`; a consumer that wants to install it hands the same
26
26
  * directory to the walker it already uses. Keeping the two reads apart is
27
27
  * what lets a catalogue of eighty entries be listed without eighty reads.
28
+ *
29
+ * `readMarketplaceFile` is the same read without the tree: what the file
30
+ * declares, for a client that holds the file alone and asks only "does this
31
+ * source offer a plugin called X" before it pays for the tree (the CLI's
32
+ * bare-name search across GitHub sources fetches one small file per source
33
+ * instead of a zipball each). Whether the tree holds an entry is still
34
+ * `readMarketplace`'s to say, on the tree, before anything is installed.
28
35
  */
29
36
 
30
37
  import { hasPluginManifest, isValidPluginName } from "../detect.js";
@@ -47,6 +54,24 @@ export function hasMarketplaceFile(paths: Iterable<string>): boolean {
47
54
  }
48
55
 
49
56
  export function readMarketplace(files: PluginFiles): MarketplaceReadOutcome {
57
+ return read(files, "tree");
58
+ }
59
+
60
+ /**
61
+ * The marketplace file as declared, the tree unverified: every entry with a
62
+ * readable source is offered, whether or not `files` holds its directory.
63
+ * For a client that has fetched the file alone; never for an install.
64
+ */
65
+ export function readMarketplaceFile(files: PluginFiles): MarketplaceReadOutcome {
66
+ return read(files, "file");
67
+ }
68
+
69
+ /**
70
+ * `tree`: entries whose directory the tree lacks, or holds without a plugin
71
+ * manifest, are dropped with their warning. `file`: entries are taken as the
72
+ * file declares them, and the tree is not consulted.
73
+ */
74
+ function read(files: PluginFiles, verify: "tree" | "file"): MarketplaceReadOutcome {
50
75
  const findings = new MarketplaceFindings();
51
76
  const index = new PluginFileIndex(files);
52
77
 
@@ -62,7 +87,7 @@ export function readMarketplace(files: PluginFiles): MarketplaceReadOutcome {
62
87
 
63
88
  const name = readName(object, path, findings);
64
89
  const raw = readEntries(object, dialect, path, findings);
65
- const entries = offeredEntries(raw, index, path, findings);
90
+ const entries = verify === "tree" ? offeredEntries(raw, index, path, findings) : declaredEntries(raw);
66
91
  const defaults = resolveDefaults(object, raw, entries, dialect, path, findings);
67
92
 
68
93
  if (findings.errors.length > 0 || name === undefined) return refused(findings);
@@ -349,6 +374,20 @@ function offeredEntries(
349
374
  return offered;
350
375
  }
351
376
 
377
+ /** Every entry with a readable source, as the file declares it; the tree is not asked. */
378
+ function declaredEntries(raw: readonly RawEntry[]): readonly MarketplaceEntry[] {
379
+ const declared: MarketplaceEntry[] = [];
380
+ for (const entry of raw) {
381
+ if (entry.dir === undefined) continue;
382
+ declared.push({
383
+ name: entry.name,
384
+ dir: entry.dir,
385
+ ...(entry.description !== undefined && { description: entry.description }),
386
+ });
387
+ }
388
+ return declared;
389
+ }
390
+
352
391
  /** The files under `dir` as plugin-relative paths, so `hasPluginManifest` reads them as it reads a plugin's own listing. */
353
392
  function childFilesOf(index: PluginFileIndex, dir: string): readonly string[] {
354
393
  const prefix = dir === "" ? "" : `${dir}/`;