@snap-rail/plugin-kit 0.2.0 → 0.2.1

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
  /**
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/pack.js CHANGED
@@ -2,6 +2,8 @@ import { CLIENT_EXTERNALS } from "./seeds.js";
2
2
  import { createRequire } from "node:module";
3
3
  import { readFile, readdir } from "node:fs/promises";
4
4
  import { join, relative } from "node:path";
5
+ import { createHash } from "node:crypto";
6
+ import { unzipSync } from "fflate";
5
7
  //#region lib/types/pack.js
6
8
  /**
7
9
  * Final-format assembly: turn a built plugin package into the file set of
@@ -154,5 +156,50 @@ async function releaseFiles(spec) {
154
156
  function zipFileName(packageName) {
155
157
  return `${packageName.replaceAll("/", "__")}.zip`;
156
158
  }
159
+ /**
160
+ * The one feed-entry emitter every producer shares: read a plugin zip's own
161
+ * bytes back (release manifest + signature envelope), derive the
162
+ * `index.json` entry from exactly what the zip carries, and digest the exact
163
+ * bytes the client will download — the feed can never advertise something a
164
+ * zip does not. The repo's pack/collect pipeline and the standalone
165
+ * `snap-rail-plugin feed` command all converge here.
166
+ *
167
+ * @param zipped - the exact zip bytes the feed will serve.
168
+ * @param file - the pure file name the entry advertises (no path).
169
+ * @param fallbackName - the entry's name when the manifest carries none.
170
+ * @param options.requireSignature - refuse unsigned zips (feed policy).
171
+ * @param options.repository - an optional source-repository URL.
172
+ * @returns the entry, unknown fields stripped by construction.
173
+ * @throws when the zip has no readable manifest, or no signature while
174
+ * `requireSignature` is set.
175
+ */
176
+ function catalogEntryFromZip(zipped, file, fallbackName, options = {}) {
177
+ const files = unzipSync(zipped);
178
+ const manifestFile = files["package.json"];
179
+ if (manifestFile === void 0) throw new Error(`catalog: ${file} 缺少 package.json`);
180
+ const manifest = JSON.parse(new TextDecoder().decode(manifestFile));
181
+ const signatureFile = files["META-INF/signature.json"];
182
+ if (signatureFile === void 0 && options.requireSignature === true) throw new Error(`catalog: ${file} 没有签名(META-INF/signature.json 缺失)`);
183
+ const signature = signatureFile === void 0 ? void 0 : JSON.parse(new TextDecoder().decode(signatureFile));
184
+ return {
185
+ name: manifest.name ?? fallbackName,
186
+ version: manifest.version ?? "0.0.0",
187
+ ...manifest.description !== void 0 && manifest.description !== "" ? { description: manifest.description } : {},
188
+ ...manifest.snapRail?.kind !== void 0 ? { kind: manifest.snapRail.kind } : {},
189
+ ...manifest.snapRail?.title !== void 0 ? { title: manifest.snapRail.title } : {},
190
+ ...manifest.snapRail?.category !== void 0 ? { category: manifest.snapRail.category } : {},
191
+ ...manifest.snapRail?.requires !== void 0 ? { requires: manifest.snapRail.requires } : {},
192
+ ...manifest.snapRail?.permissions !== void 0 ? { permissions: manifest.snapRail.permissions } : {},
193
+ ...manifest.snapRail?.engines !== void 0 ? { engines: manifest.snapRail.engines } : {},
194
+ file,
195
+ sha256: createHash("sha256").update(zipped).digest("hex"),
196
+ size: zipped.length,
197
+ ...signature === void 0 ? {} : { signature: {
198
+ algorithm: signature.algorithm,
199
+ keyId: signature.keyId
200
+ } },
201
+ ...options.repository === void 0 ? {} : { repository: options.repository }
202
+ };
203
+ }
157
204
  //#endregion
158
- export { releaseFiles, releaseManifest, zipFileName };
205
+ export { catalogEntryFromZip, releaseFiles, releaseManifest, zipFileName };
@@ -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
@@ -75,5 +75,51 @@ export declare function releaseManifest(source: SourceManifest, main: string, ex
75
75
  export declare function releaseFiles(spec: ReleaseSpec): Promise<Record<string, Uint8Array>>;
76
76
  /** The zip file name a package's release takes under dist-plugins/. */
77
77
  export declare function zipFileName(packageName: string): string;
78
+ /** One plugin entry the feed's `index.json` carries (feed facts only). */
79
+ export interface FeedEntry {
80
+ name: string;
81
+ version: string;
82
+ description?: string;
83
+ kind?: string;
84
+ title?: string;
85
+ category?: string;
86
+ requires?: string[];
87
+ permissions?: string[];
88
+ engines?: {
89
+ snapRail?: string;
90
+ hostProtocol?: string;
91
+ renderer?: string;
92
+ };
93
+ /** The pure file name the entry advertises (no path). */
94
+ file: string;
95
+ sha256: string;
96
+ size: number;
97
+ signature?: {
98
+ algorithm: 'Ed25519';
99
+ keyId: string;
100
+ };
101
+ repository?: string;
102
+ }
103
+ /**
104
+ * The one feed-entry emitter every producer shares: read a plugin zip's own
105
+ * bytes back (release manifest + signature envelope), derive the
106
+ * `index.json` entry from exactly what the zip carries, and digest the exact
107
+ * bytes the client will download — the feed can never advertise something a
108
+ * zip does not. The repo's pack/collect pipeline and the standalone
109
+ * `snap-rail-plugin feed` command all converge here.
110
+ *
111
+ * @param zipped - the exact zip bytes the feed will serve.
112
+ * @param file - the pure file name the entry advertises (no path).
113
+ * @param fallbackName - the entry's name when the manifest carries none.
114
+ * @param options.requireSignature - refuse unsigned zips (feed policy).
115
+ * @param options.repository - an optional source-repository URL.
116
+ * @returns the entry, unknown fields stripped by construction.
117
+ * @throws when the zip has no readable manifest, or no signature while
118
+ * `requireSignature` is set.
119
+ */
120
+ export declare function catalogEntryFromZip(zipped: Uint8Array, file: string, fallbackName: string, options?: {
121
+ requireSignature?: boolean;
122
+ repository?: string;
123
+ }): FeedEntry;
78
124
  export {};
79
125
  //# 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.1",
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,6 +56,7 @@
43
56
  ],
44
57
  "license": "Apache-2.0",
45
58
  "dependencies": {
59
+ "fflate": "^0.8.3",
46
60
  "zod": "^4.4.3",
47
61
  "@snap-rail/util": "^0.1.2"
48
62
  },