@yodaos-pkg/ink 0.1.0 → 0.2.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 +156 -0
- package/dist/index.d.ts +52 -0
- package/dist/index.js +83 -3
- package/dist/pkg/README.md +4 -4
- package/dist/pkg/ink_web.d.ts +5 -5
- package/dist/pkg/ink_web.js +19 -19
- 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,167 @@ 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;
|
|
5
6
|
|
|
6
7
|
export function __setWasmInstance(exports) {
|
|
7
8
|
wasmExports = exports;
|
|
8
9
|
}
|
|
9
10
|
|
|
11
|
+
function ensureFetchImplementation(fetchImpl) {
|
|
12
|
+
const resolved = fetchImpl || globalThis.fetch;
|
|
13
|
+
if (typeof resolved !== 'function') {
|
|
14
|
+
throw new Error('A fetch implementation is required for Ink networking.');
|
|
15
|
+
}
|
|
16
|
+
return resolved;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function headersToObject(headersLike) {
|
|
20
|
+
if (!headersLike) {
|
|
21
|
+
return {};
|
|
22
|
+
}
|
|
23
|
+
if (typeof Headers !== 'undefined' && headersLike instanceof Headers) {
|
|
24
|
+
const result = {};
|
|
25
|
+
for (const [name, value] of headersLike.entries()) {
|
|
26
|
+
result[name] = value;
|
|
27
|
+
}
|
|
28
|
+
return result;
|
|
29
|
+
}
|
|
30
|
+
if (Array.isArray(headersLike)) {
|
|
31
|
+
const result = {};
|
|
32
|
+
for (const entry of headersLike) {
|
|
33
|
+
if (!Array.isArray(entry) || entry.length < 2) {
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
result[String(entry[0])] = String(entry[1]);
|
|
37
|
+
}
|
|
38
|
+
return result;
|
|
39
|
+
}
|
|
40
|
+
if (headersLike && typeof headersLike === 'object') {
|
|
41
|
+
return Object.fromEntries(
|
|
42
|
+
Object.entries(headersLike).map(([name, value]) => [name, Array.isArray(value) ? value.join(', ') : String(value)]),
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
return {};
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function cloneBody(body) {
|
|
49
|
+
if (body == null) {
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
if (typeof body === 'string') {
|
|
53
|
+
return body;
|
|
54
|
+
}
|
|
55
|
+
if (body instanceof Uint8Array) {
|
|
56
|
+
return new Uint8Array(body);
|
|
57
|
+
}
|
|
58
|
+
if (ArrayBuffer.isView(body)) {
|
|
59
|
+
return new Uint8Array(body.buffer.slice(body.byteOffset, body.byteOffset + body.byteLength));
|
|
60
|
+
}
|
|
61
|
+
if (body instanceof ArrayBuffer) {
|
|
62
|
+
return body.slice(0);
|
|
63
|
+
}
|
|
64
|
+
return body;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function normalizeRequest(input, init = {}, metadata = {}) {
|
|
68
|
+
const url = typeof input === 'string' ? input : String(input);
|
|
69
|
+
return {
|
|
70
|
+
url,
|
|
71
|
+
method: String(init.method || 'GET').toUpperCase(),
|
|
72
|
+
headers: headersToObject(init.headers),
|
|
73
|
+
body: cloneBody(init.body),
|
|
74
|
+
metadata: metadata && typeof metadata === 'object' ? { ...metadata } : {},
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function normalizeInterceptorResult(request, result) {
|
|
79
|
+
if (result == null || result === false) {
|
|
80
|
+
return {
|
|
81
|
+
url: request.url,
|
|
82
|
+
init: {
|
|
83
|
+
method: request.method,
|
|
84
|
+
headers: request.headers,
|
|
85
|
+
body: request.body,
|
|
86
|
+
},
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (typeof result !== 'object') {
|
|
91
|
+
throw new TypeError('Ink request interceptor must return an object, null, or undefined.');
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const action = result.action || 'rewrite';
|
|
95
|
+
if (action === 'continue') {
|
|
96
|
+
return {
|
|
97
|
+
url: request.url,
|
|
98
|
+
init: {
|
|
99
|
+
method: request.method,
|
|
100
|
+
headers: request.headers,
|
|
101
|
+
body: request.body,
|
|
102
|
+
},
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (action === 'block') {
|
|
107
|
+
throw new Error(result.reason || `Ink request blocked: ${request.url}`);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
if (action !== 'rewrite') {
|
|
111
|
+
throw new Error(`Unsupported Ink request interceptor action: ${action}`);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return {
|
|
115
|
+
url: typeof result.url === 'string' && result.url ? result.url : request.url,
|
|
116
|
+
init: {
|
|
117
|
+
method: typeof result.method === 'string' && result.method ? result.method : request.method,
|
|
118
|
+
headers: result.headers ? headersToObject(result.headers) : request.headers,
|
|
119
|
+
body: Object.prototype.hasOwnProperty.call(result, 'body') ? result.body : request.body,
|
|
120
|
+
},
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
async function resolveInkFetchRequest(input, init = {}, metadata = {}, interceptorOverride = null) {
|
|
125
|
+
const request = normalizeRequest(input, init, metadata);
|
|
126
|
+
const interceptor = interceptorOverride || inkRequestInterceptor;
|
|
127
|
+
if (!interceptor) {
|
|
128
|
+
return {
|
|
129
|
+
url: request.url,
|
|
130
|
+
init: {
|
|
131
|
+
method: request.method,
|
|
132
|
+
headers: request.headers,
|
|
133
|
+
body: request.body,
|
|
134
|
+
},
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
const result = await interceptor(request);
|
|
138
|
+
return normalizeInterceptorResult(request, result);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export function setInkRequestInterceptor(interceptor) {
|
|
142
|
+
if (interceptor != null && typeof interceptor !== 'function') {
|
|
143
|
+
throw new TypeError('Ink request interceptor must be a function, null, or undefined.');
|
|
144
|
+
}
|
|
145
|
+
inkRequestInterceptor = interceptor || null;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
export function clearInkRequestInterceptor() {
|
|
149
|
+
inkRequestInterceptor = null;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
export async function __inkFetch(input, init, metadata) {
|
|
153
|
+
const resolved = await resolveInkFetchRequest(input, init, metadata);
|
|
154
|
+
const fetchImpl = ensureFetchImplementation();
|
|
155
|
+
return fetchImpl(resolved.url, resolved.init);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
export async function fetchWithInkRequestInterceptor(input, init = {}, options = {}) {
|
|
159
|
+
const resolved = await resolveInkFetchRequest(input, init, options.metadata, options.interceptor || null);
|
|
160
|
+
const fetchImpl = ensureFetchImplementation(options.fetch);
|
|
161
|
+
return fetchImpl(resolved.url, resolved.init);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
globalThis.__inkFetch = __inkFetch;
|
|
165
|
+
|
|
10
166
|
function requireWasm() {
|
|
11
167
|
if (!wasmExports) {
|
|
12
168
|
throw new Error('Wasm exports are not initialized');
|
package/dist/index.d.ts
CHANGED
|
@@ -12,6 +12,9 @@ export type BundleFiles =
|
|
|
12
12
|
export interface InitInkOptions {
|
|
13
13
|
wasmUrl?: string | URL | Request;
|
|
14
14
|
moduleOrPath?: RequestInfo | URL | Response | BufferSource | WebAssembly.Module;
|
|
15
|
+
proxyUrl?: string;
|
|
16
|
+
targetSearchParam?: string;
|
|
17
|
+
requestInterceptor?: InkRequestInterceptor;
|
|
15
18
|
}
|
|
16
19
|
|
|
17
20
|
export interface CreateInkViewOptions {
|
|
@@ -35,6 +38,7 @@ export interface LoadBundleFromVfsOptions {
|
|
|
35
38
|
fetch?: typeof globalThis.fetch;
|
|
36
39
|
signal?: AbortSignal;
|
|
37
40
|
headers?: HeadersInit;
|
|
41
|
+
requestInterceptor?: InkRequestInterceptor;
|
|
38
42
|
}
|
|
39
43
|
|
|
40
44
|
export interface OpenFromVfsOptions extends LoadBundleFromVfsOptions {
|
|
@@ -42,6 +46,39 @@ export interface OpenFromVfsOptions extends LoadBundleFromVfsOptions {
|
|
|
42
46
|
query?: string | Record<string, unknown> | null;
|
|
43
47
|
}
|
|
44
48
|
|
|
49
|
+
export interface InkInterceptedRequest {
|
|
50
|
+
url: string;
|
|
51
|
+
method: string;
|
|
52
|
+
headers: Record<string, string>;
|
|
53
|
+
body: BodyInit | ArrayBuffer | ArrayBufferView | Uint8Array | null;
|
|
54
|
+
metadata: Record<string, unknown>;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export type InkInterceptedRequestAction =
|
|
58
|
+
| { action?: 'continue' }
|
|
59
|
+
| {
|
|
60
|
+
action: 'rewrite';
|
|
61
|
+
url?: string;
|
|
62
|
+
method?: string;
|
|
63
|
+
headers?: HeadersInit | Record<string, string>;
|
|
64
|
+
body?: BodyInit | ArrayBuffer | ArrayBufferView | Uint8Array | null;
|
|
65
|
+
}
|
|
66
|
+
| {
|
|
67
|
+
action: 'block';
|
|
68
|
+
reason?: string;
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
export type InkRequestInterceptor = (
|
|
72
|
+
request: InkInterceptedRequest,
|
|
73
|
+
) => InkInterceptedRequestAction | Promise<InkInterceptedRequestAction>;
|
|
74
|
+
|
|
75
|
+
export interface ConfigureNetworkOptions {
|
|
76
|
+
proxyUrl?: string;
|
|
77
|
+
targetSearchParam?: string;
|
|
78
|
+
interceptor?: InkRequestInterceptor;
|
|
79
|
+
clear?: boolean;
|
|
80
|
+
}
|
|
81
|
+
|
|
45
82
|
export interface VfsManifestEntry {
|
|
46
83
|
path: string;
|
|
47
84
|
size?: number;
|
|
@@ -78,6 +115,17 @@ export declare function normalizeBundleFiles(files: BundleFiles): Map<string, Ui
|
|
|
78
115
|
|
|
79
116
|
export declare function serializeQuery(query: string | Record<string, unknown> | null | undefined): string | null;
|
|
80
117
|
|
|
118
|
+
export declare function createProxyUrlResolver(options: {
|
|
119
|
+
proxyUrl: string;
|
|
120
|
+
targetSearchParam?: string;
|
|
121
|
+
}): InkRequestInterceptor;
|
|
122
|
+
|
|
123
|
+
export declare function setInkRequestInterceptor(interceptor: InkRequestInterceptor | null | undefined): void;
|
|
124
|
+
|
|
125
|
+
export declare function clearInkRequestInterceptor(): void;
|
|
126
|
+
|
|
127
|
+
export declare function configureNetwork(options?: ConfigureNetworkOptions): void;
|
|
128
|
+
|
|
81
129
|
export declare function createVfsUrls(input: {
|
|
82
130
|
baseUrl: string;
|
|
83
131
|
appId: string;
|
|
@@ -112,4 +160,8 @@ export declare function createFrameworkBindings(): {
|
|
|
112
160
|
ensureLeadingSlash(path: string): string;
|
|
113
161
|
initInk: typeof initInk;
|
|
114
162
|
createInkView: typeof createInkView;
|
|
163
|
+
configureNetwork: typeof configureNetwork;
|
|
164
|
+
setInkRequestInterceptor: typeof setInkRequestInterceptor;
|
|
165
|
+
clearInkRequestInterceptor: typeof clearInkRequestInterceptor;
|
|
166
|
+
createProxyUrlResolver: typeof createProxyUrlResolver;
|
|
115
167
|
};
|
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
|
|
|
@@ -97,6 +102,51 @@ export function serializeQuery(query) {
|
|
|
97
102
|
return JSON.stringify(query);
|
|
98
103
|
}
|
|
99
104
|
|
|
105
|
+
export function createProxyUrlResolver({ proxyUrl, targetSearchParam = 'url' }) {
|
|
106
|
+
if (typeof proxyUrl !== 'string' || !proxyUrl.trim()) {
|
|
107
|
+
throw new Error('`proxyUrl` must be a non-empty string.');
|
|
108
|
+
}
|
|
109
|
+
if (typeof targetSearchParam !== 'string' || !targetSearchParam.trim()) {
|
|
110
|
+
throw new Error('`targetSearchParam` must be a non-empty string.');
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const normalizedProxyUrl = proxyUrl.trim();
|
|
114
|
+
const normalizedTargetSearchParam = targetSearchParam.trim();
|
|
115
|
+
return (request) => {
|
|
116
|
+
const target = new URL(normalizedProxyUrl, globalThis.location?.href || 'http://localhost');
|
|
117
|
+
target.searchParams.set(normalizedTargetSearchParam, request.url);
|
|
118
|
+
return {
|
|
119
|
+
action: 'rewrite',
|
|
120
|
+
url: target.toString(),
|
|
121
|
+
method: request.method,
|
|
122
|
+
headers: request.headers,
|
|
123
|
+
body: request.body,
|
|
124
|
+
};
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export function setInkRequestInterceptor(interceptor) {
|
|
129
|
+
setInkRequestInterceptorBridge(interceptor);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export function clearInkRequestInterceptor() {
|
|
133
|
+
clearInkRequestInterceptorBridge();
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export function configureNetwork(options = {}) {
|
|
137
|
+
if (options.interceptor) {
|
|
138
|
+
setInkRequestInterceptor(options.interceptor);
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
if (options.proxyUrl) {
|
|
142
|
+
setInkRequestInterceptor(createProxyUrlResolver(options));
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
if (options.clear) {
|
|
146
|
+
clearInkRequestInterceptor();
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
100
150
|
async function buildHttpError(response, bodyReader = (res) => res.text()) {
|
|
101
151
|
let details = response.statusText;
|
|
102
152
|
try {
|
|
@@ -137,11 +187,21 @@ export async function loadBundleFromVfs({
|
|
|
137
187
|
fetch: fetchImpl,
|
|
138
188
|
signal,
|
|
139
189
|
headers,
|
|
190
|
+
requestInterceptor,
|
|
140
191
|
}) {
|
|
141
192
|
const resolvedFetch = ensureFetch(fetchImpl);
|
|
193
|
+
const wrappedFetch = async (url, init) =>
|
|
194
|
+
fetchWithInkRequestInterceptor(url, init, {
|
|
195
|
+
fetch: resolvedFetch,
|
|
196
|
+
interceptor: requestInterceptor || null,
|
|
197
|
+
metadata: {
|
|
198
|
+
kind: 'vfs',
|
|
199
|
+
appId,
|
|
200
|
+
},
|
|
201
|
+
});
|
|
142
202
|
const { manifestUrl, fileUrl } = createVfsUrls({ baseUrl, appId });
|
|
143
203
|
|
|
144
|
-
const manifestResponse = await
|
|
204
|
+
const manifestResponse = await wrappedFetch(manifestUrl, {
|
|
145
205
|
method: 'GET',
|
|
146
206
|
headers,
|
|
147
207
|
signal,
|
|
@@ -162,7 +222,7 @@ export async function loadBundleFromVfs({
|
|
|
162
222
|
throw new Error('Each VFS manifest entry must include a non-empty `path`.');
|
|
163
223
|
}
|
|
164
224
|
|
|
165
|
-
const response = await
|
|
225
|
+
const response = await wrappedFetch(fileUrl(entry.path), {
|
|
166
226
|
method: 'GET',
|
|
167
227
|
headers,
|
|
168
228
|
signal,
|
|
@@ -217,6 +277,12 @@ function ensureAnimationFrameApi() {
|
|
|
217
277
|
}
|
|
218
278
|
|
|
219
279
|
export async function initInk(options = {}) {
|
|
280
|
+
if (options.requestInterceptor) {
|
|
281
|
+
setInkRequestInterceptor(options.requestInterceptor);
|
|
282
|
+
} else if (options.proxyUrl) {
|
|
283
|
+
setInkRequestInterceptor(createProxyUrlResolver(options));
|
|
284
|
+
}
|
|
285
|
+
|
|
220
286
|
if (!bindingsPromise) {
|
|
221
287
|
const initInput = options.wasmUrl || options.moduleOrPath || new URL('./pkg/ink_web_bg.wasm', import.meta.url);
|
|
222
288
|
bindingsPromise = initInkWasm(initInput).then(() => ({
|
|
@@ -377,13 +443,23 @@ export class InkView {
|
|
|
377
443
|
return this;
|
|
378
444
|
}
|
|
379
445
|
|
|
380
|
-
async openFromVfs({
|
|
446
|
+
async openFromVfs({
|
|
447
|
+
appId,
|
|
448
|
+
baseUrl,
|
|
449
|
+
initialPage = null,
|
|
450
|
+
query = null,
|
|
451
|
+
fetch,
|
|
452
|
+
signal,
|
|
453
|
+
headers,
|
|
454
|
+
requestInterceptor,
|
|
455
|
+
}) {
|
|
381
456
|
const bundle = await loadBundleFromVfs({
|
|
382
457
|
appId,
|
|
383
458
|
baseUrl,
|
|
384
459
|
fetch,
|
|
385
460
|
signal,
|
|
386
461
|
headers,
|
|
462
|
+
requestInterceptor,
|
|
387
463
|
});
|
|
388
464
|
this.openBundle({
|
|
389
465
|
appId: bundle.appId,
|
|
@@ -472,5 +548,9 @@ export function createFrameworkBindings() {
|
|
|
472
548
|
ensureLeadingSlash,
|
|
473
549
|
initInk,
|
|
474
550
|
createInkView,
|
|
551
|
+
configureNetwork,
|
|
552
|
+
setInkRequestInterceptor,
|
|
553
|
+
clearInkRequestInterceptor,
|
|
554
|
+
createProxyUrlResolver,
|
|
475
555
|
};
|
|
476
556
|
}
|
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_8655: (a: number, b: number) => void;
|
|
45
|
+
readonly __wasm_bindgen_func_elem_12872: (a: number, b: number) => void;
|
|
46
|
+
readonly __wasm_bindgen_func_elem_8822: (a: number, b: number, c: number) => void;
|
|
47
|
+
readonly __wasm_bindgen_func_elem_12873: (a: number, b: number, c: number) => void;
|
|
48
|
+
readonly __wasm_bindgen_func_elem_8821: (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
|
@@ -314,6 +314,10 @@ function __wbg_get_imports() {
|
|
|
314
314
|
const ret = getObject(arg0).call(getObject(arg1));
|
|
315
315
|
return addHeapObject(ret);
|
|
316
316
|
}, arguments); },
|
|
317
|
+
__wbg_call_e8c868596c950cf6: function() { return handleError(function (arg0, arg1, arg2, arg3, arg4) {
|
|
318
|
+
const ret = getObject(arg0).call(getObject(arg1), getObject(arg2), getObject(arg3), getObject(arg4));
|
|
319
|
+
return addHeapObject(ret);
|
|
320
|
+
}, arguments); },
|
|
317
321
|
__wbg_clearRect_1eed255045515c55: function(arg0, arg1, arg2, arg3, arg4) {
|
|
318
322
|
getObject(arg0).clearRect(arg1, arg2, arg3, arg4);
|
|
319
323
|
},
|
|
@@ -433,10 +437,6 @@ function __wbg_get_imports() {
|
|
|
433
437
|
__wbg_error_9a7fe3f932034cde: function(arg0) {
|
|
434
438
|
console.error(getObject(arg0));
|
|
435
439
|
},
|
|
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
440
|
__wbg_fillRect_d44afec47e3a3fab: function(arg0, arg1, arg2, arg3, arg4) {
|
|
441
441
|
getObject(arg0).fillRect(arg1, arg2, arg3, arg4);
|
|
442
442
|
},
|
|
@@ -943,28 +943,28 @@ function __wbg_get_imports() {
|
|
|
943
943
|
return ret;
|
|
944
944
|
},
|
|
945
945
|
__wbindgen_cast_0000000000000001: function(arg0, arg1) {
|
|
946
|
-
// Cast intrinsic for `Closure(Closure { dtor_idx:
|
|
947
|
-
const ret = makeMutClosure(arg0, arg1, wasm.
|
|
946
|
+
// Cast intrinsic for `Closure(Closure { dtor_idx: 2276, function: Function { arguments: [NamedExternref("CloseEvent")], shim_idx: 2278, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
|
|
947
|
+
const ret = makeMutClosure(arg0, arg1, wasm.__wasm_bindgen_func_elem_8655, __wasm_bindgen_func_elem_8822);
|
|
948
948
|
return addHeapObject(ret);
|
|
949
949
|
},
|
|
950
950
|
__wbindgen_cast_0000000000000002: function(arg0, arg1) {
|
|
951
|
-
// Cast intrinsic for `Closure(Closure { dtor_idx:
|
|
952
|
-
const ret = makeMutClosure(arg0, arg1, wasm.
|
|
951
|
+
// Cast intrinsic for `Closure(Closure { dtor_idx: 2276, function: Function { arguments: [NamedExternref("Event")], shim_idx: 2278, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
|
|
952
|
+
const ret = makeMutClosure(arg0, arg1, wasm.__wasm_bindgen_func_elem_8655, __wasm_bindgen_func_elem_8822);
|
|
953
953
|
return addHeapObject(ret);
|
|
954
954
|
},
|
|
955
955
|
__wbindgen_cast_0000000000000003: function(arg0, arg1) {
|
|
956
|
-
// Cast intrinsic for `Closure(Closure { dtor_idx:
|
|
957
|
-
const ret = makeMutClosure(arg0, arg1, wasm.
|
|
956
|
+
// Cast intrinsic for `Closure(Closure { dtor_idx: 2276, function: Function { arguments: [NamedExternref("MessageEvent")], shim_idx: 2278, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
|
|
957
|
+
const ret = makeMutClosure(arg0, arg1, wasm.__wasm_bindgen_func_elem_8655, __wasm_bindgen_func_elem_8822);
|
|
958
958
|
return addHeapObject(ret);
|
|
959
959
|
},
|
|
960
960
|
__wbindgen_cast_0000000000000004: function(arg0, arg1) {
|
|
961
|
-
// Cast intrinsic for `Closure(Closure { dtor_idx:
|
|
962
|
-
const ret = makeMutClosure(arg0, arg1, wasm.
|
|
961
|
+
// Cast intrinsic for `Closure(Closure { dtor_idx: 2276, function: Function { arguments: [], shim_idx: 2280, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
|
|
962
|
+
const ret = makeMutClosure(arg0, arg1, wasm.__wasm_bindgen_func_elem_8655, __wasm_bindgen_func_elem_8821);
|
|
963
963
|
return addHeapObject(ret);
|
|
964
964
|
},
|
|
965
965
|
__wbindgen_cast_0000000000000005: function(arg0, arg1) {
|
|
966
966
|
// Cast intrinsic for `Closure(Closure { dtor_idx: 3267, function: Function { arguments: [Externref], shim_idx: 3268, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
|
|
967
|
-
const ret = makeMutClosure(arg0, arg1, wasm.
|
|
967
|
+
const ret = makeMutClosure(arg0, arg1, wasm.__wasm_bindgen_func_elem_12872, __wasm_bindgen_func_elem_12873);
|
|
968
968
|
return addHeapObject(ret);
|
|
969
969
|
},
|
|
970
970
|
__wbindgen_cast_0000000000000006: function(arg0) {
|
|
@@ -1019,16 +1019,16 @@ function __wbg_get_imports() {
|
|
|
1019
1019
|
};
|
|
1020
1020
|
}
|
|
1021
1021
|
|
|
1022
|
-
function
|
|
1023
|
-
wasm.
|
|
1022
|
+
function __wasm_bindgen_func_elem_8821(arg0, arg1) {
|
|
1023
|
+
wasm.__wasm_bindgen_func_elem_8821(arg0, arg1);
|
|
1024
1024
|
}
|
|
1025
1025
|
|
|
1026
|
-
function
|
|
1027
|
-
wasm.
|
|
1026
|
+
function __wasm_bindgen_func_elem_8822(arg0, arg1, arg2) {
|
|
1027
|
+
wasm.__wasm_bindgen_func_elem_8822(arg0, arg1, addHeapObject(arg2));
|
|
1028
1028
|
}
|
|
1029
1029
|
|
|
1030
|
-
function
|
|
1031
|
-
wasm.
|
|
1030
|
+
function __wasm_bindgen_func_elem_12873(arg0, arg1, arg2) {
|
|
1031
|
+
wasm.__wasm_bindgen_func_elem_12873(arg0, arg1, addHeapObject(arg2));
|
|
1032
1032
|
}
|
|
1033
1033
|
|
|
1034
1034
|
|
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_8655: (a: number, b: number) => void;
|
|
20
|
+
export const __wasm_bindgen_func_elem_12872: (a: number, b: number) => void;
|
|
21
|
+
export const __wasm_bindgen_func_elem_8822: (a: number, b: number, c: number) => void;
|
|
22
|
+
export const __wasm_bindgen_func_elem_12873: (a: number, b: number, c: number) => void;
|
|
23
|
+
export const __wasm_bindgen_func_elem_8821: (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;
|