@napi-rs/cli 3.8.3 → 3.8.4
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 +7 -4
- package/dist/cli.js +501 -15
- package/dist/index.cjs +501 -15
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +501 -15
- package/package.json +1 -1
- package/src/api/__tests__/__snapshots__/templates.spec.ts.md +768 -9
- package/src/api/__tests__/__snapshots__/templates.spec.ts.snap +0 -0
- package/src/api/__tests__/templates.spec.ts +85 -1
- package/src/api/templates/load-wasi-template.ts +499 -13
|
Binary file
|
|
@@ -2,7 +2,11 @@ import ava, { type ExecutionContext } from 'ava'
|
|
|
2
2
|
import { parseSync } from 'oxc-parser'
|
|
3
3
|
|
|
4
4
|
import { createCjsBinding, createEsmBinding } from '../templates/js-binding.js'
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
createWasiBinding,
|
|
7
|
+
createWasiBrowserBinding,
|
|
8
|
+
createWasiDeferredBrowserBinding,
|
|
9
|
+
} from '../templates/load-wasi-template.js'
|
|
6
10
|
import { createWasiBrowserWorkerBinding } from '../templates/wasi-worker-template.js'
|
|
7
11
|
|
|
8
12
|
const test = ava
|
|
@@ -200,6 +204,86 @@ for (const { name, code } of cjsBindingCases) {
|
|
|
200
204
|
})
|
|
201
205
|
}
|
|
202
206
|
|
|
207
|
+
// `napi_prepare_wasm_env_cleanup` only *queues* the promise settlements of the
|
|
208
|
+
// tasks it cancels: `napi_call_threadsafe_function` appends to the
|
|
209
|
+
// threadsafe-function queue, and @emnapi/core dispatches that queue from a
|
|
210
|
+
// macrotask two coalescing turns later. `Context.destroy()` then drains the
|
|
211
|
+
// queue with a null env and discards it. Measured against @emnapi/core
|
|
212
|
+
// 2.0.0-alpha.3: zero microtask checkpoints ever deliver the settlement, and it
|
|
213
|
+
// takes exactly two macrotask turns.
|
|
214
|
+
//
|
|
215
|
+
// So a loader that emits the barrier and `destroy()` back to back strands
|
|
216
|
+
// exactly the promises the barrier exists to settle, and it does so silently.
|
|
217
|
+
// `examples/custom-async-runtime` covers the hand-written loader and the two
|
|
218
|
+
// emitted flavors it builds (node cjs threadless, deferred/workerd)
|
|
219
|
+
// behaviorally; the other flavors are never instantiated by any test, so assert
|
|
220
|
+
// the shape here as well.
|
|
221
|
+
const wasiLoaderCases: Array<{ name: string; code: string }> = [
|
|
222
|
+
{ name: 'node cjs', code: createWasiBinding('test', '@scope/test') },
|
|
223
|
+
{
|
|
224
|
+
name: 'node cjs threadless',
|
|
225
|
+
code: createWasiBinding('test', '@scope/test', 4000, 65536, false),
|
|
226
|
+
},
|
|
227
|
+
{ name: 'browser esm', code: createWasiBrowserBinding('test') },
|
|
228
|
+
{ name: 'deferred/workerd', code: createWasiDeferredBrowserBinding('test') },
|
|
229
|
+
]
|
|
230
|
+
|
|
231
|
+
for (const { name, code } of wasiLoaderCases) {
|
|
232
|
+
test(`WASI loader waits for queued settlements before destroy: ${name}`, (t) => {
|
|
233
|
+
t.true(
|
|
234
|
+
code.includes('napi_prepare_wasm_env_cleanup'),
|
|
235
|
+
'loader must run the pre-teardown barrier',
|
|
236
|
+
)
|
|
237
|
+
t.true(
|
|
238
|
+
code.includes('napi_wasm_env_cleanup_pending'),
|
|
239
|
+
'loader must poll napi_wasm_env_cleanup_pending; without it the barrier queues settlements that Context.destroy() then discards',
|
|
240
|
+
)
|
|
241
|
+
t.true(
|
|
242
|
+
code.includes('__drainWasmEnvCleanup'),
|
|
243
|
+
'loader must call the settlement drain on its disposal path',
|
|
244
|
+
)
|
|
245
|
+
t.true(
|
|
246
|
+
code.includes('__scheduleMacrotask'),
|
|
247
|
+
'the drain must yield real macrotask turns; microtask checkpoints never let the emnapi dispatch run',
|
|
248
|
+
)
|
|
249
|
+
// Initialization rollback is the same hazard, one step earlier. Registration
|
|
250
|
+
// runs with a live environment, so a module-init hook can start a task and
|
|
251
|
+
// *then* return an error; the barrier cancels the task and queues its
|
|
252
|
+
// rejection, and a rollback that destroys the context in the same turn
|
|
253
|
+
// discards it — stranding a promise that already escaped into JavaScript.
|
|
254
|
+
t.true(
|
|
255
|
+
initializationRollbackBody(code).includes(
|
|
256
|
+
DRAIN_CALL_BY_ROLLBACK_FLAVOR[
|
|
257
|
+
code.includes(EAGER_ROLLBACK_SIGNATURE) ? 'eager' : 'deferred'
|
|
258
|
+
],
|
|
259
|
+
),
|
|
260
|
+
'initialization rollback must drain queued settlements before destroying the context',
|
|
261
|
+
)
|
|
262
|
+
})
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
const EAGER_ROLLBACK_SIGNATURE = 'function __rollbackWasiInitialization() {'
|
|
266
|
+
const DEFERRED_ROLLBACK_SIGNATURE = "__lifecycleState = 'failed'"
|
|
267
|
+
const DRAIN_CALL_BY_ROLLBACK_FLAVOR = {
|
|
268
|
+
eager: '__drainWasmEnvCleanup',
|
|
269
|
+
deferred: '__prepareForDisposal',
|
|
270
|
+
} as const
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* The body of a loader's initialization-failure path: `__rollbackWasiInitialization`
|
|
274
|
+
* for the eager loaders, `__createInstance`'s catch for the deferred one.
|
|
275
|
+
* Sliced rather than searched whole-file, so a drain that only runs on the
|
|
276
|
+
* ordinary disposal path cannot satisfy the assertion.
|
|
277
|
+
*/
|
|
278
|
+
function initializationRollbackBody(code: string): string {
|
|
279
|
+
const eagerStart = code.indexOf(EAGER_ROLLBACK_SIGNATURE)
|
|
280
|
+
if (eagerStart !== -1) {
|
|
281
|
+
return code.slice(eagerStart, code.indexOf('\n}', eagerStart))
|
|
282
|
+
}
|
|
283
|
+
const deferredStart = code.indexOf(DEFERRED_ROLLBACK_SIGNATURE)
|
|
284
|
+
return code.slice(deferredStart, code.indexOf('throw error', deferredStart))
|
|
285
|
+
}
|
|
286
|
+
|
|
203
287
|
test('createEsmBinding is Node 12 compatible', (t) => {
|
|
204
288
|
const code = createEsmBinding('test', '@scope/test', ['sum'])
|
|
205
289
|
assertValidJS(t, code, 'esm')
|