space-data-module-sdk 0.5.15 → 0.5.19
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 +51 -0
- package/package.json +13 -4
- package/schemas/HostStorageAbi.fbs +53 -0
- package/src/browser.js +6 -0
- package/src/bundle/codec.js +1 -1
- package/src/compiler/compileModule.js +3 -0
- package/src/compliance/pluginCompliance.js +1 -2
- package/src/generated/orbpro/invoke/plugin-invoke-request.js +1 -1
- package/src/generated/orbpro/invoke/plugin-invoke-response.js +1 -1
- package/src/generated/orbpro/manifest/accepted-type-set.js +1 -1
- package/src/generated/orbpro/manifest/build-artifact.js +1 -1
- package/src/generated/orbpro/manifest/host-capability.js +1 -1
- package/src/generated/orbpro/manifest/method-manifest.js +1 -1
- package/src/generated/orbpro/manifest/plugin-manifest.js +1 -1
- package/src/generated/orbpro/manifest/port-manifest.js +1 -1
- package/src/generated/orbpro/manifest/protocol-spec.js +1 -1
- package/src/generated/orbpro/manifest/timer-spec.js +1 -1
- package/src/generated/orbpro/module/canonicalization-rule.js +1 -1
- package/src/generated/orbpro/module/module-bundle-entry.js +1 -1
- package/src/generated/orbpro/module/module-bundle.js +1 -1
- package/src/generated/orbpro/stream/flat-buffer-type-ref.js +1 -1
- package/src/generated/orbpro/stream/typed-arena-buffer.js +1 -1
- package/src/host/browserEdgeShims.js +355 -0
- package/src/host/browserHost.js +399 -0
- package/src/host/index.js +4 -0
- package/src/host/isomorphicLoader.js +101 -0
- package/src/host/wasiShim.js +275 -0
- package/src/index.d.ts +364 -0
- package/src/index.js +1 -0
- package/src/invoke/codec.js +1 -1
- package/src/manifest/codec.js +1 -1
- package/src/manifest/typeRefs.js +49 -12
- package/src/runtime-host/flatsqlRuntimeStore.js +217 -0
- package/src/runtime-host/index.js +21 -0
- package/src/runtime-host/moduleRegistry.js +92 -0
- package/src/runtime-host/runtimeRegionStore.js +245 -0
- package/src/testing/browserModuleHarness.js +275 -0
- package/src/testing/buildWasmEdgeRunner.js +41 -2
- package/src/testing/index.d.ts +173 -2
- package/src/testing/index.js +5 -0
- package/src/testing/moduleHarness.js +102 -1
- package/src/testing/native/wasmedge_emscripten_pthread_runner.c +2319 -209
- package/src/testing/processInvoke.js +250 -9
- package/src/testing/streamInvokeCodec.js +175 -0
- package/src/transport/records.js +19 -6
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Browser-side module harness.
|
|
3
|
+
*
|
|
4
|
+
* Loads the same standalone WASI .wasm artifact that WasmEdge runs,
|
|
5
|
+
* instantiating it in the browser with the WASI shim + optional sdn_host
|
|
6
|
+
* bridge. Matches the createModuleHarness() API surface.
|
|
7
|
+
*
|
|
8
|
+
* Supports two invoke paths:
|
|
9
|
+
* 1. "direct" — call plugin_invoke_stream(ptr, len, &outLen) and read
|
|
10
|
+
* the FlatBuffer response from WASM memory.
|
|
11
|
+
* 2. "command" — call _start() with stdin piped via WASI shim, read
|
|
12
|
+
* stdout for the response bytes.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { createBrowserWasiShim, WasiExitError } from "../host/wasiShim.js";
|
|
16
|
+
import { createBrowserHost } from "../host/browserHost.js";
|
|
17
|
+
import {
|
|
18
|
+
createJsonHostcallBridge,
|
|
19
|
+
createNodeHostSyncDispatcher,
|
|
20
|
+
DEFAULT_HOSTCALL_IMPORT_MODULE,
|
|
21
|
+
} from "../host/abi.js";
|
|
22
|
+
import {
|
|
23
|
+
DefaultInvokeExports,
|
|
24
|
+
DefaultManifestExports,
|
|
25
|
+
} from "../runtime/constants.js";
|
|
26
|
+
import {
|
|
27
|
+
encodePluginInvokeRequest,
|
|
28
|
+
decodePluginInvokeResponse,
|
|
29
|
+
} from "../invoke/codec.js";
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Detect artifact profile from WebAssembly.Module imports.
|
|
33
|
+
* Returns "standalone" (WASI-only), "sdn-abi" (WASI + sdn_host),
|
|
34
|
+
* or "emscripten" (env.* with invoke trampolines).
|
|
35
|
+
*/
|
|
36
|
+
export function detectArtifactProfile(wasmModule) {
|
|
37
|
+
const imports = WebAssembly.Module.imports(wasmModule);
|
|
38
|
+
const moduleNames = new Set(imports.map((i) => i.module));
|
|
39
|
+
|
|
40
|
+
if (moduleNames.has("env")) {
|
|
41
|
+
const envImports = imports.filter((i) => i.module === "env");
|
|
42
|
+
const hasInvokeTrampolines = envImports.some((i) => i.name.startsWith("invoke_"));
|
|
43
|
+
const hasPthreads = envImports.some(
|
|
44
|
+
(i) => i.name.includes("pthread") || i.name.includes("thread"),
|
|
45
|
+
);
|
|
46
|
+
if (hasInvokeTrampolines || hasPthreads) {
|
|
47
|
+
return "emscripten";
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (moduleNames.has(DEFAULT_HOSTCALL_IMPORT_MODULE)) {
|
|
52
|
+
return "sdn-abi";
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (moduleNames.has("wasi_snapshot_preview1") || moduleNames.has("wasi_unstable")) {
|
|
56
|
+
return "standalone";
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return "unknown";
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
async function compileWasmModule(source) {
|
|
63
|
+
if (source instanceof WebAssembly.Module) {
|
|
64
|
+
return source;
|
|
65
|
+
}
|
|
66
|
+
if (source instanceof Response) {
|
|
67
|
+
return WebAssembly.compileStreaming(source);
|
|
68
|
+
}
|
|
69
|
+
if (typeof source === "string") {
|
|
70
|
+
return WebAssembly.compileStreaming(fetch(source));
|
|
71
|
+
}
|
|
72
|
+
const bytes = source instanceof ArrayBuffer ? new Uint8Array(source) : source;
|
|
73
|
+
return WebAssembly.compile(bytes);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
async function instantiateBrowserModule(options = {}) {
|
|
77
|
+
const wasi = createBrowserWasiShim({
|
|
78
|
+
args: options.args ?? [],
|
|
79
|
+
env: options.env ?? {},
|
|
80
|
+
stdinBytes: options.stdinBytes ?? new Uint8Array(),
|
|
81
|
+
logOutput: options.logOutput === true,
|
|
82
|
+
performance: options.performance,
|
|
83
|
+
});
|
|
84
|
+
const importObject = { ...wasi.imports };
|
|
85
|
+
const moduleImports = WebAssembly.Module.imports(options.wasmModule);
|
|
86
|
+
const needsHostBridge = moduleImports.some(
|
|
87
|
+
(entry) => entry.module === DEFAULT_HOSTCALL_IMPORT_MODULE,
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
let instance = null;
|
|
91
|
+
let bridge = null;
|
|
92
|
+
if (needsHostBridge) {
|
|
93
|
+
const dispatch = createNodeHostSyncDispatcher(options.host);
|
|
94
|
+
bridge = createJsonHostcallBridge({
|
|
95
|
+
dispatch,
|
|
96
|
+
getMemory: () => instance.exports.memory,
|
|
97
|
+
});
|
|
98
|
+
Object.assign(importObject, bridge.imports);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
instance = await WebAssembly.instantiate(options.wasmModule, importObject);
|
|
102
|
+
if (instance.exports.memory) {
|
|
103
|
+
wasi.setMemory(instance.exports.memory);
|
|
104
|
+
}
|
|
105
|
+
if (instance.exports._initialize) {
|
|
106
|
+
instance.exports._initialize();
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return {
|
|
110
|
+
instance,
|
|
111
|
+
bridge,
|
|
112
|
+
wasi,
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Create a browser-side module harness for a standalone WASI artifact.
|
|
118
|
+
*
|
|
119
|
+
* @param {Object} options
|
|
120
|
+
* @param {Uint8Array|ArrayBuffer|Response|string} options.wasmSource
|
|
121
|
+
* WASM bytes, ArrayBuffer, fetch Response, or URL string.
|
|
122
|
+
* @param {Object} [options.host] - BrowserHost instance (created if omitted).
|
|
123
|
+
* @param {string[]} [options.args] - WASI args passed to the module.
|
|
124
|
+
* @param {Object} [options.env] - WASI environment variables.
|
|
125
|
+
* @param {string} [options.surface] - "direct" or "command" (default: auto-detect).
|
|
126
|
+
*/
|
|
127
|
+
export async function createBrowserModuleHarness(options = {}) {
|
|
128
|
+
const host = options.host ?? createBrowserHost(options.hostOptions);
|
|
129
|
+
const wasmModule = await compileWasmModule(options.wasmSource);
|
|
130
|
+
|
|
131
|
+
const profile = detectArtifactProfile(wasmModule);
|
|
132
|
+
const moduleExports = WebAssembly.Module.exports(wasmModule);
|
|
133
|
+
const exportNames = new Set(moduleExports.map((e) => e.name));
|
|
134
|
+
|
|
135
|
+
const hasDirectInvoke = exportNames.has(DefaultInvokeExports.invokeSymbol);
|
|
136
|
+
const hasCommand = exportNames.has(DefaultInvokeExports.commandSymbol);
|
|
137
|
+
const surface =
|
|
138
|
+
options.surface ?? (hasDirectInvoke ? "direct" : hasCommand ? "command" : "direct");
|
|
139
|
+
if (profile === "emscripten") {
|
|
140
|
+
throw new Error(
|
|
141
|
+
"Browser harness only supports standalone WASI or sdn_host artifacts. " +
|
|
142
|
+
'Compile shared browser/WasmEdge modules with runtimeTargets: ["browser", "wasmedge"] ' +
|
|
143
|
+
'or override threadModel to "single-thread".',
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const activeContext = await instantiateBrowserModule({
|
|
148
|
+
wasmModule,
|
|
149
|
+
host,
|
|
150
|
+
args: options.args,
|
|
151
|
+
env: options.env,
|
|
152
|
+
performance: options.performance ?? host?.performance,
|
|
153
|
+
logOutput: options.logOutput === true,
|
|
154
|
+
});
|
|
155
|
+
const { instance, bridge, wasi } = activeContext;
|
|
156
|
+
|
|
157
|
+
// --- Invoke helpers ---
|
|
158
|
+
function invokeDirectRaw(requestBytes) {
|
|
159
|
+
const alloc = instance.exports[DefaultInvokeExports.allocSymbol];
|
|
160
|
+
const free = instance.exports[DefaultInvokeExports.freeSymbol];
|
|
161
|
+
const invokeStream = instance.exports[DefaultInvokeExports.invokeSymbol];
|
|
162
|
+
const memory = instance.exports.memory;
|
|
163
|
+
if (
|
|
164
|
+
typeof alloc !== "function" ||
|
|
165
|
+
typeof free !== "function" ||
|
|
166
|
+
typeof invokeStream !== "function" ||
|
|
167
|
+
!memory
|
|
168
|
+
) {
|
|
169
|
+
throw new Error(
|
|
170
|
+
"Direct browser invoke requires plugin_alloc, plugin_free, plugin_invoke_stream, and memory exports.",
|
|
171
|
+
);
|
|
172
|
+
}
|
|
173
|
+
const reqLen = requestBytes.length;
|
|
174
|
+
const reqPtr = alloc(reqLen);
|
|
175
|
+
if (!reqPtr) throw new Error("plugin_alloc returned null for request.");
|
|
176
|
+
|
|
177
|
+
new Uint8Array(memory.buffer, reqPtr, reqLen).set(requestBytes);
|
|
178
|
+
|
|
179
|
+
// Allocate space for the response length output
|
|
180
|
+
const outLenPtr = alloc(4);
|
|
181
|
+
if (!outLenPtr) throw new Error("plugin_alloc returned null for response length.");
|
|
182
|
+
|
|
183
|
+
new DataView(memory.buffer).setUint32(outLenPtr, 0, true);
|
|
184
|
+
|
|
185
|
+
const resPtr = invokeStream(reqPtr, reqLen, outLenPtr);
|
|
186
|
+
const resLen = new DataView(memory.buffer).getUint32(outLenPtr, true);
|
|
187
|
+
|
|
188
|
+
free(reqPtr, reqLen);
|
|
189
|
+
free(outLenPtr, 4);
|
|
190
|
+
|
|
191
|
+
if (!resPtr || !resLen) {
|
|
192
|
+
throw new Error("plugin_invoke_stream returned null response.");
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
const responseBytes = new Uint8Array(memory.buffer, resPtr, resLen).slice();
|
|
196
|
+
free(resPtr, resLen);
|
|
197
|
+
return responseBytes;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
async function invokeCommandRaw(stdinBytes) {
|
|
201
|
+
const commandContext = await instantiateBrowserModule({
|
|
202
|
+
wasmModule,
|
|
203
|
+
host,
|
|
204
|
+
args: options.args,
|
|
205
|
+
env: options.env,
|
|
206
|
+
stdinBytes,
|
|
207
|
+
performance: options.performance ?? host?.performance,
|
|
208
|
+
logOutput: false,
|
|
209
|
+
});
|
|
210
|
+
try {
|
|
211
|
+
const commandExport = commandContext.instance.exports[DefaultInvokeExports.commandSymbol];
|
|
212
|
+
if (typeof commandExport !== "function") {
|
|
213
|
+
throw new Error(
|
|
214
|
+
`Command-surface browser invoke requires the ${DefaultInvokeExports.commandSymbol} export.`,
|
|
215
|
+
);
|
|
216
|
+
}
|
|
217
|
+
commandExport();
|
|
218
|
+
} catch (error) {
|
|
219
|
+
if (!(error instanceof WasiExitError) || error.code !== 0) {
|
|
220
|
+
throw error;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
return commandContext.wasi.stdout;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// --- Public API ---
|
|
227
|
+
|
|
228
|
+
async function invokeRaw(requestBytes) {
|
|
229
|
+
if (surface === "command") {
|
|
230
|
+
return invokeCommandRaw(requestBytes);
|
|
231
|
+
}
|
|
232
|
+
return invokeDirectRaw(requestBytes);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
async function invoke(request) {
|
|
236
|
+
const requestBytes = encodePluginInvokeRequest(request);
|
|
237
|
+
const responseBytes = await invokeRaw(requestBytes);
|
|
238
|
+
return decodePluginInvokeResponse(responseBytes);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
function readManifest() {
|
|
242
|
+
const getBytesExport =
|
|
243
|
+
instance.exports[DefaultManifestExports.pluginBytesSymbol];
|
|
244
|
+
const getSizeExport =
|
|
245
|
+
instance.exports[DefaultManifestExports.pluginSizeSymbol];
|
|
246
|
+
if (!getBytesExport || !getSizeExport) return null;
|
|
247
|
+
|
|
248
|
+
const ptr = getBytesExport();
|
|
249
|
+
const size = getSizeExport();
|
|
250
|
+
if (!ptr || !size) return null;
|
|
251
|
+
|
|
252
|
+
return new Uint8Array(instance.exports.memory.buffer, ptr, size).slice();
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
function destroy() {
|
|
256
|
+
wasi.flushOutput();
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
return {
|
|
260
|
+
runtime: {
|
|
261
|
+
kind: "browser",
|
|
262
|
+
profile,
|
|
263
|
+
surface,
|
|
264
|
+
},
|
|
265
|
+
instance,
|
|
266
|
+
module: wasmModule,
|
|
267
|
+
host,
|
|
268
|
+
bridge,
|
|
269
|
+
wasi,
|
|
270
|
+
invoke,
|
|
271
|
+
invokeRaw,
|
|
272
|
+
readManifest,
|
|
273
|
+
destroy,
|
|
274
|
+
};
|
|
275
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { accessSync, existsSync } from "node:fs";
|
|
2
2
|
import { execFile } from "node:child_process";
|
|
3
|
+
import os from "node:os";
|
|
3
4
|
import path from "node:path";
|
|
4
5
|
import process from "node:process";
|
|
5
6
|
import { promisify } from "node:util";
|
|
@@ -63,12 +64,50 @@ export function resolveWasmEdgeRunnerSourcePath() {
|
|
|
63
64
|
);
|
|
64
65
|
}
|
|
65
66
|
|
|
67
|
+
function resolveDefaultWasmEdgeInstall() {
|
|
68
|
+
const home = os.homedir();
|
|
69
|
+
const candidates = [
|
|
70
|
+
{
|
|
71
|
+
includeDir: path.join(home, ".wasmedge", "include"),
|
|
72
|
+
libDir: path.join(home, ".wasmedge", "lib"),
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
includeDir: "/opt/homebrew/include",
|
|
76
|
+
libDir: "/opt/homebrew/opt/wasmedge/lib",
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
includeDir: "/usr/local/include",
|
|
80
|
+
libDir: "/usr/local/lib",
|
|
81
|
+
},
|
|
82
|
+
];
|
|
83
|
+
for (const candidate of candidates) {
|
|
84
|
+
const header = path.join(
|
|
85
|
+
candidate.includeDir,
|
|
86
|
+
"wasmedge",
|
|
87
|
+
"enum_configure.h",
|
|
88
|
+
);
|
|
89
|
+
const library = path.join(
|
|
90
|
+
candidate.libDir,
|
|
91
|
+
resolveWasmEdgeSharedLibraryFilename(),
|
|
92
|
+
);
|
|
93
|
+
if (existsSync(header) && existsSync(library)) {
|
|
94
|
+
return candidate;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
|
|
66
100
|
export function resolveWasmEdgeRunnerBuildPlan(options = {}) {
|
|
101
|
+
const detectedInstall = resolveDefaultWasmEdgeInstall();
|
|
67
102
|
const requestedIncludeDir = normalizeResolvedPath(
|
|
68
|
-
options.wasmedgeIncludeDir ??
|
|
103
|
+
options.wasmedgeIncludeDir ??
|
|
104
|
+
process.env.WASMEDGE_INCLUDE_DIR ??
|
|
105
|
+
detectedInstall?.includeDir,
|
|
69
106
|
);
|
|
70
107
|
const wasmedgeLibDir = normalizeResolvedPath(
|
|
71
|
-
options.wasmedgeLibDir ??
|
|
108
|
+
options.wasmedgeLibDir ??
|
|
109
|
+
process.env.WASMEDGE_LIB_DIR ??
|
|
110
|
+
detectedInstall?.libDir,
|
|
72
111
|
);
|
|
73
112
|
const outputPath = normalizeResolvedPath(
|
|
74
113
|
options.outputPath ?? options.output,
|
package/src/testing/index.d.ts
CHANGED
|
@@ -131,7 +131,55 @@ export interface PluginInvokeProcessLaunchPlan {
|
|
|
131
131
|
args: string[];
|
|
132
132
|
env?: Record<string, string | undefined>;
|
|
133
133
|
cwd?: string;
|
|
134
|
-
wasmPath?: string;
|
|
134
|
+
wasmPath?: string | null;
|
|
135
|
+
hostProfile?: "runtime-host";
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
export interface RuntimeHostTestModuleDefinition {
|
|
139
|
+
moduleId: string;
|
|
140
|
+
wasmPath?: string | null;
|
|
141
|
+
metadata?: unknown;
|
|
142
|
+
[key: string]: unknown;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
export interface RuntimeHostInstalledModule {
|
|
146
|
+
moduleId: string;
|
|
147
|
+
metadata: unknown;
|
|
148
|
+
methodIds: string[];
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export interface RuntimeHostRowHandle {
|
|
152
|
+
schemaFileId: string;
|
|
153
|
+
rowId: number;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
export interface RuntimeHostRowView {
|
|
157
|
+
handle: RuntimeHostRowHandle;
|
|
158
|
+
payload: unknown;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
export interface RuntimeHostRowQueryResult {
|
|
162
|
+
columns: string[];
|
|
163
|
+
rows: unknown[][];
|
|
164
|
+
rowCount: number;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
export interface RuntimeHostRegionDescriptor {
|
|
168
|
+
regionId: number;
|
|
169
|
+
layoutId: string;
|
|
170
|
+
recordByteLength: number;
|
|
171
|
+
alignment: number;
|
|
172
|
+
recordCount: number;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
export interface RuntimeHostRegionRecord {
|
|
176
|
+
regionId: number;
|
|
177
|
+
recordIndex: number;
|
|
178
|
+
layoutId: string;
|
|
179
|
+
recordByteLength: number;
|
|
180
|
+
alignment: number;
|
|
181
|
+
byteLength: number;
|
|
182
|
+
bytes: Uint8Array;
|
|
135
183
|
}
|
|
136
184
|
|
|
137
185
|
export interface PluginInvokeProcessClient {
|
|
@@ -140,12 +188,42 @@ export interface PluginInvokeProcessClient {
|
|
|
140
188
|
invoke(request: {
|
|
141
189
|
methodId?: string | null;
|
|
142
190
|
inputs?: HarnessInputFrame[];
|
|
191
|
+
}): Promise<{
|
|
192
|
+
statusCode: number;
|
|
193
|
+
errorCode?: string | null;
|
|
194
|
+
errorMessage?: string | null;
|
|
195
|
+
outputs: HarnessInputFrame[];
|
|
196
|
+
}>;
|
|
197
|
+
installModule(definition: RuntimeHostTestModuleDefinition): Promise<RuntimeHostInstalledModule>;
|
|
198
|
+
listModules(): Promise<RuntimeHostInstalledModule[]>;
|
|
199
|
+
unloadModule(moduleId: string): Promise<boolean>;
|
|
200
|
+
invokeModule(requestModuleId: string, request: {
|
|
201
|
+
methodId?: string | null;
|
|
202
|
+
inputs?: HarnessInputFrame[];
|
|
143
203
|
}): Promise<{
|
|
144
204
|
statusCode: number;
|
|
145
205
|
errorCode?: string | null;
|
|
146
206
|
errorMessage?: string | null;
|
|
147
207
|
outputs: HarnessInputFrame[];
|
|
148
208
|
}>;
|
|
209
|
+
appendRow(options: {
|
|
210
|
+
schemaFileId: string;
|
|
211
|
+
payload?: unknown;
|
|
212
|
+
}): Promise<RuntimeHostRowHandle>;
|
|
213
|
+
listRows(schemaFileId?: string | null): Promise<RuntimeHostRowView[]>;
|
|
214
|
+
resolveRow(handle: RuntimeHostRowHandle): Promise<RuntimeHostRowView | null>;
|
|
215
|
+
queryRows(sql: string): Promise<RuntimeHostRowQueryResult>;
|
|
216
|
+
allocateRegion(options: {
|
|
217
|
+
layoutId: string;
|
|
218
|
+
recordByteLength: number;
|
|
219
|
+
alignment?: number;
|
|
220
|
+
initialRecords?: Array<Uint8Array | ArrayBuffer | ArrayBufferView | null | undefined>;
|
|
221
|
+
}): Promise<RuntimeHostRegionDescriptor>;
|
|
222
|
+
describeRegion(regionId: number): Promise<RuntimeHostRegionDescriptor | null>;
|
|
223
|
+
resolveRecord(query: {
|
|
224
|
+
regionId: number;
|
|
225
|
+
recordIndex: number;
|
|
226
|
+
}): Promise<RuntimeHostRegionRecord | null>;
|
|
149
227
|
destroy(): Promise<void>;
|
|
150
228
|
}
|
|
151
229
|
|
|
@@ -160,6 +238,10 @@ export interface ModuleHarnessRuntimeDescriptor {
|
|
|
160
238
|
wasmEdgeBinary?: string;
|
|
161
239
|
wasmEdgeRunnerBinary?: string;
|
|
162
240
|
enableThreads?: boolean;
|
|
241
|
+
hostProfile?: "runtime-host";
|
|
242
|
+
modules?: RuntimeHostTestModuleDefinition[];
|
|
243
|
+
defaultModuleId?: string;
|
|
244
|
+
metadata?: unknown;
|
|
163
245
|
}
|
|
164
246
|
|
|
165
247
|
export interface ModuleHarness {
|
|
@@ -169,12 +251,42 @@ export interface ModuleHarness {
|
|
|
169
251
|
invoke(request: {
|
|
170
252
|
methodId?: string | null;
|
|
171
253
|
inputs?: HarnessInputFrame[];
|
|
254
|
+
}): Promise<{
|
|
255
|
+
statusCode: number;
|
|
256
|
+
errorCode?: string | null;
|
|
257
|
+
errorMessage?: string | null;
|
|
258
|
+
outputs: HarnessInputFrame[];
|
|
259
|
+
}>;
|
|
260
|
+
installModule(definition: RuntimeHostTestModuleDefinition): Promise<RuntimeHostInstalledModule>;
|
|
261
|
+
listModules(): Promise<RuntimeHostInstalledModule[]>;
|
|
262
|
+
unloadModule(moduleId: string): Promise<boolean>;
|
|
263
|
+
invokeModule(moduleId: string, request: {
|
|
264
|
+
methodId?: string | null;
|
|
265
|
+
inputs?: HarnessInputFrame[];
|
|
172
266
|
}): Promise<{
|
|
173
267
|
statusCode: number;
|
|
174
268
|
errorCode?: string | null;
|
|
175
269
|
errorMessage?: string | null;
|
|
176
270
|
outputs: HarnessInputFrame[];
|
|
177
271
|
}>;
|
|
272
|
+
appendRow(options: {
|
|
273
|
+
schemaFileId: string;
|
|
274
|
+
payload?: unknown;
|
|
275
|
+
}): Promise<RuntimeHostRowHandle>;
|
|
276
|
+
listRows(schemaFileId?: string | null): Promise<RuntimeHostRowView[]>;
|
|
277
|
+
resolveRow(handle: RuntimeHostRowHandle): Promise<RuntimeHostRowView | null>;
|
|
278
|
+
queryRows(sql: string): Promise<RuntimeHostRowQueryResult>;
|
|
279
|
+
allocateRegion(options: {
|
|
280
|
+
layoutId: string;
|
|
281
|
+
recordByteLength: number;
|
|
282
|
+
alignment?: number;
|
|
283
|
+
initialRecords?: Array<Uint8Array | ArrayBuffer | ArrayBufferView | null | undefined>;
|
|
284
|
+
}): Promise<RuntimeHostRegionDescriptor>;
|
|
285
|
+
describeRegion(regionId: number): Promise<RuntimeHostRegionDescriptor | null>;
|
|
286
|
+
resolveRecord(query: {
|
|
287
|
+
regionId: number;
|
|
288
|
+
recordIndex: number;
|
|
289
|
+
}): Promise<RuntimeHostRegionRecord | null>;
|
|
178
290
|
destroy(): Promise<void>;
|
|
179
291
|
}
|
|
180
292
|
|
|
@@ -205,6 +317,40 @@ export function createPublicationProtectionDemoSummary(options?: {
|
|
|
205
317
|
};
|
|
206
318
|
}): Promise<PublicationProtectionDemoSummary>;
|
|
207
319
|
|
|
320
|
+
export interface BrowserModuleHarness {
|
|
321
|
+
runtime: {
|
|
322
|
+
kind: "browser";
|
|
323
|
+
profile: string;
|
|
324
|
+
surface: string;
|
|
325
|
+
};
|
|
326
|
+
instance: WebAssembly.Instance;
|
|
327
|
+
module: WebAssembly.Module;
|
|
328
|
+
host: unknown;
|
|
329
|
+
bridge: unknown;
|
|
330
|
+
wasi: {
|
|
331
|
+
imports: Record<string, Record<string, (...args: number[]) => number>>;
|
|
332
|
+
setMemory(mem: { buffer: ArrayBuffer | SharedArrayBuffer }): void;
|
|
333
|
+
getMemory(): { buffer: ArrayBuffer | SharedArrayBuffer } | null;
|
|
334
|
+
flushOutput(): void;
|
|
335
|
+
stdout: Uint8Array;
|
|
336
|
+
stderr: Uint8Array;
|
|
337
|
+
};
|
|
338
|
+
invokeRaw(
|
|
339
|
+
requestBytes: Uint8Array | ArrayBuffer | ArrayBufferView,
|
|
340
|
+
): Promise<Uint8Array>;
|
|
341
|
+
invoke(request: {
|
|
342
|
+
methodId?: string | null;
|
|
343
|
+
inputs?: HarnessInputFrame[];
|
|
344
|
+
}): Promise<{
|
|
345
|
+
statusCode: number;
|
|
346
|
+
errorCode?: string | null;
|
|
347
|
+
errorMessage?: string | null;
|
|
348
|
+
outputs: HarnessInputFrame[];
|
|
349
|
+
}>;
|
|
350
|
+
readManifest(): Uint8Array | null;
|
|
351
|
+
destroy(): void;
|
|
352
|
+
}
|
|
353
|
+
|
|
208
354
|
export function generateManifestHarnessPlan(options: {
|
|
209
355
|
manifest: PluginManifest;
|
|
210
356
|
includeOptionalInputs?: boolean;
|
|
@@ -234,12 +380,13 @@ export function buildWasmEdgeSpawnEnv(
|
|
|
234
380
|
): Record<string, string | undefined>;
|
|
235
381
|
|
|
236
382
|
export function resolveWasmEdgePluginLaunchPlan(options: {
|
|
237
|
-
wasmPath
|
|
383
|
+
wasmPath?: string;
|
|
238
384
|
wasmEdgeBinary?: string;
|
|
239
385
|
wasmEdgeRunnerBinary?: string;
|
|
240
386
|
enableThreads?: boolean;
|
|
241
387
|
invokeArgs?: string[];
|
|
242
388
|
env?: Record<string, string | undefined>;
|
|
389
|
+
hostProfile?: "runtime-host";
|
|
243
390
|
}): PluginInvokeProcessLaunchPlan;
|
|
244
391
|
|
|
245
392
|
export function createPluginInvokeProcessClient(options: {
|
|
@@ -250,10 +397,34 @@ export function createPluginInvokeProcessClient(options: {
|
|
|
250
397
|
cwd?: string;
|
|
251
398
|
}): Promise<PluginInvokeProcessClient>;
|
|
252
399
|
|
|
400
|
+
export function createWasmEdgeStreamProcessClient(options: {
|
|
401
|
+
launchPlan?: PluginInvokeProcessLaunchPlan;
|
|
402
|
+
command?: string;
|
|
403
|
+
args?: string[];
|
|
404
|
+
env?: Record<string, string | undefined>;
|
|
405
|
+
cwd?: string;
|
|
406
|
+
}): Promise<PluginInvokeProcessClient>;
|
|
407
|
+
|
|
253
408
|
export function resolveModuleHarnessLaunchPlan(options: {
|
|
254
409
|
runtime?: ModuleHarnessRuntimeDescriptor;
|
|
255
410
|
} | ModuleHarnessRuntimeDescriptor): PluginInvokeProcessLaunchPlan;
|
|
256
411
|
|
|
412
|
+
export function detectArtifactProfile(wasmModule: WebAssembly.Module): string;
|
|
413
|
+
|
|
414
|
+
export function createBrowserModuleHarness(options?: {
|
|
415
|
+
wasmSource: Uint8Array | ArrayBuffer | string | WebAssembly.Module | unknown;
|
|
416
|
+
host?: unknown;
|
|
417
|
+
hostOptions?: unknown;
|
|
418
|
+
args?: string[];
|
|
419
|
+
env?: Record<string, string>;
|
|
420
|
+
surface?: "direct" | "command";
|
|
421
|
+
performance?: {
|
|
422
|
+
now(): number;
|
|
423
|
+
timeOrigin: number;
|
|
424
|
+
};
|
|
425
|
+
logOutput?: boolean;
|
|
426
|
+
}): Promise<BrowserModuleHarness>;
|
|
427
|
+
|
|
257
428
|
export function createModuleHarness(options: {
|
|
258
429
|
runtime?: ModuleHarnessRuntimeDescriptor;
|
|
259
430
|
} | ModuleHarnessRuntimeDescriptor): Promise<ModuleHarness>;
|
package/src/testing/index.js
CHANGED
|
@@ -7,9 +7,14 @@ export {
|
|
|
7
7
|
createPublicationProtectionDemoManifest,
|
|
8
8
|
createPublicationProtectionDemoSummary,
|
|
9
9
|
} from "./publicationProtectionDemo.js";
|
|
10
|
+
export {
|
|
11
|
+
createBrowserModuleHarness,
|
|
12
|
+
detectArtifactProfile,
|
|
13
|
+
} from "./browserModuleHarness.js";
|
|
10
14
|
export {
|
|
11
15
|
buildWasmEdgeSpawnEnv,
|
|
12
16
|
createPluginInvokeProcessClient,
|
|
17
|
+
createWasmEdgeStreamProcessClient,
|
|
13
18
|
resolveWasmEdgePluginLaunchPlan,
|
|
14
19
|
} from "./processInvoke.js";
|
|
15
20
|
export {
|