crossbind 2.0.0-beta.62 → 2.0.0-beta.63

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.
Files changed (107) hide show
  1. package/README.md +2 -2
  2. package/package.json +6 -1
  3. package/src/actions/buildDependencies.js +15 -2
  4. package/src/actions/buildExternal.js +9 -1
  5. package/src/actions/buildLib.js +25 -8
  6. package/src/actions/buildNativeCommand.js +84 -0
  7. package/src/actions/buildNode.js +48 -7
  8. package/src/actions/buildTypes.js +8 -2
  9. package/src/actions/buildWasiCommand.js +0 -4
  10. package/src/actions/buildWasm.js +49 -29
  11. package/src/actions/cloudCommands.js +133 -0
  12. package/src/actions/createImportedBridges.js +64 -0
  13. package/src/actions/createInterface.js +247 -68
  14. package/src/actions/createLib.js +57 -41
  15. package/src/actions/getData.js +4 -1
  16. package/src/actions/getLinkInputs.js +12 -5
  17. package/src/actions/isSourceNewer.js +2 -0
  18. package/src/actions/licenses.js +143 -19
  19. package/src/actions/prepareConanDependencies.js +51 -0
  20. package/src/actions/publishBinary.js +32 -0
  21. package/src/actions/run.js +63 -66
  22. package/src/actions/runnerCommands.js +421 -0
  23. package/src/actions/writeRuntimeEntry.js +69 -0
  24. package/src/assets/cmake/command/CMakeLists.txt +21 -0
  25. package/src/assets/cmake/command/command.cpp +1 -0
  26. package/src/assets/cmake/dist.cmake +2 -1
  27. package/src/assets/configure/install.sh +22 -0
  28. package/src/assets/js-runtime/adapters/path-url.js +6 -3
  29. package/src/assets/js-runtime/adapters/unboundMessage.js +2 -0
  30. package/src/assets/js-runtime/adapters/worker-comlink.js +87 -60
  31. package/src/assets/js-runtime/core.js +11 -0
  32. package/src/assets/node-import-hooks.mjs +61 -0
  33. package/src/assets/toolchain-digests.json +19 -19
  34. package/src/assets/wasi-runtime/stubs.c +29 -0
  35. package/src/bin.js +257 -50
  36. package/src/index.js +3 -0
  37. package/src/integration/bindHeaderImports.js +18 -0
  38. package/src/integration/getCrossbindScript.js +46 -10
  39. package/src/integration/getDependFilePath.js +9 -0
  40. package/src/integration/resolveNativeImport.js +14 -0
  41. package/src/node/dev.mjs +19 -0
  42. package/src/runner/blobs.js +135 -0
  43. package/src/runner/files.js +193 -0
  44. package/src/runner/server.js +320 -0
  45. package/src/state/attachConanDependencies.js +56 -0
  46. package/src/state/index.js +17 -9
  47. package/src/state/loadConfig.js +33 -24
  48. package/src/state/refreshBuiltDependencies.js +20 -0
  49. package/src/state/refreshConanDependencies.js +17 -0
  50. package/src/utils/androidToolchain.js +4 -0
  51. package/src/utils/appRustCrates.js +15 -1
  52. package/src/utils/appSources.js +97 -6
  53. package/src/utils/archiveFlags.js +12 -0
  54. package/src/utils/boundHeaders.js +79 -0
  55. package/src/utils/bridgeExtras.js +486 -0
  56. package/src/utils/bridgeRuntimeFixes.js +48 -0
  57. package/src/utils/bundledLicenses.js +26 -0
  58. package/src/utils/cargoTarget.js +21 -3
  59. package/src/utils/cloudAccount.js +55 -0
  60. package/src/utils/conanDependencies.js +66 -0
  61. package/src/utils/conanImport.js +58 -0
  62. package/src/utils/conanInstall.js +154 -0
  63. package/src/utils/conanProfile.js +203 -0
  64. package/src/utils/conanStage.js +292 -0
  65. package/src/utils/copyToDistSource.js +13 -0
  66. package/src/utils/cppDts.js +58 -15
  67. package/src/utils/darwinToolchain.js +11 -0
  68. package/src/utils/dirLock.js +137 -28
  69. package/src/utils/downloadAndExtractFile.js +34 -7
  70. package/src/utils/embindArgumentGuards.js +41 -2
  71. package/src/utils/embindCallArguments.js +19 -0
  72. package/src/utils/embindJspiQueue.js +25 -0
  73. package/src/utils/execContainer.js +49 -0
  74. package/src/utils/headerImports.js +16 -5
  75. package/src/utils/hostPlatform.js +21 -0
  76. package/src/utils/iosToolchain.js +6 -0
  77. package/src/utils/isSourceCmakePackage.js +10 -0
  78. package/src/utils/licenseReport.js +11 -2
  79. package/src/utils/linuxToolchain.js +24 -0
  80. package/src/utils/makeTreeWritable.js +12 -0
  81. package/src/utils/nativeImports.js +23 -0
  82. package/src/utils/nativeSourceStamp.js +36 -0
  83. package/src/utils/nodeDevBuild.js +92 -0
  84. package/src/utils/packageLicense.js +101 -0
  85. package/src/utils/pthreadMainScript.js +14 -0
  86. package/src/utils/pullDockerImage.js +3 -1
  87. package/src/utils/relocatePrebuilt.js +119 -0
  88. package/src/utils/remoteClient.js +127 -0
  89. package/src/utils/remoteOutputs.js +39 -0
  90. package/src/utils/remoteRunner.js +97 -0
  91. package/src/utils/remoteUpload.js +134 -0
  92. package/src/utils/replaceFile.js +8 -0
  93. package/src/utils/runCargo.js +48 -51
  94. package/src/utils/runConan.js +257 -0
  95. package/src/utils/runtimeEntries.js +56 -0
  96. package/src/utils/rustBridgeGen.js +9 -4
  97. package/src/utils/rustMt.js +4 -0
  98. package/src/utils/scopedEmbind.js +22 -0
  99. package/src/utils/selectRunner.js +81 -0
  100. package/src/utils/sourceFingerprint.js +4 -3
  101. package/src/utils/swigInterface.js +69 -4
  102. package/src/utils/systemKeys.js +35 -3
  103. package/src/utils/targets.js +49 -4
  104. package/src/utils/toolchainNotices.js +5 -0
  105. package/src/utils/wasiToolchain.js +14 -1
  106. package/src/utils/windowsToolchain.js +18 -0
  107. 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,39 @@ 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: Comlink proxy -> id
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
+
20
27
  function registerEmbindObject(obj) {
21
28
  const id = nextEmbindId++;
22
29
  embindRegistry.set(id, obj);
23
30
  return id;
24
31
  }
