@nativewindow/webview 1.0.4 → 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.
- package/dist/index.d.ts +174 -190
- package/dist/index.js +71 -370
- package/package.json +10 -12
- package/native-window.d.ts +0 -264
- package/native-window.js +0 -62
package/dist/index.d.ts
CHANGED
|
@@ -1,61 +1,15 @@
|
|
|
1
|
-
|
|
2
|
-
export
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
* Use {@link sanitizeForJs} to escape strings before embedding them in
|
|
10
|
-
* script code.
|
|
11
|
-
*/
|
|
12
|
-
export interface UnsafeNamespace {
|
|
13
|
-
/**
|
|
14
|
-
* Evaluate arbitrary JavaScript in the webview context.
|
|
15
|
-
* Fire-and-forget — there is no return value.
|
|
16
|
-
* Use `postMessage`/`onMessage` to send results back.
|
|
17
|
-
*
|
|
18
|
-
* @security **Injection risk.** Never pass unsanitized user input directly.
|
|
19
|
-
* Use {@link sanitizeForJs} to escape strings before embedding them in
|
|
20
|
-
* script code.
|
|
21
|
-
*/
|
|
22
|
-
evaluateJs(script: string): void;
|
|
23
|
-
}
|
|
24
|
-
/**
|
|
25
|
-
* Control the browser devtools panel for this window's webview.
|
|
26
|
-
* Grouped under {@link NativeWindow.devtools} for discoverability.
|
|
27
|
-
*
|
|
28
|
-
* Requires `devtools: true` in {@link WindowOptions} at window creation.
|
|
29
|
-
*
|
|
30
|
-
* @example
|
|
31
|
-
* ```ts
|
|
32
|
-
* const win = new NativeWindow({ devtools: true });
|
|
33
|
-
* win.devtools.open();
|
|
34
|
-
* console.log(win.devtools.isOpen()); // true
|
|
35
|
-
* win.devtools.close();
|
|
36
|
-
* ```
|
|
37
|
-
*/
|
|
38
|
-
export interface DevtoolsNamespace {
|
|
39
|
-
/** Open the browser devtools panel. */
|
|
40
|
-
open(): void;
|
|
41
|
-
/** Close the browser devtools panel. */
|
|
42
|
-
close(): void;
|
|
43
|
-
/** Check whether the devtools panel is currently open. */
|
|
44
|
-
isOpen(): boolean;
|
|
1
|
+
/** Information about the native webview runtime. */
|
|
2
|
+
export interface RuntimeInfo {
|
|
3
|
+
/** Whether the webview runtime is available. */
|
|
4
|
+
available: boolean;
|
|
5
|
+
/** The version string of the runtime, if detected. */
|
|
6
|
+
version?: string;
|
|
7
|
+
/** The current platform: "macos", "windows", "linux", or "unsupported". */
|
|
8
|
+
platform: "macos" | "windows" | "linux" | "unsupported";
|
|
45
9
|
}
|
|
46
10
|
/**
|
|
47
11
|
* Information about a cookie from the native cookie store.
|
|
48
12
|
* Includes `HttpOnly` cookies that are invisible to `document.cookie`.
|
|
49
|
-
*
|
|
50
|
-
* @example
|
|
51
|
-
* ```ts
|
|
52
|
-
* win.onCookies((cookies) => {
|
|
53
|
-
* for (const c of cookies) {
|
|
54
|
-
* console.log(c.name, c.value, c.httpOnly);
|
|
55
|
-
* }
|
|
56
|
-
* });
|
|
57
|
-
* win.getCookies("https://example.com");
|
|
58
|
-
* ```
|
|
59
13
|
*/
|
|
60
14
|
export interface CookieInfo {
|
|
61
15
|
/** Cookie name. */
|
|
@@ -70,79 +24,22 @@ export interface CookieInfo {
|
|
|
70
24
|
httpOnly: boolean;
|
|
71
25
|
/** Whether the cookie requires HTTPS. */
|
|
72
26
|
secure: boolean;
|
|
73
|
-
/** SameSite policy: "
|
|
74
|
-
sameSite: string;
|
|
75
|
-
/** Expiry as Unix timestamp (seconds).
|
|
76
|
-
expires: number;
|
|
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;
|
|
77
31
|
}
|
|
78
|
-
type
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
export declare class NativeWindow {
|
|
86
|
-
/** @internal */
|
|
87
|
-
private _native;
|
|
88
|
-
/** @internal */
|
|
89
|
-
private _closed;
|
|
90
|
-
/** @internal */
|
|
91
|
-
private _unsafe?;
|
|
92
|
-
/** @internal */
|
|
93
|
-
private _devtools?;
|
|
94
|
-
constructor(options?: WindowOptions);
|
|
95
|
-
/** @internal */
|
|
96
|
-
private _handleClose;
|
|
97
|
-
/**
|
|
98
|
-
* Throws if the window has been closed.
|
|
99
|
-
* @internal
|
|
100
|
-
*/
|
|
101
|
-
private _ensureOpen;
|
|
102
|
-
private _userCloseCallback?;
|
|
103
|
-
/**
|
|
104
|
-
* Register a handler for the window close event.
|
|
105
|
-
* The pump is automatically stopped when all windows are closed.
|
|
106
|
-
*
|
|
107
|
-
* Calling this multiple times replaces the previous handler.
|
|
108
|
-
*/
|
|
109
|
-
onClose(callback: () => void): void;
|
|
110
|
-
/** Unique window ID */
|
|
111
|
-
get id(): number;
|
|
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;
|
|
112
39
|
loadUrl(url: string): void;
|
|
113
|
-
/**
|
|
114
|
-
* Load raw HTML content into the webview.
|
|
115
|
-
*
|
|
116
|
-
* @security **Injection risk.** Never interpolate unsanitized user input
|
|
117
|
-
* into HTML strings. Use a dedicated sanitization library such as
|
|
118
|
-
* [DOMPurify](https://github.com/cure53/DOMPurify) or
|
|
119
|
-
* [sanitize-html](https://github.com/apostrophecms/sanitize-html) to
|
|
120
|
-
* sanitize untrusted content before embedding it.
|
|
121
|
-
*/
|
|
122
40
|
loadHtml(html: string): void;
|
|
41
|
+
evaluateJs(script: string): void;
|
|
123
42
|
postMessage(message: string): void;
|
|
124
|
-
/**
|
|
125
|
-
* Namespace for operations that require extra care to avoid injection risks.
|
|
126
|
-
* Methods under `unsafe` execute arbitrary code in the webview context.
|
|
127
|
-
*
|
|
128
|
-
* @security Never pass unsanitized user input to these methods.
|
|
129
|
-
* Use {@link sanitizeForJs} to escape strings before embedding them in
|
|
130
|
-
* script code.
|
|
131
|
-
*/
|
|
132
|
-
get unsafe(): UnsafeNamespace;
|
|
133
|
-
/**
|
|
134
|
-
* Namespace for controlling the browser devtools panel.
|
|
135
|
-
* Requires `devtools: true` in {@link WindowOptions} at window creation.
|
|
136
|
-
*
|
|
137
|
-
* @example
|
|
138
|
-
* ```ts
|
|
139
|
-
* const win = new NativeWindow({ devtools: true });
|
|
140
|
-
* win.devtools.open();
|
|
141
|
-
* console.log(win.devtools.isOpen()); // true
|
|
142
|
-
* win.devtools.close();
|
|
143
|
-
* ```
|
|
144
|
-
*/
|
|
145
|
-
get devtools(): DevtoolsNamespace;
|
|
146
43
|
setTitle(title: string): void;
|
|
147
44
|
setSize(width: number, height: number): void;
|
|
148
45
|
setMinSize(width: number, height: number): void;
|
|
@@ -151,11 +48,6 @@ export declare class NativeWindow {
|
|
|
151
48
|
setResizable(resizable: boolean): void;
|
|
152
49
|
setDecorations(decorations: boolean): void;
|
|
153
50
|
setAlwaysOnTop(alwaysOnTop: boolean): void;
|
|
154
|
-
/**
|
|
155
|
-
* Set the window icon from a PNG or ICO file path.
|
|
156
|
-
* On macOS this is silently ignored (macOS doesn't support per-window icons).
|
|
157
|
-
* Relative paths resolve from the working directory.
|
|
158
|
-
*/
|
|
159
51
|
setIcon(path: string): void;
|
|
160
52
|
show(): void;
|
|
161
53
|
hide(): void;
|
|
@@ -165,21 +57,8 @@ export declare class NativeWindow {
|
|
|
165
57
|
minimize(): void;
|
|
166
58
|
unmaximize(): void;
|
|
167
59
|
reload(): void;
|
|
168
|
-
/**
|
|
169
|
-
* Register a handler for messages from the webview.
|
|
170
|
-
*
|
|
171
|
-
* @security **No origin filtering.** The raw `onMessage` API does not
|
|
172
|
-
* enforce origin restrictions. If your webview navigates to untrusted
|
|
173
|
-
* URLs, validate the `sourceUrl` parameter before processing messages.
|
|
174
|
-
* For automatic origin filtering, use `createChannel()` with the
|
|
175
|
-
* `trustedOrigins` option from `native-window-ipc`.
|
|
176
|
-
*
|
|
177
|
-
* @security **No rate limiting.** Messages from the webview are delivered
|
|
178
|
-
* without throttling. A malicious page can flood the host with messages.
|
|
179
|
-
* Consider implementing application-level rate limiting if loading
|
|
180
|
-
* untrusted content.
|
|
181
|
-
*/
|
|
182
60
|
onMessage(callback: (message: string, sourceUrl: string) => void): void;
|
|
61
|
+
onClose(callback: () => void): void;
|
|
183
62
|
onResize(callback: (width: number, height: number) => void): void;
|
|
184
63
|
onMove(callback: (x: number, y: number) => void): void;
|
|
185
64
|
onFocus(callback: () => void): void;
|
|
@@ -187,67 +66,149 @@ export declare class NativeWindow {
|
|
|
187
66
|
onPageLoad(callback: (event: "started" | "finished", url: string) => void): void;
|
|
188
67
|
onTitleChanged(callback: (title: string) => void): void;
|
|
189
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
|
+
*/
|
|
83
|
+
export interface WindowOptions {
|
|
84
|
+
/** Window title. Default: "" */
|
|
85
|
+
title?: string;
|
|
86
|
+
/** Inner width in logical pixels. Default: 800 */
|
|
87
|
+
width?: number;
|
|
88
|
+
/** Inner height in logical pixels. Default: 600 */
|
|
89
|
+
height?: number;
|
|
90
|
+
/** X position in screen coordinates */
|
|
91
|
+
x?: number;
|
|
92
|
+
/** Y position in screen coordinates */
|
|
93
|
+
y?: number;
|
|
94
|
+
/** Minimum inner width */
|
|
95
|
+
minWidth?: number;
|
|
96
|
+
/** Minimum inner height */
|
|
97
|
+
minHeight?: number;
|
|
98
|
+
/** Maximum inner width */
|
|
99
|
+
maxWidth?: number;
|
|
100
|
+
/** Maximum inner height */
|
|
101
|
+
maxHeight?: number;
|
|
102
|
+
/** Allow resizing. Default: true */
|
|
103
|
+
resizable?: boolean;
|
|
104
|
+
/** Show window decorations (title bar, borders). Default: true */
|
|
105
|
+
decorations?: boolean;
|
|
106
|
+
/** Transparent window background. Default: false */
|
|
107
|
+
transparent?: boolean;
|
|
108
|
+
/** Always on top of other windows. Default: false */
|
|
109
|
+
alwaysOnTop?: boolean;
|
|
110
|
+
/** Initially visible. Default: true */
|
|
111
|
+
visible?: boolean;
|
|
112
|
+
/** Enable devtools. Default: false */
|
|
113
|
+
devtools?: boolean;
|
|
190
114
|
/**
|
|
191
|
-
*
|
|
192
|
-
*
|
|
193
|
-
*
|
|
115
|
+
* Content Security Policy to inject at document start.
|
|
116
|
+
* When set, a `<meta http-equiv="Content-Security-Policy">` tag is injected
|
|
117
|
+
* before any page scripts run.
|
|
194
118
|
*
|
|
195
|
-
*
|
|
196
|
-
*
|
|
197
|
-
*
|
|
198
|
-
*
|
|
199
|
-
*
|
|
200
|
-
*
|
|
119
|
+
* **Limitation:** The CSP is applied via a `<meta>` tag at `DOMContentLoaded`,
|
|
120
|
+
* so scripts executing before that event are not restricted. Meta-tag CSP also
|
|
121
|
+
* cannot enforce `frame-ancestors` or `report-uri` directives. For stronger
|
|
122
|
+
* enforcement, serve pages via the custom protocol handler with a real HTTP
|
|
123
|
+
* `Content-Security-Policy` header.
|
|
124
|
+
*
|
|
125
|
+
* @example `"default-src 'self'; script-src 'self' 'unsafe-inline'"`
|
|
201
126
|
*/
|
|
202
|
-
|
|
127
|
+
csp?: string;
|
|
203
128
|
/**
|
|
204
|
-
*
|
|
205
|
-
*
|
|
206
|
-
*
|
|
129
|
+
* Trusted origins for IPC messages at the native layer.
|
|
130
|
+
* When set, only messages whose source URL origin matches one of these
|
|
131
|
+
* entries are forwarded to the host. Messages from other origins are
|
|
132
|
+
* silently dropped.
|
|
133
|
+
*
|
|
134
|
+
* Each entry should be a full origin string (scheme + host + optional port),
|
|
135
|
+
* e.g. `"https://example.com"`. No trailing slash.
|
|
207
136
|
*
|
|
208
|
-
* @
|
|
137
|
+
* @security Defense-in-depth. For application-level origin filtering,
|
|
138
|
+
* use `trustedOrigins` in `createChannel()` from `native-window-ipc`.
|
|
139
|
+
*
|
|
140
|
+
* @example `["https://myapp.com", "https://cdn.myapp.com"]`
|
|
209
141
|
*/
|
|
210
|
-
|
|
142
|
+
trustedOrigins?: string[];
|
|
211
143
|
/**
|
|
212
|
-
*
|
|
213
|
-
*
|
|
214
|
-
*
|
|
215
|
-
*
|
|
144
|
+
* Allowed hosts for navigation restriction.
|
|
145
|
+
* When set and non-empty, ALL navigations (including `loadUrl()`, link
|
|
146
|
+
* clicks, form submissions, and redirects) are restricted to URLs whose
|
|
147
|
+
* host matches one of these patterns.
|
|
216
148
|
*
|
|
217
|
-
*
|
|
218
|
-
*
|
|
219
|
-
* - **Windows**: Uses `ICoreWebView2CookieManager.GetCookies` which
|
|
220
|
-
* filters by URI natively.
|
|
149
|
+
* Supports wildcard prefixes: `"*.example.com"` matches any subdomain
|
|
150
|
+
* of `example.com` and `example.com` itself.
|
|
221
151
|
*
|
|
222
|
-
*
|
|
223
|
-
*
|
|
152
|
+
* Internal navigations (`about:blank`, `loadHtml()` content) are always
|
|
153
|
+
* permitted. When unset or empty, all hosts are allowed.
|
|
224
154
|
*
|
|
225
|
-
* @example
|
|
226
|
-
* ```ts
|
|
227
|
-
* const cookies = await win.getCookies("https://example.com");
|
|
228
|
-
* const session = cookies.find((c) => c.name === "session_id");
|
|
229
|
-
* if (session) console.log("Session:", session.value, "HttpOnly:", session.httpOnly);
|
|
230
|
-
* ```
|
|
155
|
+
* @example `["myapp.com", "*.cdn.myapp.com"]`
|
|
231
156
|
*/
|
|
232
|
-
|
|
157
|
+
allowedHosts?: string[];
|
|
233
158
|
/**
|
|
234
|
-
*
|
|
235
|
-
*
|
|
236
|
-
*
|
|
237
|
-
|
|
238
|
-
|
|
159
|
+
* Allow the webview to access the camera when requested.
|
|
160
|
+
* Default: false (all camera requests are denied).
|
|
161
|
+
* @note Not yet enforced in the wry backend. The OS default (prompt user) applies.
|
|
162
|
+
*/
|
|
163
|
+
allowCamera?: boolean;
|
|
164
|
+
/**
|
|
165
|
+
* Allow the webview to access the microphone when requested.
|
|
166
|
+
* Default: false (all microphone requests are denied).
|
|
167
|
+
* @note Not yet enforced in the wry backend. The OS default (prompt user) applies.
|
|
168
|
+
*/
|
|
169
|
+
allowMicrophone?: boolean;
|
|
170
|
+
/**
|
|
171
|
+
* Allow the webview to use the File System Access API
|
|
172
|
+
* (`showOpenFilePicker`, `showSaveFilePicker`, `showDirectoryPicker`).
|
|
173
|
+
* Default: false (all file system access requests are denied).
|
|
174
|
+
* @note Not yet enforced in the wry backend. The OS default applies.
|
|
175
|
+
*/
|
|
176
|
+
allowFileSystem?: boolean;
|
|
177
|
+
/**
|
|
178
|
+
* Path to a PNG or ICO file for the window icon (title bar).
|
|
179
|
+
* On macOS this option is silently ignored (macOS doesn't support
|
|
180
|
+
* per-window icons). Relative paths resolve from the working directory.
|
|
181
|
+
*/
|
|
182
|
+
icon?: string;
|
|
183
|
+
/**
|
|
184
|
+
* Run the webview in incognito (private) mode.
|
|
185
|
+
* When `true`, no cookies, cache, or other browsing data are persisted to disk.
|
|
186
|
+
* Each window starts with a clean, isolated session and all data is discarded
|
|
187
|
+
* when the window closes.
|
|
239
188
|
*
|
|
240
|
-
*
|
|
241
|
-
*
|
|
242
|
-
*
|
|
243
|
-
*
|
|
189
|
+
* Platform notes:
|
|
190
|
+
* - **macOS**: Uses `WKWebsiteDataStore.nonPersistentDataStore()` (WKWebView).
|
|
191
|
+
* - **Windows**: Enables `IsInPrivateModeEnabled` on the WebView2 controller.
|
|
192
|
+
* - **Linux**: Uses a temporary in-memory WebContext (no persistent storage).
|
|
244
193
|
*
|
|
245
|
-
*
|
|
246
|
-
* win.clearCookies("example.com");
|
|
247
|
-
* ```
|
|
194
|
+
* Default: `false`
|
|
248
195
|
*/
|
|
249
|
-
|
|
196
|
+
incognito?: boolean;
|
|
250
197
|
}
|
|
198
|
+
/** {@inheritDoc RuntimeInfo} */
|
|
199
|
+
export declare const checkRuntime: () => RuntimeInfo;
|
|
200
|
+
/** {@inheritDoc RuntimeInfo} */
|
|
201
|
+
export declare const ensureRuntime: () => RuntimeInfo;
|
|
202
|
+
/**
|
|
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.
|
|
207
|
+
*
|
|
208
|
+
* - macOS/Linux: `"nativewindow://localhost"`
|
|
209
|
+
* - Windows: `"https://nativewindow.localhost"`
|
|
210
|
+
*/
|
|
211
|
+
export declare const loadHtmlOrigin: () => string;
|
|
251
212
|
/**
|
|
252
213
|
* Escape a string for safe embedding inside a JavaScript string literal.
|
|
253
214
|
* Handles backslashes, double quotes, newlines, carriage returns, null
|
|
@@ -259,10 +220,33 @@ export declare class NativeWindow {
|
|
|
259
220
|
*
|
|
260
221
|
* @example
|
|
261
222
|
* ```ts
|
|
262
|
-
* import { NativeWindow, sanitizeForJs } from "
|
|
223
|
+
* import { NativeWindow, sanitizeForJs } from "@nativewindow/webview";
|
|
263
224
|
*
|
|
264
225
|
* const userInput = 'He said "hello"\n<script>alert(1)</script>';
|
|
265
|
-
* win.
|
|
226
|
+
* win.evaluateJs(`display("${sanitizeForJs(userInput)}")`);
|
|
227
|
+
* ```
|
|
228
|
+
*/
|
|
229
|
+
export declare const sanitizeForJs: (input: string) => string;
|
|
230
|
+
/**
|
|
231
|
+
* A native OS window with an embedded webview.
|
|
232
|
+
*
|
|
233
|
+
* Automatically initializes the native subsystem and starts pumping
|
|
234
|
+
* events on first construction. Stops the pump when all windows close.
|
|
235
|
+
*
|
|
236
|
+
* All methods throw `"Window is closed"` if called after `close()`.
|
|
237
|
+
*
|
|
238
|
+
* @example
|
|
239
|
+
* ```ts
|
|
240
|
+
* import { NativeWindow } from "@nativewindow/webview";
|
|
241
|
+
*
|
|
242
|
+
* const win = new NativeWindow({ title: "Hello", width: 800, height: 600 });
|
|
243
|
+
* win.loadUrl("https://example.com");
|
|
244
|
+
* win.onClose(() => console.log("Window closed"));
|
|
266
245
|
* ```
|
|
267
246
|
*/
|
|
268
|
-
export declare
|
|
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,373 +1,58 @@
|
|
|
1
|
-
import {
|
|
2
|
-
//#region index.ts
|
|
3
|
-
var
|
|
4
|
-
var
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
//#region src/index.ts
|
|
3
|
+
var _require = createRequire(import.meta.url);
|
|
4
|
+
var _platforms = {
|
|
5
|
+
"darwin-arm64": {
|
|
6
|
+
pkg: "@nativewindow/webview-darwin-arm64",
|
|
7
|
+
file: "native-window.darwin-arm64.node"
|
|
8
|
+
},
|
|
9
|
+
"darwin-x64": {
|
|
10
|
+
pkg: "@nativewindow/webview-darwin-x64",
|
|
11
|
+
file: "native-window.darwin-x64.node"
|
|
12
|
+
},
|
|
13
|
+
"win32-x64": {
|
|
14
|
+
pkg: "@nativewindow/webview-win32-x64-msvc",
|
|
15
|
+
file: "native-window.win32-x64-msvc.node"
|
|
16
|
+
},
|
|
17
|
+
"win32-arm64": {
|
|
18
|
+
pkg: "@nativewindow/webview-win32-arm64-msvc",
|
|
19
|
+
file: "native-window.win32-arm64-msvc.node"
|
|
20
|
+
},
|
|
21
|
+
"linux-x64": {
|
|
22
|
+
pkg: "@nativewindow/webview-linux-x64-gnu",
|
|
23
|
+
file: "native-window.linux-x64-gnu.node"
|
|
24
|
+
},
|
|
25
|
+
"linux-arm64": {
|
|
26
|
+
pkg: "@nativewindow/webview-linux-arm64-gnu",
|
|
27
|
+
file: "native-window.linux-arm64-gnu.node"
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
function _tryRequire(id) {
|
|
31
|
+
try {
|
|
32
|
+
return _require(id);
|
|
33
|
+
} catch {
|
|
34
|
+
return null;
|
|
20
35
|
}
|
|
21
36
|
}
|
|
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
|
+
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
|
+
/** {@inheritDoc RuntimeInfo} */
|
|
43
|
+
var checkRuntime = _nativeBinding.checkRuntime;
|
|
44
|
+
/** {@inheritDoc RuntimeInfo} */
|
|
45
|
+
var ensureRuntime = _nativeBinding.ensureRuntime;
|
|
22
46
|
/**
|
|
23
|
-
*
|
|
47
|
+
* Returns the origin of pages loaded via `loadHtml()`.
|
|
24
48
|
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
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"`
|
|
27
54
|
*/
|
|
28
|
-
var
|
|
29
|
-
/** @internal */
|
|
30
|
-
_native;
|
|
31
|
-
/** @internal */
|
|
32
|
-
_closed = false;
|
|
33
|
-
/** @internal */
|
|
34
|
-
_unsafe;
|
|
35
|
-
/** @internal */
|
|
36
|
-
_devtools;
|
|
37
|
-
constructor(options) {
|
|
38
|
-
ensureInit();
|
|
39
|
-
_windowCount++;
|
|
40
|
-
this._native = new NativeWindow$1(options);
|
|
41
|
-
this._native.onClose(() => this._handleClose());
|
|
42
|
-
}
|
|
43
|
-
/** @internal */
|
|
44
|
-
_handleClose() {
|
|
45
|
-
if (this._closed) return;
|
|
46
|
-
this._closed = true;
|
|
47
|
-
_windowCount--;
|
|
48
|
-
this._userCloseCallback?.();
|
|
49
|
-
if (_windowCount <= 0) {
|
|
50
|
-
_windowCount = 0;
|
|
51
|
-
setTimeout(() => stopPump(), 200);
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
/**
|
|
55
|
-
* Throws if the window has been closed.
|
|
56
|
-
* @internal
|
|
57
|
-
*/
|
|
58
|
-
_ensureOpen() {
|
|
59
|
-
if (this._closed) throw new Error("Window is closed");
|
|
60
|
-
}
|
|
61
|
-
_userCloseCallback;
|
|
62
|
-
/**
|
|
63
|
-
* Register a handler for the window close event.
|
|
64
|
-
* The pump is automatically stopped when all windows are closed.
|
|
65
|
-
*
|
|
66
|
-
* Calling this multiple times replaces the previous handler.
|
|
67
|
-
*/
|
|
68
|
-
onClose(callback) {
|
|
69
|
-
if (this._userCloseCallback) console.warn("NativeWindow: onClose() called multiple times. The previous handler will be replaced.");
|
|
70
|
-
this._userCloseCallback = callback;
|
|
71
|
-
}
|
|
72
|
-
/** Unique window ID */
|
|
73
|
-
get id() {
|
|
74
|
-
return this._native.id;
|
|
75
|
-
}
|
|
76
|
-
loadUrl(url) {
|
|
77
|
-
this._ensureOpen();
|
|
78
|
-
this._native.loadUrl(url);
|
|
79
|
-
}
|
|
80
|
-
/**
|
|
81
|
-
* Load raw HTML content into the webview.
|
|
82
|
-
*
|
|
83
|
-
* @security **Injection risk.** Never interpolate unsanitized user input
|
|
84
|
-
* into HTML strings. Use a dedicated sanitization library such as
|
|
85
|
-
* [DOMPurify](https://github.com/cure53/DOMPurify) or
|
|
86
|
-
* [sanitize-html](https://github.com/apostrophecms/sanitize-html) to
|
|
87
|
-
* sanitize untrusted content before embedding it.
|
|
88
|
-
*/
|
|
89
|
-
loadHtml(html) {
|
|
90
|
-
this._ensureOpen();
|
|
91
|
-
this._native.loadHtml(html);
|
|
92
|
-
}
|
|
93
|
-
postMessage(message) {
|
|
94
|
-
this._ensureOpen();
|
|
95
|
-
this._native.postMessage(message);
|
|
96
|
-
}
|
|
97
|
-
/**
|
|
98
|
-
* Namespace for operations that require extra care to avoid injection risks.
|
|
99
|
-
* Methods under `unsafe` execute arbitrary code in the webview context.
|
|
100
|
-
*
|
|
101
|
-
* @security Never pass unsanitized user input to these methods.
|
|
102
|
-
* Use {@link sanitizeForJs} to escape strings before embedding them in
|
|
103
|
-
* script code.
|
|
104
|
-
*/
|
|
105
|
-
get unsafe() {
|
|
106
|
-
this._ensureOpen();
|
|
107
|
-
if (!this._unsafe) this._unsafe = { evaluateJs: (script) => {
|
|
108
|
-
this._ensureOpen();
|
|
109
|
-
this._native.evaluateJs(script);
|
|
110
|
-
} };
|
|
111
|
-
return this._unsafe;
|
|
112
|
-
}
|
|
113
|
-
/**
|
|
114
|
-
* Namespace for controlling the browser devtools panel.
|
|
115
|
-
* Requires `devtools: true` in {@link WindowOptions} at window creation.
|
|
116
|
-
*
|
|
117
|
-
* @example
|
|
118
|
-
* ```ts
|
|
119
|
-
* const win = new NativeWindow({ devtools: true });
|
|
120
|
-
* win.devtools.open();
|
|
121
|
-
* console.log(win.devtools.isOpen()); // true
|
|
122
|
-
* win.devtools.close();
|
|
123
|
-
* ```
|
|
124
|
-
*/
|
|
125
|
-
get devtools() {
|
|
126
|
-
this._ensureOpen();
|
|
127
|
-
if (!this._devtools) this._devtools = {
|
|
128
|
-
open: () => {
|
|
129
|
-
this._ensureOpen();
|
|
130
|
-
this._native.openDevtools();
|
|
131
|
-
},
|
|
132
|
-
close: () => {
|
|
133
|
-
this._ensureOpen();
|
|
134
|
-
this._native.closeDevtools();
|
|
135
|
-
},
|
|
136
|
-
isOpen: () => {
|
|
137
|
-
this._ensureOpen();
|
|
138
|
-
return this._native.isDevtoolsOpen();
|
|
139
|
-
}
|
|
140
|
-
};
|
|
141
|
-
return this._devtools;
|
|
142
|
-
}
|
|
143
|
-
setTitle(title) {
|
|
144
|
-
this._ensureOpen();
|
|
145
|
-
this._native.setTitle(title);
|
|
146
|
-
}
|
|
147
|
-
setSize(width, height) {
|
|
148
|
-
this._ensureOpen();
|
|
149
|
-
this._native.setSize(width, height);
|
|
150
|
-
}
|
|
151
|
-
setMinSize(width, height) {
|
|
152
|
-
this._ensureOpen();
|
|
153
|
-
this._native.setMinSize(width, height);
|
|
154
|
-
}
|
|
155
|
-
setMaxSize(width, height) {
|
|
156
|
-
this._ensureOpen();
|
|
157
|
-
this._native.setMaxSize(width, height);
|
|
158
|
-
}
|
|
159
|
-
setPosition(x, y) {
|
|
160
|
-
this._ensureOpen();
|
|
161
|
-
this._native.setPosition(x, y);
|
|
162
|
-
}
|
|
163
|
-
setResizable(resizable) {
|
|
164
|
-
this._ensureOpen();
|
|
165
|
-
this._native.setResizable(resizable);
|
|
166
|
-
}
|
|
167
|
-
setDecorations(decorations) {
|
|
168
|
-
this._ensureOpen();
|
|
169
|
-
this._native.setDecorations(decorations);
|
|
170
|
-
}
|
|
171
|
-
setAlwaysOnTop(alwaysOnTop) {
|
|
172
|
-
this._ensureOpen();
|
|
173
|
-
this._native.setAlwaysOnTop(alwaysOnTop);
|
|
174
|
-
}
|
|
175
|
-
/**
|
|
176
|
-
* Set the window icon from a PNG or ICO file path.
|
|
177
|
-
* On macOS this is silently ignored (macOS doesn't support per-window icons).
|
|
178
|
-
* Relative paths resolve from the working directory.
|
|
179
|
-
*/
|
|
180
|
-
setIcon(path) {
|
|
181
|
-
this._ensureOpen();
|
|
182
|
-
this._native.setIcon(path);
|
|
183
|
-
}
|
|
184
|
-
show() {
|
|
185
|
-
this._ensureOpen();
|
|
186
|
-
this._native.show();
|
|
187
|
-
}
|
|
188
|
-
hide() {
|
|
189
|
-
this._ensureOpen();
|
|
190
|
-
this._native.hide();
|
|
191
|
-
}
|
|
192
|
-
close() {
|
|
193
|
-
this._ensureOpen();
|
|
194
|
-
this._native.close();
|
|
195
|
-
}
|
|
196
|
-
focus() {
|
|
197
|
-
this._ensureOpen();
|
|
198
|
-
this._native.focus();
|
|
199
|
-
}
|
|
200
|
-
maximize() {
|
|
201
|
-
this._ensureOpen();
|
|
202
|
-
this._native.maximize();
|
|
203
|
-
}
|
|
204
|
-
minimize() {
|
|
205
|
-
this._ensureOpen();
|
|
206
|
-
this._native.minimize();
|
|
207
|
-
}
|
|
208
|
-
unmaximize() {
|
|
209
|
-
this._ensureOpen();
|
|
210
|
-
this._native.unmaximize();
|
|
211
|
-
}
|
|
212
|
-
reload() {
|
|
213
|
-
this._ensureOpen();
|
|
214
|
-
this._native.reload();
|
|
215
|
-
}
|
|
216
|
-
/**
|
|
217
|
-
* Register a handler for messages from the webview.
|
|
218
|
-
*
|
|
219
|
-
* @security **No origin filtering.** The raw `onMessage` API does not
|
|
220
|
-
* enforce origin restrictions. If your webview navigates to untrusted
|
|
221
|
-
* URLs, validate the `sourceUrl` parameter before processing messages.
|
|
222
|
-
* For automatic origin filtering, use `createChannel()` with the
|
|
223
|
-
* `trustedOrigins` option from `native-window-ipc`.
|
|
224
|
-
*
|
|
225
|
-
* @security **No rate limiting.** Messages from the webview are delivered
|
|
226
|
-
* without throttling. A malicious page can flood the host with messages.
|
|
227
|
-
* Consider implementing application-level rate limiting if loading
|
|
228
|
-
* untrusted content.
|
|
229
|
-
*/
|
|
230
|
-
onMessage(callback) {
|
|
231
|
-
this._ensureOpen();
|
|
232
|
-
this._native.onMessage(callback);
|
|
233
|
-
}
|
|
234
|
-
onResize(callback) {
|
|
235
|
-
this._ensureOpen();
|
|
236
|
-
this._native.onResize(callback);
|
|
237
|
-
}
|
|
238
|
-
onMove(callback) {
|
|
239
|
-
this._ensureOpen();
|
|
240
|
-
this._native.onMove(callback);
|
|
241
|
-
}
|
|
242
|
-
onFocus(callback) {
|
|
243
|
-
this._ensureOpen();
|
|
244
|
-
this._native.onFocus(callback);
|
|
245
|
-
}
|
|
246
|
-
onBlur(callback) {
|
|
247
|
-
this._ensureOpen();
|
|
248
|
-
this._native.onBlur(callback);
|
|
249
|
-
}
|
|
250
|
-
onPageLoad(callback) {
|
|
251
|
-
this._ensureOpen();
|
|
252
|
-
this._native.onPageLoad(callback);
|
|
253
|
-
}
|
|
254
|
-
onTitleChanged(callback) {
|
|
255
|
-
this._ensureOpen();
|
|
256
|
-
this._native.onTitleChanged(callback);
|
|
257
|
-
}
|
|
258
|
-
onReload(callback) {
|
|
259
|
-
this._ensureOpen();
|
|
260
|
-
this._native.onReload(callback);
|
|
261
|
-
}
|
|
262
|
-
/**
|
|
263
|
-
* Register a handler for blocked navigation events.
|
|
264
|
-
* Fired when a navigation is blocked by the {@link WindowOptions.allowedHosts}
|
|
265
|
-
* restriction. Receives the URL that was blocked.
|
|
266
|
-
*
|
|
267
|
-
* @example
|
|
268
|
-
* ```ts
|
|
269
|
-
* win.onNavigationBlocked((url) => {
|
|
270
|
-
* console.log("Blocked navigation to:", url);
|
|
271
|
-
* });
|
|
272
|
-
* ```
|
|
273
|
-
*/
|
|
274
|
-
onNavigationBlocked(callback) {
|
|
275
|
-
this._ensureOpen();
|
|
276
|
-
this._native.onNavigationBlocked(callback);
|
|
277
|
-
}
|
|
278
|
-
/**
|
|
279
|
-
* Validate and parse a raw cookies JSON array from the native layer.
|
|
280
|
-
* Returns a cleaned {@link CookieInfo} array or `null` if the payload
|
|
281
|
-
* is malformed.
|
|
282
|
-
*
|
|
283
|
-
* @internal
|
|
284
|
-
*/
|
|
285
|
-
_validateCookies(raw) {
|
|
286
|
-
let parsed;
|
|
287
|
-
try {
|
|
288
|
-
parsed = JSON.parse(raw);
|
|
289
|
-
} catch {
|
|
290
|
-
return null;
|
|
291
|
-
}
|
|
292
|
-
if (!Array.isArray(parsed)) return null;
|
|
293
|
-
const cookies = [];
|
|
294
|
-
for (const item of parsed) {
|
|
295
|
-
if (typeof item !== "object" || item === null) continue;
|
|
296
|
-
const obj = item;
|
|
297
|
-
if (typeof obj.name !== "string" || typeof obj.value !== "string") continue;
|
|
298
|
-
if (typeof obj.domain !== "string" || typeof obj.path !== "string") continue;
|
|
299
|
-
if (typeof obj.httpOnly !== "boolean" || typeof obj.secure !== "boolean") continue;
|
|
300
|
-
if (typeof obj.sameSite !== "string" || typeof obj.expires !== "number") continue;
|
|
301
|
-
cookies.push({
|
|
302
|
-
name: obj.name,
|
|
303
|
-
value: obj.value,
|
|
304
|
-
domain: obj.domain,
|
|
305
|
-
path: obj.path,
|
|
306
|
-
httpOnly: obj.httpOnly,
|
|
307
|
-
secure: obj.secure,
|
|
308
|
-
sameSite: obj.sameSite,
|
|
309
|
-
expires: obj.expires
|
|
310
|
-
});
|
|
311
|
-
}
|
|
312
|
-
return cookies;
|
|
313
|
-
}
|
|
314
|
-
/**
|
|
315
|
-
* Query cookies from the native cookie store.
|
|
316
|
-
*
|
|
317
|
-
* Returns a Promise that resolves with validated {@link CookieInfo} objects,
|
|
318
|
-
* including `HttpOnly` cookies that are invisible to `document.cookie`.
|
|
319
|
-
*
|
|
320
|
-
* - **macOS**: Uses `WKHTTPCookieStore.getAllCookies` with client-side
|
|
321
|
-
* URL filtering (domain + path match).
|
|
322
|
-
* - **Windows**: Uses `ICoreWebView2CookieManager.GetCookies` which
|
|
323
|
-
* filters by URI natively.
|
|
324
|
-
*
|
|
325
|
-
* @param url If provided, only cookies matching this URL are returned.
|
|
326
|
-
* If omitted, all cookies in the webview's cookie store are returned.
|
|
327
|
-
*
|
|
328
|
-
* @example
|
|
329
|
-
* ```ts
|
|
330
|
-
* const cookies = await win.getCookies("https://example.com");
|
|
331
|
-
* const session = cookies.find((c) => c.name === "session_id");
|
|
332
|
-
* if (session) console.log("Session:", session.value, "HttpOnly:", session.httpOnly);
|
|
333
|
-
* ```
|
|
334
|
-
*/
|
|
335
|
-
getCookies(url) {
|
|
336
|
-
this._ensureOpen();
|
|
337
|
-
return new Promise((resolve, reject) => {
|
|
338
|
-
const timeout = setTimeout(() => {
|
|
339
|
-
reject(/* @__PURE__ */ new Error("getCookies() timed out after 10 seconds"));
|
|
340
|
-
}, 1e4);
|
|
341
|
-
this._native.onCookies((raw) => {
|
|
342
|
-
clearTimeout(timeout);
|
|
343
|
-
const validated = this._validateCookies(raw);
|
|
344
|
-
if (validated) resolve(validated);
|
|
345
|
-
else reject(/* @__PURE__ */ new Error("Failed to parse cookie response"));
|
|
346
|
-
});
|
|
347
|
-
this._native.getCookies(url);
|
|
348
|
-
});
|
|
349
|
-
}
|
|
350
|
-
/**
|
|
351
|
-
* Clear cookies from the native cookie store.
|
|
352
|
-
*
|
|
353
|
-
* - If `host` is provided, only cookies whose domain matches that host
|
|
354
|
-
* are deleted (e.g. `"example.com"` deletes `.example.com` cookies).
|
|
355
|
-
* - If omitted, all cookies in the webview's cookie store are cleared.
|
|
356
|
-
*
|
|
357
|
-
* @example
|
|
358
|
-
* ```ts
|
|
359
|
-
* // Clear all cookies
|
|
360
|
-
* win.clearCookies();
|
|
361
|
-
*
|
|
362
|
-
* // Clear cookies for a specific host
|
|
363
|
-
* win.clearCookies("example.com");
|
|
364
|
-
* ```
|
|
365
|
-
*/
|
|
366
|
-
clearCookies(host) {
|
|
367
|
-
this._ensureOpen();
|
|
368
|
-
this._native.clearCookies(host);
|
|
369
|
-
}
|
|
370
|
-
};
|
|
55
|
+
var loadHtmlOrigin = _nativeBinding.loadHtmlOrigin;
|
|
371
56
|
/**
|
|
372
57
|
* Escape a string for safe embedding inside a JavaScript string literal.
|
|
373
58
|
* Handles backslashes, double quotes, newlines, carriage returns, null
|
|
@@ -379,14 +64,30 @@ var NativeWindow = class {
|
|
|
379
64
|
*
|
|
380
65
|
* @example
|
|
381
66
|
* ```ts
|
|
382
|
-
* import { NativeWindow, sanitizeForJs } from "
|
|
67
|
+
* import { NativeWindow, sanitizeForJs } from "@nativewindow/webview";
|
|
383
68
|
*
|
|
384
69
|
* const userInput = 'He said "hello"\n<script>alert(1)<\/script>';
|
|
385
|
-
* win.
|
|
70
|
+
* win.evaluateJs(`display("${sanitizeForJs(userInput)}")`);
|
|
386
71
|
* ```
|
|
387
72
|
*/
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
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;
|
|
391
92
|
//#endregion
|
|
392
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.
|
|
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": {
|
|
@@ -23,8 +23,6 @@
|
|
|
23
23
|
],
|
|
24
24
|
"files": [
|
|
25
25
|
"dist",
|
|
26
|
-
"native-window.js",
|
|
27
|
-
"native-window.d.ts",
|
|
28
26
|
"README.md",
|
|
29
27
|
"LICENSE"
|
|
30
28
|
],
|
|
@@ -39,8 +37,8 @@
|
|
|
39
37
|
}
|
|
40
38
|
},
|
|
41
39
|
"scripts": {
|
|
42
|
-
"build": "napi build --release --platform && vite build",
|
|
43
|
-
"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",
|
|
44
42
|
"build:ts": "vite build",
|
|
45
43
|
"version": "napi version",
|
|
46
44
|
"fuzz": "cargo +nightly fuzz list --fuzz-dir fuzz",
|
|
@@ -54,7 +52,7 @@
|
|
|
54
52
|
},
|
|
55
53
|
"devDependencies": {
|
|
56
54
|
"@napi-rs/cli": "^3.6.0",
|
|
57
|
-
"@types/
|
|
55
|
+
"@types/node": "^25.5.2",
|
|
58
56
|
"vite": "^8.0.3",
|
|
59
57
|
"vite-plugin-dts": "^4.5.4"
|
|
60
58
|
},
|
|
@@ -62,12 +60,12 @@
|
|
|
62
60
|
"typescript": "^6.0.2"
|
|
63
61
|
},
|
|
64
62
|
"optionalDependencies": {
|
|
65
|
-
"@nativewindow/webview-darwin-arm64": "1.0.
|
|
66
|
-
"@nativewindow/webview-darwin-x64": "1.0.
|
|
67
|
-
"@nativewindow/webview-linux-arm64-gnu": "1.0.
|
|
68
|
-
"@nativewindow/webview-linux-x64-gnu": "1.0.
|
|
69
|
-
"@nativewindow/webview-win32-arm64-msvc": "1.0.
|
|
70
|
-
"@nativewindow/webview-win32-x64-msvc": "1.0.
|
|
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"
|
|
71
69
|
},
|
|
72
70
|
"napi": {
|
|
73
71
|
"binaryName": "native-window",
|
package/native-window.d.ts
DELETED
|
@@ -1,264 +0,0 @@
|
|
|
1
|
-
/* eslint-disable */
|
|
2
|
-
// Auto-generated type declarations for the native addon.
|
|
3
|
-
// These will be overwritten by `napi build` but serve as
|
|
4
|
-
// a reference during development.
|
|
5
|
-
|
|
6
|
-
export interface WindowOptions {
|
|
7
|
-
/** Window title. Default: "" */
|
|
8
|
-
title?: string;
|
|
9
|
-
/** Inner width in logical pixels. Default: 800 */
|
|
10
|
-
width?: number;
|
|
11
|
-
/** Inner height in logical pixels. Default: 600 */
|
|
12
|
-
height?: number;
|
|
13
|
-
/** X position in screen coordinates */
|
|
14
|
-
x?: number;
|
|
15
|
-
/** Y position in screen coordinates */
|
|
16
|
-
y?: number;
|
|
17
|
-
/** Minimum inner width */
|
|
18
|
-
minWidth?: number;
|
|
19
|
-
/** Minimum inner height */
|
|
20
|
-
minHeight?: number;
|
|
21
|
-
/** Maximum inner width */
|
|
22
|
-
maxWidth?: number;
|
|
23
|
-
/** Maximum inner height */
|
|
24
|
-
maxHeight?: number;
|
|
25
|
-
/** Allow resizing. Default: true */
|
|
26
|
-
resizable?: boolean;
|
|
27
|
-
/** Show window decorations (title bar, borders). Default: true */
|
|
28
|
-
decorations?: boolean;
|
|
29
|
-
/** Transparent window background. Default: false */
|
|
30
|
-
transparent?: boolean;
|
|
31
|
-
/** Always on top of other windows. Default: false */
|
|
32
|
-
alwaysOnTop?: boolean;
|
|
33
|
-
/** Initially visible. Default: true */
|
|
34
|
-
visible?: boolean;
|
|
35
|
-
/** Enable devtools. Default: false */
|
|
36
|
-
devtools?: boolean;
|
|
37
|
-
/**
|
|
38
|
-
* Content Security Policy to inject at document start.
|
|
39
|
-
* When set, a `<meta http-equiv="Content-Security-Policy">` tag is injected
|
|
40
|
-
* before any page scripts run.
|
|
41
|
-
*
|
|
42
|
-
* **Limitation:** The CSP is applied via a `<meta>` tag at `DOMContentLoaded`,
|
|
43
|
-
* so scripts executing before that event are not restricted. Meta-tag CSP also
|
|
44
|
-
* cannot enforce `frame-ancestors` or `report-uri` directives. For stronger
|
|
45
|
-
* enforcement, serve pages via the custom protocol handler with a real HTTP
|
|
46
|
-
* `Content-Security-Policy` header.
|
|
47
|
-
*
|
|
48
|
-
* @example `"default-src 'self'; script-src 'self' 'unsafe-inline'"`
|
|
49
|
-
*/
|
|
50
|
-
csp?: string;
|
|
51
|
-
/**
|
|
52
|
-
* Trusted origins for IPC messages at the native layer.
|
|
53
|
-
* When set, only messages whose source URL origin matches one of these
|
|
54
|
-
* entries are forwarded to the host. Messages from other origins are
|
|
55
|
-
* silently dropped.
|
|
56
|
-
*
|
|
57
|
-
* Each entry should be a full origin string (scheme + host + optional port),
|
|
58
|
-
* e.g. `"https://example.com"`. No trailing slash.
|
|
59
|
-
*
|
|
60
|
-
* @security Defense-in-depth. For application-level origin filtering,
|
|
61
|
-
* use `trustedOrigins` in `createChannel()` from `native-window-ipc`.
|
|
62
|
-
*
|
|
63
|
-
* @example `["https://myapp.com", "https://cdn.myapp.com"]`
|
|
64
|
-
*/
|
|
65
|
-
trustedOrigins?: string[];
|
|
66
|
-
/**
|
|
67
|
-
* Allowed hosts for navigation restriction.
|
|
68
|
-
* When set and non-empty, ALL navigations (including `loadUrl()`, link
|
|
69
|
-
* clicks, form submissions, and redirects) are restricted to URLs whose
|
|
70
|
-
* host matches one of these patterns.
|
|
71
|
-
*
|
|
72
|
-
* Supports wildcard prefixes: `"*.example.com"` matches any subdomain
|
|
73
|
-
* of `example.com` and `example.com` itself.
|
|
74
|
-
*
|
|
75
|
-
* Internal navigations (`about:blank`, `loadHtml()` content) are always
|
|
76
|
-
* permitted. When unset or empty, all hosts are allowed.
|
|
77
|
-
*
|
|
78
|
-
* @example `["myapp.com", "*.cdn.myapp.com"]`
|
|
79
|
-
*/
|
|
80
|
-
allowedHosts?: string[];
|
|
81
|
-
/**
|
|
82
|
-
* Allow the webview to access the camera when requested.
|
|
83
|
-
* Default: false (all camera requests are denied).
|
|
84
|
-
* @note Not yet enforced in the wry backend. The OS default (prompt user) applies.
|
|
85
|
-
*/
|
|
86
|
-
allowCamera?: boolean;
|
|
87
|
-
/**
|
|
88
|
-
* Allow the webview to access the microphone when requested.
|
|
89
|
-
* Default: false (all microphone requests are denied).
|
|
90
|
-
* @note Not yet enforced in the wry backend. The OS default (prompt user) applies.
|
|
91
|
-
*/
|
|
92
|
-
allowMicrophone?: boolean;
|
|
93
|
-
/**
|
|
94
|
-
* Allow the webview to use the File System Access API
|
|
95
|
-
* (`showOpenFilePicker`, `showSaveFilePicker`, `showDirectoryPicker`).
|
|
96
|
-
* Default: false (all file system access requests are denied).
|
|
97
|
-
* @note Not yet enforced in the wry backend. The OS default applies.
|
|
98
|
-
*/
|
|
99
|
-
allowFileSystem?: boolean;
|
|
100
|
-
|
|
101
|
-
/**
|
|
102
|
-
* Path to a PNG or ICO file for the window icon (title bar).
|
|
103
|
-
* On macOS this option is silently ignored (macOS doesn't support
|
|
104
|
-
* per-window icons). Relative paths resolve from the working directory.
|
|
105
|
-
*/
|
|
106
|
-
icon?: string;
|
|
107
|
-
/**
|
|
108
|
-
* Run the webview in incognito (private) mode.
|
|
109
|
-
* When `true`, no cookies, cache, or other browsing data are persisted to disk.
|
|
110
|
-
* Each window starts with a clean, isolated session and all data is discarded
|
|
111
|
-
* when the window closes.
|
|
112
|
-
*
|
|
113
|
-
* Platform notes:
|
|
114
|
-
* - **macOS**: Uses `WKWebsiteDataStore.nonPersistentDataStore()` (WKWebView).
|
|
115
|
-
* - **Windows**: Enables `IsInPrivateModeEnabled` on the WebView2 controller.
|
|
116
|
-
* - **Linux**: Uses a temporary in-memory WebContext (no persistent storage).
|
|
117
|
-
*
|
|
118
|
-
* Default: `false`
|
|
119
|
-
*/
|
|
120
|
-
incognito?: boolean;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
export class NativeWindow {
|
|
124
|
-
constructor(options?: WindowOptions);
|
|
125
|
-
|
|
126
|
-
/** Unique window ID */
|
|
127
|
-
readonly id: number;
|
|
128
|
-
|
|
129
|
-
// Content loading
|
|
130
|
-
loadUrl(url: string): void;
|
|
131
|
-
loadHtml(html: string): void;
|
|
132
|
-
evaluateJs(script: string): void;
|
|
133
|
-
postMessage(message: string): void;
|
|
134
|
-
|
|
135
|
-
// Window control
|
|
136
|
-
setTitle(title: string): void;
|
|
137
|
-
setSize(width: number, height: number): void;
|
|
138
|
-
setMinSize(width: number, height: number): void;
|
|
139
|
-
setMaxSize(width: number, height: number): void;
|
|
140
|
-
setPosition(x: number, y: number): void;
|
|
141
|
-
setResizable(resizable: boolean): void;
|
|
142
|
-
setDecorations(decorations: boolean): void;
|
|
143
|
-
setAlwaysOnTop(alwaysOnTop: boolean): void;
|
|
144
|
-
/** Set the window icon from a PNG or ICO file path. Ignored on macOS. */
|
|
145
|
-
setIcon(path: string): void;
|
|
146
|
-
|
|
147
|
-
// Window state
|
|
148
|
-
show(): void;
|
|
149
|
-
hide(): void;
|
|
150
|
-
close(): void;
|
|
151
|
-
focus(): void;
|
|
152
|
-
maximize(): void;
|
|
153
|
-
minimize(): void;
|
|
154
|
-
unmaximize(): void;
|
|
155
|
-
reload(): void;
|
|
156
|
-
|
|
157
|
-
// Event handlers
|
|
158
|
-
onMessage(callback: (message: string, sourceUrl: string) => void): void;
|
|
159
|
-
onClose(callback: () => void): void;
|
|
160
|
-
onResize(callback: (width: number, height: number) => void): void;
|
|
161
|
-
onMove(callback: (x: number, y: number) => void): void;
|
|
162
|
-
onFocus(callback: () => void): void;
|
|
163
|
-
onBlur(callback: () => void): void;
|
|
164
|
-
onPageLoad(callback: (event: "started" | "finished", url: string) => void): void;
|
|
165
|
-
onTitleChanged(callback: (title: string) => void): void;
|
|
166
|
-
onReload(callback: () => void): void;
|
|
167
|
-
onNavigationBlocked(callback: (url: string) => void): void;
|
|
168
|
-
|
|
169
|
-
// Cookie access
|
|
170
|
-
getCookies(url?: string): void;
|
|
171
|
-
onCookies(callback: (cookies: string) => void): void;
|
|
172
|
-
clearCookies(host?: string): void;
|
|
173
|
-
|
|
174
|
-
// Devtools
|
|
175
|
-
/** Open the browser devtools panel. Requires `devtools: true` in options. */
|
|
176
|
-
openDevtools(): void;
|
|
177
|
-
/** Close the browser devtools panel. */
|
|
178
|
-
closeDevtools(): void;
|
|
179
|
-
/** Check whether the devtools panel is currently open. */
|
|
180
|
-
isDevtoolsOpen(): boolean;
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
/** Initialize the native window system. Must be called once before creating any windows. */
|
|
184
|
-
export function init(): void;
|
|
185
|
-
|
|
186
|
-
/** Process pending native UI events. Call periodically (~16ms) to keep windows responsive. */
|
|
187
|
-
export function pumpEvents(): void;
|
|
188
|
-
|
|
189
|
-
/** Information about the native webview runtime. */
|
|
190
|
-
export interface RuntimeInfo {
|
|
191
|
-
/** Whether the webview runtime is available. */
|
|
192
|
-
available: boolean;
|
|
193
|
-
/** The version string of the runtime, if detected. */
|
|
194
|
-
version?: string;
|
|
195
|
-
/** The current platform: "macos", "windows", "linux", or "unsupported". */
|
|
196
|
-
platform: "macos" | "windows" | "linux" | "unsupported";
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
/**
|
|
200
|
-
* Check if the native webview runtime is available.
|
|
201
|
-
*
|
|
202
|
-
* - **macOS**: Always returns available (WKWebView is a system framework).
|
|
203
|
-
* - **Windows**: Detects WebView2 via `GetAvailableCoreWebView2BrowserVersionString`.
|
|
204
|
-
* - **Linux**: Always returns available (WebKitGTK is required at build time).
|
|
205
|
-
* - **Other**: Returns `{ available: false, platform: "unsupported" }`.
|
|
206
|
-
*/
|
|
207
|
-
export function checkRuntime(): RuntimeInfo;
|
|
208
|
-
|
|
209
|
-
/**
|
|
210
|
-
* Ensure the native webview runtime is available, installing it if necessary.
|
|
211
|
-
*
|
|
212
|
-
* - **macOS**: Returns immediately (WKWebView is always available).
|
|
213
|
-
* - **Windows**: If WebView2 is missing, downloads the Evergreen Bootstrapper
|
|
214
|
-
* (~2MB) from Microsoft and runs it silently. Throws on failure.
|
|
215
|
-
* - **Linux**: Returns immediately (WebKitGTK is required at build time).
|
|
216
|
-
* - **Other**: Throws an error.
|
|
217
|
-
*
|
|
218
|
-
* @security This function downloads and executes a Microsoft-signed binary
|
|
219
|
-
* from the internet (Windows only). Authenticode signature verification is
|
|
220
|
-
* performed before execution; unverified binaries are never run.
|
|
221
|
-
*
|
|
222
|
-
* **Do not call in an elevated (Administrator) context without explicit user
|
|
223
|
-
* consent.** The silent installer applies system-wide. Prefer calling
|
|
224
|
-
* {@link checkRuntime} first to avoid unnecessary network requests when the
|
|
225
|
-
* runtime is already present.
|
|
226
|
-
*/
|
|
227
|
-
export function ensureRuntime(): RuntimeInfo;
|
|
228
|
-
|
|
229
|
-
/**
|
|
230
|
-
* Escape a string for safe embedding inside a JavaScript string literal.
|
|
231
|
-
* Handles backslashes, quotes, newlines, null bytes, closing `</script>` tags,
|
|
232
|
-
* and Unicode line/paragraph separators (U+2028, U+2029).
|
|
233
|
-
*
|
|
234
|
-
* @security Use this when interpolating untrusted input into `win.unsafe.evaluateJs()` calls.
|
|
235
|
-
*
|
|
236
|
-
* @example
|
|
237
|
-
* ```ts
|
|
238
|
-
* import { sanitizeForJs } from "native-window";
|
|
239
|
-
*
|
|
240
|
-
* const userInput = 'He said "hello"\n<script>alert(1)</script>';
|
|
241
|
-
* win.unsafe.evaluateJs(`display("${sanitizeForJs(userInput)}")`);
|
|
242
|
-
* ```
|
|
243
|
-
*/
|
|
244
|
-
export function sanitizeForJs(input: string): string;
|
|
245
|
-
|
|
246
|
-
/**
|
|
247
|
-
* Returns the origin of pages loaded via `loadHtml()`.
|
|
248
|
-
*
|
|
249
|
-
* Use this in `trustedOrigins` to restrict IPC messages to only accept
|
|
250
|
-
* messages from `loadHtml()` content.
|
|
251
|
-
*
|
|
252
|
-
* - macOS/Linux: `"nativewindow://localhost"`
|
|
253
|
-
* - Windows: `"https://nativewindow.localhost"`
|
|
254
|
-
*
|
|
255
|
-
* @example
|
|
256
|
-
* ```ts
|
|
257
|
-
* import { NativeWindow, loadHtmlOrigin } from "@nativewindow/webview";
|
|
258
|
-
*
|
|
259
|
-
* const win = new NativeWindow({
|
|
260
|
-
* trustedOrigins: [loadHtmlOrigin()],
|
|
261
|
-
* });
|
|
262
|
-
* ```
|
|
263
|
-
*/
|
|
264
|
-
export function loadHtmlOrigin(): string;
|
package/native-window.js
DELETED
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
/* eslint-disable */
|
|
2
|
-
// JS loader for the native addon.
|
|
3
|
-
// Tries local .node files first (development), then per-platform npm packages (production).
|
|
4
|
-
|
|
5
|
-
import { createRequire } from "node:module";
|
|
6
|
-
|
|
7
|
-
const require = createRequire(import.meta.url);
|
|
8
|
-
const { platform, arch } = process;
|
|
9
|
-
|
|
10
|
-
const platforms = {
|
|
11
|
-
"darwin-arm64": {
|
|
12
|
-
pkg: "@nativewindow/webview-darwin-arm64",
|
|
13
|
-
file: "native-window.darwin-arm64.node",
|
|
14
|
-
},
|
|
15
|
-
"darwin-x64": {
|
|
16
|
-
pkg: "@nativewindow/webview-darwin-x64",
|
|
17
|
-
file: "native-window.darwin-x64.node",
|
|
18
|
-
},
|
|
19
|
-
"win32-x64": {
|
|
20
|
-
pkg: "@nativewindow/webview-win32-x64-msvc",
|
|
21
|
-
file: "native-window.win32-x64-msvc.node",
|
|
22
|
-
},
|
|
23
|
-
"win32-arm64": {
|
|
24
|
-
pkg: "@nativewindow/webview-win32-arm64-msvc",
|
|
25
|
-
file: "native-window.win32-arm64-msvc.node",
|
|
26
|
-
},
|
|
27
|
-
"linux-x64": {
|
|
28
|
-
pkg: "@nativewindow/webview-linux-x64-gnu",
|
|
29
|
-
file: "native-window.linux-x64-gnu.node",
|
|
30
|
-
},
|
|
31
|
-
"linux-arm64": {
|
|
32
|
-
pkg: "@nativewindow/webview-linux-arm64-gnu",
|
|
33
|
-
file: "native-window.linux-arm64-gnu.node",
|
|
34
|
-
},
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
const key = `${platform}-${arch}`;
|
|
38
|
-
const entry = platforms[key];
|
|
39
|
-
|
|
40
|
-
if (!entry) {
|
|
41
|
-
throw new Error(`Unsupported platform: ${key}`);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
const tryRequire = (id) => {
|
|
45
|
-
try {
|
|
46
|
-
return require(id);
|
|
47
|
-
} catch {
|
|
48
|
-
return null;
|
|
49
|
-
}
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
const nativeBinding = tryRequire(`./${entry.file}`) ?? tryRequire(entry.pkg);
|
|
53
|
-
|
|
54
|
-
if (!nativeBinding) {
|
|
55
|
-
throw new Error(
|
|
56
|
-
`Failed to load native binding for platform: ${key}. ` +
|
|
57
|
-
`Ensure the correct platform package is installed or the .node file exists.`,
|
|
58
|
-
);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
export const { NativeWindow, init, pumpEvents, checkRuntime, ensureRuntime, loadHtmlOrigin } =
|
|
62
|
-
nativeBinding;
|