@yodaos-pkg/ink 0.1.0 → 0.3.0
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 +81 -5
- package/dist/README.md +81 -5
- package/dist/env.js +424 -10
- package/dist/index.d.ts +62 -11
- package/dist/index.js +154 -14
- package/dist/pkg/README.md +4 -4
- package/dist/pkg/ink_web.d.ts +5 -5
- package/dist/pkg/ink_web.js +46 -20
- package/dist/pkg/ink_web_bg.wasm +0 -0
- package/dist/pkg/ink_web_bg.wasm.d.ts +5 -5
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -36,8 +36,7 @@ Before integrating the SDK, make sure you have one of these two inputs:
|
|
|
36
36
|
- This is a good fit when assets live on the server and the browser fetches
|
|
37
37
|
them on demand.
|
|
38
38
|
|
|
39
|
-
If you use the VFS flow,
|
|
40
|
-
`@yodaos-pkg/ink-vfs-server`.
|
|
39
|
+
If you use the VFS flow, provide your own HTTP VFS endpoint on the server side.
|
|
41
40
|
|
|
42
41
|
## Installation
|
|
43
42
|
|
|
@@ -47,10 +46,11 @@ If you use the VFS flow, the server side usually works together with
|
|
|
47
46
|
npm install @yodaos-pkg/ink
|
|
48
47
|
```
|
|
49
48
|
|
|
50
|
-
If you also want to use the VFS flow,
|
|
49
|
+
If you also want to use the VFS flow, prepare an HTTP endpoint that exposes:
|
|
51
50
|
|
|
52
|
-
```
|
|
53
|
-
|
|
51
|
+
```text
|
|
52
|
+
GET /apps/:appId/manifest
|
|
53
|
+
GET /apps/:appId/files/:path
|
|
54
54
|
```
|
|
55
55
|
|
|
56
56
|
## Core API
|
|
@@ -94,6 +94,54 @@ Creates an `InkView` instance and initializes the wasm runtime internally.
|
|
|
94
94
|
- Resolves to an `InkView` instance that can then call
|
|
95
95
|
`bindDomEvents()`, `openBundle()`, and `openFromVfs()`
|
|
96
96
|
|
|
97
|
+
### `configureNetwork(options)`
|
|
98
|
+
|
|
99
|
+
Configures host-controlled request interception for Ink network traffic.
|
|
100
|
+
|
|
101
|
+
**Parameters**
|
|
102
|
+
|
|
103
|
+
- `options.interceptor`
|
|
104
|
+
- Optional
|
|
105
|
+
- A function that receives the outgoing request and returns an action
|
|
106
|
+
- `options.proxyUrl`
|
|
107
|
+
- Optional
|
|
108
|
+
- A convenience option for rewriting requests through a proxy endpoint
|
|
109
|
+
- `options.targetSearchParam`
|
|
110
|
+
- Optional
|
|
111
|
+
- The query parameter name used when `proxyUrl` is provided
|
|
112
|
+
- `options.clear`
|
|
113
|
+
- Optional
|
|
114
|
+
- Clears the previously registered interceptor
|
|
115
|
+
|
|
116
|
+
**What it does**
|
|
117
|
+
|
|
118
|
+
- Registers a global Ink request interceptor
|
|
119
|
+
- Lets hosts continue, rewrite, or block outgoing requests
|
|
120
|
+
- Mirrors the shape of a WebView-style request interception hook
|
|
121
|
+
|
|
122
|
+
**Returns**
|
|
123
|
+
|
|
124
|
+
- `void`
|
|
125
|
+
|
|
126
|
+
### `createProxyUrlResolver(options)`
|
|
127
|
+
|
|
128
|
+
Creates a request interceptor that rewrites outgoing requests to a host-managed
|
|
129
|
+
proxy endpoint such as `'/__proxy?url=...'`.
|
|
130
|
+
|
|
131
|
+
**Parameters**
|
|
132
|
+
|
|
133
|
+
- `options.proxyUrl`
|
|
134
|
+
- Required
|
|
135
|
+
- The proxy endpoint to call
|
|
136
|
+
- `options.targetSearchParam`
|
|
137
|
+
- Optional
|
|
138
|
+
- The query parameter name that receives the original target URL
|
|
139
|
+
|
|
140
|
+
**Returns**
|
|
141
|
+
|
|
142
|
+
- `InkRequestInterceptor`
|
|
143
|
+
- A reusable interceptor for `configureNetwork()` or `initInk()`
|
|
144
|
+
|
|
97
145
|
### `view.bindDomEvents(options?)`
|
|
98
146
|
|
|
99
147
|
Binds common DOM events to the current `InkView`.
|
|
@@ -191,6 +239,9 @@ Fetches an Ink bundle from a remote HTTP VFS service and opens it.
|
|
|
191
239
|
- `options.headers?: HeadersInit`
|
|
192
240
|
- Optional
|
|
193
241
|
- Extra request headers
|
|
242
|
+
- `options.requestInterceptor?: InkRequestInterceptor`
|
|
243
|
+
- Optional
|
|
244
|
+
- Overrides the global interceptor for this VFS load only
|
|
194
245
|
- `options.initialPage?: string | null`
|
|
195
246
|
- Optional
|
|
196
247
|
- Sets the first page to open
|
|
@@ -203,6 +254,7 @@ Fetches an Ink bundle from a remote HTTP VFS service and opens it.
|
|
|
203
254
|
- Fetches the VFS manifest first
|
|
204
255
|
- Fetches each file listed in the manifest
|
|
205
256
|
- Reconstructs the bundle in the browser
|
|
257
|
+
- Applies the request interceptor when one is configured
|
|
206
258
|
- Calls `openBundle()` automatically
|
|
207
259
|
|
|
208
260
|
**Returns**
|
|
@@ -213,6 +265,30 @@ Fetches an Ink bundle from a remote HTTP VFS service and opens it.
|
|
|
213
265
|
- `manifest: VfsManifest`
|
|
214
266
|
- `files: Map<string, Uint8Array>`
|
|
215
267
|
|
|
268
|
+
### `initInk(options)`
|
|
269
|
+
|
|
270
|
+
Initializes the wasm runtime and optionally installs a host networking policy.
|
|
271
|
+
|
|
272
|
+
**Parameters**
|
|
273
|
+
|
|
274
|
+
- `options.wasmUrl?: string | URL | Request`
|
|
275
|
+
- Optional
|
|
276
|
+
- Custom URL for the wasm binary
|
|
277
|
+
- `options.moduleOrPath?: RequestInfo | URL | Response | BufferSource | WebAssembly.Module`
|
|
278
|
+
- Optional
|
|
279
|
+
- Custom wasm module input supported by `wasm-bindgen`
|
|
280
|
+
- `options.requestInterceptor?: InkRequestInterceptor`
|
|
281
|
+
- Optional
|
|
282
|
+
- Installs a host request interceptor before Ink networking starts
|
|
283
|
+
- `options.proxyUrl?: string`
|
|
284
|
+
- Optional
|
|
285
|
+
- Shorthand for a proxy-based interceptor
|
|
286
|
+
|
|
287
|
+
**Returns**
|
|
288
|
+
|
|
289
|
+
- `Promise<{ InkWebView, getInkVersion }>`
|
|
290
|
+
- Resolves to the wasm bindings
|
|
291
|
+
|
|
216
292
|
### `view.startRendering()`
|
|
217
293
|
|
|
218
294
|
Starts the continuous render loop.
|
package/dist/README.md
CHANGED
|
@@ -36,8 +36,7 @@ Before integrating the SDK, make sure you have one of these two inputs:
|
|
|
36
36
|
- This is a good fit when assets live on the server and the browser fetches
|
|
37
37
|
them on demand.
|
|
38
38
|
|
|
39
|
-
If you use the VFS flow,
|
|
40
|
-
`@yodaos-pkg/ink-vfs-server`.
|
|
39
|
+
If you use the VFS flow, provide your own HTTP VFS endpoint on the server side.
|
|
41
40
|
|
|
42
41
|
## Installation
|
|
43
42
|
|
|
@@ -47,10 +46,11 @@ If you use the VFS flow, the server side usually works together with
|
|
|
47
46
|
npm install @yodaos-pkg/ink
|
|
48
47
|
```
|
|
49
48
|
|
|
50
|
-
If you also want to use the VFS flow,
|
|
49
|
+
If you also want to use the VFS flow, prepare an HTTP endpoint that exposes:
|
|
51
50
|
|
|
52
|
-
```
|
|
53
|
-
|
|
51
|
+
```text
|
|
52
|
+
GET /apps/:appId/manifest
|
|
53
|
+
GET /apps/:appId/files/:path
|
|
54
54
|
```
|
|
55
55
|
|
|
56
56
|
## Core API
|
|
@@ -94,6 +94,54 @@ Creates an `InkView` instance and initializes the wasm runtime internally.
|
|
|
94
94
|
- Resolves to an `InkView` instance that can then call
|
|
95
95
|
`bindDomEvents()`, `openBundle()`, and `openFromVfs()`
|
|
96
96
|
|
|
97
|
+
### `configureNetwork(options)`
|
|
98
|
+
|
|
99
|
+
Configures host-controlled request interception for Ink network traffic.
|
|
100
|
+
|
|
101
|
+
**Parameters**
|
|
102
|
+
|
|
103
|
+
- `options.interceptor`
|
|
104
|
+
- Optional
|
|
105
|
+
- A function that receives the outgoing request and returns an action
|
|
106
|
+
- `options.proxyUrl`
|
|
107
|
+
- Optional
|
|
108
|
+
- A convenience option for rewriting requests through a proxy endpoint
|
|
109
|
+
- `options.targetSearchParam`
|
|
110
|
+
- Optional
|
|
111
|
+
- The query parameter name used when `proxyUrl` is provided
|
|
112
|
+
- `options.clear`
|
|
113
|
+
- Optional
|
|
114
|
+
- Clears the previously registered interceptor
|
|
115
|
+
|
|
116
|
+
**What it does**
|
|
117
|
+
|
|
118
|
+
- Registers a global Ink request interceptor
|
|
119
|
+
- Lets hosts continue, rewrite, or block outgoing requests
|
|
120
|
+
- Mirrors the shape of a WebView-style request interception hook
|
|
121
|
+
|
|
122
|
+
**Returns**
|
|
123
|
+
|
|
124
|
+
- `void`
|
|
125
|
+
|
|
126
|
+
### `createProxyUrlResolver(options)`
|
|
127
|
+
|
|
128
|
+
Creates a request interceptor that rewrites outgoing requests to a host-managed
|
|
129
|
+
proxy endpoint such as `'/__proxy?url=...'`.
|
|
130
|
+
|
|
131
|
+
**Parameters**
|
|
132
|
+
|
|
133
|
+
- `options.proxyUrl`
|
|
134
|
+
- Required
|
|
135
|
+
- The proxy endpoint to call
|
|
136
|
+
- `options.targetSearchParam`
|
|
137
|
+
- Optional
|
|
138
|
+
- The query parameter name that receives the original target URL
|
|
139
|
+
|
|
140
|
+
**Returns**
|
|
141
|
+
|
|
142
|
+
- `InkRequestInterceptor`
|
|
143
|
+
- A reusable interceptor for `configureNetwork()` or `initInk()`
|
|
144
|
+
|
|
97
145
|
### `view.bindDomEvents(options?)`
|
|
98
146
|
|
|
99
147
|
Binds common DOM events to the current `InkView`.
|
|
@@ -191,6 +239,9 @@ Fetches an Ink bundle from a remote HTTP VFS service and opens it.
|
|
|
191
239
|
- `options.headers?: HeadersInit`
|
|
192
240
|
- Optional
|
|
193
241
|
- Extra request headers
|
|
242
|
+
- `options.requestInterceptor?: InkRequestInterceptor`
|
|
243
|
+
- Optional
|
|
244
|
+
- Overrides the global interceptor for this VFS load only
|
|
194
245
|
- `options.initialPage?: string | null`
|
|
195
246
|
- Optional
|
|
196
247
|
- Sets the first page to open
|
|
@@ -203,6 +254,7 @@ Fetches an Ink bundle from a remote HTTP VFS service and opens it.
|
|
|
203
254
|
- Fetches the VFS manifest first
|
|
204
255
|
- Fetches each file listed in the manifest
|
|
205
256
|
- Reconstructs the bundle in the browser
|
|
257
|
+
- Applies the request interceptor when one is configured
|
|
206
258
|
- Calls `openBundle()` automatically
|
|
207
259
|
|
|
208
260
|
**Returns**
|
|
@@ -213,6 +265,30 @@ Fetches an Ink bundle from a remote HTTP VFS service and opens it.
|
|
|
213
265
|
- `manifest: VfsManifest`
|
|
214
266
|
- `files: Map<string, Uint8Array>`
|
|
215
267
|
|
|
268
|
+
### `initInk(options)`
|
|
269
|
+
|
|
270
|
+
Initializes the wasm runtime and optionally installs a host networking policy.
|
|
271
|
+
|
|
272
|
+
**Parameters**
|
|
273
|
+
|
|
274
|
+
- `options.wasmUrl?: string | URL | Request`
|
|
275
|
+
- Optional
|
|
276
|
+
- Custom URL for the wasm binary
|
|
277
|
+
- `options.moduleOrPath?: RequestInfo | URL | Response | BufferSource | WebAssembly.Module`
|
|
278
|
+
- Optional
|
|
279
|
+
- Custom wasm module input supported by `wasm-bindgen`
|
|
280
|
+
- `options.requestInterceptor?: InkRequestInterceptor`
|
|
281
|
+
- Optional
|
|
282
|
+
- Installs a host request interceptor before Ink networking starts
|
|
283
|
+
- `options.proxyUrl?: string`
|
|
284
|
+
- Optional
|
|
285
|
+
- Shorthand for a proxy-based interceptor
|
|
286
|
+
|
|
287
|
+
**Returns**
|
|
288
|
+
|
|
289
|
+
- `Promise<{ InkWebView, getInkVersion }>`
|
|
290
|
+
- Resolves to the wasm bindings
|
|
291
|
+
|
|
216
292
|
### `view.startRendering()`
|
|
217
293
|
|
|
218
294
|
Starts the continuous render loop.
|
package/dist/env.js
CHANGED
|
@@ -2,11 +2,190 @@ let wasmExports = null;
|
|
|
2
2
|
const allocationSizes = new Map();
|
|
3
3
|
const textDecoder = new TextDecoder('utf-8', { fatal: false });
|
|
4
4
|
const textEncoder = new TextEncoder();
|
|
5
|
+
let inkRequestInterceptor = null;
|
|
6
|
+
const hrtimeOriginNs =
|
|
7
|
+
typeof performance !== 'undefined' && typeof performance.now === 'function'
|
|
8
|
+
? BigInt(Math.floor(performance.now() * 1_000_000))
|
|
9
|
+
: 0n;
|
|
10
|
+
|
|
11
|
+
export function rquickjs_browser_date_now_us() {
|
|
12
|
+
return BigInt(Date.now()) * 1000n;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function rquickjs_browser_hrtime_ns() {
|
|
16
|
+
if (typeof performance !== 'undefined' && typeof performance.now === 'function') {
|
|
17
|
+
return BigInt(Math.floor(performance.now() * 1_000_000)) - hrtimeOriginNs;
|
|
18
|
+
}
|
|
19
|
+
return BigInt(Date.now()) * 1_000_000n;
|
|
20
|
+
}
|
|
5
21
|
|
|
6
22
|
export function __setWasmInstance(exports) {
|
|
7
23
|
wasmExports = exports;
|
|
8
24
|
}
|
|
9
25
|
|
|
26
|
+
function ensureFetchImplementation(fetchImpl) {
|
|
27
|
+
const resolved = fetchImpl || globalThis.fetch;
|
|
28
|
+
if (typeof resolved !== 'function') {
|
|
29
|
+
throw new Error('A fetch implementation is required for Ink networking.');
|
|
30
|
+
}
|
|
31
|
+
return resolved;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function headersToObject(headersLike) {
|
|
35
|
+
if (!headersLike) {
|
|
36
|
+
return {};
|
|
37
|
+
}
|
|
38
|
+
if (typeof Headers !== 'undefined' && headersLike instanceof Headers) {
|
|
39
|
+
const result = {};
|
|
40
|
+
for (const [name, value] of headersLike.entries()) {
|
|
41
|
+
result[name] = value;
|
|
42
|
+
}
|
|
43
|
+
return result;
|
|
44
|
+
}
|
|
45
|
+
if (Array.isArray(headersLike)) {
|
|
46
|
+
const result = {};
|
|
47
|
+
for (const entry of headersLike) {
|
|
48
|
+
if (!Array.isArray(entry) || entry.length < 2) {
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
result[String(entry[0])] = String(entry[1]);
|
|
52
|
+
}
|
|
53
|
+
return result;
|
|
54
|
+
}
|
|
55
|
+
if (headersLike && typeof headersLike === 'object') {
|
|
56
|
+
return Object.fromEntries(
|
|
57
|
+
Object.entries(headersLike).map(([name, value]) => [
|
|
58
|
+
name,
|
|
59
|
+
Array.isArray(value) ? value.join(', ') : String(value),
|
|
60
|
+
]),
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
return {};
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function cloneBody(body) {
|
|
67
|
+
if (body == null) {
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
if (typeof body === 'string') {
|
|
71
|
+
return body;
|
|
72
|
+
}
|
|
73
|
+
if (body instanceof Uint8Array) {
|
|
74
|
+
return new Uint8Array(body);
|
|
75
|
+
}
|
|
76
|
+
if (ArrayBuffer.isView(body)) {
|
|
77
|
+
return new Uint8Array(body.buffer.slice(body.byteOffset, body.byteOffset + body.byteLength));
|
|
78
|
+
}
|
|
79
|
+
if (body instanceof ArrayBuffer) {
|
|
80
|
+
return body.slice(0);
|
|
81
|
+
}
|
|
82
|
+
return body;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function normalizeRequest(input, init = {}, metadata = {}) {
|
|
86
|
+
const url = typeof input === 'string' ? input : String(input);
|
|
87
|
+
return {
|
|
88
|
+
url,
|
|
89
|
+
method: String(init.method || 'GET').toUpperCase(),
|
|
90
|
+
headers: headersToObject(init.headers),
|
|
91
|
+
body: cloneBody(init.body),
|
|
92
|
+
metadata: metadata && typeof metadata === 'object' ? { ...metadata } : {},
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function normalizeInterceptorResult(request, result) {
|
|
97
|
+
if (result == null || result === false) {
|
|
98
|
+
return {
|
|
99
|
+
url: request.url,
|
|
100
|
+
init: {
|
|
101
|
+
method: request.method,
|
|
102
|
+
headers: request.headers,
|
|
103
|
+
body: request.body,
|
|
104
|
+
},
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (typeof result !== 'object') {
|
|
109
|
+
throw new TypeError('Ink request interceptor must return an object, null, or undefined.');
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const action = result.action || 'rewrite';
|
|
113
|
+
if (action === 'continue') {
|
|
114
|
+
return {
|
|
115
|
+
url: request.url,
|
|
116
|
+
init: {
|
|
117
|
+
method: request.method,
|
|
118
|
+
headers: request.headers,
|
|
119
|
+
body: request.body,
|
|
120
|
+
},
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (action === 'block') {
|
|
125
|
+
throw new Error(result.reason || `Ink request blocked: ${request.url}`);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
if (action !== 'rewrite') {
|
|
129
|
+
throw new Error(`Unsupported Ink request interceptor action: ${action}`);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
return {
|
|
133
|
+
url: typeof result.url === 'string' && result.url ? result.url : request.url,
|
|
134
|
+
init: {
|
|
135
|
+
method: typeof result.method === 'string' && result.method ? result.method : request.method,
|
|
136
|
+
headers: result.headers ? headersToObject(result.headers) : request.headers,
|
|
137
|
+
body: Object.prototype.hasOwnProperty.call(result, 'body') ? result.body : request.body,
|
|
138
|
+
},
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
async function resolveInkFetchRequest(input, init = {}, metadata = {}, interceptorOverride = null) {
|
|
143
|
+
const request = normalizeRequest(input, init, metadata);
|
|
144
|
+
const interceptor = interceptorOverride || inkRequestInterceptor;
|
|
145
|
+
if (!interceptor) {
|
|
146
|
+
return {
|
|
147
|
+
url: request.url,
|
|
148
|
+
init: {
|
|
149
|
+
method: request.method,
|
|
150
|
+
headers: request.headers,
|
|
151
|
+
body: request.body,
|
|
152
|
+
},
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
const result = await interceptor(request);
|
|
156
|
+
return normalizeInterceptorResult(request, result);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
export function setInkRequestInterceptor(interceptor) {
|
|
160
|
+
if (interceptor != null && typeof interceptor !== 'function') {
|
|
161
|
+
throw new TypeError('Ink request interceptor must be a function, null, or undefined.');
|
|
162
|
+
}
|
|
163
|
+
inkRequestInterceptor = interceptor || null;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
export function clearInkRequestInterceptor() {
|
|
167
|
+
inkRequestInterceptor = null;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
export async function __inkFetch(input, init, metadata) {
|
|
171
|
+
const resolved = await resolveInkFetchRequest(input, init, metadata);
|
|
172
|
+
const fetchImpl = ensureFetchImplementation();
|
|
173
|
+
return fetchImpl(resolved.url, resolved.init);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
export async function fetchWithInkRequestInterceptor(input, init = {}, options = {}) {
|
|
177
|
+
const resolved = await resolveInkFetchRequest(
|
|
178
|
+
input,
|
|
179
|
+
init,
|
|
180
|
+
options.metadata,
|
|
181
|
+
options.interceptor || null,
|
|
182
|
+
);
|
|
183
|
+
const fetchImpl = ensureFetchImplementation(options.fetch);
|
|
184
|
+
return fetchImpl(resolved.url, resolved.init);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
globalThis.__inkFetch = __inkFetch;
|
|
188
|
+
|
|
10
189
|
function requireWasm() {
|
|
11
190
|
if (!wasmExports) {
|
|
12
191
|
throw new Error('Wasm exports are not initialized');
|
|
@@ -73,8 +252,243 @@ function consoleWrite(prefix, text) {
|
|
|
73
252
|
console.log(value);
|
|
74
253
|
}
|
|
75
254
|
|
|
76
|
-
function
|
|
77
|
-
|
|
255
|
+
function readCStringWithLength(ptr, maxBytes) {
|
|
256
|
+
ptr >>>= 0;
|
|
257
|
+
const bytes = memoryBytes();
|
|
258
|
+
let end = ptr;
|
|
259
|
+
const maxEnd = Math.min(bytes.length, ptr + Math.max(0, maxBytes | 0));
|
|
260
|
+
while (end < maxEnd && bytes[end] !== 0) {
|
|
261
|
+
end += 1;
|
|
262
|
+
}
|
|
263
|
+
return textDecoder.decode(bytes.subarray(ptr, end));
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
function normalizePrintfValue(value) {
|
|
267
|
+
if (typeof value === 'bigint') {
|
|
268
|
+
return value;
|
|
269
|
+
}
|
|
270
|
+
if (typeof value === 'number') {
|
|
271
|
+
return Number.isFinite(value) ? value : 0;
|
|
272
|
+
}
|
|
273
|
+
if (value == null) {
|
|
274
|
+
return 0;
|
|
275
|
+
}
|
|
276
|
+
return Number(value) || 0;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
function createDirectArgumentReader(values, offset) {
|
|
280
|
+
let index = offset;
|
|
281
|
+
return {
|
|
282
|
+
next() {
|
|
283
|
+
const value = index < values.length ? values[index] : 0;
|
|
284
|
+
index += 1;
|
|
285
|
+
return value;
|
|
286
|
+
},
|
|
287
|
+
nextInt32() {
|
|
288
|
+
return Number(normalizePrintfValue(this.next())) | 0;
|
|
289
|
+
},
|
|
290
|
+
nextUint32() {
|
|
291
|
+
return Number(normalizePrintfValue(this.next())) >>> 0;
|
|
292
|
+
},
|
|
293
|
+
nextPointer() {
|
|
294
|
+
return Number(normalizePrintfValue(this.next())) >>> 0;
|
|
295
|
+
},
|
|
296
|
+
nextFloat64() {
|
|
297
|
+
return Number(normalizePrintfValue(this.next()));
|
|
298
|
+
},
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
function createVaListReader(argsPtr) {
|
|
303
|
+
let cursor = argsPtr >>> 0;
|
|
304
|
+
const view = memoryView();
|
|
305
|
+
const nextSlot = () => {
|
|
306
|
+
const slot = cursor;
|
|
307
|
+
cursor = (cursor + 8) >>> 0;
|
|
308
|
+
return slot;
|
|
309
|
+
};
|
|
310
|
+
return {
|
|
311
|
+
nextInt32() {
|
|
312
|
+
return view.getInt32(nextSlot(), true);
|
|
313
|
+
},
|
|
314
|
+
nextUint32() {
|
|
315
|
+
return view.getUint32(nextSlot(), true);
|
|
316
|
+
},
|
|
317
|
+
nextPointer() {
|
|
318
|
+
return view.getUint32(nextSlot(), true);
|
|
319
|
+
},
|
|
320
|
+
nextFloat64() {
|
|
321
|
+
return view.getFloat64(nextSlot(), true);
|
|
322
|
+
},
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
function formatInteger(value, {
|
|
327
|
+
signed = true,
|
|
328
|
+
base = 10,
|
|
329
|
+
width = 0,
|
|
330
|
+
padZero = false,
|
|
331
|
+
uppercase = false,
|
|
332
|
+
} = {}) {
|
|
333
|
+
let normalized = normalizePrintfValue(value);
|
|
334
|
+
let negative = false;
|
|
335
|
+
let digits = '';
|
|
336
|
+
|
|
337
|
+
if (typeof normalized === 'bigint') {
|
|
338
|
+
if (signed && normalized < 0n) {
|
|
339
|
+
negative = true;
|
|
340
|
+
normalized = -normalized;
|
|
341
|
+
} else if (!signed) {
|
|
342
|
+
normalized = BigInt.asUintN(64, normalized);
|
|
343
|
+
}
|
|
344
|
+
digits = normalized.toString(base);
|
|
345
|
+
} else {
|
|
346
|
+
let numberValue = Math.trunc(Number(normalized) || 0);
|
|
347
|
+
if (signed) {
|
|
348
|
+
negative = numberValue < 0;
|
|
349
|
+
numberValue = Math.abs(numberValue);
|
|
350
|
+
digits = numberValue.toString(base);
|
|
351
|
+
} else {
|
|
352
|
+
digits = (numberValue >>> 0).toString(base);
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
if (uppercase) {
|
|
357
|
+
digits = digits.toUpperCase();
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
const prefix = negative ? '-' : '';
|
|
361
|
+
const paddedDigits = padZero && width > prefix.length + digits.length
|
|
362
|
+
? digits.padStart(width - prefix.length, '0')
|
|
363
|
+
: digits;
|
|
364
|
+
const result = `${prefix}${paddedDigits}`;
|
|
365
|
+
return !padZero && width > result.length
|
|
366
|
+
? result.padStart(width, ' ')
|
|
367
|
+
: result;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
function formatStringValue(value, precision) {
|
|
371
|
+
if (typeof value === 'string') {
|
|
372
|
+
return precision == null ? value : value.slice(0, precision);
|
|
373
|
+
}
|
|
374
|
+
const ptr = Number(normalizePrintfValue(value)) >>> 0;
|
|
375
|
+
if (ptr === 0) {
|
|
376
|
+
return '(null)';
|
|
377
|
+
}
|
|
378
|
+
if (precision == null) {
|
|
379
|
+
return readCString(ptr);
|
|
380
|
+
}
|
|
381
|
+
return readCStringWithLength(ptr, precision);
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
function formatPrintf(fmtPtr, reader = null) {
|
|
385
|
+
const fmt = readCString(fmtPtr);
|
|
386
|
+
if (!reader) {
|
|
387
|
+
return fmt;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
let result = '';
|
|
391
|
+
for (let i = 0; i < fmt.length; i += 1) {
|
|
392
|
+
const ch = fmt[i];
|
|
393
|
+
if (ch !== '%') {
|
|
394
|
+
result += ch;
|
|
395
|
+
continue;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
const next = fmt[i + 1];
|
|
399
|
+
if (next === '%') {
|
|
400
|
+
result += '%';
|
|
401
|
+
i += 1;
|
|
402
|
+
continue;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
let cursor = i + 1;
|
|
406
|
+
let padZero = false;
|
|
407
|
+
if (fmt[cursor] === '0') {
|
|
408
|
+
padZero = true;
|
|
409
|
+
cursor += 1;
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
let widthText = '';
|
|
413
|
+
while (cursor < fmt.length && /[0-9]/.test(fmt[cursor])) {
|
|
414
|
+
widthText += fmt[cursor];
|
|
415
|
+
cursor += 1;
|
|
416
|
+
}
|
|
417
|
+
const width = widthText ? Number.parseInt(widthText, 10) : 0;
|
|
418
|
+
|
|
419
|
+
let precision = null;
|
|
420
|
+
if (fmt[cursor] === '.') {
|
|
421
|
+
cursor += 1;
|
|
422
|
+
if (fmt[cursor] === '*') {
|
|
423
|
+
precision = Math.max(0, reader.nextInt32());
|
|
424
|
+
cursor += 1;
|
|
425
|
+
} else {
|
|
426
|
+
let precisionText = '';
|
|
427
|
+
while (cursor < fmt.length && /[0-9]/.test(fmt[cursor])) {
|
|
428
|
+
precisionText += fmt[cursor];
|
|
429
|
+
cursor += 1;
|
|
430
|
+
}
|
|
431
|
+
precision = precisionText ? Number.parseInt(precisionText, 10) : 0;
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
while (cursor < fmt.length && /[hljztL]/.test(fmt[cursor])) {
|
|
436
|
+
cursor += 1;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
const specifier = fmt[cursor];
|
|
440
|
+
if (!specifier) {
|
|
441
|
+
result += '%';
|
|
442
|
+
break;
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
switch (specifier) {
|
|
446
|
+
case 's':
|
|
447
|
+
result += formatStringValue(reader.nextPointer(), precision);
|
|
448
|
+
break;
|
|
449
|
+
case 'c':
|
|
450
|
+
result += String.fromCodePoint(reader.nextInt32() >>> 0);
|
|
451
|
+
break;
|
|
452
|
+
case 'd':
|
|
453
|
+
case 'i':
|
|
454
|
+
result += formatInteger(reader.nextInt32(), {
|
|
455
|
+
signed: true,
|
|
456
|
+
base: 10,
|
|
457
|
+
width,
|
|
458
|
+
padZero,
|
|
459
|
+
});
|
|
460
|
+
break;
|
|
461
|
+
case 'u':
|
|
462
|
+
result += formatInteger(reader.nextUint32(), {
|
|
463
|
+
signed: false,
|
|
464
|
+
base: 10,
|
|
465
|
+
width,
|
|
466
|
+
padZero,
|
|
467
|
+
});
|
|
468
|
+
break;
|
|
469
|
+
case 'x':
|
|
470
|
+
case 'X':
|
|
471
|
+
result += formatInteger(reader.nextUint32(), {
|
|
472
|
+
signed: false,
|
|
473
|
+
base: 16,
|
|
474
|
+
width,
|
|
475
|
+
padZero,
|
|
476
|
+
uppercase: specifier === 'X',
|
|
477
|
+
});
|
|
478
|
+
break;
|
|
479
|
+
case 'f':
|
|
480
|
+
case 'g':
|
|
481
|
+
result += String(reader.nextFloat64());
|
|
482
|
+
break;
|
|
483
|
+
default:
|
|
484
|
+
result += `%${fmt.slice(i + 1, cursor + 1)}`;
|
|
485
|
+
break;
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
i = cursor;
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
return result;
|
|
78
492
|
}
|
|
79
493
|
|
|
80
494
|
function parseNumberPrefix(text) {
|
|
@@ -106,8 +520,8 @@ export function __assert_fail(assertionPtr, filePtr, line, functionPtr) {
|
|
|
106
520
|
throw new Error(`assertion failed: ${assertion} at ${file}:${line} in ${func}`);
|
|
107
521
|
}
|
|
108
522
|
|
|
109
|
-
export function printf(fmtPtr
|
|
110
|
-
const message = formatPrintf(fmtPtr);
|
|
523
|
+
export function printf(fmtPtr) {
|
|
524
|
+
const message = formatPrintf(fmtPtr, createDirectArgumentReader(arguments, 1));
|
|
111
525
|
consoleWrite('', message);
|
|
112
526
|
return message.length | 0;
|
|
113
527
|
}
|
|
@@ -128,8 +542,8 @@ export function putchar(ch) {
|
|
|
128
542
|
return ch | 0;
|
|
129
543
|
}
|
|
130
544
|
|
|
131
|
-
export function fprintf(_stream, fmtPtr
|
|
132
|
-
const message = formatPrintf(fmtPtr);
|
|
545
|
+
export function fprintf(_stream, fmtPtr) {
|
|
546
|
+
const message = formatPrintf(fmtPtr, createDirectArgumentReader(arguments, 2));
|
|
133
547
|
consoleWrite('', message);
|
|
134
548
|
return message.length | 0;
|
|
135
549
|
}
|
|
@@ -145,12 +559,12 @@ export function fputc(ch, _stream) {
|
|
|
145
559
|
return putchar(ch);
|
|
146
560
|
}
|
|
147
561
|
|
|
148
|
-
export function vsnprintf(dst, size, fmtPtr,
|
|
149
|
-
return writeCString(dst, size, formatPrintf(fmtPtr)) | 0;
|
|
562
|
+
export function vsnprintf(dst, size, fmtPtr, argsPtr) {
|
|
563
|
+
return writeCString(dst, size, formatPrintf(fmtPtr, createVaListReader(argsPtr))) | 0;
|
|
150
564
|
}
|
|
151
565
|
|
|
152
|
-
export function snprintf(dst, size, fmtPtr
|
|
153
|
-
return writeCString(dst, size, formatPrintf(fmtPtr)) | 0;
|
|
566
|
+
export function snprintf(dst, size, fmtPtr) {
|
|
567
|
+
return writeCString(dst, size, formatPrintf(fmtPtr, createDirectArgumentReader(arguments, 3))) | 0;
|
|
154
568
|
}
|
|
155
569
|
|
|
156
570
|
export function scalbn(x, n) {
|
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,4 @@
|
|
|
1
|
-
export type BundleFileInput =
|
|
2
|
-
| string
|
|
3
|
-
| Uint8Array
|
|
4
|
-
| ArrayBuffer
|
|
5
|
-
| ArrayBufferView;
|
|
1
|
+
export type BundleFileInput = string | Uint8Array | ArrayBuffer | ArrayBufferView;
|
|
6
2
|
|
|
7
3
|
export type BundleFiles =
|
|
8
4
|
| Map<string, BundleFileInput>
|
|
@@ -12,6 +8,9 @@ export type BundleFiles =
|
|
|
12
8
|
export interface InitInkOptions {
|
|
13
9
|
wasmUrl?: string | URL | Request;
|
|
14
10
|
moduleOrPath?: RequestInfo | URL | Response | BufferSource | WebAssembly.Module;
|
|
11
|
+
proxyUrl?: string;
|
|
12
|
+
targetSearchParam?: string;
|
|
13
|
+
requestInterceptor?: InkRequestInterceptor;
|
|
15
14
|
}
|
|
16
15
|
|
|
17
16
|
export interface CreateInkViewOptions {
|
|
@@ -35,6 +34,7 @@ export interface LoadBundleFromVfsOptions {
|
|
|
35
34
|
fetch?: typeof globalThis.fetch;
|
|
36
35
|
signal?: AbortSignal;
|
|
37
36
|
headers?: HeadersInit;
|
|
37
|
+
requestInterceptor?: InkRequestInterceptor;
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
export interface OpenFromVfsOptions extends LoadBundleFromVfsOptions {
|
|
@@ -42,6 +42,39 @@ export interface OpenFromVfsOptions extends LoadBundleFromVfsOptions {
|
|
|
42
42
|
query?: string | Record<string, unknown> | null;
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
+
export interface InkInterceptedRequest {
|
|
46
|
+
url: string;
|
|
47
|
+
method: string;
|
|
48
|
+
headers: Record<string, string>;
|
|
49
|
+
body: BodyInit | ArrayBuffer | ArrayBufferView | Uint8Array | null;
|
|
50
|
+
metadata: Record<string, unknown>;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export type InkInterceptedRequestAction =
|
|
54
|
+
| { action?: 'continue' }
|
|
55
|
+
| {
|
|
56
|
+
action: 'rewrite';
|
|
57
|
+
url?: string;
|
|
58
|
+
method?: string;
|
|
59
|
+
headers?: HeadersInit | Record<string, string>;
|
|
60
|
+
body?: BodyInit | ArrayBuffer | ArrayBufferView | Uint8Array | null;
|
|
61
|
+
}
|
|
62
|
+
| {
|
|
63
|
+
action: 'block';
|
|
64
|
+
reason?: string;
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
export type InkRequestInterceptor = (
|
|
68
|
+
request: InkInterceptedRequest,
|
|
69
|
+
) => InkInterceptedRequestAction | Promise<InkInterceptedRequestAction>;
|
|
70
|
+
|
|
71
|
+
export interface ConfigureNetworkOptions {
|
|
72
|
+
proxyUrl?: string;
|
|
73
|
+
targetSearchParam?: string;
|
|
74
|
+
interceptor?: InkRequestInterceptor;
|
|
75
|
+
clear?: boolean;
|
|
76
|
+
}
|
|
77
|
+
|
|
45
78
|
export interface VfsManifestEntry {
|
|
46
79
|
path: string;
|
|
47
80
|
size?: number;
|
|
@@ -76,17 +109,31 @@ export declare function getInkVersion(): string;
|
|
|
76
109
|
|
|
77
110
|
export declare function normalizeBundleFiles(files: BundleFiles): Map<string, Uint8Array>;
|
|
78
111
|
|
|
79
|
-
export declare function serializeQuery(
|
|
112
|
+
export declare function serializeQuery(
|
|
113
|
+
query: string | Record<string, unknown> | null | undefined,
|
|
114
|
+
): string | null;
|
|
80
115
|
|
|
81
|
-
export declare function
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
}):
|
|
116
|
+
export declare function createProxyUrlResolver(options: {
|
|
117
|
+
proxyUrl: string;
|
|
118
|
+
targetSearchParam?: string;
|
|
119
|
+
}): InkRequestInterceptor;
|
|
120
|
+
|
|
121
|
+
export declare function setInkRequestInterceptor(
|
|
122
|
+
interceptor: InkRequestInterceptor | null | undefined,
|
|
123
|
+
): void;
|
|
124
|
+
|
|
125
|
+
export declare function clearInkRequestInterceptor(): void;
|
|
126
|
+
|
|
127
|
+
export declare function configureNetwork(options?: ConfigureNetworkOptions): void;
|
|
128
|
+
|
|
129
|
+
export declare function createVfsUrls(input: { baseUrl: string; appId: string }): {
|
|
85
130
|
manifestUrl: string;
|
|
86
131
|
fileUrl(filePath: string): string;
|
|
87
132
|
};
|
|
88
133
|
|
|
89
|
-
export declare function loadBundleFromVfs(
|
|
134
|
+
export declare function loadBundleFromVfs(
|
|
135
|
+
options: LoadBundleFromVfsOptions,
|
|
136
|
+
): Promise<LoadedVfsBundle>;
|
|
90
137
|
|
|
91
138
|
export declare class InkView {
|
|
92
139
|
static create(options: CreateInkViewOptions): Promise<InkView>;
|
|
@@ -112,4 +159,8 @@ export declare function createFrameworkBindings(): {
|
|
|
112
159
|
ensureLeadingSlash(path: string): string;
|
|
113
160
|
initInk: typeof initInk;
|
|
114
161
|
createInkView: typeof createInkView;
|
|
162
|
+
configureNetwork: typeof configureNetwork;
|
|
163
|
+
setInkRequestInterceptor: typeof setInkRequestInterceptor;
|
|
164
|
+
clearInkRequestInterceptor: typeof clearInkRequestInterceptor;
|
|
165
|
+
createProxyUrlResolver: typeof createProxyUrlResolver;
|
|
115
166
|
};
|
package/dist/index.js
CHANGED
|
@@ -2,6 +2,11 @@ import initInkWasm, {
|
|
|
2
2
|
InkWebView as RawInkWebView,
|
|
3
3
|
get_version as getInkVersionFromWasm,
|
|
4
4
|
} from './pkg/ink_web.js';
|
|
5
|
+
import {
|
|
6
|
+
clearInkRequestInterceptor as clearInkRequestInterceptorBridge,
|
|
7
|
+
fetchWithInkRequestInterceptor,
|
|
8
|
+
setInkRequestInterceptor as setInkRequestInterceptorBridge,
|
|
9
|
+
} from './env.js';
|
|
5
10
|
|
|
6
11
|
let bindingsPromise;
|
|
7
12
|
|
|
@@ -40,7 +45,9 @@ function cloneUint8Array(value) {
|
|
|
40
45
|
return new Uint8Array(value);
|
|
41
46
|
}
|
|
42
47
|
if (ArrayBuffer.isView(value)) {
|
|
43
|
-
return new Uint8Array(
|
|
48
|
+
return new Uint8Array(
|
|
49
|
+
value.buffer.slice(value.byteOffset, value.byteOffset + value.byteLength),
|
|
50
|
+
);
|
|
44
51
|
}
|
|
45
52
|
if (value instanceof ArrayBuffer) {
|
|
46
53
|
return new Uint8Array(value.slice(0));
|
|
@@ -97,6 +104,51 @@ export function serializeQuery(query) {
|
|
|
97
104
|
return JSON.stringify(query);
|
|
98
105
|
}
|
|
99
106
|
|
|
107
|
+
export function createProxyUrlResolver({ proxyUrl, targetSearchParam = 'url' }) {
|
|
108
|
+
if (typeof proxyUrl !== 'string' || !proxyUrl.trim()) {
|
|
109
|
+
throw new Error('`proxyUrl` must be a non-empty string.');
|
|
110
|
+
}
|
|
111
|
+
if (typeof targetSearchParam !== 'string' || !targetSearchParam.trim()) {
|
|
112
|
+
throw new Error('`targetSearchParam` must be a non-empty string.');
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const normalizedProxyUrl = proxyUrl.trim();
|
|
116
|
+
const normalizedTargetSearchParam = targetSearchParam.trim();
|
|
117
|
+
return (request) => {
|
|
118
|
+
const target = new URL(normalizedProxyUrl, globalThis.location?.href || 'http://localhost');
|
|
119
|
+
target.searchParams.set(normalizedTargetSearchParam, request.url);
|
|
120
|
+
return {
|
|
121
|
+
action: 'rewrite',
|
|
122
|
+
url: target.toString(),
|
|
123
|
+
method: request.method,
|
|
124
|
+
headers: request.headers,
|
|
125
|
+
body: request.body,
|
|
126
|
+
};
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export function setInkRequestInterceptor(interceptor) {
|
|
131
|
+
setInkRequestInterceptorBridge(interceptor);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export function clearInkRequestInterceptor() {
|
|
135
|
+
clearInkRequestInterceptorBridge();
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
export function configureNetwork(options = {}) {
|
|
139
|
+
if (options.interceptor) {
|
|
140
|
+
setInkRequestInterceptor(options.interceptor);
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
if (options.proxyUrl) {
|
|
144
|
+
setInkRequestInterceptor(createProxyUrlResolver(options));
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
if (options.clear) {
|
|
148
|
+
clearInkRequestInterceptor();
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
100
152
|
async function buildHttpError(response, bodyReader = (res) => res.text()) {
|
|
101
153
|
let details = response.statusText;
|
|
102
154
|
try {
|
|
@@ -137,11 +189,21 @@ export async function loadBundleFromVfs({
|
|
|
137
189
|
fetch: fetchImpl,
|
|
138
190
|
signal,
|
|
139
191
|
headers,
|
|
192
|
+
requestInterceptor,
|
|
140
193
|
}) {
|
|
141
194
|
const resolvedFetch = ensureFetch(fetchImpl);
|
|
195
|
+
const wrappedFetch = async (url, init) =>
|
|
196
|
+
fetchWithInkRequestInterceptor(url, init, {
|
|
197
|
+
fetch: resolvedFetch,
|
|
198
|
+
interceptor: requestInterceptor || null,
|
|
199
|
+
metadata: {
|
|
200
|
+
kind: 'vfs',
|
|
201
|
+
appId,
|
|
202
|
+
},
|
|
203
|
+
});
|
|
142
204
|
const { manifestUrl, fileUrl } = createVfsUrls({ baseUrl, appId });
|
|
143
205
|
|
|
144
|
-
const manifestResponse = await
|
|
206
|
+
const manifestResponse = await wrappedFetch(manifestUrl, {
|
|
145
207
|
method: 'GET',
|
|
146
208
|
headers,
|
|
147
209
|
signal,
|
|
@@ -162,7 +224,7 @@ export async function loadBundleFromVfs({
|
|
|
162
224
|
throw new Error('Each VFS manifest entry must include a non-empty `path`.');
|
|
163
225
|
}
|
|
164
226
|
|
|
165
|
-
const response = await
|
|
227
|
+
const response = await wrappedFetch(fileUrl(entry.path), {
|
|
166
228
|
method: 'GET',
|
|
167
229
|
headers,
|
|
168
230
|
signal,
|
|
@@ -217,8 +279,15 @@ function ensureAnimationFrameApi() {
|
|
|
217
279
|
}
|
|
218
280
|
|
|
219
281
|
export async function initInk(options = {}) {
|
|
282
|
+
if (options.requestInterceptor) {
|
|
283
|
+
setInkRequestInterceptor(options.requestInterceptor);
|
|
284
|
+
} else if (options.proxyUrl) {
|
|
285
|
+
setInkRequestInterceptor(createProxyUrlResolver(options));
|
|
286
|
+
}
|
|
287
|
+
|
|
220
288
|
if (!bindingsPromise) {
|
|
221
|
-
const initInput =
|
|
289
|
+
const initInput =
|
|
290
|
+
options.wasmUrl || options.moduleOrPath || new URL('./pkg/ink_web_bg.wasm', import.meta.url);
|
|
222
291
|
bindingsPromise = initInkWasm(initInput).then(() => ({
|
|
223
292
|
InkWebView: RawInkWebView,
|
|
224
293
|
getInkVersion: getInkVersionFromWasm,
|
|
@@ -243,7 +312,11 @@ export class InkView {
|
|
|
243
312
|
}
|
|
244
313
|
|
|
245
314
|
const bindings = await initInk(config.wasm);
|
|
246
|
-
const rawView = new bindings.InkWebView(
|
|
315
|
+
const rawView = new bindings.InkWebView(
|
|
316
|
+
width,
|
|
317
|
+
height,
|
|
318
|
+
Number(config.scaleFactor || getDefaultScaleFactor()),
|
|
319
|
+
);
|
|
247
320
|
const view = new InkView(rawView, config);
|
|
248
321
|
|
|
249
322
|
if (config.canvas) {
|
|
@@ -310,22 +383,54 @@ export class InkView {
|
|
|
310
383
|
if (focusTarget && typeof focusTarget.focus === 'function') {
|
|
311
384
|
focusTarget.focus();
|
|
312
385
|
}
|
|
313
|
-
this.#rawView.dispatchPointer(
|
|
386
|
+
this.#rawView.dispatchPointer(
|
|
387
|
+
'pointerdown',
|
|
388
|
+
x,
|
|
389
|
+
y,
|
|
390
|
+
event.pointerId || 0,
|
|
391
|
+
event.button || 0,
|
|
392
|
+
0,
|
|
393
|
+
0,
|
|
394
|
+
);
|
|
314
395
|
this.requestRender();
|
|
315
396
|
});
|
|
316
397
|
addListener(canvas, 'pointermove', (event) => {
|
|
317
398
|
const { x, y } = getPointerPosition(canvas, event);
|
|
318
|
-
this.#rawView.dispatchPointer(
|
|
399
|
+
this.#rawView.dispatchPointer(
|
|
400
|
+
'pointermove',
|
|
401
|
+
x,
|
|
402
|
+
y,
|
|
403
|
+
event.pointerId || 0,
|
|
404
|
+
event.button || 0,
|
|
405
|
+
0,
|
|
406
|
+
0,
|
|
407
|
+
);
|
|
319
408
|
this.requestRender();
|
|
320
409
|
});
|
|
321
410
|
addListener(canvas, 'pointerup', (event) => {
|
|
322
411
|
const { x, y } = getPointerPosition(canvas, event);
|
|
323
|
-
this.#rawView.dispatchPointer(
|
|
412
|
+
this.#rawView.dispatchPointer(
|
|
413
|
+
'pointerup',
|
|
414
|
+
x,
|
|
415
|
+
y,
|
|
416
|
+
event.pointerId || 0,
|
|
417
|
+
event.button || 0,
|
|
418
|
+
0,
|
|
419
|
+
0,
|
|
420
|
+
);
|
|
324
421
|
this.requestRender();
|
|
325
422
|
});
|
|
326
423
|
addListener(canvas, 'pointercancel', (event) => {
|
|
327
424
|
const { x, y } = getPointerPosition(canvas, event);
|
|
328
|
-
this.#rawView.dispatchPointer(
|
|
425
|
+
this.#rawView.dispatchPointer(
|
|
426
|
+
'touchcancel',
|
|
427
|
+
x,
|
|
428
|
+
y,
|
|
429
|
+
event.pointerId || 0,
|
|
430
|
+
event.button || 0,
|
|
431
|
+
0,
|
|
432
|
+
0,
|
|
433
|
+
);
|
|
329
434
|
this.requestRender();
|
|
330
435
|
});
|
|
331
436
|
addListener(
|
|
@@ -336,18 +441,34 @@ export class InkView {
|
|
|
336
441
|
if (options.preventWheelDefault !== false && typeof event.preventDefault === 'function') {
|
|
337
442
|
event.preventDefault();
|
|
338
443
|
}
|
|
339
|
-
this.#rawView.dispatchPointer(
|
|
444
|
+
this.#rawView.dispatchPointer(
|
|
445
|
+
'mousewheel',
|
|
446
|
+
x,
|
|
447
|
+
y,
|
|
448
|
+
0,
|
|
449
|
+
0,
|
|
450
|
+
event.deltaX || 0,
|
|
451
|
+
event.deltaY || 0,
|
|
452
|
+
);
|
|
340
453
|
this.requestRender();
|
|
341
454
|
},
|
|
342
455
|
{ passive: false },
|
|
343
456
|
);
|
|
344
457
|
|
|
345
458
|
addListener(keyboardTarget, 'keydown', (event) => {
|
|
346
|
-
this.#rawView.dispatchInput(
|
|
459
|
+
this.#rawView.dispatchInput(
|
|
460
|
+
'keydown',
|
|
461
|
+
normalizeKeyboardCode(event),
|
|
462
|
+
Number(event.timeStamp || Date.now()),
|
|
463
|
+
);
|
|
347
464
|
this.requestRender();
|
|
348
465
|
});
|
|
349
466
|
addListener(keyboardTarget, 'keyup', (event) => {
|
|
350
|
-
this.#rawView.dispatchInput(
|
|
467
|
+
this.#rawView.dispatchInput(
|
|
468
|
+
'keyup',
|
|
469
|
+
normalizeKeyboardCode(event),
|
|
470
|
+
Number(event.timeStamp || Date.now()),
|
|
471
|
+
);
|
|
351
472
|
this.requestRender();
|
|
352
473
|
});
|
|
353
474
|
addListener(focusTarget, 'focus', () => {
|
|
@@ -372,18 +493,33 @@ export class InkView {
|
|
|
372
493
|
throw new Error('`appId` must be a non-empty string.');
|
|
373
494
|
}
|
|
374
495
|
|
|
375
|
-
this.#rawView.openBundle(
|
|
496
|
+
this.#rawView.openBundle(
|
|
497
|
+
appId,
|
|
498
|
+
normalizeBundleFiles(files),
|
|
499
|
+
initialPage,
|
|
500
|
+
serializeQuery(query),
|
|
501
|
+
);
|
|
376
502
|
this.requestRender();
|
|
377
503
|
return this;
|
|
378
504
|
}
|
|
379
505
|
|
|
380
|
-
async openFromVfs({
|
|
506
|
+
async openFromVfs({
|
|
507
|
+
appId,
|
|
508
|
+
baseUrl,
|
|
509
|
+
initialPage = null,
|
|
510
|
+
query = null,
|
|
511
|
+
fetch,
|
|
512
|
+
signal,
|
|
513
|
+
headers,
|
|
514
|
+
requestInterceptor,
|
|
515
|
+
}) {
|
|
381
516
|
const bundle = await loadBundleFromVfs({
|
|
382
517
|
appId,
|
|
383
518
|
baseUrl,
|
|
384
519
|
fetch,
|
|
385
520
|
signal,
|
|
386
521
|
headers,
|
|
522
|
+
requestInterceptor,
|
|
387
523
|
});
|
|
388
524
|
this.openBundle({
|
|
389
525
|
appId: bundle.appId,
|
|
@@ -472,5 +608,9 @@ export function createFrameworkBindings() {
|
|
|
472
608
|
ensureLeadingSlash,
|
|
473
609
|
initInk,
|
|
474
610
|
createInkView,
|
|
611
|
+
configureNetwork,
|
|
612
|
+
setInkRequestInterceptor,
|
|
613
|
+
clearInkRequestInterceptor,
|
|
614
|
+
createProxyUrlResolver,
|
|
475
615
|
};
|
|
476
616
|
}
|
package/dist/pkg/README.md
CHANGED
|
@@ -17,7 +17,7 @@ This package compiles the Ink engine into Wasm, enabling it to run in modern web
|
|
|
17
17
|
./build.sh
|
|
18
18
|
```
|
|
19
19
|
|
|
20
|
-
2. Start the bundled Node static server
|
|
20
|
+
2. Start the bundled Node static server:
|
|
21
21
|
|
|
22
22
|
```bash
|
|
23
23
|
npm run dev --prefix playground
|
|
@@ -29,6 +29,6 @@ npm run dev --prefix playground
|
|
|
29
29
|
http://localhost:8080
|
|
30
30
|
```
|
|
31
31
|
|
|
32
|
-
The
|
|
33
|
-
|
|
34
|
-
|
|
32
|
+
The playground host configures a same-origin `/__proxy` interceptor example for
|
|
33
|
+
external HTTP resources. This proxy behavior is no longer hard-coded inside
|
|
34
|
+
`ink-web`; hosts now opt into request interception explicitly from the SDK side.
|
package/dist/pkg/ink_web.d.ts
CHANGED
|
@@ -41,11 +41,11 @@ export interface InitOutput {
|
|
|
41
41
|
readonly inkwebview_render: (a: number, b: number) => void;
|
|
42
42
|
readonly inkwebview_resize: (a: number, b: number, c: number, d: number) => void;
|
|
43
43
|
readonly main: () => void;
|
|
44
|
-
readonly
|
|
45
|
-
readonly
|
|
46
|
-
readonly
|
|
47
|
-
readonly
|
|
48
|
-
readonly
|
|
44
|
+
readonly __wasm_bindgen_func_elem_8658: (a: number, b: number) => void;
|
|
45
|
+
readonly __wasm_bindgen_func_elem_12847: (a: number, b: number) => void;
|
|
46
|
+
readonly __wasm_bindgen_func_elem_8747: (a: number, b: number, c: number) => void;
|
|
47
|
+
readonly __wasm_bindgen_func_elem_12848: (a: number, b: number, c: number) => void;
|
|
48
|
+
readonly __wasm_bindgen_func_elem_8748: (a: number, b: number) => void;
|
|
49
49
|
readonly __wbindgen_export: (a: number, b: number) => number;
|
|
50
50
|
readonly __wbindgen_export2: (a: number, b: number, c: number, d: number) => number;
|
|
51
51
|
readonly __wbindgen_export3: (a: number) => void;
|
package/dist/pkg/ink_web.js
CHANGED
|
@@ -208,6 +208,8 @@ import * as import25 from "../env.js"
|
|
|
208
208
|
import * as import26 from "../env.js"
|
|
209
209
|
import * as import27 from "../env.js"
|
|
210
210
|
import * as import28 from "../env.js"
|
|
211
|
+
import * as import29 from "../env.js"
|
|
212
|
+
import * as import30 from "../env.js"
|
|
211
213
|
|
|
212
214
|
function __wbg_get_imports() {
|
|
213
215
|
const import0 = {
|
|
@@ -314,6 +316,10 @@ function __wbg_get_imports() {
|
|
|
314
316
|
const ret = getObject(arg0).call(getObject(arg1));
|
|
315
317
|
return addHeapObject(ret);
|
|
316
318
|
}, arguments); },
|
|
319
|
+
__wbg_call_e8c868596c950cf6: function() { return handleError(function (arg0, arg1, arg2, arg3, arg4) {
|
|
320
|
+
const ret = getObject(arg0).call(getObject(arg1), getObject(arg2), getObject(arg3), getObject(arg4));
|
|
321
|
+
return addHeapObject(ret);
|
|
322
|
+
}, arguments); },
|
|
317
323
|
__wbg_clearRect_1eed255045515c55: function(arg0, arg1, arg2, arg3, arg4) {
|
|
318
324
|
getObject(arg0).clearRect(arg1, arg2, arg3, arg4);
|
|
319
325
|
},
|
|
@@ -433,10 +439,6 @@ function __wbg_get_imports() {
|
|
|
433
439
|
__wbg_error_9a7fe3f932034cde: function(arg0) {
|
|
434
440
|
console.error(getObject(arg0));
|
|
435
441
|
},
|
|
436
|
-
__wbg_fetch_7f864e6b0cbd00ea: function(arg0, arg1, arg2, arg3) {
|
|
437
|
-
const ret = getObject(arg0).fetch(getStringFromWasm0(arg1, arg2), getObject(arg3));
|
|
438
|
-
return addHeapObject(ret);
|
|
439
|
-
},
|
|
440
442
|
__wbg_fillRect_d44afec47e3a3fab: function(arg0, arg1, arg2, arg3, arg4) {
|
|
441
443
|
getObject(arg0).fillRect(arg1, arg2, arg3, arg4);
|
|
442
444
|
},
|
|
@@ -498,6 +500,16 @@ function __wbg_get_imports() {
|
|
|
498
500
|
const ret = result;
|
|
499
501
|
return ret;
|
|
500
502
|
},
|
|
503
|
+
__wbg_instanceof_Error_8573fe0b0b480f46: function(arg0) {
|
|
504
|
+
let result;
|
|
505
|
+
try {
|
|
506
|
+
result = getObject(arg0) instanceof Error;
|
|
507
|
+
} catch (_) {
|
|
508
|
+
result = false;
|
|
509
|
+
}
|
|
510
|
+
const ret = result;
|
|
511
|
+
return ret;
|
|
512
|
+
},
|
|
501
513
|
__wbg_instanceof_HtmlCanvasElement_3f2f6e1edb1c9792: function(arg0) {
|
|
502
514
|
let result;
|
|
503
515
|
try {
|
|
@@ -598,9 +610,17 @@ function __wbg_get_imports() {
|
|
|
598
610
|
const ret = getObject(arg0).measureText(getStringFromWasm0(arg1, arg2));
|
|
599
611
|
return addHeapObject(ret);
|
|
600
612
|
}, arguments); },
|
|
613
|
+
__wbg_message_9ddc4b9a62a7c379: function(arg0) {
|
|
614
|
+
const ret = getObject(arg0).message;
|
|
615
|
+
return addHeapObject(ret);
|
|
616
|
+
},
|
|
601
617
|
__wbg_moveTo_e9190fc700d55b40: function(arg0, arg1, arg2) {
|
|
602
618
|
getObject(arg0).moveTo(arg1, arg2);
|
|
603
619
|
},
|
|
620
|
+
__wbg_name_446e25ef2cfdab5a: function(arg0) {
|
|
621
|
+
const ret = getObject(arg0).name;
|
|
622
|
+
return addHeapObject(ret);
|
|
623
|
+
},
|
|
604
624
|
__wbg_navigator_43be698ba96fc088: function(arg0) {
|
|
605
625
|
const ret = getObject(arg0).navigator;
|
|
606
626
|
return addHeapObject(ret);
|
|
@@ -621,6 +641,10 @@ function __wbg_get_imports() {
|
|
|
621
641
|
const ret = new Headers();
|
|
622
642
|
return addHeapObject(ret);
|
|
623
643
|
}, arguments); },
|
|
644
|
+
__wbg_new_72b49615380db768: function(arg0, arg1) {
|
|
645
|
+
const ret = new Error(getStringFromWasm0(arg0, arg1));
|
|
646
|
+
return addHeapObject(ret);
|
|
647
|
+
},
|
|
624
648
|
__wbg_new_7455c5eb8798868d: function() { return handleError(function () {
|
|
625
649
|
const ret = new Audio();
|
|
626
650
|
return addHeapObject(ret);
|
|
@@ -943,28 +967,28 @@ function __wbg_get_imports() {
|
|
|
943
967
|
return ret;
|
|
944
968
|
},
|
|
945
969
|
__wbindgen_cast_0000000000000001: function(arg0, arg1) {
|
|
946
|
-
// Cast intrinsic for `Closure(Closure { dtor_idx:
|
|
947
|
-
const ret = makeMutClosure(arg0, arg1, wasm.
|
|
970
|
+
// Cast intrinsic for `Closure(Closure { dtor_idx: 2300, function: Function { arguments: [NamedExternref("CloseEvent")], shim_idx: 2304, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
|
|
971
|
+
const ret = makeMutClosure(arg0, arg1, wasm.__wasm_bindgen_func_elem_8658, __wasm_bindgen_func_elem_8747);
|
|
948
972
|
return addHeapObject(ret);
|
|
949
973
|
},
|
|
950
974
|
__wbindgen_cast_0000000000000002: function(arg0, arg1) {
|
|
951
|
-
// Cast intrinsic for `Closure(Closure { dtor_idx:
|
|
952
|
-
const ret = makeMutClosure(arg0, arg1, wasm.
|
|
975
|
+
// Cast intrinsic for `Closure(Closure { dtor_idx: 2300, function: Function { arguments: [NamedExternref("Event")], shim_idx: 2304, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
|
|
976
|
+
const ret = makeMutClosure(arg0, arg1, wasm.__wasm_bindgen_func_elem_8658, __wasm_bindgen_func_elem_8747);
|
|
953
977
|
return addHeapObject(ret);
|
|
954
978
|
},
|
|
955
979
|
__wbindgen_cast_0000000000000003: function(arg0, arg1) {
|
|
956
|
-
// Cast intrinsic for `Closure(Closure { dtor_idx:
|
|
957
|
-
const ret = makeMutClosure(arg0, arg1, wasm.
|
|
980
|
+
// Cast intrinsic for `Closure(Closure { dtor_idx: 2300, function: Function { arguments: [NamedExternref("MessageEvent")], shim_idx: 2304, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
|
|
981
|
+
const ret = makeMutClosure(arg0, arg1, wasm.__wasm_bindgen_func_elem_8658, __wasm_bindgen_func_elem_8747);
|
|
958
982
|
return addHeapObject(ret);
|
|
959
983
|
},
|
|
960
984
|
__wbindgen_cast_0000000000000004: function(arg0, arg1) {
|
|
961
|
-
// Cast intrinsic for `Closure(Closure { dtor_idx:
|
|
962
|
-
const ret = makeMutClosure(arg0, arg1, wasm.
|
|
985
|
+
// Cast intrinsic for `Closure(Closure { dtor_idx: 2300, function: Function { arguments: [], shim_idx: 2301, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
|
|
986
|
+
const ret = makeMutClosure(arg0, arg1, wasm.__wasm_bindgen_func_elem_8658, __wasm_bindgen_func_elem_8748);
|
|
963
987
|
return addHeapObject(ret);
|
|
964
988
|
},
|
|
965
989
|
__wbindgen_cast_0000000000000005: function(arg0, arg1) {
|
|
966
|
-
// Cast intrinsic for `Closure(Closure { dtor_idx:
|
|
967
|
-
const ret = makeMutClosure(arg0, arg1, wasm.
|
|
990
|
+
// Cast intrinsic for `Closure(Closure { dtor_idx: 3264, function: Function { arguments: [Externref], shim_idx: 3265, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
|
|
991
|
+
const ret = makeMutClosure(arg0, arg1, wasm.__wasm_bindgen_func_elem_12847, __wasm_bindgen_func_elem_12848);
|
|
968
992
|
return addHeapObject(ret);
|
|
969
993
|
},
|
|
970
994
|
__wbindgen_cast_0000000000000006: function(arg0) {
|
|
@@ -1016,19 +1040,21 @@ function __wbg_get_imports() {
|
|
|
1016
1040
|
"env": import26,
|
|
1017
1041
|
"env": import27,
|
|
1018
1042
|
"env": import28,
|
|
1043
|
+
"env": import29,
|
|
1044
|
+
"env": import30,
|
|
1019
1045
|
};
|
|
1020
1046
|
}
|
|
1021
1047
|
|
|
1022
|
-
function
|
|
1023
|
-
wasm.
|
|
1048
|
+
function __wasm_bindgen_func_elem_8748(arg0, arg1) {
|
|
1049
|
+
wasm.__wasm_bindgen_func_elem_8748(arg0, arg1);
|
|
1024
1050
|
}
|
|
1025
1051
|
|
|
1026
|
-
function
|
|
1027
|
-
wasm.
|
|
1052
|
+
function __wasm_bindgen_func_elem_8747(arg0, arg1, arg2) {
|
|
1053
|
+
wasm.__wasm_bindgen_func_elem_8747(arg0, arg1, addHeapObject(arg2));
|
|
1028
1054
|
}
|
|
1029
1055
|
|
|
1030
|
-
function
|
|
1031
|
-
wasm.
|
|
1056
|
+
function __wasm_bindgen_func_elem_12848(arg0, arg1, arg2) {
|
|
1057
|
+
wasm.__wasm_bindgen_func_elem_12848(arg0, arg1, addHeapObject(arg2));
|
|
1032
1058
|
}
|
|
1033
1059
|
|
|
1034
1060
|
|
package/dist/pkg/ink_web_bg.wasm
CHANGED
|
Binary file
|
|
@@ -16,11 +16,11 @@ export const inkwebview_openBundle: (a: number, b: number, c: number, d: number,
|
|
|
16
16
|
export const inkwebview_render: (a: number, b: number) => void;
|
|
17
17
|
export const inkwebview_resize: (a: number, b: number, c: number, d: number) => void;
|
|
18
18
|
export const main: () => void;
|
|
19
|
-
export const
|
|
20
|
-
export const
|
|
21
|
-
export const
|
|
22
|
-
export const
|
|
23
|
-
export const
|
|
19
|
+
export const __wasm_bindgen_func_elem_8658: (a: number, b: number) => void;
|
|
20
|
+
export const __wasm_bindgen_func_elem_12847: (a: number, b: number) => void;
|
|
21
|
+
export const __wasm_bindgen_func_elem_8747: (a: number, b: number, c: number) => void;
|
|
22
|
+
export const __wasm_bindgen_func_elem_12848: (a: number, b: number, c: number) => void;
|
|
23
|
+
export const __wasm_bindgen_func_elem_8748: (a: number, b: number) => void;
|
|
24
24
|
export const __wbindgen_export: (a: number, b: number) => number;
|
|
25
25
|
export const __wbindgen_export2: (a: number, b: number, c: number, d: number) => number;
|
|
26
26
|
export const __wbindgen_export3: (a: number) => void;
|