25
32
 
33
+ // Comlink answers every member with a remote one: JSON.stringify and String() called toJSON and Symbol.toPrimitive
34
+ // on the worker's object, which has neither, and a member below the module is thenable. A handle answers them as a
35
+ // direct-mode object does.
36
+ const LOCAL_MEMBERS = {
37
+ then: undefined,
38
+ toJSON: () => ({}),
39
+ [Symbol.toPrimitive]: (hint) => (hint === 'number' ? NaN : '[object Object]'),
40
+ };
41
+
42
+ function handleFor(id) {
43
+ const handle = new Proxy(remoteModule[HANDLES][id], {
44
+ get: (target, prop) => (Object.hasOwn(LOCAL_MEMBERS, prop) ? LOCAL_MEMBERS[prop] : target[prop]),
45
+ });
46
+ embindProxyIds.set(handle, id);
47
+ return handle;
48
+ }
49
+
26
50
  // Reorder transfer handlers for correct priority
27
51
  const _proxyHandler = Comlink.transferHandlers.get('proxy');
28
52
  const _throwHandler = Comlink.transferHandlers.get('throw');
@@ -47,22 +71,16 @@ Comlink.transferHandlers.set('proxy', {
47
71
  canHandle: _proxyHandler.canHandle,
48
72
  serialize(obj) {
49
73
  if (typeof obj.delete === 'function' && typeof obj.isDeleted === 'function') {
50
- // CONSTRUCT results (Comlink marks them with proxy()) are exposed through
51
- // the same coercion wrapper as method-returned objects (embindObject
52
- // handler), and the registry keeps the RAW object so arguments resolve
53
- // back to real embind identities.
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];
74
+ // CONSTRUCT results (Comlink marks them with proxy()) are handed out as
75
+ // method-returned objects are (embindObject handler), and the registry keeps
76
+ // the RAW object so arguments resolve back to real embind identities.
77
+ return [{ __embindId: registerEmbindObject(unwrapCoercionProxy(obj)) }, []];
58
78
  }
59
79
  return _proxyHandler.serialize(obj);
60
80
  },
61
81
  deserialize(data) {
62
82
  if (data != null && typeof data === 'object' && '__embindId' in data) {
63
- const proxy = _proxyHandler.deserialize(data.__port);
64
- embindProxyIds.set(proxy, data.__embindId);
65
- return proxy;
83
+ return handleFor(data.__embindId);
66
84
  }
67
85
  return _proxyHandler.deserialize(data);
68
86
  },
@@ -102,40 +120,18 @@ Comlink.transferHandlers.set('embindVector', {
102
120
  serialize(obj) {
103
121
  const len = obj.size();
104
122
  const elements = new Array(len);
105
- let hasObjects = false;
106
123
  for (let i = 0; i < len; i++) {
107
124
  const elem = obj.get(i);
108
- elements[i] = elem;
109
- if (!hasObjects && elem !== null && typeof elem === 'object') {
110
- hasObjects = true;
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
- }
125
+ elements[i] = elem !== null && typeof elem === 'object'
126
+ ? { __comlinkProxy: true, __embindId: registerEmbindObject(elem) }
127
+ : elem;
126
128
  }
127
- return [elements, transferables];
129
+ return [elements, []];
128
130
  },
129
131
  deserialize(elements) {
130
- return elements.map((elem) => {
131
- if (elem && typeof elem === 'object' && elem.__comlinkProxy) {
132
- elem.port.start();
133
- const proxy = Comlink.wrap(elem.port);
134
- embindProxyIds.set(proxy, elem.__embindId);
135
- return proxy;
136
- }
137
- return elem;
138
- });
132
+ return elements.map((elem) => (elem && typeof elem === 'object' && elem.__comlinkProxy
133
+ ? handleFor(elem.__embindId)
134
+ : elem));
139
135
  },
140
136
  });
141
137
 
@@ -210,20 +206,13 @@ Comlink.transferHandlers.set('embindObject', {
210
206
  && typeof obj.isDeleted === 'function';
211
207
  },
212
208
  serialize(obj) {
213
- // An object a property returns comes wrapped by its owner's coercion proxy. Registering and exposing
214
- // the raw object, as the proxy handler does, keeps objects read from it one wrapper deep, which an
215
- // argument's unwrapping undoes.
216
- const raw = unwrapCoercionProxy(obj);
217
- const id = registerEmbindObject(raw);
218
- const { port1, port2 } = new MessageChannel();
219
- Comlink.expose(wrapWithVectorCoercion(raw), port1);
220
- return [{ __embindId: id, port: port2 }, [port2]];
209
+ // An object a property returns comes wrapped by its owner's coercion proxy. Registering the raw object,
210
+ // as the proxy handler does, keeps objects read from it one wrapper deep, which an argument's unwrapping
211
+ // undoes.
212
+ return [{ __embindId: registerEmbindObject(unwrapCoercionProxy(obj)) }, []];
221
213
  },
222
214
  deserialize(data) {
223
- data.port.start();
224
- const proxy = Comlink.wrap(data.port);
225
- embindProxyIds.set(proxy, data.__embindId);
226
- return proxy;
215
+ return handleFor(data.__embindId);
227
216
  },
228
217
  });
