electrobun 0.0.19-beta.118 → 0.0.19-beta.119

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.
Files changed (68) hide show
  1. package/README.md +1 -1
  2. package/dist/api/browser/webviewtag.ts +54 -2
  3. package/dist/api/bun/ElectrobunConfig.ts +171 -0
  4. package/dist/api/bun/core/BrowserWindow.ts +4 -0
  5. package/dist/api/bun/core/Tray.ts +14 -0
  6. package/dist/api/bun/index.ts +2 -0
  7. package/dist/api/bun/proc/native.ts +76 -5
  8. package/package.json +4 -2
  9. package/src/cli/index.ts +43 -17
  10. package/templates/hello-world/electrobun.config.ts +28 -0
  11. package/templates/hello-world/package.json +1 -1
  12. package/templates/interactive-playground/README.md +26 -0
  13. package/templates/interactive-playground/assets/tray-icon.png +0 -0
  14. package/templates/interactive-playground/electrobun.config.ts +36 -0
  15. package/templates/interactive-playground/package-lock.json +36 -0
  16. package/templates/interactive-playground/package.json +15 -0
  17. package/templates/interactive-playground/src/bun/demos/files.ts +70 -0
  18. package/templates/interactive-playground/src/bun/demos/menus.ts +139 -0
  19. package/templates/interactive-playground/src/bun/demos/rpc.ts +83 -0
  20. package/templates/interactive-playground/src/bun/demos/system.ts +72 -0
  21. package/templates/interactive-playground/src/bun/demos/updates.ts +105 -0
  22. package/templates/interactive-playground/src/bun/demos/windows.ts +90 -0
  23. package/templates/interactive-playground/src/bun/index.ts +124 -0
  24. package/templates/interactive-playground/src/bun/types/rpc.ts +109 -0
  25. package/templates/interactive-playground/src/mainview/components/EventLog.ts +107 -0
  26. package/templates/interactive-playground/src/mainview/components/Sidebar.ts +65 -0
  27. package/templates/interactive-playground/src/mainview/components/Toast.ts +57 -0
  28. package/templates/interactive-playground/src/mainview/demos/FileDemo.ts +211 -0
  29. package/templates/interactive-playground/src/mainview/demos/MenuDemo.ts +102 -0
  30. package/templates/interactive-playground/src/mainview/demos/RPCDemo.ts +229 -0
  31. package/templates/interactive-playground/src/mainview/demos/TrayDemo.ts +132 -0
  32. package/templates/interactive-playground/src/mainview/demos/WebViewDemo.ts +411 -0
  33. package/templates/interactive-playground/src/mainview/demos/WindowDemo.ts +207 -0
  34. package/templates/interactive-playground/src/mainview/index.css +538 -0
  35. package/templates/interactive-playground/src/mainview/index.html +103 -0
  36. package/templates/interactive-playground/src/mainview/index.ts +238 -0
  37. package/templates/multitab-browser/README.md +34 -0
  38. package/templates/multitab-browser/bun.lock +224 -0
  39. package/templates/multitab-browser/electrobun.config.ts +32 -0
  40. package/templates/multitab-browser/package-lock.json +20 -0
  41. package/templates/multitab-browser/package.json +12 -0
  42. package/templates/multitab-browser/src/bun/index.ts +137 -0
  43. package/templates/multitab-browser/src/bun/tabManager.ts +200 -0
  44. package/templates/multitab-browser/src/bun/types/rpc.ts +78 -0
  45. package/templates/multitab-browser/src/mainview/index.css +487 -0
  46. package/templates/multitab-browser/src/mainview/index.html +94 -0
  47. package/templates/multitab-browser/src/mainview/index.ts +629 -0
  48. package/templates/photo-booth/electrobun.config.ts +28 -0
  49. package/templates/photo-booth/package.json +1 -1
  50. package/tests/bun.lock +14 -0
  51. package/tests/electrobun.config.ts +45 -0
  52. package/tests/package-lock.json +36 -0
  53. package/tests/package.json +13 -0
  54. package/tests/src/bun/index.ts +100 -0
  55. package/tests/src/bun/test-runner.ts +508 -0
  56. package/tests/src/mainview/index.html +110 -0
  57. package/tests/src/mainview/index.ts +458 -0
  58. package/tests/src/mainview/styles/main.css +451 -0
  59. package/tests/src/testviews/tray-test.html +57 -0
  60. package/tests/src/testviews/webview-mask.html +114 -0
  61. package/tests/src/testviews/webview-navigation.html +36 -0
  62. package/tests/src/testviews/window-create.html +17 -0
  63. package/tests/src/testviews/window-events.html +29 -0
  64. package/tests/src/testviews/window-focus.html +37 -0
  65. package/tests/src/webviewtag/index.ts +11 -0
  66. package/templates/hello-world/electrobun.config +0 -28
  67. package/templates/photo-booth/electrobun.config +0 -28
  68. package/templates/photo-booth/src/mainview/index_old.ts +0 -671
