nexfep 0.4.4 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -37,13 +37,13 @@ pnpm add nexfep
37
37
  ## Quick Start
38
38
 
39
39
  ```typescript
40
- import { Application } from 'nexfep';
40
+ import { Application } from "nexfep";
41
41
 
42
42
  const app = new Application();
43
43
 
44
44
  const window = await app.windows.createWindow(true, false);
45
45
 
46
- await window.loadHTML('<h1 nexfep-area-drag>Hello Nexfep!</h1>');
46
+ await window.loadHTML("<h1 nexfep-area-drag>Hello Nexfep!</h1>");
47
47
  ```
48
48
 
49
49
  ## Usage Guide
@@ -53,21 +53,21 @@ await window.loadHTML('<h1 nexfep-area-drag>Hello Nexfep!</h1>');
53
53
  `Application` is the main entry point of the framework, responsible for managing the application lifecycle and providing access to windows, system tray, and logger.
54
54
 
55
55
  ```typescript
56
- import { Application } from 'nexfep';
56
+ import { Application } from "nexfep";
57
57
 
58
58
  const app = new Application();
59
59
  // or with custom WebView2 user data directory (Windows only)
60
- const app = new Application({ WindowsWebview2UserDataFolder: 'C:\\custom\\webview2-data' });
60
+ const app = new Application({ WindowsWebview2UserDataFolder: "C:\\custom\\webview2-data" });
61
61
  // or with log file path
62
- const app = new Application({ LogFilePath: './app.log' });
62
+ const app = new Application({ LogFilePath: "./app.log" });
63
63
  ```
64
64
 
65
65
  **Constructor Options**
66
66
 
67
- | Option | Type | Default | Description |
68
- |--------|------|---------|-------------|
67
+ | Option | Type | Default | Description |
68
+ | ------------------------------- | ------------------- | ------------------------------------------------ | ------------------------------------------- |
69
69
  | `WindowsWebview2UserDataFolder` | `string` (optional) | `%LOCALAPPDATA%\NexfepDevelopment.webview2-data` | WebView2 user data directory (Windows only) |
70
- | `LogFilePath` | `string` (optional) | none | File path for log output |
70
+ | `LogFilePath` | `string` (optional) | none | File path for log output |
71
71
 
72
72
  **Properties**
73
73
 
@@ -78,6 +78,7 @@ const app = new Application({ LogFilePath: './app.log' });
78
78
  **Methods**
79
79
 
80
80
  - `createTray(options)` — Create a system tray icon with context menu
81
+ - `createLocker(appName)` — Create an application instance lock to prevent multiple instances
81
82
  - `exit()` — Exit the application
82
83
 
83
84
  ### Logger
@@ -85,22 +86,22 @@ const app = new Application({ LogFilePath: './app.log' });
85
86
  The logger supports both file output and colored console output. It can be accessed via `app.logger`.
86
87
 
87
88
  ```typescript
88
- app.logger.log('Hello World');
89
- app.logger.error('An error occurred');
90
- app.logger.warn('Warning message');
91
- app.logger.info('Info message');
92
- app.logger.debug('Debug message');
89
+ app.logger.log("Hello World");
90
+ app.logger.error("An error occurred");
91
+ app.logger.warn("Warning message");
92
+ app.logger.info("Info message");
93
+ app.logger.debug("Debug message");
93
94
  ```
94
95
 
95
96
  **Methods**
96
97
 
97
- | Method | Description |
98
- |--------|-------------|
99
- | `log(message)` | Log a message |
100
- | `error(message)` | Log an error message (red) |
101
- | `warn(message)` | Log a warning message (yellow) |
102
- | `info(message)` | Log an info message (blue) |
103
- | `debug(message)` | Log a debug message (gray) |
98
+ | Method | Description |
99
+ | ---------------- | ------------------------------ |
100
+ | `log(message)` | Log a message |
101
+ | `error(message)` | Log an error message (red) |
102
+ | `warn(message)` | Log a warning message (yellow) |
103
+ | `info(message)` | Log an info message (blue) |
104
+ | `debug(message)` | Log a debug message (gray) |
104
105
 
105
106
  Each method accepts either a string or an array of strings.