229
218
 
@@ -251,16 +240,28 @@ Comlink.transferHandlers.set('embindProxyArray', {
251
240
 
252
241
  let _worker = null;
253
242
 
243
+ // Configurable, so the coercion wrapper wraps the objects read through it as it does every other member.
244
+ export function moduleRoot(m) {
245
+ Object.defineProperty(m, HANDLES, {
246
+ value: new Proxy({}, { get: (_, id) => embindRegistry.get(Number(id)) }),
247
+ configurable: true,
248
+ });
249
+ return wrapWithVectorCoercion(m);
250
+ }
251
+
252
+ export function adoptModule(remote) {
253
+ remoteModule = remote;
254
+ return remote;
255
+ }
256
+
254
257
  function resolveScriptUrl(config) {
255
258
  const fileName = config.paths.js || config.paths.worker;
256
- let prefix = '';
259
+ let prefix = urlPath.getDefaultPathPrefix();
257
260
  if (config.path) {
258
261
  prefix = config.path;
259
262
  if (prefix.slice(-1) !== '/') prefix += '/';
260
263
  }
261
- let output = prefix + fileName;
262
- if (output.substring(0, 4) !== 'http' && output[0] !== '/') output = `/${output}`;
263
- return output;
264
+ return urlPath.finalizePath(prefix + fileName);
264
265
  }
265
266
 
266
267
  function exposeWorker(systemConfig, createModule) {
@@ -273,7 +274,7 @@ function exposeWorker(systemConfig, createModule) {
273
274
  // comlink throw handler, a raw WebAssembly.Exception does not.
274
275
  patchModuleForExceptionDecode(m);
275
276
  registerModuleEnums(m);
276
- return Comlink.proxy(wrapWithVectorCoercion(m));
277
+ return Comlink.proxy(moduleRoot(m));
277
278
  },
278
279
  };
279
280
  Comlink.expose(workerApi);
@@ -288,10 +289,35 @@ async function initWithWorker(config, userConfig) {
288
289
  logHandler, errorHandler, onRuntimeInitialized, getWasmFunction, useWorker, workerUrl,
289
290
  ...serializableConfig
290
291
  } = userConfig;
291
- const module = await workerApi.init(serializableConfig);
292
+ // The worker resolves a relative URL against its own script, so it gets the path resolved against the page.
293
+ const workerConfig = config.path ? { ...serializableConfig, path: urlPath.finalizePath(config.path) } : serializableConfig;
294
+ return moduleOnMainThread(adoptModule(await workerApi.init(workerConfig)));
295
+ }
296
+
297
+ // A call the worker cannot make, because the module lacks the function, fails there with a TypeError from inside comlink
298
+ // that names nothing: the failed call asks for the member, and names it when the module has none.
299
+ function namedCall(member, name, module) {
300
+ return new Proxy(member, {
301
+ // A member still needs Comlink's then to read its value (including an absent export).
302
+ get(target, prop) {
303
+ // Console formatters inspect function names and constructors synchronously.
304
+ if (prop === 'name') return name;
305
+ if (prop === 'constructor') return Function;
306
+ return prop !== 'then' && Object.hasOwn(LOCAL_MEMBERS, prop) ? LOCAL_MEMBERS[prop] : target[prop];
307
+ },
308
+ apply: (call, thisArg, args) => Reflect.apply(call, thisArg, args).catch(async (error) => {
309
+ const isBound = await Promise.resolve(module[name]).then((value) => value !== undefined, () => true);
310
+ if (isBound) throw error;
311
+ throw new Error(`crossbind: ${name} ${UNBOUND_MESSAGE}`);
312
+ }),
313
+ });
314
+ }
292
315
 
316
+ export function moduleOnMainThread(module) {
293
317
  return new Proxy(module, {
294
318
  get(target, prop) {
319
+ if (Object.hasOwn(LOCAL_MEMBERS, prop)) return LOCAL_MEMBERS[prop];
320
+ if (prop === 'constructor') return Object;
295
321
  if (prop === 'toArray') {
296
322
  return function toArray(vector) {
297
323
  if (Array.isArray(vector)) return vector;
@@ -306,7 +332,8 @@ async function initWithWorker(config, userConfig) {
306
332
  return target.toVector(classOrName, array);
307
333
  };
308
334
  }
309
- return target[prop];
335
+ const member = target[prop];
336
+ return typeof prop === 'string' && typeof member === 'function' ? namedCall(member, prop, target) : member;
310
337
  },
311
338
  });
312
339
  }
@@ -73,6 +73,16 @@ 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.
78
+ function replaceOnWriteFile(FS) {
79
+ const { writeFile } = FS;
80
+ FS.writeFile = (path, data) => {
81
+ FS.close(FS.open(path, 'w'));
82
+ return writeFile(path, data);
83
+ };
84
+ }
85
+
76
86
  export function createBaseModule(Module, config, adapter) {
77
87
  return new Promise((resolve, reject) => {
78
88
  const locateFile = buildLocateFile(config, adapter);
@@ -137,6 +147,7 @@ export function createBaseModule(Module, config, adapter) {
137
147
  // fs-browser), which emscripten's onRuntimeInitialized callback cannot, so
138
148
  // both hooks run after the factory settles - adapter first, then the user's.
139
149
  Module(m).then(async (mod) => {
150
+ if (mod.FS) replaceOnWriteFile(mod.FS);
140
151
  if (adapter.onModuleReady) await adapter.onModuleReady(mod, config);
141
152
  if (config.onRuntimeInitialized) config.onRuntimeInitialized(mod);
142
153
  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.8",
2
+ "version": "1.0.12",
3
3
  "registry": "ghcr.io/crossbind",
4
4
  "toolchains": {
5
- "rust": "1.98.1"
5
+ "rust": "1.99.0"
6
6
  },
7
7
  "images": {
8
8
  "rust-sysroot": {
9
- "index": "sha256:d816d27f1f3b110aed92f7f81cb8eb99f58ba95cafc96a797c46f30536549a45",
9
+ "index": "sha256:fcaddb9514956c80c28152679d11817599b3c544e2bb56568d79dbd7699af805",
10
10
  "platforms": {
11
- "linux/arm64": "sha256:217f908b3e1c883bed8cd4db65aae48044481e88126c09c3ce9bf754288d8720",
12
- "linux/amd64": "sha256:15719494b51ea8ee6f3a71556b2c04f37828e632bc46d2c3fb7121a1afb37303"
11
+ "linux/arm64": "sha256:70dca2248666ee712ad5cb11fd013274ca4bb1efdafee732a0ec15492889f622",
12
+ "linux/amd64": "sha256:a3377c70598ef4e1918a73feeebb0ec1b80b3cde956daac9b2b62f9d742b88dc"
13
13
  }
14
14
  },
15
15
  "base": {
16
- "index": "sha256:051aa70184d29e95d5192cc60cc42523b42fab72291efbf13f71006482f063c0",
16
+ "index": "sha256:86c6559bd51c10f8fc1ff6cbc0cf5386115fd7f0491a59f30f0d26a0203c200d",
17
17
  "platforms": {
18
- "linux/arm64": "sha256:cdf189ad4ae220698088fda54c4a5005a207542bba8ab2c01fe58fc008586df8",
19
- "linux/amd64": "sha256:f501545972e2a253b19f1900946cfe39ce5dea74600d885cae47db3f320b506b"
18
+ "linux/amd64": "sha256:16056b4bd85ba1792791401003db0325c31d4aa4821ff40f6f2eb1e0fff1d3ce",
19
+ "linux/arm64": "sha256:8d213f83ddd1ad9101b74b2b071f304ac8924ffbe68d79ece50668076e0172c0"
20
20
  }
21
21
  },
22
22
  "web": {
23
- "index": "sha256:89e0ea288d42d9f24671e43b3e59dc6b9913e389b68e51d8f0e314e81d111bf3",
23
+ "index": "sha256:ffa089b83160e380e0b4447f483bf66cb87324f89b8e80b5776ed9346275a5ca",
24
24
  "platforms": {
25
- "linux/amd64": "sha256:40fe9f7573ee5a696c68043b12486e4562e0b2a87f74ef21a9b11c08454aff75",
26
- "linux/arm64": "sha256:7172f994c262600dcd1334806eee9b44e873ac42fe286bf8b0983491586d1225"
25
+ "linux/arm64": "sha256:1baf14ee0f1a821c1562d12902fe362d3639f57acb31f969402f2a2d8486647f",
26
+ "linux/amd64": "sha256:d3bd3aa785447f1679fdcb898921f614579d9eaad2aa9e828675ba7f82dc11ec"
27
27
  }
28
28
  },
29
29
  "android": {
30
- "index": "sha256:ef6dc5ed724e7ea977a1f644793967a5ad7ff62b9a6bb6f2971d4a2a9e8f5a4b",
30
+ "index": "sha256:830286886d8bb259e94e112e4f1bab5f153106365b17859d20c9ef714349e520",
31
31
  "platforms": {
32
- "linux/amd64": "sha256:d6843be98e4bc56a21e39b2670d081f60d27b45c149c0ee132d2c45bde337ec8"
32
+ "linux/amd64": "sha256:1004144243fea89a8915417954073e8ffabb20d8a9aed31045ce2a95c1abe1da"
33
33
  }
34
34
  },
35
35
  "linux": {
36
- "index": "sha256:e8b6e6afd1af9f3a84eee739bd25ce6abb8416c5af87a175b780cd18d871513d",
36
+ "index": "sha256:8d4cc55d2ef8ea40845fd13708575e06f6aecdc035e7200deddf8c662d5c910f",
37
37
  "platforms": {
38
- "linux/amd64": "sha256:39fe90d1cb2fbb411823bc396d463e298020b5a93b9a5244f27644c5c0b87b2a",
39
- "linux/arm64": "sha256:9cd9550a39010bf7f00bf08d8505a22f85e31155bf63c8a46597852dc72ef4cc"
38
+ "linux/arm64": "sha256:0de59cc6ce7b381f213af0d26ccc83e0c41545a91eb0b36c51832c7fb660566c",
39
+ "linux/amd64": "sha256:3b3bc24d8f5dffe3a2408193265a807764fcf2744243c0a5e07f312f608fc6c0"
40
40
  }
41
41
  },
42
42
  "windows": {
43
- "index": "sha256:c90a7c495e8becc6154b20fc6226362813938413bb3af626d0d0982cceaf32c5",
43
+ "index": "sha256:a31110874a9b6b9e3fec177edc8a8093905902bcc6abc6a85e45eb0927d4f070",
44
44
  "platforms": {
45
- "linux/amd64": "sha256:1fbc5c59e09253cfe86bb54fa76f0c1c6b1c1e942e4059725658340f64708e59",
46
- "linux/arm64": "sha256:229389bbabe838124cbb572b91b42ae0e3fdcd6020462203fdbbcf5864c4a234"
45
+ "linux/arm64": "sha256:bd9ec6ba60952f929e09777374a3bb05512bbe796325c0e8a0b84e1a12d1b86c",
46
+ "linux/amd64": "sha256:01f4bd8c4d1044bde68fe758d2632c510f8efb76aa4bad28696f9e9b199c8f4e"
47
47
  }
48
48
  }
49
49
  }
@@ -7,12 +7,32 @@
7
7
 
8
8
  #include <netinet/in.h>
9
9
  #include <sys/socket.h>
10
+ #include <sys/stat.h>
11
+ #include <unistd.h>
10
12
 
11
13
  /* Compiled by the C++ driver at the command link; keep C linkage. */
12
14
  #ifdef __cplusplus
13
15
  extern "C" {
14
16
  #endif
15
17
 
18
+ /* wasi-libc p2/p3 leaves its output stream at the old offset after SEEK_END. SEEK_SET resets
19
+ that stream, so resolve the end offset through fstat and perform an absolute seek instead. */
20
+ off_t __real_lseek(int fd, off_t offset, int whence);
21
+ off_t __wrap_lseek(int fd, off_t offset, int whence)
22
+ {
23
+ if (whence == SEEK_END) {
24
+ struct stat status;
25
+ if (fstat(fd, &status) != 0) return (off_t)-1;
26
+ off_t absolute;
27
+ if (__builtin_add_overflow(status.st_size, offset, &absolute)) {
28
+ errno = EOVERFLOW;
29
+ return (off_t)-1;
30
+ }
31
+ return __real_lseek(fd, absolute, SEEK_SET);
32
+ }
33
+ return __real_lseek(fd, offset, whence);
34
+ }
35
+
16
36
  /* No dynamic loading on WASI; loaders treat NULL as "plugin unavailable". */
17
37
  void *dlopen(const char *file, int mode)
18
38
  {
@@ -79,6 +99,15 @@ int getpeername(int fd, struct sockaddr *addr, socklen_t *len)
79
99
  return crossbind_zeroed_inet(addr, len);
80
100
  }
81
101
 
102
+ /* The WASI SQLite leaves extension loading out, yet SpatiaLite's stored procedures switch it off; this answers
103
+ SQLITE_ERROR as such a build does. Weak, so a SQLite that has the function keeps its own. */
104
+ __attribute__((weak)) int sqlite3_enable_load_extension(void *db, int onoff)
105
+ {
106
+ (void)db;
107
+ (void)onoff;
108
+ return 1;
109
+ }
110
+
82
111
  #ifdef __cplusplus
83
112
  }
84
113
  #endif