crossbind 2.0.0-beta.62 → 2.0.0-beta.64
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/AGENTS.md +2 -1
- package/README.md +2 -2
- package/package.json +7 -2
- package/src/actions/buildBinTools.js +0 -0
- package/src/actions/buildDependencies.js +15 -2
- package/src/actions/buildExternal.js +9 -1
- package/src/actions/buildJs.js +2 -9
- package/src/actions/buildLib.js +25 -8
- package/src/actions/buildNativeCommand.js +84 -0
- package/src/actions/buildNode.js +49 -10
- package/src/actions/buildTypes.js +8 -2
- package/src/actions/buildWasiCommand.js +10 -9
- package/src/actions/buildWasm.js +72 -31
- package/src/actions/cloudCommands.js +133 -0
- package/src/actions/createImportedBridges.js +71 -0
- package/src/actions/createInterface.js +247 -68
- package/src/actions/createLib.js +70 -42
- package/src/actions/getData.js +6 -2
- package/src/actions/getEnv.js +7 -0
- package/src/actions/getLinkInputs.js +12 -5
- package/src/actions/isSourceNewer.js +2 -0
- package/src/actions/licenses.js +143 -19
- package/src/actions/prepareConanDependencies.js +51 -0
- package/src/actions/publishBinary.js +32 -0
- package/src/actions/run.js +63 -66
- package/src/actions/runnerCommands.js +433 -0
- package/src/actions/writeRuntimeEntry.js +80 -0
- package/src/assets/cmake/command/CMakeLists.txt +21 -0
- package/src/assets/cmake/command/command.cpp +1 -0
- package/src/assets/cmake/dist.cmake +2 -1
- package/src/assets/configure/install.sh +22 -0
- package/src/assets/cpp-runtime/node.cpp +18 -1
- package/src/assets/js-runtime/adapters/path-url.js +6 -3
- package/src/assets/js-runtime/adapters/unboundMessage.js +2 -0
- package/src/assets/js-runtime/adapters/worker-comlink.js +138 -60
- package/src/assets/js-runtime/core.js +12 -0
- package/src/assets/node-import-hooks.mjs +61 -0
- package/src/assets/toolchain-digests.json +19 -19
- package/src/assets/wasi-runtime/http/README.md +17 -0
- package/src/assets/wasi-runtime/http/bindings/crossbind_http.c +2537 -0
- package/src/assets/wasi-runtime/http/bindings/crossbind_http.h +826 -0
- package/src/assets/wasi-runtime/http/bindings/crossbind_http_component_type.o +0 -0
- package/src/assets/wasi-runtime/http/handler.cpp +298 -0
- package/src/assets/wasi-runtime/http/include/crossbind/http.h +31 -0
- package/src/assets/wasi-runtime/http/wit/deps/LICENSE.md +8 -0
- package/src/assets/wasi-runtime/http/wit/deps/cli.wit +28 -0
- package/src/assets/wasi-runtime/http/wit/deps/clocks.wit +43 -0
- package/src/assets/wasi-runtime/http/wit/deps/http.wit +509 -0
- package/src/assets/wasi-runtime/http/wit/deps/random.wit +18 -0
- package/src/assets/wasi-runtime/http/wit/world.wit +6 -0
- package/src/assets/wasi-runtime/stubs.c +29 -0
- package/src/bin.js +218 -161
- package/src/cli.js +14 -0
- package/src/index.js +3 -0
- package/src/integration/bindHeaderImports.js +18 -0
- package/src/integration/getCrossbindScript.js +50 -13
- package/src/integration/getDependFilePath.js +9 -0
- package/src/integration/resolveNativeImport.js +14 -0
- package/src/node/dev.mjs +19 -0
- package/src/program.js +169 -0
- package/src/runner/blobs.js +135 -0
- package/src/runner/files.js +193 -0
- package/src/runner/server.js +320 -0
- package/src/state/attachConanDependencies.js +56 -0
- package/src/state/index.js +20 -11
- package/src/state/loadConfig.js +37 -35
- package/src/state/refreshBuiltDependencies.js +20 -0
- package/src/state/refreshConanDependencies.js +17 -0
- package/src/utils/androidToolchain.js +4 -0
- package/src/utils/appRustCrates.js +19 -1
- package/src/utils/appSources.js +97 -6
- package/src/utils/archiveFlags.js +12 -0
- package/src/utils/boundHeaders.js +79 -0
- package/src/utils/bridgeExtras.js +554 -0
- package/src/utils/bridgeRuntimeFixes.js +48 -0
- package/src/utils/bundledLicenses.js +26 -0
- package/src/utils/cargoLock.js +19 -0
- package/src/utils/cargoTarget.js +21 -3
- package/src/utils/cloudAccount.js +55 -0
- package/src/utils/conanDependencies.js +66 -0
- package/src/utils/conanImport.js +58 -0
- package/src/utils/conanInstall.js +154 -0
- package/src/utils/conanProfile.js +203 -0
- package/src/utils/conanStage.js +292 -0
- package/src/utils/copyToDistSource.js +13 -0
- package/src/utils/cppDts.js +60 -15
- package/src/utils/darwinToolchain.js +11 -0
- package/src/utils/dirLock.js +137 -28
- package/src/utils/downloadAndExtractFile.js +34 -7
- package/src/utils/embindArgumentGuards.js +41 -2
- package/src/utils/embindCallArguments.js +19 -0
- package/src/utils/embindJspiQueue.js +25 -0
- package/src/utils/embindObjectLifetime.js +35 -0
- package/src/utils/execContainer.js +49 -0
- package/src/utils/headerImports.js +16 -5
- package/src/utils/hostPlatform.js +21 -0
- package/src/utils/iosToolchain.js +6 -0
- package/src/utils/isSourceCmakePackage.js +10 -0
- package/src/utils/licenseReport.js +11 -2
- package/src/utils/linuxToolchain.js +24 -0
- package/src/utils/makeTreeWritable.js +12 -0
- package/src/utils/nativeImports.js +23 -0
- package/src/utils/nativeSourceStamp.js +36 -0
- package/src/utils/nodeDevBuild.js +92 -0
- package/src/utils/packageLicense.js +103 -0
- package/src/utils/pthreadMainScript.js +14 -0
- package/src/utils/pullDockerImage.js +3 -1
- package/src/utils/relocatePrebuilt.js +119 -0
- package/src/utils/remoteClient.js +127 -0
- package/src/utils/remoteOutputs.js +39 -0
- package/src/utils/remoteRunner.js +97 -0
- package/src/utils/remoteUpload.js +134 -0
- package/src/utils/replaceFile.js +8 -0
- package/src/utils/resetCMakeCacheForSource.js +26 -0
- package/src/utils/runCargo.js +48 -51
- package/src/utils/runConan.js +257 -0
- package/src/utils/runtimeEntries.js +56 -0
- package/src/utils/rustBridgeGen.js +22 -8
- package/src/utils/rustMt.js +9 -0
- package/src/utils/rustSysroot.js +7 -5
- package/src/utils/scopedEmbind.js +22 -0
- package/src/utils/selectRunner.js +81 -0
- package/src/utils/sourceFingerprint.js +4 -3
- package/src/utils/swigInterface.js +70 -4
- package/src/utils/systemConfig.js +13 -0
- package/src/utils/systemKeys.js +35 -3
- package/src/utils/targets.js +60 -4
- package/src/utils/toolchainNotices.js +5 -0
- package/src/utils/wasiHttp.js +50 -0
- package/src/utils/wasiToolchain.js +14 -1
- package/src/utils/windowsToolchain.js +18 -0
- package/vitest.config.js +11 -0
|
@@ -5,6 +5,8 @@ import {
|
|
|
5
5
|
callWithVectorCoercion, wrapWithVectorCoercion, setCoercionModule, unwrapCoercionProxy,
|
|
6
6
|
} from './vector-coercion.js';
|
|
7
7
|
import { patchModuleForExceptionDecode } from './exception-decode.js';
|
|
8
|
+
import urlPath from './path-url.js';
|
|
9
|
+
import { UNBOUND_MESSAGE } from './unboundMessage.js';
|
|
8
10
|
|
|
9
11
|
const isWorkerScope = typeof WorkerGlobalScope !== 'undefined'
|
|
10
12
|
&& typeof self !== 'undefined'
|
|
@@ -12,17 +14,87 @@ const isWorkerScope = typeof WorkerGlobalScope !== 'undefined'
|
|
|
12
14
|
|
|
13
15
|
// === Embind <-> Comlink Bridge ===
|
|
14
16
|
// Worker-side registry: id -> original embind object
|
|
15
|
-
// Main-thread registry:
|
|
17
|
+
// Main-thread registry: handle -> id
|
|
16
18
|
const embindRegistry = new Map();
|
|
17
19
|
const embindProxyIds = new WeakMap();
|
|
18
20
|
let nextEmbindId = 1;
|
|
19
21
|
|
|
22
|
+
// The objects the worker hands out are reached through the module's channel, so writes to them keep their order
|
|
23
|
+
// with the calls after them; messages on different channels keep none.
|
|
24
|
+
const HANDLES = '__crossbindHandles';
|
|
25
|
+
let remoteModule = null;
|
|
26
|
+
|
|
27
|
+
// How many ids name each object, as a raw pointer handed out twice is one object.
|
|
28
|
+
const holders = new WeakMap();
|
|
29
|
+
|
|
20
30
|
function registerEmbindObject(obj) {
|
|
21
31
|
const id = nextEmbindId++;
|
|
22
32
|
embindRegistry.set(id, obj);
|
|
33
|
+
holders.set(obj, (holders.get(obj) ?? 0) + 1);
|
|
23
34
|
return id;
|
|
24
35
|
}
|
|
25
36
|
|
|
37
|
+
// What JavaScript owns: an object behind a smart pointer, or a copy embind made of a returned value or an object
|
|
38
|
+
// JavaScript constructed, which utils/embindObjectLifetime.js marks. A raw pointer stays its library's.
|
|
39
|
+
const ownsObject = (obj) => {
|
|
40
|
+
const $$ = obj?.$$;
|
|
41
|
+
return Boolean($$ && ($$.smartPtr || $$.count?.owned));
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
const freeIfOwned = (obj) => {
|
|
45
|
+
if (ownsObject(obj) && !obj.isDeleted()) obj.delete();
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
// The worker side of a handle the main thread no longer reaches: its id goes, and the object with the last id.
|
|
49
|
+
const RELEASE = '__crossbindRelease';
|
|
50
|
+
|
|
51
|
+
function releaseEmbindObjects(ids) {
|
|
52
|
+
for (const id of ids) {
|
|
53
|
+
const obj = embindRegistry.get(id);
|
|
54
|
+
if (!embindRegistry.delete(id)) continue;
|
|
55
|
+
const left = holders.get(obj) - 1;
|
|
56
|
+
if (left > 0) {
|
|
57
|
+
holders.set(obj, left);
|
|
58
|
+
} else {
|
|
59
|
+
holders.delete(obj);
|
|
60
|
+
freeIfOwned(obj);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Comlink answers every member with a remote one: JSON.stringify and String() called toJSON and Symbol.toPrimitive
|
|
66
|
+
// on the worker's object, which has neither, and a member below the module is thenable. A handle answers them as a
|
|
67
|
+
// direct-mode object does.
|
|
68
|
+
const LOCAL_MEMBERS = {
|
|
69
|
+
then: undefined,
|
|
70
|
+
toJSON: () => ({}),
|
|
71
|
+
[Symbol.toPrimitive]: (hint) => (hint === 'number' ? NaN : '[object Object]'),
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
// The main thread side: once a handle is collected, the worker lets go of its object, the ids collected in one task
|
|
75
|
+
// in one message.
|
|
76
|
+
const collected = [];
|
|
77
|
+
|
|
78
|
+
function releaseLater(id) {
|
|
79
|
+
collected.push(id);
|
|
80
|
+
if (collected.length > 1) return;
|
|
81
|
+
setTimeout(() => {
|
|
82
|
+
const ids = collected.splice(0);
|
|
83
|
+
Promise.resolve(remoteModule?.[RELEASE](ids)).catch(() => {});
|
|
84
|
+
}, 0);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const handleWatcher = typeof FinalizationRegistry === 'function' ? new FinalizationRegistry(releaseLater) : null;
|
|
88
|
+
|
|
89
|
+
function handleFor(id) {
|
|
90
|
+
const handle = new Proxy(remoteModule[HANDLES][id], {
|
|
91
|
+
get: (target, prop) => (Object.hasOwn(LOCAL_MEMBERS, prop) ? LOCAL_MEMBERS[prop] : target[prop]),
|
|
92
|
+
});
|
|
93
|
+
embindProxyIds.set(handle, id);
|
|
94
|
+
handleWatcher?.register(handle, id);
|
|
95
|
+
return handle;
|
|
96
|
+
}
|
|
97
|
+
|
|
26
98
|
// Reorder transfer handlers for correct priority
|
|
27
99
|
const _proxyHandler = Comlink.transferHandlers.get('proxy');
|
|
28
100
|
const _throwHandler = Comlink.transferHandlers.get('throw');
|
|
@@ -47,22 +119,16 @@ Comlink.transferHandlers.set('proxy', {
|
|
|
47
119
|
canHandle: _proxyHandler.canHandle,
|
|
48
120
|
serialize(obj) {
|
|
49
121
|
if (typeof obj.delete === 'function' && typeof obj.isDeleted === 'function') {
|
|
50
|
-
// CONSTRUCT results (Comlink marks them with proxy()) are
|
|
51
|
-
//
|
|
52
|
-
//
|
|
53
|
-
|
|
54
|
-
const raw = unwrapCoercionProxy(obj);
|
|
55
|
-
const [port, transferables] = _proxyHandler.serialize(wrapWithVectorCoercion(raw));
|
|
56
|
-
const id = registerEmbindObject(raw);
|
|
57
|
-
return [{ __embindId: id, __port: port }, transferables];
|
|
122
|
+
// CONSTRUCT results (Comlink marks them with proxy()) are handed out as
|
|
123
|
+
// method-returned objects are (embindObject handler), and the registry keeps
|
|
124
|
+
// the RAW object so arguments resolve back to real embind identities.
|
|
125
|
+
return [{ __embindId: registerEmbindObject(unwrapCoercionProxy(obj)) }, []];
|
|
58
126
|
}
|
|
59
127
|
return _proxyHandler.serialize(obj);
|
|
60
128
|
},
|
|
61
129
|
deserialize(data) {
|
|
62
130
|
if (data != null && typeof data === 'object' && '__embindId' in data) {
|
|
63
|
-
|
|
64
|
-
embindProxyIds.set(proxy, data.__embindId);
|
|
65
|
-
return proxy;
|
|
131
|
+
return handleFor(data.__embindId);
|
|
66
132
|
}
|
|
67
133
|
return _proxyHandler.deserialize(data);
|
|
68
134
|
},
|
|
@@ -102,40 +168,20 @@ Comlink.transferHandlers.set('embindVector', {
|
|
|
102
168
|
serialize(obj) {
|
|
103
169
|
const len = obj.size();
|
|
104
170
|
const elements = new Array(len);
|
|
105
|
-
let hasObjects = false;
|
|
106
171
|
for (let i = 0; i < len; i++) {
|
|
107
172
|
const elem = obj.get(i);
|
|
108
|
-
elements[i] = elem
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
if (!hasObjects) {
|
|
114
|
-
return [elements, []];
|
|
115
|
-
}
|
|
116
|
-
const transferables = [];
|
|
117
|
-
for (let i = 0; i < len; i++) {
|
|
118
|
-
const elem = elements[i];
|
|
119
|
-
if (elem !== null && typeof elem === 'object') {
|
|
120
|
-
const id = registerEmbindObject(elem);
|
|
121
|
-
const { port1, port2 } = new MessageChannel();
|
|
122
|
-
Comlink.expose(wrapWithVectorCoercion(elem), port1);
|
|
123
|
-
transferables.push(port2);
|
|
124
|
-
elements[i] = { __comlinkProxy: true, __embindId: id, port: port2 };
|
|
125
|
-
}
|
|
173
|
+
elements[i] = elem !== null && typeof elem === 'object'
|
|
174
|
+
? { __comlinkProxy: true, __embindId: registerEmbindObject(elem) }
|
|
175
|
+
: elem;
|
|
126
176
|
}
|
|
127
|
-
|
|
177
|
+
// The main thread gets the array alone, so nothing can reach a vector the call handed over any more.
|
|
178
|
+
freeIfOwned(unwrapCoercionProxy(obj));
|
|
179
|
+
return [elements, []];
|
|
128
180
|
},
|
|
129
181
|
deserialize(elements) {
|
|
130
|
-
return elements.map((elem) =>
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
const proxy = Comlink.wrap(elem.port);
|
|
134
|
-
embindProxyIds.set(proxy, elem.__embindId);
|
|
135
|
-
return proxy;
|
|
136
|
-
}
|
|
137
|
-
return elem;
|
|
138
|
-
});
|
|
182
|
+
return elements.map((elem) => (elem && typeof elem === 'object' && elem.__comlinkProxy
|
|
183
|
+
? handleFor(elem.__embindId)
|
|
184
|
+
: elem));
|
|
139
185
|
},
|
|
140
186
|
});
|
|
141
187
|
|
|
@@ -210,20 +256,13 @@ Comlink.transferHandlers.set('embindObject', {
|
|
|
210
256
|
&& typeof obj.isDeleted === 'function';
|
|
211
257
|
},
|
|
212
258
|
serialize(obj) {
|
|
213
|
-
// An object a property returns comes wrapped by its owner's coercion proxy. Registering
|
|
214
|
-
//
|
|
215
|
-
//
|
|
216
|
-
|
|
217
|
-
const id = registerEmbindObject(raw);
|
|
218
|
-
const { port1, port2 } = new MessageChannel();
|
|
219
|
-
Comlink.expose(wrapWithVectorCoercion(raw), port1);
|
|
220
|
-
return [{ __embindId: id, port: port2 }, [port2]];
|
|
259
|
+
// An object a property returns comes wrapped by its owner's coercion proxy. Registering the raw object,
|
|
260
|
+
// as the proxy handler does, keeps objects read from it one wrapper deep, which an argument's unwrapping
|
|
261
|
+
// undoes.
|
|
262
|
+
return [{ __embindId: registerEmbindObject(unwrapCoercionProxy(obj)) }, []];
|
|
221
263
|
},
|
|
222
264
|
deserialize(data) {
|
|
223
|
-
data.
|
|
224
|
-
const proxy = Comlink.wrap(data.port);
|
|
225
|
-
embindProxyIds.set(proxy, data.__embindId);
|
|
226
|
-
return proxy;
|
|
265
|
+
return handleFor(data.__embindId);
|
|
227
266
|
},
|
|
228
267
|
});
|
|
229
268
|
|
|
@@ -251,16 +290,29 @@ Comlink.transferHandlers.set('embindProxyArray', {
|
|
|
251
290
|
|
|
252
291
|
let _worker = null;
|
|
253
292
|
|
|
293
|
+
// Configurable, so the coercion wrapper wraps the objects read through it as it does every other member.
|
|
294
|
+
export function moduleRoot(m) {
|
|
295
|
+
Object.defineProperty(m, HANDLES, {
|
|
296
|
+
value: new Proxy({}, { get: (_, id) => embindRegistry.get(Number(id)) }),
|
|
297
|
+
configurable: true,
|
|
298
|
+
});
|
|
299
|
+
Object.defineProperty(m, RELEASE, { value: releaseEmbindObjects, configurable: true });
|
|
300
|
+
return wrapWithVectorCoercion(m);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
export function adoptModule(remote) {
|
|
304
|
+
remoteModule = remote;
|
|
305
|
+
return remote;
|
|
306
|
+
}
|
|
307
|
+
|
|
254
308
|
function resolveScriptUrl(config) {
|
|
255
309
|
const fileName = config.paths.js || config.paths.worker;
|
|
256
|
-
let prefix =
|
|
310
|
+
let prefix = urlPath.getDefaultPathPrefix();
|
|
257
311
|
if (config.path) {
|
|
258
312
|
prefix = config.path;
|
|
259
313
|
if (prefix.slice(-1) !== '/') prefix += '/';
|
|
260
314
|
}
|
|
261
|
-
|
|
262
|
-
if (output.substring(0, 4) !== 'http' && output[0] !== '/') output = `/${output}`;
|
|
263
|
-
return output;
|
|
315
|
+
return urlPath.finalizePath(prefix + fileName);
|
|
264
316
|
}
|
|
265
317
|
|
|
266
318
|
function exposeWorker(systemConfig, createModule) {
|
|
@@ -273,7 +325,7 @@ function exposeWorker(systemConfig, createModule) {
|
|
|
273
325
|
// comlink throw handler, a raw WebAssembly.Exception does not.
|
|
274
326
|
patchModuleForExceptionDecode(m);
|
|
275
327
|
registerModuleEnums(m);
|
|
276
|
-
return Comlink.proxy(
|
|
328
|
+
return Comlink.proxy(moduleRoot(m));
|
|
277
329
|
},
|
|
278
330
|
};
|
|
279
331
|
Comlink.expose(workerApi);
|
|
@@ -288,10 +340,35 @@ async function initWithWorker(config, userConfig) {
|
|
|
288
340
|
logHandler, errorHandler, onRuntimeInitialized, getWasmFunction, useWorker, workerUrl,
|
|
289
341
|
...serializableConfig
|
|
290
342
|
} = userConfig;
|
|
291
|
-
|
|
343
|
+
// The worker resolves a relative URL against its own script, so it gets the path resolved against the page.
|
|
344
|
+
const workerConfig = config.path ? { ...serializableConfig, path: urlPath.finalizePath(config.path) } : serializableConfig;
|
|
345
|
+
return moduleOnMainThread(adoptModule(await workerApi.init(workerConfig)));
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
// A call the worker cannot make, because the module lacks the function, fails there with a TypeError from inside comlink
|
|
349
|
+
// that names nothing: the failed call asks for the member, and names it when the module has none.
|
|
350
|
+
function namedCall(member, name, module) {
|
|
351
|
+
return new Proxy(member, {
|
|
352
|
+
// A member still needs Comlink's then to read its value (including an absent export).
|
|
353
|
+
get(target, prop) {
|
|
354
|
+
// Console formatters inspect function names and constructors synchronously.
|
|
355
|
+
if (prop === 'name') return name;
|
|
356
|
+
if (prop === 'constructor') return Function;
|
|
357
|
+
return prop !== 'then' && Object.hasOwn(LOCAL_MEMBERS, prop) ? LOCAL_MEMBERS[prop] : target[prop];
|
|
358
|
+
},
|
|
359
|
+
apply: (call, thisArg, args) => Reflect.apply(call, thisArg, args).catch(async (error) => {
|
|
360
|
+
const isBound = await Promise.resolve(module[name]).then((value) => value !== undefined, () => true);
|
|
361
|
+
if (isBound) throw error;
|
|
362
|
+
throw new Error(`crossbind: ${name} ${UNBOUND_MESSAGE}`);
|
|
363
|
+
}),
|
|
364
|
+
});
|
|
365
|
+
}
|
|
292
366
|
|
|
367
|
+
export function moduleOnMainThread(module) {
|
|
293
368
|
return new Proxy(module, {
|
|
294
369
|
get(target, prop) {
|
|
370
|
+
if (Object.hasOwn(LOCAL_MEMBERS, prop)) return LOCAL_MEMBERS[prop];
|
|
371
|
+
if (prop === 'constructor') return Object;
|
|
295
372
|
if (prop === 'toArray') {
|
|
296
373
|
return function toArray(vector) {
|
|
297
374
|
if (Array.isArray(vector)) return vector;
|
|
@@ -306,7 +383,8 @@ async function initWithWorker(config, userConfig) {
|
|
|
306
383
|
return target.toVector(classOrName, array);
|
|
307
384
|
};
|
|
308
385
|
}
|
|
309
|
-
|
|
386
|
+
const member = target[prop];
|
|
387
|
+
return typeof prop === 'string' && typeof member === 'function' ? namedCall(member, prop, target) : member;
|
|
310
388
|
},
|
|
311
389
|
});
|
|
312
390
|
}
|
|
@@ -73,6 +73,17 @@ function buildLocateFile(config, adapter) {
|
|
|
73
73
|
};
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
+
// WASMFS's FS.writeFile writes at the end of a file that exists (emsdk 6.0.9 js_api.cpp), where the classic FS
|
|
77
|
+
// replaces it; opening the file for writing empties it first, unless the flags ask to append.
|
|
78
|
+
function replaceOnWriteFile(FS) {
|
|
79
|
+
const { writeFile } = FS;
|
|
80
|
+
FS.writeFile = (path, data, opts) => {
|
|
81
|
+
const appends = typeof opts?.flags === 'string' && opts.flags.startsWith('a');
|
|
82
|
+
if (!appends) FS.close(FS.open(path, 'w', opts?.mode));
|
|
83
|
+
return writeFile(path, data, opts);
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
|
|
76
87
|
export function createBaseModule(Module, config, adapter) {
|
|
77
88
|
return new Promise((resolve, reject) => {
|
|
78
89
|
const locateFile = buildLocateFile(config, adapter);
|
|
@@ -137,6 +148,7 @@ export function createBaseModule(Module, config, adapter) {
|
|
|
137
148
|
// fs-browser), which emscripten's onRuntimeInitialized callback cannot, so
|
|
138
149
|
// both hooks run after the factory settles - adapter first, then the user's.
|
|
139
150
|
Module(m).then(async (mod) => {
|
|
151
|
+
if (mod.FS) replaceOnWriteFile(mod.FS);
|
|
140
152
|
if (adapter.onModuleReady) await adapter.onModuleReady(mod, config);
|
|
141
153
|
if (config.onRuntimeInitialized) config.onRuntimeInitialized(mod);
|
|
142
154
|
return mod;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
// Node's module hooks for the native imports one crossbind build bound, so a Node app imports a header, a
|
|
2
|
+
// conan: header or a package's header the way a bundler plugin lets it. Each resolves to a module that
|
|
3
|
+
// re-exports its names from the runtime entry, which initNative() fills. Copied into dist by the build.
|
|
4
|
+
import { registerHooks } from 'node:module';
|
|
5
|
+
import path from 'node:path';
|
|
6
|
+
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
7
|
+
|
|
8
|
+
const SCHEME = /^(cargo|conan):/;
|
|
9
|
+
const isBare = (specifier) => !/^(\.{1,2}\/|\/|[A-Za-z]:[\\/]|file:)/.test(specifier);
|
|
10
|
+
|
|
11
|
+
function notBound(what, parentURL, cause) {
|
|
12
|
+
const from = parentURL ? `, imported from ${parentURL},` : '';
|
|
13
|
+
return new Error(`crossbind: ${what}${from} is not bound by the last crossbind build. Build again after adding a native import, or start Node with --import crossbind/node/dev to build whenever one is added; an import specifier computed at run time is not found by the build.`, { cause });
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const exportOf = (name) => (typeof name === 'string' ? name : `${name.wire} as ${name.local}`);
|
|
17
|
+
const proxyOf = (entry, names) => `export { ${['initNative', 'AllSymbols', ...names.map(exportOf)].join(', ')} } from ${JSON.stringify(entry)};\n`;
|
|
18
|
+
|
|
19
|
+
// Another hook may still serve it; Node's own resolver hands an unknown scheme on unresolved.
|
|
20
|
+
function resolveUnbound(specifier, context, nextResolve) {
|
|
21
|
+
let resolved;
|
|
22
|
+
try {
|
|
23
|
+
resolved = nextResolve(specifier, context);
|
|
24
|
+
} catch (error) {
|
|
25
|
+
throw notBound(specifier, context.parentURL, error);
|
|
26
|
+
}
|
|
27
|
+
if (SCHEME.test(resolved.url)) throw notBound(specifier, context.parentURL);
|
|
28
|
+
return resolved;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// `natives` lists each bound file, relative to the entry, with the bare specifiers that name it and the names it
|
|
32
|
+
// exports, a name the entry exports under another as { local, wire }.
|
|
33
|
+
export default function registerNativeImports(entry, { extensions, natives }) {
|
|
34
|
+
const entryUrl = new URL(entry).href;
|
|
35
|
+
const dir = path.dirname(fileURLToPath(entryUrl));
|
|
36
|
+
const isNative = new RegExp(`\\.(${extensions.join('|')})$`);
|
|
37
|
+
const byFile = new Map();
|
|
38
|
+
const bySpecifier = new Map();
|
|
39
|
+
natives.forEach(({ file, specifiers, names }) => {
|
|
40
|
+
const absolute = path.resolve(dir, file);
|
|
41
|
+
byFile.set(absolute, names);
|
|
42
|
+
specifiers.forEach((specifier) => bySpecifier.set(specifier, pathToFileURL(absolute).href));
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
registerHooks({
|
|
46
|
+
resolve(specifier, context, nextResolve) {
|
|
47
|
+
const url = bySpecifier.get(specifier);
|
|
48
|
+
if (url) return { url, format: 'module', shortCircuit: true };
|
|
49
|
+
if (isBare(specifier) && (SCHEME.test(specifier) || isNative.test(specifier))) return resolveUnbound(specifier, context, nextResolve);
|
|
50
|
+
return nextResolve(specifier, context);
|
|
51
|
+
},
|
|
52
|
+
load(url, context, nextLoad) {
|
|
53
|
+
if (!url.startsWith('file:')) return nextLoad(url, context);
|
|
54
|
+
const file = fileURLToPath(url);
|
|
55
|
+
const names = byFile.get(file);
|
|
56
|
+
if (names) return { format: 'module', source: proxyOf(entryUrl, names), shortCircuit: true };
|
|
57
|
+
if (isNative.test(file)) throw notBound(file);
|
|
58
|
+
return nextLoad(url, context);
|
|
59
|
+
},
|
|
60
|
+
});
|
|
61
|
+
}
|
|
@@ -1,49 +1,49 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "1.0.
|
|
2
|
+
"version": "1.0.13",
|
|
3
3
|
"registry": "ghcr.io/crossbind",
|
|
4
4
|
"toolchains": {
|
|
5
|
-
"rust": "1.
|
|
5
|
+
"rust": "1.99.1"
|
|
6
6
|
},
|
|
7
7
|
"images": {
|
|
8
8
|
"rust-sysroot": {
|
|
9
|
-
"index": "sha256:
|
|
9
|
+
"index": "sha256:c545ea396bd8919f7a671617dbbdf184bd0d6eb904d3170dd120d6671db3e0a9",
|
|
10
10
|
"platforms": {
|
|
11
|
-
"linux/arm64": "sha256:
|
|
12
|
-
"linux/amd64": "sha256:
|
|
11
|
+
"linux/arm64": "sha256:c53ee0a31c52fdc6eba175e479218ddbff0c071654b5e93a08ae768cdbbfe35a",
|
|
12
|
+
"linux/amd64": "sha256:1427255e619c3f5dcd3fa7fd284d15afbe00eef1a0798e08a9b50ebbb86c5234"
|
|
13
13
|
}
|
|
14
14
|
},
|
|
15
15
|
"base": {
|
|
16
|
-
"index": "sha256:
|
|
16
|
+
"index": "sha256:5f5d133504cb2c81ee67a93ca5795698423277522caac742478510d6158ed559",
|
|
17
17
|
"platforms": {
|
|
18
|
-
"linux/arm64": "sha256:
|
|
19
|
-
"linux/amd64": "sha256:
|
|
18
|
+
"linux/arm64": "sha256:df1c82f4b7e00a4ab33e2423f6d5bbaa66dd67bc45b96e5498e3391ec5f55fae",
|
|
19
|
+
"linux/amd64": "sha256:ffc0a178bc821e56975d9348b7e44d8081b9c6fb9351bc168b38d5063d9864ea"
|
|
20
20
|
}
|
|
21
21
|
},
|
|
22
22
|
"web": {
|
|
23
|
-
"index": "sha256:
|
|
23
|
+
"index": "sha256:b5ee271886c316404cae103c5412bc02d811ad48fd36a919fdf3a82af14fe688",
|
|
24
24
|
"platforms": {
|
|
25
|
-
"linux/
|
|
26
|
-
"linux/
|
|
25
|
+
"linux/arm64": "sha256:91d35c9eac65f479f5139ba476b3daa3b517aab6f21f5206070af610cec5b62c",
|
|
26
|
+
"linux/amd64": "sha256:f308cb1702f308d69d9f21eb99aa109cdbf62e655549b483580476d8f01fb07b"
|
|
27
27
|
}
|
|
28
28
|
},
|
|
29
29
|
"android": {
|
|
30
|
-
"index": "sha256:
|
|
30
|
+
"index": "sha256:a01ddeaed550091f45e720d09bd559978d4c46e396c4553b3fc4544b90033fd1",
|
|
31
31
|
"platforms": {
|
|
32
|
-
"linux/amd64": "sha256:
|
|
32
|
+
"linux/amd64": "sha256:3bafd0a3f80bf7370a19522a3b75cb58a977d1b1b28940ed02b87db1058a8fd6"
|
|
33
33
|
}
|
|
34
34
|
},
|
|
35
35
|
"linux": {
|
|
36
|
-
"index": "sha256:
|
|
36
|
+
"index": "sha256:c1d7f9672edb6eeea86172d8ba8cc8ba824f6c53134587ea247ea5dc126d6c43",
|
|
37
37
|
"platforms": {
|
|
38
|
-
"linux/amd64": "sha256:
|
|
39
|
-
"linux/arm64": "sha256:
|
|
38
|
+
"linux/amd64": "sha256:0ff9ee1d5c139eb97934919f7b9535af0eb2c3bebd9c1974fa95cfb143e3ccf7",
|
|
39
|
+
"linux/arm64": "sha256:f476e4a95635c04aca741937c2174a1915731c52c9d182b247e17d4ca4163b33"
|
|
40
40
|
}
|
|
41
41
|
},
|
|
42
42
|
"windows": {
|
|
43
|
-
"index": "sha256:
|
|
43
|
+
"index": "sha256:53b08c8918a84023ea90c6420fff783564aced0ec711fa0e7b71a09578643a32",
|
|
44
44
|
"platforms": {
|
|
45
|
-
"linux/
|
|
46
|
-
"linux/
|
|
45
|
+
"linux/arm64": "sha256:402f115c8eed9e6418cf9e47a6bcad2d456d15d032c9b2baaa54a5005f00c8ba",
|
|
46
|
+
"linux/amd64": "sha256:50f359882015ca93c8b356a01bf03ce4cb098307f72c30122c7b6ad123eae339"
|
|
47
47
|
}
|
|
48
48
|
}
|
|
49
49
|
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# HTTP component runtime
|
|
2
|
+
|
|
3
|
+
What an http build (`crossbind build -p wasi -e http`) links besides the app: `handler.cpp`, the
|
|
4
|
+
`wasi:http/handler` export that calls the app's `crossbind::http::handle` (`include/crossbind/http.h`),
|
|
5
|
+
and `bindings/`, which `wit-bindgen c` generated from `wit/`.
|
|
6
|
+
|
|
7
|
+
`wit/deps/` holds the `http` package of the WASI 0.3.0 release, unchanged: `wasi-wit-0.3.0.tar.gz` from
|
|
8
|
+
https://github.com/WebAssembly/WASI/releases/tag/v0.3.0 (sha256
|
|
9
|
+
`596182ecd79311c8d010389b78b0253d54bee596254002df504ea5cf0124b894`), licensed as `wit/deps/LICENSE.md` says.
|
|
10
|
+
|
|
11
|
+
After changing `wit/`, regenerate the bindings with wit-bindgen 0.62.0; with `--check` it confirms instead
|
|
12
|
+
that the committed ones, the `.o` included, are what it generates:
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
wit-bindgen c wit --world crossbind-http --out-dir bindings
|
|
16
|
+
wit-bindgen c wit --world crossbind-http --out-dir bindings --check
|
|
17
|
+
```
|