@napi-rs/cli 3.7.4 → 3.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +33 -0
- package/cli.mjs +9 -12
- package/dist/cli.js +9248 -1311
- package/dist/index.cjs +9268 -1331
- package/dist/index.d.cts +175 -157
- package/dist/index.d.ts +175 -157
- package/dist/index.js +9248 -1311
- package/docs/artifacts.md +33 -0
- package/docs/build.md +58 -0
- package/docs/create-npm-dirs.md +32 -0
- package/docs/new.md +39 -0
- package/docs/pre-publish.md +37 -0
- package/docs/rename.md +37 -0
- package/docs/universalize.md +31 -0
- package/docs/version.md +31 -0
- package/docs/wasi.md +161 -0
- package/package.json +11 -10
- package/src/api/__tests__/__snapshots__/templates.spec.ts.md +1019 -114
- package/src/api/__tests__/__snapshots__/templates.spec.ts.snap +0 -0
- package/src/api/__tests__/artifacts.spec.ts +17 -0
- package/src/api/__tests__/create-npm-dirs.spec.ts +14 -15
- package/src/api/__tests__/new.spec.ts +41 -5
- package/src/api/artifacts.ts +934 -108
- package/src/api/build.ts +1317 -188
- package/src/api/create-npm-dirs.ts +472 -101
- package/src/api/new.ts +354 -35
- package/src/api/pre-publish.ts +2845 -99
- package/src/api/rename.ts +1638 -124
- package/src/api/templates/js-binding.ts +216 -38
- package/src/api/templates/load-wasi-template.ts +1641 -111
- package/src/api/templates/wasi-worker-template.ts +32 -3
- package/src/commands/rename.ts +8 -3
- package/src/def/artifacts.ts +2 -2
- package/src/utils/__tests__/__snapshots__/target.spec.ts.md +2 -2
- package/src/utils/__tests__/__snapshots__/target.spec.ts.snap +0 -0
- package/src/utils/__tests__/misc.spec.ts +124 -3
- package/src/utils/__tests__/version.spec.ts +47 -1
- package/src/utils/config.ts +15 -2
- package/src/utils/metadata.ts +155 -47
- package/src/utils/misc.ts +6079 -0
- package/src/utils/target.ts +66 -8
- package/src/utils/typegen.ts +1223 -63
- package/src/utils/version.ts +96 -0
|
@@ -1,3 +1,266 @@
|
|
|
1
|
+
const WASI_DISPOSE_SYMBOL = 'napi.rs.wasi.dispose'
|
|
2
|
+
const WASI_ROLLBACK_REGISTRY_SYMBOL = 'napi.rs.wasi.rollback.registry.v1'
|
|
3
|
+
|
|
4
|
+
const emnapiContextLifecycle = `
|
|
5
|
+
const __wasiDisposeSymbol = Symbol.for('${WASI_DISPOSE_SYMBOL}')
|
|
6
|
+
const __wasiWorkers = new Set()
|
|
7
|
+
let __napiInstance
|
|
8
|
+
let __emnapiContextDestroyed = false
|
|
9
|
+
let __emnapiContextDestroyPromise
|
|
10
|
+
let __emnapiWasmEnvCleanupPrepared = false
|
|
11
|
+
let __wasiDisposed = false
|
|
12
|
+
let __wasiDisposePromise
|
|
13
|
+
let __completeWasiDisposal = function() {}
|
|
14
|
+
|
|
15
|
+
function __isThenable(value) {
|
|
16
|
+
return (
|
|
17
|
+
value !== null &&
|
|
18
|
+
(typeof value === 'object' || typeof value === 'function') &&
|
|
19
|
+
typeof value.then === 'function'
|
|
20
|
+
)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function __createCleanupError(errors, message) {
|
|
24
|
+
if (errors.length === 1) {
|
|
25
|
+
return errors[0]
|
|
26
|
+
}
|
|
27
|
+
const __AggregateError = globalThis.AggregateError
|
|
28
|
+
if (typeof __AggregateError === 'function') {
|
|
29
|
+
return new __AggregateError(errors, message)
|
|
30
|
+
}
|
|
31
|
+
const error = new Error(message)
|
|
32
|
+
error.errors = errors
|
|
33
|
+
return error
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function __attachCleanupErrors(error, cleanupErrors) {
|
|
37
|
+
if (cleanupErrors.length === 0) {
|
|
38
|
+
return error
|
|
39
|
+
}
|
|
40
|
+
const cleanupError = __createCleanupError(
|
|
41
|
+
cleanupErrors,
|
|
42
|
+
'WASI binding cleanup failed',
|
|
43
|
+
)
|
|
44
|
+
try {
|
|
45
|
+
if (
|
|
46
|
+
error &&
|
|
47
|
+
(typeof error === 'object' || typeof error === 'function')
|
|
48
|
+
) {
|
|
49
|
+
if (error.cause === undefined) {
|
|
50
|
+
error.cause = cleanupError
|
|
51
|
+
if (error.cause === cleanupError) {
|
|
52
|
+
return error
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
if (Array.isArray(error.cleanupErrors)) {
|
|
56
|
+
error.cleanupErrors.push(cleanupError)
|
|
57
|
+
return error
|
|
58
|
+
} else {
|
|
59
|
+
const attachedCleanupErrors = [cleanupError]
|
|
60
|
+
error.cleanupErrors = attachedCleanupErrors
|
|
61
|
+
if (error.cleanupErrors === attachedCleanupErrors) {
|
|
62
|
+
return error
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
} catch {}
|
|
67
|
+
const aggregate = __createCleanupError(
|
|
68
|
+
[error, cleanupError],
|
|
69
|
+
'WASI binding initialization and cleanup failed',
|
|
70
|
+
)
|
|
71
|
+
try {
|
|
72
|
+
aggregate.cause = error
|
|
73
|
+
} catch {}
|
|
74
|
+
return aggregate
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function __prepareWasmEnvCleanup() {
|
|
78
|
+
if (__emnapiWasmEnvCleanupPrepared) {
|
|
79
|
+
return
|
|
80
|
+
}
|
|
81
|
+
const prepare = __napiInstance?.exports?.napi_prepare_wasm_env_cleanup
|
|
82
|
+
if (typeof prepare === 'function') {
|
|
83
|
+
prepare()
|
|
84
|
+
}
|
|
85
|
+
__emnapiWasmEnvCleanupPrepared = true
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function __destroyEmnapiContext() {
|
|
89
|
+
if (__emnapiContextDestroyed || __emnapiContext === undefined) {
|
|
90
|
+
__emnapiContextDestroyed = true
|
|
91
|
+
return
|
|
92
|
+
}
|
|
93
|
+
if (__emnapiContextDestroyPromise) {
|
|
94
|
+
return __emnapiContextDestroyPromise
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
__prepareWasmEnvCleanup()
|
|
98
|
+
const result = __emnapiContext.destroy()
|
|
99
|
+
if (!__isThenable(result)) {
|
|
100
|
+
__emnapiContextDestroyed = true
|
|
101
|
+
return
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const destroyPromise = Promise.resolve(result).then(
|
|
105
|
+
(value) => {
|
|
106
|
+
__emnapiContextDestroyed = true
|
|
107
|
+
return value
|
|
108
|
+
},
|
|
109
|
+
(error) => {
|
|
110
|
+
__emnapiContextDestroyPromise = undefined
|
|
111
|
+
throw error
|
|
112
|
+
},
|
|
113
|
+
)
|
|
114
|
+
__emnapiContextDestroyPromise = destroyPromise
|
|
115
|
+
return destroyPromise
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function __terminateWasiWorkers() {
|
|
119
|
+
const cleanupErrors = []
|
|
120
|
+
const pending = []
|
|
121
|
+
|
|
122
|
+
for (const worker of __wasiWorkers) {
|
|
123
|
+
let result
|
|
124
|
+
try {
|
|
125
|
+
result = worker.terminate()
|
|
126
|
+
} catch (error) {
|
|
127
|
+
cleanupErrors.push(error)
|
|
128
|
+
continue
|
|
129
|
+
}
|
|
130
|
+
if (__isThenable(result)) {
|
|
131
|
+
pending.push(
|
|
132
|
+
Promise.resolve(result).then(
|
|
133
|
+
() => {
|
|
134
|
+
__wasiWorkers.delete(worker)
|
|
135
|
+
},
|
|
136
|
+
(error) => {
|
|
137
|
+
cleanupErrors.push(error)
|
|
138
|
+
},
|
|
139
|
+
),
|
|
140
|
+
)
|
|
141
|
+
} else {
|
|
142
|
+
__wasiWorkers.delete(worker)
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const finish = () => {
|
|
147
|
+
if (cleanupErrors.length > 0) {
|
|
148
|
+
throw __createCleanupError(
|
|
149
|
+
cleanupErrors,
|
|
150
|
+
'Failed to terminate WASI workers',
|
|
151
|
+
)
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
return pending.length > 0 ? Promise.all(pending).then(finish) : finish()
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function __finishWasiDisposal() {
|
|
158
|
+
const workerResult = __terminateWasiWorkers()
|
|
159
|
+
if (__isThenable(workerResult)) {
|
|
160
|
+
return Promise.resolve(workerResult).then(__completeWasiDisposal)
|
|
161
|
+
}
|
|
162
|
+
return __completeWasiDisposal()
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
function __startWasiDisposal() {
|
|
166
|
+
const destroyResult = __destroyEmnapiContext()
|
|
167
|
+
if (__isThenable(destroyResult)) {
|
|
168
|
+
return Promise.resolve(destroyResult).then(__finishWasiDisposal)
|
|
169
|
+
}
|
|
170
|
+
return __finishWasiDisposal()
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Disposes this generated WASI binding.
|
|
175
|
+
*
|
|
176
|
+
* Access this function with:
|
|
177
|
+
* binding[Symbol.for('${WASI_DISPOSE_SYMBOL}')]()
|
|
178
|
+
*/
|
|
179
|
+
function __disposeWasiBinding() {
|
|
180
|
+
if (__wasiDisposePromise) {
|
|
181
|
+
return __wasiDisposePromise
|
|
182
|
+
}
|
|
183
|
+
if (__wasiDisposed) {
|
|
184
|
+
return Promise.resolve()
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
let resolveDispose
|
|
188
|
+
let rejectDispose
|
|
189
|
+
const disposePromise = new Promise((resolve, reject) => {
|
|
190
|
+
resolveDispose = resolve
|
|
191
|
+
rejectDispose = reject
|
|
192
|
+
})
|
|
193
|
+
__wasiDisposePromise = disposePromise
|
|
194
|
+
|
|
195
|
+
let result
|
|
196
|
+
try {
|
|
197
|
+
result = __startWasiDisposal()
|
|
198
|
+
} catch (error) {
|
|
199
|
+
__wasiDisposePromise = undefined
|
|
200
|
+
rejectDispose(error)
|
|
201
|
+
return disposePromise
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
Promise.resolve(result).then(
|
|
205
|
+
(value) => {
|
|
206
|
+
__wasiDisposed = true
|
|
207
|
+
resolveDispose(value)
|
|
208
|
+
},
|
|
209
|
+
(error) => {
|
|
210
|
+
__wasiDisposePromise = undefined
|
|
211
|
+
rejectDispose(error)
|
|
212
|
+
},
|
|
213
|
+
)
|
|
214
|
+
return disposePromise
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
function __publishWasiDispose(exports) {
|
|
218
|
+
Object.defineProperty(exports, __wasiDisposeSymbol, {
|
|
219
|
+
configurable: false,
|
|
220
|
+
enumerable: false,
|
|
221
|
+
value: __disposeWasiBinding,
|
|
222
|
+
writable: false,
|
|
223
|
+
})
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
function __finishWasiInitializationRollback(cleanupErrors) {
|
|
227
|
+
let workerResult
|
|
228
|
+
try {
|
|
229
|
+
workerResult = __terminateWasiWorkers()
|
|
230
|
+
} catch (cleanupError) {
|
|
231
|
+
cleanupErrors.push(cleanupError)
|
|
232
|
+
return cleanupErrors
|
|
233
|
+
}
|
|
234
|
+
if (__isThenable(workerResult)) {
|
|
235
|
+
return Promise.resolve(workerResult)
|
|
236
|
+
.catch((cleanupError) => {
|
|
237
|
+
cleanupErrors.push(cleanupError)
|
|
238
|
+
})
|
|
239
|
+
.then(() => cleanupErrors)
|
|
240
|
+
}
|
|
241
|
+
return cleanupErrors
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
function __rollbackWasiInitialization() {
|
|
245
|
+
const cleanupErrors = []
|
|
246
|
+
let destroyResult
|
|
247
|
+
try {
|
|
248
|
+
destroyResult = __destroyEmnapiContext()
|
|
249
|
+
} catch (cleanupError) {
|
|
250
|
+
cleanupErrors.push(cleanupError)
|
|
251
|
+
return __finishWasiInitializationRollback(cleanupErrors)
|
|
252
|
+
}
|
|
253
|
+
if (__isThenable(destroyResult)) {
|
|
254
|
+
return Promise.resolve(destroyResult)
|
|
255
|
+
.catch((cleanupError) => {
|
|
256
|
+
cleanupErrors.push(cleanupError)
|
|
257
|
+
})
|
|
258
|
+
.then(() => __finishWasiInitializationRollback(cleanupErrors))
|
|
259
|
+
}
|
|
260
|
+
return __finishWasiInitializationRollback(cleanupErrors)
|
|
261
|
+
}
|
|
262
|
+
`
|
|
263
|
+
|
|
1
264
|
export const createWasiBrowserBinding = (
|
|
2
265
|
wasiFilename: string,
|
|
3
266
|
initialMemory = 4000,
|
|
@@ -6,6 +269,7 @@ export const createWasiBrowserBinding = (
|
|
|
6
269
|
asyncInit = false,
|
|
7
270
|
buffer = false,
|
|
8
271
|
errorEvent = false,
|
|
272
|
+
threads = true,
|
|
9
273
|
) => {
|
|
10
274
|
const fsImport = fs
|
|
11
275
|
? buffer
|
|
@@ -30,20 +294,28 @@ const __wasi = new __WASI({
|
|
|
30
294
|
})`
|
|
31
295
|
|
|
32
296
|
const workerFsHandler = fs
|
|
33
|
-
? `
|
|
297
|
+
? ` worker.addEventListener('message', __wasmCreateOnMessageForFsProxy(__fs))\n`
|
|
34
298
|
: ''
|
|
35
299
|
|
|
36
300
|
const workerErrorHandler = errorEvent
|
|
37
|
-
? `
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
301
|
+
? ` worker.addEventListener('message', (event) => {
|
|
302
|
+
if (event.data && typeof event.data === 'object' && event.data.type === 'error') {
|
|
303
|
+
const __CustomEvent = globalThis.CustomEvent
|
|
304
|
+
if (
|
|
305
|
+
typeof globalThis.dispatchEvent === 'function' &&
|
|
306
|
+
typeof __CustomEvent === 'function'
|
|
307
|
+
) {
|
|
308
|
+
globalThis.dispatchEvent(
|
|
309
|
+
new __CustomEvent('napi-rs-worker-error', { detail: event.data }),
|
|
310
|
+
)
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
})
|
|
42
314
|
`
|
|
43
315
|
: ''
|
|
44
316
|
|
|
45
317
|
const emnapiInjectBuffer = buffer
|
|
46
|
-
? '__emnapiContext.
|
|
318
|
+
? ' __emnapiContext.features.Buffer = Buffer\n'
|
|
47
319
|
: ''
|
|
48
320
|
const emnapiInstantiateImport = asyncInit
|
|
49
321
|
? `instantiateNapiModule as __emnapiInstantiateNapiModule`
|
|
@@ -51,71 +323,1171 @@ const __wasi = new __WASI({
|
|
|
51
323
|
const emnapiInstantiateCall = asyncInit
|
|
52
324
|
? `await __emnapiInstantiateNapiModule`
|
|
53
325
|
: `__emnapiInstantiateNapiModuleSync`
|
|
326
|
+
const workerRuntimeImport = threads
|
|
327
|
+
? ` createOnMessage as __wasmCreateOnMessageForFsProxy,\n`
|
|
328
|
+
: ''
|
|
329
|
+
const memoryName = threads ? '__sharedMemory' : '__wasmMemory'
|
|
330
|
+
const asyncWorkPoolOption = ` asyncWorkPoolSize: ${threads ? 4 : 0},
|
|
331
|
+
`
|
|
332
|
+
// Every build links a "basic" emnapi archive without the C async-work and
|
|
333
|
+
// threadsafe-function implementations (the `emnapi-napi-rs(-mt)` archives shipped by the emnapi package), so the
|
|
334
|
+
// JavaScript implementations must be provided through the emnapi plugins in
|
|
335
|
+
// both threading modes. Without threads the C code would be unconditional
|
|
336
|
+
// `napi_generic_failure` stubs; with threads it would shadow the
|
|
337
|
+
// `@emnapi/core` threaded TSFN/async-work protocol the plugins implement.
|
|
338
|
+
const emnapiPluginImport = ` emnapiAsyncWorkPlugin as __emnapiAsyncWorkPlugin,\n emnapiTSFNPlugin as __emnapiTSFNPlugin,\n`
|
|
339
|
+
const emnapiPluginOption = ` plugins: [__emnapiAsyncWorkPlugin, __emnapiTSFNPlugin],\n`
|
|
340
|
+
const workerOption = threads
|
|
341
|
+
? ` onCreateWorker() {
|
|
342
|
+
const worker = new Worker(new URL('./wasi-worker-browser.mjs', import.meta.url), {
|
|
343
|
+
type: 'module',
|
|
344
|
+
})
|
|
345
|
+
__wasiWorkers.add(worker)
|
|
346
|
+
${workerFsHandler}
|
|
347
|
+
${workerErrorHandler}
|
|
348
|
+
return worker
|
|
349
|
+
},
|
|
350
|
+
`
|
|
351
|
+
: ''
|
|
54
352
|
|
|
55
353
|
return `import {
|
|
56
|
-
|
|
57
|
-
|
|
354
|
+
${emnapiPluginImport}\
|
|
355
|
+
${workerRuntimeImport}\
|
|
58
356
|
${emnapiInstantiateImport},
|
|
59
357
|
WASI as __WASI,
|
|
60
358
|
} from '@napi-rs/wasm-runtime'
|
|
359
|
+
import { createContext as __emnapiCreateContext } from '@emnapi/runtime'
|
|
61
360
|
${fsImport}
|
|
62
361
|
${bufferImport}
|
|
63
362
|
${wasiCreation}
|
|
64
363
|
|
|
65
364
|
const __wasmUrl = new URL('./${wasiFilename}.wasm', import.meta.url).href
|
|
66
|
-
const
|
|
67
|
-
|
|
365
|
+
const __wasmResponse = await globalThis.fetch(__wasmUrl)
|
|
366
|
+
if (!__wasmResponse.ok) {
|
|
367
|
+
throw new Error(
|
|
368
|
+
'Failed to fetch WASI module ' +
|
|
369
|
+
__wasmUrl +
|
|
370
|
+
': ' +
|
|
371
|
+
__wasmResponse.status +
|
|
372
|
+
' ' +
|
|
373
|
+
(__wasmResponse.statusText || 'Unknown Status'),
|
|
374
|
+
)
|
|
375
|
+
}
|
|
376
|
+
const __wasmFile = await __wasmResponse.arrayBuffer()
|
|
68
377
|
|
|
69
|
-
const
|
|
378
|
+
const ${memoryName} = new WebAssembly.Memory({
|
|
70
379
|
initial: ${initialMemory},
|
|
71
380
|
maximum: ${maximumMemory},
|
|
72
|
-
shared: true
|
|
381
|
+
${threads ? ' shared: true,\n' : ''}\
|
|
73
382
|
})
|
|
74
383
|
|
|
75
|
-
|
|
384
|
+
let __emnapiContext
|
|
385
|
+
${emnapiContextLifecycle}
|
|
386
|
+
let __wasiModule
|
|
387
|
+
let __napiModule
|
|
76
388
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
389
|
+
try {
|
|
390
|
+
__emnapiContext = __emnapiCreateContext({ autoDestroy: false })
|
|
391
|
+
__emnapiContext.suppressDestroy()
|
|
392
|
+
${emnapiInjectBuffer}
|
|
393
|
+
;({
|
|
394
|
+
instance: __napiInstance,
|
|
395
|
+
module: __wasiModule,
|
|
396
|
+
napiModule: __napiModule,
|
|
397
|
+
} = ${emnapiInstantiateCall}(__wasmFile, {
|
|
398
|
+
context: __emnapiContext,
|
|
399
|
+
${asyncWorkPoolOption}\
|
|
400
|
+
${emnapiPluginOption}\
|
|
401
|
+
wasi: __wasi,
|
|
402
|
+
${workerOption}\
|
|
403
|
+
overwriteImports(importObject) {
|
|
404
|
+
importObject.env = {
|
|
405
|
+
...importObject.env,
|
|
406
|
+
...importObject.napi,
|
|
407
|
+
...importObject.emnapi,
|
|
408
|
+
memory: ${memoryName},
|
|
409
|
+
}
|
|
410
|
+
return importObject
|
|
411
|
+
},
|
|
412
|
+
beforeInit({ instance }) {
|
|
413
|
+
__napiInstance = instance
|
|
414
|
+
for (const name of Object.keys(instance.exports)) {
|
|
415
|
+
if (name.startsWith('__napi_register__')) {
|
|
416
|
+
instance.exports[name]()
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
},
|
|
420
|
+
}))
|
|
421
|
+
__publishWasiDispose(__napiModule.exports)
|
|
422
|
+
} catch (error) {
|
|
423
|
+
const cleanupErrors = await __rollbackWasiInitialization()
|
|
424
|
+
throw __attachCleanupErrors(error, cleanupErrors)
|
|
425
|
+
}
|
|
426
|
+
`
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
export const createWasiDeferredBrowserBinding = (
|
|
430
|
+
wasiFilename: string,
|
|
431
|
+
// 64 MiB leaves headroom for JS/runtime state under workerd's 128 MiB
|
|
432
|
+
// isolate limit. The regular Node/browser loaders retain their historical
|
|
433
|
+
// 4,000-page default.
|
|
434
|
+
initialMemory = 1024,
|
|
435
|
+
maximumMemory = 65536,
|
|
436
|
+
buffer = false,
|
|
437
|
+
) => {
|
|
438
|
+
const bufferImport = buffer ? `import { Buffer } from 'buffer'` : ''
|
|
439
|
+
const emnapiInjectBuffer = buffer
|
|
440
|
+
? ' __emnapiContext.features.Buffer = Buffer\n'
|
|
441
|
+
: ''
|
|
442
|
+
return `import {
|
|
443
|
+
emnapiAsyncWorkPlugin as __emnapiAsyncWorkPlugin,
|
|
444
|
+
emnapiTSFNPlugin as __emnapiTSFNPlugin,
|
|
445
|
+
instantiateNapiModule as __emnapiInstantiateNapiModule,
|
|
446
|
+
WASI as __WASI,
|
|
447
|
+
} from '@napi-rs/wasm-runtime'
|
|
448
|
+
import { createContext as __emnapiCreateContext } from '@emnapi/runtime'
|
|
449
|
+
${bufferImport}
|
|
450
|
+
|
|
451
|
+
/**
|
|
452
|
+
* Deferred, workerd-safe instantiation: no top-level I/O, no compile-from-bytes.
|
|
453
|
+
* Accepts ONLY a precompiled WebAssembly.Module, or a Promise resolving to one
|
|
454
|
+
* (e.g. \`import mod from './${wasiFilename}.wasm'\` under a CompiledWasm
|
|
455
|
+
* module rule / wrangler module import). Byte buffers, URLs and Response
|
|
456
|
+
* objects are rejected: they require dynamic Wasm compilation, which
|
|
457
|
+
* Cloudflare Workers disallows.
|
|
458
|
+
*/
|
|
459
|
+
async function __resolveModule(__wasmInput) {
|
|
460
|
+
const __module = await __wasmInput
|
|
461
|
+
// Brand check, not \`instanceof\`: \`WebAssembly.Module.imports\` throws unless
|
|
462
|
+
// its argument is a genuine WebAssembly.Module, so prototype-spoofed byte
|
|
463
|
+
// buffers are rejected while cross-realm Module instances are accepted.
|
|
464
|
+
try {
|
|
465
|
+
WebAssembly.Module.imports(__module)
|
|
466
|
+
} catch {
|
|
467
|
+
throw new TypeError(
|
|
468
|
+
"instantiate() and createInstance() expect a precompiled WebAssembly.Module (or a Promise resolving to one), " +
|
|
469
|
+
"e.g. import mod from './${wasiFilename}.wasm' under a CompiledWasm module rule / wrangler module import. " +
|
|
470
|
+
"Byte buffers, URLs and Response objects require dynamic Wasm compilation, which Cloudflare Workers disallows.",
|
|
471
|
+
)
|
|
472
|
+
}
|
|
473
|
+
return __module
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
let __normalizedModules
|
|
477
|
+
|
|
478
|
+
function __rememberNormalizedModule(__module, __normalizedModule) {
|
|
479
|
+
if (!__normalizedModules) {
|
|
480
|
+
__normalizedModules = new WeakMap()
|
|
481
|
+
}
|
|
482
|
+
__normalizedModules.set(__module, __normalizedModule)
|
|
483
|
+
return __normalizedModule
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
async function __normalizeModuleForEmnapi(__module) {
|
|
487
|
+
if (__module instanceof WebAssembly.Module) {
|
|
488
|
+
return __module
|
|
489
|
+
}
|
|
490
|
+
if (__normalizedModules) {
|
|
491
|
+
const __normalizedModule = __normalizedModules.get(__module)
|
|
492
|
+
if (__normalizedModule) {
|
|
493
|
+
return __normalizedModule
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
// @emnapi/core currently performs realm-local \`instanceof\` checks after
|
|
497
|
+
// accepting the module. Structured cloning preserves compiled code without
|
|
498
|
+
// compiling bytes and produces a Module owned by the current realm.
|
|
499
|
+
if (typeof structuredClone === 'function') {
|
|
500
|
+
try {
|
|
501
|
+
const __normalizedModule = structuredClone(__module)
|
|
502
|
+
if (__normalizedModule instanceof WebAssembly.Module) {
|
|
503
|
+
return __rememberNormalizedModule(__module, __normalizedModule)
|
|
504
|
+
}
|
|
505
|
+
} catch {}
|
|
506
|
+
}
|
|
507
|
+
// MessageChannel uses the same structured-clone semantics and covers older
|
|
508
|
+
// browser/Node hosts that expose it but not the structuredClone function.
|
|
509
|
+
if (typeof MessageChannel === 'function') {
|
|
510
|
+
let __channel
|
|
511
|
+
try {
|
|
512
|
+
__channel = new MessageChannel()
|
|
513
|
+
const __normalizedModule = await new Promise((resolve, reject) => {
|
|
514
|
+
__channel.port1.onmessage = (event) => resolve(event.data)
|
|
515
|
+
__channel.port1.onmessageerror = () =>
|
|
516
|
+
reject(new TypeError('Failed to clone WebAssembly.Module'))
|
|
517
|
+
try {
|
|
518
|
+
__channel.port2.postMessage(__module)
|
|
519
|
+
} catch (error) {
|
|
520
|
+
reject(error)
|
|
521
|
+
}
|
|
522
|
+
})
|
|
523
|
+
if (__normalizedModule instanceof WebAssembly.Module) {
|
|
524
|
+
return __rememberNormalizedModule(__module, __normalizedModule)
|
|
525
|
+
}
|
|
526
|
+
} catch {
|
|
527
|
+
} finally {
|
|
528
|
+
try {
|
|
529
|
+
__channel?.port1.close()
|
|
530
|
+
} catch {}
|
|
531
|
+
try {
|
|
532
|
+
__channel?.port2.close()
|
|
533
|
+
} catch {}
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
// Last-resort compatibility for genuine, extensible foreign Modules.
|
|
537
|
+
try {
|
|
538
|
+
Object.setPrototypeOf(__module, WebAssembly.Module.prototype)
|
|
539
|
+
} catch {}
|
|
540
|
+
if (__module instanceof WebAssembly.Module) {
|
|
541
|
+
return __module
|
|
542
|
+
}
|
|
543
|
+
throw new TypeError(
|
|
544
|
+
'This host cannot normalize a cross-realm WebAssembly.Module; ' +
|
|
545
|
+
'provide structuredClone or MessageChannel support.',
|
|
546
|
+
)
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
function __captureEmnapiAutoDestroyListener(__process) {
|
|
550
|
+
if (
|
|
551
|
+
!__process ||
|
|
552
|
+
typeof __process.prependListener !== 'function' ||
|
|
553
|
+
typeof __process.removeListener !== 'function'
|
|
554
|
+
) {
|
|
555
|
+
return
|
|
556
|
+
}
|
|
557
|
+
let __autoDestroyListener
|
|
558
|
+
const __captureListener = (__event, __listener) => {
|
|
559
|
+
if (__event === 'beforeExit' && __autoDestroyListener === undefined) {
|
|
560
|
+
__autoDestroyListener = __listener
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
try {
|
|
564
|
+
// Run before existing newListener hooks so a hook that registers its own
|
|
565
|
+
// beforeExit listener cannot be mistaken for emnapi's registration.
|
|
566
|
+
__process.prependListener('newListener', __captureListener)
|
|
567
|
+
} catch {
|
|
568
|
+
return
|
|
569
|
+
}
|
|
570
|
+
return () => {
|
|
571
|
+
try {
|
|
572
|
+
__process.removeListener('newListener', __captureListener)
|
|
573
|
+
} catch {}
|
|
574
|
+
if (__autoDestroyListener !== undefined) {
|
|
575
|
+
try {
|
|
576
|
+
__process.removeListener('beforeExit', __autoDestroyListener)
|
|
577
|
+
} catch {}
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
function __attachCleanupError(__error, __cleanupError) {
|
|
583
|
+
try {
|
|
584
|
+
if (
|
|
585
|
+
__error &&
|
|
586
|
+
(typeof __error === 'object' || typeof __error === 'function') &&
|
|
587
|
+
__error.cause === undefined
|
|
588
|
+
) {
|
|
589
|
+
__error.cause = __cleanupError
|
|
590
|
+
}
|
|
591
|
+
} catch {}
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
function __createLifecycleReentryError(__operation) {
|
|
595
|
+
const __error = new Error(
|
|
596
|
+
__operation +
|
|
597
|
+
'() cannot run while an emnapi Context.destroy() call is still active; await the original cleanup promise instead.',
|
|
598
|
+
)
|
|
599
|
+
__error.code = 'ERR_NAPI_WASI_LIFECYCLE_REENTRY'
|
|
600
|
+
return __error
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
const __managedEmnapiContextDestroyers = new Set()
|
|
604
|
+
let __managedCleanupProcess
|
|
605
|
+
let __managedBeforeExitListener
|
|
606
|
+
let __managedDestroyPromise
|
|
607
|
+
let __managedDestroyersInFlight
|
|
608
|
+
let __managedBeforeExitRegistrationRetryCount = 0
|
|
609
|
+
let __managedBeforeExitRegistrationRetryScheduled = false
|
|
610
|
+
let __moduleLifecycleDestroyDepth = 0
|
|
611
|
+
|
|
612
|
+
function __removeManagedEmnapiCleanupListeners() {
|
|
613
|
+
const __process = __managedCleanupProcess
|
|
614
|
+
const __beforeExitListener = __managedBeforeExitListener
|
|
615
|
+
__managedCleanupProcess = undefined
|
|
616
|
+
__managedBeforeExitListener = undefined
|
|
617
|
+
__managedBeforeExitRegistrationRetryCount = 0
|
|
618
|
+
if (__process && __beforeExitListener) {
|
|
619
|
+
try {
|
|
620
|
+
__process.removeListener('beforeExit', __beforeExitListener)
|
|
621
|
+
} catch {}
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
function __scheduleManagedBeforeExitListenerRegistration() {
|
|
626
|
+
if (
|
|
627
|
+
!__managedCleanupProcess ||
|
|
628
|
+
__managedBeforeExitListener ||
|
|
629
|
+
__managedEmnapiContextDestroyers.size === 0 ||
|
|
630
|
+
__managedBeforeExitRegistrationRetryScheduled ||
|
|
631
|
+
__managedBeforeExitRegistrationRetryCount >= 3
|
|
632
|
+
) {
|
|
633
|
+
return
|
|
634
|
+
}
|
|
635
|
+
__managedBeforeExitRegistrationRetryScheduled = true
|
|
636
|
+
__managedBeforeExitRegistrationRetryCount++
|
|
637
|
+
queueMicrotask(() => {
|
|
638
|
+
__managedBeforeExitRegistrationRetryScheduled = false
|
|
639
|
+
if (
|
|
640
|
+
!__managedCleanupProcess ||
|
|
641
|
+
__managedBeforeExitListener ||
|
|
642
|
+
__managedEmnapiContextDestroyers.size === 0
|
|
643
|
+
) {
|
|
644
|
+
return
|
|
645
|
+
}
|
|
646
|
+
try {
|
|
647
|
+
__registerManagedBeforeExitListener()
|
|
648
|
+
} catch {}
|
|
649
|
+
})
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
function __registerManagedBeforeExitListener() {
|
|
653
|
+
if (!__managedCleanupProcess || __managedBeforeExitListener) {
|
|
654
|
+
return
|
|
655
|
+
}
|
|
656
|
+
try {
|
|
657
|
+
__managedCleanupProcess.once(
|
|
658
|
+
'beforeExit',
|
|
659
|
+
__destroyManagedEmnapiContextsBeforeExit,
|
|
660
|
+
)
|
|
661
|
+
} catch (error) {
|
|
662
|
+
__scheduleManagedBeforeExitListenerRegistration()
|
|
663
|
+
throw error
|
|
664
|
+
}
|
|
665
|
+
__managedBeforeExitListener = __destroyManagedEmnapiContextsBeforeExit
|
|
666
|
+
__managedBeforeExitRegistrationRetryCount = 0
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
function __settleManagedEmnapiContextDestroy(__promise) {
|
|
670
|
+
if (__managedDestroyPromise === __promise) {
|
|
671
|
+
__managedDestroyPromise = undefined
|
|
672
|
+
__managedDestroyersInFlight = undefined
|
|
673
|
+
}
|
|
674
|
+
if (__managedEmnapiContextDestroyers.size === 0) {
|
|
675
|
+
__removeManagedEmnapiCleanupListeners()
|
|
676
|
+
return
|
|
677
|
+
}
|
|
678
|
+
try {
|
|
679
|
+
__registerManagedBeforeExitListener()
|
|
680
|
+
} catch {}
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
function __destroyManagedEmnapiContexts(__excludedDestroyers) {
|
|
684
|
+
if (__managedDestroyPromise) {
|
|
685
|
+
return __managedDestroyPromise
|
|
686
|
+
}
|
|
687
|
+
const __destroyers = Array.from(__managedEmnapiContextDestroyers).filter(
|
|
688
|
+
(__destroy) => !__excludedDestroyers?.has(__destroy),
|
|
689
|
+
)
|
|
690
|
+
if (__destroyers.length === 0) {
|
|
691
|
+
return Promise.resolve()
|
|
692
|
+
}
|
|
693
|
+
let __resolveDestroy
|
|
694
|
+
let __rejectDestroy
|
|
695
|
+
const __promise = new Promise((resolve, reject) => {
|
|
696
|
+
__resolveDestroy = resolve
|
|
697
|
+
__rejectDestroy = reject
|
|
698
|
+
})
|
|
699
|
+
__managedDestroyPromise = __promise
|
|
700
|
+
__managedDestroyersInFlight = new Set(__destroyers)
|
|
701
|
+
void Promise.all(
|
|
702
|
+
__destroyers.map((__destroy) => {
|
|
703
|
+
try {
|
|
704
|
+
return Promise.resolve(__destroy()).then(
|
|
705
|
+
() => ({ failed: false }),
|
|
706
|
+
(error) => ({ failed: true, error }),
|
|
707
|
+
)
|
|
708
|
+
} catch (error) {
|
|
709
|
+
return { failed: true, error }
|
|
710
|
+
}
|
|
711
|
+
}),
|
|
712
|
+
).then((__results) => {
|
|
713
|
+
let __primaryError
|
|
714
|
+
let __failed = false
|
|
715
|
+
for (const __result of __results) {
|
|
716
|
+
if (!__result.failed) {
|
|
717
|
+
continue
|
|
718
|
+
}
|
|
719
|
+
if (!__failed) {
|
|
720
|
+
__failed = true
|
|
721
|
+
__primaryError = __result.error
|
|
722
|
+
} else {
|
|
723
|
+
__attachCleanupError(__primaryError, __result.error)
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
if (__failed) {
|
|
727
|
+
__rejectDestroy(__primaryError)
|
|
728
|
+
} else {
|
|
729
|
+
__resolveDestroy()
|
|
730
|
+
}
|
|
731
|
+
}, __rejectDestroy)
|
|
732
|
+
void __promise.then(
|
|
733
|
+
() => {
|
|
734
|
+
__settleManagedEmnapiContextDestroy(__promise)
|
|
735
|
+
},
|
|
736
|
+
() => {
|
|
737
|
+
__settleManagedEmnapiContextDestroy(__promise)
|
|
738
|
+
},
|
|
739
|
+
)
|
|
740
|
+
return __promise
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
async function __drainManagedEmnapiContexts(__excludedDestroyers) {
|
|
744
|
+
const __attemptedDestroyers = new Set(__excludedDestroyers)
|
|
745
|
+
let __primaryError
|
|
746
|
+
let __failed = false
|
|
747
|
+
while (true) {
|
|
748
|
+
let __promise = __managedDestroyPromise
|
|
749
|
+
let __destroyers = __managedDestroyersInFlight
|
|
750
|
+
if (!__promise) {
|
|
751
|
+
__promise = __destroyManagedEmnapiContexts(__attemptedDestroyers)
|
|
752
|
+
__destroyers = __managedDestroyersInFlight
|
|
753
|
+
if (!__destroyers) {
|
|
754
|
+
break
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
for (const __destroy of __destroyers) {
|
|
758
|
+
__attemptedDestroyers.add(__destroy)
|
|
759
|
+
}
|
|
760
|
+
try {
|
|
761
|
+
await __promise
|
|
762
|
+
} catch (error) {
|
|
763
|
+
if (!__failed) {
|
|
764
|
+
__failed = true
|
|
765
|
+
__primaryError = error
|
|
766
|
+
} else {
|
|
767
|
+
__attachCleanupError(__primaryError, error)
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
if (__failed) {
|
|
772
|
+
throw __primaryError
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
function __destroyManagedEmnapiContextsBeforeExit() {
|
|
777
|
+
// A once listener is consumed before Node invokes it, including when another
|
|
778
|
+
// cleanup batch is still pending.
|
|
779
|
+
__managedBeforeExitListener = undefined
|
|
780
|
+
if (__managedDestroyPromise) {
|
|
781
|
+
return
|
|
782
|
+
}
|
|
783
|
+
void __destroyManagedEmnapiContexts().catch((error) => {
|
|
784
|
+
queueMicrotask(() => {
|
|
785
|
+
throw error
|
|
88
786
|
})
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
787
|
+
})
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
function __registerManagedEmnapiContext(__process, __destroy) {
|
|
791
|
+
__managedEmnapiContextDestroyers.add(__destroy)
|
|
792
|
+
if (
|
|
793
|
+
!__managedCleanupProcess &&
|
|
794
|
+
__process &&
|
|
795
|
+
typeof __process.once === 'function' &&
|
|
796
|
+
typeof __process.removeListener === 'function'
|
|
797
|
+
) {
|
|
798
|
+
__managedCleanupProcess = __process
|
|
799
|
+
}
|
|
800
|
+
let __registered = true
|
|
801
|
+
return () => {
|
|
802
|
+
if (!__registered) {
|
|
803
|
+
return
|
|
804
|
+
}
|
|
805
|
+
__registered = false
|
|
806
|
+
__managedEmnapiContextDestroyers.delete(__destroy)
|
|
807
|
+
if (__managedEmnapiContextDestroyers.size === 0) {
|
|
808
|
+
__removeManagedEmnapiCleanupListeners()
|
|
809
|
+
}
|
|
810
|
+
}
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
async function __createManagedEmnapiContext(__prepareEnvCleanup) {
|
|
814
|
+
const __process =
|
|
815
|
+
typeof process === 'object' && process !== null ? process : undefined
|
|
816
|
+
const __finishAutoDestroyCapture =
|
|
817
|
+
__captureEmnapiAutoDestroyListener(__process)
|
|
818
|
+
let __emnapiContext
|
|
819
|
+
let __contextInitializationError
|
|
820
|
+
let __contextInitializationFailed = false
|
|
821
|
+
try {
|
|
822
|
+
__emnapiContext = __emnapiCreateContext({ autoDestroy: false })
|
|
823
|
+
// emnapi 2.x still registers an unconditional process.once('beforeExit')
|
|
824
|
+
// auto-destroy listener on Node hosts, and suppressDestroy() only
|
|
825
|
+
// neutralizes its callback without removing it. This loader must stay
|
|
826
|
+
// side-effect free per instance, so the listener is captured and removed;
|
|
827
|
+
// suppressDestroy() remains the safety net when removal is unavailable.
|
|
828
|
+
__emnapiContext.suppressDestroy()
|
|
829
|
+
} catch (error) {
|
|
830
|
+
__contextInitializationError = error
|
|
831
|
+
__contextInitializationFailed = true
|
|
832
|
+
} finally {
|
|
833
|
+
// Remove only the exact emnapi callback captured above.
|
|
834
|
+
__finishAutoDestroyCapture?.()
|
|
835
|
+
}
|
|
836
|
+
if (__emnapiContext === undefined) {
|
|
837
|
+
throw __contextInitializationError
|
|
838
|
+
}
|
|
839
|
+
let __disposed = false
|
|
840
|
+
let __destroying = false
|
|
841
|
+
let __destroyPromise
|
|
842
|
+
let __cleanupRegistered = false
|
|
843
|
+
let __unregisterCleanup
|
|
844
|
+
const __destroy = (__blocksModuleLifecycle = false) => {
|
|
845
|
+
if (__disposed) {
|
|
846
|
+
return
|
|
847
|
+
}
|
|
848
|
+
if (__destroying) {
|
|
849
|
+
throw __createLifecycleReentryError('dispose')
|
|
850
|
+
}
|
|
851
|
+
if (__destroyPromise) {
|
|
852
|
+
return __destroyPromise
|
|
853
|
+
}
|
|
854
|
+
__destroying = true
|
|
855
|
+
let __result
|
|
856
|
+
const __finishDestroyInvocation = () => {
|
|
857
|
+
__destroying = false
|
|
858
|
+
}
|
|
859
|
+
const __finishModuleLifecycleDestroy = () => {
|
|
860
|
+
if (__blocksModuleLifecycle) {
|
|
861
|
+
__blocksModuleLifecycle = false
|
|
862
|
+
__moduleLifecycleDestroyDepth--
|
|
106
863
|
}
|
|
107
864
|
}
|
|
108
|
-
|
|
109
|
-
|
|
865
|
+
if (__blocksModuleLifecycle) {
|
|
866
|
+
__moduleLifecycleDestroyDepth++
|
|
867
|
+
}
|
|
868
|
+
try {
|
|
869
|
+
// Context.destroy() disables JS before cleanup hooks run, so settle
|
|
870
|
+
// runtime-owned promises while this environment can still call JS.
|
|
871
|
+
__prepareEnvCleanup?.()
|
|
872
|
+
__result = __emnapiContext.destroy()
|
|
873
|
+
} catch (error) {
|
|
874
|
+
__finishDestroyInvocation()
|
|
875
|
+
__finishModuleLifecycleDestroy()
|
|
876
|
+
throw error
|
|
877
|
+
}
|
|
878
|
+
let __then
|
|
879
|
+
try {
|
|
880
|
+
if (
|
|
881
|
+
__result !== null &&
|
|
882
|
+
(typeof __result === 'object' || typeof __result === 'function')
|
|
883
|
+
) {
|
|
884
|
+
__then = __result.then
|
|
885
|
+
}
|
|
886
|
+
} catch (error) {
|
|
887
|
+
__finishDestroyInvocation()
|
|
888
|
+
__finishModuleLifecycleDestroy()
|
|
889
|
+
throw error
|
|
890
|
+
}
|
|
891
|
+
if (typeof __then === 'function') {
|
|
892
|
+
let __resolveResult
|
|
893
|
+
let __rejectResult
|
|
894
|
+
const __resultPromise = new Promise((resolve, reject) => {
|
|
895
|
+
__resolveResult = resolve
|
|
896
|
+
__rejectResult = reject
|
|
897
|
+
})
|
|
898
|
+
const __promise = __resultPromise.then(
|
|
899
|
+
(value) => {
|
|
900
|
+
__finishDestroyInvocation()
|
|
901
|
+
__finishModuleLifecycleDestroy()
|
|
902
|
+
__disposed = true
|
|
903
|
+
__destroyPromise = undefined
|
|
904
|
+
__unregisterCleanup?.()
|
|
905
|
+
return value
|
|
906
|
+
},
|
|
907
|
+
(error) => {
|
|
908
|
+
__finishDestroyInvocation()
|
|
909
|
+
__finishModuleLifecycleDestroy()
|
|
910
|
+
__destroyPromise = undefined
|
|
911
|
+
throw error
|
|
912
|
+
},
|
|
913
|
+
)
|
|
914
|
+
__destroyPromise = __promise
|
|
915
|
+
try {
|
|
916
|
+
Reflect.apply(__then, __result, [__resolveResult, __rejectResult])
|
|
917
|
+
} catch (error) {
|
|
918
|
+
__rejectResult(error)
|
|
919
|
+
}
|
|
920
|
+
return __promise
|
|
921
|
+
}
|
|
922
|
+
__finishDestroyInvocation()
|
|
923
|
+
__finishModuleLifecycleDestroy()
|
|
924
|
+
__disposed = true
|
|
925
|
+
__unregisterCleanup?.()
|
|
926
|
+
}
|
|
927
|
+
const __destroyForModuleLifecycle = () => __destroy(true)
|
|
928
|
+
const __registerCleanup = (
|
|
929
|
+
__beforeExitDestroy = __destroyForModuleLifecycle,
|
|
930
|
+
) => {
|
|
931
|
+
if (__cleanupRegistered || __disposed) {
|
|
932
|
+
return
|
|
933
|
+
}
|
|
934
|
+
__unregisterCleanup = __registerManagedEmnapiContext(
|
|
935
|
+
__process,
|
|
936
|
+
__beforeExitDestroy,
|
|
937
|
+
)
|
|
938
|
+
__cleanupRegistered = true
|
|
939
|
+
__registerManagedBeforeExitListener()
|
|
940
|
+
}
|
|
941
|
+
if (__contextInitializationFailed) {
|
|
942
|
+
let __registrationError
|
|
943
|
+
let __registrationFailed = false
|
|
944
|
+
try {
|
|
945
|
+
__registerCleanup()
|
|
946
|
+
} catch (error) {
|
|
947
|
+
__attachCleanupError(__contextInitializationError, error)
|
|
948
|
+
__registrationError = error
|
|
949
|
+
__registrationFailed = true
|
|
950
|
+
}
|
|
951
|
+
try {
|
|
952
|
+
await __destroyForModuleLifecycle()
|
|
953
|
+
} catch (error) {
|
|
954
|
+
__attachCleanupError(
|
|
955
|
+
__registrationFailed
|
|
956
|
+
? __registrationError
|
|
957
|
+
: __contextInitializationError,
|
|
958
|
+
error,
|
|
959
|
+
)
|
|
960
|
+
try {
|
|
961
|
+
__registerManagedBeforeExitListener()
|
|
962
|
+
} catch {}
|
|
963
|
+
}
|
|
964
|
+
throw __contextInitializationError
|
|
965
|
+
}
|
|
966
|
+
return {
|
|
967
|
+
context: __emnapiContext,
|
|
968
|
+
destroy: __destroy,
|
|
969
|
+
destroyForModuleLifecycle: __destroyForModuleLifecycle,
|
|
970
|
+
registerCleanup: __registerCleanup,
|
|
971
|
+
}
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
async function __createInstance(
|
|
975
|
+
__wasmInput,
|
|
976
|
+
__beforeExitDestroy,
|
|
977
|
+
__onManagedDestroyer,
|
|
978
|
+
) {
|
|
979
|
+
const __module = await __resolveModule(__wasmInput)
|
|
980
|
+
const __emnapiModule = await __normalizeModuleForEmnapi(__module)
|
|
981
|
+
const __wasi = new __WASI({
|
|
982
|
+
version: 'preview1',
|
|
983
|
+
})
|
|
984
|
+
// The wasm module is linked with \`--import-memory\`, so a Memory must be
|
|
985
|
+
// provided. It is allocated here in function scope (workerd bans global
|
|
986
|
+
// scope allocation) and is not shared (no threads, no SharedArrayBuffer).
|
|
987
|
+
// Allocate it before the emnapi context so a host memory-limit failure cannot
|
|
988
|
+
// leak a context that never reaches instantiation.
|
|
989
|
+
const __wasmMemory = new WebAssembly.Memory({
|
|
990
|
+
initial: ${initialMemory},
|
|
991
|
+
maximum: ${maximumMemory},
|
|
992
|
+
})
|
|
993
|
+
let __lifecycleState = 'pending'
|
|
994
|
+
let __destroyEmnapiContext
|
|
995
|
+
let __destroyOwnedContext
|
|
996
|
+
let __destroyManagedOwnedContext
|
|
997
|
+
let __napiInstance
|
|
998
|
+
const __destroyBeforeExit = __beforeExitDestroy
|
|
999
|
+
? async () => {
|
|
1000
|
+
if (__lifecycleState === 'failed') {
|
|
1001
|
+
await __destroyManagedOwnedContext()
|
|
1002
|
+
return
|
|
1003
|
+
}
|
|
1004
|
+
__lifecycleState = 'disposal'
|
|
1005
|
+
try {
|
|
1006
|
+
await __beforeExitDestroy()
|
|
1007
|
+
} catch (error) {
|
|
1008
|
+
if (__lifecycleState !== 'failed') {
|
|
1009
|
+
throw error
|
|
1010
|
+
}
|
|
1011
|
+
// The singleton's initialization rejection is already observable
|
|
1012
|
+
// through instantiate() and dispose(). Managed beforeExit cleanup
|
|
1013
|
+
// owns only context destruction, including retrying a failed rollback.
|
|
1014
|
+
await __destroyManagedOwnedContext()
|
|
1015
|
+
}
|
|
1016
|
+
}
|
|
1017
|
+
: undefined
|
|
1018
|
+
const {
|
|
1019
|
+
context: __emnapiContext,
|
|
1020
|
+
destroy,
|
|
1021
|
+
destroyForModuleLifecycle,
|
|
1022
|
+
registerCleanup: __registerCleanup,
|
|
1023
|
+
} = await __createManagedEmnapiContext(() => {
|
|
1024
|
+
const __prepareWasmEnvCleanup =
|
|
1025
|
+
__napiInstance?.exports.napi_prepare_wasm_env_cleanup
|
|
1026
|
+
if (typeof __prepareWasmEnvCleanup === 'function') {
|
|
1027
|
+
__prepareWasmEnvCleanup()
|
|
1028
|
+
}
|
|
1029
|
+
})
|
|
1030
|
+
__destroyEmnapiContext = destroy
|
|
1031
|
+
__destroyOwnedContext = () => __destroyEmnapiContext()
|
|
1032
|
+
__destroyManagedOwnedContext = destroyForModuleLifecycle
|
|
1033
|
+
try {
|
|
1034
|
+
if (__destroyBeforeExit) {
|
|
1035
|
+
__onManagedDestroyer(__destroyBeforeExit)
|
|
1036
|
+
await __registerCleanup(__destroyBeforeExit)
|
|
1037
|
+
}
|
|
1038
|
+
${emnapiInjectBuffer}\
|
|
1039
|
+
let __napiModule
|
|
1040
|
+
;({
|
|
1041
|
+
instance: __napiInstance,
|
|
1042
|
+
napiModule: __napiModule,
|
|
1043
|
+
} = await __emnapiInstantiateNapiModule(__emnapiModule, {
|
|
1044
|
+
context: __emnapiContext,
|
|
1045
|
+
asyncWorkPoolSize: 0,
|
|
1046
|
+
plugins: [__emnapiAsyncWorkPlugin, __emnapiTSFNPlugin],
|
|
1047
|
+
wasi: __wasi,
|
|
1048
|
+
overwriteImports(importObject) {
|
|
1049
|
+
importObject.env = {
|
|
1050
|
+
...importObject.env,
|
|
1051
|
+
...importObject.napi,
|
|
1052
|
+
...importObject.emnapi,
|
|
1053
|
+
memory: __wasmMemory,
|
|
1054
|
+
}
|
|
1055
|
+
return importObject
|
|
1056
|
+
},
|
|
1057
|
+
beforeInit({ instance }) {
|
|
1058
|
+
__napiInstance = instance
|
|
1059
|
+
for (const name of Object.keys(instance.exports)) {
|
|
1060
|
+
if (name.startsWith('__napi_register__')) {
|
|
1061
|
+
instance.exports[name]()
|
|
1062
|
+
}
|
|
1063
|
+
}
|
|
1064
|
+
},
|
|
1065
|
+
}))
|
|
1066
|
+
if (__lifecycleState === 'pending') {
|
|
1067
|
+
__lifecycleState = 'succeeded'
|
|
1068
|
+
}
|
|
1069
|
+
return {
|
|
1070
|
+
exports: __napiModule.exports,
|
|
1071
|
+
async dispose() {
|
|
1072
|
+
if (__lifecycleState !== 'failed') {
|
|
1073
|
+
__lifecycleState = 'disposal'
|
|
1074
|
+
}
|
|
1075
|
+
return __beforeExitDestroy
|
|
1076
|
+
? __destroyManagedOwnedContext()
|
|
1077
|
+
: __destroyOwnedContext()
|
|
1078
|
+
},
|
|
1079
|
+
}
|
|
1080
|
+
} catch (error) {
|
|
1081
|
+
__lifecycleState = 'failed'
|
|
1082
|
+
let __registrationError
|
|
1083
|
+
let __registrationFailed = false
|
|
1084
|
+
if (!__beforeExitDestroy) {
|
|
1085
|
+
try {
|
|
1086
|
+
// Independent instances are caller-owned while pending and after
|
|
1087
|
+
// success. Register only failed rollback so cleanup remains retryable.
|
|
1088
|
+
await __registerCleanup()
|
|
1089
|
+
} catch (registrationError) {
|
|
1090
|
+
__attachCleanupError(error, registrationError)
|
|
1091
|
+
__registrationError = registrationError
|
|
1092
|
+
__registrationFailed = true
|
|
1093
|
+
}
|
|
1094
|
+
}
|
|
1095
|
+
try {
|
|
1096
|
+
await __destroyManagedOwnedContext()
|
|
1097
|
+
} catch (disposeError) {
|
|
1098
|
+
// Initialization is the primary failure. Preserve it even if cleanup
|
|
1099
|
+
// also fails, while retaining the cleanup error when the value is
|
|
1100
|
+
// extensible and has no existing cause.
|
|
1101
|
+
__attachCleanupError(
|
|
1102
|
+
__registrationFailed ? __registrationError : error,
|
|
1103
|
+
disposeError,
|
|
1104
|
+
)
|
|
1105
|
+
try {
|
|
1106
|
+
__registerManagedBeforeExitListener()
|
|
1107
|
+
} catch {}
|
|
1108
|
+
}
|
|
1109
|
+
throw error
|
|
1110
|
+
}
|
|
1111
|
+
}
|
|
1112
|
+
|
|
1113
|
+
/**
|
|
1114
|
+
* Create an independent instance. Call dispose() when the instance is no
|
|
1115
|
+
* longer needed so emnapi cleanup hooks run deterministically.
|
|
1116
|
+
*/
|
|
1117
|
+
export async function createInstance(__wasmInput) {
|
|
1118
|
+
return __createInstance(__wasmInput)
|
|
1119
|
+
}
|
|
1120
|
+
|
|
1121
|
+
let __defaultModulePromise
|
|
1122
|
+
let __defaultInstancePromise
|
|
1123
|
+
let __defaultDisposePromise
|
|
1124
|
+
let __defaultDisposalStarted = false
|
|
1125
|
+
const __defaultManagedDestroyers = new WeakMap()
|
|
1126
|
+
let __moduleDisposePromise
|
|
1127
|
+
|
|
1128
|
+
/**
|
|
1129
|
+
* Instantiate a module-local singleton. Concurrent and repeated calls
|
|
1130
|
+
* with the same module share one instance and one Memory allocation.
|
|
1131
|
+
*/
|
|
1132
|
+
export function instantiate(__wasmInput) {
|
|
1133
|
+
const __modulePromise = __resolveModule(__wasmInput)
|
|
1134
|
+
if (__moduleLifecycleDestroyDepth !== 0) {
|
|
1135
|
+
void __modulePromise.catch(() => {})
|
|
1136
|
+
return Promise.reject(__createLifecycleReentryError('instantiate'))
|
|
1137
|
+
}
|
|
1138
|
+
if (__moduleDisposePromise) {
|
|
1139
|
+
void __modulePromise.catch(() => {})
|
|
1140
|
+
return __moduleDisposePromise.then(() => instantiate(__modulePromise))
|
|
1141
|
+
}
|
|
1142
|
+
if (__defaultDisposalStarted) {
|
|
1143
|
+
// Observe rejected input immediately, but preserve lifecycle ordering and
|
|
1144
|
+
// error precedence by instantiating only after disposal succeeds. A failed
|
|
1145
|
+
// disposal retains the old instance only so its cleanup can be retried.
|
|
1146
|
+
void __modulePromise.catch(() => {})
|
|
1147
|
+
const __disposePromise = __defaultDisposePromise ?? dispose()
|
|
1148
|
+
return __disposePromise.then(() => instantiate(__modulePromise))
|
|
1149
|
+
}
|
|
1150
|
+
if (!__defaultInstancePromise) {
|
|
1151
|
+
__defaultModulePromise = __modulePromise
|
|
1152
|
+
const __instancePromise = __modulePromise.then((__module) =>
|
|
1153
|
+
__createInstance(
|
|
1154
|
+
__module,
|
|
1155
|
+
__disposeDefaultInstance,
|
|
1156
|
+
(__managedDestroyer) => {
|
|
1157
|
+
__defaultManagedDestroyers.set(
|
|
1158
|
+
__instancePromise,
|
|
1159
|
+
__managedDestroyer,
|
|
1160
|
+
)
|
|
1161
|
+
},
|
|
1162
|
+
),
|
|
1163
|
+
)
|
|
1164
|
+
__defaultInstancePromise = __instancePromise
|
|
1165
|
+
void __instancePromise.catch(() => {
|
|
1166
|
+
if (__defaultInstancePromise === __instancePromise) {
|
|
1167
|
+
__defaultInstancePromise = undefined
|
|
1168
|
+
__defaultModulePromise = undefined
|
|
1169
|
+
}
|
|
1170
|
+
})
|
|
1171
|
+
return __instancePromise.then((__instance) => __instance.exports)
|
|
1172
|
+
}
|
|
1173
|
+
const __defaultModulePromiseForCall = __defaultModulePromise
|
|
1174
|
+
const __defaultInstancePromiseForCall = __defaultInstancePromise
|
|
1175
|
+
return Promise.all([__defaultModulePromiseForCall, __modulePromise]).then(
|
|
1176
|
+
async ([__defaultModule, __module]) => {
|
|
1177
|
+
if (__defaultModule !== __module) {
|
|
1178
|
+
throw new Error(
|
|
1179
|
+
'instantiate() already owns a different WebAssembly.Module; call dispose() first or use createInstance() for independent instances.',
|
|
1180
|
+
)
|
|
1181
|
+
}
|
|
1182
|
+
return (await __defaultInstancePromiseForCall).exports
|
|
1183
|
+
},
|
|
1184
|
+
)
|
|
1185
|
+
}
|
|
1186
|
+
|
|
1187
|
+
async function __disposeDefaultInstance(__onDestroy) {
|
|
1188
|
+
if (__defaultDisposePromise) {
|
|
1189
|
+
return __defaultDisposePromise
|
|
1190
|
+
}
|
|
1191
|
+
const __instancePromise = __defaultInstancePromise
|
|
1192
|
+
if (!__instancePromise) {
|
|
1193
|
+
__defaultDisposalStarted = false
|
|
1194
|
+
return
|
|
1195
|
+
}
|
|
1196
|
+
__defaultDisposalStarted = true
|
|
1197
|
+
const __disposePromise = (async () => {
|
|
1198
|
+
let __instance
|
|
1199
|
+
try {
|
|
1200
|
+
__instance = await __instancePromise
|
|
1201
|
+
} catch (error) {
|
|
1202
|
+
const __managedDestroyer =
|
|
1203
|
+
__defaultManagedDestroyers.get(__instancePromise)
|
|
1204
|
+
if (__managedDestroyer) {
|
|
1205
|
+
__onDestroy?.(__managedDestroyer)
|
|
1206
|
+
}
|
|
1207
|
+
__defaultManagedDestroyers.delete(__instancePromise)
|
|
1208
|
+
throw error
|
|
1209
|
+
}
|
|
1210
|
+
const __managedDestroyer =
|
|
1211
|
+
__defaultManagedDestroyers.get(__instancePromise)
|
|
1212
|
+
if (__managedDestroyer) {
|
|
1213
|
+
__onDestroy?.(__managedDestroyer)
|
|
1214
|
+
}
|
|
1215
|
+
await __instance.dispose()
|
|
1216
|
+
if (__defaultInstancePromise === __instancePromise) {
|
|
1217
|
+
__defaultInstancePromise = undefined
|
|
1218
|
+
__defaultModulePromise = undefined
|
|
1219
|
+
__defaultDisposalStarted = false
|
|
1220
|
+
}
|
|
1221
|
+
__defaultManagedDestroyers.delete(__instancePromise)
|
|
1222
|
+
})()
|
|
1223
|
+
__defaultDisposePromise = __disposePromise
|
|
1224
|
+
try {
|
|
1225
|
+
await __disposePromise
|
|
1226
|
+
} finally {
|
|
1227
|
+
if (__defaultDisposePromise === __disposePromise) {
|
|
1228
|
+
__defaultDisposePromise = undefined
|
|
1229
|
+
}
|
|
1230
|
+
}
|
|
1231
|
+
}
|
|
1232
|
+
|
|
1233
|
+
async function __dispose() {
|
|
1234
|
+
let __defaultDisposeError
|
|
1235
|
+
let __defaultDisposeFailed = false
|
|
1236
|
+
let __attemptedDefaultDestroyer
|
|
1237
|
+
try {
|
|
1238
|
+
await __disposeDefaultInstance((__destroyer) => {
|
|
1239
|
+
__attemptedDefaultDestroyer = __destroyer
|
|
1240
|
+
})
|
|
1241
|
+
} catch (error) {
|
|
1242
|
+
__defaultDisposeError = error
|
|
1243
|
+
__defaultDisposeFailed = true
|
|
1244
|
+
}
|
|
1245
|
+
const __excludedDestroyers = new Set()
|
|
1246
|
+
if (__defaultDisposeFailed && __attemptedDefaultDestroyer) {
|
|
1247
|
+
__excludedDestroyers.add(__attemptedDefaultDestroyer)
|
|
1248
|
+
}
|
|
1249
|
+
try {
|
|
1250
|
+
await __drainManagedEmnapiContexts(__excludedDestroyers)
|
|
1251
|
+
} catch (error) {
|
|
1252
|
+
if (!__defaultDisposeFailed) {
|
|
1253
|
+
throw error
|
|
1254
|
+
}
|
|
1255
|
+
if (error !== __defaultDisposeError) {
|
|
1256
|
+
__attachCleanupError(__defaultDisposeError, error)
|
|
1257
|
+
}
|
|
1258
|
+
}
|
|
1259
|
+
if (__defaultDisposeFailed) {
|
|
1260
|
+
throw __defaultDisposeError
|
|
1261
|
+
}
|
|
1262
|
+
}
|
|
1263
|
+
|
|
1264
|
+
/**
|
|
1265
|
+
* Dispose the singleton created by instantiate(). A later call may create a
|
|
1266
|
+
* fresh instance, including from a different module. This also retries cleanup
|
|
1267
|
+
* retained after a failed initialization rollback.
|
|
1268
|
+
*/
|
|
1269
|
+
export function dispose() {
|
|
1270
|
+
if (__moduleLifecycleDestroyDepth !== 0) {
|
|
1271
|
+
return Promise.reject(__createLifecycleReentryError('dispose'))
|
|
1272
|
+
}
|
|
1273
|
+
if (__moduleDisposePromise) {
|
|
1274
|
+
return __moduleDisposePromise
|
|
1275
|
+
}
|
|
1276
|
+
let __resolveDispose
|
|
1277
|
+
let __rejectDispose
|
|
1278
|
+
const __promise = new Promise((resolve, reject) => {
|
|
1279
|
+
__resolveDispose = resolve
|
|
1280
|
+
__rejectDispose = reject
|
|
1281
|
+
})
|
|
1282
|
+
__moduleDisposePromise = __promise
|
|
1283
|
+
void __dispose().then(__resolveDispose, __rejectDispose)
|
|
1284
|
+
void __promise.then(
|
|
1285
|
+
() => {
|
|
1286
|
+
if (__moduleDisposePromise === __promise) {
|
|
1287
|
+
__moduleDisposePromise = undefined
|
|
1288
|
+
}
|
|
1289
|
+
},
|
|
1290
|
+
() => {
|
|
1291
|
+
if (__moduleDisposePromise === __promise) {
|
|
1292
|
+
__moduleDisposePromise = undefined
|
|
1293
|
+
}
|
|
1294
|
+
},
|
|
1295
|
+
)
|
|
1296
|
+
return __promise
|
|
1297
|
+
}
|
|
110
1298
|
`
|
|
111
1299
|
}
|
|
112
1300
|
|
|
1301
|
+
export const createWasiDeferredBrowserBindingTypeDef = (
|
|
1302
|
+
packageName: string,
|
|
1303
|
+
) => `export type WasiBinding = typeof import('${packageName}')
|
|
1304
|
+
|
|
1305
|
+
export type WasiModuleInput =
|
|
1306
|
+
| WebAssembly.Module
|
|
1307
|
+
| PromiseLike<WebAssembly.Module>
|
|
1308
|
+
|
|
1309
|
+
export interface WasiInstance {
|
|
1310
|
+
readonly exports: WasiBinding
|
|
1311
|
+
dispose(): Promise<void>
|
|
1312
|
+
}
|
|
1313
|
+
|
|
1314
|
+
export function instantiate(wasmInput: WasiModuleInput): Promise<WasiBinding>
|
|
1315
|
+
export function createInstance(wasmInput: WasiModuleInput): Promise<WasiInstance>
|
|
1316
|
+
/** Dispose the singleton and retry retained failed-initialization cleanup. */
|
|
1317
|
+
export function dispose(): Promise<void>
|
|
1318
|
+
`
|
|
1319
|
+
|
|
113
1320
|
export const createWasiBinding = (
|
|
114
1321
|
wasmFileName: string,
|
|
115
1322
|
packageName: string,
|
|
116
1323
|
initialMemory = 4000,
|
|
117
1324
|
maximumMemory = 65536,
|
|
118
|
-
|
|
1325
|
+
threads = true,
|
|
1326
|
+
// `platformArchABI` of the flavor this loader belongs to; the fallback
|
|
1327
|
+
// package (`<packageName>-<platformArchABI>`) must ship the same flavor's
|
|
1328
|
+
// wasm artifact.
|
|
1329
|
+
platformArchABI = 'wasm32-wasi',
|
|
1330
|
+
packageWasmFileName = wasmFileName,
|
|
1331
|
+
) => {
|
|
1332
|
+
const workerImports = threads
|
|
1333
|
+
? `const { Worker } = require('node:worker_threads')
|
|
1334
|
+
`
|
|
1335
|
+
: ''
|
|
1336
|
+
const workerExecArgv = threads
|
|
1337
|
+
? `
|
|
1338
|
+
function __getWasiWorkerExecArgv() {
|
|
1339
|
+
const __workerExecArgv = []
|
|
1340
|
+
for (let __index = 0; __index < process.execArgv.length; __index += 1) {
|
|
1341
|
+
const __arg = process.execArgv[__index]
|
|
1342
|
+
if (
|
|
1343
|
+
__arg === '--input-type' ||
|
|
1344
|
+
__arg === '--eval' ||
|
|
1345
|
+
__arg === '-e' ||
|
|
1346
|
+
__arg === '--print' ||
|
|
1347
|
+
__arg === '-p'
|
|
1348
|
+
) {
|
|
1349
|
+
__index += 1
|
|
1350
|
+
continue
|
|
1351
|
+
}
|
|
1352
|
+
if (
|
|
1353
|
+
__arg.startsWith('--input-type=') ||
|
|
1354
|
+
__arg.startsWith('--eval=') ||
|
|
1355
|
+
__arg.startsWith('--print=')
|
|
1356
|
+
) {
|
|
1357
|
+
continue
|
|
1358
|
+
}
|
|
1359
|
+
__workerExecArgv.push(__arg)
|
|
1360
|
+
}
|
|
1361
|
+
return __workerExecArgv
|
|
1362
|
+
}
|
|
1363
|
+
|
|
1364
|
+
function __isInvalidWasiWorkerExecArgv(errorMessage, argument) {
|
|
1365
|
+
const __equalsIndex = argument.indexOf('=')
|
|
1366
|
+
const __argumentName =
|
|
1367
|
+
__equalsIndex === -1 ? argument : argument.slice(0, __equalsIndex)
|
|
1368
|
+
return (
|
|
1369
|
+
errorMessage.includes(': ' + __argumentName + ',') ||
|
|
1370
|
+
errorMessage.includes(': ' + __argumentName + '=') ||
|
|
1371
|
+
errorMessage.endsWith(': ' + __argumentName) ||
|
|
1372
|
+
errorMessage.includes(', ' + __argumentName + ',') ||
|
|
1373
|
+
errorMessage.includes(', ' + __argumentName + '=') ||
|
|
1374
|
+
errorMessage.endsWith(', ' + __argumentName)
|
|
1375
|
+
)
|
|
1376
|
+
}
|
|
1377
|
+
|
|
1378
|
+
function __removeInvalidWasiWorkerExecArgv(execArgv, error) {
|
|
1379
|
+
if (typeof error.message !== 'string') {
|
|
1380
|
+
return
|
|
1381
|
+
}
|
|
1382
|
+
const __workerExecArgv = []
|
|
1383
|
+
let __removed = false
|
|
1384
|
+
for (let __index = 0; __index < execArgv.length; __index += 1) {
|
|
1385
|
+
const __arg = execArgv[__index]
|
|
1386
|
+
if (
|
|
1387
|
+
__arg.startsWith('-') &&
|
|
1388
|
+
__isInvalidWasiWorkerExecArgv(error.message, __arg)
|
|
1389
|
+
) {
|
|
1390
|
+
__removed = true
|
|
1391
|
+
if (
|
|
1392
|
+
!__arg.includes('=') &&
|
|
1393
|
+
__index + 1 < execArgv.length &&
|
|
1394
|
+
!execArgv[__index + 1].startsWith('-')
|
|
1395
|
+
) {
|
|
1396
|
+
__index += 1
|
|
1397
|
+
}
|
|
1398
|
+
continue
|
|
1399
|
+
}
|
|
1400
|
+
__workerExecArgv.push(__arg)
|
|
1401
|
+
}
|
|
1402
|
+
return __removed ? __workerExecArgv : undefined
|
|
1403
|
+
}
|
|
1404
|
+
|
|
1405
|
+
function __createWasiWorker(filename) {
|
|
1406
|
+
let __workerExecArgv = __getWasiWorkerExecArgv()
|
|
1407
|
+
while (true) {
|
|
1408
|
+
try {
|
|
1409
|
+
return new Worker(filename, {
|
|
1410
|
+
env: process.env,
|
|
1411
|
+
execArgv: __workerExecArgv,
|
|
1412
|
+
})
|
|
1413
|
+
} catch (error) {
|
|
1414
|
+
if (!error || error.code !== 'ERR_WORKER_INVALID_EXEC_ARGV') {
|
|
1415
|
+
throw error
|
|
1416
|
+
}
|
|
1417
|
+
const __nextWorkerExecArgv =
|
|
1418
|
+
__removeInvalidWasiWorkerExecArgv(__workerExecArgv, error)
|
|
1419
|
+
if (!__nextWorkerExecArgv) {
|
|
1420
|
+
throw error
|
|
1421
|
+
}
|
|
1422
|
+
__workerExecArgv = __nextWorkerExecArgv
|
|
1423
|
+
}
|
|
1424
|
+
}
|
|
1425
|
+
}
|
|
1426
|
+
`
|
|
1427
|
+
: ''
|
|
1428
|
+
const workerRuntimeImport = threads
|
|
1429
|
+
? ` createOnMessage: __wasmCreateOnMessageForFsProxy,\n`
|
|
1430
|
+
: ''
|
|
1431
|
+
const memoryName = threads ? '__sharedMemory' : '__wasmMemory'
|
|
1432
|
+
const asyncWorkOptions = threads
|
|
1433
|
+
? ` asyncWorkPoolSize: (function() {
|
|
1434
|
+
const threadsSizeFromEnv = Number(process.env.NAPI_RS_ASYNC_WORK_POOL_SIZE ?? process.env.UV_THREADPOOL_SIZE)
|
|
1435
|
+
// NaN > 0 is false
|
|
1436
|
+
if (threadsSizeFromEnv > 0) {
|
|
1437
|
+
return threadsSizeFromEnv
|
|
1438
|
+
} else {
|
|
1439
|
+
return 4
|
|
1440
|
+
}
|
|
1441
|
+
})(),
|
|
1442
|
+
reuseWorker: true,
|
|
1443
|
+
plugins: [__emnapiAsyncWorkPlugin, __emnapiTSFNPlugin],
|
|
1444
|
+
`
|
|
1445
|
+
: ` asyncWorkPoolSize: 0,
|
|
1446
|
+
plugins: [__emnapiAsyncWorkPlugin, __emnapiTSFNPlugin],
|
|
1447
|
+
`
|
|
1448
|
+
// Every build links a "basic" emnapi archive without the C async-work and
|
|
1449
|
+
// threadsafe-function implementations (the `emnapi-napi-rs(-mt)` archives shipped by the emnapi package), so the
|
|
1450
|
+
// JavaScript implementations must be provided through the emnapi plugins in
|
|
1451
|
+
// both threading modes. Without threads the C code would be unconditional
|
|
1452
|
+
// `napi_generic_failure` stubs; with threads it would shadow the
|
|
1453
|
+
// `@emnapi/core` threaded TSFN/async-work protocol the plugins implement.
|
|
1454
|
+
const emnapiPluginRequire = ` emnapiAsyncWorkPlugin: __emnapiAsyncWorkPlugin,\n emnapiTSFNPlugin: __emnapiTSFNPlugin,\n`
|
|
1455
|
+
const workerOption = threads
|
|
1456
|
+
? ` onCreateWorker() {
|
|
1457
|
+
const worker = __createWasiWorker(__nodePath.join(__dirname, 'wasi-worker.mjs'))
|
|
1458
|
+
__wasiWorkers.add(worker)
|
|
1459
|
+
worker.onmessage = ({ data }) => {
|
|
1460
|
+
__wasmCreateOnMessageForFsProxy(__nodeFs)(data)
|
|
1461
|
+
}
|
|
1462
|
+
|
|
1463
|
+
// The main thread of Node.js waits for all the active handles before exiting.
|
|
1464
|
+
// But Rust threads are never waited without \`thread::join\`.
|
|
1465
|
+
// So here we hack the code of Node.js to prevent the workers from being referenced (active).
|
|
1466
|
+
// According to https://github.com/nodejs/node/blob/19e0d472728c79d418b74bddff588bea70a403d0/lib/internal/worker.js#L415,
|
|
1467
|
+
// a worker is consist of two handles: kPublicPort and kHandle.
|
|
1468
|
+
{
|
|
1469
|
+
const kPublicPort = Object.getOwnPropertySymbols(worker).find(s =>
|
|
1470
|
+
s.toString().includes("kPublicPort")
|
|
1471
|
+
);
|
|
1472
|
+
if (kPublicPort) {
|
|
1473
|
+
worker[kPublicPort].ref = () => {};
|
|
1474
|
+
}
|
|
1475
|
+
|
|
1476
|
+
const kHandle = Object.getOwnPropertySymbols(worker).find(s =>
|
|
1477
|
+
s.toString().includes("kHandle")
|
|
1478
|
+
);
|
|
1479
|
+
if (kHandle) {
|
|
1480
|
+
worker[kHandle].ref = () => {};
|
|
1481
|
+
}
|
|
1482
|
+
|
|
1483
|
+
worker.unref();
|
|
1484
|
+
}
|
|
1485
|
+
return worker
|
|
1486
|
+
},
|
|
1487
|
+
`
|
|
1488
|
+
: ''
|
|
1489
|
+
|
|
1490
|
+
return `/* eslint-disable */
|
|
119
1491
|
/* prettier-ignore */
|
|
120
1492
|
|
|
121
1493
|
/* auto-generated by NAPI-RS */
|
|
@@ -123,13 +1495,15 @@ export const createWasiBinding = (
|
|
|
123
1495
|
const __nodeFs = require('node:fs')
|
|
124
1496
|
const __nodePath = require('node:path')
|
|
125
1497
|
const { WASI: __nodeWASI } = require('node:wasi')
|
|
126
|
-
|
|
1498
|
+
${workerImports}\
|
|
127
1499
|
|
|
128
1500
|
const {
|
|
129
|
-
|
|
130
|
-
|
|
1501
|
+
${emnapiPluginRequire}\
|
|
1502
|
+
${workerRuntimeImport}\
|
|
131
1503
|
instantiateNapiModuleSync: __emnapiInstantiateNapiModuleSync,
|
|
132
1504
|
} = require('@napi-rs/wasm-runtime')
|
|
1505
|
+
const { createContext: __emnapiCreateContext } = require('@emnapi/runtime')
|
|
1506
|
+
${workerExecArgv}\
|
|
133
1507
|
|
|
134
1508
|
const __rootDir = __nodePath.parse(process.cwd()).root
|
|
135
1509
|
|
|
@@ -141,12 +1515,10 @@ const __wasi = new __nodeWASI({
|
|
|
141
1515
|
}
|
|
142
1516
|
})
|
|
143
1517
|
|
|
144
|
-
const
|
|
145
|
-
|
|
146
|
-
const __sharedMemory = new WebAssembly.Memory({
|
|
1518
|
+
const ${memoryName} = new WebAssembly.Memory({
|
|
147
1519
|
initial: ${initialMemory},
|
|
148
1520
|
maximum: ${maximumMemory},
|
|
149
|
-
shared: true
|
|
1521
|
+
${threads ? ' shared: true,\n' : ''}\
|
|
150
1522
|
})
|
|
151
1523
|
|
|
152
1524
|
let __wasmFilePath = __nodePath.join(__dirname, '${wasmFileName}.wasm')
|
|
@@ -155,73 +1527,231 @@ const __wasmDebugFilePath = __nodePath.join(__dirname, '${wasmFileName}.debug.wa
|
|
|
155
1527
|
if (__nodeFs.existsSync(__wasmDebugFilePath)) {
|
|
156
1528
|
__wasmFilePath = __wasmDebugFilePath
|
|
157
1529
|
} else if (!__nodeFs.existsSync(__wasmFilePath)) {
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
1530
|
+
const __wasiPackageEntry = require.resolve('${packageName}-${platformArchABI}')
|
|
1531
|
+
const __packagedWasmFilePath = __nodePath.join(
|
|
1532
|
+
__nodePath.dirname(__wasiPackageEntry),
|
|
1533
|
+
'${packageWasmFileName}.wasm',
|
|
1534
|
+
)
|
|
1535
|
+
if (!__nodeFs.existsSync(__packagedWasmFilePath)) {
|
|
1536
|
+
throw new Error(
|
|
1537
|
+
'${packageName}-${platformArchABI} is installed but is missing ${packageWasmFileName}.wasm.',
|
|
1538
|
+
)
|
|
162
1539
|
}
|
|
1540
|
+
__wasmFilePath = __packagedWasmFilePath
|
|
163
1541
|
}
|
|
164
1542
|
|
|
165
|
-
const
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
const worker = new Worker(__nodePath.join(__dirname, 'wasi-worker.mjs'), {
|
|
180
|
-
env: process.env,
|
|
181
|
-
})
|
|
182
|
-
worker.onmessage = ({ data }) => {
|
|
183
|
-
__wasmCreateOnMessageForFsProxy(__nodeFs)(data)
|
|
1543
|
+
const __wasmFile = __nodeFs.readFileSync(__wasmFilePath)
|
|
1544
|
+
let __emnapiContext
|
|
1545
|
+
${emnapiContextLifecycle}
|
|
1546
|
+
const __wasiRollbackRegistrySymbol = Symbol.for('${WASI_ROLLBACK_REGISTRY_SYMBOL}')
|
|
1547
|
+
const __wasiRollbackRegistryKey =
|
|
1548
|
+
typeof __filename === 'string' ? __filename : __wasmFilePath
|
|
1549
|
+
|
|
1550
|
+
function __getWasiRollbackRegistry() {
|
|
1551
|
+
const existing = process[__wasiRollbackRegistrySymbol]
|
|
1552
|
+
if (existing !== undefined) {
|
|
1553
|
+
if (!(existing instanceof Map)) {
|
|
1554
|
+
throw new TypeError(
|
|
1555
|
+
'The process-wide NAPI-RS WASI rollback registry is invalid',
|
|
1556
|
+
)
|
|
184
1557
|
}
|
|
1558
|
+
return existing
|
|
1559
|
+
}
|
|
1560
|
+
const registry = new Map()
|
|
1561
|
+
Object.defineProperty(process, __wasiRollbackRegistrySymbol, {
|
|
1562
|
+
configurable: false,
|
|
1563
|
+
enumerable: false,
|
|
1564
|
+
value: registry,
|
|
1565
|
+
writable: false,
|
|
1566
|
+
})
|
|
1567
|
+
return registry
|
|
1568
|
+
}
|
|
185
1569
|
|
|
186
|
-
|
|
187
|
-
// But Rust threads are never waited without \`thread::join\`.
|
|
188
|
-
// So here we hack the code of Node.js to prevent the workers from being referenced (active).
|
|
189
|
-
// According to https://github.com/nodejs/node/blob/19e0d472728c79d418b74bddff588bea70a403d0/lib/internal/worker.js#L415,
|
|
190
|
-
// a worker is consist of two handles: kPublicPort and kHandle.
|
|
191
|
-
{
|
|
192
|
-
const kPublicPort = Object.getOwnPropertySymbols(worker).find(s =>
|
|
193
|
-
s.toString().includes("kPublicPort")
|
|
194
|
-
);
|
|
195
|
-
if (kPublicPort) {
|
|
196
|
-
worker[kPublicPort].ref = () => {};
|
|
197
|
-
}
|
|
1570
|
+
const __wasiRollbackRegistry = __getWasiRollbackRegistry()
|
|
198
1571
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
if (
|
|
203
|
-
|
|
1572
|
+
function __completeWasiInitializationRollback(record, cleanupErrors) {
|
|
1573
|
+
try {
|
|
1574
|
+
if (cleanupErrors.length === 0) {
|
|
1575
|
+
if (
|
|
1576
|
+
__wasiRollbackRegistry.get(__wasiRollbackRegistryKey) === record
|
|
1577
|
+
) {
|
|
1578
|
+
__wasiRollbackRegistry.delete(__wasiRollbackRegistryKey)
|
|
204
1579
|
}
|
|
1580
|
+
return
|
|
1581
|
+
}
|
|
1582
|
+
record.error = __attachCleanupErrors(record.error, cleanupErrors)
|
|
1583
|
+
} catch (cleanupError) {
|
|
1584
|
+
try {
|
|
1585
|
+
record.error = __createCleanupError(
|
|
1586
|
+
[record.error, cleanupError],
|
|
1587
|
+
'WASI binding initialization and cleanup failed',
|
|
1588
|
+
)
|
|
1589
|
+
} catch {}
|
|
1590
|
+
} finally {
|
|
1591
|
+
record.active = false
|
|
1592
|
+
record.promise = undefined
|
|
1593
|
+
}
|
|
1594
|
+
}
|
|
205
1595
|
|
|
206
|
-
|
|
1596
|
+
function __runWasiInitializationRollback(record) {
|
|
1597
|
+
if (record.active) {
|
|
1598
|
+
return
|
|
1599
|
+
}
|
|
1600
|
+
record.active = true
|
|
1601
|
+
|
|
1602
|
+
let rollbackResult
|
|
1603
|
+
try {
|
|
1604
|
+
rollbackResult = record.rollback()
|
|
1605
|
+
} catch (cleanupError) {
|
|
1606
|
+
__completeWasiInitializationRollback(record, [cleanupError])
|
|
1607
|
+
return
|
|
1608
|
+
}
|
|
1609
|
+
|
|
1610
|
+
if (!__isThenable(rollbackResult)) {
|
|
1611
|
+
__completeWasiInitializationRollback(record, rollbackResult)
|
|
1612
|
+
return
|
|
1613
|
+
}
|
|
1614
|
+
|
|
1615
|
+
record.promise = Promise.resolve(rollbackResult).then(
|
|
1616
|
+
(cleanupErrors) => {
|
|
1617
|
+
__completeWasiInitializationRollback(record, cleanupErrors)
|
|
1618
|
+
},
|
|
1619
|
+
(cleanupError) => {
|
|
1620
|
+
__completeWasiInitializationRollback(record, [cleanupError])
|
|
1621
|
+
},
|
|
1622
|
+
)
|
|
1623
|
+
}
|
|
1624
|
+
|
|
1625
|
+
const __pendingWasiRollback = __wasiRollbackRegistry.get(
|
|
1626
|
+
__wasiRollbackRegistryKey,
|
|
1627
|
+
)
|
|
1628
|
+
if (__pendingWasiRollback !== undefined) {
|
|
1629
|
+
__runWasiInitializationRollback(__pendingWasiRollback)
|
|
1630
|
+
throw __pendingWasiRollback.error
|
|
1631
|
+
}
|
|
1632
|
+
|
|
1633
|
+
let __wasiModule
|
|
1634
|
+
let __napiModule
|
|
1635
|
+
let __wasiExitListenerRegistered = false
|
|
1636
|
+
|
|
1637
|
+
function __removeWasiExitListener() {
|
|
1638
|
+
if (
|
|
1639
|
+
__wasiExitListenerRegistered &&
|
|
1640
|
+
typeof process.removeListener === 'function'
|
|
1641
|
+
) {
|
|
1642
|
+
process.removeListener('exit', __disposeWasiBindingAtExit)
|
|
1643
|
+
}
|
|
1644
|
+
__wasiExitListenerRegistered = false
|
|
1645
|
+
}
|
|
1646
|
+
|
|
1647
|
+
function __disposeWasiBindingAtExit() {
|
|
1648
|
+
__wasiExitListenerRegistered = false
|
|
1649
|
+
try {
|
|
1650
|
+
const result = __disposeWasiBinding()
|
|
1651
|
+
if (__isThenable(result)) {
|
|
1652
|
+
void Promise.resolve(result).catch(() => {})
|
|
207
1653
|
}
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
1654
|
+
} catch {}
|
|
1655
|
+
}
|
|
1656
|
+
|
|
1657
|
+
function __registerWasiExitListener() {
|
|
1658
|
+
if (
|
|
1659
|
+
!__wasiExitListenerRegistered &&
|
|
1660
|
+
typeof process.once === 'function'
|
|
1661
|
+
) {
|
|
1662
|
+
process.once('exit', __disposeWasiBindingAtExit)
|
|
1663
|
+
__wasiExitListenerRegistered = true
|
|
1664
|
+
}
|
|
1665
|
+
}
|
|
1666
|
+
|
|
1667
|
+
__completeWasiDisposal = __removeWasiExitListener
|
|
1668
|
+
|
|
1669
|
+
function __captureEmnapiAutoDestroyListener() {
|
|
1670
|
+
if (
|
|
1671
|
+
typeof process.prependListener !== 'function' ||
|
|
1672
|
+
typeof process.removeListener !== 'function'
|
|
1673
|
+
) {
|
|
1674
|
+
return
|
|
1675
|
+
}
|
|
1676
|
+
let __autoDestroyListener
|
|
1677
|
+
const __captureListener = (__event, __listener) => {
|
|
1678
|
+
if (__event === 'beforeExit' && __autoDestroyListener === undefined) {
|
|
1679
|
+
__autoDestroyListener = __listener
|
|
224
1680
|
}
|
|
225
|
-
}
|
|
226
|
-
|
|
1681
|
+
}
|
|
1682
|
+
try {
|
|
1683
|
+
// Run before existing newListener hooks so a hook that registers its own
|
|
1684
|
+
// beforeExit listener cannot be mistaken for emnapi's registration.
|
|
1685
|
+
process.prependListener('newListener', __captureListener)
|
|
1686
|
+
} catch {
|
|
1687
|
+
return
|
|
1688
|
+
}
|
|
1689
|
+
return () => {
|
|
1690
|
+
try {
|
|
1691
|
+
process.removeListener('newListener', __captureListener)
|
|
1692
|
+
} catch {}
|
|
1693
|
+
if (__autoDestroyListener !== undefined) {
|
|
1694
|
+
try {
|
|
1695
|
+
process.removeListener('beforeExit', __autoDestroyListener)
|
|
1696
|
+
} catch {}
|
|
1697
|
+
}
|
|
1698
|
+
}
|
|
1699
|
+
}
|
|
1700
|
+
|
|
1701
|
+
try {
|
|
1702
|
+
const __finishAutoDestroyCapture = __captureEmnapiAutoDestroyListener()
|
|
1703
|
+
try {
|
|
1704
|
+
__emnapiContext = __emnapiCreateContext({ autoDestroy: false })
|
|
1705
|
+
// emnapi 2.x still registers an unconditional once-listener for
|
|
1706
|
+
// beforeExit that auto-destroys the context, and suppressDestroy() only
|
|
1707
|
+
// neutralizes its callback without removing it. This loader owns cleanup
|
|
1708
|
+
// through its 'exit' listener, so emnapi's listener is captured and
|
|
1709
|
+
// removed; suppressDestroy() remains the safety net when removal fails.
|
|
1710
|
+
__emnapiContext.suppressDestroy()
|
|
1711
|
+
} finally {
|
|
1712
|
+
// Remove only the exact emnapi callback captured above.
|
|
1713
|
+
__finishAutoDestroyCapture?.()
|
|
1714
|
+
}
|
|
1715
|
+
|
|
1716
|
+
;({
|
|
1717
|
+
instance: __napiInstance,
|
|
1718
|
+
module: __wasiModule,
|
|
1719
|
+
napiModule: __napiModule,
|
|
1720
|
+
} = __emnapiInstantiateNapiModuleSync(__wasmFile, {
|
|
1721
|
+
context: __emnapiContext,
|
|
1722
|
+
${asyncWorkOptions}\
|
|
1723
|
+
wasi: __wasi,
|
|
1724
|
+
${workerOption}\
|
|
1725
|
+
overwriteImports(importObject) {
|
|
1726
|
+
importObject.env = {
|
|
1727
|
+
...importObject.env,
|
|
1728
|
+
...importObject.napi,
|
|
1729
|
+
...importObject.emnapi,
|
|
1730
|
+
memory: ${memoryName},
|
|
1731
|
+
}
|
|
1732
|
+
return importObject
|
|
1733
|
+
},
|
|
1734
|
+
beforeInit({ instance }) {
|
|
1735
|
+
__napiInstance = instance
|
|
1736
|
+
for (const name of Object.keys(instance.exports)) {
|
|
1737
|
+
if (name.startsWith('__napi_register__')) {
|
|
1738
|
+
instance.exports[name]()
|
|
1739
|
+
}
|
|
1740
|
+
}
|
|
1741
|
+
},
|
|
1742
|
+
}))
|
|
1743
|
+
__publishWasiDispose(__napiModule.exports)
|
|
1744
|
+
__registerWasiExitListener()
|
|
1745
|
+
} catch (error) {
|
|
1746
|
+
const rollback = {
|
|
1747
|
+
active: false,
|
|
1748
|
+
error,
|
|
1749
|
+
promise: undefined,
|
|
1750
|
+
rollback: __rollbackWasiInitialization,
|
|
1751
|
+
}
|
|
1752
|
+
__wasiRollbackRegistry.set(__wasiRollbackRegistryKey, rollback)
|
|
1753
|
+
__runWasiInitializationRollback(rollback)
|
|
1754
|
+
throw rollback.error
|
|
1755
|
+
}
|
|
227
1756
|
`
|
|
1757
|
+
}
|