-
Notifications
You must be signed in to change notification settings - Fork 12
/
Copy pathinterfaces.ts
396 lines (351 loc) · 12 KB
/
interfaces.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
import { CallContext } from './call-context.ts';
/**
* {@link Plugin} Config
*/
export interface PluginConfigLike {
[key: string]: string;
}
/**
* `PluginOutput` is a view around some memory exposed by the plugin. Typically
* returned by {@link Plugin#call | `plugin.call()`} or {@link CallContext#read
* | `callContext.read()`}. It implements the read side of
* [`DataView`](https://mdn.io/dataview) along with methods for reading string
* and JSON data out of the backing buffer.
*/
export class PluginOutput extends DataView {
static #decoder = new TextDecoder();
#bytes: Uint8Array | null = null;
/** @hidden */
constructor(buffer: ArrayBufferLike) {
super(buffer);
}
json(): any {
return JSON.parse(this.string());
}
arrayBuffer(): ArrayBufferLike {
return this.buffer;
}
text(): string {
return this.string();
}
/** @hidden */
string(): string {
return PluginOutput.#decoder.decode(this.buffer);
}
bytes(): Uint8Array {
this.#bytes ??= new Uint8Array(this.buffer);
return this.#bytes;
}
setInt8(_byteOffset: number, _value: number): void {
throw new Error('Cannot set values on output');
}
setInt16(_byteOffset: number, _value: number, _littleEndian?: boolean): void {
throw new Error('Cannot set values on output');
}
setInt32(_byteOffset: number, _value: number, _littleEndian?: boolean): void {
throw new Error('Cannot set values on output');
}
setUint8(_byteOffset: number, _value: number): void {
throw new Error('Cannot set values on output');
}
setUint16(_byteOffset: number, _value: number, _littleEndian?: boolean): void {
throw new Error('Cannot set values on output');
}
setUint32(_byteOffset: number, _value: number, _littleEndian?: boolean): void {
throw new Error('Cannot set values on output');
}
setFloat32(_byteOffset: number, _value: number, _littleEndian?: boolean): void {
throw new Error('Cannot set values on output');
}
setFloat64(_byteOffset: number, _value: number, _littleEndian?: boolean): void {
throw new Error('Cannot set values on output');
}
setBigInt64(_byteOffset: number, _value: bigint, _littleEndian?: boolean): void {
throw new Error('Cannot set values on output');
}
setBigUint64(_byteOffset: number, _value: bigint, _littleEndian?: boolean): void {
throw new Error('Cannot set values on output');
}
}
export type PluginConfig = Record<string, string>;
export interface Plugin {
/**
* Check if a function exists in the WebAssembly module.
*
* @param {string | [string, string]} funcName The function's name, or a tuple of target module name and function name.
* @returns {Promise<boolean>} true if the function exists, otherwise false
*/
functionExists(funcName: string | [string, string]): Promise<boolean>;
close(): Promise<void>;
/**
* Call a specific function from the WebAssembly module with provided input.
*
* @param {string | [string, string]} funcName The name of the function to call
* @param {Uint8Array | string} input The input to pass to the function
* @returns {Promise<PluginOutput | null>} The result from the function call
*/
call(funcName: string | [string, string], input?: string | number | Uint8Array): Promise<PluginOutput | null>;
getExports(name?: string): Promise<WebAssembly.ModuleExportDescriptor[]>;
getImports(name?: string): Promise<WebAssembly.ModuleImportDescriptor[]>;
getInstance(name?: string): Promise<WebAssembly.Instance>;
/**
* Whether the plugin is currently processing a call.
*/
isActive(): boolean;
/**
* Reset Plugin memory. If called while the plugin is {@link Plugin#isActive|actively executing}, memory will not be reset.
*
* @returns {Promise<boolean>} Whether or not the reset was successful.
*/
reset(): Promise<boolean>;
}
/**
* Options for initializing an Extism plugin.
*/
export interface ExtismPluginOptions {
/**
* Whether or not to enable WASI preview 1.
*/
useWasi?: boolean;
/**
* Whether or not to run the Wasm module in a Worker thread. Requires
* {@link Capabilities#hasWorkerCapability | `CAPABILITIES.hasWorkerCapability`} to
* be true. Defaults to false.
*
* This feature is marked experimental as we work out [a bug](https://github.com/extism/js-sdk/issues/46).
*
* @experimental
*/
runInWorker?: boolean;
/**
* A logger implementation. Must provide `info`, `debug`, `warn`, and `error` methods.
*/
logger?: Console;
/**
* A map of namespaces to function names to host functions.
*
* ```js
* const functions = {
* 'my_great_namespace': {
* 'my_func': (callContext: CallContext, input: bigint) => {
* const output = callContext.read(input);
* if (output !== null) {
* console.log(output.string());
* }
* }
* }
* }
* ```
*/
functions?: { [key: string]: { [key: string]: (callContext: CallContext, ...args: any[]) => any } } | undefined;
allowedPaths?: { [key: string]: string } | undefined;
allowedHosts?: string[] | undefined;
/**
* Whether WASI stdout should be forwarded to the host.
*
* Overrides the `EXTISM_ENABLE_WASI_OUTPUT` environment variable.
*/
enableWasiOutput?: boolean;
config?: PluginConfigLike;
fetch?: typeof fetch;
sharedArrayBufferSize?: number;
}
export interface InternalConfig {
logger: Console;
allowedHosts: string[];
allowedPaths: { [key: string]: string };
enableWasiOutput: boolean;
functions: { [namespace: string]: { [func: string]: any } };
fetch: typeof fetch;
wasiEnabled: boolean;
config: PluginConfig;
sharedArrayBufferSize: number;
}
export interface InternalWasi {
importObject(): Promise<Record<string, WebAssembly.ImportValue>>;
initialize(instance: WebAssembly.Instance): Promise<void>;
close(): Promise<void>;
}
/**
* Represents the raw bytes of a WASM file loaded into memory
*
* @category Manifests
*/
export interface ManifestWasmData {
data: Uint8Array;
}
/**
* Represents a url to a WASM module
*/
export interface ManifestWasmUrl {
url: URL | string;
}
/**
* Represents a path to a WASM module
*/
export interface ManifestWasmPath {
path: string;
}
/**
* Represents a WASM module as a response
*/
export interface ManifestWasmResponse {
response: Response;
}
/**
* Represents a WASM module as a response
*/
export interface ManifestWasmModule {
module: WebAssembly.Module;
}
/**
* The WASM to load as bytes, a path, a fetch `Response`, a `WebAssembly.Module`, or a url
*
* @property name The name of the Wasm module. Used when disambiguating {@link Plugin#call | `Plugin#call`} targets when the
* plugin embeds multiple Wasm modules.
*
* @property hash The expected SHA-256 hash of the associated Wasm module data. {@link createPlugin} validates incoming Wasm against
* provided hashes. If running on Node v18, `node` must be invoked using the `--experimental-global-webcrypto` flag.
*
* ⚠️ `module` cannot be used in conjunction with `hash`: the Web Platform does not currently provide a way to get source
* bytes from a `WebAssembly.Module` in order to hash.
*
*/
export type ManifestWasm = (
| ManifestWasmUrl
| ManifestWasmData
| ManifestWasmPath
| ManifestWasmResponse
| ManifestWasmModule
) & {
name?: string;
hash?: string;
};
/**
* The manifest which describes the {@link Plugin} code and runtime constraints. This is passed to {@link createPlugin}
*
* ```js
* let manifest = {
* wasm: [{name: 'my-wasm', url: 'http://example.com/path/to/wasm'}],
* config: {
* 'greeting': 'hello' // these variables will be available via `extism_get_var` in plugins
* }
* }
* ```
*
* Every member of `.wasm` is expected to be an instance of {@link ManifestWasm}.
*
* @see [Extism](https://extism.org/) > [Concepts](https://extism.org/docs/category/concepts) > [Manifest](https://extism.org/docs/concepts/manifest)
*/
export interface Manifest {
wasm: Array<ManifestWasm>;
config?: PluginConfigLike;
}
/**
* Any type that can be converted into an Extism {@link Manifest}.
* - `object` instances that implement {@link Manifest} are validated.
* - `ArrayBuffer` instances are converted into {@link Manifest}s with a single {@link ManifestUint8Array} member.
* - `URL` instances are fetched and their responses interpreted according to their `content-type` response header. `application/wasm` and `application/octet-stream` items
* are treated as {@link ManifestUint8Array} items; `application/json` and `text/json` are treated as JSON-encoded {@link Manifest}s.
* - `string` instances that start with `http://`, `https://`, or `file://` are treated as URLs.
* - `string` instances that start with `{` treated as JSON-encoded {@link Manifest}s.
* - All other `string` instances are treated as {@link ManifestWasmPath}.
*
* ```js
* let manifest = {
* wasm: [{name: 'my-wasm', url: 'http://example.com/path/to/wasm'}],
* config: {
* 'greeting': 'hello' // these variables will be available via `extism_get_var` in plugins
* }
* }
*
* let manifest = '{"wasm": {"url": "https://example.com"}}'
* let manifest = 'path/to/file.wasm'
* let manifest = new ArrayBuffer()
* ```
*
* @see [Extism](https://extism.org/) > [Concepts](https://extism.org/docs/category/concepts) > [Manifest](https://extism.org/docs/concepts/manifest)
*
* @throws {@link TypeError} when `URL` parameters don't resolve to a known `content-type`
* @throws {@link TypeError} when the resulting {@link Manifest} does not contain a `wasm` member with valid {@link ManifestWasm} items.
*/
export type ManifestLike = Manifest | Response | WebAssembly.Module | ArrayBuffer | string | URL;
export interface Capabilities {
/**
* Whether or not the environment allows SharedArrayBuffers to be passed to `TextDecoder.decode` and `TextEncoder.encodeInto` directly
*
* - ✅ node
* - ✅ deno
* - ✅ bun
* - ❌ firefox
* - ❌ chrome
* - ❌ webkit
*/
allowSharedBufferCodec: boolean;
/**
* Whether or not {@link ManifestWasm} items support the "path:" key.
*
* - ✅ node
* - ✅ deno
* - ✅ bun
* - ❌ firefox
* - ❌ chrome
* - ❌ webkit
*/
manifestSupportsPaths: boolean;
/**
* Whether or not cross-origin checks are enforced for outgoing HTTP requests on this platform.
*
* - ❌ node
* - ❌ deno
* - ❌ bun
* - ✅ firefox
* - ✅ chrome
* - ✅ webkit
*/
crossOriginChecksEnforced: boolean;
/**
* Whether or not the host environment has access to a filesystem.
*
* - ✅ node
* - ✅ deno
* - ✅ bun
* - ❌ firefox
* - ❌ chrome
* - ❌ webkit
*/
fsAccess: boolean;
/**
* Whether or not the host environment supports moving Wasm plugin workloads to a worker. This requires
* SharedArrayBuffer support, which requires `window.crossOriginIsolated` to be true in browsers.
*
* @see [`crossOriginalIsolated` on MDN](https://mdn.io/crossOriginIsolated)
*
* - ✅ node
* - ✅ deno
* - ✅ bun
* - 🔒 firefox
* - 🔒 chrome
* - 🔒 webkit
*/
hasWorkerCapability: boolean;
/**
* Whether or not the host environment supports WASI preview 1.
*
* @see [`WASI`](https://wasi.dev/) and [`WASI Preview 1`](https://github.com/WebAssembly/WASI/blob/main/legacy/preview1/docs.md)
*
* - ✅ node (via [`node:wasi`](https://nodejs.org/api/wasi.html))
* - ✅ deno (via [`deno.land/std/wasi/snapshot_preview1`](https://deno.land/[email protected]/wasi/snapshot_preview1.ts))
* - ❌ bun
* - ✅ firefox (via [`@bjorn3/browser_wasi_shim`](https://www.npmjs.com/package/@bjorn3/browser_wasi_shim))
* - ✅ chrome (via [`@bjorn3/browser_wasi_shim`](https://www.npmjs.com/package/@bjorn3/browser_wasi_shim))
* - ✅ webkit (via [`@bjorn3/browser_wasi_shim`](https://www.npmjs.com/package/@bjorn3/browser_wasi_shim))
*/
supportsWasiPreview1: boolean;
/**
* Whether or not the `EXTISM_ENABLE_WASI_OUTPUT` environment variable has been set.
*
* This value is consulted whenever {@link ExtismPluginOptions#enableWasiOutput} is omitted.
*/
extismStdoutEnvVarSet: boolean;
}