relaxnative 0.1.0-beta.1

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 (130) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +592 -0
  3. package/dist/chunk-22W76CYR.js +607 -0
  4. package/dist/chunk-24NXCU65.js +254 -0
  5. package/dist/chunk-2APMRURB.js +65 -0
  6. package/dist/chunk-2CHBHJPT.js +607 -0
  7. package/dist/chunk-2I4JHZI7.js +287 -0
  8. package/dist/chunk-2JOHYYQO.js +607 -0
  9. package/dist/chunk-3GW77EWF.js +505 -0
  10. package/dist/chunk-5J5CAKCD.js +266 -0
  11. package/dist/chunk-5NTDZ7YZ.js +377 -0
  12. package/dist/chunk-5TA6MROS.js +529 -0
  13. package/dist/chunk-5WVEBKMJ.js +1019 -0
  14. package/dist/chunk-6O5TIEEI.js +545 -0
  15. package/dist/chunk-6XU5DETO.js +896 -0
  16. package/dist/chunk-7BIZ6P3B.js +176 -0
  17. package/dist/chunk-7DKO777J.js +285 -0
  18. package/dist/chunk-7JYWUH4Y.js +268 -0
  19. package/dist/chunk-7NMCEP2V.js +756 -0
  20. package/dist/chunk-A7N4YBP2.js +379 -0
  21. package/dist/chunk-AZTCDV6R.js +572 -0
  22. package/dist/chunk-B34XEGM6.js +559 -0
  23. package/dist/chunk-BFHBLVXW.js +607 -0
  24. package/dist/chunk-BLOJ33LO.js +65 -0
  25. package/dist/chunk-BYPXCWTI.js +375 -0
  26. package/dist/chunk-C4KJD2AN.js +1044 -0
  27. package/dist/chunk-CJALJTRQ.js +814 -0
  28. package/dist/chunk-D4PK367Z.js +627 -0
  29. package/dist/chunk-DCWBZPEV.js +287 -0
  30. package/dist/chunk-DI7KSUEC.js +676 -0
  31. package/dist/chunk-DQ2KXIOO.js +665 -0
  32. package/dist/chunk-DV5STE3W.js +986 -0
  33. package/dist/chunk-EG5KNEKP.js +1027 -0
  34. package/dist/chunk-EOA2OWFA.js +1020 -0
  35. package/dist/chunk-ES3B6EZJ.js +56 -0
  36. package/dist/chunk-ETIXNPU5.js +741 -0
  37. package/dist/chunk-EUZBU2H7.js +824 -0
  38. package/dist/chunk-F6V7XDEB.js +150 -0
  39. package/dist/chunk-FNJKUFNF.js +1019 -0
  40. package/dist/chunk-FZB37DWL.js +453 -0
  41. package/dist/chunk-G3NDHZNZ.js +453 -0
  42. package/dist/chunk-G4YR34LE.js +410 -0
  43. package/dist/chunk-GU4XXISM.js +264 -0
  44. package/dist/chunk-GVPSQXGJ.js +1027 -0
  45. package/dist/chunk-HD5C4RNU.js +676 -0
  46. package/dist/chunk-HDIVY47T.js +287 -0
  47. package/dist/chunk-HFLRTDNK.js +985 -0
  48. package/dist/chunk-HGWRCVQ5.js +287 -0
  49. package/dist/chunk-HRG3SVKK.js +995 -0
  50. package/dist/chunk-HUGFULJ3.js +1027 -0
  51. package/dist/chunk-IDYSBXYS.js +344 -0
  52. package/dist/chunk-ISDDUQVI.js +1019 -0
  53. package/dist/chunk-IZ632ZCJ.js +286 -0
  54. package/dist/chunk-J5XI4L52.js +218 -0
  55. package/dist/chunk-JTIO7BUH.js +582 -0
  56. package/dist/chunk-JTWSFMF2.js +1020 -0
  57. package/dist/chunk-K5TV62T4.js +736 -0
  58. package/dist/chunk-K7MTG53V.js +985 -0
  59. package/dist/chunk-KGLZB3H2.js +676 -0
  60. package/dist/chunk-KYAB35P5.js +741 -0
  61. package/dist/chunk-KYDW3YVX.js +453 -0
  62. package/dist/chunk-L3MEMPRH.js +361 -0
  63. package/dist/chunk-LFTO3Z7N.js +757 -0
  64. package/dist/chunk-LLZ4I4OR.js +405 -0
  65. package/dist/chunk-LMRUM4U4.js +207 -0
  66. package/dist/chunk-LT5OGU6T.js +559 -0
  67. package/dist/chunk-LZQQOC3M.js +741 -0
  68. package/dist/chunk-LZYUNF6Q.js +1017 -0
  69. package/dist/chunk-MCTPVW4G.js +453 -0
  70. package/dist/chunk-MGLWXBIB.js +65 -0
  71. package/dist/chunk-MLKGABMK.js +9 -0
  72. package/dist/chunk-MTE6XDGC.js +541 -0
  73. package/dist/chunk-NDJUNDAE.js +676 -0
  74. package/dist/chunk-NG7SNFUD.js +1027 -0
  75. package/dist/chunk-ONVWKYK7.js +739 -0
  76. package/dist/chunk-OVMTFGE7.js +1042 -0
  77. package/dist/chunk-P5RQPRJ4.js +741 -0
  78. package/dist/chunk-PFABSW6Y.js +401 -0
  79. package/dist/chunk-PVVUJA2M.js +65 -0
  80. package/dist/chunk-Q3CDTGTX.js +676 -0
  81. package/dist/chunk-QKAKWDOQ.js +967 -0
  82. package/dist/chunk-QMPRDU6I.js +598 -0
  83. package/dist/chunk-R5U7XKVJ.js +16 -0
  84. package/dist/chunk-RB6RHB6C.js +254 -0
  85. package/dist/chunk-RD2K7ODW.js +175 -0
  86. package/dist/chunk-RHBHJND2.js +582 -0
  87. package/dist/chunk-RUP6POSE.js +453 -0
  88. package/dist/chunk-RYNSM23L.js +582 -0
  89. package/dist/chunk-S72S7XXS.js +255 -0
  90. package/dist/chunk-SDV5AAPW.js +213 -0
  91. package/dist/chunk-STXQPXUY.js +242 -0
  92. package/dist/chunk-TUSF5AEG.js +140 -0
  93. package/dist/chunk-V74SNTE6.js +736 -0
  94. package/dist/chunk-VHM5XETC.js +453 -0
  95. package/dist/chunk-VKQIXLNL.js +273 -0
  96. package/dist/chunk-VPG23Z7Y.js +545 -0
  97. package/dist/chunk-VSP234PR.js +627 -0
  98. package/dist/chunk-WH4JPUWF.js +598 -0
  99. package/dist/chunk-WLAUJL3K.js +409 -0
  100. package/dist/chunk-WXCN2QJ7.js +350 -0
  101. package/dist/chunk-X3JZKLJC.js +896 -0
  102. package/dist/chunk-X7SAP7FC.js +582 -0
  103. package/dist/chunk-XEH6PRYE.js +968 -0
  104. package/dist/chunk-XI65CAQV.js +211 -0
  105. package/dist/chunk-Y7OSHR6W.js +235 -0
  106. package/dist/chunk-YN4WUMVD.js +1020 -0
  107. package/dist/chunk-YUWJ2C4Y.js +1020 -0
  108. package/dist/chunk-YXLBPWNU.js +263 -0
  109. package/dist/chunk-YYJJHO7R.js +407 -0
  110. package/dist/chunk-Z2RBHUIH.js +757 -0
  111. package/dist/chunk-Z6G3KIOM.js +1027 -0
  112. package/dist/chunk-ZPPXCDSH.js +361 -0
  113. package/dist/chunk-ZRTY24SZ.js +582 -0
  114. package/dist/chunk-ZSDFBCQG.js +741 -0
  115. package/dist/cli.d.ts +1 -0
  116. package/dist/cli.js +339 -0
  117. package/dist/esmLoader.d.ts +10 -0
  118. package/dist/esmLoader.js +112 -0
  119. package/dist/index.d.ts +407 -0
  120. package/dist/index.js +126 -0
  121. package/dist/memory/memory.selftest.d.ts +2 -0
  122. package/dist/memory/memory.selftest.js +25 -0
  123. package/dist/worker/processEntry.d.ts +2 -0
  124. package/dist/worker/processEntry.js +160 -0
  125. package/dist/worker/workerEntry.d.ts +2 -0
  126. package/dist/worker/workerEntry.js +27 -0
  127. package/native/examples/add.c +6 -0
  128. package/native/examples/add_test.c +23 -0
  129. package/native/relaxnative_test.h +36 -0
  130. package/package.json +81 -0
