@snap-rail/plugin-kit 0.2.0 → 0.2.2

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/lib/build.js CHANGED
@@ -156,7 +156,8 @@ function hostBundle(entry) {
156
156
  platform: "node",
157
157
  target: "es2024",
158
158
  dts: false,
159
- clean: false
159
+ clean: false,
160
+ fixedExtension: false
160
161
  });
161
162
  }
162
163
  /**
@@ -172,7 +173,13 @@ function hostBundle(entry) {
172
173
  * subpath to its module namespace, and the shell seeds
173
174
  * `<package>/<subpath>` ids from that map after requiring the face.
174
175
  *
175
- * @param packageName - the plugin's npm name (the module id it registers as).
176
+ * A package that renders in more than one window calls this once per surface:
177
+ * the main surface keeps the package name as its module id and `client` as its
178
+ * file name, while an auxiliary surface passes `outName` and `moduleId` so its
179
+ * bundle lands beside the main one (`lib-client/ball.js`) and registers as
180
+ * `<package>/ball` — the id that surface's window requires.
181
+ *
182
+ * @param packageName - the plugin's npm name (asset URLs and the default module id).
176
183
  * @param entry - the renderer entry source file.
177
184
  * @param options - see {@link ClientBundleOptions}.
178
185
  */
@@ -190,7 +197,7 @@ function clientBundle(packageName, entry, options = {}) {
190
197
  }
191
198
  };
192
199
  return defineConfig({
193
- entry: { client: entry },
200
+ entry: { [options.outName ?? "client"]: entry },
194
201
  outDir: "lib-client",
195
202
  format: ["cjs"],
196
203
  platform: "browser",
@@ -207,7 +214,7 @@ function clientBundle(packageName, entry, options = {}) {
207
214
  seedImportGuard()
208
215
  ],
209
216
  outputOptions: {
210
- banner: `window.__ModuleLoader__.load({ id: ${JSON.stringify(packageName)}, factory: function (require, module, exports) {`,
217
+ banner: `window.__ModuleLoader__.load({ id: ${JSON.stringify(options.moduleId ?? packageName)}, factory: function (require, module, exports) {`,
211
218
  footer: "return module.exports && module.exports.__esModule === true && \"default\" in module.exports ? module.exports.default : module.exports; } });"
212
219
  }
213
220
  });
package/lib/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { CLIENT_EXTERNALS, CONTRIBUTED_SEED_MODULES, SEED_ABI_REVISION, SEED_MODULES, checkSeedAbi } from "./seeds.js";
2
2
  import { clientBundle, hostBundle, seedImportGuard } from "./build.js";
3
3
  import { PLUGIN_KINDS, clientFaceSchema, seedAbiSchema, snapRailManifestSchema } from "./manifest.js";
4
- import { releaseFiles, releaseManifest, zipFileName } from "./pack.js";
4
+ import { catalogEntryFromZip, releaseFiles, releaseManifest, zipFileName } from "./pack.js";
5
5
  import { packageNameOf, recipeDocumentSchema, recipePackageNames, recipeRowSchema } from "./recipe.js";
6
6
  import { RELEASE_METADATA_PATH, RELEASE_SIGNATURE_PATH, canonicalJson, releaseMetadata, sha256, signReleaseFiles, signReleaseMetadata, verifyReleaseFiles } from "./sign.js";
7
7
  //#region lib/types/slot-vocabulary.js
@@ -40,4 +40,4 @@ function defineSlotVocabulary(ids, options) {
40
40
  };
41
41
  }
42
42
  //#endregion