106
107
 
@@ -108,24 +109,53 @@ Each method accepts either a string or an array of strings.
108
109
 
109
110
  Console calls (`console.log`, `console.error`, `console.info`, `console.warn`, `console.debug`) in the page are automatically intercepted and forwarded to the main process logger, with the source window ID included in the output.
110
111
 
112
+ ### Locker
113
+
114
+ `Locker` is a class for managing application instance locks, preventing multiple instances from running simultaneously.
115
+
116
+ ```typescript
117
+ const locker = app.createLocker("my-app");
118
+ try {
119
+ // Try to acquire the lock
120
+ await locker.lock();
121
+ } catch {
122
+ // Instance already exists, exit the application
123
+ app.exit();
124
+ }
125
+ // Focus the current instance when other instances acquire the lock
126
+ locker.whenLost(() => {
127
+ if (!win.isFocused()) {
128
+ win.focus();
129
+ }
130
+ });
131
+ // Release the lock
132
+ locker.unlock();
133
+ ```
134
+
135
+ **Methods**
136
+
137
+ - `lock()` — Try to acquire the lock
138
+ - `whenLost(callback)` — Register a callback to be called when other instances acquire the lock
139
+ - `unlock()` — Release the lock
140
+
111
141
  ### Tray
112
142
 
113
143
  Create and manage system tray icons with context menus via `app.createTray()`.
114
144
 
115
145
  ```typescript
116
- import { readFileSync } from 'fs';
146
+ import { readFileSync } from "fs";
117
147
 
118
148
  const tray = app.createTray({
119
- id: 'my-tray',
120
- tooltip: 'My App',
149
+ id: "my-tray",
150
+ tooltip: "My App",
121
151
  icon: {
122
- data: readFileSync('./icon.png'),
152
+ data: readFileSync("./icon.png"),
123
153
  width: 32,
124
154
  height: 32,
125
155
  },
126
156
  menuItems: [
127
- { id: 'show', label: 'Show Window' },
128
- { id: 'quit', label: 'Quit' },
157
+ { id: "show", label: "Show Window" },
158
+ { id: "quit", label: "Quit" },
129
159
  ],
130
160
  });
131
161
  ```
@@ -134,32 +164,32 @@ The `icon` field accepts a `TrayIconImage` object:
134
164
 
135
165
  ```typescript
136
166
  interface TrayIconImage {
137
- data: Buffer; // Image binary data
138
- width?: number; // Optional width
139
- height?: number; // Optional height
167
+ data: Buffer; // Image binary data
168
+ width?: number; // Optional width
169
+ height?: number; // Optional height
140
170
  }
141
171
  ```
142
172
 
143
173
  **Methods**
144
174
 
145
- | Method | Description |
146
- |---------------------------------------------|-------------------------------------|
147
- | `addMenuItem(item)` | Add a menu item |
148
- | `removeMenuItem(id)` | Remove a menu item by ID |
149
- | `setMenuItems(items)` | Replace all menu items |
150
- | `setIcon(icon, width?, height?)` | Change the tray icon (raw pixel data as `Uint8Array` / `number[]`) |
151
- | `setTooltip(tooltip)` | Change the tooltip text |
152
- | `on(event, callback)` | Listen for tray events (e.g. `'click'`) |
153
- | `show()` | Show the tray icon |
154
- | `hide()` | Hide the tray icon |
155
- | `destroy()` | Destroy the tray icon |
175
+ | Method | Description |
176
+ | -------------------------------- | ------------------------------------------------------------------ |
177
+ | `addMenuItem(item)` | Add a menu item |
178
+ | `removeMenuItem(id)` | Remove a menu item by ID |
179
+ | `setMenuItems(items)` | Replace all menu items |
180
+ | `setIcon(icon, width?, height?)` | Change the tray icon (raw pixel data as `Uint8Array` / `number[]`) |
181
+ | `setTooltip(tooltip)` | Change the tooltip text |
182
+ | `on(event, callback)` | Listen for tray events (e.g. `'click'`) |
183
+ | `show()` | Show the tray icon |
184
+ | `hide()` | Hide the tray icon |
185
+ | `destroy()` | Destroy the tray icon |
156
186
 
