@nativewindow/webview 1.0.5 → 1.0.6

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 (3) hide show
  1. package/dist/index.d.ts +105 -243
  2. package/dist/index.js +37 -376
  3. package/package.json +9 -9
package/dist/index.d.ts CHANGED
@@ -1,5 +1,3 @@
1
- declare const checkRuntime: () => RuntimeInfo, ensureRuntime: () => RuntimeInfo, loadHtmlOrigin: () => string;
2
- export { checkRuntime, ensureRuntime, loadHtmlOrigin };
3
1
  /** Information about the native webview runtime. */
4
2
  export interface RuntimeInfo {
5
3
  /** Whether the webview runtime is available. */
@@ -9,6 +7,79 @@ export interface RuntimeInfo {
9
7
  /** The current platform: "macos", "windows", "linux", or "unsupported". */
10
8
  platform: "macos" | "windows" | "linux" | "unsupported";
11
9
  }
10
+ /**
11
+ * Information about a cookie from the native cookie store.
12
+ * Includes `HttpOnly` cookies that are invisible to `document.cookie`.
13
+ */
14
+ export interface CookieInfo {
15
+ /** Cookie name. */
16
+ name: string;
17
+ /** Cookie value. */
18
+ value: string;
19
+ /** Domain the cookie belongs to. */
20
+ domain: string;
21
+ /** Path the cookie is restricted to. */
22
+ path: string;
23
+ /** Whether the cookie is HttpOnly (inaccessible to JS). */
24
+ httpOnly: boolean;
25
+ /** Whether the cookie requires HTTPS. */
26
+ secure: boolean;
27
+ /** SameSite policy: "Strict", "Lax", "None", or null for unset. */
28
+ sameSite: string | null;
29
+ /** Expiry as Unix timestamp (seconds). Null for session cookies. */
30
+ expires: number | null;
31
+ }
32
+ /** @internal Constructor type for the raw native NativeWindow class. */
33
+ interface NativeWindowConstructor {
34
+ new (options?: WindowOptions): NativeWindowInstance;
35
+ }
36
+ /** @internal Instance type for the raw native NativeWindow class. */
37
+ interface NativeWindowInstance {
38
+ readonly id: number;
39
+ loadUrl(url: string): void;
40
+ loadHtml(html: string): void;
41
+ evaluateJs(script: string): void;
42
+ postMessage(message: string): void;
43
+ setTitle(title: string): void;
44
+ setSize(width: number, height: number): void;
45
+ setMinSize(width: number, height: number): void;
46
+ setMaxSize(width: number, height: number): void;
47
+ setPosition(x: number, y: number): void;
48
+ setResizable(resizable: boolean): void;
49
+ setDecorations(decorations: boolean): void;
50
+ setAlwaysOnTop(alwaysOnTop: boolean): void;
51
+ setIcon(path: string): void;
52
+ show(): void;
53
+ hide(): void;
54
+ close(): void;
55
+ focus(): void;
56
+ maximize(): void;
57
+ minimize(): void;
58
+ unmaximize(): void;
59
+ reload(): void;
60
+ onMessage(callback: (message: string, sourceUrl: string) => void): void;
61
+ onClose(callback: () => void): void;
62
+ onResize(callback: (width: number, height: number) => void): void;
63
+ onMove(callback: (x: number, y: number) => void): void;
64
+ onFocus(callback: () => void): void;
65
+ onBlur(callback: () => void): void;
66
+ onPageLoad(callback: (event: "started" | "finished", url: string) => void): void;
67
+ onTitleChanged(callback: (title: string) => void): void;
68
+ onReload(callback: () => void): void;
69
+ onNavigationBlocked(callback: (url: string) => void): void;
70
+ getCookies(url?: string): CookieInfo[];
71
+ clearCookies(host?: string): void;
72
+ openDevtools(): void;
73
+ closeDevtools(): void;
74
+ isDevtoolsOpen(): boolean;
75
+ }
76
+ /**
77
+ * Options for creating a new native window.
78
+ *
79
+ * Security: When loading untrusted content, use the `csp` field to restrict
80
+ * what the page can do. Without a CSP, loaded content can execute inline
81
+ * scripts and load resources from any origin.
82
+ */
12
83
  export interface WindowOptions {
13
84
  /** Window title. Default: "" */
14
85
  title?: string;
@@ -124,267 +195,58 @@ export interface WindowOptions {
124
195
  */
125
196
  incognito?: boolean;
126
197
  }
198
+ /** {@inheritDoc RuntimeInfo} */
199
+ export declare const checkRuntime: () => RuntimeInfo;
200
+ /** {@inheritDoc RuntimeInfo} */
201
+ export declare const ensureRuntime: () => RuntimeInfo;
127
202
  /**
128
- * Operations that execute arbitrary code in the webview context.
129
- * Grouped under {@link NativeWindow.unsafe} to signal injection risk.
203
+ * Returns the origin of pages loaded via `loadHtml()`.
204
+ *
205
+ * This is the origin string to use in `trustedOrigins` when restricting
206
+ * IPC messages to only accept messages from `loadHtml()` content.
130
207
  *
131
- * @security Never pass unsanitized user input to these methods.
132
- * Use {@link sanitizeForJs} to escape strings before embedding them in
133
- * script code.
208
+ * - macOS/Linux: `"nativewindow://localhost"`
209
+ * - Windows: `"https://nativewindow.localhost"`
134
210
  */
135
- export interface UnsafeNamespace {
136
- /**
137
- * Evaluate arbitrary JavaScript in the webview context.
138
- * Fire-and-forget — there is no return value.
139
- * Use `postMessage`/`onMessage` to send results back.
140
- *
141
- * @security **Injection risk.** Never pass unsanitized user input directly.
142
- * Use {@link sanitizeForJs} to escape strings before embedding them in
143
- * script code.
144
- */
145
- evaluateJs(script: string): void;
146
- }
211
+ export declare const loadHtmlOrigin: () => string;
147
212
  /**
148
- * Control the browser devtools panel for this window's webview.
149
- * Grouped under {@link NativeWindow.devtools} for discoverability.
213
+ * Escape a string for safe embedding inside a JavaScript string literal.
214
+ * Handles backslashes, double quotes, newlines, carriage returns, null
215
+ * bytes, closing `</script>` tags, Unicode line/paragraph separators
216
+ * (U+2028, U+2029), backticks, and `${` template expressions.
150
217
  *
151
- * Requires `devtools: true` in {@link WindowOptions} at window creation.
218
+ * Safe for use in double-quoted, single-quoted, and template literal
219
+ * contexts.
152
220
  *
153
221
  * @example
154
222
  * ```ts
155
- * const win = new NativeWindow({ devtools: true });
156
- * win.devtools.open();
157
- * console.log(win.devtools.isOpen()); // true
158
- * win.devtools.close();
159
- * ```
160
- */
161
- export interface DevtoolsNamespace {
162
- /** Open the browser devtools panel. */
163
- open(): void;
164
- /** Close the browser devtools panel. */
165
- close(): void;
166
- /** Check whether the devtools panel is currently open. */
167
- isOpen(): boolean;
168
- }
169
- /**
170
- * Information about a cookie from the native cookie store.
171
- * Includes `HttpOnly` cookies that are invisible to `document.cookie`.
223
+ * import { NativeWindow, sanitizeForJs } from "@nativewindow/webview";
172
224
  *
173
- * @example
174
- * ```ts
175
- * win.onCookies((cookies) => {
176
- * for (const c of cookies) {
177
- * console.log(c.name, c.value, c.httpOnly);
178
- * }
179
- * });
180
- * win.getCookies("https://example.com");
225
+ * const userInput = 'He said "hello"\n<script>alert(1)</script>';
226
+ * win.evaluateJs(`display("${sanitizeForJs(userInput)}")`);
181
227
  * ```
182
228
  */
183
- export interface CookieInfo {
184
- /** Cookie name. */
185
- name: string;
186
- /** Cookie value. */
187
- value: string;
188
- /** Domain the cookie belongs to. */
189
- domain: string;
190
- /** Path the cookie is restricted to. */
191
- path: string;
192
- /** Whether the cookie is HttpOnly (inaccessible to JS). */
193
- httpOnly: boolean;
194
- /** Whether the cookie requires HTTPS. */
195
- secure: boolean;
196
- /** SameSite policy: "none", "lax", or "strict". */
197
- sameSite: string;
198
- /** Expiry as Unix timestamp (seconds). -1 for session cookies. */
199
- expires: number;
200
- }
229
+ export declare const sanitizeForJs: (input: string) => string;
201
230
  /**
202
231
  * A native OS window with an embedded webview.
203
232
  *
204
233
  * Automatically initializes the native subsystem and starts pumping
205
234
  * events on first construction. Stops the pump when all windows close.
206
- */
207
- export declare class NativeWindow {
208
- /** @internal */
209
- private _native;
210
- /** @internal */
211
- private _closed;
212
- /** @internal */
213
- private _unsafe?;
214
- /** @internal */
215
- private _devtools?;
216
- constructor(options?: WindowOptions);
217
- /** @internal */
218
- private _handleClose;
219
- /**
220
- * Throws if the window has been closed.
221
- * @internal
222
- */
223
- private _ensureOpen;
224
- private _userCloseCallback?;
225
- /**
226
- * Register a handler for the window close event.
227
- * The pump is automatically stopped when all windows are closed.
228
- *
229
- * Calling this multiple times replaces the previous handler.
230
- */
231
- onClose(callback: () => void): void;
232
- /** Unique window ID */
233
- get id(): number;
234
- loadUrl(url: string): void;
235
- /**
236
- * Load raw HTML content into the webview.
237
- *
238
- * @security **Injection risk.** Never interpolate unsanitized user input
239
- * into HTML strings. Use a dedicated sanitization library such as
240
- * [DOMPurify](https://github.com/cure53/DOMPurify) or
241
- * [sanitize-html](https://github.com/apostrophecms/sanitize-html) to
242
- * sanitize untrusted content before embedding it.
243
- */
244
- loadHtml(html: string): void;
245
- postMessage(message: string): void;
246
- /**
247
- * Namespace for operations that require extra care to avoid injection risks.
248
- * Methods under `unsafe` execute arbitrary code in the webview context.
249
- *
250
- * @security Never pass unsanitized user input to these methods.
251
- * Use {@link sanitizeForJs} to escape strings before embedding them in
252
- * script code.
253
- */
254
- get unsafe(): UnsafeNamespace;
255
- /**
256
- * Namespace for controlling the browser devtools panel.
257
- * Requires `devtools: true` in {@link WindowOptions} at window creation.
258
- *
259
- * @example
260
- * ```ts
261
- * const win = new NativeWindow({ devtools: true });
262
- * win.devtools.open();
263
- * console.log(win.devtools.isOpen()); // true
264
- * win.devtools.close();
265
- * ```
266
- */
267
- get devtools(): DevtoolsNamespace;
268
- setTitle(title: string): void;
269
- setSize(width: number, height: number): void;
270
- setMinSize(width: number, height: number): void;
271
- setMaxSize(width: number, height: number): void;
272
- setPosition(x: number, y: number): void;
273
- setResizable(resizable: boolean): void;
274
- setDecorations(decorations: boolean): void;
275
- setAlwaysOnTop(alwaysOnTop: boolean): void;
276
- /**
277
- * Set the window icon from a PNG or ICO file path.
278
- * On macOS this is silently ignored (macOS doesn't support per-window icons).
279
- * Relative paths resolve from the working directory.
280
- */
281
- setIcon(path: string): void;
282
- show(): void;
283
- hide(): void;
284
- close(): void;
285
- focus(): void;
286
- maximize(): void;
287
- minimize(): void;
288
- unmaximize(): void;
289
- reload(): void;
290
- /**
291
- * Register a handler for messages from the webview.
292
- *
293
- * @security **No origin filtering.** The raw `onMessage` API does not
294
- * enforce origin restrictions. If your webview navigates to untrusted
295
- * URLs, validate the `sourceUrl` parameter before processing messages.
296
- * For automatic origin filtering, use `createChannel()` with the
297
- * `trustedOrigins` option from `native-window-ipc`.
298
- *
299
- * @security **No rate limiting.** Messages from the webview are delivered
300
- * without throttling. A malicious page can flood the host with messages.
301
- * Consider implementing application-level rate limiting if loading
302
- * untrusted content.
303
- */
304
- onMessage(callback: (message: string, sourceUrl: string) => void): void;
305
- onResize(callback: (width: number, height: number) => void): void;
306
- onMove(callback: (x: number, y: number) => void): void;
307
- onFocus(callback: () => void): void;
308
- onBlur(callback: () => void): void;
309
- onPageLoad(callback: (event: "started" | "finished", url: string) => void): void;
310
- onTitleChanged(callback: (title: string) => void): void;
311
- onReload(callback: () => void): void;
312
- /**
313
- * Register a handler for blocked navigation events.
314
- * Fired when a navigation is blocked by the {@link WindowOptions.allowedHosts}
315
- * restriction. Receives the URL that was blocked.
316
- *
317
- * @example
318
- * ```ts
319
- * win.onNavigationBlocked((url) => {
320
- * console.log("Blocked navigation to:", url);
321
- * });
322
- * ```
323
- */
324
- onNavigationBlocked(callback: (url: string) => void): void;
325
- /**
326
- * Validate and parse a raw cookies JSON array from the native layer.
327
- * Returns a cleaned {@link CookieInfo} array or `null` if the payload
328
- * is malformed.
329
- *
330
- * @internal
331
- */
332
- private _validateCookies;
333
- /**
334
- * Query cookies from the native cookie store.
335
- *
336
- * Returns a Promise that resolves with validated {@link CookieInfo} objects,
337
- * including `HttpOnly` cookies that are invisible to `document.cookie`.
338
- *
339
- * - **macOS**: Uses `WKHTTPCookieStore.getAllCookies` with client-side
340
- * URL filtering (domain + path match).
341
- * - **Windows**: Uses `ICoreWebView2CookieManager.GetCookies` which
342
- * filters by URI natively.
343
- *
344
- * @param url If provided, only cookies matching this URL are returned.
345
- * If omitted, all cookies in the webview's cookie store are returned.
346
- *
347
- * @example
348
- * ```ts
349
- * const cookies = await win.getCookies("https://example.com");
350
- * const session = cookies.find((c) => c.name === "session_id");
351
- * if (session) console.log("Session:", session.value, "HttpOnly:", session.httpOnly);
352
- * ```
353
- */
354
- getCookies(url?: string): Promise<CookieInfo[]>;
355
- /**
356
- * Clear cookies from the native cookie store.
357
- *
358
- * - If `host` is provided, only cookies whose domain matches that host
359
- * are deleted (e.g. `"example.com"` deletes `.example.com` cookies).
360
- * - If omitted, all cookies in the webview's cookie store are cleared.
361
- *
362
- * @example
363
- * ```ts
364
- * // Clear all cookies
365
- * win.clearCookies();
366
- *
367
- * // Clear cookies for a specific host
368
- * win.clearCookies("example.com");
369
- * ```
370
- */
371
- clearCookies(host?: string): void;
372
- }
373
- /**
374
- * Escape a string for safe embedding inside a JavaScript string literal.
375
- * Handles backslashes, double quotes, newlines, carriage returns, null
376
- * bytes, closing `</script>` tags, Unicode line/paragraph separators
377
- * (U+2028, U+2029), backticks, and `${` template expressions.
378
235
  *
379
- * Safe for use in double-quoted, single-quoted, and template literal
380
- * contexts.
236
+ * All methods throw `"Window is closed"` if called after `close()`.
381
237
  *
382
238
  * @example
383
239
  * ```ts
384
- * import { NativeWindow, sanitizeForJs } from "native-window";
240
+ * import { NativeWindow } from "@nativewindow/webview";
385
241
  *
386
- * const userInput = 'He said "hello"\n<script>alert(1)</script>';
387
- * win.unsafe.evaluateJs(`display("${sanitizeForJs(userInput)}")`);
242
+ * const win = new NativeWindow({ title: "Hello", width: 800, height: 600 });
243
+ * win.loadUrl("https://example.com");
244
+ * win.onClose(() => console.log("Window closed"));
388
245
  * ```
389
246
  */
390
- export declare function sanitizeForJs(input: string): string;
247
+ export declare const NativeWindow: NativeWindowConstructor;
248
+ /**
249
+ * Instance type for {@link NativeWindow}.
250
+ */
251
+ export type NativeWindow = InstanceType<typeof NativeWindow>;
252
+ export {};
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { createRequire } from "node:module";
2
- //#region index.ts
2
+ //#region src/index.ts
3
3
  var _require = createRequire(import.meta.url);
4
4
  var _platforms = {
5
5
  "darwin-arm64": {
@@ -27,9 +27,6 @@ var _platforms = {
27
27
  file: "native-window.linux-arm64-gnu.node"
28
28
  }
29
29
  };
30
- var _platformKey = `${process.platform}-${process.arch}`;
31
- var _entry = _platforms[_platformKey];
32
- if (!_entry) throw new Error(`Unsupported platform: ${_platformKey}`);
33
30
  function _tryRequire(id) {
34
31
  try {
35
32
  return _require(id);
@@ -37,377 +34,25 @@ function _tryRequire(id) {
37
34
  return null;
38
35
  }
39
36
  }
40
- var _nativeBinding = _tryRequire(`./${_entry.file}`) ?? _tryRequire(`../${_entry.file}`) ?? _tryRequire(_entry.pkg);
37
+ var _platformKey = `${process.platform}-${process.arch}`;
38
+ var _entry = _platforms[_platformKey];
39
+ if (!_entry) throw new Error(`Unsupported platform: ${_platformKey}`);
40
+ var _nativeBinding = _tryRequire(`../${_entry.file}`) ?? _tryRequire(_entry.pkg);
41
41
  if (!_nativeBinding) throw new Error(`Failed to load native binding for platform: ${_platformKey}. Ensure the correct platform package is installed or the .node file exists.`);
42
- var { NativeWindow: _NativeWindow, init, pumpEvents, checkRuntime, ensureRuntime, loadHtmlOrigin } = _nativeBinding;
43
- var _pump = null;
44
- var _windowCount = 0;
45
- function ensureInit() {
46
- if (_pump) return;
47
- init();
48
- _pump = setInterval(() => {
49
- try {
50
- pumpEvents();
51
- } catch (e) {
52
- console.error("[native-window] pumpEvents() error:", e);
53
- }
54
- }, 16);
55
- }
56
- function stopPump() {
57
- if (_pump) {
58
- clearInterval(_pump);
59
- _pump = null;
60
- }
61
- }
42
+ /** {@inheritDoc RuntimeInfo} */
43
+ var checkRuntime = _nativeBinding.checkRuntime;
44
+ /** {@inheritDoc RuntimeInfo} */
45
+ var ensureRuntime = _nativeBinding.ensureRuntime;
62
46
  /**
63
- * A native OS window with an embedded webview.
47
+ * Returns the origin of pages loaded via `loadHtml()`.
64
48
  *
65
- * Automatically initializes the native subsystem and starts pumping
66
- * events on first construction. Stops the pump when all windows close.
49
+ * This is the origin string to use in `trustedOrigins` when restricting
50
+ * IPC messages to only accept messages from `loadHtml()` content.
51
+ *
52
+ * - macOS/Linux: `"nativewindow://localhost"`
53
+ * - Windows: `"https://nativewindow.localhost"`
67
54
  */
68
- var NativeWindow = class {
69
- /** @internal */
70
- _native;
71
- /** @internal */
72
- _closed = false;
73
- /** @internal */
74
- _unsafe;
75
- /** @internal */
76
- _devtools;
77
- constructor(options) {
78
- ensureInit();
79
- _windowCount++;
80
- this._native = new _NativeWindow(options);
81
- this._native.onClose(() => this._handleClose());
82
- }
83
- /** @internal */
84
- _handleClose() {
85
- if (this._closed) return;
86
- this._closed = true;
87
- _windowCount--;
88
- this._userCloseCallback?.();
89
- if (_windowCount <= 0) {
90
- _windowCount = 0;
91
- setTimeout(() => stopPump(), 200);
92
- }
93
- }
94
- /**
95
- * Throws if the window has been closed.
96
- * @internal
97
- */
98
- _ensureOpen() {
99
- if (this._closed) throw new Error("Window is closed");
100
- }
101
- _userCloseCallback;
102
- /**
103
- * Register a handler for the window close event.
104
- * The pump is automatically stopped when all windows are closed.
105
- *
106
- * Calling this multiple times replaces the previous handler.
107
- */
108
- onClose(callback) {
109
- if (this._userCloseCallback) console.warn("NativeWindow: onClose() called multiple times. The previous handler will be replaced.");
110
- this._userCloseCallback = callback;
111
- }
112
- /** Unique window ID */
113
- get id() {
114
- return this._native.id;
115
- }
116
- loadUrl(url) {
117
- this._ensureOpen();
118
- this._native.loadUrl(url);
119
- }
120
- /**
121
- * Load raw HTML content into the webview.
122
- *
123
- * @security **Injection risk.** Never interpolate unsanitized user input
124
- * into HTML strings. Use a dedicated sanitization library such as
125
- * [DOMPurify](https://github.com/cure53/DOMPurify) or
126
- * [sanitize-html](https://github.com/apostrophecms/sanitize-html) to
127
- * sanitize untrusted content before embedding it.
128
- */
129
- loadHtml(html) {
130
- this._ensureOpen();
131
- this._native.loadHtml(html);
132
- }
133
- postMessage(message) {
134
- this._ensureOpen();
135
- this._native.postMessage(message);
136
- }
137
- /**
138
- * Namespace for operations that require extra care to avoid injection risks.
139
- * Methods under `unsafe` execute arbitrary code in the webview context.
140
- *
141
- * @security Never pass unsanitized user input to these methods.
142
- * Use {@link sanitizeForJs} to escape strings before embedding them in
143
- * script code.
144
- */
145
- get unsafe() {
146
- this._ensureOpen();
147
- if (!this._unsafe) this._unsafe = { evaluateJs: (script) => {
148
- this._ensureOpen();
149
- this._native.evaluateJs(script);
150
- } };
151
- return this._unsafe;
152
- }
153
- /**
154
- * Namespace for controlling the browser devtools panel.
155
- * Requires `devtools: true` in {@link WindowOptions} at window creation.
156
- *
157
- * @example
158
- * ```ts
159
- * const win = new NativeWindow({ devtools: true });
160
- * win.devtools.open();
161
- * console.log(win.devtools.isOpen()); // true
162
- * win.devtools.close();
163
- * ```
164
- */
165
- get devtools() {
166
- this._ensureOpen();
167
- if (!this._devtools) this._devtools = {
168
- open: () => {
169
- this._ensureOpen();
170
- this._native.openDevtools();
171
- },
172
- close: () => {
173
- this._ensureOpen();
174
- this._native.closeDevtools();
175
- },
176
- isOpen: () => {
177
- this._ensureOpen();
178
- return this._native.isDevtoolsOpen();
179
- }
180
- };
181
- return this._devtools;
182
- }
183
- setTitle(title) {
184
- this._ensureOpen();
185
- this._native.setTitle(title);
186
- }
187
- setSize(width, height) {
188
- this._ensureOpen();
189
- this._native.setSize(width, height);
190
- }
191
- setMinSize(width, height) {
192
- this._ensureOpen();
193
- this._native.setMinSize(width, height);
194
- }
195
- setMaxSize(width, height) {
196
- this._ensureOpen();
197
- this._native.setMaxSize(width, height);
198
- }
199
- setPosition(x, y) {
200
- this._ensureOpen();
201
- this._native.setPosition(x, y);
202
- }
203
- setResizable(resizable) {
204
- this._ensureOpen();
205
- this._native.setResizable(resizable);
206
- }
207
- setDecorations(decorations) {
208
- this._ensureOpen();
209
- this._native.setDecorations(decorations);
210
- }
211
- setAlwaysOnTop(alwaysOnTop) {
212
- this._ensureOpen();
213
- this._native.setAlwaysOnTop(alwaysOnTop);
214
- }
215
- /**
216
- * Set the window icon from a PNG or ICO file path.
217
- * On macOS this is silently ignored (macOS doesn't support per-window icons).
218
- * Relative paths resolve from the working directory.
219
- */
220
- setIcon(path) {
221
- this._ensureOpen();
222
- this._native.setIcon(path);
223
- }
224
- show() {
225
- this._ensureOpen();
226
- this._native.show();
227
- }
228
- hide() {
229
- this._ensureOpen();
230
- this._native.hide();
231
- }
232
- close() {
233
- this._ensureOpen();
234
- this._native.close();
235
- }
236
- focus() {
237
- this._ensureOpen();
238
- this._native.focus();
239
- }
240
- maximize() {
241
- this._ensureOpen();
242
- this._native.maximize();
243
- }
244
- minimize() {
245
- this._ensureOpen();
246
- this._native.minimize();
247
- }
248
- unmaximize() {
249
- this._ensureOpen();
250
- this._native.unmaximize();
251
- }
252
- reload() {
253
- this._ensureOpen();
254
- this._native.reload();
255
- }
256
- /**
257
- * Register a handler for messages from the webview.
258
- *
259
- * @security **No origin filtering.** The raw `onMessage` API does not
260
- * enforce origin restrictions. If your webview navigates to untrusted
261
- * URLs, validate the `sourceUrl` parameter before processing messages.
262
- * For automatic origin filtering, use `createChannel()` with the
263
- * `trustedOrigins` option from `native-window-ipc`.
264
- *
265
- * @security **No rate limiting.** Messages from the webview are delivered
266
- * without throttling. A malicious page can flood the host with messages.
267
- * Consider implementing application-level rate limiting if loading
268
- * untrusted content.
269
- */
270
- onMessage(callback) {
271
- this._ensureOpen();
272
- this._native.onMessage(callback);
273
- }
274
- onResize(callback) {
275
- this._ensureOpen();
276
- this._native.onResize(callback);
277
- }
278
- onMove(callback) {
279
- this._ensureOpen();
280
- this._native.onMove(callback);
281
- }
282
- onFocus(callback) {
283
- this._ensureOpen();
284
- this._native.onFocus(callback);
285
- }
286
- onBlur(callback) {
287
- this._ensureOpen();
288
- this._native.onBlur(callback);
289
- }
290
- onPageLoad(callback) {
291
- this._ensureOpen();
292
- this._native.onPageLoad(callback);
293
- }
294
- onTitleChanged(callback) {
295
- this._ensureOpen();
296
- this._native.onTitleChanged(callback);
297
- }
298
- onReload(callback) {
299
- this._ensureOpen();
300
- this._native.onReload(callback);
301
- }
302
- /**
303
- * Register a handler for blocked navigation events.
304
- * Fired when a navigation is blocked by the {@link WindowOptions.allowedHosts}
305
- * restriction. Receives the URL that was blocked.
306
- *
307
- * @example
308
- * ```ts
309
- * win.onNavigationBlocked((url) => {
310
- * console.log("Blocked navigation to:", url);
311
- * });
312
- * ```
313
- */
314
- onNavigationBlocked(callback) {
315
- this._ensureOpen();
316
- this._native.onNavigationBlocked(callback);
317
- }
318
- /**
319
- * Validate and parse a raw cookies JSON array from the native layer.
320
- * Returns a cleaned {@link CookieInfo} array or `null` if the payload
321
- * is malformed.
322
- *
323
- * @internal
324
- */
325
- _validateCookies(raw) {
326
- let parsed;
327
- try {
328
- parsed = JSON.parse(raw);
329
- } catch {
330
- return null;
331
- }
332
- if (!Array.isArray(parsed)) return null;
333
- const cookies = [];
334
- for (const item of parsed) {
335
- if (typeof item !== "object" || item === null) continue;
336
- const obj = item;
337
- if (typeof obj.name !== "string" || typeof obj.value !== "string") continue;
338
- if (typeof obj.domain !== "string" || typeof obj.path !== "string") continue;
339
- if (typeof obj.httpOnly !== "boolean" || typeof obj.secure !== "boolean") continue;
340
- if (typeof obj.sameSite !== "string" || typeof obj.expires !== "number") continue;
341
- cookies.push({
342
- name: obj.name,
343
- value: obj.value,
344
- domain: obj.domain,
345
- path: obj.path,
346
- httpOnly: obj.httpOnly,
347
- secure: obj.secure,
348
- sameSite: obj.sameSite,
349
- expires: obj.expires
350
- });
351
- }
352
- return cookies;
353
- }
354
- /**
355
- * Query cookies from the native cookie store.
356
- *
357
- * Returns a Promise that resolves with validated {@link CookieInfo} objects,
358
- * including `HttpOnly` cookies that are invisible to `document.cookie`.
359
- *
360
- * - **macOS**: Uses `WKHTTPCookieStore.getAllCookies` with client-side
361
- * URL filtering (domain + path match).
362
- * - **Windows**: Uses `ICoreWebView2CookieManager.GetCookies` which
363
- * filters by URI natively.
364
- *
365
- * @param url If provided, only cookies matching this URL are returned.
366
- * If omitted, all cookies in the webview's cookie store are returned.
367
- *
368
- * @example
369
- * ```ts
370
- * const cookies = await win.getCookies("https://example.com");
371
- * const session = cookies.find((c) => c.name === "session_id");
372
- * if (session) console.log("Session:", session.value, "HttpOnly:", session.httpOnly);
373
- * ```
374
- */
375
- getCookies(url) {
376
- this._ensureOpen();
377
- return new Promise((resolve, reject) => {
378
- const timeout = setTimeout(() => {
379
- reject(/* @__PURE__ */ new Error("getCookies() timed out after 10 seconds"));
380
- }, 1e4);
381
- this._native.onCookies((raw) => {
382
- clearTimeout(timeout);
383
- const validated = this._validateCookies(raw);
384
- if (validated) resolve(validated);
385
- else reject(/* @__PURE__ */ new Error("Failed to parse cookie response"));
386
- });
387
- this._native.getCookies(url);
388
- });
389
- }
390
- /**
391
- * Clear cookies from the native cookie store.
392
- *
393
- * - If `host` is provided, only cookies whose domain matches that host
394
- * are deleted (e.g. `"example.com"` deletes `.example.com` cookies).
395
- * - If omitted, all cookies in the webview's cookie store are cleared.
396
- *
397
- * @example
398
- * ```ts
399
- * // Clear all cookies
400
- * win.clearCookies();
401
- *
402
- * // Clear cookies for a specific host
403
- * win.clearCookies("example.com");
404
- * ```
405
- */
406
- clearCookies(host) {
407
- this._ensureOpen();
408
- this._native.clearCookies(host);
409
- }
410
- };
55
+ var loadHtmlOrigin = _nativeBinding.loadHtmlOrigin;
411
56
  /**
412
57
  * Escape a string for safe embedding inside a JavaScript string literal.
413
58
  * Handles backslashes, double quotes, newlines, carriage returns, null
@@ -419,14 +64,30 @@ var NativeWindow = class {
419
64
  *
420
65
  * @example
421
66
  * ```ts
422
- * import { NativeWindow, sanitizeForJs } from "native-window";
67
+ * import { NativeWindow, sanitizeForJs } from "@nativewindow/webview";
423
68
  *
424
69
  * const userInput = 'He said "hello"\n<script>alert(1)<\/script>';
425
- * win.unsafe.evaluateJs(`display("${sanitizeForJs(userInput)}")`);
70
+ * win.evaluateJs(`display("${sanitizeForJs(userInput)}")`);
426
71
  * ```
427
72
  */
428
- function sanitizeForJs(input) {
429
- return JSON.stringify(input).slice(1, -1).replace(/<\/script>/gi, "<\\/script>").replace(/`/g, "\\`").replace(/\$\{/g, "\\${");
430
- }
73
+ var sanitizeForJs = _nativeBinding.sanitizeForJs;
74
+ /**
75
+ * A native OS window with an embedded webview.
76
+ *
77
+ * Automatically initializes the native subsystem and starts pumping
78
+ * events on first construction. Stops the pump when all windows close.
79
+ *
80
+ * All methods throw `"Window is closed"` if called after `close()`.
81
+ *
82
+ * @example
83
+ * ```ts
84
+ * import { NativeWindow } from "@nativewindow/webview";
85
+ *
86
+ * const win = new NativeWindow({ title: "Hello", width: 800, height: 600 });
87
+ * win.loadUrl("https://example.com");
88
+ * win.onClose(() => console.log("Window closed"));
89
+ * ```
90
+ */
91
+ var NativeWindow = _nativeBinding.NativeWindow;
431
92
  //#endregion
432
93
  export { NativeWindow, checkRuntime, ensureRuntime, loadHtmlOrigin, sanitizeForJs };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nativewindow/webview",
3
- "version": "1.0.5",
3
+ "version": "1.0.6",
4
4
  "description": "Native OS webview windows for Bun & Node.js (beta)",
5
5
  "homepage": "https://nativewindow.fcannizzaro.com",
6
6
  "bugs": {
@@ -37,8 +37,8 @@
37
37
  }
38
38
  },
39
39
  "scripts": {
40
- "build": "napi build --release --platform && vite build",
41
- "build:debug": "napi build --platform && vite build",
40
+ "build": "napi build --release --platform --no-js && rm -f index.d.ts && vite build",
41
+ "build:debug": "napi build --platform --no-js && rm -f index.d.ts && vite build",
42
42
  "build:ts": "vite build",
43
43
  "version": "napi version",
44
44
  "fuzz": "cargo +nightly fuzz list --fuzz-dir fuzz",
@@ -60,12 +60,12 @@
60
60
  "typescript": "^6.0.2"
61
61
  },
62
62
  "optionalDependencies": {
63
- "@nativewindow/webview-darwin-arm64": "1.0.5",
64
- "@nativewindow/webview-darwin-x64": "1.0.5",
65
- "@nativewindow/webview-linux-arm64-gnu": "1.0.5",
66
- "@nativewindow/webview-linux-x64-gnu": "1.0.5",
67
- "@nativewindow/webview-win32-arm64-msvc": "1.0.5",
68
- "@nativewindow/webview-win32-x64-msvc": "1.0.5"
63
+ "@nativewindow/webview-darwin-arm64": "1.0.6",
64
+ "@nativewindow/webview-darwin-x64": "1.0.6",
65
+ "@nativewindow/webview-linux-arm64-gnu": "1.0.6",
66
+ "@nativewindow/webview-linux-x64-gnu": "1.0.6",
67
+ "@nativewindow/webview-win32-arm64-msvc": "1.0.6",
68
+ "@nativewindow/webview-win32-x64-msvc": "1.0.6"
69
69
  },
70
70
  "napi": {
71
71
  "binaryName": "native-window",