mirinjs 0.1.0-alpha.20 → 0.1.0-alpha.23

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mirinjs",
3
- "version": "0.1.0-alpha.20",
3
+ "version": "0.1.0-alpha.23",
4
4
  "description": "Build desktop apps with Bun, TypeScript, and Chromium (CEF). The Bun-native Electron alternative.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -77,6 +77,19 @@ export interface WindowConfig {
77
77
  visible?: boolean;
78
78
  }
79
79
 
80
+ /**
81
+ * Per-platform icon sources, for when one file can't serve every target — most
82
+ * often an Icon Composer `.icon` on macOS (appearance variants, glass) beside a
83
+ * `.iconset`/`.png` for Linux and Windows, which cannot read `.icon` at all.
84
+ */
85
+ export interface IconSources {
86
+ /** Used by any platform without its own entry. */
87
+ default: string;
88
+ macos?: string;
89
+ windows?: string;
90
+ linux?: string;
91
+ }
92
+
80
93
  export interface MirinConfig {
81
94
  /** Reverse-DNS app id, e.g. "dev.peje.hello". */
82
95
  id: string;
@@ -100,9 +113,12 @@ export interface MirinConfig {
100
113
  * only way macOS 26+ resolves light / dark / tinted appearance variants. That
101
114
  * step needs `actool` from a full Xcode — with Command Line Tools alone the
102
115
  * build warns and falls back to the plain `.icns`, so it never fails a build.
103
- * On Linux and Windows an `.icon` is skipped; give those a `.png`/`.ico`.
116
+ *
117
+ * Linux and Windows cannot read an `.icon`. To ship one on macOS while still
118
+ * icon-ing those targets, pass {@link IconSources}:
119
+ * `{ default: "icon.iconset", macos: "AppIcon.icon" }`.
104
120
  */
105
- icon?: string;
121
+ icon?: string | IconSources;
106
122
  /** CEF runtime packaging options. Omit to bundle every locale. */
107
123
  cef?: CefConfig;
108
124
  /**
package/src/runtime.ts CHANGED
@@ -118,6 +118,21 @@ function dispatch(raw: string): void {
118
118
  }
119
119
  }
120
120
 
121
+ /** Process-global boot marker. Module-level state won't do: a bundle carrying
122
+ * two mirinjs copies (workspace version skew) evaluates this module twice, and
123
+ * a second event poller on the shared native queue steals events from the
124
+ * first — the app's `ready` never fires and no window opens, with no error.
125
+ * `Symbol.for` is the one namespace both copies share. */
126
+ const BOOT_SLOT = Symbol.for("mirinjs.runtime.booted");
127
+
128
+ /** Claim the process-wide boot slot; false when another mirinjs copy holds it. */
129
+ export function claimBootSlot(): boolean {
130
+ const g = globalThis as Record<symbol, unknown>;
131
+ if (g[BOOT_SLOT]) return false;
132
+ g[BOOT_SLOT] = true;
133
+ return true;
134
+ }
135
+
121
136
  /** Boot the runtime from the Worker's workerData. No-op when run detached. */
122
137
  export function boot(): void {
123
138
  const data = (workerData ?? {}) as {
@@ -131,6 +146,14 @@ export function boot(): void {
131
146
  };
132
147
  const corePath = data.corePath ?? process.env.MIRIN_CORE;
133
148
  if (!corePath) return; // not under the host; the API stays detached
149
+ if (!claimBootSlot()) {
150
+ console.error(
151
+ "[mirin] refusing to boot a second mirinjs copy in this process — the bundle " +
152
+ "contains duplicate mirinjs installs (workspace packages pinning different " +
153
+ "versions?). This copy stays detached; align every mirinjs dependency to one version.",
154
+ );
155
+ return;
156
+ }
134
157
 
135
158
  const core = new Core(corePath);
136
159
  const rpc = new RpcServer();