@napi-rs/cli 3.9.0 → 3.10.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.
Files changed (39) hide show
  1. package/README.md +17 -4
  2. package/dist/cli.js +10359 -8729
  3. package/dist/index.cjs +10381 -8751
  4. package/dist/index.d.cts +83 -16
  5. package/dist/index.d.ts +83 -16
  6. package/dist/index.js +10359 -8729
  7. package/docs/wasi.md +318 -4
  8. package/package.json +5 -6
  9. package/src/api/__tests__/__snapshots__/templates.spec.ts.md +4003 -53
  10. package/src/api/__tests__/__snapshots__/templates.spec.ts.snap +0 -0
  11. package/src/api/__tests__/build-regressions.spec.ts +210 -3
  12. package/src/api/__tests__/build.spec.ts +2333 -3
  13. package/src/api/__tests__/create-npm-dirs.spec.ts +105 -3
  14. package/src/api/__tests__/pre-publish.spec.ts +153 -1
  15. package/src/api/__tests__/templates.spec.ts +1309 -1
  16. package/src/api/build.ts +756 -30
  17. package/src/api/create-npm-dirs.ts +23 -10
  18. package/src/api/new.ts +13 -18
  19. package/src/api/pre-publish.ts +34 -11
  20. package/src/api/rename.ts +10 -21
  21. package/src/api/templates/binding-target.ts +176 -0
  22. package/src/api/templates/index.ts +1 -0
  23. package/src/api/templates/js-binding.ts +54 -10
  24. package/src/api/templates/load-wasi-template.ts +661 -58
  25. package/src/api/templates/wasi-worker-template.ts +36 -31
  26. package/src/commands/build.ts +1 -1
  27. package/src/utils/__tests__/__snapshots__/typegen.spec.ts.md +18 -28
  28. package/src/utils/__tests__/__snapshots__/typegen.spec.ts.snap +0 -0
  29. package/src/utils/__tests__/misc.spec.ts +4 -0
  30. package/src/utils/__tests__/reconciliation.spec.ts +676 -0
  31. package/src/utils/__tests__/serialize.spec.ts +55 -0
  32. package/src/utils/__tests__/target.spec.ts +221 -0
  33. package/src/utils/__tests__/typegen.spec.ts +115 -0
  34. package/src/utils/config.ts +50 -0
  35. package/src/utils/index.ts +1 -0
  36. package/src/utils/misc.ts +351 -79
  37. package/src/utils/serialize.ts +47 -0
  38. package/src/utils/target.ts +150 -1
  39. package/src/utils/typegen.ts +608 -42
