@opentray/vite-plugin 0.16.0 → 0.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/README.md CHANGED
@@ -21,3 +21,59 @@ export default {
21
21
  The adapter stages artifacts during Vite build output and writes the same
22
22
  manifest shape as `@opentray/packaging`. It does not own tray lifecycle,
23
23
  sessions, backend selection, or extension dispatch.
24
+
25
+ ## Application Icon
26
+
27
+ Use `openTrayAppIconPlugin` in a consumer's Vite config to generate one strict
28
+ cross-platform `AppIcon` asset set from the consumer's brand source. The plugin
29
+ runs in both `vite dev` and `vite build`; generated files are written under the
30
+ Vite root's `static/icons` directory so the same paths are available to the dev
31
+ daemon and the packaged build.
32
+
33
+ ```ts
34
+ import { fileURLToPath } from "node:url";
35
+ import { openTrayAppIconPlugin } from "@opentray/vite-plugin";
36
+
37
+ export default {
38
+ plugins: [
39
+ openTrayAppIconPlugin({
40
+ sourcePath: fileURLToPath(
41
+ new URL("../resources/color-symbol.png", import.meta.url)
42
+ ),
43
+ }),
44
+ ],
45
+ };
46
+ ```
47
+
48
+ The cache identity includes the source image, the plugin implementation, the
49
+ rendering recipe, and the `sharp`, `@shockpkg/icon-encoder`, and
50
+ `figma-squircle` versions. ICNS output uses explicit macOS @1x/@2x tags rather
51
+ than copying one PNG into incompatible representation slots. In a linked
52
+ checkout the cache also hashes `packages/vite-plugin/src/app-icon.ts`, so editing
53
+ the generator source invalidates the cache even when the bundle hash is
54
+ unchanged. A linked consumer should rebuild this package before starting Vite.
55
+
56
+ The output contains:
57
+
58
+ ```text
59
+ static/icons/
60
+ |- app-icon.icns Darwin application asset
61
+ |- app-icon.ico Windows application asset
62
+ |- app-icon.json portable AppIcon manifest
63
+ |- app-icon.png 1024px rendered preview
64
+ `- linux/<size>x<size>/app-icon.png
65
+ ```
66
+
67
+ `generateOpenTrayAppIcon()` returns an `appIcon` array whose file paths are
68
+ absolute and can be passed directly to `createTray(..., { appIcon })`. Paths in
69
+ `app-icon.json` are relative to the manifest so packaged outputs remain
70
+ relocatable. The application contract accepts only `darwin/icns`,
71
+ `windows/ico`, and `linux/png|svg` assets; it does not accept tray templates,
72
+ raw RGBA, text, or page favicons.
73
+
74
+ ## Darwin App Bundle
75
+
76
+ Use `openTrayAppBundlePlugin()` to prebuild the same stable bundle consumed by
77
+ runtime `appBundle.reinitialize: false`. The plugin delegates all file layout,
78
+ hashes, and manifest rules to `@opentray/packaging` and defaults to
79
+ `<vite outDir>/<appName>.app`.
package/dist/index.d.mts CHANGED
@@ -1,5 +1,61 @@
1
- import { OpenTrayArtifactInput, OpenTrayPackageManifest, OpenTrayPackageResult, OpenTrayPackagingApp } from "@opentray/packaging";
1
+ import { DarwinAppBundleOptions, OpenTrayArtifactInput, OpenTrayDarwinAppBundleResult, OpenTrayPackageManifest, OpenTrayPackageResult, OpenTrayPackagingApp } from "@opentray/packaging";
2
+ import { Plugin } from "vite";
3
+ import { AppIcon } from "@opentray/spec";
2
4
 
5
+ //#region src/app-icon.d.ts
6
+ interface OpenTrayAppIconOptions {
7
+ readonly sourcePath: string;
8
+ readonly outputPath?: string;
9
+ readonly icnsOutputPath?: string;
10
+ readonly icoOutputPath?: string;
11
+ readonly linuxOutputDirectory?: string;
12
+ readonly manifestOutputPath?: string;
13
+ readonly cachePath?: string;
14
+ /** Advanced: override the module whose bytes identify the generator implementation. */
15
+ readonly implementationPath?: string;
16
+ /** Advanced: override the source file whose bytes identify the generator implementation. */
17
+ readonly implementationSourcePath?: string;
18
+ }
19
+ interface OpenTrayAppIconCacheMetadata {
20
+ readonly schemaVersion: number;
21
+ readonly sourceSha256: string;
22
+ readonly sourceImplementationSha256: string | null;
23
+ readonly implementationSha256: string;
24
+ readonly recipeVersion: string;
25
+ readonly sharpVersion: string;
26
+ readonly iconEncoderVersion: string;
27
+ readonly figmaSquircleVersion: string;
28
+ readonly outputPath: string;
29
+ readonly icnsOutputPath: string;
30
+ readonly icoOutputPath: string;
31
+ readonly linuxPngOutputPaths: readonly {
32
+ readonly size: number;
33
+ readonly path: string;
34
+ }[];
35
+ readonly manifestOutputPath: string;
36
+ /** Absolute file sources ready to pass to OpenTray at runtime. */
37
+ readonly appIcon: AppIcon;
38
+ }
39
+ interface OpenTrayAppIconManifest {
40
+ readonly schemaVersion: 1;
41
+ /** File paths are relative to the manifest file. */
42
+ readonly appIcon: AppIcon;
43
+ }
44
+ interface OpenTrayAppIconPluginOptions {
45
+ /** Brand source image. This is intentionally explicit so the plugin is app-agnostic. */
46
+ readonly sourcePath: string;
47
+ readonly outputPath?: string;
48
+ readonly icnsOutputPath?: string;
49
+ readonly icoOutputPath?: string;
50
+ readonly linuxOutputDirectory?: string;
51
+ readonly manifestOutputPath?: string;
52
+ readonly cachePath?: string;
53
+ }
54
+ /** Generate one strict cross-platform AppIcon asset set. */
55
+ declare function generateOpenTrayAppIcon(options: OpenTrayAppIconOptions): Promise<OpenTrayAppIconCacheMetadata>;
56
+ /** Create the Vite plugin used by both serve and build modes. */
57
+ declare function openTrayAppIconPlugin(options: OpenTrayAppIconPluginOptions): Plugin;
58
+ //#endregion
3
59
  //#region src/index.d.ts
4
60
  interface OpenTrayVitePluginOptions {
5
61
  readonly app: OpenTrayPackagingApp;
@@ -31,8 +87,21 @@ interface OpenTrayVitePlugin {
31
87
  writeBundle(options: unknown, bundle: ViteBundleLike): Promise<void>;
32
88
  readonly getLastResult: () => OpenTrayPackageResult | undefined;
33
89
  }
90
+ interface OpenTrayViteAppBundlePluginOptions extends Omit<DarwinAppBundleOptions, "bundlePath" | "reinitialize"> {
91
+ /** Optional output path. Defaults to `<vite outDir>/<appName>.app`. */
92
+ readonly bundlePath?: string;
93
+ }
94
+ interface OpenTrayViteAppBundlePlugin {
95
+ readonly name: "opentray-app-bundle";
96
+ readonly apply: "build";
97
+ configResolved(config: ViteResolvedConfigLike): void;
98
+ writeBundle(): Promise<void>;
99
+ readonly getLastResult: () => OpenTrayDarwinAppBundleResult | undefined;
100
+ }
101
+ /** Vite lifecycle adapter for the shared Darwin app bundle contract. */
102
+ declare const openTrayAppBundlePlugin: (options: OpenTrayViteAppBundlePluginOptions) => OpenTrayViteAppBundlePlugin;
34
103
  declare const openTrayVitePlugin: (options: OpenTrayVitePluginOptions) => OpenTrayVitePlugin;
35
104
  declare const resolveViteEntry: (bundle: ViteBundleLike) => string;
36
105
  //#endregion
37
- export { type OpenTrayPackageManifest, type OpenTrayPackageResult, OpenTrayVitePlugin, OpenTrayVitePluginOptions, ViteBundleLike, ViteOutputChunkLike, ViteResolvedConfigLike, openTrayVitePlugin, resolveViteEntry };
106
+ export { type OpenTrayAppIconCacheMetadata, type OpenTrayAppIconManifest, type OpenTrayAppIconOptions, type OpenTrayAppIconPluginOptions, type OpenTrayPackageManifest, type OpenTrayPackageResult, OpenTrayViteAppBundlePlugin, OpenTrayViteAppBundlePluginOptions, OpenTrayVitePlugin, OpenTrayVitePluginOptions, ViteBundleLike, ViteOutputChunkLike, ViteResolvedConfigLike, generateOpenTrayAppIcon, openTrayAppBundlePlugin, openTrayAppIconPlugin, openTrayVitePlugin, resolveViteEntry };
38
107
  //# sourceMappingURL=index.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../src/index.ts"],"mappings":";;;UAUiB,yBAAA;EAAA,SACN,GAAA,EAAK,oBAAA;EAAA,SACL,WAAA,EAAa,qBAAA;EAAA,SACb,eAAA,GAAkB,QAAA,CAAS,MAAA,SAAe,qBAAA;EAAA,SAC1C,eAAA,GAAkB,QAAA,CAAS,MAAA,SAAe,qBAAA;EAAA,SAC1C,KAAA;EAAA,SACA,YAAA;AAAA;AAAA,UAGM,sBAAA;EAAA,SACN,IAAA;EAAA,SACA,IAAA;EAAA,SACA,KAAA;IAAA,SACE,MAAA;EAAA;AAAA;AAAA,UAII,mBAAA;EAAA,SACN,IAAA;EAAA,SACA,OAAA;EAAA,SACA,QAAA;EAAA,SACA,cAAA;EAAA,SACA,IAAA;AAAA;AAAA,KAGC,cAAA,GAAiB,QAAQ,CAAC,MAAA;AAAA,UAErB,kBAAA;EAAA,SACN,IAAA;EAAA,SACA,KAAA;EACT,cAAA,CAAe,MAAA,EAAQ,sBAAA;EACvB,WAAA,CAAY,OAAA,WAAkB,MAAA,EAAQ,cAAA,GAAiB,OAAA;EAAA,SAC9C,aAAA,QAAqB,qBAAA;AAAA;AAAA,cAGnB,kBAAA,GACX,OAAA,EAAS,yBAAA,KACR,kBAiCF;AAAA,cAEY,gBAAA,GAAoB,MAAsB,EAAd,cAAc"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/app-icon.ts","../src/index.ts"],"mappings":";;;;;UAmDiB,sBAAA;EAAA,SACN,UAAA;EAAA,SACA,UAAA;EAAA,SACA,cAAA;EAAA,SACA,aAAA;EAAA,SACA,oBAAA;EAAA,SACA,kBAAA;EAAA,SACA,SAAA;EALA;EAAA,SAOA,kBAAA;EALA;EAAA,SAOA,wBAAA;AAAA;AAAA,UAGM,4BAAA;EAAA,SACN,aAAA;EAAA,SACA,YAAA;EAAA,SACA,0BAAA;EAAA,SACA,oBAAA;EAAA,SACA,aAAA;EAAA,SACA,YAAA;EAAA,SACA,kBAAA;EAAA,SACA,oBAAA;EAAA,SACA,UAAA;EAAA,SACA,cAAA;EAAA,SACA,aAAA;EAAA,SACA,mBAAA;IAAA,SACE,IAAA;IAAA,SACA,IAAA;EAAA;EAAA,SAEF,kBAAA;EAPA;EAAA,SASA,OAAA,EAAS,OAAO;AAAA;AAAA,UAGV,uBAAA;EAAA,SACN,aAAA;EARE;EAAA,SAUF,OAAA,EAAS,OAAO;AAAA;AAAA,UAGV,4BAAA;EATU;EAAA,SAWhB,UAAA;EAAA,SACA,UAAA;EAAA,SACA,cAAA;EAAA,SACA,aAAA;EAAA,SACA,oBAAA;EAAA,SACA,kBAAA;EAAA,SACA,SAAA;AAAA;;iBAIW,uBAAA,CACpB,OAAA,EAAS,sBAAA,GACR,OAAA,CAAQ,4BAAA;AAdX;AAAA,iBAoEgB,qBAAA,CACd,OAAA,EAAS,4BAAA,GACR,MAAM;;;UC9IQ,yBAAA;EAAA,SACN,GAAA,EAAK,oBAAA;EAAA,SACL,WAAA,EAAa,qBAAA;EAAA,SACb,eAAA,GAAkB,QAAA,CAAS,MAAA,SAAe,qBAAA;EAAA,SAC1C,eAAA,GAAkB,QAAA,CAAS,MAAA,SAAe,qBAAA;EAAA,SAC1C,KAAA;EAAA,SACA,YAAA;AAAA;AAAA,UAGM,sBAAA;EAAA,SACN,IAAA;EAAA,SACA,IAAA;EAAA,SACA,KAAA;IAAA,SACE,MAAA;EAAA;AAAA;AAAA,UAII,mBAAA;EAAA,SACN,IAAA;EAAA,SACA,OAAA;EAAA,SACA,QAAA;EAAA,SACA,cAAA;EAAA,SACA,IAAA;AAAA;AAAA,KAGC,cAAA,GAAiB,QAAQ,CAAC,MAAA;AAAA,UAErB,kBAAA;EAAA,SACN,IAAA;EAAA,SACA,KAAA;EACT,cAAA,CAAe,MAAA,EAAQ,sBAAA;EACvB,WAAA,CAAY,OAAA,WAAkB,MAAA,EAAQ,cAAA,GAAiB,OAAA;EAAA,SAC9C,aAAA,QAAqB,qBAAA;AAAA;AAAA,UAGf,kCAAA,SACP,IAAI,CAAC,sBAAA;EDkBJ;EAAA,SChBA,UAAA;AAAA;AAAA,UAGM,2BAAA;EAAA,SACN,IAAA;EAAA,SACA,KAAA;EACT,cAAA,CAAe,MAAA,EAAQ,sBAAA;EACvB,WAAA,IAAe,OAAA;EAAA,SACN,aAAA,QAAqB,6BAAA;AAAA;ADiBL;AAAA,cCbd,uBAAA,GACX,OAAA,EAAS,kCAAA,KACR,2BAyBF;AAAA,cAEY,kBAAA,GAAsB,OAAA,EAAS,yBAAA,KAA4B,kBAiCvE;AAAA,cAEY,gBAAA,GAAoB,MAAsB,EAAd,cAAc"}
package/dist/index.mjs CHANGED
@@ -1,6 +1,363 @@
1
- import { resolve } from "node:path";
2
- import { stageOpenTrayPackage } from "@opentray/packaging";
1
+ import { createRequire } from "node:module";
2
+ import path, { resolve } from "node:path";
3
+ import { buildDarwinAppBundle, stageOpenTrayPackage } from "@opentray/packaging";
4
+ import crypto from "node:crypto";
5
+ import fs from "node:fs/promises";
6
+ import { fileURLToPath } from "node:url";
7
+ import { getSvgPath } from "figma-squircle";
8
+ import sharp from "sharp";
9
+ import { IconIcns, IconIco } from "@shockpkg/icon-encoder";
10
+ //#region src/app-icon.ts
11
+ const ICON_SIZE = 1024;
12
+ const TILE_INSET = 64;
13
+ const TILE_SIZE = ICON_SIZE - TILE_INSET * 2;
14
+ const TILE_RADIUS = 196;
15
+ const TILE_SMOOTHING = 1;
16
+ const SYMBOL_SIZE = 704;
17
+ const APP_ICON_DENSITY = 72;
18
+ const CACHE_SCHEMA_VERSION = 6;
19
+ const RECIPE_VERSION = `squircle-v3:${ICON_SIZE}:${TILE_INSET}:${TILE_RADIUS}:${TILE_SMOOTHING}:${SYMBOL_SIZE}:${APP_ICON_DENSITY}dpi:icns-tagged`;
20
+ const ICO_SIZES = [
21
+ 16,
22
+ 24,
23
+ 32,
24
+ 48,
25
+ 64,
26
+ 128,
27
+ 256
28
+ ];
29
+ const LINUX_SIZES = [
30
+ 16,
31
+ 32,
32
+ 48,
33
+ 64,
34
+ 128,
35
+ 256,
36
+ 512
37
+ ];
38
+ const ICNS_REPRESENTATIONS = [
39
+ {
40
+ tag: "ic12",
41
+ size: 64
42
+ },
43
+ {
44
+ tag: "ic07",
45
+ size: 128
46
+ },
47
+ {
48
+ tag: "ic13",
49
+ size: 256
50
+ },
51
+ {
52
+ tag: "ic08",
53
+ size: 256
54
+ },
55
+ {
56
+ tag: "ic04",
57
+ size: 16
58
+ },
59
+ {
60
+ tag: "ic14",
61
+ size: 512
62
+ },
63
+ {
64
+ tag: "ic09",
65
+ size: 512
66
+ },
67
+ {
68
+ tag: "ic05",
69
+ size: 32
70
+ },
71
+ {
72
+ tag: "ic10",
73
+ size: 1024
74
+ },
75
+ {
76
+ tag: "ic11",
77
+ size: 32
78
+ }
79
+ ];
80
+ const require = createRequire(import.meta.url);
81
+ /** Generate one strict cross-platform AppIcon asset set. */
82
+ async function generateOpenTrayAppIcon(options) {
83
+ const outputPath = options.outputPath ?? path.join(path.dirname(options.sourcePath), "app-icon.png");
84
+ const icnsOutputPath = options.icnsOutputPath ?? path.join(path.dirname(outputPath), "app-icon.icns");
85
+ const icoOutputPath = options.icoOutputPath ?? path.join(path.dirname(outputPath), "app-icon.ico");
86
+ const linuxOutputDirectory = options.linuxOutputDirectory ?? path.join(path.dirname(outputPath), "linux");
87
+ const manifestOutputPath = options.manifestOutputPath ?? path.join(path.dirname(outputPath), "app-icon.json");
88
+ const cachePath = options.cachePath ?? path.join(path.dirname(outputPath), "../../.cache/app-icon.json");
89
+ const implementationPath = options.implementationPath ?? fileURLToPath(import.meta.url);
90
+ const metadata = await createCacheMetadata({
91
+ sourcePath: options.sourcePath,
92
+ implementationPath,
93
+ outputPath,
94
+ icnsOutputPath,
95
+ icoOutputPath,
96
+ linuxOutputDirectory,
97
+ manifestOutputPath,
98
+ ...options.implementationSourcePath === void 0 ? {} : { implementationSourcePath: options.implementationSourcePath }
99
+ });
100
+ if (await cacheMatches(cachePath, metadata)) return metadata;
101
+ const rendered = await renderAppIcon(options.sourcePath);
102
+ await fs.mkdir(path.dirname(outputPath), { recursive: true });
103
+ await fs.mkdir(path.dirname(icnsOutputPath), { recursive: true });
104
+ await fs.mkdir(path.dirname(icoOutputPath), { recursive: true });
105
+ await fs.mkdir(path.dirname(cachePath), { recursive: true });
106
+ await fs.writeFile(outputPath, rendered);
107
+ await encodeNativeIcons(rendered, icnsOutputPath, icoOutputPath);
108
+ await writeLinuxIcons(rendered, metadata.linuxPngOutputPaths);
109
+ await writeManifest(metadata);
110
+ await fs.writeFile(cachePath, `${JSON.stringify(metadata, null, 2)}\n`, "utf8");
111
+ return metadata;
112
+ }
113
+ /** Create the Vite plugin used by both serve and build modes. */
114
+ function openTrayAppIconPlugin(options) {
115
+ let generation;
116
+ return {
117
+ name: "opentray/app-icon",
118
+ enforce: "pre",
119
+ async configResolved(config) {
120
+ const outputPath = options.outputPath ?? path.resolve(config.root, "static/icons/app-icon.png");
121
+ const icnsOutputPath = options.icnsOutputPath ?? path.resolve(config.root, "static/icons/app-icon.icns");
122
+ const icoOutputPath = options.icoOutputPath ?? path.resolve(config.root, "static/icons/app-icon.ico");
123
+ const linuxOutputDirectory = options.linuxOutputDirectory ?? path.resolve(config.root, "static/icons/linux");
124
+ const manifestOutputPath = options.manifestOutputPath ?? path.resolve(config.root, "static/icons/app-icon.json");
125
+ const cachePath = options.cachePath ?? path.resolve(config.root, ".cache/app-icon.json");
126
+ generation ??= generateOpenTrayAppIcon({
127
+ sourcePath: path.resolve(options.sourcePath),
128
+ outputPath,
129
+ icnsOutputPath,
130
+ icoOutputPath,
131
+ linuxOutputDirectory,
132
+ manifestOutputPath,
133
+ cachePath
134
+ });
135
+ await generation;
136
+ }
137
+ };
138
+ }
139
+ async function createCacheMetadata(options) {
140
+ const sourceImplementationPath = options.implementationSourcePath ?? await resolveSourceImplementationPath(options.implementationPath);
141
+ const linuxPngOutputPaths = LINUX_SIZES.map((size) => ({
142
+ size,
143
+ path: path.resolve(options.linuxOutputDirectory, `${size}x${size}`, "app-icon.png")
144
+ }));
145
+ const icnsOutputPath = path.resolve(options.icnsOutputPath);
146
+ const icoOutputPath = path.resolve(options.icoOutputPath);
147
+ const appIcon = [
148
+ {
149
+ platform: "darwin",
150
+ format: "icns",
151
+ source: {
152
+ type: "file",
153
+ path: icnsOutputPath
154
+ }
155
+ },
156
+ {
157
+ platform: "windows",
158
+ format: "ico",
159
+ source: {
160
+ type: "file",
161
+ path: icoOutputPath
162
+ }
163
+ },
164
+ ...linuxPngOutputPaths.map(({ size, path: pngPath }) => ({
165
+ platform: "linux",
166
+ format: "png",
167
+ size,
168
+ source: {
169
+ type: "file",
170
+ path: pngPath
171
+ }
172
+ }))
173
+ ];
174
+ return {
175
+ schemaVersion: CACHE_SCHEMA_VERSION,
176
+ sourceSha256: await sha256(options.sourcePath),
177
+ sourceImplementationSha256: sourceImplementationPath === null ? null : await sha256(sourceImplementationPath),
178
+ implementationSha256: await sha256(options.implementationPath),
179
+ recipeVersion: RECIPE_VERSION,
180
+ sharpVersion: await packageVersion("sharp"),
181
+ iconEncoderVersion: await packageVersion("@shockpkg/icon-encoder"),
182
+ figmaSquircleVersion: await packageVersion("figma-squircle"),
183
+ outputPath: path.resolve(options.outputPath),
184
+ icnsOutputPath,
185
+ icoOutputPath,
186
+ linuxPngOutputPaths,
187
+ manifestOutputPath: path.resolve(options.manifestOutputPath),
188
+ appIcon
189
+ };
190
+ }
191
+ async function renderAppIcon(sourcePath) {
192
+ const symbol = await sharp(sourcePath).trim({ threshold: 0 }).resize(SYMBOL_SIZE, SYMBOL_SIZE, {
193
+ fit: "inside",
194
+ kernel: sharp.kernel.lanczos3
195
+ }).png().toBuffer({ resolveWithObject: true });
196
+ const symbolLeft = Math.round((ICON_SIZE - symbol.info.width) / 2);
197
+ const symbolTop = Math.round((ICON_SIZE - symbol.info.height) / 2);
198
+ const squirclePath = getSvgPath({
199
+ width: TILE_SIZE,
200
+ height: TILE_SIZE,
201
+ cornerRadius: TILE_RADIUS,
202
+ cornerSmoothing: TILE_SMOOTHING,
203
+ preserveSmoothing: true
204
+ });
205
+ const whiteTile = Buffer.from(`<svg xmlns="http://www.w3.org/2000/svg" width="${TILE_SIZE}" height="${TILE_SIZE}"><path d="${squirclePath}" fill="#fff"/></svg>`);
206
+ return sharp({ create: {
207
+ width: ICON_SIZE,
208
+ height: ICON_SIZE,
209
+ channels: 4,
210
+ background: {
211
+ r: 0,
212
+ g: 0,
213
+ b: 0,
214
+ alpha: 0
215
+ }
216
+ } }).composite([{
217
+ input: whiteTile,
218
+ top: TILE_INSET,
219
+ left: TILE_INSET
220
+ }, {
221
+ input: symbol.data,
222
+ top: symbolTop,
223
+ left: symbolLeft
224
+ }]).withMetadata({ density: APP_ICON_DENSITY }).png({ compressionLevel: 9 }).toBuffer();
225
+ }
226
+ async function encodeNativeIcons(rendered, icnsOutputPath, icoOutputPath) {
227
+ const pngBySize = /* @__PURE__ */ new Map();
228
+ const pngAt = async (size) => {
229
+ const cached = pngBySize.get(size);
230
+ if (cached !== void 0) return cached;
231
+ const png = await sharp(rendered).resize(size, size, { fit: "contain" }).withMetadata({ density: APP_ICON_DENSITY }).png({ compressionLevel: 9 }).toBuffer();
232
+ pngBySize.set(size, png);
233
+ return png;
234
+ };
235
+ const icns = new IconIcns();
236
+ icns.toc = true;
237
+ for (const { tag, size } of ICNS_REPRESENTATIONS) await icns.addFromPng(await pngAt(size), [tag], false);
238
+ await fs.writeFile(icnsOutputPath, icns.encode());
239
+ const ico = new IconIco();
240
+ for (const size of ICO_SIZES) await ico.addFromPng(await pngAt(size), null, false);
241
+ await fs.writeFile(icoOutputPath, ico.encode());
242
+ }
243
+ async function writeLinuxIcons(rendered, outputs) {
244
+ await Promise.all(outputs.map(async ({ size, path: outputPath }) => {
245
+ await fs.mkdir(path.dirname(outputPath), { recursive: true });
246
+ await sharp(rendered).resize(size, size, { fit: "contain" }).withMetadata({ density: APP_ICON_DENSITY }).png({ compressionLevel: 9 }).toFile(outputPath);
247
+ }));
248
+ }
249
+ async function writeManifest(metadata) {
250
+ const manifestDirectory = path.dirname(metadata.manifestOutputPath);
251
+ const relativeSource = (sourcePath) => ({
252
+ type: "file",
253
+ path: path.relative(manifestDirectory, sourcePath).split(path.sep).join("/")
254
+ });
255
+ const manifest = {
256
+ schemaVersion: 1,
257
+ appIcon: [
258
+ {
259
+ platform: "darwin",
260
+ format: "icns",
261
+ source: relativeSource(metadata.icnsOutputPath)
262
+ },
263
+ {
264
+ platform: "windows",
265
+ format: "ico",
266
+ source: relativeSource(metadata.icoOutputPath)
267
+ },
268
+ ...metadata.linuxPngOutputPaths.map(({ size, path: pngPath }) => ({
269
+ platform: "linux",
270
+ format: "png",
271
+ size,
272
+ source: relativeSource(pngPath)
273
+ }))
274
+ ]
275
+ };
276
+ await fs.mkdir(manifestDirectory, { recursive: true });
277
+ await fs.writeFile(metadata.manifestOutputPath, `${JSON.stringify(manifest, null, 2)}\n`);
278
+ }
279
+ async function cacheMatches(file, expected) {
280
+ try {
281
+ const parsed = JSON.parse(await fs.readFile(file, "utf8"));
282
+ if (!isCacheMetadata(parsed) || !sameCacheIdentity(parsed, expected)) return false;
283
+ await Promise.all([
284
+ fs.access(expected.outputPath),
285
+ fs.access(expected.icnsOutputPath),
286
+ fs.access(expected.icoOutputPath),
287
+ fs.access(expected.manifestOutputPath),
288
+ ...expected.linuxPngOutputPaths.map(({ path: outputPath }) => fs.access(outputPath))
289
+ ]);
290
+ return true;
291
+ } catch {
292
+ return false;
293
+ }
294
+ }
295
+ function sameCacheIdentity(actual, expected) {
296
+ return actual.schemaVersion === expected.schemaVersion && actual.sourceSha256 === expected.sourceSha256 && actual.sourceImplementationSha256 === expected.sourceImplementationSha256 && actual.implementationSha256 === expected.implementationSha256 && actual.recipeVersion === expected.recipeVersion && actual.sharpVersion === expected.sharpVersion && actual.iconEncoderVersion === expected.iconEncoderVersion && actual.figmaSquircleVersion === expected.figmaSquircleVersion && actual.outputPath === expected.outputPath && actual.icnsOutputPath === expected.icnsOutputPath && actual.icoOutputPath === expected.icoOutputPath && actual.manifestOutputPath === expected.manifestOutputPath && JSON.stringify(actual.linuxPngOutputPaths) === JSON.stringify(expected.linuxPngOutputPaths) && JSON.stringify(actual.appIcon) === JSON.stringify(expected.appIcon);
297
+ }
298
+ function isCacheMetadata(value) {
299
+ if (typeof value !== "object" || value === null) return false;
300
+ const record = value;
301
+ return typeof record.schemaVersion === "number" && typeof record.sourceSha256 === "string" && (record.sourceImplementationSha256 === null || typeof record.sourceImplementationSha256 === "string") && typeof record.implementationSha256 === "string" && typeof record.recipeVersion === "string" && typeof record.sharpVersion === "string" && typeof record.iconEncoderVersion === "string" && typeof record.figmaSquircleVersion === "string" && typeof record.outputPath === "string" && typeof record.icnsOutputPath === "string" && typeof record.icoOutputPath === "string" && Array.isArray(record.linuxPngOutputPaths) && typeof record.manifestOutputPath === "string" && Array.isArray(record.appIcon);
302
+ }
303
+ async function resolveSourceImplementationPath(implementationPath) {
304
+ if (implementationPath.endsWith(`${path.sep}src${path.sep}app-icon.ts`)) return implementationPath;
305
+ const candidate = path.join(path.dirname(path.dirname(implementationPath)), "src", "app-icon.ts");
306
+ try {
307
+ await fs.access(candidate);
308
+ return candidate;
309
+ } catch {
310
+ return null;
311
+ }
312
+ }
313
+ async function packageVersion(packageName) {
314
+ const entryPath = require.resolve(packageName);
315
+ let directory = path.dirname(entryPath);
316
+ while (true) {
317
+ const packagePath = path.join(directory, "package.json");
318
+ try {
319
+ const parsed = JSON.parse(await fs.readFile(packagePath, "utf8"));
320
+ if (isPackageMetadata(parsed, packageName)) return parsed.version;
321
+ } catch {}
322
+ const parent = path.dirname(directory);
323
+ if (parent === directory) break;
324
+ directory = parent;
325
+ }
326
+ throw new Error(`Unable to resolve ${packageName} package version`);
327
+ }
328
+ function isPackageMetadata(value, packageName) {
329
+ return typeof value === "object" && value !== null && "name" in value && value.name === packageName && "version" in value && typeof value.version === "string";
330
+ }
331
+ async function sha256(file) {
332
+ return crypto.createHash("sha256").update(await fs.readFile(file)).digest("hex");
333
+ }
334
+ //#endregion
3
335
  //#region src/index.ts
336
+ /** Vite lifecycle adapter for the shared Darwin app bundle contract. */
337
+ const openTrayAppBundlePlugin = (options) => {
338
+ let config;
339
+ let lastResult;
340
+ return {
341
+ name: "opentray-app-bundle",
342
+ apply: "build",
343
+ configResolved(resolvedConfig) {
344
+ config = resolvedConfig;
345
+ },
346
+ async writeBundle() {
347
+ const resolvedConfig = config ?? {
348
+ root: process.cwd(),
349
+ mode: "production",
350
+ build: { outDir: "dist" }
351
+ };
352
+ const bundlePath = options.bundlePath ?? resolve(resolvedConfig.root, resolvedConfig.build.outDir, `${options.appName}.app`);
353
+ lastResult = await buildDarwinAppBundle({
354
+ ...options,
355
+ bundlePath
356
+ });
357
+ },
358
+ getLastResult: () => lastResult
359
+ };
360
+ };
4
361
  const openTrayVitePlugin = (options) => {
5
362
  let config;
6
363
  let lastResult;
@@ -51,6 +408,6 @@ const asOutputChunk = (value) => {
51
408
  };
52
409
  };
53
410
  //#endregion
54
- export { openTrayVitePlugin, resolveViteEntry };
411
+ export { generateOpenTrayAppIcon, openTrayAppBundlePlugin, openTrayAppIconPlugin, openTrayVitePlugin, resolveViteEntry };
55
412
 
56
413
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../src/index.ts"],"sourcesContent":["import { resolve } from \"node:path\";\n\nimport {\n stageOpenTrayPackage,\n type OpenTrayArtifactInput,\n type OpenTrayPackagingApp,\n type OpenTrayPackageManifest,\n type OpenTrayPackageResult,\n} from \"@opentray/packaging\";\n\nexport interface OpenTrayVitePluginOptions {\n readonly app: OpenTrayPackagingApp;\n readonly runtimeHost: OpenTrayArtifactInput;\n readonly nativeArtifacts?: Readonly<Record<string, OpenTrayArtifactInput>>;\n readonly companionAssets?: Readonly<Record<string, OpenTrayArtifactInput>>;\n readonly entry?: string;\n readonly manifestPath?: string;\n}\n\nexport interface ViteResolvedConfigLike {\n readonly root: string;\n readonly mode: string;\n readonly build: {\n readonly outDir: string;\n };\n}\n\nexport interface ViteOutputChunkLike {\n readonly type?: string;\n readonly isEntry?: boolean;\n readonly fileName?: string;\n readonly facadeModuleId?: string | null;\n readonly name?: string;\n}\n\nexport type ViteBundleLike = Readonly<Record<string, unknown>>;\n\nexport interface OpenTrayVitePlugin {\n readonly name: \"opentray-packaging\";\n readonly apply: \"build\";\n configResolved(config: ViteResolvedConfigLike): void;\n writeBundle(options: unknown, bundle: ViteBundleLike): Promise<void>;\n readonly getLastResult: () => OpenTrayPackageResult | undefined;\n}\n\nexport const openTrayVitePlugin = (\n options: OpenTrayVitePluginOptions,\n): OpenTrayVitePlugin => {\n let config: ViteResolvedConfigLike | undefined;\n let lastResult: OpenTrayPackageResult | undefined;\n\n return {\n name: \"opentray-packaging\",\n apply: \"build\",\n configResolved(resolvedConfig) {\n config = resolvedConfig;\n },\n async writeBundle(_options, bundle) {\n const resolvedConfig = config ?? {\n root: process.cwd(),\n mode: \"production\",\n build: { outDir: \"dist\" },\n };\n lastResult = await stageOpenTrayPackage({\n app: options.app,\n outDir: resolve(resolvedConfig.root, resolvedConfig.build.outDir),\n entry: options.entry ?? resolveViteEntry(bundle),\n adapter: { name: \"vite\", mode: resolvedConfig.mode },\n runtimeHost: options.runtimeHost,\n ...(options.nativeArtifacts === undefined\n ? {}\n : { nativeArtifacts: options.nativeArtifacts }),\n ...(options.companionAssets === undefined\n ? {}\n : { companionAssets: options.companionAssets }),\n ...(options.manifestPath === undefined ? {} : { manifestPath: options.manifestPath }),\n });\n },\n getLastResult: () => lastResult,\n };\n};\n\nexport const resolveViteEntry = (bundle: ViteBundleLike): string => {\n const entry = Object.values(bundle)\n .map(asOutputChunk)\n .find((chunk): chunk is ViteOutputChunkLike => chunk?.isEntry === true);\n const identity = entry?.facadeModuleId ?? entry?.fileName ?? entry?.name;\n if (identity === undefined || identity.length === 0) {\n throw new Error(\"OpenTray Vite packaging requires a Vite entry chunk or explicit entry option\");\n }\n return identity;\n};\n\nconst asOutputChunk = (value: unknown): ViteOutputChunkLike | undefined => {\n if (typeof value !== \"object\" || value === null) {\n return undefined;\n }\n const record = value as Record<string, unknown>;\n return {\n ...(record.type === \"chunk\" ? { type: \"chunk\" } : {}),\n ...(typeof record.isEntry === \"boolean\" ? { isEntry: record.isEntry } : {}),\n ...(typeof record.fileName === \"string\" ? { fileName: record.fileName } : {}),\n ...(typeof record.facadeModuleId === \"string\" || record.facadeModuleId === null\n ? { facadeModuleId: record.facadeModuleId }\n : {}),\n ...(typeof record.name === \"string\" ? { name: record.name } : {}),\n };\n};\n\nexport type { OpenTrayPackageManifest, OpenTrayPackageResult };\n"],"mappings":";;;AA6CA,MAAa,sBACX,YACuB;CACvB,IAAI;CACJ,IAAI;CAEJ,OAAO;EACL,MAAM;EACN,OAAO;EACP,eAAe,gBAAgB;GAC7B,SAAS;EACX;EACA,MAAM,YAAY,UAAU,QAAQ;GAClC,MAAM,iBAAiB,UAAU;IAC/B,MAAM,QAAQ,IAAI;IAClB,MAAM;IACN,OAAO,EAAE,QAAQ,OAAO;GAC1B;GACA,aAAa,MAAM,qBAAqB;IACtC,KAAK,QAAQ;IACb,QAAQ,QAAQ,eAAe,MAAM,eAAe,MAAM,MAAM;IAChE,OAAO,QAAQ,SAAS,iBAAiB,MAAM;IAC/C,SAAS;KAAE,MAAM;KAAQ,MAAM,eAAe;IAAK;IACnD,aAAa,QAAQ;IACrB,GAAI,QAAQ,oBAAoB,KAAA,IAC5B,CAAC,IACD,EAAE,iBAAiB,QAAQ,gBAAgB;IAC/C,GAAI,QAAQ,oBAAoB,KAAA,IAC5B,CAAC,IACD,EAAE,iBAAiB,QAAQ,gBAAgB;IAC/C,GAAI,QAAQ,iBAAiB,KAAA,IAAY,CAAC,IAAI,EAAE,cAAc,QAAQ,aAAa;GACrF,CAAC;EACH;EACA,qBAAqB;CACvB;AACF;AAEA,MAAa,oBAAoB,WAAmC;CAClE,MAAM,QAAQ,OAAO,OAAO,MAAM,EAC/B,IAAI,aAAa,EACjB,MAAM,UAAwC,OAAO,YAAY,IAAI;CACxE,MAAM,WAAW,OAAO,kBAAkB,OAAO,YAAY,OAAO;CACpE,IAAI,aAAa,KAAA,KAAa,SAAS,WAAW,GAChD,MAAM,IAAI,MAAM,8EAA8E;CAEhG,OAAO;AACT;AAEA,MAAM,iBAAiB,UAAoD;CACzE,IAAI,OAAO,UAAU,YAAY,UAAU,MACzC;CAEF,MAAM,SAAS;CACf,OAAO;EACL,GAAI,OAAO,SAAS,UAAU,EAAE,MAAM,QAAQ,IAAI,CAAC;EACnD,GAAI,OAAO,OAAO,YAAY,YAAY,EAAE,SAAS,OAAO,QAAQ,IAAI,CAAC;EACzE,GAAI,OAAO,OAAO,aAAa,WAAW,EAAE,UAAU,OAAO,SAAS,IAAI,CAAC;EAC3E,GAAI,OAAO,OAAO,mBAAmB,YAAY,OAAO,mBAAmB,OACvE,EAAE,gBAAgB,OAAO,eAAe,IACxC,CAAC;EACL,GAAI,OAAO,OAAO,SAAS,WAAW,EAAE,MAAM,OAAO,KAAK,IAAI,CAAC;CACjE;AACF"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../src/app-icon.ts","../src/index.ts"],"sourcesContent":["// Orthogonal intents (maintained 2026-07-20; original user request: move the\n// skill-creator-v2 app-icon build chain into OpenTray's Vite plugin):\n// 1. Normalize a brand source image into a readable application icon with a\n// white safe-area tile and a transparent outer margin.\n// 2. Produce standard macOS ICNS, Windows ICO, and Linux theme PNG assets.\n// 3. Cache the output by source, source implementation, bundled implementation,\n// recipe, encoder, and output identity so stale generated assets cannot leak\n// into a dev runtime.\n// Compromise: published packages do not ship TypeScript sources, so their cache\n// uses a null source hash and the bundled plugin hash as the implementation\n// authority; linked consumers hash both layers.\n\nimport crypto from \"node:crypto\";\nimport fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { createRequire } from \"node:module\";\nimport { fileURLToPath } from \"node:url\";\n\nimport { getSvgPath } from \"figma-squircle\";\nimport sharp from \"sharp\";\nimport type { Plugin } from \"vite\";\n\nimport type { AppIcon } from \"@opentray/spec\";\nimport { IconIcns, IconIco } from \"@shockpkg/icon-encoder\";\n\nconst ICON_SIZE = 1024;\nconst TILE_INSET = 64;\nconst TILE_SIZE = ICON_SIZE - TILE_INSET * 2;\nconst TILE_RADIUS = 196;\nconst TILE_SMOOTHING = 1;\nconst SYMBOL_SIZE = 704;\nconst APP_ICON_DENSITY = 72;\nconst CACHE_SCHEMA_VERSION = 6;\nconst RECIPE_VERSION = `squircle-v3:${ICON_SIZE}:${TILE_INSET}:${TILE_RADIUS}:${TILE_SMOOTHING}:${SYMBOL_SIZE}:${APP_ICON_DENSITY}dpi:icns-tagged`;\nconst ICO_SIZES = [16, 24, 32, 48, 64, 128, 256] as const;\nconst LINUX_SIZES = [16, 32, 48, 64, 128, 256, 512] as const;\nconst ICNS_REPRESENTATIONS = [\n { tag: \"ic12\", size: 64 },\n { tag: \"ic07\", size: 128 },\n { tag: \"ic13\", size: 256 },\n { tag: \"ic08\", size: 256 },\n { tag: \"ic04\", size: 16 },\n { tag: \"ic14\", size: 512 },\n { tag: \"ic09\", size: 512 },\n { tag: \"ic05\", size: 32 },\n { tag: \"ic10\", size: 1024 },\n { tag: \"ic11\", size: 32 },\n] as const;\n\nconst require = createRequire(import.meta.url);\n\nexport interface OpenTrayAppIconOptions {\n readonly sourcePath: string;\n readonly outputPath?: string;\n readonly icnsOutputPath?: string;\n readonly icoOutputPath?: string;\n readonly linuxOutputDirectory?: string;\n readonly manifestOutputPath?: string;\n readonly cachePath?: string;\n /** Advanced: override the module whose bytes identify the generator implementation. */\n readonly implementationPath?: string;\n /** Advanced: override the source file whose bytes identify the generator implementation. */\n readonly implementationSourcePath?: string;\n}\n\nexport interface OpenTrayAppIconCacheMetadata {\n readonly schemaVersion: number;\n readonly sourceSha256: string;\n readonly sourceImplementationSha256: string | null;\n readonly implementationSha256: string;\n readonly recipeVersion: string;\n readonly sharpVersion: string;\n readonly iconEncoderVersion: string;\n readonly figmaSquircleVersion: string;\n readonly outputPath: string;\n readonly icnsOutputPath: string;\n readonly icoOutputPath: string;\n readonly linuxPngOutputPaths: readonly {\n readonly size: number;\n readonly path: string;\n }[];\n readonly manifestOutputPath: string;\n /** Absolute file sources ready to pass to OpenTray at runtime. */\n readonly appIcon: AppIcon;\n}\n\nexport interface OpenTrayAppIconManifest {\n readonly schemaVersion: 1;\n /** File paths are relative to the manifest file. */\n readonly appIcon: AppIcon;\n}\n\nexport interface OpenTrayAppIconPluginOptions {\n /** Brand source image. This is intentionally explicit so the plugin is app-agnostic. */\n readonly sourcePath: string;\n readonly outputPath?: string;\n readonly icnsOutputPath?: string;\n readonly icoOutputPath?: string;\n readonly linuxOutputDirectory?: string;\n readonly manifestOutputPath?: string;\n readonly cachePath?: string;\n}\n\n/** Generate one strict cross-platform AppIcon asset set. */\nexport async function generateOpenTrayAppIcon(\n options: OpenTrayAppIconOptions\n): Promise<OpenTrayAppIconCacheMetadata> {\n const outputPath =\n options.outputPath ??\n path.join(path.dirname(options.sourcePath), \"app-icon.png\");\n const icnsOutputPath =\n options.icnsOutputPath ??\n path.join(path.dirname(outputPath), \"app-icon.icns\");\n const icoOutputPath =\n options.icoOutputPath ??\n path.join(path.dirname(outputPath), \"app-icon.ico\");\n const linuxOutputDirectory =\n options.linuxOutputDirectory ??\n path.join(path.dirname(outputPath), \"linux\");\n const manifestOutputPath =\n options.manifestOutputPath ??\n path.join(path.dirname(outputPath), \"app-icon.json\");\n const cachePath =\n options.cachePath ??\n path.join(path.dirname(outputPath), \"../../.cache/app-icon.json\");\n const implementationPath =\n options.implementationPath ?? fileURLToPath(import.meta.url);\n const metadata = await createCacheMetadata({\n sourcePath: options.sourcePath,\n implementationPath,\n outputPath,\n icnsOutputPath,\n icoOutputPath,\n linuxOutputDirectory,\n manifestOutputPath,\n ...(options.implementationSourcePath === undefined\n ? {}\n : { implementationSourcePath: options.implementationSourcePath }),\n });\n\n if (await cacheMatches(cachePath, metadata)) return metadata;\n\n const rendered = await renderAppIcon(options.sourcePath);\n await fs.mkdir(path.dirname(outputPath), { recursive: true });\n await fs.mkdir(path.dirname(icnsOutputPath), { recursive: true });\n await fs.mkdir(path.dirname(icoOutputPath), { recursive: true });\n await fs.mkdir(path.dirname(cachePath), { recursive: true });\n await fs.writeFile(outputPath, rendered);\n await encodeNativeIcons(rendered, icnsOutputPath, icoOutputPath);\n await writeLinuxIcons(rendered, metadata.linuxPngOutputPaths);\n await writeManifest(metadata);\n await fs.writeFile(\n cachePath,\n `${JSON.stringify(metadata, null, 2)}\\n`,\n \"utf8\"\n );\n return metadata;\n}\n\n/** Create the Vite plugin used by both serve and build modes. */\nexport function openTrayAppIconPlugin(\n options: OpenTrayAppIconPluginOptions\n): Plugin {\n let generation: Promise<OpenTrayAppIconCacheMetadata> | undefined;\n\n return {\n name: \"opentray/app-icon\",\n enforce: \"pre\",\n async configResolved(config) {\n const outputPath =\n options.outputPath ??\n path.resolve(config.root, \"static/icons/app-icon.png\");\n const icnsOutputPath =\n options.icnsOutputPath ??\n path.resolve(config.root, \"static/icons/app-icon.icns\");\n const icoOutputPath =\n options.icoOutputPath ??\n path.resolve(config.root, \"static/icons/app-icon.ico\");\n const linuxOutputDirectory =\n options.linuxOutputDirectory ??\n path.resolve(config.root, \"static/icons/linux\");\n const manifestOutputPath =\n options.manifestOutputPath ??\n path.resolve(config.root, \"static/icons/app-icon.json\");\n const cachePath =\n options.cachePath ?? path.resolve(config.root, \".cache/app-icon.json\");\n generation ??= generateOpenTrayAppIcon({\n sourcePath: path.resolve(options.sourcePath),\n outputPath,\n icnsOutputPath,\n icoOutputPath,\n linuxOutputDirectory,\n manifestOutputPath,\n cachePath,\n });\n await generation;\n },\n };\n}\n\nasync function createCacheMetadata(options: {\n sourcePath: string;\n implementationPath: string;\n implementationSourcePath?: string;\n outputPath: string;\n icnsOutputPath: string;\n icoOutputPath: string;\n linuxOutputDirectory: string;\n manifestOutputPath: string;\n}): Promise<OpenTrayAppIconCacheMetadata> {\n const sourceImplementationPath =\n options.implementationSourcePath ??\n (await resolveSourceImplementationPath(options.implementationPath));\n const linuxPngOutputPaths = LINUX_SIZES.map((size) => ({\n size,\n path: path.resolve(\n options.linuxOutputDirectory,\n `${size}x${size}`,\n \"app-icon.png\"\n ),\n }));\n const icnsOutputPath = path.resolve(options.icnsOutputPath);\n const icoOutputPath = path.resolve(options.icoOutputPath);\n const appIcon: AppIcon = [\n {\n platform: \"darwin\",\n format: \"icns\",\n source: { type: \"file\", path: icnsOutputPath },\n },\n {\n platform: \"windows\",\n format: \"ico\",\n source: { type: \"file\", path: icoOutputPath },\n },\n ...linuxPngOutputPaths.map(({ size, path: pngPath }) => ({\n platform: \"linux\" as const,\n format: \"png\" as const,\n size,\n source: { type: \"file\" as const, path: pngPath },\n })),\n ];\n return {\n schemaVersion: CACHE_SCHEMA_VERSION,\n sourceSha256: await sha256(options.sourcePath),\n sourceImplementationSha256:\n sourceImplementationPath === null\n ? null\n : await sha256(sourceImplementationPath),\n implementationSha256: await sha256(options.implementationPath),\n recipeVersion: RECIPE_VERSION,\n sharpVersion: await packageVersion(\"sharp\"),\n iconEncoderVersion: await packageVersion(\"@shockpkg/icon-encoder\"),\n figmaSquircleVersion: await packageVersion(\"figma-squircle\"),\n outputPath: path.resolve(options.outputPath),\n icnsOutputPath,\n icoOutputPath,\n linuxPngOutputPaths,\n manifestOutputPath: path.resolve(options.manifestOutputPath),\n appIcon,\n };\n}\n\nasync function renderAppIcon(sourcePath: string): Promise<Buffer> {\n const symbol = await sharp(sourcePath)\n .trim({ threshold: 0 })\n .resize(SYMBOL_SIZE, SYMBOL_SIZE, {\n fit: \"inside\",\n kernel: sharp.kernel.lanczos3,\n })\n .png()\n .toBuffer({ resolveWithObject: true });\n const symbolLeft = Math.round((ICON_SIZE - symbol.info.width) / 2);\n const symbolTop = Math.round((ICON_SIZE - symbol.info.height) / 2);\n const squirclePath = getSvgPath({\n width: TILE_SIZE,\n height: TILE_SIZE,\n cornerRadius: TILE_RADIUS,\n cornerSmoothing: TILE_SMOOTHING,\n preserveSmoothing: true,\n });\n const whiteTile = Buffer.from(\n `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"${TILE_SIZE}\" height=\"${TILE_SIZE}\"><path d=\"${squirclePath}\" fill=\"#fff\"/></svg>`\n );\n return sharp({\n create: {\n width: ICON_SIZE,\n height: ICON_SIZE,\n channels: 4,\n background: { r: 0, g: 0, b: 0, alpha: 0 },\n },\n })\n .composite([\n { input: whiteTile, top: TILE_INSET, left: TILE_INSET },\n { input: symbol.data, top: symbolTop, left: symbolLeft },\n ])\n .withMetadata({ density: APP_ICON_DENSITY })\n .png({ compressionLevel: 9 })\n .toBuffer();\n}\n\nasync function encodeNativeIcons(\n rendered: Buffer,\n icnsOutputPath: string,\n icoOutputPath: string\n): Promise<void> {\n const pngBySize = new Map<number, Buffer>();\n const pngAt = async (size: number): Promise<Buffer> => {\n const cached = pngBySize.get(size);\n if (cached !== undefined) return cached;\n const png = await sharp(rendered)\n .resize(size, size, { fit: \"contain\" })\n .withMetadata({ density: APP_ICON_DENSITY })\n .png({ compressionLevel: 9 })\n .toBuffer();\n pngBySize.set(size, png);\n return png;\n };\n\n const icns = new IconIcns();\n icns.toc = true;\n for (const { tag, size } of ICNS_REPRESENTATIONS) {\n await icns.addFromPng(await pngAt(size), [tag], false);\n }\n await fs.writeFile(icnsOutputPath, icns.encode());\n\n const ico = new IconIco();\n for (const size of ICO_SIZES) {\n await ico.addFromPng(await pngAt(size), null, false);\n }\n await fs.writeFile(icoOutputPath, ico.encode());\n}\n\nasync function writeLinuxIcons(\n rendered: Buffer,\n outputs: OpenTrayAppIconCacheMetadata[\"linuxPngOutputPaths\"]\n): Promise<void> {\n await Promise.all(\n outputs.map(async ({ size, path: outputPath }) => {\n await fs.mkdir(path.dirname(outputPath), { recursive: true });\n await sharp(rendered)\n .resize(size, size, { fit: \"contain\" })\n .withMetadata({ density: APP_ICON_DENSITY })\n .png({ compressionLevel: 9 })\n .toFile(outputPath);\n })\n );\n}\n\nasync function writeManifest(\n metadata: OpenTrayAppIconCacheMetadata\n): Promise<void> {\n const manifestDirectory = path.dirname(metadata.manifestOutputPath);\n const relativeSource = (\n sourcePath: string\n ): { type: \"file\"; path: string } => ({\n type: \"file\",\n path: path\n .relative(manifestDirectory, sourcePath)\n .split(path.sep)\n .join(\"/\"),\n });\n const manifest: OpenTrayAppIconManifest = {\n schemaVersion: 1,\n appIcon: [\n {\n platform: \"darwin\",\n format: \"icns\",\n source: relativeSource(metadata.icnsOutputPath),\n },\n {\n platform: \"windows\",\n format: \"ico\",\n source: relativeSource(metadata.icoOutputPath),\n },\n ...metadata.linuxPngOutputPaths.map(({ size, path: pngPath }) => ({\n platform: \"linux\" as const,\n format: \"png\" as const,\n size,\n source: relativeSource(pngPath),\n })),\n ],\n };\n await fs.mkdir(manifestDirectory, { recursive: true });\n await fs.writeFile(\n metadata.manifestOutputPath,\n `${JSON.stringify(manifest, null, 2)}\\n`\n );\n}\n\nasync function cacheMatches(\n file: string,\n expected: OpenTrayAppIconCacheMetadata\n): Promise<boolean> {\n try {\n const parsed: unknown = JSON.parse(await fs.readFile(file, \"utf8\"));\n if (!isCacheMetadata(parsed) || !sameCacheIdentity(parsed, expected))\n return false;\n await Promise.all([\n fs.access(expected.outputPath),\n fs.access(expected.icnsOutputPath),\n fs.access(expected.icoOutputPath),\n fs.access(expected.manifestOutputPath),\n ...expected.linuxPngOutputPaths.map(({ path: outputPath }) =>\n fs.access(outputPath)\n ),\n ]);\n return true;\n } catch {\n return false;\n }\n}\n\nfunction sameCacheIdentity(\n actual: OpenTrayAppIconCacheMetadata,\n expected: OpenTrayAppIconCacheMetadata\n): boolean {\n return (\n actual.schemaVersion === expected.schemaVersion &&\n actual.sourceSha256 === expected.sourceSha256 &&\n actual.sourceImplementationSha256 === expected.sourceImplementationSha256 &&\n actual.implementationSha256 === expected.implementationSha256 &&\n actual.recipeVersion === expected.recipeVersion &&\n actual.sharpVersion === expected.sharpVersion &&\n actual.iconEncoderVersion === expected.iconEncoderVersion &&\n actual.figmaSquircleVersion === expected.figmaSquircleVersion &&\n actual.outputPath === expected.outputPath &&\n actual.icnsOutputPath === expected.icnsOutputPath &&\n actual.icoOutputPath === expected.icoOutputPath &&\n actual.manifestOutputPath === expected.manifestOutputPath &&\n JSON.stringify(actual.linuxPngOutputPaths) ===\n JSON.stringify(expected.linuxPngOutputPaths) &&\n JSON.stringify(actual.appIcon) === JSON.stringify(expected.appIcon)\n );\n}\n\nfunction isCacheMetadata(\n value: unknown\n): value is OpenTrayAppIconCacheMetadata {\n if (typeof value !== \"object\" || value === null) return false;\n const record = value as Record<string, unknown>;\n return (\n typeof record.schemaVersion === \"number\" &&\n typeof record.sourceSha256 === \"string\" &&\n (record.sourceImplementationSha256 === null ||\n typeof record.sourceImplementationSha256 === \"string\") &&\n typeof record.implementationSha256 === \"string\" &&\n typeof record.recipeVersion === \"string\" &&\n typeof record.sharpVersion === \"string\" &&\n typeof record.iconEncoderVersion === \"string\" &&\n typeof record.figmaSquircleVersion === \"string\" &&\n typeof record.outputPath === \"string\" &&\n typeof record.icnsOutputPath === \"string\" &&\n typeof record.icoOutputPath === \"string\" &&\n Array.isArray(record.linuxPngOutputPaths) &&\n typeof record.manifestOutputPath === \"string\" &&\n Array.isArray(record.appIcon)\n );\n}\n\nasync function resolveSourceImplementationPath(\n implementationPath: string\n): Promise<string | null> {\n if (implementationPath.endsWith(`${path.sep}src${path.sep}app-icon.ts`)) {\n return implementationPath;\n }\n const candidate = path.join(\n path.dirname(path.dirname(implementationPath)),\n \"src\",\n \"app-icon.ts\"\n );\n try {\n await fs.access(candidate);\n return candidate;\n } catch {\n return null;\n }\n}\n\nasync function packageVersion(packageName: string): Promise<string> {\n const entryPath = require.resolve(packageName);\n let directory = path.dirname(entryPath);\n while (true) {\n const packagePath = path.join(directory, \"package.json\");\n try {\n const parsed: unknown = JSON.parse(\n await fs.readFile(packagePath, \"utf8\")\n );\n if (isPackageMetadata(parsed, packageName)) return parsed.version;\n } catch {\n // Continue towards the package root; package exports may hide package.json.\n }\n const parent = path.dirname(directory);\n if (parent === directory) break;\n directory = parent;\n }\n throw new Error(`Unable to resolve ${packageName} package version`);\n}\n\nfunction isPackageMetadata(\n value: unknown,\n packageName: string\n): value is { name: string; version: string } {\n return (\n typeof value === \"object\" &&\n value !== null &&\n \"name\" in value &&\n value.name === packageName &&\n \"version\" in value &&\n typeof value.version === \"string\"\n );\n}\n\nasync function sha256(file: string): Promise<string> {\n return crypto\n .createHash(\"sha256\")\n .update(await fs.readFile(file))\n .digest(\"hex\");\n}\n","// Orthogonal intents (maintained 2026-07-20; original user request: expose the\n// OpenTray Vite packaging adapter and move skill-creator-v2 app-icon generation into it):\n// 1. Stage Vite bundle metadata and native runtime artifacts through one adapter.\n// 2. Re-export the app-icon generator without coupling the packaging contract to a consumer.\n// Compromise: both exports share the package entrypoint because Vite resolves one public adapter\n// module and the icon plugin has no runtime dependency on the artifact manifest.\n\nimport { resolve } from \"node:path\";\n\nimport {\n buildDarwinAppBundle,\n stageOpenTrayPackage,\n type DarwinAppBundleOptions,\n type OpenTrayArtifactInput,\n type OpenTrayPackagingApp,\n type OpenTrayPackageManifest,\n type OpenTrayPackageResult,\n type OpenTrayDarwinAppBundleResult,\n} from \"@opentray/packaging\";\n\nexport interface OpenTrayVitePluginOptions {\n readonly app: OpenTrayPackagingApp;\n readonly runtimeHost: OpenTrayArtifactInput;\n readonly nativeArtifacts?: Readonly<Record<string, OpenTrayArtifactInput>>;\n readonly companionAssets?: Readonly<Record<string, OpenTrayArtifactInput>>;\n readonly entry?: string;\n readonly manifestPath?: string;\n}\n\nexport interface ViteResolvedConfigLike {\n readonly root: string;\n readonly mode: string;\n readonly build: {\n readonly outDir: string;\n };\n}\n\nexport interface ViteOutputChunkLike {\n readonly type?: string;\n readonly isEntry?: boolean;\n readonly fileName?: string;\n readonly facadeModuleId?: string | null;\n readonly name?: string;\n}\n\nexport type ViteBundleLike = Readonly<Record<string, unknown>>;\n\nexport interface OpenTrayVitePlugin {\n readonly name: \"opentray-packaging\";\n readonly apply: \"build\";\n configResolved(config: ViteResolvedConfigLike): void;\n writeBundle(options: unknown, bundle: ViteBundleLike): Promise<void>;\n readonly getLastResult: () => OpenTrayPackageResult | undefined;\n}\n\nexport interface OpenTrayViteAppBundlePluginOptions\n extends Omit<DarwinAppBundleOptions, \"bundlePath\" | \"reinitialize\"> {\n /** Optional output path. Defaults to `<vite outDir>/<appName>.app`. */\n readonly bundlePath?: string;\n}\n\nexport interface OpenTrayViteAppBundlePlugin {\n readonly name: \"opentray-app-bundle\";\n readonly apply: \"build\";\n configResolved(config: ViteResolvedConfigLike): void;\n writeBundle(): Promise<void>;\n readonly getLastResult: () => OpenTrayDarwinAppBundleResult | undefined;\n}\n\n/** Vite lifecycle adapter for the shared Darwin app bundle contract. */\nexport const openTrayAppBundlePlugin = (\n options: OpenTrayViteAppBundlePluginOptions,\n): OpenTrayViteAppBundlePlugin => {\n let config: ViteResolvedConfigLike | undefined;\n let lastResult: OpenTrayDarwinAppBundleResult | undefined;\n return {\n name: \"opentray-app-bundle\",\n apply: \"build\",\n configResolved(resolvedConfig) {\n config = resolvedConfig;\n },\n async writeBundle() {\n const resolvedConfig = config ?? {\n root: process.cwd(),\n mode: \"production\",\n build: { outDir: \"dist\" },\n };\n const bundlePath =\n options.bundlePath ?? resolve(\n resolvedConfig.root,\n resolvedConfig.build.outDir,\n `${options.appName}.app`,\n );\n lastResult = await buildDarwinAppBundle({ ...options, bundlePath });\n },\n getLastResult: () => lastResult,\n };\n};\n\nexport const openTrayVitePlugin = (options: OpenTrayVitePluginOptions): OpenTrayVitePlugin => {\n let config: ViteResolvedConfigLike | undefined;\n let lastResult: OpenTrayPackageResult | undefined;\n\n return {\n name: \"opentray-packaging\",\n apply: \"build\",\n configResolved(resolvedConfig) {\n config = resolvedConfig;\n },\n async writeBundle(_options, bundle) {\n const resolvedConfig = config ?? {\n root: process.cwd(),\n mode: \"production\",\n build: { outDir: \"dist\" },\n };\n lastResult = await stageOpenTrayPackage({\n app: options.app,\n outDir: resolve(resolvedConfig.root, resolvedConfig.build.outDir),\n entry: options.entry ?? resolveViteEntry(bundle),\n adapter: { name: \"vite\", mode: resolvedConfig.mode },\n runtimeHost: options.runtimeHost,\n ...(options.nativeArtifacts === undefined\n ? {}\n : { nativeArtifacts: options.nativeArtifacts }),\n ...(options.companionAssets === undefined\n ? {}\n : { companionAssets: options.companionAssets }),\n ...(options.manifestPath === undefined ? {} : { manifestPath: options.manifestPath }),\n });\n },\n getLastResult: () => lastResult,\n };\n};\n\nexport const resolveViteEntry = (bundle: ViteBundleLike): string => {\n const entry = Object.values(bundle)\n .map(asOutputChunk)\n .find((chunk): chunk is ViteOutputChunkLike => chunk?.isEntry === true);\n const identity = entry?.facadeModuleId ?? entry?.fileName ?? entry?.name;\n if (identity === undefined || identity.length === 0) {\n throw new Error(\"OpenTray Vite packaging requires a Vite entry chunk or explicit entry option\");\n }\n return identity;\n};\n\nconst asOutputChunk = (value: unknown): ViteOutputChunkLike | undefined => {\n if (typeof value !== \"object\" || value === null) {\n return undefined;\n }\n const record = value as Record<string, unknown>;\n return {\n ...(record.type === \"chunk\" ? { type: \"chunk\" } : {}),\n ...(typeof record.isEntry === \"boolean\" ? { isEntry: record.isEntry } : {}),\n ...(typeof record.fileName === \"string\" ? { fileName: record.fileName } : {}),\n ...(typeof record.facadeModuleId === \"string\" || record.facadeModuleId === null\n ? { facadeModuleId: record.facadeModuleId }\n : {}),\n ...(typeof record.name === \"string\" ? { name: record.name } : {}),\n };\n};\n\nexport type { OpenTrayPackageManifest, OpenTrayPackageResult };\n\nexport {\n generateOpenTrayAppIcon,\n openTrayAppIconPlugin,\n type OpenTrayAppIconCacheMetadata,\n type OpenTrayAppIconManifest,\n type OpenTrayAppIconOptions,\n type OpenTrayAppIconPluginOptions,\n} from \"./app-icon\";\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,13 +1,24 @@
1
1
  {
2
2
  "name": "@opentray/vite-plugin",
3
- "version": "0.16.0",
3
+ "version": "0.18.0",
4
4
  "description": "Vite adapter for the OpenTray runtime artifact packaging contract.",
5
- "type": "module",
5
+ "keywords": [
6
+ "app-icon",
7
+ "icns",
8
+ "opentray",
9
+ "vite"
10
+ ],
6
11
  "license": "MIT",
7
12
  "repository": {
8
13
  "type": "git",
9
14
  "url": "https://github.com/jixoai/opentray"
10
15
  },
16
+ "files": [
17
+ "dist",
18
+ "README.md"
19
+ ],
20
+ "type": "module",
21
+ "sideEffects": false,
11
22
  "exports": {
12
23
  ".": {
13
24
  "types": "./dist/index.d.mts",
@@ -15,13 +26,17 @@
15
26
  },
16
27
  "./package.json": "./package.json"
17
28
  },
18
- "files": [
19
- "dist",
20
- "README.md"
21
- ],
22
- "sideEffects": false,
23
29
  "dependencies": {
24
- "@opentray/packaging": "0.16.0"
30
+ "@shockpkg/icon-encoder": "^3.2.3",
31
+ "figma-squircle": "^1.1.0",
32
+ "sharp": "^0.33.5",
33
+ "@opentray/packaging": "0.18.0",
34
+ "@opentray/spec": "0.18.0"
35
+ },
36
+ "devDependencies": {
37
+ "tsdown": "^0.22.1",
38
+ "typescript": "^6.0.3",
39
+ "vitest": "^4.1.7"
25
40
  },
26
41
  "peerDependencies": {
27
42
  "vite": ">=5"
@@ -31,11 +46,6 @@
31
46
  "optional": true
32
47
  }
33
48
  },
34
- "devDependencies": {
35
- "tsdown": "^0.22.1",
36
- "typescript": "^6.0.3",
37
- "vitest": "^4.1.7"
38
- },
39
49
  "scripts": {
40
50
  "build": "tsdown src/index.ts --format esm --dts",
41
51
  "test": "vitest run --config vitest.config.ts",