@opentray/vite-plugin 0.16.0 → 0.17.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 +56 -0
- package/dist/index.d.mts +71 -2
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +360 -3
- package/dist/index.mjs.map +1 -1
- package/package.json +23 -13
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
|
package/dist/index.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/index.ts"],"mappings":";;;
|
|
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 {
|
|
2
|
-
import {
|
|
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
|
package/dist/index.mjs.map
CHANGED
|
@@ -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.
|
|
3
|
+
"version": "0.17.0",
|
|
4
4
|
"description": "Vite adapter for the OpenTray runtime artifact packaging contract.",
|
|
5
|
-
"
|
|
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
|
-
"@
|
|
30
|
+
"@shockpkg/icon-encoder": "^3.2.3",
|
|
31
|
+
"figma-squircle": "^1.1.0",
|
|
32
|
+
"sharp": "^0.33.5",
|
|
33
|
+
"@opentray/packaging": "0.17.0",
|
|
34
|
+
"@opentray/spec": "0.17.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",
|