43
- export { CLIENT_EXTERNALS, CONTRIBUTED_SEED_MODULES, CUSTOM_SLOT_PATTERN, PLUGIN_KINDS, RELEASE_METADATA_PATH, RELEASE_SIGNATURE_PATH, SEED_ABI_REVISION, SEED_MODULES, canonicalJson, checkSeedAbi, clientBundle, clientFaceSchema, defineSlotVocabulary, hostBundle, packageNameOf, recipeDocumentSchema, recipePackageNames, recipeRowSchema, releaseFiles, releaseManifest, releaseMetadata, seedAbiSchema, seedImportGuard, sha256, signReleaseFiles, signReleaseMetadata, snapRailManifestSchema, verifyReleaseFiles, zipFileName };
43
+ export { CLIENT_EXTERNALS, CONTRIBUTED_SEED_MODULES, CUSTOM_SLOT_PATTERN, PLUGIN_KINDS, RELEASE_METADATA_PATH, RELEASE_SIGNATURE_PATH, SEED_ABI_REVISION, SEED_MODULES, canonicalJson, catalogEntryFromZip, checkSeedAbi, clientBundle, clientFaceSchema, defineSlotVocabulary, hostBundle, packageNameOf, recipeDocumentSchema, recipePackageNames, recipeRowSchema, releaseFiles, releaseManifest, releaseMetadata, seedAbiSchema, seedImportGuard, sha256, signReleaseFiles, signReleaseMetadata, snapRailManifestSchema, verifyReleaseFiles, zipFileName };
package/lib/manifest.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { z } from "zod";
2
+ import { AUX_SURFACE_IDS } from "@snap-rail/protocol";
2
3
  import { PLUGIN_LAYERS } from "@snap-rail/util/manifest";
3
4
  //#region lib/types/manifest.js
4
5
  /**
@@ -25,11 +26,29 @@ const seedAbiSchema = z.object({
25
26
  /** Base-package versions of the seeds the bundle requires, by seed id. */
26
27
  versions: z.record(z.string().min(1), z.string().min(1))
27
28
  }).strict();
29
+ /**
30
+ * The auxiliary-surface entry map: one client bundle per extra surface the
31
+ * package renders in. Keys are the auxiliary surface ids (`ball`) —
32
+ * `main` is deliberately absent, since the main window's bundle is
33
+ * `client.entry` and a package gets exactly one entry per window. Every
34
+ * declared path is a CJS factory bundle inside the package, packed and
35
+ * validated like the main entry; the surfaces a package does not declare
36
+ * simply have no face and show the kernel's plain fallback.
37
+ */
38
+ const clientSurfacesSchema = z.partialRecord(z.enum(AUX_SURFACE_IDS), z.string().min(1));
28
39
  /** The renderer face declaration: where the client bundle lives. */