package/README.md CHANGED
@@ -20,7 +20,7 @@ Visit <a href="https://www.electrobun.dev/">Electrobun.dev</a> to see api docume
20
20
  - Write typescript for the main process and webviews without having to think about it.
21
21
  - Isolation between main and webview processes with fast, typed, easy to implement RPC between them.
22
22
  - Small self-extracting app bundles ~12MB (when using system webview, most of this is the bun runtime)
23
- - Even smaller app updates as small as 4KB (using bsdiff it only downloads tiny patches between versions)
23
+ - Even smaller app updates as small as 14KB (using bsdiff it only downloads tiny patches between versions)
24
24
  - Provide everything you need in one tightly integrated workflow to start writing code in 5 minutes and distribute in 10.
25
25
 
26
26
  ## Architecture
@@ -54,6 +54,7 @@ const ConfigureWebviewTags = (
54
54
  hiddenMirrorMode: boolean = false;
55
55
  wasZeroRect: boolean = false;
56
56
  isMirroring: boolean = false;
57
+ masks: string = '';
57
58
 
58
59
  partition: string | null = null;
59
60
 
@@ -83,7 +84,15 @@ const ConfigureWebviewTags = (
83
84
  this.lastRect = rect;
84
85
 
85
86
  const url = this.src || this.getAttribute("src");
86
- const html = this.html || this.getAttribute("html");
87
+ const html = this.html || this.getAttribute("html");
88
+
89
+ const maskSelectors = this.masks || this.getAttribute("masks");
90
+
91
+ if (maskSelectors) {
92
+ maskSelectors.split(',').forEach(s => {
93
+ this.maskSelectors.add(s);
94
+ })
95
+ }
87
96
 
88
97
  const webviewId = await this.internalRpc.request.webviewTagInit({
89
98
  hostWebviewId: window.__electrobunWebviewId,
@@ -371,7 +380,12 @@ const ConfigureWebviewTags = (
371
380
  // this.mutationObserver?.disconnect();
372
381
  window.removeEventListener("resize", this.boundForceSyncDimensions);
373
382
  window.removeEventListener("scroll", this.boundSyncDimensions);
374
- this.internalRpc.send.webviewTagRemove({ id: this.webviewId });
383
+
384
+ if (this.webviewId) {
385
+ this.internalRpc.send.webviewTagRemove({ id: this.webviewId });
386
+ // Mark webview as removed to prevent further method calls
387
+ this.webviewId = undefined;
388
+ }
375
389
  }
376
390
 
377
391
  static get observedAttributes() {
@@ -393,6 +407,7 @@ const ConfigureWebviewTags = (
393
407
 
394
408
  updateIFrameSrc(src: string) {
395
409
  if (!this.webviewId) {
410
+ console.warn('updateIFrameSrc called on removed webview');
396
411
  return;
397
412
  }
398
413
  this.internalRpc.send.webviewTagUpdateSrc({
@@ -403,6 +418,7 @@ const ConfigureWebviewTags = (
403
418
 
404
419
  updateIFrameHtml(html: string) {
405
420
  if (!this.webviewId) {
421
+ console.warn('updateIFrameHtml called on removed webview');
406
422
  return;
407
423
  }
408
424
 
@@ -414,6 +430,7 @@ const ConfigureWebviewTags = (
414
430
 
415
431
  updateIFramePreload(preload: string) {
416
432
  if (!this.webviewId) {
433
+ console.warn('updateIFramePreload called on removed webview');
417
434
  return;
418
435
  }
419
436
  this.internalRpc.send.webviewTagUpdatePreload({
@@ -423,17 +440,33 @@ const ConfigureWebviewTags = (
423
440
  }
424
441
 
425
442
  goBack() {
443
+ if (!this.webviewId) {
444
+ console.warn('goBack called on removed webview');
445
+ return;
446
+ }
426
447
  this.internalRpc.send.webviewTagGoBack({ id: this.webviewId });
427
448
  }
428
449
 
429
450
  goForward() {
451
+ if (!this.webviewId) {
452
+ console.warn('goForward called on removed webview');
453
+ return;
454
+ }
430
455
  this.internalRpc.send.webviewTagGoForward({ id: this.webviewId });
431
456
  }
432
457
 
433
458
  reload() {
459
+ if (!this.webviewId) {
460
+ console.warn('reload called on removed webview');
461
+ return;
462
+ }
434
463
  this.internalRpc.send.webviewTagReload({ id: this.webviewId });
435
464
  }
436
465
  loadURL(url: string) {
466
+ if (!this.webviewId) {
467
+ console.warn('loadURL called on removed webview');
468
+ return;
469
+ }
437
470
  this.setAttribute("src", url);
438
471
  this.internalRpc.send.webviewTagUpdateSrc({
439
472
  id: this.webviewId,
@@ -441,6 +474,10 @@ const ConfigureWebviewTags = (
441
474
  });
442
475
  }
443
476
  loadHTML(html: string) {
477
+ if (!this.webviewId) {
478
+ console.warn('loadHTML called on removed webview');
479
+ return;
480
+ }
444
481
  this.setAttribute("html", html);
445
482
  this.internalRpc.send.webviewTagUpdateHtml({
446
483
  id: this.webviewId,
@@ -450,6 +487,11 @@ const ConfigureWebviewTags = (
450
487
 
451
488
  // This sets the native webview hovering over the dom to be transparent
452
489
  toggleTransparent(transparent?: boolean, bypassState?: boolean) {
490
+ if (!this.webviewId) {
491
+ console.warn('toggleTransparent called on removed webview');
492
+ return;
493
+ }
494
+
453
495
  if (!bypassState) {
454
496
  if (typeof transparent === "undefined") {
455
497
  this.transparent = !this.transparent;
@@ -464,6 +506,11 @@ const ConfigureWebviewTags = (
464
506
  });
465
507
  }
466
508
  togglePassthrough(enablePassthrough?: boolean, bypassState?: boolean) {
509
+ if (!this.webviewId) {
510
+ console.warn('togglePassthrough called on removed webview');
511
+ return;
512
+ }
513
+
467
514
  if (!bypassState) {
468
515
  if (typeof enablePassthrough === "undefined") {
469
516
  this.passthroughEnabled = !this.passthroughEnabled;
@@ -480,6 +527,11 @@ const ConfigureWebviewTags = (
480
527
  }
481
528
 
482
529
  toggleHidden(hidden?: boolean, bypassState?: boolean) {
530
+ if (!this.webviewId) {
531
+ console.warn('toggleHidden called on removed webview');
532
+ return;
533
+ }
534
+
483
535
  if (!bypassState) {
484
536
  if (typeof hidden === "undefined") {
485
537
  this.hidden = !this.hidden;
@@ -0,0 +1,171 @@
1
+ /**
2
+ * Electrobun configuration type definitions
3
+ * Used in electrobun.config.ts files
4
+ */
5
+
6
+ export interface ElectrobunConfig {
7
+ /**
8
+ * Application metadata configuration
9
+ */
10
+ app: {
11
+ /**
12
+ * The display name of your application
13
+ */
14
+ name: string;
15
+
16
+ /**
17
+ * Unique identifier for your application (e.g., "com.example.myapp")
18
+ * Used for platform-specific identifiers
19
+ */
20
+ identifier: string;
21
+
22
+ /**
23
+ * Application version string (e.g., "1.0.0")
24
+ */
25
+ version: string;
26
+ };
27
+
28
+ /**
29
+ * Build configuration options
30
+ */
31
+ build?: {
32
+ /**
33
+ * Bun process build configuration
34
+ */
35
+ bun?: {
36
+ /**
37
+ * Entry point for the main Bun process
38
+ * @default "src/bun/index.ts"
39
+ */
40
+ entrypoint?: string;
41
+
42
+ /**
43
+ * External modules to exclude from bundling
44
+ * @default []
45
+ */
46
+ external?: string[];
47
+ };
48
+
49
+ /**
50
+ * Browser view build configurations
51
+ */
52
+ views?: {
53
+ [viewName: string]: {
54
+ /**
55
+ * Entry point for this view's TypeScript code
56
+ */
57
+ entrypoint: string;
58
+
59
+ /**
60
+ * External modules to exclude from bundling for this view
61
+ */
62
+ external?: string[];
63
+ };
64
+ };
65
+
66
+ /**
67
+ * Files to copy directly to the build output
68
+ * Key is source path, value is destination path
69
+ */
70
+ copy?: {
71
+ [sourcePath: string]: string;
72
+ };
73
+ /**
74
+ * Output folder for built application
75
+ * @default "build"
76
+ */
77
+ buildFolder?: string;
78
+
79
+ /**
80
+ * Output folder for distribution artifacts
81
+ * @default "artifacts"
82
+ */
83
+ artifactFolder?: string;
84
+
85
+ /**
86
+ * Build targets to compile for
87
+ * Can be "current", "all", or comma-separated list like "macos-arm64,win-x64"
88
+ */
89
+ targets?: string;
90
+
91
+ /**
92
+ * macOS-specific build configuration
93
+ */
94
+ mac?: {
95
+ /**
96
+ * Enable code signing for macOS builds
97
+ * @default false
98
+ */
99
+ codesign?: boolean;
100
+
101
+ /**
102
+ * Enable notarization for macOS builds (requires codesign)
103
+ * @default false
104
+ */
105
+ notarize?: boolean;
106
+
107
+ /**
108
+ * Bundle CEF (Chromium Embedded Framework) instead of using system WebView
109
+ * @default false
110
+ */
111
+ bundleCEF?: boolean;
112
+
113
+ /**
114
+ * macOS entitlements for code signing
115
+ */
116
+ entitlements?: Record<string, boolean | string>;
117
+
118
+ /**
119
+ * Path to .iconset folder containing app icons
120
+ * @default "icon.iconset"
121
+ */
122
+ icons?: string;
123
+ };
124
+
125
+ /**
126
+ * Windows-specific build configuration
127
+ */
128
+ win?: {
129
+ /**
130
+ * Bundle CEF (Chromium Embedded Framework) instead of using WebView2
131
+ * @default false
132
+ */
133
+ bundleCEF?: boolean;
134
+ };
135
+
136
+ /**
137
+ * Linux-specific build configuration
138
+ */
139
+ linux?: {
140
+ /**
141
+ * Bundle CEF (Chromium Embedded Framework) instead of using GTKWebKit
142
+ * Recommended on Linux for advanced layer compositing features
143
+ * @default false
144
+ */
145
+ bundleCEF?: boolean;
146
+ };
147
+ };
148
+
149
+ /**
150
+ * Build scripts configuration
151
+ */
152
+ scripts?: {
153
+ /**
154
+ * Script to run after build completes
155
+ * Can be a path to a script file
156
+ */
157
+ postBuild?: string;
158
+ };
159
+
160
+ /**
161
+ * Release and distribution configuration
162
+ */
163
+ release?: {
164
+ /**
165
+ * Base URL for artifact distribution (e.g., S3 bucket URL)
166
+ * Used for auto-updates and patch generation
167
+ */
168
+ bucketUrl?: string;
169
+ };
170
+ }
171
+
@@ -182,6 +182,10 @@ export class BrowserWindow<T> {
182
182
  return ffi.request.closeWindow({ winId: this.id });
183
183
  }
184
184
 
185
+ focus() {
186
+ return ffi.request.focusWindow({ winId: this.id });
187
+ }
188
+
185
189
  // todo (yoav): move this to a class that also has off, append, prepend, etc.
186
190
  // name should only allow browserWindow events
187
191
  on(name, handler) {
@@ -73,6 +73,13 @@ export class Tray {
73
73
  electrobunEventEmitter.on(specificName, handler);
74
74
  }
75
75
 
76
+ remove() {
77
+ console.log('Tray.remove() called for id:', this.id);
78
+ ffi.request.removeTray({ id: this.id });
79
+ delete TrayMap[this.id];
80
+ console.log('Tray removed from TrayMap');
81
+ }
82
+
76
83
  static getById(id: number) {
77
84
  return TrayMap[id];
78
85
  }
@@ -80,6 +87,13 @@ export class Tray {
80
87
  static getAll() {
81
88
  return Object.values(TrayMap);
82
89
  }
90
+
91
+ static removeById(id: number) {
92
+ const tray = TrayMap[id];
93
+ if (tray) {
94
+ tray.remove();
95
+ }
96
+ }
83
97
  }
84
98
 
85
99
  const menuConfigWithDefaults = (
@@ -10,11 +10,13 @@ import { type RPCSchema, createRPC } from "rpc-anywhere";
10
10
  import type ElectrobunEvent from "./events/event";
11
11
  import * as PATHS from "./core/Paths";
12
12
  import * as Socket from "./core/Socket";
13
+ import type { ElectrobunConfig } from "./ElectrobunConfig";
13
14
 
14
15
  // Named Exports
15
16
  export {
16
17
  type RPCSchema,
17
18
  type ElectrobunEvent,
19
+ type ElectrobunConfig,
18
20
  createRPC,
19
21
  BrowserWindow,
20
22
  BrowserView,
@@ -186,6 +186,10 @@ export const native = (() => {
186
186
  args: [FFIType.ptr, FFIType.cstring],
187
187
  returns: FFIType.void
188
188
  },
189
+ removeTray: {
190
+ args: [FFIType.ptr],
191
+ returns: FFIType.void
192
+ },
189
193
  setApplicationMenu: {
190
194
  args: [FFIType.cstring, FFIType.function],
191
195
  returns: FFIType.void
@@ -382,6 +386,17 @@ export const ffi = {
382
386
  // Note: Cleanup of BrowserWindowMap happens in the windowCloseCallback
383
387
  },
384
388
 
389
+ focusWindow: (params: {winId: number}) => {
390
+ const {winId} = params;
391
+ const windowPtr = BrowserWindow.getById(winId)?.ptr;
392
+
393
+ if (!windowPtr) {
394
+ throw `Can't focus window. Window no longer exists`;
395
+ }
396
+
397
+ native.symbols.makeNSWindowKeyAndOrderFront(windowPtr);
398
+ },
399
+
385
400
  createWebview: (params: {
386
401
  id: number;
387
402
  windowId: number;
@@ -674,6 +689,22 @@ export const ffi = {
674
689
  toCString(menuConfig)
675
690
  );
676
691
  },
692
+
693
+ removeTray: (params: { id: number }): void => {
694
+ const { id } = params;
695
+ console.log('removeTray called with id:', id);
696
+ const tray = Tray.getById(id);
697
+ console.log('Found tray:', tray);
698
+
699
+ if (!tray) {
700
+ throw `Can't remove tray. Tray no longer exists`;
701
+ }
702
+
703
+ console.log('Calling native.symbols.removeTray with ptr:', tray.ptr);
704
+ native.symbols.removeTray(tray.ptr);
705
+ console.log('Native removeTray called successfully');
706
+ // The Tray class will handle removing from TrayMap
707
+ },
677
708
  setApplicationMenu: (params: {menuConfig: string}): void => {
678
709
  const {
679
710
  menuConfig
@@ -1141,6 +1172,7 @@ export const internalRpcHandlers = {
1141
1172
  },
1142
1173
  webviewTagCallAsyncJavaScript: (params) => {
1143
1174
  console.log('-----------+ request: ', 'webviewTagCallAsyncJavaScript', params)
1175
+ // Not implemented - users can use RPC for JavaScript execution if needed
1144
1176
  }
1145
1177
  },
1146
1178
  message: {
@@ -1157,33 +1189,60 @@ export const internalRpcHandlers = {
1157
1189
  native.symbols.resizeWebview(webviewPtr, x, y, width, height, toCString(params.masks))
1158
1190
  },
1159
1191
  webviewTagUpdateSrc: (params) => {
1160
- const webviewPtr = BrowserView.getById(params.id)?.ptr;
1161
- native.symbols.loadURLInWebView(webviewPtr, toCString(params.url))
1192
+ const webview = BrowserView.getById(params.id);
1193
+ if (!webview || !webview.ptr) {
1194
+ console.error(`webviewTagUpdateSrc: BrowserView not found or has no ptr for id ${params.id}`);
1195
+ return;
1196
+ }
1197
+ native.symbols.loadURLInWebView(webview.ptr, toCString(params.url));
1162
1198
  },
1163
1199
  webviewTagUpdateHtml: (params) => {
1164
- const webview = BrowserView.getById(params.id);
1165
- webview.loadHTML(params.html)
1200
+ const webview = BrowserView.getById(params.id);
1201
+ if (!webview || !webview.ptr) {
1202
+ console.error(`webviewTagUpdateHtml: BrowserView not found or has no ptr for id ${params.id}`);
1203
+ return;
1204
+ }
1205
+ webview.loadHTML(params.html);
1166
1206
  webview.html = params.html;
1167
-
1168
1207
  },
1169
1208
  webviewTagUpdatePreload: (params) => {
1170
1209
  const webview = BrowserView.getById(params.id);
1210
+ if (!webview || !webview.ptr) {
1211
+ console.error(`webviewTagUpdatePreload: BrowserView not found or has no ptr for id ${params.id}`);
1212
+ return;
1213
+ }
1171
1214
  native.symbols.updatePreloadScriptToWebView(webview.ptr, toCString('electrobun_custom_preload_script'), toCString(params.preload), true);
1172
1215
  },
1173
1216
  webviewTagGoBack: (params) => {
1174
1217
  const webview = BrowserView.getById(params.id);
1218
+ if (!webview || !webview.ptr) {
1219
+ console.error(`webviewTagGoBack: BrowserView not found or has no ptr for id ${params.id}`);
1220
+ return;
1221
+ }
1175
1222
  native.symbols.webviewGoBack(webview.ptr);
1176
1223
  },
1177
1224
  webviewTagGoForward: (params) => {
1178
1225
  const webview = BrowserView.getById(params.id);
1226
+ if (!webview || !webview.ptr) {
1227
+ console.error(`webviewTagGoForward: BrowserView not found or has no ptr for id ${params.id}`);
1228
+ return;
1229
+ }
1179
1230
  native.symbols.webviewGoForward(webview.ptr);
1180
1231
  },
1181
1232
  webviewTagReload: (params) => {
1182
1233
  const webview = BrowserView.getById(params.id);
1234
+ if (!webview || !webview.ptr) {
1235
+ console.error(`webviewTagReload: BrowserView not found or has no ptr for id ${params.id}`);
1236
+ return;
1237
+ }
1183
1238
  native.symbols.webviewReload(webview.ptr);
1184
1239
  },
1185
1240
  webviewTagRemove: (params) => {
1186
1241
  const webview = BrowserView.getById(params.id);
1242
+ if (!webview || !webview.ptr) {
1243
+ console.error(`webviewTagRemove: BrowserView not found or has no ptr for id ${params.id}`);
1244
+ return;
1245
+ }
1187
1246
  native.symbols.webviewRemove(webview.ptr);
1188
1247
  },
1189
1248
  startWindowMove: (params) => {
@@ -1195,14 +1254,26 @@ export const internalRpcHandlers = {
1195
1254
  },
1196
1255
  webviewTagSetTransparent: (params) => {
1197
1256
  const webview = BrowserView.getById(params.id);
1257
+ if (!webview || !webview.ptr) {
1258
+ console.error(`webviewTagSetTransparent: BrowserView not found or has no ptr for id ${params.id}`);
1259
+ return;
1260
+ }
1198
1261
  native.symbols.webviewSetTransparent(webview.ptr, params.transparent);
1199
1262
  },
1200
1263
  webviewTagSetPassthrough: (params) => {
1201
1264
  const webview = BrowserView.getById(params.id);
1265
+ if (!webview || !webview.ptr) {
1266
+ console.error(`webviewTagSetPassthrough: BrowserView not found or has no ptr for id ${params.id}`);
1267
+ return;
1268
+ }
1202
1269
  native.symbols.webviewSetPassthrough(webview.ptr, params.enablePassthrough);
1203
1270
  },
1204
1271
  webviewTagSetHidden: (params) => {
1205
1272
  const webview = BrowserView.getById(params.id);
1273
+ if (!webview || !webview.ptr) {
1274
+ console.error(`webviewTagSetHidden: BrowserView not found or has no ptr for id ${params.id}`);
1275
+ return;
1276
+ }
1206
1277
  native.symbols.webviewSetHidden(webview.ptr, params.hidden);
1207
1278
  },
1208
1279
  webviewEvent: (params) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "electrobun",
3
- "version": "0.0.19-beta.118",
3
+ "version": "0.0.19-beta.119",
4
4
  "description": "Build ultra fast, tiny, and cross-platform desktop apps with Typescript.",
5
5
  "license": "MIT",
6
6
  "author": "Blackboard Technologies Inc.",
@@ -36,6 +36,7 @@
36
36
  "dev:playground:clean": "cd playground && rm -rf node_modules && npm install && cd .. && bun dev:playground",
37
37
  "dev:playground:rerun": "cd playground && bun start",
38
38
  "dev:playground:canary": "bun build:release && cd playground && npm install && bun build:canary && bun start:canary",
39
+ "run:playground": "bun build:dev && bun build:cli && cd templates/interactive-playground && npm install && bun build:dev && bun start",
39
40
  "dev:docs": "cd documentation && bun start",
40
41
  "build:docs:release": "cd documentation && bun run build",
41
42
  "npm:publish": "bun build:release && npm publish",
@@ -45,7 +46,8 @@
45
46
  "push:patch": "npm version patch && git push origin main --tags",
46
47
  "push:minor": "npm version minor && git push origin main --tags",
47
48
  "push:major": "npm version major && git push origin main --tags",
48
- "build:push:artifacts": "bun scripts/build-and-upload-artifacts.js"
49
+ "build:push:artifacts": "bun scripts/build-and-upload-artifacts.js",
50
+ "test": "bun build:dev && bun build:cli && cd tests && npm install && bun build:dev && bun start"
49
51
  },
50
52
  "devDependencies": {
51
53
  "@types/archiver": "^6.0.3",
package/src/cli/index.ts CHANGED
@@ -30,8 +30,12 @@ const MAX_CHUNK_SIZE = 1024 * 2;
30
30
 
31
31
  // this when run as an npm script this will be where the folder where package.json is.
32
32
  const projectRoot = process.cwd();
33
- const configName = "electrobun.config";
34
- const configPath = join(projectRoot, configName);
33
+
34
+ // Find TypeScript ESM config file
35
+ function findConfigFile(): string | null {
36
+ const configFile = join(projectRoot, 'electrobun.config.ts');
37
+ return existsSync(configFile) ? configFile : null;
38
+ }
35
39
 
36
40
  // Note: cli args can be called via npm bun /path/to/electorbun/binary arg1 arg2
37
41
  const indexOfElectrobun = process.argv.findIndex((arg) =>
@@ -440,19 +444,21 @@ if (!command) {
440
444
  process.exit(1);
441
445
  }
442
446
 
443
- const config = getConfig();
447
+ // Main execution function
448
+ async function main() {
449
+ const config = await getConfig();
444
450
 
445
- const envArg =
446
- process.argv.find((arg) => arg.startsWith("--env="))?.split("=")[1] || "";
451
+ const envArg =
452
+ process.argv.find((arg) => arg.startsWith("--env="))?.split("=")[1] || "";
447
453
 
448
- const targetsArg =
449
- process.argv.find((arg) => arg.startsWith("--targets="))?.split("=")[1] || "";
454
+ const targetsArg =
455
+ process.argv.find((arg) => arg.startsWith("--targets="))?.split("=")[1] || "";
450
456
 
451
- const validEnvironments = ["dev", "canary", "stable"];
457
+ const validEnvironments = ["dev", "canary", "stable"];
452
458
 
453
- // todo (yoav): dev, canary, and stable;
454
- const buildEnvironment: "dev" | "canary" | "stable" =
455
- validEnvironments.includes(envArg || "dev") ? (envArg || "dev") : "dev";
459
+ // todo (yoav): dev, canary, and stable;
460
+ const buildEnvironment: "dev" | "canary" | "stable" =
461
+ validEnvironments.includes(envArg || "dev") ? (envArg || "dev") : "dev";
456
462
 
457
463
  // Determine build targets
458
464
  type BuildTarget = { os: 'macos' | 'win' | 'linux', arch: 'arm64' | 'x64' };
@@ -1893,15 +1899,27 @@ exec "\$LAUNCHER_BINARY" "\$@"
1893
1899
 
1894
1900
  }
1895
1901
 
1896
- function getConfig() {
1902
+ async function getConfig() {
1897
1903
  let loadedConfig = {};
1898
- if (existsSync(configPath)) {
1899
- const configFileContents = readFileSync(configPath, "utf8");
1900
- // Note: we want this to hard fail if there's a syntax error
1904
+ const foundConfigPath = findConfigFile();
1905
+
1906
+ if (foundConfigPath) {
1907
+ console.log(`Using config file: ${basename(foundConfigPath)}`);
1908
+
1901
1909
  try {
1902
- loadedConfig = JSON.parse(configFileContents);
1910
+ // Use dynamic import for TypeScript ESM files
1911
+ // Bun handles TypeScript natively, no transpilation needed
1912
+ const configModule = await import(foundConfigPath);
1913
+ loadedConfig = configModule.default || configModule;
1914
+
1915
+ // Validate that we got a valid config object
1916
+ if (!loadedConfig || typeof loadedConfig !== 'object') {
1917
+ console.error("Config file must export a default object");
1918
+ console.error("using default config instead");
1919
+ loadedConfig = {};
1920
+ }
1903
1921
  } catch (error) {
1904
- console.error("Failed to parse config file:", error);
1922
+ console.error("Failed to load config file:", error);
1905
1923
  console.error("using default config instead");
1906
1924
  }
1907
1925
  }
@@ -2606,3 +2624,11 @@ function createAppBundle(bundleName: string, parentFolder: string, targetOS: 'ma
2606
2624
  throw new Error(`Unsupported OS: ${targetOS}`);
2607
2625
  }
2608
2626
  }
2627
+
2628
+ } // End of main() function
2629
+
2630
+ // Run the main function
2631
+ main().catch((error) => {
2632
+ console.error('Fatal error:', error);
2633
+ process.exit(1);
2634
+ });
@@ -0,0 +1,28 @@
1
+ export default {
2
+ app: {
3
+ name: "hello-world",
4
+ identifier: "helloworld.electrobun.dev",
5
+ version: "0.0.1",
6
+ },
7
+ build: {
8
+ views: {
9
+ mainview: {
10
+ entrypoint: "src/mainview/index.ts",
11
+ external: [],
12
+ },
13
+ },
14
+ copy: {
15
+ "src/mainview/index.html": "views/mainview/index.html",
16
+ "src/mainview/index.css": "views/mainview/index.css",
17
+ },
18
+ mac: {
19
+ bundleCEF: false,
20
+ },
21
+ linux: {
22
+ bundleCEF: false,
23
+ },
24
+ win: {
25
+ bundleCEF: false,
26
+ },
27
+ },
28
+ };
@@ -8,7 +8,7 @@
8
8
  "start": "bun run build && bun run dev"
9
9
  },
10
10
  "dependencies": {
11
- "electrobun": "^0.0.19-beta.115"
11
+ "electrobun": "latest"
12
12
  },
13
13
  "devDependencies": {
14
14
  "@types/bun": "latest"