@@ -0,0 +1,273 @@
1
+ // src/memory/memoryTypes.ts
2
+ var MemoryError = class extends Error {
3
+ name = "MemoryError";
4
+ };
5
+ var UseAfterFreeError = class extends MemoryError {
6
+ name = "UseAfterFreeError";
7
+ };
8
+ var InvalidFreeError = class extends MemoryError {
9
+ name = "InvalidFreeError";
10
+ };
11
+ var NullPointerError = class extends MemoryError {
12
+ name = "NullPointerError";
13
+ };
14
+
15
+ // src/memory/NativeBuffer.ts
16
+ import koffi from "koffi";
17
+ var kBrand = /* @__PURE__ */ Symbol.for("relaxnative.NativeBuffer");
18
+ var finalizer = typeof FinalizationRegistry !== "undefined" ? new FinalizationRegistry((held) => {
19
+ try {
20
+ koffi.free(held.handle);
21
+ } catch {
22
+ }
23
+ }) : null;
24
+ var NativeBuffer = class {
25
+ [kBrand] = true;
26
+ _handle;
27
+ _view;
28
+ _freed = false;
29
+ ownership;
30
+ constructor(allocation, opts) {
31
+ if (!allocation?.handle || !allocation?.view) {
32
+ throw new NullPointerError("NativeBuffer: missing allocation");
33
+ }
34
+ this._handle = allocation.handle;
35
+ this._view = allocation.view;
36
+ this.ownership = opts?.ownership ?? "js";
37
+ if (opts?.autoFree && this.ownership === "js") {
38
+ finalizer?.register(
39
+ this,
40
+ { handle: this._handle, addr: this.address },
41
+ this
42
+ );
43
+ }
44
+ }
45
+ get address() {
46
+ this.assertAlive();
47
+ const raw = koffi.address(this._handle);
48
+ const addr = typeof raw === "bigint" ? Number(raw) : raw;
49
+ if (!Number.isFinite(addr) || addr === 0) {
50
+ throw new NullPointerError(`NativeBuffer has null/invalid address: ${addr}`);
51
+ }
52
+ return addr;
53
+ }
54
+ get size() {
55
+ this.assertAlive();
56
+ return this._view.byteLength;
57
+ }
58
+ get freed() {
59
+ return this._freed;
60
+ }
61
+ assertAlive() {
62
+ if (this._freed) {
63
+ throw new UseAfterFreeError("Use-after-free: NativeBuffer was freed");
64
+ }
65
+ }
66
+ toUint8Array() {
67
+ this.assertAlive();
68
+ return this._view;
69
+ }
70
+ write(src, offset = 0) {
71
+ this.assertAlive();
72
+ if (!(src instanceof Uint8Array)) {
73
+ throw new TypeError("NativeBuffer.write(src): src must be a Uint8Array");
74
+ }
75
+ if (!Number.isInteger(offset) || offset < 0) {
76
+ throw new RangeError(`NativeBuffer.write: offset must be >= 0, got ${offset}`);
77
+ }
78
+ if (offset + src.byteLength > this._view.byteLength) {
79
+ throw new RangeError(
80
+ `NativeBuffer.write: write out of bounds (offset=${offset}, len=${src.byteLength}, size=${this._view.byteLength})`
81
+ );
82
+ }
83
+ this._view.set(src, offset);
84
+ }
85
+ free() {
86
+ if (this._freed) {
87
+ throw new InvalidFreeError("Double-free: NativeBuffer already freed");
88
+ }
89
+ if (this.ownership !== "js") {
90
+ throw new InvalidFreeError(
91
+ "Invalid free: NativeBuffer is native-owned"
92
+ );
93
+ }
94
+ finalizer?.unregister(this);
95
+ koffi.free(this._handle);
96
+ this._freed = true;
97
+ }
98
+ toJSON() {
99
+ return { address: this.address, size: this.size, ownership: this.ownership };
100
+ }
101
+ static isNativeBuffer(v) {
102
+ return !!v && v[kBrand] === true;
103
+ }
104
+ /**
105
+ * Return the koffi allocation handle.
106
+ *
107
+ * Important: passing raw numeric addresses to koffi is not reliably supported
108
+ * across platforms/Node versions and can segfault. The handle returned by
109
+ * `koffi.alloc()` is the safe thing to pass back into FFI calls.
110
+ */
111
+ toKoffiPointer() {
112
+ this.assertAlive();
113
+ return this._handle;
114
+ }
115
+ };
116
+
117
+ // src/memory/NativePointer.ts
118
+ import koffi2 from "koffi";
119
+ var kBrand2 = /* @__PURE__ */ Symbol.for("relaxnative.NativePointer");
120
+ var NativePointer = class {
121
+ [kBrand2] = true;
122
+ /** Opaque native address (number). */
123
+ address;
124
+ /** Size in bytes when known (0 means unknown). */
125
+ size;
126
+ /** Ownership of the pointee memory. */
127
+ ownership;
128
+ _freed = false;
129
+ constructor(opts) {
130
+ const address = opts.address;
131
+ if (!Number.isFinite(address) || address === 0) {
132
+ throw new NullPointerError(`Null/invalid native pointer address: ${address}`);
133
+ }
134
+ this.address = address;
135
+ this.size = opts.size ?? 0;
136
+ this.ownership = opts.ownership ?? "native";
137
+ }
138
+ get freed() {
139
+ return this._freed;
140
+ }
141
+ /**
142
+ * Marks this pointer as freed (used internally by NativeBuffer).
143
+ * This does *not* free underlying memory.
144
+ */
145
+ _markFreed() {
146
+ this._freed = true;
147
+ }
148
+ assertAlive() {
149
+ if (this._freed) {
150
+ throw new UseAfterFreeError(
151
+ `Use-after-free: pointer 0x${this.address.toString(16)} was freed`
152
+ );
153
+ }
154
+ }
155
+ /**
156
+ * Convert to the koffi pointer value.
157
+ *
158
+ * Note: numeric-address pointers are inherently less safe than passing a
159
+ * koffi External handle (like NativeBuffer does). Use NativePointer for
160
+ * borrowed/opaque pointers returned by native code.
161
+ */
162
+ toKoffiPointer() {
163
+ this.assertAlive();
164
+ return this.address;
165
+ }
166
+ static isNativePointer(v) {
167
+ return !!v && v[kBrand2] === true;
168
+ }
169
+ /**
170
+ * Convenience for koffi type declarations.
171
+ * Example: lib.func('foo', 'int', [NativePointer.koffiType()])
172
+ */
173
+ static koffiType() {
174
+ return koffi2.pointer("void");
175
+ }
176
+ };
177
+
178
+ // src/ffi/typeMap.ts
179
+ import koffi3 from "koffi";
180
+ function mapType(type) {
181
+ if (type == null) {
182
+ throw new Error("Unsupported native type: <undefined>");
183
+ }
184
+ if (/^pointer\s*<.+>$/i.test(type)) {
185
+ return koffi3.pointer("void");
186
+ }
187
+ switch (type) {
188
+ case "int":
189
+ return koffi3.types.int;
190
+ case "long":
191
+ return koffi3.types.int64;
192
+ case "float":
193
+ return koffi3.types.float;
194
+ case "double":
195
+ return koffi3.types.double;
196
+ case "char*":
197
+ return koffi3.types.cstring;
198
+ case "void":
199
+ return koffi3.types.void;
200
+ case "pointer":
201
+ return koffi3.pointer("void");
202
+ case "buffer":
203
+ return koffi3.pointer("void");
204
+ default:
205
+ throw new Error(`Unsupported native type: ${type}`);
206
+ }
207
+ }
208
+
209
+ // src/ffi/bindFunctions.ts
210
+ function bindFunctions(lib, bindings) {
211
+ const exports = {};
212
+ const functions = Array.isArray(bindings.functions) ? bindings.functions : Object.values(bindings.functions);
213
+ for (const fn of functions) {
214
+ if (!fn?.name || !fn?.returns || !Array.isArray(fn?.args)) {
215
+ throw new Error(
216
+ `Invalid FFI binding entry: ${JSON.stringify(fn)}. Expected {name, returns, args[]}.`
217
+ );
218
+ }
219
+ const returns = mapType(fn.returns);
220
+ const args = fn.args.map(mapType);
221
+ if (process.env.RELAXNATIVE_DEBUG_FFI === "1") {
222
+ console.log("[relaxnative ffi] bind", fn.name, { returns: fn.returns, args: fn.args });
223
+ }
224
+ const raw = lib.func(
225
+ fn.name,
226
+ returns,
227
+ args
228
+ );
229
+ exports[fn.name] = (...args2) => {
230
+ const mapped = args2.map((a) => {
231
+ if (NativeBuffer.isNativeBuffer(a)) return a.toKoffiPointer();
232
+ if (NativePointer.isNativePointer(a)) return a.toKoffiPointer();
233
+ if (a instanceof Uint8Array) return a;
234
+ return a;
235
+ });
236
+ const out = raw(...mapped);
237
+ if (fn.returns === "pointer" || /^pointer\s*<.+>$/i.test(fn.returns)) {
238
+ if (out == null) return out;
239
+ const rawAddr = out;
240
+ const addr = typeof rawAddr === "bigint" ? Number(rawAddr) : rawAddr;
241
+ return new NativePointer({ address: addr, ownership: "borrowed" });
242
+ }
243
+ return out;
244
+ };
245
+ }
246
+ return exports;
247
+ }
248
+
249
+ // src/ffi/createLibrary.ts
250
+ import koffi4 from "koffi";
251
+ function loadLibrary(libPath) {
252
+ try {
253
+ return koffi4.load(libPath);
254
+ } catch (err) {
255
+ throw new Error(`Failed to load native library: ${libPath}`);
256
+ }
257
+ }
258
+
259
+ // src/ffi/index.ts
260
+ function loadFfi(libPath, bindings) {
261
+ const lib = loadLibrary(libPath);
262
+ return bindFunctions(lib, bindings);
263
+ }
264
+
265
+ export {
266
+ MemoryError,
267
+ UseAfterFreeError,
268
+ InvalidFreeError,
269
+ NullPointerError,
270
+ NativeBuffer,
271
+ NativePointer,
272
+ loadFfi
273
+ };