electrobun 1.9.0-beta.1 → 1.9.0-beta.3

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.
@@ -260,6 +260,21 @@ export interface ElectrobunConfig {
260
260
  };
261
261
  };
262
262
 
263
+ /**
264
+ * Runtime behaviour configuration.
265
+ * These values are copied into build.json and available to the Bun process at runtime.
266
+ * You can add arbitrary keys here and access them via BuildConfig.
267
+ */
268
+ runtime?: {
269
+ /**
270
+ * Quit the application when the last BrowserWindow is closed.
271
+ * @default true
272
+ */
273
+ exitOnLastWindowClosed?: boolean;
274
+
275
+ [key: string]: unknown;
276
+ };
277
+
263
278
  /**
264
279
  * Build scripts configuration
265
280
  */
@@ -3,6 +3,7 @@ import electrobunEventEmitter from "../events/eventEmitter";
3
3
  import { BrowserView } from "./BrowserView";
4
4
  import { type Pointer } from "bun:ffi";
5
5
  import { BuildConfig } from "./BuildConfig";
6
+ import { quit } from "./Utils";
6
7
 
7
8
  const buildConfig = await BuildConfig.get();
8
9
 
@@ -53,6 +54,18 @@ export const BrowserWindowMap: {
53
54
  [id: number]: BrowserWindow<RPCWithTransport>;
54
55
  } = {};
55
56
 
57
+ // Clean up the window map when a window closes and optionally quit the app
58
+ electrobunEventEmitter.on("close", (event: { data: { id: number } }) => {
59
+ delete BrowserWindowMap[event.data.id];
60
+
61
+ const exitOnLastWindowClosed =
62
+ buildConfig.runtime?.exitOnLastWindowClosed ?? true;
63
+
64
+ if (exitOnLastWindowClosed && Object.keys(BrowserWindowMap).length === 0) {
65
+ quit();
66
+ }
67
+ });
68
+
56
69
  interface RPCWithTransport {
57
70
  setTransport: (transport: {
58
71
  send: (msg: unknown) => void;
@@ -1,6 +1,10 @@
1
1
  export type BuildConfigType = {
2
2
  defaultRenderer: "native" | "cef";
3
3
  availableRenderers: ("native" | "cef")[];
4
+ runtime?: {
5
+ exitOnLastWindowClosed?: boolean;
6
+ [key: string]: unknown;
7
+ };
4
8
  };
5
9
 
6
10
  let buildConfig: BuildConfigType | null = null;
@@ -111,11 +111,24 @@ export const showNotification = (options: NotificationOptions): void => {
111
111
  ffi.request.showNotification({ title, body, subtitle, silent });
112
112
  };
113
113
 
114
+ let isQuitting = false;
115
+
114
116
  export const quit = () => {
115
- // Use native killApp for graceful shutdown
117
+ if (isQuitting) return;
118
+ isQuitting = true;
116
119
  native.symbols.killApp();
117
120
  };
118
121
 
122
+ // Override process.exit so that calling it triggers proper native cleanup
123
+ const originalProcessExit = process.exit;
124
+ process.exit = ((code?: number) => {
125
+ if (isQuitting) {
126
+ originalProcessExit(code);
127
+ return;
128
+ }
129
+ quit();
130
+ }) as typeof process.exit;
131
+
119
132
  export const openFileDialog = async (
120
133
  opts: {
121
134
  startingFolder?: string;
@@ -280,7 +293,10 @@ const home = homedir();
280
293
 
281
294
  function getLinuxXdgUserDirs(): Record<string, string> {
282
295
  try {
283
- const content = readFileSync(join(home, ".config", "user-dirs.dirs"), "utf-8");
296
+ const content = readFileSync(
297
+ join(home, ".config", "user-dirs.dirs"),
298
+ "utf-8",
299
+ );
284
300
  const dirs: Record<string, string> = {};
285
301
  for (const line of content.split("\n")) {
286
302
  const trimmed = line.trim();
@@ -368,7 +384,12 @@ function getConfigDir(): string {
368
384
  }
369
385
  }
370
386
 
371
- function getUserDir(macName: string, winName: string, xdgKey: string, fallbackName: string): string {
387
+ function getUserDir(
388
+ macName: string,
389
+ winName: string,
390
+ xdgKey: string,
391
+ fallbackName: string,
392
+ ): string {
372
393
  switch (OS) {
373
394
  case "macos":
374
395
  return join(home, macName);
@@ -401,10 +422,20 @@ export const paths = {
401
422
  return getLogsDir();
402
423
  },
403
424
  get documents(): string {
404
- return getUserDir("Documents", "Documents", "XDG_DOCUMENTS_DIR", "Documents");
425
+ return getUserDir(
426
+ "Documents",
427
+ "Documents",
428
+ "XDG_DOCUMENTS_DIR",
429
+ "Documents",
430
+ );
405
431
  },
406
432
  get downloads(): string {
407
- return getUserDir("Downloads", "Downloads", "XDG_DOWNLOAD_DIR", "Downloads");
433
+ return getUserDir(
434
+ "Downloads",
435
+ "Downloads",
436
+ "XDG_DOWNLOAD_DIR",
437
+ "Downloads",
438
+ );
408
439
  },
409
440
  get desktop(): string {
410
441
  return getUserDir("Desktop", "Desktop", "XDG_DESKTOP_DIR", "Desktop");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "electrobun",
3
- "version": "1.9.0-beta.1",
3
+ "version": "1.9.0-beta.3",
4
4
  "description": "Build ultra fast, tiny, and cross-platform desktop apps with Typescript.",
5
5
  "license": "MIT",
6
6
  "author": "Blackboard Technologies Inc.",
package/src/cli/index.ts CHANGED
@@ -2724,6 +2724,7 @@ ${schemesXml}
2724
2724
  const buildJsonObj: Record<string, unknown> = {
2725
2725
  defaultRenderer: platformConfig?.defaultRenderer ?? "native",
2726
2726
  availableRenderers: bundlesCEF ? ["native", "cef"] : ["native"],
2727
+ runtime: config.runtime ?? {},
2727
2728
  };
2728
2729
 
2729
2730
  // Include chromiumFlags only if the developer defined them