157
187
  ```typescript
158
- tray.on('click', () => {
159
- console.log('Tray clicked');
188
+ tray.on("click", () => {
189
+ console.log("Tray clicked");
160
190
  });
161
- tray.addMenuItem({ id: 'about', label: 'About' });
162
- tray.setTooltip('Nexfep App');
191
+ tray.addMenuItem({ id: "about", label: "About" });
192
+ tray.setTooltip("Nexfep App");
163
193
  ```
164
194
 
165
195
  ### Notifications
@@ -167,7 +197,7 @@ tray.setTooltip('Nexfep App');
167
197
  Send desktop notifications via `app.utils.notify()`.
168
198
 
169
199
  ```typescript
170
- const notification = app.utils.notify('Title', 'Notification body');
200
+ const notification = app.utils.notify("Title", "Notification body");
171
201
  ```
172
202
 
173
203
  **Parameters**
@@ -202,7 +232,8 @@ window.hide();
202
232
  window.maximize();
203
233
  window.minimize();
204
234
  window.close();
205
- window.setTitle('New Title');
235
+ window.focus();
236
+ window.setTitle("New Title");
206
237
  window.setSize(800, 600);
207
238
  window.openDevTools();
208
239
  ```
@@ -214,7 +245,7 @@ window.openDevTools();
214
245
  Send messages via `window.postMessage` in the page:
215
246
 
216
247
  ```javascript
217
- window.postMessage({ hello: 'world' });
248
+ window.postMessage({ hello: "world" });
218
249
  ```
219
250
 
220
251
  **Parameters**
@@ -243,8 +274,8 @@ pool.onCustomMessage = (window, data) => {
243
274
  Invoke events via `window.invoke` in the page:
244
275
 
245
276
  ```javascript
246
- window.invoke('hello');
247
- window.invoke('hello', 'world');
277
+ window.invoke("hello");
278
+ window.invoke("hello", "world");
248
279
  ```
249
280
 
250
281
  **Parameters**
@@ -257,8 +288,8 @@ window.invoke('hello', 'world');
257
288
  Listen for events via `pool.handle` in the main process:
258
289
 
259
290
  ```typescript