@@ -18,6 +18,55 @@ Generated by [AVA](https://avajs.dev).
18
18
  import { createContext as __emnapiCreateContext } from '@emnapi/runtime'␊
19
19
  ␊
20
20
  ␊
21
+ export const __napiBindingTarget = 'wasm32-wasi'␊
22
+ function __napiStampBindingTarget(exportsObject, target) {␊
23
+ if (␊
24
+ Object.prototype.hasOwnProperty.call(exportsObject, '__napiBindingTarget')␊
25
+ ) {␊
26
+ if (exportsObject.__napiBindingTarget === target) {␊
27
+ // Already ours: the root entry aliases the object it loaded, so a WASI␊
28
+ // fallback candidate — or a \`NAPI_RS_NATIVE_LIBRARY_PATH\` override that␊
29
+ // is a generated loader — arrives already stamped with this same value.␊
30
+ return target␊
31
+ }␊
32
+ const error = new Error(␊
33
+ '\`__napiBindingTarget\` is reserved by the generated binding loader, but the loaded binding already exports it. Rename the export, e.g. #[napi(js_name = "...")].',␊
34
+ )␊
35
+ error.code = 'ERR_NAPI_BINDING_TARGET_CONFLICT'␊
36
+ throw error␊
37
+ }␊
38
+ if (!Object.isExtensible(exportsObject)) {␊
39
+ // A \`#[napi(module_exports)]\` hook may seal or freeze this object␊
40
+ // (\`Object::seal\` / \`Object::freeze\`). Reporting the artifact is metadata,␊
41
+ // never a reason to fail an otherwise successful load, so the stamp is␊
42
+ // skipped. What a consumer still sees then follows the entry point: the␊
43
+ // browser and deferred loaders declare \`__napiBindingTarget\` at module␊
44
+ // level and go on reporting it, while the CommonJS entries hand back this␊
45
+ // very object as \`module.exports\`, so there the value is absent.␊
46
+ return target␊
47
+ }␊
48
+ try {␊
49
+ // [[Define]], not [[Set]]: an ordinary assignment walks the prototype␊
50
+ // chain, so an inherited accessor could swallow the value or throw and␊
51
+ // fail an otherwise successful load. The descriptor is what a successful␊
52
+ // assignment would have produced.␊
53
+ Object.defineProperty(exportsObject, '__napiBindingTarget', {␊
54
+ configurable: true,␊
55
+ enumerable: true,␊
56
+ value: target,␊
57
+ writable: true,␊
58
+ })␊
59
+ } catch {␊
60
+ // Same rule as the non-extensible skip above: reporting the artifact is␊
61
+ // metadata, never a reason to fail an otherwise successful load. An exotic␊
62
+ // object (a Proxy whose defineProperty trap refuses) is skipped, not␊
63
+ // thrown over.␊
64
+ }␊
65
+ // The CommonJS loaders assign this return value so \`cjs-module-lexer\` — and␊
66
+ // therefore Node's CJS -> ESM named export detection — can see␊
67
+ // \`__napiBindingTarget\` statically.␊
68
+ return target␊
69
+ }␊
21
70
  ␊
22
71
  const __wasi = new __WASI({␊
23
72
  version: 'preview1',␊
@@ -56,16 +105,17 @@ Generated by [AVA](https://avajs.dev).
56
105
  let __emnapiContextDestroyed = false␊
57
106
  let __emnapiContextDestroyPromise␊
58
107
  let __emnapiWasmEnvCleanupPrepared = false␊
108
+ let __emnapiWasmEnvCleanupPreparing = false␊
59
109
  let __emnapiWasmEnvCleanupRan = false␊
60
110
  let __emnapiWasmEnvCleanupDrained = false␊
61
111
  let __emnapiWasmEnvCleanupDrainPromise␊
62
112
  let __wasiDisposed = false␊
63
113
  let __wasiDisposePromise␊
64
- let __completeWasiDisposal = function() {}␊
114
+ let __completeWasiDisposal = function () {}␊
65
115
  // Overridden by loader flavors that have a last-resort reclaim for a rollback␊
66
116
  // that stopped short of destroying the context. See␊
67
117
  // \`__rollbackWasiInitialization\`.␊
68
- let __retainWasiRollbackForRetry = function() {}␊
118
+ let __retainWasiRollbackForRetry = function () {}␊
69
119
  ␊
70
120
  function __isThenable(value) {␊
71
121
  return (␊
@@ -129,13 +179,58 @@ Generated by [AVA](https://avajs.dev).
129
179
  return aggregate␊
130
180
  }␊
131
181
  ␊
182
+ function __wrapEmnapiContextDestroyForSettlement(␊
183
+ context,␊
184
+ prepareEnvCleanup,␊
185
+ isPreparingEnvCleanup,␊
186
+ ) {␊
187
+ let destroy␊
188
+ try {␊
189
+ destroy = context.destroy␊
190
+ } catch {␊
191
+ return context␊
192
+ }␊
193
+ if (typeof destroy !== 'function') {␊
194
+ return context␊
195
+ }␊
196
+ try {␊
197
+ Object.defineProperty(context, 'destroy', {␊
198
+ configurable: true,␊
199
+ enumerable: false,␊
200
+ writable: true,␊
201
+ value: function () {␊
202
+ // Reentered from a promise hook that fired inside the barrier: the␊
203
+ // frame running it destroys as soon as it returns.␊
204
+ if (isPreparingEnvCleanup?.()) {␊
205
+ return␊
206
+ }␊
207
+ prepareEnvCleanup?.()␊
208
+ return Reflect.apply(destroy, this, arguments)␊
209
+ },␊
210
+ })␊
211
+ } catch {}␊
212
+ return context␊
213
+ }␊
214
+ ␊
215
+ function __isPreparingWasmEnvCleanup() {␊
216
+ return __emnapiWasmEnvCleanupPreparing␊
217
+ }␊
218
+ ␊
132
219
  function __prepareWasmEnvCleanup() {␊
133
- if (__emnapiWasmEnvCleanupPrepared) {␊
220
+ if (__emnapiWasmEnvCleanupPrepared || __emnapiWasmEnvCleanupPreparing) {␊
134
221
  return␊
135
222
  }␊
136
223
  const prepare = __napiInstance?.exports?.napi_prepare_wasm_env_cleanup␊
137
224
  if (typeof prepare === 'function') {␊
138
- prepare()␊
225
+ // The addon settles the promises it cancels synchronously, under a␊
226
+ // non-reentrant lifecycle mutex: anything a promise hook calls from in␊
227
+ // here must not reach this export again.␊
228
+ __emnapiWasmEnvCleanupPreparing = true␊
229
+ try {␊
230
+ prepare()␊
231
+ } finally {␊
232
+ __emnapiWasmEnvCleanupPreparing = false␊
233
+ }␊
139
234
  __emnapiWasmEnvCleanupRan = true␊
140
235
  }␊
141
236
  __emnapiWasmEnvCleanupPrepared = true␊
@@ -565,7 +660,11 @@ Generated by [AVA](https://avajs.dev).
565
660
  let __napiModule␊
566
661
  ␊
567
662
  try {␊
568
- __emnapiContext = __emnapiCreateContext({ autoDestroy: false })␊
663
+ __emnapiContext = __wrapEmnapiContextDestroyForSettlement(␊
664
+ __emnapiCreateContext({ autoDestroy: false }),␊
665
+ __prepareWasmEnvCleanup,␊
666
+ __isPreparingWasmEnvCleanup,␊
667
+ )␊
569
668
  __emnapiContext.suppressDestroy()␊
570
669
  ␊
571
670
  ;({␊
@@ -606,6 +705,12 @@ Generated by [AVA](https://avajs.dev).
606
705
  },␊
607
706
  }))␊
608
707
  __publishWasiDispose(__napiModule.exports)␊
708
+ // The default export hands out this object; a named module export does not␊
709
+ // travel with it, so carry the marker on the binding itself too. After the␊
710
+ // host install, which hands the same object to addon-provided registration␊
711
+ // functions that may put anything on it, and inside this \`try\`, so a claimed␊
712
+ // name fails the load through the rollback below rather than past it.␊
713
+ __napiStampBindingTarget(__napiModule.exports, __napiBindingTarget)␊
609
714
  } catch (error) {␊
610
715
  const cleanupErrors = await __rollbackWasiInitialization()␊
611
716
  throw __attachCleanupErrors(error, cleanupErrors)␊
@@ -626,6 +731,55 @@ Generated by [AVA](https://avajs.dev).
626
731
  import { createContext as __emnapiCreateContext } from '@emnapi/runtime'␊
627
732
  ␊
628
733
  ␊
734
+ export const __napiBindingTarget = 'wasm32-wasi'␊
735
+ function __napiStampBindingTarget(exportsObject, target) {␊
736
+ if (␊
737
+ Object.prototype.hasOwnProperty.call(exportsObject, '__napiBindingTarget')␊
738
+ ) {␊
739
+ if (exportsObject.__napiBindingTarget === target) {␊
740
+ // Already ours: the root entry aliases the object it loaded, so a WASI␊
741
+ // fallback candidate — or a \`NAPI_RS_NATIVE_LIBRARY_PATH\` override that␊
742
+ // is a generated loader — arrives already stamped with this same value.␊
743
+ return target␊
744
+ }␊
745
+ const error = new Error(␊
746
+ '\`__napiBindingTarget\` is reserved by the generated binding loader, but the loaded binding already exports it. Rename the export, e.g. #[napi(js_name = "...")].',␊
747
+ )␊
748
+ error.code = 'ERR_NAPI_BINDING_TARGET_CONFLICT'␊
749
+ throw error␊
750
+ }␊
751
+ if (!Object.isExtensible(exportsObject)) {␊
752
+ // A \`#[napi(module_exports)]\` hook may seal or freeze this object␊
753
+ // (\`Object::seal\` / \`Object::freeze\`). Reporting the artifact is metadata,␊
754
+ // never a reason to fail an otherwise successful load, so the stamp is␊
755
+ // skipped. What a consumer still sees then follows the entry point: the␊
756
+ // browser and deferred loaders declare \`__napiBindingTarget\` at module␊
757
+ // level and go on reporting it, while the CommonJS entries hand back this␊
758
+ // very object as \`module.exports\`, so there the value is absent.␊
759
+ return target␊
760
+ }␊
761
+ try {␊
762
+ // [[Define]], not [[Set]]: an ordinary assignment walks the prototype␊
763
+ // chain, so an inherited accessor could swallow the value or throw and␊
764
+ // fail an otherwise successful load. The descriptor is what a successful␊
765
+ // assignment would have produced.␊
766
+ Object.defineProperty(exportsObject, '__napiBindingTarget', {␊
767
+ configurable: true,␊
768
+ enumerable: true,␊
769
+ value: target,␊
770
+ writable: true,␊
771
+ })␊
772
+ } catch {␊
773
+ // Same rule as the non-extensible skip above: reporting the artifact is␊
774
+ // metadata, never a reason to fail an otherwise successful load. An exotic␊
775
+ // object (a Proxy whose defineProperty trap refuses) is skipped, not␊
776
+ // thrown over.␊
777
+ }␊
778
+ // The CommonJS loaders assign this return value so \`cjs-module-lexer\` — and␊
779
+ // therefore Node's CJS -> ESM named export detection — can see␊
780
+ // \`__napiBindingTarget\` statically.␊
781
+ return target␊
782
+ }␊
629
783
  ␊
630
784
  const __wasi = new __WASI({␊
631
785
  version: 'preview1',␊
@@ -664,16 +818,17 @@ Generated by [AVA](https://avajs.dev).
664
818
  let __emnapiContextDestroyed = false␊
665
819
  let __emnapiContextDestroyPromise␊
666
820
  let __emnapiWasmEnvCleanupPrepared = false␊
821
+ let __emnapiWasmEnvCleanupPreparing = false␊
667
822
  let __emnapiWasmEnvCleanupRan = false␊
668
823
  let __emnapiWasmEnvCleanupDrained = false␊
669
824
  let __emnapiWasmEnvCleanupDrainPromise␊
670
825
  let __wasiDisposed = false␊
671
826
  let __wasiDisposePromise␊
672
- let __completeWasiDisposal = function() {}␊
827
+ let __completeWasiDisposal = function () {}␊
673
828
  // Overridden by loader flavors that have a last-resort reclaim for a rollback␊
674
829
  // that stopped short of destroying the context. See␊
675
830
  // \`__rollbackWasiInitialization\`.␊
676
- let __retainWasiRollbackForRetry = function() {}␊
831
+ let __retainWasiRollbackForRetry = function () {}␊
677
832
  ␊
678
833
  function __isThenable(value) {␊
679
834
  return (␊
@@ -737,13 +892,58 @@ Generated by [AVA](https://avajs.dev).
737
892
  return aggregate␊
738
893
  }␊
739
894
  ␊
895
+ function __wrapEmnapiContextDestroyForSettlement(␊
896
+ context,␊
897
+ prepareEnvCleanup,␊
898
+ isPreparingEnvCleanup,␊
899
+ ) {␊
900
+ let destroy␊
901
+ try {␊
902
+ destroy = context.destroy␊
903
+ } catch {␊
904
+ return context␊
905
+ }␊
906
+ if (typeof destroy !== 'function') {␊
907
+ return context␊
908
+ }␊
909
+ try {␊
910
+ Object.defineProperty(context, 'destroy', {␊
911
+ configurable: true,␊
912
+ enumerable: false,␊
913
+ writable: true,␊
914
+ value: function () {␊
915
+ // Reentered from a promise hook that fired inside the barrier: the␊
916
+ // frame running it destroys as soon as it returns.␊
917
+ if (isPreparingEnvCleanup?.()) {␊
918
+ return␊
919
+ }␊
920
+ prepareEnvCleanup?.()␊
921
+ return Reflect.apply(destroy, this, arguments)␊
922
+ },␊
923
+ })␊
924
+ } catch {}␊
925
+ return context␊
926
+ }␊
927
+ ␊
928
+ function __isPreparingWasmEnvCleanup() {␊
929
+ return __emnapiWasmEnvCleanupPreparing␊
930
+ }␊
931
+ ␊
740
932
  function __prepareWasmEnvCleanup() {␊
741
- if (__emnapiWasmEnvCleanupPrepared) {␊
933
+ if (__emnapiWasmEnvCleanupPrepared || __emnapiWasmEnvCleanupPreparing) {␊
742
934
  return␊
743
935
  }␊
744
936
  const prepare = __napiInstance?.exports?.napi_prepare_wasm_env_cleanup␊
745
937
  if (typeof prepare === 'function') {␊
746
- prepare()␊
938
+ // The addon settles the promises it cancels synchronously, under a␊
939
+ // non-reentrant lifecycle mutex: anything a promise hook calls from in␊
940
+ // here must not reach this export again.␊
941
+ __emnapiWasmEnvCleanupPreparing = true␊
942
+ try {␊
943
+ prepare()␊
944
+ } finally {␊
945
+ __emnapiWasmEnvCleanupPreparing = false␊
946
+ }␊
747
947
  __emnapiWasmEnvCleanupRan = true␊
748
948
  }␊
749
949
  __emnapiWasmEnvCleanupPrepared = true␊
@@ -1173,7 +1373,11 @@ Generated by [AVA](https://avajs.dev).
1173
1373
  let __napiModule␊
1174
1374
  ␊
1175
1375
  try {␊
1176
- __emnapiContext = __emnapiCreateContext({ autoDestroy: false })␊
1376
+ __emnapiContext = __wrapEmnapiContextDestroyForSettlement(␊
1377
+ __emnapiCreateContext({ autoDestroy: false }),␊
1378
+ __prepareWasmEnvCleanup,␊
1379
+ __isPreparingWasmEnvCleanup,␊
1380
+ )␊
1177
1381
  __emnapiContext.suppressDestroy()␊
1178
1382
  ␊
1179
1383
  ;({␊
@@ -1227,6 +1431,12 @@ Generated by [AVA](https://avajs.dev).
1227
1431
  },␊
1228
1432
  }))␊
1229
1433
  __publishWasiDispose(__napiModule.exports)␊
1434
+ // The default export hands out this object; a named module export does not␊
1435
+ // travel with it, so carry the marker on the binding itself too. After the␊
1436
+ // host install, which hands the same object to addon-provided registration␊
1437
+ // functions that may put anything on it, and inside this \`try\`, so a claimed␊
1438
+ // name fails the load through the rollback below rather than past it.␊
1439
+ __napiStampBindingTarget(__napiModule.exports, __napiBindingTarget)␊
1230
1440
  } catch (error) {␊
1231
1441
  const cleanupErrors = await __rollbackWasiInitialization()␊
1232
1442
  throw __attachCleanupErrors(error, cleanupErrors)␊
@@ -1247,6 +1457,55 @@ Generated by [AVA](https://avajs.dev).
1247
1457
  import { createContext as __emnapiCreateContext } from '@emnapi/runtime'␊
1248
1458
  import { memfs } from '@napi-rs/wasm-runtime/fs'␊
1249
1459
  ␊
1460
+ export const __napiBindingTarget = 'wasm32-wasi'␊
1461
+ function __napiStampBindingTarget(exportsObject, target) {␊
1462
+ if (␊
1463
+ Object.prototype.hasOwnProperty.call(exportsObject, '__napiBindingTarget')␊
1464
+ ) {␊
1465
+ if (exportsObject.__napiBindingTarget === target) {␊
1466
+ // Already ours: the root entry aliases the object it loaded, so a WASI␊
1467
+ // fallback candidate — or a \`NAPI_RS_NATIVE_LIBRARY_PATH\` override that␊
1468
+ // is a generated loader — arrives already stamped with this same value.␊
1469
+ return target␊
1470
+ }␊
1471
+ const error = new Error(␊
1472
+ '\`__napiBindingTarget\` is reserved by the generated binding loader, but the loaded binding already exports it. Rename the export, e.g. #[napi(js_name = "...")].',␊
1473
+ )␊
1474
+ error.code = 'ERR_NAPI_BINDING_TARGET_CONFLICT'␊
1475
+ throw error␊
1476
+ }␊
1477
+ if (!Object.isExtensible(exportsObject)) {␊
1478
+ // A \`#[napi(module_exports)]\` hook may seal or freeze this object␊
1479
+ // (\`Object::seal\` / \`Object::freeze\`). Reporting the artifact is metadata,␊
1480
+ // never a reason to fail an otherwise successful load, so the stamp is␊
1481
+ // skipped. What a consumer still sees then follows the entry point: the␊
1482
+ // browser and deferred loaders declare \`__napiBindingTarget\` at module␊
1483
+ // level and go on reporting it, while the CommonJS entries hand back this␊
1484
+ // very object as \`module.exports\`, so there the value is absent.␊
1485
+ return target␊
1486
+ }␊
1487
+ try {␊
1488
+ // [[Define]], not [[Set]]: an ordinary assignment walks the prototype␊
1489
+ // chain, so an inherited accessor could swallow the value or throw and␊
1490
+ // fail an otherwise successful load. The descriptor is what a successful␊
1491
+ // assignment would have produced.␊
1492
+ Object.defineProperty(exportsObject, '__napiBindingTarget', {␊
1493
+ configurable: true,␊
1494
+ enumerable: true,␊
1495
+ value: target,␊
1496
+ writable: true,␊
1497
+ })␊
1498
+ } catch {␊
1499
+ // Same rule as the non-extensible skip above: reporting the artifact is␊
1500
+ // metadata, never a reason to fail an otherwise successful load. An exotic␊
1501
+ // object (a Proxy whose defineProperty trap refuses) is skipped, not␊
1502
+ // thrown over.␊
1503
+ }␊
1504
+ // The CommonJS loaders assign this return value so \`cjs-module-lexer\` — and␊
1505
+ // therefore Node's CJS -> ESM named export detection — can see␊
1506
+ // \`__napiBindingTarget\` statically.␊
1507
+ return target␊
1508
+ }␊
1250
1509
  ␊
1251
1510
  export const { fs: __fs, vol: __volume } = memfs()␊
1252
1511
  ␊
@@ -1291,16 +1550,17 @@ Generated by [AVA](https://avajs.dev).
1291
1550
  let __emnapiContextDestroyed = false␊
1292
1551
  let __emnapiContextDestroyPromise␊
1293
1552
  let __emnapiWasmEnvCleanupPrepared = false␊
1553
+ let __emnapiWasmEnvCleanupPreparing = false␊
1294
1554
  let __emnapiWasmEnvCleanupRan = false␊
1295
1555
  let __emnapiWasmEnvCleanupDrained = false␊
1296
1556
  let __emnapiWasmEnvCleanupDrainPromise␊
1297
1557
  let __wasiDisposed = false␊
1298
1558
  let __wasiDisposePromise␊
1299
- let __completeWasiDisposal = function() {}␊
1559
+ let __completeWasiDisposal = function () {}␊
1300
1560
  // Overridden by loader flavors that have a last-resort reclaim for a rollback␊
1301
1561
  // that stopped short of destroying the context. See␊
1302
1562
  // \`__rollbackWasiInitialization\`.␊
1303
- let __retainWasiRollbackForRetry = function() {}␊
1563
+ let __retainWasiRollbackForRetry = function () {}␊
1304
1564
  ␊
1305
1565
  function __isThenable(value) {␊
1306
1566
  return (␊
@@ -1364,13 +1624,58 @@ Generated by [AVA](https://avajs.dev).
1364
1624
  return aggregate␊
1365
1625
  }␊
1366
1626
  ␊
1627
+ function __wrapEmnapiContextDestroyForSettlement(␊
1628
+ context,␊
1629
+ prepareEnvCleanup,␊
1630
+ isPreparingEnvCleanup,␊
1631
+ ) {␊
1632
+ let destroy␊
1633
+ try {␊
1634
+ destroy = context.destroy␊
1635
+ } catch {␊
1636
+ return context␊
1637
+ }␊
1638
+ if (typeof destroy !== 'function') {␊
1639
+ return context␊
1640
+ }␊
1641
+ try {␊
1642
+ Object.defineProperty(context, 'destroy', {␊
1643
+ configurable: true,␊
1644
+ enumerable: false,␊
1645
+ writable: true,␊
1646
+ value: function () {␊
1647
+ // Reentered from a promise hook that fired inside the barrier: the␊
1648
+ // frame running it destroys as soon as it returns.␊
1649
+ if (isPreparingEnvCleanup?.()) {␊
1650
+ return␊
1651
+ }␊
1652
+ prepareEnvCleanup?.()␊
1653
+ return Reflect.apply(destroy, this, arguments)␊
1654
+ },␊
1655
+ })␊
1656
+ } catch {}␊
1657
+ return context␊
1658
+ }␊
1659
+ ␊
1660
+ function __isPreparingWasmEnvCleanup() {␊
1661
+ return __emnapiWasmEnvCleanupPreparing␊
1662
+ }␊
1663
+ ␊
1367
1664
  function __prepareWasmEnvCleanup() {␊
1368
- if (__emnapiWasmEnvCleanupPrepared) {␊
1665
+ if (__emnapiWasmEnvCleanupPrepared || __emnapiWasmEnvCleanupPreparing) {␊
1369
1666
  return␊
1370
1667
  }␊
1371
1668
  const prepare = __napiInstance?.exports?.napi_prepare_wasm_env_cleanup␊
1372
1669
  if (typeof prepare === 'function') {␊
1373
- prepare()␊
1670
+ // The addon settles the promises it cancels synchronously, under a␊
1671
+ // non-reentrant lifecycle mutex: anything a promise hook calls from in␊
1672
+ // here must not reach this export again.␊
1673
+ __emnapiWasmEnvCleanupPreparing = true␊
1674
+ try {␊
1675
+ prepare()␊
1676
+ } finally {␊
1677
+ __emnapiWasmEnvCleanupPreparing = false␊
1678
+ }␊
1374
1679
  __emnapiWasmEnvCleanupRan = true␊
1375
1680
  }␊
1376
1681
  __emnapiWasmEnvCleanupPrepared = true␊
@@ -1800,7 +2105,11 @@ Generated by [AVA](https://avajs.dev).
1800
2105
  let __napiModule␊
1801
2106
  ␊
1802
2107
  try {␊
1803
- __emnapiContext = __emnapiCreateContext({ autoDestroy: false })␊
2108
+ __emnapiContext = __wrapEmnapiContextDestroyForSettlement(␊
2109
+ __emnapiCreateContext({ autoDestroy: false }),␊
2110
+ __prepareWasmEnvCleanup,␊
2111
+ __isPreparingWasmEnvCleanup,␊
2112
+ )␊
1804
2113
  __emnapiContext.suppressDestroy()␊
1805
2114
  ␊
1806
2115
  ;({␊
@@ -1855,56 +2164,3699 @@ Generated by [AVA](https://avajs.dev).
1855
2164
  },␊
1856
2165
  }))␊
1857
2166
  __publishWasiDispose(__napiModule.exports)␊
2167
+ // The default export hands out this object; a named module export does not␊
2168
+ // travel with it, so carry the marker on the binding itself too. After the␊
2169
+ // host install, which hands the same object to addon-provided registration␊
2170
+ // functions that may put anything on it, and inside this \`try\`, so a claimed␊
2171
+ // name fails the load through the rollback below rather than past it.␊
2172
+ __napiStampBindingTarget(__napiModule.exports, __napiBindingTarget)␊
1858
2173
  } catch (error) {␊
1859
2174
  const cleanupErrors = await __rollbackWasiInitialization()␊
1860
2175
  throw __attachCleanupErrors(error, cleanupErrors)␊
1861
2176
  }␊
1862
2177
  `
1863
2178
 
1864
- ## createWasiBrowserWorkerBinding default
2179
+ ## createWasiBrowserBinding with asyncRuntime hosts
1865
2180
 
1866
2181
  > Snapshot 1
1867
2182
 
1868
2183
  `import {␊
1869
- instantiateNapiModuleSync,␊
1870
- MessageHandler,␊
1871
- WASI,␊
1872
- emnapiAsyncWorkPlugin,␊
1873
- emnapiTSFNPlugin,␊
2184
+ emnapiAsyncWorkPlugin as __emnapiAsyncWorkPlugin,␊
2185
+ emnapiTSFNPlugin as __emnapiTSFNPlugin,␊
2186
+ instantiateNapiModuleSync as __emnapiInstantiateNapiModuleSync,␊
2187
+ WASI as __WASI,␊
1874
2188
  } from '@napi-rs/wasm-runtime'␊
2189
+ import { createContext as __emnapiCreateContext } from '@emnapi/runtime'␊
2190
+ import { installCurrentThreadHosts as __installCurrentThreadHosts } from '@napi-rs/async-runtime'␊
1875
2191
  ␊
1876
- const handler = new MessageHandler({␊
1877
- onLoad({ wasmModule, wasmMemory }) {␊
1878
- const wasi = new WASI({␊
1879
- print: function () {␊
1880
- // eslint-disable-next-line no-console␊
1881
- console.log.apply(console, arguments)␊
1882
- },␊
1883
- printErr: function() {␊
1884
- // eslint-disable-next-line no-console␊
1885
- console.error.apply(console, arguments)␊
1886
- ␊
1887
- },␊
2192
+ ␊
2193
+ export const __napiBindingTarget = 'wasm32-wasip1'␊
2194
+ function __napiStampBindingTarget(exportsObject, target) {␊
2195
+ if (␊
2196
+ Object.prototype.hasOwnProperty.call(exportsObject, '__napiBindingTarget')␊
2197
+ ) {␊
2198
+ if (exportsObject.__napiBindingTarget === target) {␊
2199
+ // Already ours: the root entry aliases the object it loaded, so a WASI␊
2200
+ // fallback candidate — or a \`NAPI_RS_NATIVE_LIBRARY_PATH\` override that␊
2201
+ // is a generated loader — arrives already stamped with this same value.␊
2202
+ return target␊
2203
+ }␊
2204
+ const error = new Error(␊
2205
+ '\`__napiBindingTarget\` is reserved by the generated binding loader, but the loaded binding already exports it. Rename the export, e.g. #[napi(js_name = "...")].',␊
2206
+ )␊
2207
+ error.code = 'ERR_NAPI_BINDING_TARGET_CONFLICT'␊
2208
+ throw error␊
2209
+ }␊
2210
+ if (!Object.isExtensible(exportsObject)) {␊
2211
+ // A \`#[napi(module_exports)]\` hook may seal or freeze this object␊
2212
+ // (\`Object::seal\` / \`Object::freeze\`). Reporting the artifact is metadata,␊
2213
+ // never a reason to fail an otherwise successful load, so the stamp is␊
2214
+ // skipped. What a consumer still sees then follows the entry point: the␊
2215
+ // browser and deferred loaders declare \`__napiBindingTarget\` at module␊
2216
+ // level and go on reporting it, while the CommonJS entries hand back this␊
2217
+ // very object as \`module.exports\`, so there the value is absent.␊
2218
+ return target␊
2219
+ }␊
2220
+ try {␊
2221
+ // [[Define]], not [[Set]]: an ordinary assignment walks the prototype␊
2222
+ // chain, so an inherited accessor could swallow the value or throw and␊
2223
+ // fail an otherwise successful load. The descriptor is what a successful␊
2224
+ // assignment would have produced.␊
2225
+ Object.defineProperty(exportsObject, '__napiBindingTarget', {␊
2226
+ configurable: true,␊
2227
+ enumerable: true,␊
2228
+ value: target,␊
2229
+ writable: true,␊
1888
2230
  })␊
1889
- return instantiateNapiModuleSync(wasmModule, {␊
1890
- childThread: true,␊
1891
- wasi,␊
1892
- // The wasm links a "basic" emnapi archive (no C async-work /␊
1893
- // threadsafe-function implementations), so every thread that␊
1894
- // instantiates it must provide the JavaScript implementations␊
1895
- // through the emnapi plugins.␊
1896
- plugins: [emnapiAsyncWorkPlugin, emnapiTSFNPlugin],␊
1897
- overwriteImports(importObject) {␊
1898
- importObject.env = {␊
1899
- ...importObject.env,␊
1900
- ...importObject.napi,␊
1901
- ...importObject.emnapi,␊
1902
- memory: wasmMemory,␊
2231
+ } catch {␊
2232
+ // Same rule as the non-extensible skip above: reporting the artifact is␊
2233
+ // metadata, never a reason to fail an otherwise successful load. An exotic␊
2234
+ // object (a Proxy whose defineProperty trap refuses) is skipped, not␊
2235
+ // thrown over.␊
2236
+ }␊
2237
+ // The CommonJS loaders assign this return value so \`cjs-module-lexer\` — and␊
2238
+ // therefore Node's CJS -> ESM named export detection — can see␊
2239
+ // \`__napiBindingTarget\` statically.␊
2240
+ return target␊
2241
+ }␊
2242
+ ␊
2243
+ const __wasi = new __WASI({␊
2244
+ version: 'preview1',␊
2245
+ })␊
2246
+ ␊
2247
+ const __wasmUrl = new URL('./test-wasi.wasm', import.meta.url).href␊
2248
+ const __wasmResponse = await globalThis.fetch(__wasmUrl)␊
2249
+ if (!__wasmResponse.ok) {␊
2250
+ throw new Error(␊
2251
+ 'Failed to fetch WASI module ' +␊
2252
+ __wasmUrl +␊
2253
+ ': ' +␊
2254
+ __wasmResponse.status +␊
2255
+ ' ' +␊
2256
+ (__wasmResponse.statusText || 'Unknown Status'),␊
2257
+ )␊
2258
+ }␊
2259
+ const __wasmFile = await __wasmResponse.arrayBuffer()␊
2260
+ ␊
2261
+ const __wasmMemory = new WebAssembly.Memory({␊
2262
+ initial: 4000,␊
2263
+ maximum: 65536,␊
2264
+ })␊
2265
+ let __emnapiContext␊
2266
+ ␊
2267
+ const __wasiDisposeSymbol = Symbol.for('napi.rs.wasi.dispose')␊
2268
+ const __wasiWorkers = new Set()␊
2269
+ let __napiInstance␊
2270
+ let __emnapiContextDestroyed = false␊
2271
+ let __emnapiContextDestroyPromise␊
2272
+ let __emnapiWasmEnvCleanupPrepared = false␊
2273
+ let __emnapiWasmEnvCleanupPreparing = false␊
2274
+ let __emnapiWasmEnvCleanupRan = false␊
2275
+ let __emnapiWasmEnvCleanupDrained = false␊
2276
+ let __emnapiWasmEnvCleanupDrainPromise␊
2277
+ let __wasiDisposed = false␊
2278
+ let __wasiDisposePromise␊
2279
+ let __completeWasiDisposal = function () {}␊
2280
+ // Overridden by loader flavors that have a last-resort reclaim for a rollback␊
2281
+ // that stopped short of destroying the context. See␊
2282
+ // \`__rollbackWasiInitialization\`.␊
2283
+ let __retainWasiRollbackForRetry = function () {}␊
2284
+ ␊
2285
+ let __currentThreadHostsDisposer␊
2286
+ ␊
2287
+ function __reportCurrentThreadHostDisposalError(error) {␊
2288
+ try {␊
2289
+ const consoleHost = globalThis.console␊
2290
+ if (consoleHost && typeof consoleHost.error === 'function') {␊
2291
+ consoleHost.error(error)␊
2292
+ }␊
2293
+ } catch {}␊
2294
+ }␊
2295
+ ␊
2296
+ /**␊
2297
+ * Unregister the CurrentThread task and timer hosts this loader installed.␊
2298
+ * Idempotent, and never throws: an unregister failure must not abort␊
2299
+ * \`Context.destroy()\`, which would retain the whole environment over a␊
2300
+ * bookkeeping error. The failure is reported instead.␊
2301
+ */␊
2302
+ function __disposeCurrentThreadHosts() {␊
2303
+ const dispose = __currentThreadHostsDisposer␊
2304
+ if (dispose === undefined) {␊
2305
+ return␊
2306
+ }␊
2307
+ __currentThreadHostsDisposer = undefined␊
2308
+ try {␊
2309
+ dispose()␊
2310
+ } catch (error) {␊
2311
+ __reportCurrentThreadHostDisposalError(error)␊
2312
+ }␊
2313
+ }␊
2314
+ ␊
2315
+ function __isThenable(value) {␊
2316
+ return (␊
2317
+ value !== null &&␊
2318
+ (typeof value === 'object' || typeof value === 'function') &&␊
2319
+ typeof value.then === 'function'␊
2320
+ )␊
2321
+ }␊
2322
+ ␊
2323
+ function __createCleanupError(errors, message) {␊
2324
+ if (errors.length === 1) {␊
2325
+ return errors[0]␊
2326
+ }␊
2327
+ const __AggregateError = globalThis.AggregateError␊
2328
+ if (typeof __AggregateError === 'function') {␊
2329
+ return new __AggregateError(errors, message)␊
2330
+ }␊
2331
+ const error = new Error(message)␊
2332
+ error.errors = errors␊
2333
+ return error␊
2334
+ }␊
2335
+ ␊
2336
+ function __attachCleanupErrors(error, cleanupErrors) {␊
2337
+ if (cleanupErrors.length === 0) {␊
2338
+ return error␊
2339
+ }␊
2340
+ const cleanupError = __createCleanupError(␊
2341
+ cleanupErrors,␊
2342
+ 'WASI binding cleanup failed',␊
2343
+ )␊
2344
+ try {␊
2345
+ if (␊
2346
+ error &&␊
2347
+ (typeof error === 'object' || typeof error === 'function')␊
2348
+ ) {␊
2349
+ if (error.cause === undefined) {␊
2350
+ error.cause = cleanupError␊
2351
+ if (error.cause === cleanupError) {␊
2352
+ return error␊
2353
+ }␊
2354
+ }␊
2355
+ if (Array.isArray(error.cleanupErrors)) {␊
2356
+ error.cleanupErrors.push(cleanupError)␊
2357
+ return error␊
2358
+ } else {␊
2359
+ const attachedCleanupErrors = [cleanupError]␊
2360
+ error.cleanupErrors = attachedCleanupErrors␊
2361
+ if (error.cleanupErrors === attachedCleanupErrors) {␊
2362
+ return error␊
2363
+ }␊
2364
+ }␊
2365
+ }␊
2366
+ } catch {}␊
2367
+ const aggregate = __createCleanupError(␊
2368
+ [error, cleanupError],␊
2369
+ 'WASI binding initialization and cleanup failed',␊
2370
+ )␊
2371
+ try {␊
2372
+ aggregate.cause = error␊
2373
+ } catch {}␊
2374
+ return aggregate␊
2375
+ }␊
2376
+ ␊
2377
+ function __wrapEmnapiContextDestroyForSettlement(␊
2378
+ context,␊
2379
+ prepareEnvCleanup,␊
2380
+ isPreparingEnvCleanup,␊
2381
+ ) {␊
2382
+ let destroy␊
2383
+ try {␊
2384
+ destroy = context.destroy␊
2385
+ } catch {␊
2386
+ return context␊
2387
+ }␊
2388
+ if (typeof destroy !== 'function') {␊
2389
+ return context␊
2390
+ }␊
2391
+ try {␊
2392
+ Object.defineProperty(context, 'destroy', {␊
2393
+ configurable: true,␊
2394
+ enumerable: false,␊
2395
+ writable: true,␊
2396
+ value: function () {␊
2397
+ // Reentered from a promise hook that fired inside the barrier: the␊
2398
+ // frame running it destroys as soon as it returns.␊
2399
+ if (isPreparingEnvCleanup?.()) {␊
2400
+ return␊
1903
2401
  }␊
2402
+ prepareEnvCleanup?.()␊
2403
+ return Reflect.apply(destroy, this, arguments)␊
1904
2404
  },␊
1905
2405
  })␊
1906
- },␊
1907
- ␊
2406
+ } catch {}␊
2407
+ return context␊
2408
+ }␊
2409
+ ␊
2410
+ function __isPreparingWasmEnvCleanup() {␊
2411
+ return __emnapiWasmEnvCleanupPreparing␊
2412
+ }␊
2413
+ ␊
2414
+ function __prepareWasmEnvCleanup() {␊
2415
+ if (__emnapiWasmEnvCleanupPrepared || __emnapiWasmEnvCleanupPreparing) {␊
2416
+ return␊
2417
+ }␊
2418
+ const prepare = __napiInstance?.exports?.napi_prepare_wasm_env_cleanup␊
2419
+ if (typeof prepare === 'function') {␊
2420
+ // The addon settles the promises it cancels synchronously, under a␊
2421
+ // non-reentrant lifecycle mutex: anything a promise hook calls from in␊
2422
+ // here must not reach this export again.␊
2423
+ __emnapiWasmEnvCleanupPreparing = true␊
2424
+ try {␊
2425
+ prepare()␊
2426
+ } finally {␊
2427
+ __emnapiWasmEnvCleanupPreparing = false␊
2428
+ }␊
2429
+ __emnapiWasmEnvCleanupRan = true␊
2430
+ }␊
2431
+ __emnapiWasmEnvCleanupPrepared = true␊
2432
+ }␊
2433
+ ␊
2434
+ // Mirror the primitive @emnapi/core schedules its threadsafe-function dispatch␊
2435
+ // on, so the drain turns below interleave with that dispatch instead of racing␊
2436
+ // ahead of it on a faster queue.␊
2437
+ const __scheduleMacrotask = (function () {␊
2438
+ if (typeof setImmediate === 'function') {␊
2439
+ return function (callback) {␊
2440
+ setImmediate(callback)␊
2441
+ }␊
2442
+ }␊
2443
+ const __MessageChannel = globalThis.MessageChannel␊
2444
+ if (typeof __MessageChannel === 'function') {␊
2445
+ return function (callback) {␊
2446
+ const channel = new __MessageChannel()␊
2447
+ channel.port1.onmessage = function () {␊
2448
+ channel.port1.onmessage = null␊
2449
+ try {␊
2450
+ channel.port1.close()␊
2451
+ } catch {}␊
2452
+ try {␊
2453
+ channel.port2.close()␊
2454
+ } catch {}␊
2455
+ callback()␊
2456
+ }␊
2457
+ channel.port2.postMessage(null)␊
2458
+ }␊
2459
+ }␊
2460
+ return function (callback) {␊
2461
+ setTimeout(callback, 0)␊
2462
+ }␊
2463
+ })()␊
2464
+ ␊
2465
+ // Turns to wait for while the addon still reports queued settlements. Reaching␊
2466
+ // zero is the only success. A counter still nonzero at this bound rejects the␊
2467
+ // disposal as retryable (\`ERR_NAPI_WASI_CLEANUP_PENDING\`) rather than␊
2468
+ // destroying the context over a still-queued settlement — the wait stays␊
2469
+ // bounded either way.␊
2470
+ const __WASM_ENV_CLEANUP_DRAIN_TURNS = 128␊
2471
+ // Without \`napi_wasm_env_cleanup_pending\` the queue is not observable. Fall␊
2472
+ // back to the number of turns @emnapi/core needs to coalesce and dispatch a␊
2473
+ // call made on this thread (two), plus a margin.␊
2474
+ const __WASM_ENV_CLEANUP_BLIND_DRAIN_TURNS = 4␊
2475
+ ␊
2476
+ /**␊
2477
+ * \`napi_prepare_wasm_env_cleanup\` only *queues* the promise settlements of the␊
2478
+ * tasks it cancelled: \`napi_call_threadsafe_function\` appends to the␊
2479
+ * threadsafe-function queue, and @emnapi/core dispatches that queue from a␊
2480
+ * macrotask — two coalescing turns later, even for a call made on this very␊
2481
+ * thread. \`Context.destroy()\` then runs the threadsafe function's cleanup hook,␊
2482
+ * which drains the queue with a null env and *discards* whatever is still in it.␊
2483
+ *␊
2484
+ * So destroying without yielding first strands exactly the promises the barrier␊
2485
+ * exists to settle. Yield real event-loop turns until the addon reports the␊
2486
+ * queue empty; microtask checkpoints cannot help, no number of them lets a␊
2487
+ * macrotask run.␊
2488
+ *␊
2489
+ * Returns nothing when there is nothing to wait for, which keeps disposal␊
2490
+ * synchronous in the common case.␊
2491
+ *␊
2492
+ * The "already drained" flag is set only once a wait has actually finished.␊
2493
+ * Scheduling a macrotask can fail — a host-provided or patched \`setImmediate\`␊
2494
+ * that throws is enough — and a disposal that rejects stays retryable, so␊
2495
+ * marking the drain complete up front would make the retry skip it and destroy␊
2496
+ * the context with the barrier's settlements still queued.␊
2497
+ *␊
2498
+ * A wait that runs out of turns with the counter still nonzero rejects with␊
2499
+ * \`ERR_NAPI_WASI_CLEANUP_PENDING\` for the same reason: at that point␊
2500
+ * "finished" is indistinguishable from the stranding above, and destroying␊
2501
+ * would discard the very settlement the wait was for. The rejection leaves the␊
2502
+ * flag unset and disposal retryable.␊
2503
+ */␊
2504
+ function __drainWasmEnvCleanup() {␊
2505
+ if (__emnapiWasmEnvCleanupDrained || !__emnapiWasmEnvCleanupRan) {␊
2506
+ return␊
2507
+ }␊
2508
+ if (__emnapiWasmEnvCleanupDrainPromise) {␊
2509
+ return __emnapiWasmEnvCleanupDrainPromise␊
2510
+ }␊
2511
+ const pending = __napiInstance?.exports?.napi_wasm_env_cleanup_pending␊
2512
+ const observable = typeof pending === 'function'␊
2513
+ if (observable) {␊
2514
+ let queued␊
2515
+ try {␊
2516
+ queued = pending()␊
2517
+ } catch {␊
2518
+ __emnapiWasmEnvCleanupDrained = true␊
2519
+ return␊
2520
+ }␊
2521
+ if (!queued) {␊
2522
+ __emnapiWasmEnvCleanupDrained = true␊
2523
+ return␊
2524
+ }␊
2525
+ }␊
2526
+ const limit = observable␊
2527
+ ? __WASM_ENV_CLEANUP_DRAIN_TURNS␊
2528
+ : __WASM_ENV_CLEANUP_BLIND_DRAIN_TURNS␊
2529
+ const drainPromise = (async () => {␊
2530
+ let queued = 0␊
2531
+ for (let turn = 0; turn < limit; turn++) {␊
2532
+ await new Promise((resolve) => {␊
2533
+ __scheduleMacrotask(resolve)␊
2534
+ })␊
2535
+ if (!observable) {␊
2536
+ continue␊
2537
+ }␊
2538
+ try {␊
2539
+ queued = pending()␊
2540
+ } catch {␊
2541
+ return␊
2542
+ }␊
2543
+ if (!queued) {␊
2544
+ return␊
2545
+ }␊
2546
+ }␊
2547
+ if (!observable) {␊
2548
+ // Blind wait: without \`napi_wasm_env_cleanup_pending\` the bound IS the␊
2549
+ // contract — there is nothing to consult, so finishing the turns is␊
2550
+ // finishing the drain.␊
2551
+ return␊
2552
+ }␊
2553
+ // The counter is still nonzero after every turn the bound allows. The wait␊
2554
+ // stays bounded — but claiming success here would be indistinguishable from␊
2555
+ // the stranding this drain exists to prevent: disposal would go on to␊
2556
+ // destroy the context, whose cleanup hook discards the still-queued␊
2557
+ // settlement with a null env, and the promise it was for hangs forever.␊
2558
+ // Reject instead, as a retryable cleanup failure: the drained flag stays␊
2559
+ // unset, dispose() (and the rollback) decline to destroy, and a later␊
2560
+ // dispose() runs the drain again — by which time the queue has usually been␊
2561
+ // delivered. A counter that is somehow stuck nonzero therefore costs each␊
2562
+ // attempt at most another bounded wait and a rejection, never a stranded␊
2563
+ // promise; the process-exit teardown still reclaims the context.␊
2564
+ const drainError = new Error(␊
2565
+ 'the wasm environment still reports ' +␊
2566
+ queued +␊
2567
+ ' queued settlement(s) after ' +␊
2568
+ limit +␊
2569
+ ' event-loop turns; the context was not destroyed - retry dispose() to wait for the queue again',␊
2570
+ )␊
2571
+ drainError.code = 'ERR_NAPI_WASI_CLEANUP_PENDING'␊
2572
+ throw drainError␊
2573
+ })().then(␊
2574
+ (value) => {␊
2575
+ // Set only when the wait actually finished AND the queue was seen empty␊
2576
+ // (or is unobservable): a drain that timed out with settlements still␊
2577
+ // queued rejects above and must stay repeatable.␊
2578
+ __emnapiWasmEnvCleanupDrained = true␊
2579
+ __emnapiWasmEnvCleanupDrainPromise = undefined␊
2580
+ return value␊
2581
+ },␊
2582
+ (error) => {␊
2583
+ __emnapiWasmEnvCleanupDrainPromise = undefined␊
2584
+ throw error␊
2585
+ },␊
2586
+ )␊
2587
+ __emnapiWasmEnvCleanupDrainPromise = drainPromise␊
2588
+ return drainPromise␊
2589
+ }␊
2590
+ ␊
2591
+ function __destroyEmnapiContext() {␊
2592
+ if (__emnapiContextDestroyed || __emnapiContext === undefined) {␊
2593
+ __emnapiContextDestroyed = true␊
2594
+ return␊
2595
+ }␊
2596
+ if (__emnapiContextDestroyPromise) {␊
2597
+ return __emnapiContextDestroyPromise␊
2598
+ }␊
2599
+ ␊
2600
+ __disposeCurrentThreadHosts()␊
2601
+ __prepareWasmEnvCleanup()␊
2602
+ const result = __emnapiContext.destroy()␊
2603
+ if (!__isThenable(result)) {␊
2604
+ __emnapiContextDestroyed = true␊
2605
+ return␊
2606
+ }␊
2607
+ ␊
2608
+ const destroyPromise = Promise.resolve(result).then(␊
2609
+ (value) => {␊
2610
+ __emnapiContextDestroyed = true␊
2611
+ return value␊
2612
+ },␊
2613
+ (error) => {␊
2614
+ __emnapiContextDestroyPromise = undefined␊
2615
+ throw error␊
2616
+ },␊
2617
+ )␊
2618
+ __emnapiContextDestroyPromise = destroyPromise␊
2619
+ return destroyPromise␊
2620
+ }␊
2621
+ ␊
2622
+ function __terminateWasiWorkers() {␊
2623
+ const cleanupErrors = []␊
2624
+ const pending = []␊
2625
+ ␊
2626
+ for (const worker of __wasiWorkers) {␊
2627
+ let result␊
2628
+ try {␊
2629
+ result = worker.terminate()␊
2630
+ } catch (error) {␊
2631
+ cleanupErrors.push(error)␊
2632
+ continue␊
2633
+ }␊
2634
+ if (__isThenable(result)) {␊
2635
+ pending.push(␊
2636
+ Promise.resolve(result).then(␊
2637
+ () => {␊
2638
+ __wasiWorkers.delete(worker)␊
2639
+ },␊
2640
+ (error) => {␊
2641
+ cleanupErrors.push(error)␊
2642
+ },␊
2643
+ ),␊
2644
+ )␊
2645
+ } else {␊
2646
+ __wasiWorkers.delete(worker)␊
2647
+ }␊
2648
+ }␊
2649
+ ␊
2650
+ const finish = () => {␊
2651
+ if (cleanupErrors.length > 0) {␊
2652
+ throw __createCleanupError(␊
2653
+ cleanupErrors,␊
2654
+ 'Failed to terminate WASI workers',␊
2655
+ )␊
2656
+ }␊
2657
+ }␊
2658
+ return pending.length > 0 ? Promise.all(pending).then(finish) : finish()␊
2659
+ }␊
2660
+ ␊
2661
+ function __finishWasiDisposal() {␊
2662
+ const workerResult = __terminateWasiWorkers()␊
2663
+ if (__isThenable(workerResult)) {␊
2664
+ return Promise.resolve(workerResult).then(__completeWasiDisposal)␊
2665
+ }␊
2666
+ return __completeWasiDisposal()␊
2667
+ }␊
2668
+ ␊
2669
+ function __continueWasiDisposal() {␊
2670
+ const destroyResult = __destroyEmnapiContext()␊
2671
+ if (__isThenable(destroyResult)) {␊
2672
+ return Promise.resolve(destroyResult).then(__finishWasiDisposal)␊
2673
+ }␊
2674
+ return __finishWasiDisposal()␊
2675
+ }␊
2676
+ ␊
2677
+ function __startWasiDisposal() {␊
2678
+ // Run the pre-teardown barrier, then let the settlements it queued actually␊
2679
+ // reach JavaScript, and only then destroy the environment. Doing these two␊
2680
+ // back to back is what strands them.␊
2681
+ __prepareWasmEnvCleanup()␊
2682
+ const drainResult = __drainWasmEnvCleanup()␊
2683
+ if (__isThenable(drainResult)) {␊
2684
+ return Promise.resolve(drainResult).then(__continueWasiDisposal)␊
2685
+ }␊
2686
+ return __continueWasiDisposal()␊
2687
+ }␊
2688
+ ␊
2689
+ /**␊
2690
+ * Disposes this generated WASI binding.␊
2691
+ *␊
2692
+ * Access this function with:␊
2693
+ * binding[Symbol.for('napi.rs.wasi.dispose')]()␊
2694
+ */␊
2695
+ function __disposeWasiBinding() {␊
2696
+ if (__wasiDisposePromise) {␊
2697
+ return __wasiDisposePromise␊
2698
+ }␊
2699
+ if (__wasiDisposed) {␊
2700
+ return Promise.resolve()␊
2701
+ }␊
2702
+ ␊
2703
+ let resolveDispose␊
2704
+ let rejectDispose␊
2705
+ const disposePromise = new Promise((resolve, reject) => {␊
2706
+ resolveDispose = resolve␊
2707
+ rejectDispose = reject␊
2708
+ })␊
2709
+ __wasiDisposePromise = disposePromise␊
2710
+ ␊
2711
+ let result␊
2712
+ try {␊
2713
+ result = __startWasiDisposal()␊
2714
+ } catch (error) {␊
2715
+ __wasiDisposePromise = undefined␊
2716
+ rejectDispose(error)␊
2717
+ return disposePromise␊
2718
+ }␊
2719
+ ␊
2720
+ Promise.resolve(result).then(␊
2721
+ (value) => {␊
2722
+ __wasiDisposed = true␊
2723
+ resolveDispose(value)␊
2724
+ },␊
2725
+ (error) => {␊
2726
+ __wasiDisposePromise = undefined␊
2727
+ rejectDispose(error)␊
2728
+ },␊
2729
+ )␊
2730
+ return disposePromise␊
2731
+ }␊
2732
+ ␊
2733
+ function __publishWasiDispose(exports) {␊
2734
+ Object.defineProperty(exports, __wasiDisposeSymbol, {␊
2735
+ configurable: false,␊
2736
+ enumerable: false,␊
2737
+ value: __disposeWasiBinding,␊
2738
+ writable: false,␊
2739
+ })␊
2740
+ }␊
2741
+ ␊
2742
+ function __finishWasiInitializationRollback(cleanupErrors) {␊
2743
+ let workerResult␊
2744
+ try {␊
2745
+ workerResult = __terminateWasiWorkers()␊
2746
+ } catch (cleanupError) {␊
2747
+ cleanupErrors.push(cleanupError)␊
2748
+ return cleanupErrors␊
2749
+ }␊
2750
+ if (__isThenable(workerResult)) {␊
2751
+ return Promise.resolve(workerResult)␊
2752
+ .catch((cleanupError) => {␊
2753
+ cleanupErrors.push(cleanupError)␊
2754
+ })␊
2755
+ .then(() => cleanupErrors)␊
2756
+ }␊
2757
+ return cleanupErrors␊
2758
+ }␊
2759
+ ␊
2760
+ function __destroyContextForWasiRollback(cleanupErrors) {␊
2761
+ let destroyResult␊
2762
+ try {␊
2763
+ destroyResult = __destroyEmnapiContext()␊
2764
+ } catch (cleanupError) {␊
2765
+ cleanupErrors.push(cleanupError)␊
2766
+ return __finishWasiInitializationRollback(cleanupErrors)␊
2767
+ }␊
2768
+ if (__isThenable(destroyResult)) {␊
2769
+ return Promise.resolve(destroyResult)␊
2770
+ .catch((cleanupError) => {␊
2771
+ cleanupErrors.push(cleanupError)␊
2772
+ })␊
2773
+ .then(() => __finishWasiInitializationRollback(cleanupErrors))␊
2774
+ }␊
2775
+ return __finishWasiInitializationRollback(cleanupErrors)␊
2776
+ }␊
2777
+ ␊
2778
+ /**␊
2779
+ * Leaves a rollback that could not reach the queued settlements undestroyed, and␊
2780
+ * hands it to whatever this flavor has that can still reclaim it.␊
2781
+ */␊
2782
+ function __retainFailedWasiRollback(cleanupErrors) {␊
2783
+ try {␊
2784
+ __retainWasiRollbackForRetry()␊
2785
+ } catch (cleanupError) {␊
2786
+ cleanupErrors.push(cleanupError)␊
2787
+ }␊
2788
+ return cleanupErrors␊
2789
+ }␊
2790
+ ␊
2791
+ /**␊
2792
+ * Initialization can fail *after* registration has already run, and registration␊
2793
+ * runs with a live environment: a module-init hook can start async work and then␊
2794
+ * return an error, and the promise it created may already have escaped into␊
2795
+ * JavaScript. The barrier cancels that work and *queues* the settlement, so this␊
2796
+ * path needs the same drain the ordinary disposal does — destroying without␊
2797
+ * yielding discards the queue with a null env and strands the promise.␊
2798
+ *␊
2799
+ * Stays synchronous when nothing is queued, which covers every failure before␊
2800
+ * \`beforeInit\`: there is no instance to run the barrier on, so nothing to drain.␊
2801
+ *␊
2802
+ * A barrier or drain that did *not* finish stops the rollback short of␊
2803
+ * destroying, which is what \`dispose()\` already does — a rejected drain there␊
2804
+ * never reaches \`__continueWasiDisposal\`. Destroying anyway is the worse of the␊
2805
+ * two trades, and not because of what it saves:␊
2806
+ *␊
2807
+ * - It cannot deliver the settlements. \`Context.destroy()\` runs the␊
2808
+ * threadsafe function's cleanup hook, which drains the queue with a null env␊
2809
+ * and discards it, so a promise that already escaped into JavaScript hangs␊
2810
+ * forever with nothing left that could ever settle it.␊
2811
+ * - It saves less than it looks. \`Context.destroy()\` stops JavaScript calls␊
2812
+ * and runs cleanup hooks; it does not free the wasm instance or its Memory,␊
2813
+ * which this module's scope holds either way. What stopping short retains is␊
2814
+ * the emnapi context's bookkeeping and its un-run cleanup hooks.␊
2815
+ * - Retry is not theoretical. A rollback that records a cleanup error is␊
2816
+ * already kept in the process-wide registry above, so re-\`require()\`ing this␊
2817
+ * file replays it instead of re-instantiating — and the \`6e15de6f\` flag fix␊
2818
+ * means the replay drains again rather than skipping it. Destroying first is␊
2819
+ * what makes that retained record useless.␊
2820
+ *␊
2821
+ * The residual cost is honest: the CJS flavor hands the context to its␊
2822
+ * \`process.on('exit')\` teardown, so a process that never retries still reclaims␊
2823
+ * it on the way out. The ESM browser flavor has no equivalent — a module that␊
2824
+ * throws while evaluating is permanently errored, so re-importing rethrows␊
2825
+ * without re-running this file — and there the context stays until the realm␊
2826
+ * goes away. That is the deliberate choice: a hung promise is a silent liveness␊
2827
+ * bug with no upper bound, while the retained bookkeeping is bounded by the page.␊
2828
+ */␊
2829
+ function __rollbackWasiInitialization() {␊
2830
+ const cleanupErrors = []␊
2831
+ let drainResult␊
2832
+ let settlementsUnreached = false␊
2833
+ try {␊
2834
+ __prepareWasmEnvCleanup()␊
2835
+ drainResult = __drainWasmEnvCleanup()␊
2836
+ } catch (cleanupError) {␊
2837
+ cleanupErrors.push(cleanupError)␊
2838
+ settlementsUnreached = true␊
2839
+ }␊
2840
+ if (__isThenable(drainResult)) {␊
2841
+ return Promise.resolve(drainResult).then(␊
2842
+ () => __destroyContextForWasiRollback(cleanupErrors),␊
2843
+ (cleanupError) => {␊
2844
+ cleanupErrors.push(cleanupError)␊
2845
+ return __retainFailedWasiRollback(cleanupErrors)␊
2846
+ },␊
2847
+ )␊
2848
+ }␊
2849
+ if (settlementsUnreached) {␊
2850
+ return __retainFailedWasiRollback(cleanupErrors)␊
2851
+ }␊
2852
+ return __destroyContextForWasiRollback(cleanupErrors)␊
2853
+ }␊
2854
+ ␊
2855
+ let __wasiModule␊
2856
+ let __napiModule␊
2857
+ ␊
2858
+ try {␊
2859
+ __emnapiContext = __wrapEmnapiContextDestroyForSettlement(␊
2860
+ __emnapiCreateContext({ autoDestroy: false }),␊
2861
+ __prepareWasmEnvCleanup,␊
2862
+ __isPreparingWasmEnvCleanup,␊
2863
+ )␊
2864
+ __emnapiContext.suppressDestroy()␊
2865
+ ␊
2866
+ ;({␊
2867
+ instance: __napiInstance,␊
2868
+ module: __wasiModule,␊
2869
+ napiModule: __napiModule,␊
2870
+ } = __emnapiInstantiateNapiModuleSync(__wasmFile, {␊
2871
+ context: __emnapiContext,␊
2872
+ asyncWorkPoolSize: 0,␊
2873
+ plugins: [__emnapiAsyncWorkPlugin, __emnapiTSFNPlugin],␊
2874
+ wasi: __wasi,␊
2875
+ overwriteImports(importObject) {␊
2876
+ importObject.env = {␊
2877
+ ...importObject.env,␊
2878
+ ...importObject.napi,␊
2879
+ ...importObject.emnapi,␊
2880
+ memory: __wasmMemory,␊
2881
+ }␊
2882
+ return importObject␊
2883
+ },␊
2884
+ beforeInit({ instance }) {␊
2885
+ __napiInstance = instance␊
2886
+ for (const name of Object.keys(instance.exports)) {␊
2887
+ if (name.startsWith('__napi_register__')) {␊
2888
+ instance.exports[name]()␊
2889
+ }␊
2890
+ }␊
2891
+ },␊
2892
+ }))␊
2893
+ __publishWasiDispose(__napiModule.exports)␊
2894
+ __currentThreadHostsDisposer = __installCurrentThreadHosts(␊
2895
+ __napiModule.exports,␊
2896
+ )␊
2897
+ // The default export hands out this object; a named module export does not␊
2898
+ // travel with it, so carry the marker on the binding itself too. After the␊
2899
+ // host install, which hands the same object to addon-provided registration␊
2900
+ // functions that may put anything on it, and inside this \`try\`, so a claimed␊
2901
+ // name fails the load through the rollback below rather than past it.␊
2902
+ __napiStampBindingTarget(__napiModule.exports, __napiBindingTarget)␊
2903
+ } catch (error) {␊
2904
+ const cleanupErrors = await __rollbackWasiInitialization()␊
2905
+ throw __attachCleanupErrors(error, cleanupErrors)␊
2906
+ }␊
2907
+ `
2908
+
2909
+ ## createWasiDeferredBrowserBinding default
2910
+
2911
+ > Snapshot 1
2912
+
2913
+ `import {␊
2914
+ emnapiAsyncWorkPlugin as __emnapiAsyncWorkPlugin,␊
2915
+ emnapiTSFNPlugin as __emnapiTSFNPlugin,␊
2916
+ instantiateNapiModule as __emnapiInstantiateNapiModule,␊
2917
+ WASI as __WASI,␊
2918
+ } from '@napi-rs/wasm-runtime'␊
2919
+ import { createContext as __emnapiCreateContext } from '@emnapi/runtime'␊
2920
+ ␊
2921
+ ␊
2922
+ export const WASM_MEMORY = Object.freeze({␊
2923
+ initialPages: 1024,␊
2924
+ maximumPages: 65536,␊
2925
+ pageBytes: 65536,␊
2926
+ initialBytes: 1024 * 65536,␊
2927
+ maximumBytes: 65536 * 65536,␊
2928
+ })␊
2929
+ ␊
2930
+ let __createdInstances = 0␊
2931
+ let __liveInstances = 0␊
2932
+ ␊
2933
+ /**␊
2934
+ * Counters for instances created by THIS module evaluation, not process-wide:␊
2935
+ * a second bundled copy of this loader keeps its own. Only successfully␊
2936
+ * created instances are counted, and \`liveInstances\` drops when an instance's␊
2937
+ * \`dispose()\` resolves.␊
2938
+ *␊
2939
+ * \`declaredInitialMemoryBytes\` is declared address space, not a host's␊
2940
+ * committed-memory metric; pair it with host telemetry rather than treating it␊
2941
+ * as a quota.␊
2942
+ */␊
2943
+ export function getDeferredRuntimeStats() {␊
2944
+ return Object.freeze({␊
2945
+ createdInstances: __createdInstances,␊
2946
+ liveInstances: __liveInstances,␊
2947
+ declaredInitialMemoryBytes: WASM_MEMORY.initialBytes,␊
2948
+ })␊
2949
+ }␊
2950
+ ␊
2951
+ const __arrayBufferByteLengthGetter = Object.getOwnPropertyDescriptor(␊
2952
+ ArrayBuffer.prototype,␊
2953
+ 'byteLength',␊
2954
+ ).get␊
2955
+ const __memoryBufferGetter = Object.getOwnPropertyDescriptor(␊
2956
+ WebAssembly.Memory.prototype,␊
2957
+ 'buffer',␊
2958
+ ).get␊
2959
+ // One managed initialization per Memory, success or failure: an attempt that␊
2960
+ // throws may already have written into linear memory, so the bytes are not a␊
2961
+ // clean slate for a second instance. Module-local, like the counters above.␊
2962
+ const __claimedMemories = new WeakSet()␊
2963
+ ␊
2964
+ function __resolveInstanceMemory(__options) {␊
2965
+ const __provided = __options == null ? undefined : __options.memory␊
2966
+ if (__provided === undefined || __provided === null) {␊
2967
+ // Page counts are handed to the engine unvalidated: it already rejects a␊
2968
+ // negative, over-4GiB or below-maximum value with a precise message, and a␊
2969
+ // second set of bounds here would only drift from it.␊
2970
+ const __allocated = new WebAssembly.Memory({␊
2971
+ initial:␊
2972
+ __options != null && __options.initialMemoryPages !== undefined␊
2973
+ ? __options.initialMemoryPages␊
2974
+ : WASM_MEMORY.initialPages,␊
2975
+ maximum:␊
2976
+ __options != null && __options.maximumMemoryPages !== undefined␊
2977
+ ? __options.maximumMemoryPages␊
2978
+ : WASM_MEMORY.maximumPages,␊
2979
+ })␊
2980
+ // Claimed like a caller-provided one. The handle publishes it as␊
2981
+ // \`instance.memory\`, so handing it back to \`createInstance()\` is as easy␊
2982
+ // as passing your own twice, and it would put two live instances on one␊
2983
+ // linear memory: each initialization rewrites the emnapi/WASI state the␊
2984
+ // other is still running on.␊
2985
+ __claimedMemories.add(__allocated)␊
2986
+ return __allocated␊
2987
+ }␊
2988
+ if (␊
2989
+ __options.initialMemoryPages !== undefined ||␊
2990
+ __options.maximumMemoryPages !== undefined␊
2991
+ ) {␊
2992
+ throw new TypeError(␊
2993
+ 'Pass either memory or initialMemoryPages/maximumMemoryPages, not both',␊
2994
+ )␊
2995
+ }␊
2996
+ let __buffer␊
2997
+ try {␊
2998
+ // Brand check: the getter throws for anything that is not a genuine␊
2999
+ // WebAssembly.Memory, including a cross-realm look-alike object.␊
3000
+ __buffer = Reflect.apply(__memoryBufferGetter, __provided, [])␊
3001
+ } catch {␊
3002
+ throw new TypeError('memory must be an unshared WebAssembly.Memory')␊
3003
+ }␊
3004
+ try {␊
3005
+ // Throws for a SharedArrayBuffer. This loader has no threads, and shared␊
3006
+ // growth does not detach: external views handed to the addon would␊
3007
+ // silently outlive the bytes they describe.␊
3008
+ Reflect.apply(__arrayBufferByteLengthGetter, __buffer, [])␊
3009
+ } catch {␊
3010
+ throw new TypeError(␊
3011
+ 'The deferred loader requires an unshared WebAssembly.Memory',␊
3012
+ )␊
3013
+ }␊
3014
+ // The intrinsic getters above accept a genuine Memory from ANY realm, but␊
3015
+ // the loader's dependencies do not: \`WASI.setMemory\` in␊
3016
+ // \`@napi-rs/wasm-runtime\` and emnapi identify a Memory with a realm-local␊
3017
+ // \`instanceof\`. A Memory built in another realm (a \`node:vm\` context, a␊
3018
+ // same-origin iframe) would pass every check here and only fail deep inside␊
3019
+ // initialization. Reject it up front, and before the claim below, so the␊
3020
+ // caller keeps it usable in the realm that made it.␊
3021
+ if (!(__provided instanceof WebAssembly.Memory)) {␊
3022
+ throw new TypeError(␊
3023
+ 'memory must be a WebAssembly.Memory created in the same realm as this loader',␊
3024
+ )␊
3025
+ }␊
3026
+ if (__claimedMemories.has(__provided)) {␊
3027
+ throw new TypeError(␊
3028
+ 'This WebAssembly.Memory has already been used for a deferred initialization attempt and cannot be reused, including after a failed initialization or a disposal',␊
3029
+ )␊
3030
+ }␊
3031
+ // Last step, after every check: a rejected option bag must leave the Memory␊
3032
+ // unclaimed, or a caller could not fix the call and retry with it.␊
3033
+ __claimedMemories.add(__provided)␊
3034
+ return __provided␊
3035
+ }␊
3036
+ ␊
3037
+ export const __napiBindingTarget = 'wasm32-wasip1'␊
3038
+ function __napiStampBindingTarget(exportsObject, target) {␊
3039
+ if (␊
3040
+ Object.prototype.hasOwnProperty.call(exportsObject, '__napiBindingTarget')␊
3041
+ ) {␊
3042
+ if (exportsObject.__napiBindingTarget === target) {␊
3043
+ // Already ours: the root entry aliases the object it loaded, so a WASI␊
3044
+ // fallback candidate — or a \`NAPI_RS_NATIVE_LIBRARY_PATH\` override that␊
3045
+ // is a generated loader — arrives already stamped with this same value.␊
3046
+ return target␊
3047
+ }␊
3048
+ const error = new Error(␊
3049
+ '\`__napiBindingTarget\` is reserved by the generated binding loader, but the loaded binding already exports it. Rename the export, e.g. #[napi(js_name = "...")].',␊
3050
+ )␊
3051
+ error.code = 'ERR_NAPI_BINDING_TARGET_CONFLICT'␊
3052
+ throw error␊
3053
+ }␊
3054
+ if (!Object.isExtensible(exportsObject)) {␊
3055
+ // A \`#[napi(module_exports)]\` hook may seal or freeze this object␊
3056
+ // (\`Object::seal\` / \`Object::freeze\`). Reporting the artifact is metadata,␊
3057
+ // never a reason to fail an otherwise successful load, so the stamp is␊
3058
+ // skipped. What a consumer still sees then follows the entry point: the␊
3059
+ // browser and deferred loaders declare \`__napiBindingTarget\` at module␊
3060
+ // level and go on reporting it, while the CommonJS entries hand back this␊
3061
+ // very object as \`module.exports\`, so there the value is absent.␊
3062
+ return target␊
3063
+ }␊
3064
+ try {␊
3065
+ // [[Define]], not [[Set]]: an ordinary assignment walks the prototype␊
3066
+ // chain, so an inherited accessor could swallow the value or throw and␊
3067
+ // fail an otherwise successful load. The descriptor is what a successful␊
3068
+ // assignment would have produced.␊
3069
+ Object.defineProperty(exportsObject, '__napiBindingTarget', {␊
3070
+ configurable: true,␊
3071
+ enumerable: true,␊
3072
+ value: target,␊
3073
+ writable: true,␊
3074
+ })␊
3075
+ } catch {␊
3076
+ // Same rule as the non-extensible skip above: reporting the artifact is␊
3077
+ // metadata, never a reason to fail an otherwise successful load. An exotic␊
3078
+ // object (a Proxy whose defineProperty trap refuses) is skipped, not␊
3079
+ // thrown over.␊
3080
+ }␊
3081
+ // The CommonJS loaders assign this return value so \`cjs-module-lexer\` — and␊
3082
+ // therefore Node's CJS -> ESM named export detection — can see␊
3083
+ // \`__napiBindingTarget\` statically.␊
3084
+ return target␊
3085
+ }␊
3086
+ ␊
3087
+ /**␊
3088
+ * Deferred, workerd-safe instantiation: no top-level I/O, no compile-from-bytes.␊
3089
+ * Accepts ONLY a precompiled WebAssembly.Module, or a Promise resolving to one␊
3090
+ * (e.g. \`import mod from './test-wasi.wasm'\` under a CompiledWasm␊
3091
+ * module rule / wrangler module import). Byte buffers, URLs and Response␊
3092
+ * objects are rejected: they require dynamic Wasm compilation, which␊
3093
+ * Cloudflare Workers disallows.␊
3094
+ */␊
3095
+ async function __resolveModule(__wasmInput) {␊
3096
+ const __module = await __wasmInput␊
3097
+ // Brand check, not \`instanceof\`: \`WebAssembly.Module.imports\` throws unless␊
3098
+ // its argument is a genuine WebAssembly.Module, so prototype-spoofed byte␊
3099
+ // buffers are rejected while cross-realm Module instances are accepted.␊
3100
+ try {␊
3101
+ WebAssembly.Module.imports(__module)␊
3102
+ } catch {␊
3103
+ throw new TypeError(␊
3104
+ "instantiate() and createInstance() expect a precompiled WebAssembly.Module (or a Promise resolving to one), " +␊
3105
+ "e.g. import mod from './test-wasi.wasm' under a CompiledWasm module rule / wrangler module import. " +␊
3106
+ "Byte buffers, URLs and Response objects require dynamic Wasm compilation, which Cloudflare Workers disallows.",␊
3107
+ )␊
3108
+ }␊
3109
+ return __module␊
3110
+ }␊
3111
+ ␊
3112
+ let __normalizedModules␊
3113
+ ␊
3114
+ function __rememberNormalizedModule(__module, __normalizedModule) {␊
3115
+ if (!__normalizedModules) {␊
3116
+ __normalizedModules = new WeakMap()␊
3117
+ }␊
3118
+ __normalizedModules.set(__module, __normalizedModule)␊
3119
+ return __normalizedModule␊
3120
+ }␊
3121
+ ␊
3122
+ async function __normalizeModuleForEmnapi(__module) {␊
3123
+ if (__module instanceof WebAssembly.Module) {␊
3124
+ return __module␊
3125
+ }␊
3126
+ if (__normalizedModules) {␊
3127
+ const __normalizedModule = __normalizedModules.get(__module)␊
3128
+ if (__normalizedModule) {␊
3129
+ return __normalizedModule␊
3130
+ }␊
3131
+ }␊
3132
+ // @emnapi/core currently performs realm-local \`instanceof\` checks after␊
3133
+ // accepting the module. Structured cloning preserves compiled code without␊
3134
+ // compiling bytes and produces a Module owned by the current realm.␊
3135
+ if (typeof structuredClone === 'function') {␊
3136
+ try {␊
3137
+ const __normalizedModule = structuredClone(__module)␊
3138
+ if (__normalizedModule instanceof WebAssembly.Module) {␊
3139
+ return __rememberNormalizedModule(__module, __normalizedModule)␊
3140
+ }␊
3141
+ } catch {}␊
3142
+ }␊
3143
+ // MessageChannel uses the same structured-clone semantics and covers older␊
3144
+ // browser/Node hosts that expose it but not the structuredClone function.␊
3145
+ if (typeof MessageChannel === 'function') {␊
3146
+ let __channel␊
3147
+ try {␊
3148
+ __channel = new MessageChannel()␊
3149
+ const __normalizedModule = await new Promise((resolve, reject) => {␊
3150
+ __channel.port1.onmessage = (event) => resolve(event.data)␊
3151
+ __channel.port1.onmessageerror = () =>␊
3152
+ reject(new TypeError('Failed to clone WebAssembly.Module'))␊
3153
+ try {␊
3154
+ __channel.port2.postMessage(__module)␊
3155
+ } catch (error) {␊
3156
+ reject(error)␊
3157
+ }␊
3158
+ })␊
3159
+ if (__normalizedModule instanceof WebAssembly.Module) {␊
3160
+ return __rememberNormalizedModule(__module, __normalizedModule)␊
3161
+ }␊
3162
+ } catch {␊
3163
+ } finally {␊
3164
+ try {␊
3165
+ __channel?.port1.close()␊
3166
+ } catch {}␊
3167
+ try {␊
3168
+ __channel?.port2.close()␊
3169
+ } catch {}␊
3170
+ }␊
3171
+ }␊
3172
+ // Last-resort compatibility for genuine, extensible foreign Modules.␊
3173
+ try {␊
3174
+ Object.setPrototypeOf(__module, WebAssembly.Module.prototype)␊
3175
+ } catch {}␊
3176
+ if (__module instanceof WebAssembly.Module) {␊
3177
+ return __module␊
3178
+ }␊
3179
+ throw new TypeError(␊
3180
+ 'This host cannot normalize a cross-realm WebAssembly.Module; ' +␊
3181
+ 'provide structuredClone or MessageChannel support.',␊
3182
+ )␊
3183
+ }␊
3184
+ ␊
3185
+ function __wrapEmnapiContextDestroyForSettlement(␊
3186
+ context,␊
3187
+ prepareEnvCleanup,␊
3188
+ isPreparingEnvCleanup,␊
3189
+ ) {␊
3190
+ let destroy␊
3191
+ try {␊
3192
+ destroy = context.destroy␊
3193
+ } catch {␊
3194
+ return context␊
3195
+ }␊
3196
+ if (typeof destroy !== 'function') {␊
3197
+ return context␊
3198
+ }␊
3199
+ try {␊
3200
+ Object.defineProperty(context, 'destroy', {␊
3201
+ configurable: true,␊
3202
+ enumerable: false,␊
3203
+ writable: true,␊
3204
+ value: function () {␊
3205
+ // Reentered from a promise hook that fired inside the barrier: the␊
3206
+ // frame running it destroys as soon as it returns.␊
3207
+ if (isPreparingEnvCleanup?.()) {␊
3208
+ return␊
3209
+ }␊
3210
+ prepareEnvCleanup?.()␊
3211
+ return Reflect.apply(destroy, this, arguments)␊
3212
+ },␊
3213
+ })␊
3214
+ } catch {}␊
3215
+ return context␊
3216
+ }␊
3217
+ ␊
3218
+ function __captureEmnapiAutoDestroyListener(__process) {␊
3219
+ if (␊
3220
+ !__process ||␊
3221
+ typeof __process.prependListener !== 'function' ||␊
3222
+ typeof __process.removeListener !== 'function'␊
3223
+ ) {␊
3224
+ return␊
3225
+ }␊
3226
+ let __autoDestroyListener␊
3227
+ const __captureListener = (__event, __listener) => {␊
3228
+ if (__event === 'beforeExit' && __autoDestroyListener === undefined) {␊
3229
+ __autoDestroyListener = __listener␊
3230
+ }␊
3231
+ }␊
3232
+ try {␊
3233
+ // Run before existing newListener hooks so a hook that registers its own␊
3234
+ // beforeExit listener cannot be mistaken for emnapi's registration.␊
3235
+ __process.prependListener('newListener', __captureListener)␊
3236
+ } catch {␊
3237
+ return␊
3238
+ }␊
3239
+ return () => {␊
3240
+ try {␊
3241
+ __process.removeListener('newListener', __captureListener)␊
3242
+ } catch {}␊
3243
+ if (__autoDestroyListener !== undefined) {␊
3244
+ try {␊
3245
+ __process.removeListener('beforeExit', __autoDestroyListener)␊
3246
+ } catch {}␊
3247
+ }␊
3248
+ }␊
3249
+ }␊
3250
+ ␊
3251
+ function __attachCleanupError(__error, __cleanupError) {␊
3252
+ try {␊
3253
+ if (␊
3254
+ __error &&␊
3255
+ (typeof __error === 'object' || typeof __error === 'function') &&␊
3256
+ __error.cause === undefined␊
3257
+ ) {␊
3258
+ __error.cause = __cleanupError␊
3259
+ }␊
3260
+ } catch {}␊
3261
+ }␊
3262
+ ␊
3263
+ // Mirror the primitive @emnapi/core schedules its threadsafe-function dispatch␊
3264
+ // on, so the drain turns below interleave with that dispatch instead of racing␊
3265
+ // ahead of it on a faster queue.␊
3266
+ const __scheduleMacrotask = (function () {␊
3267
+ if (typeof setImmediate === 'function') {␊
3268
+ return function (__callback) {␊
3269
+ setImmediate(__callback)␊
3270
+ }␊
3271
+ }␊
3272
+ const __MessageChannel = globalThis.MessageChannel␊
3273
+ if (typeof __MessageChannel === 'function') {␊
3274
+ return function (__callback) {␊
3275
+ const __channel = new __MessageChannel()␊
3276
+ __channel.port1.onmessage = function () {␊
3277
+ __channel.port1.onmessage = null␊
3278
+ try {␊
3279
+ __channel.port1.close()␊
3280
+ } catch {}␊
3281
+ try {␊
3282
+ __channel.port2.close()␊
3283
+ } catch {}␊
3284
+ __callback()␊
3285
+ }␊
3286
+ __channel.port2.postMessage(null)␊
3287
+ }␊
3288
+ }␊
3289
+ return function (__callback) {␊
3290
+ setTimeout(__callback, 0)␊
3291
+ }␊
3292
+ })()␊
3293
+ ␊
3294
+ // Turns to wait for while the addon still reports queued settlements. Reaching␊
3295
+ // zero is the only success. A counter still nonzero at this bound rejects the␊
3296
+ // disposal as retryable (\`ERR_NAPI_WASI_CLEANUP_PENDING\`) rather than␊
3297
+ // destroying the context over a still-queued settlement — the wait stays␊
3298
+ // bounded either way.␊
3299
+ const __WASM_ENV_CLEANUP_DRAIN_TURNS = 128␊
3300
+ // Without \`napi_wasm_env_cleanup_pending\` the queue is not observable. Fall␊
3301
+ // back to the number of turns @emnapi/core needs to coalesce and dispatch a␊
3302
+ // call made on this thread (two), plus a margin.␊
3303
+ const __WASM_ENV_CLEANUP_BLIND_DRAIN_TURNS = 4␊
3304
+ ␊
3305
+ /**␊
3306
+ * \`napi_prepare_wasm_env_cleanup\` only *queues* the promise settlements of the␊
3307
+ * tasks it cancelled: \`napi_call_threadsafe_function\` appends to the␊
3308
+ * threadsafe-function queue, and @emnapi/core dispatches that queue from a␊
3309
+ * macrotask — two coalescing turns later, even for a call made on this very␊
3310
+ * thread. \`Context.destroy()\` then runs the threadsafe function's cleanup hook,␊
3311
+ * which drains the queue with a null env and *discards* whatever is still in it.␊
3312
+ *␊
3313
+ * So destroying without yielding first strands exactly the promises the barrier␊
3314
+ * exists to settle. Yield real event-loop turns until the addon reports the␊
3315
+ * queue empty; microtask checkpoints cannot help, no number of them lets a␊
3316
+ * macrotask run.␊
3317
+ *␊
3318
+ * Returns nothing when there is nothing to wait for, which keeps disposal␊
3319
+ * synchronous in the common case.␊
3320
+ */␊
3321
+ function __drainWasmEnvCleanup(__instance) {␊
3322
+ const __pending = __instance?.exports.napi_wasm_env_cleanup_pending␊
3323
+ const __observable = typeof __pending === 'function'␊
3324
+ if (__observable) {␊
3325
+ let __queued␊
3326
+ try {␊
3327
+ __queued = __pending()␊
3328
+ } catch {␊
3329
+ return␊
3330
+ }␊
3331
+ if (!__queued) {␊
3332
+ return␊
3333
+ }␊
3334
+ }␊
3335
+ const __limit = __observable␊
3336
+ ? __WASM_ENV_CLEANUP_DRAIN_TURNS␊
3337
+ : __WASM_ENV_CLEANUP_BLIND_DRAIN_TURNS␊
3338
+ return (async () => {␊
3339
+ let __queued = 0␊
3340
+ for (let __turn = 0; __turn < __limit; __turn++) {␊
3341
+ await new Promise((resolve) => {␊
3342
+ __scheduleMacrotask(resolve)␊
3343
+ })␊
3344
+ if (!__observable) {␊
3345
+ continue␊
3346
+ }␊
3347
+ try {␊
3348
+ __queued = __pending()␊
3349
+ } catch {␊
3350
+ return␊
3351
+ }␊
3352
+ if (!__queued) {␊
3353
+ return␊
3354
+ }␊
3355
+ }␊
3356
+ if (!__observable) {␊
3357
+ // Blind wait: without \`napi_wasm_env_cleanup_pending\` the bound IS the␊
3358
+ // contract — there is nothing to consult, so finishing the turns is␊
3359
+ // finishing the drain.␊
3360
+ return␊
3361
+ }␊
3362
+ // The counter is still nonzero after every turn the bound allows. The wait␊
3363
+ // stays bounded — but claiming success here would be indistinguishable from␊
3364
+ // the stranding this drain exists to prevent: disposal would go on to␊
3365
+ // destroy the context, whose cleanup hook discards the still-queued␊
3366
+ // settlement with a null env, and the promise it was for hangs forever.␊
3367
+ // Reject instead, as a retryable cleanup failure: \`__prepareForDisposal\`␊
3368
+ // leaves its drained flag unset, dispose() (and the instantiation-failure␊
3369
+ // path) decline to destroy, and a later dispose() runs the drain again — by␊
3370
+ // which time the queue has usually been delivered. A counter that is␊
3371
+ // somehow stuck nonzero therefore costs each attempt at most another␊
3372
+ // bounded wait and a rejection, never a stranded promise; the managed␊
3373
+ // beforeExit destroyer still reclaims the context.␊
3374
+ const __drainError = new Error(␊
3375
+ 'the wasm environment still reports ' +␊
3376
+ __queued +␊
3377
+ ' queued settlement(s) after ' +␊
3378
+ __limit +␊
3379
+ ' event-loop turns; the context was not destroyed - retry dispose() to wait for the queue again',␊
3380
+ )␊
3381
+ __drainError.code = 'ERR_NAPI_WASI_CLEANUP_PENDING'␊
3382
+ throw __drainError␊
3383
+ })()␊
3384
+ }␊
3385
+ ␊
3386
+ function __createLifecycleReentryError(__operation) {␊
3387
+ const __error = new Error(␊
3388
+ __operation +␊
3389
+ '() cannot run while an emnapi Context.destroy() call is still active; await the original cleanup promise instead.',␊
3390
+ )␊
3391
+ __error.code = 'ERR_NAPI_WASI_LIFECYCLE_REENTRY'␊
3392
+ return __error␊
3393
+ }␊
3394
+ ␊
3395
+ const __managedEmnapiContextDestroyers = new Set()␊
3396
+ let __managedCleanupProcess␊
3397
+ let __managedBeforeExitListener␊
3398
+ let __managedDestroyPromise␊
3399
+ let __managedDestroyersInFlight␊
3400
+ let __managedBeforeExitRegistrationRetryCount = 0␊
3401
+ let __managedBeforeExitRegistrationRetryScheduled = false␊
3402
+ let __moduleLifecycleDestroyDepth = 0␊
3403
+ ␊
3404
+ function __removeManagedEmnapiCleanupListeners() {␊
3405
+ const __process = __managedCleanupProcess␊
3406
+ const __beforeExitListener = __managedBeforeExitListener␊
3407
+ __managedCleanupProcess = undefined␊
3408
+ __managedBeforeExitListener = undefined␊
3409
+ __managedBeforeExitRegistrationRetryCount = 0␊
3410
+ if (__process && __beforeExitListener) {␊
3411
+ try {␊
3412
+ __process.removeListener('beforeExit', __beforeExitListener)␊
3413
+ } catch {}␊
3414
+ }␊
3415
+ }␊
3416
+ ␊
3417
+ function __scheduleManagedBeforeExitListenerRegistration() {␊
3418
+ if (␊
3419
+ !__managedCleanupProcess ||␊
3420
+ __managedBeforeExitListener ||␊
3421
+ __managedEmnapiContextDestroyers.size === 0 ||␊
3422
+ __managedBeforeExitRegistrationRetryScheduled ||␊
3423
+ __managedBeforeExitRegistrationRetryCount >= 3␊
3424
+ ) {␊
3425
+ return␊
3426
+ }␊
3427
+ __managedBeforeExitRegistrationRetryScheduled = true␊
3428
+ __managedBeforeExitRegistrationRetryCount++␊
3429
+ queueMicrotask(() => {␊
3430
+ __managedBeforeExitRegistrationRetryScheduled = false␊
3431
+ if (␊
3432
+ !__managedCleanupProcess ||␊
3433
+ __managedBeforeExitListener ||␊
3434
+ __managedEmnapiContextDestroyers.size === 0␊
3435
+ ) {␊
3436
+ return␊
3437
+ }␊
3438
+ try {␊
3439
+ __registerManagedBeforeExitListener()␊
3440
+ } catch {}␊
3441
+ })␊
3442
+ }␊
3443
+ ␊
3444
+ function __registerManagedBeforeExitListener() {␊
3445
+ if (!__managedCleanupProcess || __managedBeforeExitListener) {␊
3446
+ return␊
3447
+ }␊
3448
+ try {␊
3449
+ __managedCleanupProcess.once(␊
3450
+ 'beforeExit',␊
3451
+ __destroyManagedEmnapiContextsBeforeExit,␊
3452
+ )␊
3453
+ } catch (error) {␊
3454
+ __scheduleManagedBeforeExitListenerRegistration()␊
3455
+ throw error␊
3456
+ }␊
3457
+ __managedBeforeExitListener = __destroyManagedEmnapiContextsBeforeExit␊
3458
+ __managedBeforeExitRegistrationRetryCount = 0␊
3459
+ }␊
3460
+ ␊
3461
+ function __settleManagedEmnapiContextDestroy(__promise) {␊
3462
+ if (__managedDestroyPromise === __promise) {␊
3463
+ __managedDestroyPromise = undefined␊
3464
+ __managedDestroyersInFlight = undefined␊
3465
+ }␊
3466
+ if (__managedEmnapiContextDestroyers.size === 0) {␊
3467
+ __removeManagedEmnapiCleanupListeners()␊
3468
+ return␊
3469
+ }␊
3470
+ try {␊
3471
+ __registerManagedBeforeExitListener()␊
3472
+ } catch {}␊
3473
+ }␊
3474
+ ␊
3475
+ function __destroyManagedEmnapiContexts(__excludedDestroyers) {␊
3476
+ if (__managedDestroyPromise) {␊
3477
+ return __managedDestroyPromise␊
3478
+ }␊
3479
+ const __destroyers = Array.from(__managedEmnapiContextDestroyers).filter(␊
3480
+ (__destroy) => !__excludedDestroyers?.has(__destroy),␊
3481
+ )␊
3482
+ if (__destroyers.length === 0) {␊
3483
+ return Promise.resolve()␊
3484
+ }␊
3485
+ let __resolveDestroy␊
3486
+ let __rejectDestroy␊
3487
+ const __promise = new Promise((resolve, reject) => {␊
3488
+ __resolveDestroy = resolve␊
3489
+ __rejectDestroy = reject␊
3490
+ })␊
3491
+ __managedDestroyPromise = __promise␊
3492
+ __managedDestroyersInFlight = new Set(__destroyers)␊
3493
+ void Promise.all(␊
3494
+ __destroyers.map((__destroy) => {␊
3495
+ try {␊
3496
+ return Promise.resolve(__destroy()).then(␊
3497
+ () => ({ failed: false }),␊
3498
+ (error) => ({ failed: true, error }),␊
3499
+ )␊
3500
+ } catch (error) {␊
3501
+ return { failed: true, error }␊
3502
+ }␊
3503
+ }),␊
3504
+ ).then((__results) => {␊
3505
+ let __primaryError␊
3506
+ let __failed = false␊
3507
+ for (const __result of __results) {␊
3508
+ if (!__result.failed) {␊
3509
+ continue␊
3510
+ }␊
3511
+ if (!__failed) {␊
3512
+ __failed = true␊
3513
+ __primaryError = __result.error␊
3514
+ } else {␊
3515
+ __attachCleanupError(__primaryError, __result.error)␊
3516
+ }␊
3517
+ }␊
3518
+ if (__failed) {␊
3519
+ __rejectDestroy(__primaryError)␊
3520
+ } else {␊
3521
+ __resolveDestroy()␊
3522
+ }␊
3523
+ }, __rejectDestroy)␊
3524
+ void __promise.then(␊
3525
+ () => {␊
3526
+ __settleManagedEmnapiContextDestroy(__promise)␊
3527
+ },␊
3528
+ () => {␊
3529
+ __settleManagedEmnapiContextDestroy(__promise)␊
3530
+ },␊
3531
+ )␊
3532
+ return __promise␊
3533
+ }␊
3534
+ ␊
3535
+ async function __drainManagedEmnapiContexts(__excludedDestroyers) {␊
3536
+ const __attemptedDestroyers = new Set(__excludedDestroyers)␊
3537
+ let __primaryError␊
3538
+ let __failed = false␊
3539
+ while (true) {␊
3540
+ let __promise = __managedDestroyPromise␊
3541
+ let __destroyers = __managedDestroyersInFlight␊
3542
+ if (!__promise) {␊
3543
+ __promise = __destroyManagedEmnapiContexts(__attemptedDestroyers)␊
3544
+ __destroyers = __managedDestroyersInFlight␊
3545
+ if (!__destroyers) {␊
3546
+ break␊
3547
+ }␊
3548
+ }␊
3549
+ for (const __destroy of __destroyers) {␊
3550
+ __attemptedDestroyers.add(__destroy)␊
3551
+ }␊
3552
+ try {␊
3553
+ await __promise␊
3554
+ } catch (error) {␊
3555
+ if (!__failed) {␊
3556
+ __failed = true␊
3557
+ __primaryError = error␊
3558
+ } else {␊
3559
+ __attachCleanupError(__primaryError, error)␊
3560
+ }␊
3561
+ }␊
3562
+ }␊
3563
+ if (__failed) {␊
3564
+ throw __primaryError␊
3565
+ }␊
3566
+ }␊
3567
+ ␊
3568
+ function __destroyManagedEmnapiContextsBeforeExit() {␊
3569
+ // A once listener is consumed before Node invokes it, including when another␊
3570
+ // cleanup batch is still pending.␊
3571
+ __managedBeforeExitListener = undefined␊
3572
+ if (__managedDestroyPromise) {␊
3573
+ return␊
3574
+ }␊
3575
+ void __destroyManagedEmnapiContexts().catch((error) => {␊
3576
+ queueMicrotask(() => {␊
3577
+ throw error␊
3578
+ })␊
3579
+ })␊
3580
+ }␊
3581
+ ␊
3582
+ function __registerManagedEmnapiContext(__process, __destroy) {␊
3583
+ __managedEmnapiContextDestroyers.add(__destroy)␊
3584
+ if (␊
3585
+ !__managedCleanupProcess &&␊
3586
+ __process &&␊
3587
+ typeof __process.once === 'function' &&␊
3588
+ typeof __process.removeListener === 'function'␊
3589
+ ) {␊
3590
+ __managedCleanupProcess = __process␊
3591
+ }␊
3592
+ let __registered = true␊
3593
+ return () => {␊
3594
+ if (!__registered) {␊
3595
+ return␊
3596
+ }␊
3597
+ __registered = false␊
3598
+ __managedEmnapiContextDestroyers.delete(__destroy)␊
3599
+ if (__managedEmnapiContextDestroyers.size === 0) {␊
3600
+ __removeManagedEmnapiCleanupListeners()␊
3601
+ }␊
3602
+ }␊
3603
+ }␊
3604
+ ␊
3605
+ async function __createManagedEmnapiContext(␊
3606
+ __prepareEnvCleanup,␊
3607
+ __isPreparingEnvCleanup,␊
3608
+ ) {␊
3609
+ const __process =␊
3610
+ typeof process === 'object' && process !== null ? process : undefined␊
3611
+ const __finishAutoDestroyCapture =␊
3612
+ __captureEmnapiAutoDestroyListener(__process)␊
3613
+ let __emnapiContext␊
3614
+ let __contextInitializationError␊
3615
+ let __contextInitializationFailed = false␊
3616
+ try {␊
3617
+ __emnapiContext = __wrapEmnapiContextDestroyForSettlement(␊
3618
+ __emnapiCreateContext({ autoDestroy: false }),␊
3619
+ __prepareEnvCleanup,␊
3620
+ __isPreparingEnvCleanup,␊
3621
+ )␊
3622
+ // emnapi 2.x still registers an unconditional process.once('beforeExit')␊
3623
+ // auto-destroy listener on Node hosts, and suppressDestroy() only␊
3624
+ // neutralizes its callback without removing it. This loader must stay␊
3625
+ // side-effect free per instance, so the listener is captured and removed;␊
3626
+ // suppressDestroy() remains the safety net when removal is unavailable.␊
3627
+ __emnapiContext.suppressDestroy()␊
3628
+ } catch (error) {␊
3629
+ __contextInitializationError = error␊
3630
+ __contextInitializationFailed = true␊
3631
+ } finally {␊
3632
+ // Remove only the exact emnapi callback captured above.␊
3633
+ __finishAutoDestroyCapture?.()␊
3634
+ }␊
3635
+ if (__emnapiContext === undefined) {␊
3636
+ throw __contextInitializationError␊
3637
+ }␊
3638
+ let __disposed = false␊
3639
+ let __destroying = false␊
3640
+ let __destroyPromise␊
3641
+ let __cleanupRegistered = false␊
3642
+ let __unregisterCleanup␊
3643
+ const __destroy = (__blocksModuleLifecycle = false) => {␊
3644
+ if (__disposed) {␊
3645
+ return␊
3646
+ }␊
3647
+ if (__destroying) {␊
3648
+ throw __createLifecycleReentryError('dispose')␊
3649
+ }␊
3650
+ if (__destroyPromise) {␊
3651
+ return __destroyPromise␊
3652
+ }␊
3653
+ __destroying = true␊
3654
+ let __result␊
3655
+ const __finishDestroyInvocation = () => {␊
3656
+ __destroying = false␊
3657
+ }␊
3658
+ const __finishModuleLifecycleDestroy = () => {␊
3659
+ if (__blocksModuleLifecycle) {␊
3660
+ __blocksModuleLifecycle = false␊
3661
+ __moduleLifecycleDestroyDepth--␊
3662
+ }␊
3663
+ }␊
3664
+ if (__blocksModuleLifecycle) {␊
3665
+ __moduleLifecycleDestroyDepth++␊
3666
+ }␊
3667
+ try {␊
3668
+ // Context.destroy() disables JS before cleanup hooks run, so settle␊
3669
+ // runtime-owned promises while this environment can still call JS.␊
3670
+ __prepareEnvCleanup?.()␊
3671
+ if (__isPreparingEnvCleanup?.()) {␊
3672
+ // Reached from inside the barrier, so \`Context.destroy()\` below would␊
3673
+ // hit the wrapper's in-flight no-op. Recording that as a completed␊
3674
+ // destroy is what makes the frame that *did* start the barrier skip the␊
3675
+ // real one afterwards, leaving the context retained with its cleanup␊
3676
+ // hooks unrun. Refuse instead: nothing is flagged, the context stays␊
3677
+ // registered for managed beforeExit cleanup, and a later destroy still␊
3678
+ // works. dispose() coalesces reentrancy before it can get here, so this␊
3679
+ // is the backstop for any other caller that manages to.␊
3680
+ throw __createLifecycleReentryError('dispose')␊
3681
+ }␊
3682
+ __result = __emnapiContext.destroy()␊
3683
+ } catch (error) {␊
3684
+ __finishDestroyInvocation()␊
3685
+ __finishModuleLifecycleDestroy()␊
3686
+ throw error␊
3687
+ }␊
3688
+ let __then␊
3689
+ try {␊
3690
+ if (␊
3691
+ __result !== null &&␊
3692
+ (typeof __result === 'object' || typeof __result === 'function')␊
3693
+ ) {␊
3694
+ __then = __result.then␊
3695
+ }␊
3696
+ } catch (error) {␊
3697
+ __finishDestroyInvocation()␊
3698
+ __finishModuleLifecycleDestroy()␊
3699
+ throw error␊
3700
+ }␊
3701
+ if (typeof __then === 'function') {␊
3702
+ let __resolveResult␊
3703
+ let __rejectResult␊
3704
+ const __resultPromise = new Promise((resolve, reject) => {␊
3705
+ __resolveResult = resolve␊
3706
+ __rejectResult = reject␊
3707
+ })␊
3708
+ const __promise = __resultPromise.then(␊
3709
+ (value) => {␊
3710
+ __finishDestroyInvocation()␊
3711
+ __finishModuleLifecycleDestroy()␊
3712
+ __disposed = true␊
3713
+ __destroyPromise = undefined␊
3714
+ __unregisterCleanup?.()␊
3715
+ return value␊
3716
+ },␊
3717
+ (error) => {␊
3718
+ __finishDestroyInvocation()␊
3719
+ __finishModuleLifecycleDestroy()␊
3720
+ __destroyPromise = undefined␊
3721
+ throw error␊
3722
+ },␊
3723
+ )␊
3724
+ __destroyPromise = __promise␊
3725
+ try {␊
3726
+ Reflect.apply(__then, __result, [__resolveResult, __rejectResult])␊
3727
+ } catch (error) {␊
3728
+ __rejectResult(error)␊
3729
+ }␊
3730
+ return __promise␊
3731
+ }␊
3732
+ __finishDestroyInvocation()␊
3733
+ __finishModuleLifecycleDestroy()␊
3734
+ __disposed = true␊
3735
+ __unregisterCleanup?.()␊
3736
+ }␊
3737
+ const __destroyForModuleLifecycle = () => __destroy(true)␊
3738
+ const __registerCleanup = (␊
3739
+ __beforeExitDestroy = __destroyForModuleLifecycle,␊
3740
+ ) => {␊
3741
+ if (__cleanupRegistered || __disposed) {␊
3742
+ return␊
3743
+ }␊
3744
+ __unregisterCleanup = __registerManagedEmnapiContext(␊
3745
+ __process,␊
3746
+ __beforeExitDestroy,␊
3747
+ )␊
3748
+ __cleanupRegistered = true␊
3749
+ __registerManagedBeforeExitListener()␊
3750
+ }␊
3751
+ if (__contextInitializationFailed) {␊
3752
+ let __registrationError␊
3753
+ let __registrationFailed = false␊
3754
+ try {␊
3755
+ __registerCleanup()␊
3756
+ } catch (error) {␊
3757
+ __attachCleanupError(__contextInitializationError, error)␊
3758
+ __registrationError = error␊
3759
+ __registrationFailed = true␊
3760
+ }␊
3761
+ try {␊
3762
+ await __destroyForModuleLifecycle()␊
3763
+ } catch (error) {␊
3764
+ __attachCleanupError(␊
3765
+ __registrationFailed␊
3766
+ ? __registrationError␊
3767
+ : __contextInitializationError,␊
3768
+ error,␊
3769
+ )␊
3770
+ try {␊
3771
+ __registerManagedBeforeExitListener()␊
3772
+ } catch {}␊
3773
+ }␊
3774
+ throw __contextInitializationError␊
3775
+ }␊
3776
+ return {␊
3777
+ context: __emnapiContext,␊
3778
+ destroy: __destroy,␊
3779
+ destroyForModuleLifecycle: __destroyForModuleLifecycle,␊
3780
+ registerCleanup: __registerCleanup,␊
3781
+ }␊
3782
+ }␊
3783
+ ␊
3784
+ async function __createInstance(␊
3785
+ __wasmInput,␊
3786
+ __options,␊
3787
+ __beforeExitDestroy,␊
3788
+ __onManagedDestroyer,␊
3789
+ ) {␊
3790
+ const __module = await __resolveModule(__wasmInput)␊
3791
+ const __emnapiModule = await __normalizeModuleForEmnapi(__module)␊
3792
+ const __wasi = new __WASI({␊
3793
+ version: 'preview1',␊
3794
+ })␊
3795
+ // The wasm module is linked with \`--import-memory\`, so a Memory must be␊
3796
+ // provided. It is resolved here in function scope (workerd bans global scope␊
3797
+ // allocation) and is never shared (no threads, no SharedArrayBuffer).␊
3798
+ // Resolve it before the emnapi context so a rejected option bag or a host␊
3799
+ // memory-limit failure cannot leak a context that never reaches␊
3800
+ // instantiation.␊
3801
+ const __wasmMemory = __resolveInstanceMemory(__options)␊
3802
+ let __lifecycleState = 'pending'␊
3803
+ let __destroyEmnapiContext␊
3804
+ let __destroyOwnedContext␊
3805
+ let __destroyManagedOwnedContext␊
3806
+ let __napiInstance␊
3807
+ let __wasmEnvCleanupRan = false␊
3808
+ let __wasmEnvCleanupPrepared = false␊
3809
+ let __wasmEnvCleanupPreparing = false␊
3810
+ let __wasmEnvCleanupDrained = false␊
3811
+ let __wasmEnvCleanupDrainPromise␊
3812
+ const __isPreparingEnvCleanup = () => __wasmEnvCleanupPreparing␊
3813
+ const __prepareEnvCleanup = () => {␊
3814
+ if (__wasmEnvCleanupPrepared || __wasmEnvCleanupPreparing) {␊
3815
+ return␊
3816
+ }␊
3817
+ const __prepareWasmEnvCleanup =␊
3818
+ __napiInstance?.exports.napi_prepare_wasm_env_cleanup␊
3819
+ if (typeof __prepareWasmEnvCleanup === 'function') {␊
3820
+ // The addon settles the promises it cancels synchronously, under a␊
3821
+ // non-reentrant lifecycle mutex: anything a promise hook calls from in␊
3822
+ // here must not reach this export again.␊
3823
+ __wasmEnvCleanupPreparing = true␊
3824
+ try {␊
3825
+ __prepareWasmEnvCleanup()␊
3826
+ } finally {␊
3827
+ __wasmEnvCleanupPreparing = false␊
3828
+ }␊
3829
+ __wasmEnvCleanupRan = true␊
3830
+ }␊
3831
+ __wasmEnvCleanupPrepared = true␊
3832
+ }␊
3833
+ // The barrier + settlement drain, hoisted out of the context destroyer so the␊
3834
+ // drain can yield without widening the destroyer's reentry window. Both␊
3835
+ // yielding paths run it — dispose() and the initialization-failure rollback.␊
3836
+ // The destroyer still runs the barrier itself (idempotently) for the one path␊
3837
+ // that cannot yield: managed beforeExit cleanup of an instance whose rollback␊
3838
+ // is being retried.␊
3839
+ //␊
3840
+ // "Drained" is recorded only once a wait has actually finished. Scheduling a␊
3841
+ // macrotask can fail — a host-provided or patched \`setImmediate\` that throws␊
3842
+ // is enough — and dispose() stays retryable after it rejects, so marking the␊
3843
+ // drain complete up front would make the retry skip it and destroy the context␊
3844
+ // with the barrier's settlements still queued.␊
3845
+ const __prepareForDisposal = () => {␊
3846
+ if (__wasmEnvCleanupDrained) {␊
3847
+ return␊
3848
+ }␊
3849
+ if (__wasmEnvCleanupDrainPromise) {␊
3850
+ return __wasmEnvCleanupDrainPromise␊
3851
+ }␊
3852
+ __prepareEnvCleanup()␊
3853
+ if (!__wasmEnvCleanupRan) {␊
3854
+ return␊
3855
+ }␊
3856
+ const __drained = __drainWasmEnvCleanup(__napiInstance)␊
3857
+ if (!__drained || typeof __drained.then !== 'function') {␊
3858
+ __wasmEnvCleanupDrained = true␊
3859
+ return␊
3860
+ }␊
3861
+ const __tracked = __drained.then(␊
3862
+ (__value) => {␊
3863
+ __wasmEnvCleanupDrained = true␊
3864
+ __wasmEnvCleanupDrainPromise = undefined␊
3865
+ return __value␊
3866
+ },␊
3867
+ (__error) => {␊
3868
+ __wasmEnvCleanupDrainPromise = undefined␊
3869
+ throw __error␊
3870
+ },␊
3871
+ )␊
3872
+ __wasmEnvCleanupDrainPromise = __tracked␊
3873
+ return __tracked␊
3874
+ }␊
3875
+ let __disposed = false␊
3876
+ const __runInstanceDisposal = async () => {␊
3877
+ if (__lifecycleState !== 'failed') {␊
3878
+ __lifecycleState = 'disposal'␊
3879
+ }␊
3880
+ // Settle what the barrier cancelled before the environment stops␊
3881
+ // accepting JavaScript calls. Undefined unless something is queued, so␊
3882
+ // an idle disposal is not delayed by a single turn.␊
3883
+ const __drained = __prepareForDisposal()␊
3884
+ if (__drained) {␊
3885
+ await __drained␊
3886
+ }␊
3887
+ const __result = await (__beforeExitDestroy␊
3888
+ ? __destroyManagedOwnedContext()␊
3889
+ : __destroyOwnedContext())␊
3890
+ // Only a completed destroy retires the instance; a throw above leaves␊
3891
+ // the counter untouched so a retried dispose() cannot double-decrement.␊
3892
+ if (!__disposed) {␊
3893
+ __disposed = true␊
3894
+ __liveInstances -= 1␊
3895
+ }␊
3896
+ return __result␊
3897
+ }␊
3898
+ let __instanceDisposePromise␊
3899
+ /**␊
3900
+ * The disposal frame runs the barrier, and the barrier settles the promises it␊
3901
+ * cancels synchronously — so a promise hook firing inside it can call this␊
3902
+ * same instance's dispose() again while the first call is still in its drain.␊
3903
+ * That nested call finds the barrier flagged in flight, prepares nothing,␊
3904
+ * drains nothing, and falls straight through to the context destroyer, whose␊
3905
+ * \`Context.destroy()\` hits the wrapper's in-flight no-op. It would record a␊
3906
+ * destruction that never happened, and the outer frame would then skip the␊
3907
+ * real one: both disposals resolve, no cleanup hook runs, the context stays␊
3908
+ * retained.␊
3909
+ *␊
3910
+ * Memoize before any of that starts, exactly like the eager loaders'␊
3911
+ * \`__disposeWasiBinding\`, so there is only ever one disposal frame per␊
3912
+ * instance and a reentrant caller awaits it instead of racing it. Cleared on␊
3913
+ * rejection: a drain that failed has to stay retryable.␊
3914
+ */␊
3915
+ const __disposeInstance = () => {␊
3916
+ if (__instanceDisposePromise) {␊
3917
+ return __instanceDisposePromise␊
3918
+ }␊
3919
+ let __resolveDispose␊
3920
+ let __rejectDispose␊
3921
+ const __disposePromise = new Promise((__resolve, __reject) => {␊
3922
+ __resolveDispose = __resolve␊
3923
+ __rejectDispose = __reject␊
3924
+ })␊
3925
+ __instanceDisposePromise = __disposePromise␊
3926
+ __runInstanceDisposal().then(__resolveDispose, (__error) => {␊
3927
+ __instanceDisposePromise = undefined␊
3928
+ __rejectDispose(__error)␊
3929
+ })␊
3930
+ return __disposePromise␊
3931
+ }␊
3932
+ const __destroyBeforeExit = __beforeExitDestroy␊
3933
+ ? async () => {␊
3934
+ if (__lifecycleState === 'failed') {␊
3935
+ await __destroyManagedOwnedContext()␊
3936
+ return␊
3937
+ }␊
3938
+ __lifecycleState = 'disposal'␊
3939
+ try {␊
3940
+ await __beforeExitDestroy()␊
3941
+ } catch (error) {␊
3942
+ if (__lifecycleState !== 'failed') {␊
3943
+ throw error␊
3944
+ }␊
3945
+ // The singleton's initialization rejection is already observable␊
3946
+ // through instantiate() and dispose(). Managed beforeExit cleanup␊
3947
+ // owns only context destruction, including retrying a failed rollback.␊
3948
+ await __destroyManagedOwnedContext()␊
3949
+ }␊
3950
+ }␊
3951
+ : undefined␊
3952
+ const {␊
3953
+ context: __emnapiContext,␊
3954
+ destroy,␊
3955
+ destroyForModuleLifecycle,␊
3956
+ registerCleanup: __registerCleanup,␊
3957
+ } = await __createManagedEmnapiContext(␊
3958
+ __prepareEnvCleanup,␊
3959
+ __isPreparingEnvCleanup,␊
3960
+ )␊
3961
+ __destroyEmnapiContext = destroy␊
3962
+ __destroyOwnedContext = () => __destroyEmnapiContext()␊
3963
+ __destroyManagedOwnedContext = destroyForModuleLifecycle␊
3964
+ try {␊
3965
+ if (__destroyBeforeExit) {␊
3966
+ __onManagedDestroyer(__destroyBeforeExit)␊
3967
+ await __registerCleanup(__destroyBeforeExit)␊
3968
+ }␊
3969
+ let __napiModule␊
3970
+ ;({␊
3971
+ instance: __napiInstance,␊
3972
+ napiModule: __napiModule,␊
3973
+ } = await __emnapiInstantiateNapiModule(__emnapiModule, {␊
3974
+ context: __emnapiContext,␊
3975
+ asyncWorkPoolSize: 0,␊
3976
+ plugins: [__emnapiAsyncWorkPlugin, __emnapiTSFNPlugin],␊
3977
+ wasi: __wasi,␊
3978
+ overwriteImports(importObject) {␊
3979
+ importObject.env = {␊
3980
+ ...importObject.env,␊
3981
+ ...importObject.napi,␊
3982
+ ...importObject.emnapi,␊
3983
+ memory: __wasmMemory,␊
3984
+ }␊
3985
+ return importObject␊
3986
+ },␊
3987
+ beforeInit({ instance }) {␊
3988
+ __napiInstance = instance␊
3989
+ for (const name of Object.keys(instance.exports)) {␊
3990
+ if (name.startsWith('__napi_register__')) {␊
3991
+ instance.exports[name]()␊
3992
+ }␊
3993
+ }␊
3994
+ },␊
3995
+ }))␊
3996
+ // \`instantiate()\` and \`createInstance().exports\` hand out this object; a␊
3997
+ // named module export does not travel with it. After the instance host␊
3998
+ // install, which hands the same object to addon-provided registration␊
3999
+ // functions that may put anything on it, and inside this \`try\`, so a␊
4000
+ // claimed name flips \`__lifecycleState\` to 'failed' and tears the instance␊
4001
+ // down rather than escaping a half-built one.␊
4002
+ __napiStampBindingTarget(__napiModule.exports, __napiBindingTarget)␊
4003
+ if (__lifecycleState === 'pending') {␊
4004
+ __lifecycleState = 'succeeded'␊
4005
+ }␊
4006
+ __createdInstances += 1␊
4007
+ __liveInstances += 1␊
4008
+ return {␊
4009
+ exports: __napiModule.exports,␊
4010
+ get memory() {␊
4011
+ return __wasmMemory␊
4012
+ },␊
4013
+ get memoryBytes() {␊
4014
+ // The Memory outlives the environment, so this stays readable after a␊
4015
+ // FAILED dispose() (which leaves the instance undisposed and␊
4016
+ // retryable). It reports 0 only once disposal has actually completed.␊
4017
+ return __disposed ? 0 : __wasmMemory.buffer.byteLength␊
4018
+ },␊
4019
+ get disposed() {␊
4020
+ return __disposed␊
4021
+ },␊
4022
+ dispose: __disposeInstance,␊
4023
+ }␊
4024
+ } catch (error) {␊
4025
+ __lifecycleState = 'failed'␊
4026
+ // Instantiation can fail *after* registration has run, and registration runs␊
4027
+ // with a live environment: a module-init hook can start async work and then␊
4028
+ // return an error, and the promise it created may already have escaped into␊
4029
+ // JavaScript. Settle what the barrier cancels before the context is␊
4030
+ // destroyed, exactly like dispose() does; destroying without yielding␊
4031
+ // discards the queue with a null env. Undefined unless something is queued,␊
4032
+ // so a failure before beforeInit costs no extra turn.␊
4033
+ let __settlementsUnreached = false␊
4034
+ try {␊
4035
+ const __drained = __prepareForDisposal()␊
4036
+ if (__drained) {␊
4037
+ await __drained␊
4038
+ }␊
4039
+ } catch (drainError) {␊
4040
+ __attachCleanupError(error, drainError)␊
4041
+ __settlementsUnreached = true␊
4042
+ }␊
4043
+ let __registrationError␊
4044
+ let __registrationFailed = false␊
4045
+ if (!__beforeExitDestroy) {␊
4046
+ try {␊
4047
+ // Independent instances are caller-owned while pending and after␊
4048
+ // success. Register only failed rollback so cleanup remains retryable.␊
4049
+ await __registerCleanup()␊
4050
+ } catch (registrationError) {␊
4051
+ __attachCleanupError(error, registrationError)␊
4052
+ __registrationError = registrationError␊
4053
+ __registrationFailed = true␊
4054
+ }␊
4055
+ }␊
4056
+ if (__settlementsUnreached) {␊
4057
+ // The barrier or the drain did not finish, so the settlements it queued␊
4058
+ // are still in the threadsafe-function queue. Destroying now runs the␊
4059
+ // cleanup hook that drains that queue with a null env and discards it,␊
4060
+ // stranding a promise that already escaped into JavaScript — with nothing␊
4061
+ // left that could ever settle it. dispose() refuses to destroy for exactly␊
4062
+ // this reason (a rejected drain there never reaches the destroy), so this␊
4063
+ // path refuses too.␊
4064
+ //␊
4065
+ // Nothing leaks. The registration just above — and, for the singleton, the␊
4066
+ // one made before instantiation — leaves this context in␊
4067
+ // \`__managedEmnapiContextDestroyers\`, so beforeExit destroys it and␊
4068
+ // dispose() can retry it. Only the destruction is deferred, and the turns␊
4069
+ // that pass in the meantime are exactly what the queue needed.␊
4070
+ try {␊
4071
+ __registerManagedBeforeExitListener()␊
4072
+ } catch {}␊
4073
+ throw error␊
4074
+ }␊
4075
+ try {␊
4076
+ await __destroyManagedOwnedContext()␊
4077
+ } catch (disposeError) {␊
4078
+ // Initialization is the primary failure. Preserve it even if cleanup␊
4079
+ // also fails, while retaining the cleanup error when the value is␊
4080
+ // extensible and has no existing cause.␊
4081
+ __attachCleanupError(␊
4082
+ __registrationFailed ? __registrationError : error,␊
4083
+ disposeError,␊
4084
+ )␊
4085
+ try {␊
4086
+ __registerManagedBeforeExitListener()␊
4087
+ } catch {}␊
4088
+ }␊
4089
+ throw error␊
4090
+ }␊
4091
+ }␊
4092
+ ␊
4093
+ /**␊
4094
+ * Create an independent instance. Call and await dispose() when the instance␊
4095
+ * is no longer needed so emnapi cleanup hooks run deterministically.␊
4096
+ *␊
4097
+ * The optional second argument selects this instance's linear memory: either␊
4098
+ * \`memory\` (an unshared, single-use WebAssembly.Memory you allocated) or␊
4099
+ * \`initialMemoryPages\` / \`maximumMemoryPages\`, never both. Omitted, the␊
4100
+ * loader allocates WASM_MEMORY.initialPages..WASM_MEMORY.maximumPages.␊
4101
+ *␊
4102
+ * A provided Memory must come from this loader's own realm: the WASI and␊
4103
+ * emnapi layers underneath identify one with a realm-local \`instanceof\`, so a␊
4104
+ * Memory built in a \`node:vm\` context or another frame is rejected. Every␊
4105
+ * Memory an instance runs on is single-use, the loader-allocated one included:␊
4106
+ * \`instance.memory\` cannot be recycled into a second \`createInstance()\`.␊
4107
+ */␊
4108
+ export async function createInstance(__wasmInput, __options) {␊
4109
+ return __createInstance(__wasmInput, __options)␊
4110
+ }␊
4111
+ ␊
4112
+ let __defaultModulePromise␊
4113
+ let __defaultInstancePromise␊
4114
+ let __defaultDisposePromise␊
4115
+ let __defaultDisposalStarted = false␊
4116
+ const __defaultManagedDestroyers = new WeakMap()␊
4117
+ let __moduleDisposePromise␊
4118
+ ␊
4119
+ /**␊
4120
+ * Instantiate a module-local singleton. Concurrent and repeated calls␊
4121
+ * with the same module share one instance and one Memory allocation.␊
4122
+ */␊
4123
+ export function instantiate(__wasmInput) {␊
4124
+ const __modulePromise = __resolveModule(__wasmInput)␊
4125
+ if (__moduleLifecycleDestroyDepth !== 0) {␊
4126
+ void __modulePromise.catch(() => {})␊
4127
+ return Promise.reject(__createLifecycleReentryError('instantiate'))␊
4128
+ }␊
4129
+ if (__moduleDisposePromise) {␊
4130
+ void __modulePromise.catch(() => {})␊
4131
+ return __moduleDisposePromise.then(() => instantiate(__modulePromise))␊
4132
+ }␊
4133
+ if (__defaultDisposalStarted) {␊
4134
+ // Observe rejected input immediately, but preserve lifecycle ordering and␊
4135
+ // error precedence by instantiating only after disposal succeeds. A failed␊
4136
+ // disposal retains the old instance only so its cleanup can be retried.␊
4137
+ void __modulePromise.catch(() => {})␊
4138
+ const __disposePromise = __defaultDisposePromise ?? dispose()␊
4139
+ return __disposePromise.then(() => instantiate(__modulePromise))␊
4140
+ }␊
4141
+ if (!__defaultInstancePromise) {␊
4142
+ __defaultModulePromise = __modulePromise␊
4143
+ const __instancePromise = __modulePromise.then((__module) =>␊
4144
+ __createInstance(␊
4145
+ __module,␊
4146
+ undefined,␊
4147
+ __disposeDefaultInstance,␊
4148
+ (__managedDestroyer) => {␊
4149
+ __defaultManagedDestroyers.set(␊
4150
+ __instancePromise,␊
4151
+ __managedDestroyer,␊
4152
+ )␊
4153
+ },␊
4154
+ ),␊
4155
+ )␊
4156
+ __defaultInstancePromise = __instancePromise␊
4157
+ void __instancePromise.catch(() => {␊
4158
+ if (__defaultInstancePromise === __instancePromise) {␊
4159
+ __defaultInstancePromise = undefined␊
4160
+ __defaultModulePromise = undefined␊
4161
+ }␊
4162
+ })␊
4163
+ return __instancePromise.then((__instance) => __instance.exports)␊
4164
+ }␊
4165
+ const __defaultModulePromiseForCall = __defaultModulePromise␊
4166
+ const __defaultInstancePromiseForCall = __defaultInstancePromise␊
4167
+ return Promise.all([__defaultModulePromiseForCall, __modulePromise]).then(␊
4168
+ async ([__defaultModule, __module]) => {␊
4169
+ if (__defaultModule !== __module) {␊
4170
+ throw new Error(␊
4171
+ 'instantiate() already owns a different WebAssembly.Module; call dispose() first or use createInstance() for independent instances.',␊
4172
+ )␊
4173
+ }␊
4174
+ return (await __defaultInstancePromiseForCall).exports␊
4175
+ },␊
4176
+ )␊
4177
+ }␊
4178
+ ␊
4179
+ async function __disposeDefaultInstance(__onDestroy) {␊
4180
+ if (__defaultDisposePromise) {␊
4181
+ return __defaultDisposePromise␊
4182
+ }␊
4183
+ const __instancePromise = __defaultInstancePromise␊
4184
+ if (!__instancePromise) {␊
4185
+ __defaultDisposalStarted = false␊
4186
+ return␊
4187
+ }␊
4188
+ __defaultDisposalStarted = true␊
4189
+ const __disposePromise = (async () => {␊
4190
+ let __instance␊
4191
+ try {␊
4192
+ __instance = await __instancePromise␊
4193
+ } catch (error) {␊
4194
+ const __managedDestroyer =␊
4195
+ __defaultManagedDestroyers.get(__instancePromise)␊
4196
+ if (__managedDestroyer) {␊
4197
+ __onDestroy?.(__managedDestroyer)␊
4198
+ }␊
4199
+ __defaultManagedDestroyers.delete(__instancePromise)␊
4200
+ throw error␊
4201
+ }␊
4202
+ const __managedDestroyer =␊
4203
+ __defaultManagedDestroyers.get(__instancePromise)␊
4204
+ if (__managedDestroyer) {␊
4205
+ __onDestroy?.(__managedDestroyer)␊
4206
+ }␊
4207
+ await __instance.dispose()␊
4208
+ if (__defaultInstancePromise === __instancePromise) {␊
4209
+ __defaultInstancePromise = undefined␊
4210
+ __defaultModulePromise = undefined␊
4211
+ __defaultDisposalStarted = false␊
4212
+ }␊
4213
+ __defaultManagedDestroyers.delete(__instancePromise)␊
4214
+ })()␊
4215
+ __defaultDisposePromise = __disposePromise␊
4216
+ try {␊
4217
+ await __disposePromise␊
4218
+ } finally {␊
4219
+ if (__defaultDisposePromise === __disposePromise) {␊
4220
+ __defaultDisposePromise = undefined␊
4221
+ }␊
4222
+ }␊
4223
+ }␊
4224
+ ␊
4225
+ async function __dispose() {␊
4226
+ let __defaultDisposeError␊
4227
+ let __defaultDisposeFailed = false␊
4228
+ let __attemptedDefaultDestroyer␊
4229
+ try {␊
4230
+ await __disposeDefaultInstance((__destroyer) => {␊
4231
+ __attemptedDefaultDestroyer = __destroyer␊
4232
+ })␊
4233
+ } catch (error) {␊
4234
+ __defaultDisposeError = error␊
4235
+ __defaultDisposeFailed = true␊
4236
+ }␊
4237
+ const __excludedDestroyers = new Set()␊
4238
+ if (__defaultDisposeFailed && __attemptedDefaultDestroyer) {␊
4239
+ __excludedDestroyers.add(__attemptedDefaultDestroyer)␊
4240
+ }␊
4241
+ try {␊
4242
+ await __drainManagedEmnapiContexts(__excludedDestroyers)␊
4243
+ } catch (error) {␊
4244
+ if (!__defaultDisposeFailed) {␊
4245
+ throw error␊
4246
+ }␊
4247
+ if (error !== __defaultDisposeError) {␊
4248
+ __attachCleanupError(__defaultDisposeError, error)␊
4249
+ }␊
4250
+ }␊
4251
+ if (__defaultDisposeFailed) {␊
4252
+ throw __defaultDisposeError␊
4253
+ }␊
4254
+ }␊
4255
+ ␊
4256
+ /**␊
4257
+ * Dispose the singleton created by instantiate(). A later call may create a␊
4258
+ * fresh instance, including from a different module. This also retries cleanup␊
4259
+ * retained after a failed initialization rollback.␊
4260
+ */␊
4261
+ export function dispose() {␊
4262
+ if (__moduleLifecycleDestroyDepth !== 0) {␊
4263
+ return Promise.reject(__createLifecycleReentryError('dispose'))␊
4264
+ }␊
4265
+ if (__moduleDisposePromise) {␊
4266
+ return __moduleDisposePromise␊
4267
+ }␊
4268
+ let __resolveDispose␊
4269
+ let __rejectDispose␊
4270
+ const __promise = new Promise((resolve, reject) => {␊
4271
+ __resolveDispose = resolve␊
4272
+ __rejectDispose = reject␊
4273
+ })␊
4274
+ __moduleDisposePromise = __promise␊
4275
+ void __dispose().then(__resolveDispose, __rejectDispose)␊
4276
+ void __promise.then(␊
4277
+ () => {␊
4278
+ if (__moduleDisposePromise === __promise) {␊
4279
+ __moduleDisposePromise = undefined␊
4280
+ }␊
4281
+ },␊
4282
+ () => {␊
4283
+ if (__moduleDisposePromise === __promise) {␊
4284
+ __moduleDisposePromise = undefined␊
4285
+ }␊
4286
+ },␊
4287
+ )␊
4288
+ return __promise␊
4289
+ }␊
4290
+ `
4291
+
4292
+ ## createWasiDeferredBrowserBinding with async-runtime hosts and buffer
4293
+
4294
+ > Snapshot 1
4295
+
4296
+ `import {␊
4297
+ emnapiAsyncWorkPlugin as __emnapiAsyncWorkPlugin,␊
4298
+ emnapiTSFNPlugin as __emnapiTSFNPlugin,␊
4299
+ instantiateNapiModule as __emnapiInstantiateNapiModule,␊
4300
+ WASI as __WASI,␊
4301
+ } from '@napi-rs/wasm-runtime'␊
4302
+ import { createContext as __emnapiCreateContext } from '@emnapi/runtime'␊
4303
+ import {␊
4304
+ registerWorkerdCurrentThreadTaskHost as __registerWorkerdCurrentThreadTaskHost,␊
4305
+ registerWorkerdTimerHost as __registerWorkerdTimerHost,␊
4306
+ } from '@napi-rs/async-runtime/workerd'␊
4307
+ import { Buffer } from 'buffer'␊
4308
+ ␊
4309
+ export const WASM_MEMORY = Object.freeze({␊
4310
+ initialPages: 1027,␊
4311
+ maximumPages: 65536,␊
4312
+ pageBytes: 65536,␊
4313
+ initialBytes: 1027 * 65536,␊
4314
+ maximumBytes: 65536 * 65536,␊
4315
+ })␊
4316
+ ␊
4317
+ let __createdInstances = 0␊
4318
+ let __liveInstances = 0␊
4319
+ ␊
4320
+ /**␊
4321
+ * Counters for instances created by THIS module evaluation, not process-wide:␊
4322
+ * a second bundled copy of this loader keeps its own. Only successfully␊
4323
+ * created instances are counted, and \`liveInstances\` drops when an instance's␊
4324
+ * \`dispose()\` resolves.␊
4325
+ *␊
4326
+ * \`declaredInitialMemoryBytes\` is declared address space, not a host's␊
4327
+ * committed-memory metric; pair it with host telemetry rather than treating it␊
4328
+ * as a quota.␊
4329
+ */␊
4330
+ export function getDeferredRuntimeStats() {␊
4331
+ return Object.freeze({␊
4332
+ createdInstances: __createdInstances,␊
4333
+ liveInstances: __liveInstances,␊
4334
+ declaredInitialMemoryBytes: WASM_MEMORY.initialBytes,␊
4335
+ })␊
4336
+ }␊
4337
+ ␊
4338
+ const __arrayBufferByteLengthGetter = Object.getOwnPropertyDescriptor(␊
4339
+ ArrayBuffer.prototype,␊
4340
+ 'byteLength',␊
4341
+ ).get␊
4342
+ const __memoryBufferGetter = Object.getOwnPropertyDescriptor(␊
4343
+ WebAssembly.Memory.prototype,␊
4344
+ 'buffer',␊
4345
+ ).get␊
4346
+ // One managed initialization per Memory, success or failure: an attempt that␊
4347
+ // throws may already have written into linear memory, so the bytes are not a␊
4348
+ // clean slate for a second instance. Module-local, like the counters above.␊
4349
+ const __claimedMemories = new WeakSet()␊
4350
+ ␊
4351
+ function __resolveInstanceMemory(__options) {␊
4352
+ const __provided = __options == null ? undefined : __options.memory␊
4353
+ if (__provided === undefined || __provided === null) {␊
4354
+ // Page counts are handed to the engine unvalidated: it already rejects a␊
4355
+ // negative, over-4GiB or below-maximum value with a precise message, and a␊
4356
+ // second set of bounds here would only drift from it.␊
4357
+ const __allocated = new WebAssembly.Memory({␊
4358
+ initial:␊
4359
+ __options != null && __options.initialMemoryPages !== undefined␊
4360
+ ? __options.initialMemoryPages␊
4361
+ : WASM_MEMORY.initialPages,␊
4362
+ maximum:␊
4363
+ __options != null && __options.maximumMemoryPages !== undefined␊
4364
+ ? __options.maximumMemoryPages␊
4365
+ : WASM_MEMORY.maximumPages,␊
4366
+ })␊
4367
+ // Claimed like a caller-provided one. The handle publishes it as␊
4368
+ // \`instance.memory\`, so handing it back to \`createInstance()\` is as easy␊
4369
+ // as passing your own twice, and it would put two live instances on one␊
4370
+ // linear memory: each initialization rewrites the emnapi/WASI state the␊
4371
+ // other is still running on.␊
4372
+ __claimedMemories.add(__allocated)␊
4373
+ return __allocated␊
4374
+ }␊
4375
+ if (␊
4376
+ __options.initialMemoryPages !== undefined ||␊
4377
+ __options.maximumMemoryPages !== undefined␊
4378
+ ) {␊
4379
+ throw new TypeError(␊
4380
+ 'Pass either memory or initialMemoryPages/maximumMemoryPages, not both',␊
4381
+ )␊
4382
+ }␊
4383
+ let __buffer␊
4384
+ try {␊
4385
+ // Brand check: the getter throws for anything that is not a genuine␊
4386
+ // WebAssembly.Memory, including a cross-realm look-alike object.␊
4387
+ __buffer = Reflect.apply(__memoryBufferGetter, __provided, [])␊
4388
+ } catch {␊
4389
+ throw new TypeError('memory must be an unshared WebAssembly.Memory')␊
4390
+ }␊
4391
+ try {␊
4392
+ // Throws for a SharedArrayBuffer. This loader has no threads, and shared␊
4393
+ // growth does not detach: external views handed to the addon would␊
4394
+ // silently outlive the bytes they describe.␊
4395
+ Reflect.apply(__arrayBufferByteLengthGetter, __buffer, [])␊
4396
+ } catch {␊
4397
+ throw new TypeError(␊
4398
+ 'The deferred loader requires an unshared WebAssembly.Memory',␊
4399
+ )␊
4400
+ }␊
4401
+ // The intrinsic getters above accept a genuine Memory from ANY realm, but␊
4402
+ // the loader's dependencies do not: \`WASI.setMemory\` in␊
4403
+ // \`@napi-rs/wasm-runtime\` and emnapi identify a Memory with a realm-local␊
4404
+ // \`instanceof\`. A Memory built in another realm (a \`node:vm\` context, a␊
4405
+ // same-origin iframe) would pass every check here and only fail deep inside␊
4406
+ // initialization. Reject it up front, and before the claim below, so the␊
4407
+ // caller keeps it usable in the realm that made it.␊
4408
+ if (!(__provided instanceof WebAssembly.Memory)) {␊
4409
+ throw new TypeError(␊
4410
+ 'memory must be a WebAssembly.Memory created in the same realm as this loader',␊
4411
+ )␊
4412
+ }␊
4413
+ if (__claimedMemories.has(__provided)) {␊
4414
+ throw new TypeError(␊
4415
+ 'This WebAssembly.Memory has already been used for a deferred initialization attempt and cannot be reused, including after a failed initialization or a disposal',␊
4416
+ )␊
4417
+ }␊
4418
+ // Last step, after every check: a rejected option bag must leave the Memory␊
4419
+ // unclaimed, or a caller could not fix the call and retry with it.␊
4420
+ __claimedMemories.add(__provided)␊
4421
+ return __provided␊
4422
+ }␊
4423
+ ␊
4424
+ export const __napiBindingTarget = 'wasm32-wasip1'␊
4425
+ function __napiStampBindingTarget(exportsObject, target) {␊
4426
+ if (␊
4427
+ Object.prototype.hasOwnProperty.call(exportsObject, '__napiBindingTarget')␊
4428
+ ) {␊
4429
+ if (exportsObject.__napiBindingTarget === target) {␊
4430
+ // Already ours: the root entry aliases the object it loaded, so a WASI␊
4431
+ // fallback candidate — or a \`NAPI_RS_NATIVE_LIBRARY_PATH\` override that␊
4432
+ // is a generated loader — arrives already stamped with this same value.␊
4433
+ return target␊
4434
+ }␊
4435
+ const error = new Error(␊
4436
+ '\`__napiBindingTarget\` is reserved by the generated binding loader, but the loaded binding already exports it. Rename the export, e.g. #[napi(js_name = "...")].',␊
4437
+ )␊
4438
+ error.code = 'ERR_NAPI_BINDING_TARGET_CONFLICT'␊
4439
+ throw error␊
4440
+ }␊
4441
+ if (!Object.isExtensible(exportsObject)) {␊
4442
+ // A \`#[napi(module_exports)]\` hook may seal or freeze this object␊
4443
+ // (\`Object::seal\` / \`Object::freeze\`). Reporting the artifact is metadata,␊
4444
+ // never a reason to fail an otherwise successful load, so the stamp is␊
4445
+ // skipped. What a consumer still sees then follows the entry point: the␊
4446
+ // browser and deferred loaders declare \`__napiBindingTarget\` at module␊
4447
+ // level and go on reporting it, while the CommonJS entries hand back this␊
4448
+ // very object as \`module.exports\`, so there the value is absent.␊
4449
+ return target␊
4450
+ }␊
4451
+ try {␊
4452
+ // [[Define]], not [[Set]]: an ordinary assignment walks the prototype␊
4453
+ // chain, so an inherited accessor could swallow the value or throw and␊
4454
+ // fail an otherwise successful load. The descriptor is what a successful␊
4455
+ // assignment would have produced.␊
4456
+ Object.defineProperty(exportsObject, '__napiBindingTarget', {␊
4457
+ configurable: true,␊
4458
+ enumerable: true,␊
4459
+ value: target,␊
4460
+ writable: true,␊
4461
+ })␊
4462
+ } catch {␊
4463
+ // Same rule as the non-extensible skip above: reporting the artifact is␊
4464
+ // metadata, never a reason to fail an otherwise successful load. An exotic␊
4465
+ // object (a Proxy whose defineProperty trap refuses) is skipped, not␊
4466
+ // thrown over.␊
4467
+ }␊
4468
+ // The CommonJS loaders assign this return value so \`cjs-module-lexer\` — and␊
4469
+ // therefore Node's CJS -> ESM named export detection — can see␊
4470
+ // \`__napiBindingTarget\` statically.␊
4471
+ return target␊
4472
+ }␊
4473
+ ␊
4474
+ /**␊
4475
+ * Deferred, workerd-safe instantiation: no top-level I/O, no compile-from-bytes.␊
4476
+ * Accepts ONLY a precompiled WebAssembly.Module, or a Promise resolving to one␊
4477
+ * (e.g. \`import mod from './test-wasi.wasm'\` under a CompiledWasm␊
4478
+ * module rule / wrangler module import). Byte buffers, URLs and Response␊
4479
+ * objects are rejected: they require dynamic Wasm compilation, which␊
4480
+ * Cloudflare Workers disallows.␊
4481
+ */␊
4482
+ async function __resolveModule(__wasmInput) {␊
4483
+ const __module = await __wasmInput␊
4484
+ // Brand check, not \`instanceof\`: \`WebAssembly.Module.imports\` throws unless␊
4485
+ // its argument is a genuine WebAssembly.Module, so prototype-spoofed byte␊
4486
+ // buffers are rejected while cross-realm Module instances are accepted.␊
4487
+ try {␊
4488
+ WebAssembly.Module.imports(__module)␊
4489
+ } catch {␊
4490
+ throw new TypeError(␊
4491
+ "instantiate() and createInstance() expect a precompiled WebAssembly.Module (or a Promise resolving to one), " +␊
4492
+ "e.g. import mod from './test-wasi.wasm' under a CompiledWasm module rule / wrangler module import. " +␊
4493
+ "Byte buffers, URLs and Response objects require dynamic Wasm compilation, which Cloudflare Workers disallows.",␊
4494
+ )␊
4495
+ }␊
4496
+ return __module␊
4497
+ }␊
4498
+ ␊
4499
+ let __normalizedModules␊
4500
+ ␊
4501
+ function __rememberNormalizedModule(__module, __normalizedModule) {␊
4502
+ if (!__normalizedModules) {␊
4503
+ __normalizedModules = new WeakMap()␊
4504
+ }␊
4505
+ __normalizedModules.set(__module, __normalizedModule)␊
4506
+ return __normalizedModule␊
4507
+ }␊
4508
+ ␊
4509
+ async function __normalizeModuleForEmnapi(__module) {␊
4510
+ if (__module instanceof WebAssembly.Module) {␊
4511
+ return __module␊
4512
+ }␊
4513
+ if (__normalizedModules) {␊
4514
+ const __normalizedModule = __normalizedModules.get(__module)␊
4515
+ if (__normalizedModule) {␊
4516
+ return __normalizedModule␊
4517
+ }␊
4518
+ }␊
4519
+ // @emnapi/core currently performs realm-local \`instanceof\` checks after␊
4520
+ // accepting the module. Structured cloning preserves compiled code without␊
4521
+ // compiling bytes and produces a Module owned by the current realm.␊
4522
+ if (typeof structuredClone === 'function') {␊
4523
+ try {␊
4524
+ const __normalizedModule = structuredClone(__module)␊
4525
+ if (__normalizedModule instanceof WebAssembly.Module) {␊
4526
+ return __rememberNormalizedModule(__module, __normalizedModule)␊
4527
+ }␊
4528
+ } catch {}␊
4529
+ }␊
4530
+ // MessageChannel uses the same structured-clone semantics and covers older␊
4531
+ // browser/Node hosts that expose it but not the structuredClone function.␊
4532
+ if (typeof MessageChannel === 'function') {␊
4533
+ let __channel␊
4534
+ try {␊
4535
+ __channel = new MessageChannel()␊
4536
+ const __normalizedModule = await new Promise((resolve, reject) => {␊
4537
+ __channel.port1.onmessage = (event) => resolve(event.data)␊
4538
+ __channel.port1.onmessageerror = () =>␊
4539
+ reject(new TypeError('Failed to clone WebAssembly.Module'))␊
4540
+ try {␊
4541
+ __channel.port2.postMessage(__module)␊
4542
+ } catch (error) {␊
4543
+ reject(error)␊
4544
+ }␊
4545
+ })␊
4546
+ if (__normalizedModule instanceof WebAssembly.Module) {␊
4547
+ return __rememberNormalizedModule(__module, __normalizedModule)␊
4548
+ }␊
4549
+ } catch {␊
4550
+ } finally {␊
4551
+ try {␊
4552
+ __channel?.port1.close()␊
4553
+ } catch {}␊
4554
+ try {␊
4555
+ __channel?.port2.close()␊
4556
+ } catch {}␊
4557
+ }␊
4558
+ }␊
4559
+ // Last-resort compatibility for genuine, extensible foreign Modules.␊
4560
+ try {␊
4561
+ Object.setPrototypeOf(__module, WebAssembly.Module.prototype)␊
4562
+ } catch {}␊
4563
+ if (__module instanceof WebAssembly.Module) {␊
4564
+ return __module␊
4565
+ }␊
4566
+ throw new TypeError(␊
4567
+ 'This host cannot normalize a cross-realm WebAssembly.Module; ' +␊
4568
+ 'provide structuredClone or MessageChannel support.',␊
4569
+ )␊
4570
+ }␊
4571
+ ␊
4572
+ function __wrapEmnapiContextDestroyForSettlement(␊
4573
+ context,␊
4574
+ prepareEnvCleanup,␊
4575
+ isPreparingEnvCleanup,␊
4576
+ ) {␊
4577
+ let destroy␊
4578
+ try {␊
4579
+ destroy = context.destroy␊
4580
+ } catch {␊
4581
+ return context␊
4582
+ }␊
4583
+ if (typeof destroy !== 'function') {␊
4584
+ return context␊
4585
+ }␊
4586
+ try {␊
4587
+ Object.defineProperty(context, 'destroy', {␊
4588
+ configurable: true,␊
4589
+ enumerable: false,␊
4590
+ writable: true,␊
4591
+ value: function () {␊
4592
+ // Reentered from a promise hook that fired inside the barrier: the␊
4593
+ // frame running it destroys as soon as it returns.␊
4594
+ if (isPreparingEnvCleanup?.()) {␊
4595
+ return␊
4596
+ }␊
4597
+ prepareEnvCleanup?.()␊
4598
+ return Reflect.apply(destroy, this, arguments)␊
4599
+ },␊
4600
+ })␊
4601
+ } catch {}␊
4602
+ return context␊
4603
+ }␊
4604
+ ␊
4605
+ function __captureEmnapiAutoDestroyListener(__process) {␊
4606
+ if (␊
4607
+ !__process ||␊
4608
+ typeof __process.prependListener !== 'function' ||␊
4609
+ typeof __process.removeListener !== 'function'␊
4610
+ ) {␊
4611
+ return␊
4612
+ }␊
4613
+ let __autoDestroyListener␊
4614
+ const __captureListener = (__event, __listener) => {␊
4615
+ if (__event === 'beforeExit' && __autoDestroyListener === undefined) {␊
4616
+ __autoDestroyListener = __listener␊
4617
+ }␊
4618
+ }␊
4619
+ try {␊
4620
+ // Run before existing newListener hooks so a hook that registers its own␊
4621
+ // beforeExit listener cannot be mistaken for emnapi's registration.␊
4622
+ __process.prependListener('newListener', __captureListener)␊
4623
+ } catch {␊
4624
+ return␊
4625
+ }␊
4626
+ return () => {␊
4627
+ try {␊
4628
+ __process.removeListener('newListener', __captureListener)␊
4629
+ } catch {}␊
4630
+ if (__autoDestroyListener !== undefined) {␊
4631
+ try {␊
4632
+ __process.removeListener('beforeExit', __autoDestroyListener)␊
4633
+ } catch {}␊
4634
+ }␊
4635
+ }␊
4636
+ }␊
4637
+ ␊
4638
+ function __attachCleanupError(__error, __cleanupError) {␊
4639
+ try {␊
4640
+ if (␊
4641
+ __error &&␊
4642
+ (typeof __error === 'object' || typeof __error === 'function') &&␊
4643
+ __error.cause === undefined␊
4644
+ ) {␊
4645
+ __error.cause = __cleanupError␊
4646
+ }␊
4647
+ } catch {}␊
4648
+ }␊
4649
+ ␊
4650
+ // Mirror the primitive @emnapi/core schedules its threadsafe-function dispatch␊
4651
+ // on, so the drain turns below interleave with that dispatch instead of racing␊
4652
+ // ahead of it on a faster queue.␊
4653
+ const __scheduleMacrotask = (function () {␊
4654
+ if (typeof setImmediate === 'function') {␊
4655
+ return function (__callback) {␊
4656
+ setImmediate(__callback)␊
4657
+ }␊
4658
+ }␊
4659
+ const __MessageChannel = globalThis.MessageChannel␊
4660
+ if (typeof __MessageChannel === 'function') {␊
4661
+ return function (__callback) {␊
4662
+ const __channel = new __MessageChannel()␊
4663
+ __channel.port1.onmessage = function () {␊
4664
+ __channel.port1.onmessage = null␊
4665
+ try {␊
4666
+ __channel.port1.close()␊
4667
+ } catch {}␊
4668
+ try {␊
4669
+ __channel.port2.close()␊
4670
+ } catch {}␊
4671
+ __callback()␊
4672
+ }␊
4673
+ __channel.port2.postMessage(null)␊
4674
+ }␊
4675
+ }␊
4676
+ return function (__callback) {␊
4677
+ setTimeout(__callback, 0)␊
4678
+ }␊
4679
+ })()␊
4680
+ ␊
4681
+ // Turns to wait for while the addon still reports queued settlements. Reaching␊
4682
+ // zero is the only success. A counter still nonzero at this bound rejects the␊
4683
+ // disposal as retryable (\`ERR_NAPI_WASI_CLEANUP_PENDING\`) rather than␊
4684
+ // destroying the context over a still-queued settlement — the wait stays␊
4685
+ // bounded either way.␊
4686
+ const __WASM_ENV_CLEANUP_DRAIN_TURNS = 128␊
4687
+ // Without \`napi_wasm_env_cleanup_pending\` the queue is not observable. Fall␊
4688
+ // back to the number of turns @emnapi/core needs to coalesce and dispatch a␊
4689
+ // call made on this thread (two), plus a margin.␊
4690
+ const __WASM_ENV_CLEANUP_BLIND_DRAIN_TURNS = 4␊
4691
+ ␊
4692
+ /**␊
4693
+ * \`napi_prepare_wasm_env_cleanup\` only *queues* the promise settlements of the␊
4694
+ * tasks it cancelled: \`napi_call_threadsafe_function\` appends to the␊
4695
+ * threadsafe-function queue, and @emnapi/core dispatches that queue from a␊
4696
+ * macrotask — two coalescing turns later, even for a call made on this very␊
4697
+ * thread. \`Context.destroy()\` then runs the threadsafe function's cleanup hook,␊
4698
+ * which drains the queue with a null env and *discards* whatever is still in it.␊
4699
+ *␊
4700
+ * So destroying without yielding first strands exactly the promises the barrier␊
4701
+ * exists to settle. Yield real event-loop turns until the addon reports the␊
4702
+ * queue empty; microtask checkpoints cannot help, no number of them lets a␊
4703
+ * macrotask run.␊
4704
+ *␊
4705
+ * Returns nothing when there is nothing to wait for, which keeps disposal␊
4706
+ * synchronous in the common case.␊
4707
+ */␊
4708
+ function __drainWasmEnvCleanup(__instance) {␊
4709
+ const __pending = __instance?.exports.napi_wasm_env_cleanup_pending␊
4710
+ const __observable = typeof __pending === 'function'␊
4711
+ if (__observable) {␊
4712
+ let __queued␊
4713
+ try {␊
4714
+ __queued = __pending()␊
4715
+ } catch {␊
4716
+ return␊
4717
+ }␊
4718
+ if (!__queued) {␊
4719
+ return␊
4720
+ }␊
4721
+ }␊
4722
+ const __limit = __observable␊
4723
+ ? __WASM_ENV_CLEANUP_DRAIN_TURNS␊
4724
+ : __WASM_ENV_CLEANUP_BLIND_DRAIN_TURNS␊
4725
+ return (async () => {␊
4726
+ let __queued = 0␊
4727
+ for (let __turn = 0; __turn < __limit; __turn++) {␊
4728
+ await new Promise((resolve) => {␊
4729
+ __scheduleMacrotask(resolve)␊
4730
+ })␊
4731
+ if (!__observable) {␊
4732
+ continue␊
4733
+ }␊
4734
+ try {␊
4735
+ __queued = __pending()␊
4736
+ } catch {␊
4737
+ return␊
4738
+ }␊
4739
+ if (!__queued) {␊
4740
+ return␊
4741
+ }␊
4742
+ }␊
4743
+ if (!__observable) {␊
4744
+ // Blind wait: without \`napi_wasm_env_cleanup_pending\` the bound IS the␊
4745
+ // contract — there is nothing to consult, so finishing the turns is␊
4746
+ // finishing the drain.␊
4747
+ return␊
4748
+ }␊
4749
+ // The counter is still nonzero after every turn the bound allows. The wait␊
4750
+ // stays bounded — but claiming success here would be indistinguishable from␊
4751
+ // the stranding this drain exists to prevent: disposal would go on to␊
4752
+ // destroy the context, whose cleanup hook discards the still-queued␊
4753
+ // settlement with a null env, and the promise it was for hangs forever.␊
4754
+ // Reject instead, as a retryable cleanup failure: \`__prepareForDisposal\`␊
4755
+ // leaves its drained flag unset, dispose() (and the instantiation-failure␊
4756
+ // path) decline to destroy, and a later dispose() runs the drain again — by␊
4757
+ // which time the queue has usually been delivered. A counter that is␊
4758
+ // somehow stuck nonzero therefore costs each attempt at most another␊
4759
+ // bounded wait and a rejection, never a stranded promise; the managed␊
4760
+ // beforeExit destroyer still reclaims the context.␊
4761
+ const __drainError = new Error(␊
4762
+ 'the wasm environment still reports ' +␊
4763
+ __queued +␊
4764
+ ' queued settlement(s) after ' +␊
4765
+ __limit +␊
4766
+ ' event-loop turns; the context was not destroyed - retry dispose() to wait for the queue again',␊
4767
+ )␊
4768
+ __drainError.code = 'ERR_NAPI_WASI_CLEANUP_PENDING'␊
4769
+ throw __drainError␊
4770
+ })()␊
4771
+ }␊
4772
+ ␊
4773
+ function __createLifecycleReentryError(__operation) {␊
4774
+ const __error = new Error(␊
4775
+ __operation +␊
4776
+ '() cannot run while an emnapi Context.destroy() call is still active; await the original cleanup promise instead.',␊
4777
+ )␊
4778
+ __error.code = 'ERR_NAPI_WASI_LIFECYCLE_REENTRY'␊
4779
+ return __error␊
4780
+ }␊
4781
+ ␊
4782
+ const __managedEmnapiContextDestroyers = new Set()␊
4783
+ let __managedCleanupProcess␊
4784
+ let __managedBeforeExitListener␊
4785
+ let __managedDestroyPromise␊
4786
+ let __managedDestroyersInFlight␊
4787
+ let __managedBeforeExitRegistrationRetryCount = 0␊
4788
+ let __managedBeforeExitRegistrationRetryScheduled = false␊
4789
+ let __moduleLifecycleDestroyDepth = 0␊
4790
+ ␊
4791
+ function __removeManagedEmnapiCleanupListeners() {␊
4792
+ const __process = __managedCleanupProcess␊
4793
+ const __beforeExitListener = __managedBeforeExitListener␊
4794
+ __managedCleanupProcess = undefined␊
4795
+ __managedBeforeExitListener = undefined␊
4796
+ __managedBeforeExitRegistrationRetryCount = 0␊
4797
+ if (__process && __beforeExitListener) {␊
4798
+ try {␊
4799
+ __process.removeListener('beforeExit', __beforeExitListener)␊
4800
+ } catch {}␊
4801
+ }␊
4802
+ }␊
4803
+ ␊
4804
+ function __scheduleManagedBeforeExitListenerRegistration() {␊
4805
+ if (␊
4806
+ !__managedCleanupProcess ||␊
4807
+ __managedBeforeExitListener ||␊
4808
+ __managedEmnapiContextDestroyers.size === 0 ||␊
4809
+ __managedBeforeExitRegistrationRetryScheduled ||␊
4810
+ __managedBeforeExitRegistrationRetryCount >= 3␊
4811
+ ) {␊
4812
+ return␊
4813
+ }␊
4814
+ __managedBeforeExitRegistrationRetryScheduled = true␊
4815
+ __managedBeforeExitRegistrationRetryCount++␊
4816
+ queueMicrotask(() => {␊
4817
+ __managedBeforeExitRegistrationRetryScheduled = false␊
4818
+ if (␊
4819
+ !__managedCleanupProcess ||␊
4820
+ __managedBeforeExitListener ||␊
4821
+ __managedEmnapiContextDestroyers.size === 0␊
4822
+ ) {␊
4823
+ return␊
4824
+ }␊
4825
+ try {␊
4826
+ __registerManagedBeforeExitListener()␊
4827
+ } catch {}␊
4828
+ })␊
4829
+ }␊
4830
+ ␊
4831
+ function __registerManagedBeforeExitListener() {␊
4832
+ if (!__managedCleanupProcess || __managedBeforeExitListener) {␊
4833
+ return␊
4834
+ }␊
4835
+ try {␊
4836
+ __managedCleanupProcess.once(␊
4837
+ 'beforeExit',␊
4838
+ __destroyManagedEmnapiContextsBeforeExit,␊
4839
+ )␊
4840
+ } catch (error) {␊
4841
+ __scheduleManagedBeforeExitListenerRegistration()␊
4842
+ throw error␊
4843
+ }␊
4844
+ __managedBeforeExitListener = __destroyManagedEmnapiContextsBeforeExit␊
4845
+ __managedBeforeExitRegistrationRetryCount = 0␊
4846
+ }␊
4847
+ ␊
4848
+ function __settleManagedEmnapiContextDestroy(__promise) {␊
4849
+ if (__managedDestroyPromise === __promise) {␊
4850
+ __managedDestroyPromise = undefined␊
4851
+ __managedDestroyersInFlight = undefined␊
4852
+ }␊
4853
+ if (__managedEmnapiContextDestroyers.size === 0) {␊
4854
+ __removeManagedEmnapiCleanupListeners()␊
4855
+ return␊
4856
+ }␊
4857
+ try {␊
4858
+ __registerManagedBeforeExitListener()␊
4859
+ } catch {}␊
4860
+ }␊
4861
+ ␊
4862
+ function __destroyManagedEmnapiContexts(__excludedDestroyers) {␊
4863
+ if (__managedDestroyPromise) {␊
4864
+ return __managedDestroyPromise␊
4865
+ }␊
4866
+ const __destroyers = Array.from(__managedEmnapiContextDestroyers).filter(␊
4867
+ (__destroy) => !__excludedDestroyers?.has(__destroy),␊
4868
+ )␊
4869
+ if (__destroyers.length === 0) {␊
4870
+ return Promise.resolve()␊
4871
+ }␊
4872
+ let __resolveDestroy␊
4873
+ let __rejectDestroy␊
4874
+ const __promise = new Promise((resolve, reject) => {␊
4875
+ __resolveDestroy = resolve␊
4876
+ __rejectDestroy = reject␊
4877
+ })␊
4878
+ __managedDestroyPromise = __promise␊
4879
+ __managedDestroyersInFlight = new Set(__destroyers)␊
4880
+ void Promise.all(␊
4881
+ __destroyers.map((__destroy) => {␊
4882
+ try {␊
4883
+ return Promise.resolve(__destroy()).then(␊
4884
+ () => ({ failed: false }),␊
4885
+ (error) => ({ failed: true, error }),␊
4886
+ )␊
4887
+ } catch (error) {␊
4888
+ return { failed: true, error }␊
4889
+ }␊
4890
+ }),␊
4891
+ ).then((__results) => {␊
4892
+ let __primaryError␊
4893
+ let __failed = false␊
4894
+ for (const __result of __results) {␊
4895
+ if (!__result.failed) {␊
4896
+ continue␊
4897
+ }␊
4898
+ if (!__failed) {␊
4899
+ __failed = true␊
4900
+ __primaryError = __result.error␊
4901
+ } else {␊
4902
+ __attachCleanupError(__primaryError, __result.error)␊
4903
+ }␊
4904
+ }␊
4905
+ if (__failed) {␊
4906
+ __rejectDestroy(__primaryError)␊
4907
+ } else {␊
4908
+ __resolveDestroy()␊
4909
+ }␊
4910
+ }, __rejectDestroy)␊
4911
+ void __promise.then(␊
4912
+ () => {␊
4913
+ __settleManagedEmnapiContextDestroy(__promise)␊
4914
+ },␊
4915
+ () => {␊
4916
+ __settleManagedEmnapiContextDestroy(__promise)␊
4917
+ },␊
4918
+ )␊
4919
+ return __promise␊
4920
+ }␊
4921
+ ␊
4922
+ async function __drainManagedEmnapiContexts(__excludedDestroyers) {␊
4923
+ const __attemptedDestroyers = new Set(__excludedDestroyers)␊
4924
+ let __primaryError␊
4925
+ let __failed = false␊
4926
+ while (true) {␊
4927
+ let __promise = __managedDestroyPromise␊
4928
+ let __destroyers = __managedDestroyersInFlight␊
4929
+ if (!__promise) {␊
4930
+ __promise = __destroyManagedEmnapiContexts(__attemptedDestroyers)␊
4931
+ __destroyers = __managedDestroyersInFlight␊
4932
+ if (!__destroyers) {␊
4933
+ break␊
4934
+ }␊
4935
+ }␊
4936
+ for (const __destroy of __destroyers) {␊
4937
+ __attemptedDestroyers.add(__destroy)␊
4938
+ }␊
4939
+ try {␊
4940
+ await __promise␊
4941
+ } catch (error) {␊
4942
+ if (!__failed) {␊
4943
+ __failed = true␊
4944
+ __primaryError = error␊
4945
+ } else {␊
4946
+ __attachCleanupError(__primaryError, error)␊
4947
+ }␊
4948
+ }␊
4949
+ }␊
4950
+ if (__failed) {␊
4951
+ throw __primaryError␊
4952
+ }␊
4953
+ }␊
4954
+ ␊
4955
+ function __destroyManagedEmnapiContextsBeforeExit() {␊
4956
+ // A once listener is consumed before Node invokes it, including when another␊
4957
+ // cleanup batch is still pending.␊
4958
+ __managedBeforeExitListener = undefined␊
4959
+ if (__managedDestroyPromise) {␊
4960
+ return␊
4961
+ }␊
4962
+ void __destroyManagedEmnapiContexts().catch((error) => {␊
4963
+ queueMicrotask(() => {␊
4964
+ throw error␊
4965
+ })␊
4966
+ })␊
4967
+ }␊
4968
+ ␊
4969
+ function __registerManagedEmnapiContext(__process, __destroy) {␊
4970
+ __managedEmnapiContextDestroyers.add(__destroy)␊
4971
+ if (␊
4972
+ !__managedCleanupProcess &&␊
4973
+ __process &&␊
4974
+ typeof __process.once === 'function' &&␊
4975
+ typeof __process.removeListener === 'function'␊
4976
+ ) {␊
4977
+ __managedCleanupProcess = __process␊
4978
+ }␊
4979
+ let __registered = true␊
4980
+ return () => {␊
4981
+ if (!__registered) {␊
4982
+ return␊
4983
+ }␊
4984
+ __registered = false␊
4985
+ __managedEmnapiContextDestroyers.delete(__destroy)␊
4986
+ if (__managedEmnapiContextDestroyers.size === 0) {␊
4987
+ __removeManagedEmnapiCleanupListeners()␊
4988
+ }␊
4989
+ }␊
4990
+ }␊
4991
+ ␊
4992
+ async function __createManagedEmnapiContext(␊
4993
+ __prepareEnvCleanup,␊
4994
+ __isPreparingEnvCleanup,␊
4995
+ __disposeHosts,␊
4996
+ ) {␊
4997
+ const __process =␊
4998
+ typeof process === 'object' && process !== null ? process : undefined␊
4999
+ const __finishAutoDestroyCapture =␊
5000
+ __captureEmnapiAutoDestroyListener(__process)␊
5001
+ let __emnapiContext␊
5002
+ let __contextInitializationError␊
5003
+ let __contextInitializationFailed = false␊
5004
+ try {␊
5005
+ __emnapiContext = __wrapEmnapiContextDestroyForSettlement(␊
5006
+ __emnapiCreateContext({ autoDestroy: false }),␊
5007
+ __prepareEnvCleanup,␊
5008
+ __isPreparingEnvCleanup,␊
5009
+ )␊
5010
+ // emnapi 2.x still registers an unconditional process.once('beforeExit')␊
5011
+ // auto-destroy listener on Node hosts, and suppressDestroy() only␊
5012
+ // neutralizes its callback without removing it. This loader must stay␊
5013
+ // side-effect free per instance, so the listener is captured and removed;␊
5014
+ // suppressDestroy() remains the safety net when removal is unavailable.␊
5015
+ __emnapiContext.suppressDestroy()␊
5016
+ } catch (error) {␊
5017
+ __contextInitializationError = error␊
5018
+ __contextInitializationFailed = true␊
5019
+ } finally {␊
5020
+ // Remove only the exact emnapi callback captured above.␊
5021
+ __finishAutoDestroyCapture?.()␊
5022
+ }␊
5023
+ if (__emnapiContext === undefined) {␊
5024
+ throw __contextInitializationError␊
5025
+ }␊
5026
+ let __disposed = false␊
5027
+ let __destroying = false␊
5028
+ let __destroyPromise␊
5029
+ let __cleanupRegistered = false␊
5030
+ let __unregisterCleanup␊
5031
+ const __destroy = (__blocksModuleLifecycle = false) => {␊
5032
+ if (__disposed) {␊
5033
+ return␊
5034
+ }␊
5035
+ if (__destroying) {␊
5036
+ throw __createLifecycleReentryError('dispose')␊
5037
+ }␊
5038
+ if (__destroyPromise) {␊
5039
+ return __destroyPromise␊
5040
+ }␊
5041
+ __destroying = true␊
5042
+ let __result␊
5043
+ const __finishDestroyInvocation = () => {␊
5044
+ __destroying = false␊
5045
+ }␊
5046
+ const __finishModuleLifecycleDestroy = () => {␊
5047
+ if (__blocksModuleLifecycle) {␊
5048
+ __blocksModuleLifecycle = false␊
5049
+ __moduleLifecycleDestroyDepth--␊
5050
+ }␊
5051
+ }␊
5052
+ if (__blocksModuleLifecycle) {␊
5053
+ __moduleLifecycleDestroyDepth++␊
5054
+ }␊
5055
+ try {␊
5056
+ // Context.destroy() disables JS before cleanup hooks run, so settle␊
5057
+ // runtime-owned promises while this environment can still call JS.␊
5058
+ __prepareEnvCleanup?.()␊
5059
+ if (__isPreparingEnvCleanup?.()) {␊
5060
+ // Reached from inside the barrier, so \`Context.destroy()\` below would␊
5061
+ // hit the wrapper's in-flight no-op. Recording that as a completed␊
5062
+ // destroy is what makes the frame that *did* start the barrier skip the␊
5063
+ // real one afterwards, leaving the context retained with its cleanup␊
5064
+ // hooks unrun. Refuse instead: nothing is flagged, the context stays␊
5065
+ // registered for managed beforeExit cleanup, and a later destroy still␊
5066
+ // works. dispose() coalesces reentrancy before it can get here, so this␊
5067
+ // is the backstop for any other caller that manages to.␊
5068
+ throw __createLifecycleReentryError('dispose')␊
5069
+ }␊
5070
+ __disposeHosts?.()␊
5071
+ __result = __emnapiContext.destroy()␊
5072
+ } catch (error) {␊
5073
+ __finishDestroyInvocation()␊
5074
+ __finishModuleLifecycleDestroy()␊
5075
+ throw error␊
5076
+ }␊
5077
+ let __then␊
5078
+ try {␊
5079
+ if (␊
5080
+ __result !== null &&␊
5081
+ (typeof __result === 'object' || typeof __result === 'function')␊
5082
+ ) {␊
5083
+ __then = __result.then␊
5084
+ }␊
5085
+ } catch (error) {␊
5086
+ __finishDestroyInvocation()␊
5087
+ __finishModuleLifecycleDestroy()␊
5088
+ throw error␊
5089
+ }␊
5090
+ if (typeof __then === 'function') {␊
5091
+ let __resolveResult␊
5092
+ let __rejectResult␊
5093
+ const __resultPromise = new Promise((resolve, reject) => {␊
5094
+ __resolveResult = resolve␊
5095
+ __rejectResult = reject␊
5096
+ })␊
5097
+ const __promise = __resultPromise.then(␊
5098
+ (value) => {␊
5099
+ __finishDestroyInvocation()␊
5100
+ __finishModuleLifecycleDestroy()␊
5101
+ __disposed = true␊
5102
+ __destroyPromise = undefined␊
5103
+ __unregisterCleanup?.()␊
5104
+ return value␊
5105
+ },␊
5106
+ (error) => {␊
5107
+ __finishDestroyInvocation()␊
5108
+ __finishModuleLifecycleDestroy()␊
5109
+ __destroyPromise = undefined␊
5110
+ throw error␊
5111
+ },␊
5112
+ )␊
5113
+ __destroyPromise = __promise␊
5114
+ try {␊
5115
+ Reflect.apply(__then, __result, [__resolveResult, __rejectResult])␊
5116
+ } catch (error) {␊
5117
+ __rejectResult(error)␊
5118
+ }␊
5119
+ return __promise␊
5120
+ }␊
5121
+ __finishDestroyInvocation()␊
5122
+ __finishModuleLifecycleDestroy()␊
5123
+ __disposed = true␊
5124
+ __unregisterCleanup?.()␊
5125
+ }␊
5126
+ const __destroyForModuleLifecycle = () => __destroy(true)␊
5127
+ const __registerCleanup = (␊
5128
+ __beforeExitDestroy = __destroyForModuleLifecycle,␊
5129
+ ) => {␊
5130
+ if (__cleanupRegistered || __disposed) {␊
5131
+ return␊
5132
+ }␊
5133
+ __unregisterCleanup = __registerManagedEmnapiContext(␊
5134
+ __process,␊
5135
+ __beforeExitDestroy,␊
5136
+ )␊
5137
+ __cleanupRegistered = true␊
5138
+ __registerManagedBeforeExitListener()␊
5139
+ }␊
5140
+ if (__contextInitializationFailed) {␊
5141
+ let __registrationError␊
5142
+ let __registrationFailed = false␊
5143
+ try {␊
5144
+ __registerCleanup()␊
5145
+ } catch (error) {␊
5146
+ __attachCleanupError(__contextInitializationError, error)␊
5147
+ __registrationError = error␊
5148
+ __registrationFailed = true␊
5149
+ }␊
5150
+ try {␊
5151
+ await __destroyForModuleLifecycle()␊
5152
+ } catch (error) {␊
5153
+ __attachCleanupError(␊
5154
+ __registrationFailed␊
5155
+ ? __registrationError␊
5156
+ : __contextInitializationError,␊
5157
+ error,␊
5158
+ )␊
5159
+ try {␊
5160
+ __registerManagedBeforeExitListener()␊
5161
+ } catch {}␊
5162
+ }␊
5163
+ throw __contextInitializationError␊
5164
+ }␊
5165
+ return {␊
5166
+ context: __emnapiContext,␊
5167
+ destroy: __destroy,␊
5168
+ destroyForModuleLifecycle: __destroyForModuleLifecycle,␊
5169
+ registerCleanup: __registerCleanup,␊
5170
+ }␊
5171
+ }␊
5172
+ ␊
5173
+ async function __createInstance(␊
5174
+ __wasmInput,␊
5175
+ __options,␊
5176
+ __beforeExitDestroy,␊
5177
+ __onManagedDestroyer,␊
5178
+ ) {␊
5179
+ const __module = await __resolveModule(__wasmInput)␊
5180
+ const __emnapiModule = await __normalizeModuleForEmnapi(__module)␊
5181
+ const __wasi = new __WASI({␊
5182
+ version: 'preview1',␊
5183
+ })␊
5184
+ // The wasm module is linked with \`--import-memory\`, so a Memory must be␊
5185
+ // provided. It is resolved here in function scope (workerd bans global scope␊
5186
+ // allocation) and is never shared (no threads, no SharedArrayBuffer).␊
5187
+ // Resolve it before the emnapi context so a rejected option bag or a host␊
5188
+ // memory-limit failure cannot leak a context that never reaches␊
5189
+ // instantiation.␊
5190
+ const __wasmMemory = __resolveInstanceMemory(__options)␊
5191
+ let __lifecycleState = 'pending'␊
5192
+ let __destroyEmnapiContext␊
5193
+ let __destroyOwnedContext␊
5194
+ let __destroyManagedOwnedContext␊
5195
+ let __napiInstance␊
5196
+ let __disposeInstanceHosts␊
5197
+ const __reportInstanceHostDisposalError = (__error) => {␊
5198
+ try {␊
5199
+ const __consoleHost = globalThis.console␊
5200
+ if (__consoleHost && typeof __consoleHost.error === 'function') {␊
5201
+ __consoleHost.error(__error)␊
5202
+ }␊
5203
+ } catch {}␊
5204
+ }␊
5205
+ // Runs between the settlement drain and \`Context.destroy()\`; never throws,␊
5206
+ // for the same reason the eager loaders' disposer does not.␊
5207
+ const __disposeHostsBeforeDestroy = () => {␊
5208
+ const __dispose = __disposeInstanceHosts␊
5209
+ if (__dispose === undefined) {␊
5210
+ return␊
5211
+ }␊
5212
+ __disposeInstanceHosts = undefined␊
5213
+ __dispose()␊
5214
+ }␊
5215
+ let __wasmEnvCleanupRan = false␊
5216
+ let __wasmEnvCleanupPrepared = false␊
5217
+ let __wasmEnvCleanupPreparing = false␊
5218
+ let __wasmEnvCleanupDrained = false␊
5219
+ let __wasmEnvCleanupDrainPromise␊
5220
+ const __isPreparingEnvCleanup = () => __wasmEnvCleanupPreparing␊
5221
+ const __prepareEnvCleanup = () => {␊
5222
+ if (__wasmEnvCleanupPrepared || __wasmEnvCleanupPreparing) {␊
5223
+ return␊
5224
+ }␊
5225
+ const __prepareWasmEnvCleanup =␊
5226
+ __napiInstance?.exports.napi_prepare_wasm_env_cleanup␊
5227
+ if (typeof __prepareWasmEnvCleanup === 'function') {␊
5228
+ // The addon settles the promises it cancels synchronously, under a␊
5229
+ // non-reentrant lifecycle mutex: anything a promise hook calls from in␊
5230
+ // here must not reach this export again.␊
5231
+ __wasmEnvCleanupPreparing = true␊
5232
+ try {␊
5233
+ __prepareWasmEnvCleanup()␊
5234
+ } finally {␊
5235
+ __wasmEnvCleanupPreparing = false␊
5236
+ }␊
5237
+ __wasmEnvCleanupRan = true␊
5238
+ }␊
5239
+ __wasmEnvCleanupPrepared = true␊
5240
+ }␊
5241
+ // The barrier + settlement drain, hoisted out of the context destroyer so the␊
5242
+ // drain can yield without widening the destroyer's reentry window. Both␊
5243
+ // yielding paths run it — dispose() and the initialization-failure rollback.␊
5244
+ // The destroyer still runs the barrier itself (idempotently) for the one path␊
5245
+ // that cannot yield: managed beforeExit cleanup of an instance whose rollback␊
5246
+ // is being retried.␊
5247
+ //␊
5248
+ // "Drained" is recorded only once a wait has actually finished. Scheduling a␊
5249
+ // macrotask can fail — a host-provided or patched \`setImmediate\` that throws␊
5250
+ // is enough — and dispose() stays retryable after it rejects, so marking the␊
5251
+ // drain complete up front would make the retry skip it and destroy the context␊
5252
+ // with the barrier's settlements still queued.␊
5253
+ const __prepareForDisposal = () => {␊
5254
+ if (__wasmEnvCleanupDrained) {␊
5255
+ return␊
5256
+ }␊
5257
+ if (__wasmEnvCleanupDrainPromise) {␊
5258
+ return __wasmEnvCleanupDrainPromise␊
5259
+ }␊
5260
+ __prepareEnvCleanup()␊
5261
+ if (!__wasmEnvCleanupRan) {␊
5262
+ return␊
5263
+ }␊
5264
+ const __drained = __drainWasmEnvCleanup(__napiInstance)␊
5265
+ if (!__drained || typeof __drained.then !== 'function') {␊
5266
+ __wasmEnvCleanupDrained = true␊
5267
+ return␊
5268
+ }␊
5269
+ const __tracked = __drained.then(␊
5270
+ (__value) => {␊
5271
+ __wasmEnvCleanupDrained = true␊
5272
+ __wasmEnvCleanupDrainPromise = undefined␊
5273
+ return __value␊
5274
+ },␊
5275
+ (__error) => {␊
5276
+ __wasmEnvCleanupDrainPromise = undefined␊
5277
+ throw __error␊
5278
+ },␊
5279
+ )␊
5280
+ __wasmEnvCleanupDrainPromise = __tracked␊
5281
+ return __tracked␊
5282
+ }␊
5283
+ let __disposed = false␊
5284
+ const __runInstanceDisposal = async () => {␊
5285
+ if (__lifecycleState !== 'failed') {␊
5286
+ __lifecycleState = 'disposal'␊
5287
+ }␊
5288
+ // Settle what the barrier cancelled before the environment stops␊
5289
+ // accepting JavaScript calls. Undefined unless something is queued, so␊
5290
+ // an idle disposal is not delayed by a single turn.␊
5291
+ const __drained = __prepareForDisposal()␊
5292
+ if (__drained) {␊
5293
+ await __drained␊
5294
+ }␊
5295
+ const __result = await (__beforeExitDestroy␊
5296
+ ? __destroyManagedOwnedContext()␊
5297
+ : __destroyOwnedContext())␊
5298
+ // Only a completed destroy retires the instance; a throw above leaves␊
5299
+ // the counter untouched so a retried dispose() cannot double-decrement.␊
5300
+ if (!__disposed) {␊
5301
+ __disposed = true␊
5302
+ __liveInstances -= 1␊
5303
+ }␊
5304
+ return __result␊
5305
+ }␊
5306
+ let __instanceDisposePromise␊
5307
+ /**␊
5308
+ * The disposal frame runs the barrier, and the barrier settles the promises it␊
5309
+ * cancels synchronously — so a promise hook firing inside it can call this␊
5310
+ * same instance's dispose() again while the first call is still in its drain.␊
5311
+ * That nested call finds the barrier flagged in flight, prepares nothing,␊
5312
+ * drains nothing, and falls straight through to the context destroyer, whose␊
5313
+ * \`Context.destroy()\` hits the wrapper's in-flight no-op. It would record a␊
5314
+ * destruction that never happened, and the outer frame would then skip the␊
5315
+ * real one: both disposals resolve, no cleanup hook runs, the context stays␊
5316
+ * retained.␊
5317
+ *␊
5318
+ * Memoize before any of that starts, exactly like the eager loaders'␊
5319
+ * \`__disposeWasiBinding\`, so there is only ever one disposal frame per␊
5320
+ * instance and a reentrant caller awaits it instead of racing it. Cleared on␊
5321
+ * rejection: a drain that failed has to stay retryable.␊
5322
+ */␊
5323
+ const __disposeInstance = () => {␊
5324
+ if (__instanceDisposePromise) {␊
5325
+ return __instanceDisposePromise␊
5326
+ }␊
5327
+ let __resolveDispose␊
5328
+ let __rejectDispose␊
5329
+ const __disposePromise = new Promise((__resolve, __reject) => {␊
5330
+ __resolveDispose = __resolve␊
5331
+ __rejectDispose = __reject␊
5332
+ })␊
5333
+ __instanceDisposePromise = __disposePromise␊
5334
+ __runInstanceDisposal().then(__resolveDispose, (__error) => {␊
5335
+ __instanceDisposePromise = undefined␊
5336
+ __rejectDispose(__error)␊
5337
+ })␊
5338
+ return __disposePromise␊
5339
+ }␊
5340
+ const __destroyBeforeExit = __beforeExitDestroy␊
5341
+ ? async () => {␊
5342
+ if (__lifecycleState === 'failed') {␊
5343
+ await __destroyManagedOwnedContext()␊
5344
+ return␊
5345
+ }␊
5346
+ __lifecycleState = 'disposal'␊
5347
+ try {␊
5348
+ await __beforeExitDestroy()␊
5349
+ } catch (error) {␊
5350
+ if (__lifecycleState !== 'failed') {␊
5351
+ throw error␊
5352
+ }␊
5353
+ // The singleton's initialization rejection is already observable␊
5354
+ // through instantiate() and dispose(). Managed beforeExit cleanup␊
5355
+ // owns only context destruction, including retrying a failed rollback.␊
5356
+ await __destroyManagedOwnedContext()␊
5357
+ }␊
5358
+ }␊
5359
+ : undefined␊
5360
+ const {␊
5361
+ context: __emnapiContext,␊
5362
+ destroy,␊
5363
+ destroyForModuleLifecycle,␊
5364
+ registerCleanup: __registerCleanup,␊
5365
+ } = await __createManagedEmnapiContext(␊
5366
+ __prepareEnvCleanup,␊
5367
+ __isPreparingEnvCleanup,␊
5368
+ __disposeHostsBeforeDestroy,␊
5369
+ )␊
5370
+ __destroyEmnapiContext = destroy␊
5371
+ __destroyOwnedContext = () => __destroyEmnapiContext()␊
5372
+ __destroyManagedOwnedContext = destroyForModuleLifecycle␊
5373
+ try {␊
5374
+ if (__destroyBeforeExit) {␊
5375
+ __onManagedDestroyer(__destroyBeforeExit)␊
5376
+ await __registerCleanup(__destroyBeforeExit)␊
5377
+ }␊
5378
+ __emnapiContext.features.Buffer = Buffer␊
5379
+ let __napiModule␊
5380
+ ;({␊
5381
+ instance: __napiInstance,␊
5382
+ napiModule: __napiModule,␊
5383
+ } = await __emnapiInstantiateNapiModule(__emnapiModule, {␊
5384
+ context: __emnapiContext,␊
5385
+ asyncWorkPoolSize: 0,␊
5386
+ plugins: [__emnapiAsyncWorkPlugin, __emnapiTSFNPlugin],␊
5387
+ wasi: __wasi,␊
5388
+ overwriteImports(importObject) {␊
5389
+ importObject.env = {␊
5390
+ ...importObject.env,␊
5391
+ ...importObject.napi,␊
5392
+ ...importObject.emnapi,␊
5393
+ memory: __wasmMemory,␊
5394
+ }␊
5395
+ return importObject␊
5396
+ },␊
5397
+ beforeInit({ instance }) {␊
5398
+ __napiInstance = instance␊
5399
+ for (const name of Object.keys(instance.exports)) {␊
5400
+ if (name.startsWith('__napi_register__')) {␊
5401
+ instance.exports[name]()␊
5402
+ }␊
5403
+ }␊
5404
+ },␊
5405
+ }))␊
5406
+ const __disposeTaskHost = __registerWorkerdCurrentThreadTaskHost(␊
5407
+ __napiModule.exports,␊
5408
+ )␊
5409
+ try {␊
5410
+ const __disposeTimerHost = __registerWorkerdTimerHost(␊
5411
+ __napiModule.exports,␊
5412
+ )␊
5413
+ __disposeInstanceHosts = () => {␊
5414
+ try {␊
5415
+ __disposeTimerHost()␊
5416
+ } catch (__error) {␊
5417
+ __reportInstanceHostDisposalError(__error)␊
5418
+ }␊
5419
+ try {␊
5420
+ __disposeTaskHost()␊
5421
+ } catch (__error) {␊
5422
+ __reportInstanceHostDisposalError(__error)␊
5423
+ }␊
5424
+ }␊
5425
+ } catch (__error) {␊
5426
+ try {␊
5427
+ __disposeTaskHost()␊
5428
+ } catch (__cleanupError) {␊
5429
+ __attachCleanupError(__error, __cleanupError)␊
5430
+ }␊
5431
+ throw __error␊
5432
+ }␊
5433
+ // \`instantiate()\` and \`createInstance().exports\` hand out this object; a␊
5434
+ // named module export does not travel with it. After the instance host␊
5435
+ // install, which hands the same object to addon-provided registration␊
5436
+ // functions that may put anything on it, and inside this \`try\`, so a␊
5437
+ // claimed name flips \`__lifecycleState\` to 'failed' and tears the instance␊
5438
+ // down rather than escaping a half-built one.␊
5439
+ __napiStampBindingTarget(__napiModule.exports, __napiBindingTarget)␊
5440
+ if (__lifecycleState === 'pending') {␊
5441
+ __lifecycleState = 'succeeded'␊
5442
+ }␊
5443
+ __createdInstances += 1␊
5444
+ __liveInstances += 1␊
5445
+ return {␊
5446
+ exports: __napiModule.exports,␊
5447
+ get memory() {␊
5448
+ return __wasmMemory␊
5449
+ },␊
5450
+ get memoryBytes() {␊
5451
+ // The Memory outlives the environment, so this stays readable after a␊
5452
+ // FAILED dispose() (which leaves the instance undisposed and␊
5453
+ // retryable). It reports 0 only once disposal has actually completed.␊
5454
+ return __disposed ? 0 : __wasmMemory.buffer.byteLength␊
5455
+ },␊
5456
+ get disposed() {␊
5457
+ return __disposed␊
5458
+ },␊
5459
+ dispose: __disposeInstance,␊
5460
+ }␊
5461
+ } catch (error) {␊
5462
+ __lifecycleState = 'failed'␊
5463
+ // Instantiation can fail *after* registration has run, and registration runs␊
5464
+ // with a live environment: a module-init hook can start async work and then␊
5465
+ // return an error, and the promise it created may already have escaped into␊
5466
+ // JavaScript. Settle what the barrier cancels before the context is␊
5467
+ // destroyed, exactly like dispose() does; destroying without yielding␊
5468
+ // discards the queue with a null env. Undefined unless something is queued,␊
5469
+ // so a failure before beforeInit costs no extra turn.␊
5470
+ let __settlementsUnreached = false␊
5471
+ try {␊
5472
+ const __drained = __prepareForDisposal()␊
5473
+ if (__drained) {␊
5474
+ await __drained␊
5475
+ }␊
5476
+ } catch (drainError) {␊
5477
+ __attachCleanupError(error, drainError)␊
5478
+ __settlementsUnreached = true␊
5479
+ }␊
5480
+ let __registrationError␊
5481
+ let __registrationFailed = false␊
5482
+ if (!__beforeExitDestroy) {␊
5483
+ try {␊
5484
+ // Independent instances are caller-owned while pending and after␊
5485
+ // success. Register only failed rollback so cleanup remains retryable.␊
5486
+ await __registerCleanup()␊
5487
+ } catch (registrationError) {␊
5488
+ __attachCleanupError(error, registrationError)␊
5489
+ __registrationError = registrationError␊
5490
+ __registrationFailed = true␊
5491
+ }␊
5492
+ }␊
5493
+ if (__settlementsUnreached) {␊
5494
+ // The barrier or the drain did not finish, so the settlements it queued␊
5495
+ // are still in the threadsafe-function queue. Destroying now runs the␊
5496
+ // cleanup hook that drains that queue with a null env and discards it,␊
5497
+ // stranding a promise that already escaped into JavaScript — with nothing␊
5498
+ // left that could ever settle it. dispose() refuses to destroy for exactly␊
5499
+ // this reason (a rejected drain there never reaches the destroy), so this␊
5500
+ // path refuses too.␊
5501
+ //␊
5502
+ // Nothing leaks. The registration just above — and, for the singleton, the␊
5503
+ // one made before instantiation — leaves this context in␊
5504
+ // \`__managedEmnapiContextDestroyers\`, so beforeExit destroys it and␊
5505
+ // dispose() can retry it. Only the destruction is deferred, and the turns␊
5506
+ // that pass in the meantime are exactly what the queue needed.␊
5507
+ try {␊
5508
+ __registerManagedBeforeExitListener()␊
5509
+ } catch {}␊
5510
+ throw error␊
5511
+ }␊
5512
+ try {␊
5513
+ await __destroyManagedOwnedContext()␊
5514
+ } catch (disposeError) {␊
5515
+ // Initialization is the primary failure. Preserve it even if cleanup␊
5516
+ // also fails, while retaining the cleanup error when the value is␊
5517
+ // extensible and has no existing cause.␊
5518
+ __attachCleanupError(␊
5519
+ __registrationFailed ? __registrationError : error,␊
5520
+ disposeError,␊
5521
+ )␊
5522
+ try {␊
5523
+ __registerManagedBeforeExitListener()␊
5524
+ } catch {}␊
5525
+ }␊
5526
+ throw error␊
5527
+ }␊
5528
+ }␊
5529
+ ␊
5530
+ /**␊
5531
+ * Create an independent instance. Call and await dispose() when the instance␊
5532
+ * is no longer needed so emnapi cleanup hooks run deterministically.␊
5533
+ *␊
5534
+ * The optional second argument selects this instance's linear memory: either␊
5535
+ * \`memory\` (an unshared, single-use WebAssembly.Memory you allocated) or␊
5536
+ * \`initialMemoryPages\` / \`maximumMemoryPages\`, never both. Omitted, the␊
5537
+ * loader allocates WASM_MEMORY.initialPages..WASM_MEMORY.maximumPages.␊
5538
+ *␊
5539
+ * A provided Memory must come from this loader's own realm: the WASI and␊
5540
+ * emnapi layers underneath identify one with a realm-local \`instanceof\`, so a␊
5541
+ * Memory built in a \`node:vm\` context or another frame is rejected. Every␊
5542
+ * Memory an instance runs on is single-use, the loader-allocated one included:␊
5543
+ * \`instance.memory\` cannot be recycled into a second \`createInstance()\`.␊
5544
+ */␊
5545
+ export async function createInstance(__wasmInput, __options) {␊
5546
+ return __createInstance(__wasmInput, __options)␊
5547
+ }␊
5548
+ ␊
5549
+ let __defaultModulePromise␊
5550
+ let __defaultInstancePromise␊
5551
+ let __defaultDisposePromise␊
5552
+ let __defaultDisposalStarted = false␊
5553
+ const __defaultManagedDestroyers = new WeakMap()␊
5554
+ let __moduleDisposePromise␊
5555
+ ␊
5556
+ /**␊
5557
+ * Instantiate a module-local singleton. Concurrent and repeated calls␊
5558
+ * with the same module share one instance and one Memory allocation.␊
5559
+ */␊
5560
+ export function instantiate(__wasmInput) {␊
5561
+ const __modulePromise = __resolveModule(__wasmInput)␊
5562
+ if (__moduleLifecycleDestroyDepth !== 0) {␊
5563
+ void __modulePromise.catch(() => {})␊
5564
+ return Promise.reject(__createLifecycleReentryError('instantiate'))␊
5565
+ }␊
5566
+ if (__moduleDisposePromise) {␊
5567
+ void __modulePromise.catch(() => {})␊
5568
+ return __moduleDisposePromise.then(() => instantiate(__modulePromise))␊
5569
+ }␊
5570
+ if (__defaultDisposalStarted) {␊
5571
+ // Observe rejected input immediately, but preserve lifecycle ordering and␊
5572
+ // error precedence by instantiating only after disposal succeeds. A failed␊
5573
+ // disposal retains the old instance only so its cleanup can be retried.␊
5574
+ void __modulePromise.catch(() => {})␊
5575
+ const __disposePromise = __defaultDisposePromise ?? dispose()␊
5576
+ return __disposePromise.then(() => instantiate(__modulePromise))␊
5577
+ }␊
5578
+ if (!__defaultInstancePromise) {␊
5579
+ __defaultModulePromise = __modulePromise␊
5580
+ const __instancePromise = __modulePromise.then((__module) =>␊
5581
+ __createInstance(␊
5582
+ __module,␊
5583
+ undefined,␊
5584
+ __disposeDefaultInstance,␊
5585
+ (__managedDestroyer) => {␊
5586
+ __defaultManagedDestroyers.set(␊
5587
+ __instancePromise,␊
5588
+ __managedDestroyer,␊
5589
+ )␊
5590
+ },␊
5591
+ ),␊
5592
+ )␊
5593
+ __defaultInstancePromise = __instancePromise␊
5594
+ void __instancePromise.catch(() => {␊
5595
+ if (__defaultInstancePromise === __instancePromise) {␊
5596
+ __defaultInstancePromise = undefined␊
5597
+ __defaultModulePromise = undefined␊
5598
+ }␊
5599
+ })␊
5600
+ return __instancePromise.then((__instance) => __instance.exports)␊
5601
+ }␊
5602
+ const __defaultModulePromiseForCall = __defaultModulePromise␊
5603
+ const __defaultInstancePromiseForCall = __defaultInstancePromise␊
5604
+ return Promise.all([__defaultModulePromiseForCall, __modulePromise]).then(␊
5605
+ async ([__defaultModule, __module]) => {␊
5606
+ if (__defaultModule !== __module) {␊
5607
+ throw new Error(␊
5608
+ 'instantiate() already owns a different WebAssembly.Module; call dispose() first or use createInstance() for independent instances.',␊
5609
+ )␊
5610
+ }␊
5611
+ return (await __defaultInstancePromiseForCall).exports␊
5612
+ },␊
5613
+ )␊
5614
+ }␊
5615
+ ␊
5616
+ async function __disposeDefaultInstance(__onDestroy) {␊
5617
+ if (__defaultDisposePromise) {␊
5618
+ return __defaultDisposePromise␊
5619
+ }␊
5620
+ const __instancePromise = __defaultInstancePromise␊
5621
+ if (!__instancePromise) {␊
5622
+ __defaultDisposalStarted = false␊
5623
+ return␊
5624
+ }␊
5625
+ __defaultDisposalStarted = true␊
5626
+ const __disposePromise = (async () => {␊
5627
+ let __instance␊
5628
+ try {␊
5629
+ __instance = await __instancePromise␊
5630
+ } catch (error) {␊
5631
+ const __managedDestroyer =␊
5632
+ __defaultManagedDestroyers.get(__instancePromise)␊
5633
+ if (__managedDestroyer) {␊
5634
+ __onDestroy?.(__managedDestroyer)␊
5635
+ }␊
5636
+ __defaultManagedDestroyers.delete(__instancePromise)␊
5637
+ throw error␊
5638
+ }␊
5639
+ const __managedDestroyer =␊
5640
+ __defaultManagedDestroyers.get(__instancePromise)␊
5641
+ if (__managedDestroyer) {␊
5642
+ __onDestroy?.(__managedDestroyer)␊
5643
+ }␊
5644
+ await __instance.dispose()␊
5645
+ if (__defaultInstancePromise === __instancePromise) {␊
5646
+ __defaultInstancePromise = undefined␊
5647
+ __defaultModulePromise = undefined␊
5648
+ __defaultDisposalStarted = false␊
5649
+ }␊
5650
+ __defaultManagedDestroyers.delete(__instancePromise)␊
5651
+ })()␊
5652
+ __defaultDisposePromise = __disposePromise␊
5653
+ try {␊
5654
+ await __disposePromise␊
5655
+ } finally {␊
5656
+ if (__defaultDisposePromise === __disposePromise) {␊
5657
+ __defaultDisposePromise = undefined␊
5658
+ }␊
5659
+ }␊
5660
+ }␊
5661
+ ␊
5662
+ async function __dispose() {␊
5663
+ let __defaultDisposeError␊
5664
+ let __defaultDisposeFailed = false␊
5665
+ let __attemptedDefaultDestroyer␊
5666
+ try {␊
5667
+ await __disposeDefaultInstance((__destroyer) => {␊
5668
+ __attemptedDefaultDestroyer = __destroyer␊
5669
+ })␊
5670
+ } catch (error) {␊
5671
+ __defaultDisposeError = error␊
5672
+ __defaultDisposeFailed = true␊
5673
+ }␊
5674
+ const __excludedDestroyers = new Set()␊
5675
+ if (__defaultDisposeFailed && __attemptedDefaultDestroyer) {␊
5676
+ __excludedDestroyers.add(__attemptedDefaultDestroyer)␊
5677
+ }␊
5678
+ try {␊
5679
+ await __drainManagedEmnapiContexts(__excludedDestroyers)␊
5680
+ } catch (error) {␊
5681
+ if (!__defaultDisposeFailed) {␊
5682
+ throw error␊
5683
+ }␊
5684
+ if (error !== __defaultDisposeError) {␊
5685
+ __attachCleanupError(__defaultDisposeError, error)␊
5686
+ }␊
5687
+ }␊
5688
+ if (__defaultDisposeFailed) {␊
5689
+ throw __defaultDisposeError␊
5690
+ }␊
5691
+ }␊
5692
+ ␊
5693
+ /**␊
5694
+ * Dispose the singleton created by instantiate(). A later call may create a␊
5695
+ * fresh instance, including from a different module. This also retries cleanup␊
5696
+ * retained after a failed initialization rollback.␊
5697
+ */␊
5698
+ export function dispose() {␊
5699
+ if (__moduleLifecycleDestroyDepth !== 0) {␊
5700
+ return Promise.reject(__createLifecycleReentryError('dispose'))␊
5701
+ }␊
5702
+ if (__moduleDisposePromise) {␊
5703
+ return __moduleDisposePromise␊
5704
+ }␊
5705
+ let __resolveDispose␊
5706
+ let __rejectDispose␊
5707
+ const __promise = new Promise((resolve, reject) => {␊
5708
+ __resolveDispose = resolve␊
5709
+ __rejectDispose = reject␊
5710
+ })␊
5711
+ __moduleDisposePromise = __promise␊
5712
+ void __dispose().then(__resolveDispose, __rejectDispose)␊
5713
+ void __promise.then(␊
5714
+ () => {␊
5715
+ if (__moduleDisposePromise === __promise) {␊
5716
+ __moduleDisposePromise = undefined␊
5717
+ }␊
5718
+ },␊
5719
+ () => {␊
5720
+ if (__moduleDisposePromise === __promise) {␊
5721
+ __moduleDisposePromise = undefined␊
5722
+ }␊
5723
+ },␊
5724
+ )␊
5725
+ return __promise␊
5726
+ }␊
5727
+ `
5728
+
5729
+ ## createWasiDeferredBrowserBindingTypeDef
5730
+
5731
+ > Snapshot 1
5732
+
5733
+ `export type WasiBinding = typeof import('./test-wasi.wasip1.cjs')␊
5734
+ ␊
5735
+ export type WasiModuleInput =␊
5736
+ | WebAssembly.Module␊
5737
+ | PromiseLike<WebAssembly.Module>␊
5738
+ ␊
5739
+ /** Run the instance on a linear memory the caller allocated. */␊
5740
+ export interface WasiCallerMemoryOptions {␊
5741
+ /**␊
5742
+ * A caller-allocated linear memory for this instance. It must be unshared␊
5743
+ * and created in this loader's own realm — the WASI and emnapi layers␊
5744
+ * underneath identify a Memory with a realm-local \`instanceof\`, so one from␊
5745
+ * a \`node:vm\` context or another frame is rejected. It is single-use: once␊
5746
+ * a validated initialization attempt has begun, the same Memory cannot be␊
5747
+ * passed again — including after that attempt failed, and after the instance␊
5748
+ * was disposed.␊
5749
+ */␊
5750
+ memory: WebAssembly.Memory␊
5751
+ /** Not available beside \`memory\`: the loader allocates neither. */␊
5752
+ initialMemoryPages?: never␊
5753
+ /** Not available beside \`memory\`: the loader allocates neither. */␊
5754
+ maximumMemoryPages?: never␊
5755
+ }␊
5756
+ ␊
5757
+ /** Let the loader allocate the linear memory, optionally sized. */␊
5758
+ export interface WasiAllocatedMemoryOptions {␊
5759
+ /** Not available beside the page counts: they size the loader's own Memory. */␊
5760
+ memory?: never␊
5761
+ /** @default WASM_MEMORY.initialPages */␊
5762
+ initialMemoryPages?: number␊
5763
+ /** @default WASM_MEMORY.maximumPages */␊
5764
+ maximumMemoryPages?: number␊
5765
+ }␊
5766
+ ␊
5767
+ /**␊
5768
+ * Either memory form, never a mix of the two: the loader throws a TypeError␊
5769
+ * on \`memory\` beside a page count. \`{}\` and an omitted argument select the␊
5770
+ * loader defaults.␊
5771
+ */␊
5772
+ export type WasiInstanceOptions =␊
5773
+ | WasiCallerMemoryOptions␊
5774
+ | WasiAllocatedMemoryOptions␊
5775
+ ␊
5776
+ export interface WasiRuntimeStats {␊
5777
+ /** Instances created by this evaluated loader module, not process-wide. */␊
5778
+ createdInstances: number␊
5779
+ /** Created instances whose dispose() has not completed. */␊
5780
+ liveInstances: number␊
5781
+ /** Declared initial address space, not committed memory. */␊
5782
+ declaredInitialMemoryBytes: number␊
5783
+ }␊
5784
+ ␊
5785
+ export interface WasiInstance {␊
5786
+ readonly exports: WasiBinding␊
5787
+ /** This instance's linear memory. Claimed, so it cannot start another one. */␊
5788
+ readonly memory: WebAssembly.Memory␊
5789
+ /** Current linear-memory size; 0 once dispose() has completed. */␊
5790
+ readonly memoryBytes: number␊
5791
+ readonly disposed: boolean␊
5792
+ dispose(): Promise<void>␊
5793
+ }␊
5794
+ ␊
5795
+ /** The memory descriptor compiled into this loader. */␊
5796
+ export const WASM_MEMORY: Readonly<{␊
5797
+ initialPages: number␊
5798
+ maximumPages: number␊
5799
+ pageBytes: number␊
5800
+ initialBytes: number␊
5801
+ maximumBytes: number␊
5802
+ }>␊
5803
+ ␊
5804
+ export function getDeferredRuntimeStats(): Readonly<WasiRuntimeStats>␊
5805
+ ␊
5806
+ export function instantiate(wasmInput: WasiModuleInput): Promise<WasiBinding>␊
5807
+ export function createInstance(␊
5808
+ wasmInput: WasiModuleInput,␊
5809
+ options?: WasiInstanceOptions,␊
5810
+ ): Promise<WasiInstance>␊
5811
+ /** Dispose the singleton and retry retained failed-initialization cleanup. */␊
5812
+ export function dispose(): Promise<void>␊
5813
+ ␊
5814
+ /** The WASI flavor this deferred loader instantiates. */␊
5815
+ export declare const __napiBindingTarget: 'wasm32-wasip1'␊
5816
+ `
5817
+
5818
+ ## createWasiBrowserWorkerBinding default
5819
+
5820
+ > Snapshot 1
5821
+
5822
+ `import {␊
5823
+ instantiateNapiModuleSync,␊
5824
+ MessageHandler,␊
5825
+ WASI,␊
5826
+ emnapiAsyncWorkPlugin,␊
5827
+ emnapiTSFNPlugin,␊
5828
+ } from '@napi-rs/wasm-runtime'␊
5829
+ ␊
5830
+ const handler = new MessageHandler({␊
5831
+ onLoad({ wasmModule, wasmMemory }) {␊
5832
+ const wasi = new WASI({␊
5833
+ print: function () {␊
5834
+ // eslint-disable-next-line no-console␊
5835
+ console.log.apply(console, arguments)␊
5836
+ },␊
5837
+ printErr: function () {␊
5838
+ // eslint-disable-next-line no-console␊
5839
+ console.error.apply(console, arguments)␊
5840
+ },␊
5841
+ })␊
5842
+ return instantiateNapiModuleSync(wasmModule, {␊
5843
+ childThread: true,␊
5844
+ wasi,␊
5845
+ // The wasm links a "basic" emnapi archive (no C async-work /␊
5846
+ // threadsafe-function implementations), so every thread that␊
5847
+ // instantiates it must provide the JavaScript implementations␊
5848
+ // through the emnapi plugins.␊
5849
+ plugins: [emnapiAsyncWorkPlugin, emnapiTSFNPlugin],␊
5850
+ overwriteImports(importObject) {␊
5851
+ importObject.env = {␊
5852
+ ...importObject.env,␊
5853
+ ...importObject.napi,␊
5854
+ ...importObject.emnapi,␊
5855
+ memory: wasmMemory,␊
5856
+ }␊
5857
+ },␊
5858
+ })␊
5859
+ },␊
1908
5860
  })␊
1909
5861
  ␊
1910
5862
  globalThis.onmessage = function (e) {␊
@@ -1933,10 +5885,9 @@ Generated by [AVA](https://avajs.dev).
1933
5885
  // eslint-disable-next-line no-console␊
1934
5886
  console.log.apply(console, arguments)␊
1935
5887
  },␊
1936
- printErr: function() {␊
5888
+ printErr: function () {␊
1937
5889
  // eslint-disable-next-line no-console␊
1938
5890
  console.error.apply(console, arguments)␊
1939
- ␊
1940
5891
  errorOutputs.push([...arguments])␊
1941
5892
  },␊
1942
5893
  })␊
@@ -1998,10 +5949,9 @@ Generated by [AVA](https://avajs.dev).
1998
5949
  // eslint-disable-next-line no-console␊
1999
5950
  console.log.apply(console, arguments)␊
2000
5951
  },␊
2001
- printErr: function() {␊
5952
+ printErr: function () {␊
2002
5953
  // eslint-disable-next-line no-console␊
2003
5954
  console.error.apply(console, arguments)␊
2004
- ␊
2005
5955
  errorOutputs.push([...arguments])␊
2006
5956
  },␊
2007
5957
  })␊