29
40
  const clientFaceSchema = z.object({
30
- /** Path of the CJS factory bundle inside the package (from its root). */
41
+ /** Path of the CJS factory bundle inside the package (from its root) —
42
+ * the **main** surface's entry. */
31
43
  entry: z.string().min(1).default("lib/client.js"),
32
44
  /**
45
+ * Extra surfaces this package renders in: one client bundle per auxiliary
46
+ * window (`ball`). Each bundle is loaded into that surface's own
47
+ * window with the same seed table, and its module id is
48
+ * `<package>/<surface>` (the main entry keeps the plain package name).
49
+ */
50
+ surfaces: clientSurfacesSchema.optional(),
51
+ /**
33
52
  * Subpaths this client face registers as contributed seeds (e.g. framework
34
53
  * primitives like `./ui`): each becomes a `__ModuleLoader__` id other
35
54
  * plugins' client bundles may `require` — same instance, one execution.
@@ -119,4 +138,4 @@ const snapRailManifestSchema = z.object({
119
138
  }).strict().optional()
120
139
  });
121
140
  //#endregion
122
- export { PLUGIN_KINDS, PLUGIN_LAYERS, clientFaceSchema, seedAbiSchema, snapRailManifestSchema };
141
+ export { PLUGIN_KINDS, PLUGIN_LAYERS, clientFaceSchema, clientSurfacesSchema, seedAbiSchema, snapRailManifestSchema };
package/lib/pack.js CHANGED
@@ -1,7 +1,10 @@
1
1
  import { CLIENT_EXTERNALS } from "./seeds.js";
2
+ import { clientSurfacesSchema } from "./manifest.js";
2
3
  import { createRequire } from "node:module";
3
4
  import { readFile, readdir } from "node:fs/promises";
4
5
  import { join, relative } from "node:path";
6
+ import { createHash } from "node:crypto";
7
+ import { unzipSync } from "fflate";
5
8
  //#region lib/types/pack.js
6
9
  /**
7
10
  * Final-format assembly: turn a built plugin package into the file set of
@@ -62,22 +65,25 @@ function basePackageOf(seedId) {
62
65
  return seedId.startsWith("@") ? parts.slice(0, 2).join("/") : parts[0];
63
66
  }
64
67
  /**
65
- * Stamp the seed ABI a built client face was built against: the seeds its
66
- * bundle actually requires (a `require("…")` literal scan — externals are
67
- * the only bare requires the welded CJS output carries) plus each seed's
68
- * base-package version resolved from the package's own dependency tree.
69
- * Ids whose base package cannot be resolved here are omitted — the runtime
70
- * check compares only the intersection, so an omitted id is unchecked,
71
- * never failed. Returns `undefined` when the bundle requires no seeds or
72
- * none could be versioned (nothing to enforce).
68
+ * Stamp the seed ABI a set of built client faces were built against: the
69
+ * seeds their bundles actually require (a `require("…")` literal scan —
70
+ * externals are the only bare requires the welded CJS output carries) plus
71
+ * each seed's base-package version resolved from the package's own dependency
72
+ * tree. A multi-surface package stamps ONE declaration for all its entries
73
+ * (the union of their requires): every surface shares the shell's seed table,
74
+ * so a per-face stamp would only repeat the same verdict N times. Ids whose
75
+ * base package cannot be resolved here are omitted — the runtime check
76
+ * compares only the intersection, so an omitted id is unchecked, never
77
+ * failed. Returns `undefined` when the bundles require no seeds or none could
78
+ * be versioned (nothing to enforce).
73
79
  *
74
80
  * @param packageDir - the package being packed (version resolution root).
75
- * @param bundleCode - the built client bundle's source text.
81
+ * @param bundleCodes - the built client bundles' source texts, one per surface.
76
82
  */
77
- async function seedAbiStamp(packageDir, bundleCode) {
83
+ async function seedAbiStamp(packageDir, bundleCodes) {
78
84
  const seeds = new Set(CLIENT_EXTERNALS);
79
85
  const required = /* @__PURE__ */ new Set();
80
- for (const match of bundleCode.matchAll(/require\(\s*(['"])([^'"\n]+)\1\s*\)/g)) {
86
+ for (const bundleCode of bundleCodes) for (const match of bundleCode.matchAll(/require\(\s*(['"])([^'"\n]+)\1\s*\)/g)) {
81
87
  const id = match[2];
82
88
  if (id !== void 0 && seeds.has(id)) required.add(id);
83
89
  }
@@ -135,6 +141,12 @@ async function releaseFiles(spec) {
135
141
  if (spec.hostFace !== void 0 && spec.hostDir === void 0) throw new Error(`pack: ${spec.name} declares a host face without a hostDir`);
136
142
  if (spec.hostFace === void 0 && spec.clientFace === void 0) throw new Error(`pack: ${spec.name} ships neither a host face nor a client bundle`);
137
143
  const clientEntry = typeof snapRail?.client?.entry === "string" ? snapRail.client.entry : "lib/client.js";
144
+ let clientSurfaces = {};
145
+ if (snapRail?.client?.surfaces !== void 0) {
146
+ const parsed = clientSurfacesSchema.safeParse(snapRail.client.surfaces);
147
+ if (!parsed.success) throw new Error(`pack: ${spec.name} declares an invalid snapRail.client.surfaces (${parsed.error.issues.map((issue) => issue.message).join("; ")})`);
148
+ clientSurfaces = parsed.data;
149
+ }
138
150
  const main = spec.hostFace ?? clientEntry;
139
151
  const files = {};
140
152
  if (spec.hostDir !== void 0) {
@@ -144,7 +156,13 @@ async function releaseFiles(spec) {
144
156
  if (spec.clientFace !== void 0) Object.assign(files, await collectDir(join(spec.dir, spec.clientFace), spec.dir));
145
157
  if (spec.hostFace !== void 0 && files[spec.hostFace] === void 0) throw new Error(`pack: ${spec.name} is missing its host face ${spec.hostFace} under ${String(spec.hostDir)}`);
146
158
  if (declaredClient && files[clientEntry] === void 0) throw new Error(`pack: ${spec.name} declares client entry ${clientEntry} but the zip does not carry it`);
147
- const seedAbi = declaredClient && files[clientEntry] !== void 0 ? await seedAbiStamp(spec.dir, new TextDecoder().decode(files[clientEntry])) : void 0;
159
+ for (const [surface, entry] of Object.entries(clientSurfaces)) {
160
+ if (entry === void 0) continue;
161
+ if (files[entry] === void 0) throw new Error(`pack: ${spec.name} declares the ${surface} surface entry ${entry} but the zip does not carry it`);
162
+ if (entry === clientEntry) throw new Error(`pack: ${spec.name} points the ${surface} surface at the main client entry ${entry} — each surface needs its own bundle`);
163
+ }
164
+ const clientBundles = [clientEntry, ...Object.values(clientSurfaces)].filter((entry) => typeof entry === "string" && files[entry] !== void 0).map((entry) => new TextDecoder().decode(files[entry]));
165
+ const seedAbi = declaredClient && clientBundles.length > 0 ? await seedAbiStamp(spec.dir, clientBundles) : void 0;
148
166
  files["package.json"] = new TextEncoder().encode(releaseManifest(source, main, spec.exports, seedAbi));
149
167
  for (const [subpath, target] of Object.entries(spec.exports ?? {})) if (files[target] === void 0) throw new Error(`pack: ${spec.name} exports ${subpath} to ${target} but the zip does not carry it`);
150
168
  for (const path of Object.keys(files)) if (path.startsWith("src/")) throw new Error(`pack: ${spec.name} would ship a source file (${path})`);
@@ -154,5 +172,50 @@ async function releaseFiles(spec) {
154
172
  function zipFileName(packageName) {
155
173
  return `${packageName.replaceAll("/", "__")}.zip`;
156
174
  }
175
+ /**
176
+ * The one feed-entry emitter every producer shares: read a plugin zip's own
177
+ * bytes back (release manifest + signature envelope), derive the
178
+ * `index.json` entry from exactly what the zip carries, and digest the exact
179
+ * bytes the client will download — the feed can never advertise something a
180
+ * zip does not. The repo's pack/collect pipeline and the standalone
181
+ * `snap-rail-plugin feed` command all converge here.
182
+ *
183
+ * @param zipped - the exact zip bytes the feed will serve.
184
+ * @param file - the pure file name the entry advertises (no path).
185
+ * @param fallbackName - the entry's name when the manifest carries none.
186
+ * @param options.requireSignature - refuse unsigned zips (feed policy).
187
+ * @param options.repository - an optional source-repository URL.
188
+ * @returns the entry, unknown fields stripped by construction.
189
+ * @throws when the zip has no readable manifest, or no signature while
190
+ * `requireSignature` is set.
191
+ */
192
+ function catalogEntryFromZip(zipped, file, fallbackName, options = {}) {
193
+ const files = unzipSync(zipped);
194
+ const manifestFile = files["package.json"];
195
+ if (manifestFile === void 0) throw new Error(`catalog: ${file} 缺少 package.json`);
196
+ const manifest = JSON.parse(new TextDecoder().decode(manifestFile));
197
+ const signatureFile = files["META-INF/signature.json"];
198
+ if (signatureFile === void 0 && options.requireSignature === true) throw new Error(`catalog: ${file} 没有签名(META-INF/signature.json 缺失)`);
199
+ const signature = signatureFile === void 0 ? void 0 : JSON.parse(new TextDecoder().decode(signatureFile));
200
+ return {
201
+ name: manifest.name ?? fallbackName,
202
+ version: manifest.version ?? "0.0.0",
203
+ ...manifest.description !== void 0 && manifest.description !== "" ? { description: manifest.description } : {},
204
+ ...manifest.snapRail?.kind !== void 0 ? { kind: manifest.snapRail.kind } : {},
205
+ ...manifest.snapRail?.title !== void 0 ? { title: manifest.snapRail.title } : {},
206
+ ...manifest.snapRail?.category !== void 0 ? { category: manifest.snapRail.category } : {},
207
+ ...manifest.snapRail?.requires !== void 0 ? { requires: manifest.snapRail.requires } : {},
208
+ ...manifest.snapRail?.permissions !== void 0 ? { permissions: manifest.snapRail.permissions } : {},
209
+ ...manifest.snapRail?.engines !== void 0 ? { engines: manifest.snapRail.engines } : {},
210
+ file,
211
+ sha256: createHash("sha256").update(zipped).digest("hex"),
212
+ size: zipped.length,
213
+ ...signature === void 0 ? {} : { signature: {
214
+ algorithm: signature.algorithm,
215
+ keyId: signature.keyId
216
+ } },
217
+ ...options.repository === void 0 ? {} : { repository: options.repository }
218
+ };
219
+ }
157
220
  //#endregion
158
- export { releaseFiles, releaseManifest, zipFileName };
221
+ export { catalogEntryFromZip, releaseFiles, releaseManifest, zipFileName };
package/lib/seeds.js CHANGED
@@ -39,6 +39,7 @@ const SEED_MODULES = [
39
39
  "@snap-rail/client-modules",
40
40
  "@snap-rail/connection",
41
41
  "@snap-rail/protocol",
42
+ "@snap-rail/shell/contract",
42
43
  "@snap-rail/station-rpc/contract",
43
44
  "@snap-rail/app-boot/contract",
44
45
  "@snap-rail/equipment/contract",
@@ -50,6 +50,21 @@ export interface ClientBundleOptions {
50
50
  * by the entry, so the bundle carries its own styling.
51
51
  */
52
52
  css?: readonly string[] | undefined;
53
+ /**
54
+ * The emitted file's base name inside `lib-client` (default `client`, so
55
+ * the file is `lib-client/client.js`). Auxiliary surfaces build one bundle
56
+ * per window and name them after the surface (`ball`); the
57
+ * manifest's `client.surfaces` points at those files.
58
+ */
59
+ outName?: string | undefined;
60
+ /**
61
+ * The module id the bundle registers under (default: the package name).
62
+ * A package's **main** surface registers as the package itself, so
63
+ * `createClientRuntime` can require it by row name; an auxiliary surface
64
+ * registers as `<package>/<surface>` — one package, several windows, no
65
+ * two bundles fighting over one id.
66
+ */
67
+ moduleId?: string | undefined;
53
68
  }
54
69
  /**
55
70
  * The client face: a CJS browser bundle welded into the module-loader
@@ -64,7 +79,13 @@ export interface ClientBundleOptions {
64
79
  * subpath to its module namespace, and the shell seeds
65
80
  * `<package>/<subpath>` ids from that map after requiring the face.
66
81
  *
67
- * @param packageName - the plugin's npm name (the module id it registers as).
82
+ * A package that renders in more than one window calls this once per surface:
83
+ * the main surface keeps the package name as its module id and `client` as its
84
+ * file name, while an auxiliary surface passes `outName` and `moduleId` so its
85
+ * bundle lands beside the main one (`lib-client/ball.js`) and registers as
86
+ * `<package>/ball` — the id that surface's window requires.
87
+ *
88
+ * @param packageName - the plugin's npm name (asset URLs and the default module id).
68
89
  * @param entry - the renderer entry source file.
69
90
  * @param options - see {@link ClientBundleOptions}.
70
91
  */
@@ -12,7 +12,7 @@ export { SEED_MODULES } from './seeds.ts';
12
12
  export { CLIENT_EXTERNALS, CONTRIBUTED_SEED_MODULES, SEED_ABI_REVISION, checkSeedAbi, type SeedAbi, type SeedAbiVerdict, } from './seeds.ts';
13
13
  export { clientBundle, hostBundle, seedImportGuard } from './build.ts';
14
14
  export { CUSTOM_SLOT_PATTERN, defineSlotVocabulary, type SlotIdOf, type SlotVocabulary, } from './slot-vocabulary.ts';
15
- export { releaseFiles, releaseManifest, zipFileName, type ReleaseSpec } from './pack.ts';
15
+ export { catalogEntryFromZip, releaseFiles, releaseManifest, zipFileName, type FeedEntry, type ReleaseSpec } from './pack.ts';
16
16
  export { packageNameOf, recipeDocumentSchema, recipePackageNames, recipeRowSchema, type RecipeDocument, type RecipeRow, } from './recipe.ts';
17
17
  export { RELEASE_METADATA_PATH, RELEASE_SIGNATURE_PATH, canonicalJson, releaseMetadata, sha256, signReleaseFiles, signReleaseMetadata, verifyReleaseFiles, type ReleaseFileDigests, type ReleaseMetadata, type ReleaseSignature, type TrustedReleaseKey, } from './sign.ts';
18
18
  //# sourceMappingURL=index.d.ts.map
@@ -19,9 +19,24 @@ export declare const seedAbiSchema: z.ZodObject<{
19
19
  revision: z.ZodNumber;
20
20
  versions: z.ZodRecord<z.ZodString, z.ZodString>;
21
21
  }, z.core.$strict>;
22
+ /**
23
+ * The auxiliary-surface entry map: one client bundle per extra surface the
24
+ * package renders in. Keys are the auxiliary surface ids (`ball`) —
25
+ * `main` is deliberately absent, since the main window's bundle is
26
+ * `client.entry` and a package gets exactly one entry per window. Every
27
+ * declared path is a CJS factory bundle inside the package, packed and
28
+ * validated like the main entry; the surfaces a package does not declare
29
+ * simply have no face and show the kernel's plain fallback.
30
+ */
31
+ export declare const clientSurfacesSchema: z.ZodRecord<z.ZodEnum<{
32
+ ball: "ball";
33
+ }> & z.core.$partial, z.ZodString>;
22
34
  /** The renderer face declaration: where the client bundle lives. */
23
35
  export declare const clientFaceSchema: z.ZodObject<{
24
36
  entry: z.ZodDefault<z.ZodString>;
37
+ surfaces: z.ZodOptional<z.ZodRecord<z.ZodEnum<{
38
+ ball: "ball";
39
+ }> & z.core.$partial, z.ZodString>>;
25
40
  seeds: z.ZodOptional<z.ZodArray<z.ZodString>>;
26
41
  externalSeeds: z.ZodOptional<z.ZodArray<z.ZodString>>;
27
42
  seedAbi: z.ZodOptional<z.ZodObject<{
@@ -52,6 +67,9 @@ export declare const snapRailManifestSchema: z.ZodObject<{
52
67
  clientOnly: z.ZodOptional<z.ZodBoolean>;
53
68
  client: z.ZodOptional<z.ZodObject<{
54
69
  entry: z.ZodDefault<z.ZodString>;
70
+ surfaces: z.ZodOptional<z.ZodRecord<z.ZodEnum<{
71
+ ball: "ball";
72
+ }> & z.core.$partial, z.ZodString>>;
55
73
  seeds: z.ZodOptional<z.ZodArray<z.ZodString>>;
56
74
  externalSeeds: z.ZodOptional<z.ZodArray<z.ZodString>>;
57
75
  seedAbi: z.ZodOptional<z.ZodObject<{
@@ -20,6 +20,7 @@ interface SourceManifest {
20
20
  clientOnly?: unknown;
21
21
  client?: {
22
22
  entry?: unknown;
23
+ surfaces?: unknown;
23
24
  } | undefined;
24
25
  } & Record<string, unknown>;
25
26
  }
@@ -75,5 +76,51 @@ export declare function releaseManifest(source: SourceManifest, main: string, ex
75
76
  export declare function releaseFiles(spec: ReleaseSpec): Promise<Record<string, Uint8Array>>;
76
77
  /** The zip file name a package's release takes under dist-plugins/. */
77
78
  export declare function zipFileName(packageName: string): string;
79
+ /** One plugin entry the feed's `index.json` carries (feed facts only). */
80
+ export interface FeedEntry {
81
+ name: string;
82
+ version: string;
83
+ description?: string;
84
+ kind?: string;
85
+ title?: string;
86
+ category?: string;
87
+ requires?: string[];
88
+ permissions?: string[];
89
+ engines?: {
90
+ snapRail?: string;
91
+ hostProtocol?: string;
92
+ renderer?: string;
93
+ };
94
+ /** The pure file name the entry advertises (no path). */
95
+ file: string;
96
+ sha256: string;
97
+ size: number;
98
+ signature?: {
99
+ algorithm: 'Ed25519';
100
+ keyId: string;
101
+ };
102
+ repository?: string;
103
+ }
104
+ /**
105
+ * The one feed-entry emitter every producer shares: read a plugin zip's own
106
+ * bytes back (release manifest + signature envelope), derive the
107
+ * `index.json` entry from exactly what the zip carries, and digest the exact
108
+ * bytes the client will download — the feed can never advertise something a
109
+ * zip does not. The repo's pack/collect pipeline and the standalone
110
+ * `snap-rail-plugin feed` command all converge here.
111
+ *
112
+ * @param zipped - the exact zip bytes the feed will serve.
113
+ * @param file - the pure file name the entry advertises (no path).
114
+ * @param fallbackName - the entry's name when the manifest carries none.
115
+ * @param options.requireSignature - refuse unsigned zips (feed policy).
116
+ * @param options.repository - an optional source-repository URL.
117
+ * @returns the entry, unknown fields stripped by construction.
118
+ * @throws when the zip has no readable manifest, or no signature while
119
+ * `requireSignature` is set.
120
+ */
121
+ export declare function catalogEntryFromZip(zipped: Uint8Array, file: string, fallbackName: string, options?: {
122
+ requireSignature?: boolean;
123
+ repository?: string;
124
+ }): FeedEntry;
78
125
  export {};
79
126
  //# sourceMappingURL=pack.d.ts.map
package/package.json CHANGED
@@ -1,10 +1,23 @@
1
1
  {
2
2
  "name": "@snap-rail/plugin-kit",
3
- "description": "The plugin author's kit: snapRail manifest vocabulary, the renderer seed whitelist, and tsdown presets for installable host + client faces",
4
- "version": "0.2.0",
3
+ "description": "The plugin author's kit: snapRail manifest vocabulary, the renderer seed whitelist, tsdown presets for installable host + client faces, release signing, and the final-format packer",
4
+ "version": "0.2.2",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",
7
7
  "types": "lib/types/index.d.ts",
8
+ "homepage": "https://www.snap-rail.top/dev.html",
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "git+https://github.com/yansijian/snap-rail.git",
12
+ "directory": "packages/base/plugin-kit"
13
+ },
14
+ "keywords": [
15
+ "snap-rail",
16
+ "plugin",
17
+ "cordis",
18
+ "industrial",
19
+ "electron"
20
+ ],
8
21
  "exports": {
9
22
  ".": {
10
23
  "types": "./lib/types/index.d.ts",
@@ -43,7 +56,9 @@
43
56
  ],
44
57
  "license": "Apache-2.0",
45
58
  "dependencies": {
59
+ "fflate": "^0.8.3",
46
60
  "zod": "^4.4.3",
61
+ "@snap-rail/protocol": "^0.1.3",
47
62
  "@snap-rail/util": "^0.1.2"
48
63
  },
49
64
  "peerDependencies": {