260
- pool.handle('hello', (data) => {
261
- console.log('Received event hello:', data);
291
+ pool.handle("hello", (data) => {
292
+ console.log("Received event hello:", data);
262
293
  });
263
294
  ```
264
295
 
@@ -272,8 +303,8 @@ pool.handle('hello', (data) => {
272
303
  Remove event listener via `pool.unhandle` in the main process:
273
304
 
274
305
  ```typescript
275
- pool.unhandle('hello', (data) => {
276
- console.log('Received event hello:', data);
306
+ pool.unhandle("hello", (data) => {
307
+ console.log("Received event hello:", data);
277
308
  });
278
309
  ```
279
310
 
@@ -289,7 +320,7 @@ pool.unhandle('hello', (data) => {
289
320
  Set a global variable via `window.setGlobal` in the page:
290
321
 
291
322
  ```javascript
292
- window.setGlobal('hello', 'world');
323
+ window.setGlobal("hello", "world");
293
324
  ```
294
325
 
295
326
  **Parameters**
@@ -302,7 +333,7 @@ window.setGlobal('hello', 'world');
302
333
  Get a global variable via `window.getGlobal` in the page:
303
334
 
304
335
  ```javascript
305
- const value = await window.getGlobal('hello');
336
+ const value = await window.getGlobal("hello");
306
337
  ```
307
338
 
308
339
  **Parameters**
@@ -315,8 +346,8 @@ Get a `Map<string, any>` containing all global variables via `pool.global` in th
315
346
 
316
347
  ```typescript
317
348
  const globals = pool.global;
318
- globals.set('hello', 'world');
319
- const value = globals.get('hello');
349
+ globals.set("hello", "world");
350
+ const value = globals.get("hello");
320
351
  ```
321
352
 
322
353
  ### Inter-Window Communication
@@ -328,7 +359,7 @@ The framework supports direct communication between windows via `window.broadcas
328
359
  Send an event to all other open windows via `window.broadcast`:
329
360
 
330
361
  ```javascript
331
- window.broadcast('user-login', { userId: 123 });
362
+ window.broadcast("user-login", { userId: 123 });
332
363
  ```
333
364
 
334
365
  **Parameters**
@@ -339,8 +370,8 @@ window.broadcast('user-login', { userId: 123 });
339
370
  Other windows listen for the broadcast event via `window.addEventListener`:
340
371
 
341
372
  ```javascript
342
- window.addEventListener('user-login', (event) => {
343
- console.log('User logged in:', event.detail);
373
+ window.addEventListener("user-login", (event) => {
374
+ console.log("User logged in:", event.detail);
344
375
  });
345
376
  ```
346
377
 
@@ -349,7 +380,7 @@ window.addEventListener('user-login', (event) => {
349
380
  Send a message to a specific window by its ID via `window.tell`:
350
381
 
351
382
  ```javascript
352
- window.tell(2, 'custom-message', { text: 'Hello Window 2' });
383
+ window.tell(2, "custom-message", { text: "Hello Window 2" });
353
384
  ```
354
385
 
355
386
  **Parameters**
@@ -361,15 +392,15 @@ window.tell(2, 'custom-message', { text: 'Hello Window 2' });
361
392
  The target window receives the message via `window.addEventListener`:
362
393
 
363
394
  ```javascript
364
- window.addEventListener('custom-message', (event) => {
365
- console.log('Received message:', event.detail);
395
+ window.addEventListener("custom-message", (event) => {
396
+ console.log("Received message:", event.detail);
366
397
  });
367
398
  ```
368
399
 
369
400
  Each window's ID can be accessed via `window.id`:
370
401
 
371
402
  ```javascript
372
- console.log('This window ID:', window.id);
403
+ console.log("This window ID:", window.id);
373
404
  ```
374
405
 
375
406
  ### Window Control Functions
@@ -377,21 +408,21 @@ console.log('This window ID:', window.id);
377
408
  The following injected functions can be directly called in the page for window control:
378
409
 
379
410
  ```javascript
380
- window.close(); // Close window
381
- window.minimize(); // Minimize window
382
- window.unminimize(); // Restore minimized window
383
- window.maximize(); // Maximize window
384
- window.unmaximize(); // Restore maximized window
385
- window.setTitle('Title'); // Set window title
386
- window.openDevTools(); // Open developer tools
387
- window.closeDevTools(); // Close developer tools
411
+ window.close(); // Close window
412
+ window.minimize(); // Minimize window
413
+ window.unminimize(); // Restore minimized window
414
+ window.maximize(); // Maximize window
415
+ window.unmaximize(); // Restore maximized window
416
+ window.setTitle("Title"); // Set window title
417
+ window.openDevTools(); // Open developer tools
418
+ window.closeDevTools(); // Close developer tools
388
419
  ```
389
420
 
390
421
  The following properties are also available in the page:
391
422
 
392
423
  ```javascript
393
- console.log(window.id); // Window unique identifier
394
- console.log(window.isNexfepLoadDone); // Whether the window has finished loading
424
+ console.log(window.id); // Window unique identifier
425
+ console.log(window.isNexfepLoadDone); // Whether the window has finished loading
395
426
  ```
396
427
 
397
428
  ### Drag Regions
@@ -449,8 +480,8 @@ Automatically determines drag regions: the entire region is draggable, but commo
449
480
  The `nexfep-load-done` event is triggered after the WebView window finishes loading:
450
481
 
451
482
  ```javascript
452
- window.addEventListener('nexfep-load-done', () => {
453
- console.log('Nexfep window loaded');
483
+ window.addEventListener("nexfep-load-done", () => {
484
+ console.log("Nexfep window loaded");
454
485
  });
455
486
  ```
456
487
 
@@ -484,17 +515,17 @@ npx nexfep build [options]
484
515
 
485
516
  #### Options
486
517
 
487
- | Option | Description |
488
- |--------|-------------|
489
- | `-n, --name <name>` | Application name (default: from package.json) |
490
- | `-e, --entry <file>` | Entry file path (default: from package.json main) |
491
- | `-o, --output <dir>` | Output directory (default: dist) |
492
- | `-i, --ignore <pattern>` | Files or directories to ignore (can be used multiple times) |
493
- | `-c, --console` | Show console window on Windows (default: false) |
494
- | `-r, --reinstall` | Reinstall production dependencies only before building |
495
- | `-s, --skip-clean` | Skip cleaning old build files before building |
496
- | `-u, --upx <level>` | Use UPX to compress the executable, level 0-9 (default: 0) |
497
- | `-m, --meta, --metadata <file>` | Metadata file path (default: none) |
518
+ | Option | Description |
519
+ | ------------------------------- | ----------------------------------------------------------- |
520
+ | `-n, --name <name>` | Application name (default: from package.json) |
521
+ | `-e, --entry <file>` | Entry file path (default: from package.json main) |
522
+ | `-o, --output <dir>` | Output directory (default: dist) |
523
+ | `-i, --ignore <pattern>` | Files or directories to ignore (can be used multiple times) |
524
+ | `-c, --console` | Show console window on Windows (default: false) |
525
+ | `-r, --reinstall` | Reinstall production dependencies only before building |
526
+ | `-s, --skip-clean` | Skip cleaning old build files before building |
527
+ | `-u, --upx <level>` | Use UPX to compress the executable, level 0-9 (default: 0) |
528
+ | `-m, --meta, --metadata <file>` | Metadata file path (default: none) |
498
529
 
499
530
  #### Examples
500
531
 
@@ -529,46 +560,55 @@ Please do not include the outer `metadata` field, just the internal fields. Like
529
560
 
530
561
  ### Application
531
562
 
532
- | Method/Property | Parameters | Return Value | Description |
533
- |----------------|-----------|--------------|-------------|
534
- | `constructor(options?)` | `{ WindowsWebview2UserDataFolder?, LogFilePath? }` | Application | Creates the application instance |
535
- | `windows` | / | WindowPool | The window pool instance |
536
- | `utils` | / | \_\_Utils | Utility methods (notifications) |
537
- | `logger` | / | Logger | The logger instance |
538
- | `createTray(options)` | see Tray section | Tray | Creates a system tray icon |
539
- | `exit()` | None | void | Exits the application |
563
+ | Method/Property | Parameters | Return Value | Description |
564
+ | ----------------------- | -------------------------------------------------- | ------------ | -------------------------------- |
565
+ | `constructor(options?)` | `{ WindowsWebview2UserDataFolder?, LogFilePath? }` | Application | Creates the application instance |
566
+ | `windows` | / | WindowPool | The window pool instance |
567
+ | `utils` | / | \_\_Utils | Utility methods (notifications) |
568
+ | `logger` | / | Logger | The logger instance |
569
+ | `createTray(options)` | see Tray section | Tray | Creates a system tray icon |
570
+ | `exit()` | None | void | Exits the application |
540
571
 
541
572
  ### WindowPool
542
573
 
543
- | Method/Property | Parameters | Return Value | Description |
544
- |----------------|-----------|--------------|-------------|
545
- | `createWindow(isShow?, isDecorated?)` | `isShow`: boolean (default true), `isDecorated`: boolean (default true) | Promise\<Window> | Creates and returns a window |
546
- | `handle(event, callback)` | `event`: string, `callback`: (data: any) => any | None | Listens for the specified event |
547
- | `unhandle(event, callback)` | `event`: string, `callback`: (data: any) => any | None | Removes the specified event listener |
548
- | `global` | / | Map\<string, any> | A global variable map |
549
- | `closeWindow(window)` | `window`: Window | Promise\<void> | Closes the specified window and returns it to the pool |
550
- | `onCustomMessage` | `(window: Window, data: string) => void` | None | Custom message callback |
574
+ | Method/Property | Parameters | Return Value | Description |
575
+ | ------------------------------------- | ----------------------------------------------------------------------- | ----------------- | ------------------------------------------------------ |
576
+ | `createWindow(isShow?, isDecorated?)` | `isShow`: boolean (default true), `isDecorated`: boolean (default true) | Promise\<Window> | Creates and returns a window |
577
+ | `handle(event, callback)` | `event`: string, `callback`: (data: any) => any | None | Listens for the specified event |
578
+ | `unhandle(event, callback)` | `event`: string, `callback`: (data: any) => any | None | Removes the specified event listener |
579
+ | `global` | / | Map\<string, any> | A global variable map |
580
+ | `closeWindow(window)` | `window`: Window | Promise\<void> | Closes the specified window and returns it to the pool |
581
+ | `onCustomMessage` | `(window: Window, data: string) => void` | None | Custom message callback |
551
582
 
552
583
  ### Window
553
584
 
554
- | Method/Property | Parameters | Return Value | Description |
555
- |----------------|-----------|--------------|-------------|
556
- | `loadURL(url)` | `url`: string — URL to load | Promise\<void> | Loads the specified URL |
557
- | `loadHTML(html)` | `html`: string — HTML string | Promise\<void> | Loads the specified HTML content |
558
- | `show()` | None | void | Shows the window |
559
- | `hide()` | None | void | Hides the window |
560
- | `maximize()` | None | void | Maximizes the window |
561
- | `unMaximize()` | None | void | Restores the window (cancels maximize) |
562
- | `minimize()` | None | void | Minimizes the window |
563
- | `unMinimize()` | None | void | Restores the window (cancels minimize) |
564
- | `close()` | None | void | Closes the window and returns to pool |
565
- | `setTitle(title)` | `title`: string | void | Sets the window title |
566
- | `setDecorated(isDecorated)` | `isDecorated`: boolean | void | Sets whether the window has borders and title bar |
567
- | `resizable(resizable)` | `resizable`: boolean | void | Sets whether the window is resizable |
568
- | `setSize(width, height)` | `width`: number, `height`: number | void | Sets the window size in pixels |
569
- | `openDevTools()` | None | void | Opens developer tools |
570
- | `closeDevTools()` | None | void | Closes developer tools |
571
- | `id` | None | number | Unique window identifier, auto-incrementing |
585
+ | Method/Property | Parameters | Return Value | Description |
586
+ | --------------------------- | --------------------------------- | --------------------------------- | ------------------------------------------------- |
587
+ | `loadURL(url)` | `url`: string — URL to load | Promise\<void> | Loads the specified URL |
588
+ | `loadHTML(html)` | `html`: string — HTML string | Promise\<void> | Loads the specified HTML content |
589
+ | `show()` | None | void | Shows the window |
590
+ | `hide()` | None | void | Hides the window |
591
+ | `maximize()` | None | void | Maximizes the window |
592
+ | `unMaximize()` | None | void | Restores the window (cancels maximize) |
593
+ | `minimize()` | None | void | Minimizes the window |
594
+ | `unMinimize()` | None | void | Restores the window (cancels minimize) |
595
+ | `close()` | None | void | Closes the window and returns to pool |
596
+ | `setTitle(title)` | `title`: string | void | Sets the window title |
597
+ | `setDecorated(isDecorated)` | `isDecorated`: boolean | void | Sets whether the window has borders and title bar |
598
+ | `resizable(resizable)` | `resizable`: boolean | void | Sets whether the window is resizable |
599
+ | `setSize(width, height)` | `width`: number, `height`: number | void | Sets the window size in pixels |
600
+ | `getSize()` | None | { width: number, height: number } | Gets the window size in pixels |
601
+ | `setPosition(x, y)` | `x`: number, `y`: number | void | Sets the window position in pixels |
602
+ | `getPosition()` | None | { x: number, y: number } | Gets the window position in pixels |
603
+ | `isMaximized()` | None | boolean | Whether the window is maximized |
604
+ | `isMinimized()` | None | boolean | Whether the window is minimized |
605
+ | `toggleMaximize()` | None | void | Toggles the window maximized state |
606
+ | `toggleMinimize()` | None | void | Toggles the window minimized state |
607
+ | `isFocused()` | None | boolean | Whether the window has focused |
608
+ | `focus()` | None | void | Focuses the window |
609
+ | `openDevTools()` | None | void | Opens developer tools |
610
+ | `closeDevTools()` | None | void | Closes developer tools |
611
+ | `id` | None | number | Unique window identifier, auto-incrementing |
572
612
 
573
613
  ## Development
574
614