relaxnative 0.1.2 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -10,12 +10,12 @@ import {
10
10
  removePackage,
11
11
  runNativeTests,
12
12
  updateIndex
13
- } from "./chunk-ZTBXEEMF.js";
13
+ } from "./chunk-2KRTGQYD.js";
14
14
  import {
15
15
  detectCompilers,
16
16
  getCacheRoot
17
- } from "./chunk-GVGWP3E2.js";
18
- import "./chunk-CRQZJC5B.js";
17
+ } from "./chunk-UGGUZN4H.js";
18
+ import "./chunk-HBO7F7P4.js";
19
19
  import "./chunk-LLZ4I4OR.js";
20
20
  import "./chunk-MLKGABMK.js";
21
21
 
@@ -64,6 +64,7 @@ Notes:
64
64
  - Trust levels: local (no prompts), community (warning + confirmation), verified (silent install, requires signature)
65
65
  - Add: pass --yes to make the command non-interactive (community installs will fail unless previously trusted)
66
66
  - Bench: pass --traditional to include a JS baseline when available (built-in for add)
67
+ - Bench: --traditional requires --baseline <path> + --args "[...]" so both JS and native get the same inputs
67
68
  `);
68
69
  }
69
70
  function fmtOk(msg) {
@@ -179,6 +180,7 @@ async function main() {
179
180
  const iterationsRaw = getFlagValue(process.argv, "--iterations");
180
181
  const warmupRaw = getFlagValue(process.argv, "--warmup");
181
182
  const argsRaw = getFlagValue(process.argv, "--args");
183
+ const jsBaselinePath = getFlagValue(process.argv, "--baseline");
182
184
  const json = hasFlag(process.argv, "--json");
183
185
  const traditional = hasFlag(process.argv, "--traditional");
184
186
  const confirm = hasFlag(process.argv, "--confirm");
@@ -203,6 +205,32 @@ async function main() {
203
205
  process.exit(1);
204
206
  }
205
207
  }
208
+ let baseline;
209
+ if (traditional) {
210
+ if (!jsBaselinePath) {
211
+ console.error("Missing --baseline <path>. Example: --baseline ./benchmarks/matmul.js");
212
+ process.exit(1);
213
+ }
214
+ try {
215
+ const mod = await import(jsBaselinePath);
216
+ baseline = mod?.default ?? mod?.baseline ?? mod?.fn;
217
+ if (typeof baseline !== "function") {
218
+ console.error(
219
+ "Invalid baseline module: expected a default export (or named export baseline/fn) that is a function."
220
+ );
221
+ process.exit(1);
222
+ }
223
+ } catch (e) {
224
+ console.error("Failed to import baseline module:", e?.message ?? String(e));
225
+ process.exit(1);
226
+ }
227
+ if (!Array.isArray(args)) {
228
+ console.error(
229
+ "When using --traditional you must also pass --args as a JSON array so the baseline and native get identical inputs."
230
+ );
231
+ process.exit(1);
232
+ }
233
+ }
206
234
  const iterations = iterationsRaw ? Number(iterationsRaw) : 5e4;
207
235
  const warmup = warmupRaw ? Number(warmupRaw) : 2e3;
208
236
  trace("bench parsed flags", { iterations, warmup, hasArgs: Array.isArray(args) });
@@ -225,7 +253,8 @@ async function main() {
225
253
  const res = await benchmarkCompareTraditionalVsRelaxnative(nativeFile, fnName, {
226
254
  iterations,
227
255
  warmup,
228
- args
256
+ args,
257
+ baseline
229
258
  });
230
259
  trace("bench traditional: done");
231
260
  if (json) console.log(JSON.stringify(res, null, 2));
package/dist/index.d.ts CHANGED
@@ -12,9 +12,22 @@ type RelaxConfig = {
12
12
  defaultMode?: ExecutionMode;
13
13
  };
14
14
  type IsolationMode = 'in-process' | 'worker' | 'process';
15
+ type NativeBuildOptions = {
16
+ /** Additional source files to compile+link into the same shared library (C/C++ only). */
17
+ sources?: string[];
18
+ /** Header search paths (-I). */
19
+ includePaths?: string[];
20
+ /** Library search paths (-L / /LIBPATH). */
21
+ libraryPaths?: string[];
22
+ /** Link libraries (-lfoo / foo.lib). */
23
+ libraries?: string[];
24
+ /** Additional raw compiler/linker flags. */
25
+ flags?: string[];
26
+ };
15
27
  declare function loadNative(sourcePath: string, options?: {
16
28
  config?: RelaxConfig;
17
29
  isolation?: IsolationMode;
30
+ build?: NativeBuildOptions;
18
31
  }): Promise<any>;
19
32
  /**
20
33
  * Advanced API: returns both the wrapped module and the computed bindings.
@@ -23,6 +36,7 @@ declare function loadNative(sourcePath: string, options?: {
23
36
  declare function loadNativeWithBindings(sourcePath: string, options?: {
24
37
  config?: RelaxConfig;
25
38
  isolation?: IsolationMode;
39
+ build?: NativeBuildOptions;
26
40
  mutateBindings?: (bindings: any) => void;
27
41
  }): Promise<{
28
42
  mod: any;
@@ -390,9 +404,27 @@ type CompilerInfo$1 = {
390
404
  type NativeLanguage = 'c' | 'cpp' | 'rust';
391
405
 
392
406
  type CompileRequest = {
407
+ /**
408
+ * Primary entry source file.
409
+ *
410
+ * For multi-file builds, `sourcePath` is used as the "entry" for:
411
+ * - language detection (C vs C++)
412
+ * - output library naming
413
+ *
414
+ * The full compilation inputs are `sourcePath` + `sources`.
415
+ */
393
416
  sourcePath: string;
417
+ /** Additional source files to compile and link into the same shared library. */
418
+ sources?: string[];
394
419
  outDir: string;
420
+ /** Additional raw compiler/linker flags (advanced escape hatch). */
395
421
  flags?: string[];
422
+ /** Header search paths (translated to -I). */
423
+ includePaths?: string[];
424
+ /** Library search paths (translated to -L). */
425
+ libraryPaths?: string[];
426
+ /** Libraries to link (translated to -l<name>). Example: ['m', 'pthread'] */
427
+ libraries?: string[];
396
428
  };
397
429
  type CompileResult = {
398
430
  language: NativeLanguage;
@@ -404,4 +436,4 @@ declare function compileNative(compiler: CompilerInfo$1, platform: PlatformInfo,
404
436
 
405
437
  declare function compileWithCache(compiler: CompilerInfo$1, platform: PlatformInfo, request: CompileRequest): CompileResult;
406
438
 
407
- export { type BenchmarkOptions, type BenchmarkResult, type ExecutionMode, type HotReloadHandle, type HotReloadOptions, type InstallOptions, type InstallResult, InvalidFreeError, type IsolationMode, MemoryError, type NativeAddress, NativeBuffer, NativePointer, type NativeTestCase, type NativeTestKind, type NativeTestResult, NullPointerError, type Ownership, type RawAllocation, type RelaxConfig, type TraditionalBenchmarkResult, UseAfterFreeError, alloc, allocRaw, benchmarkCompareSyncVsWorker, benchmarkCompareTraditionalVsRelaxnative, benchmarkJsFunction, benchmarkNativeFunction, compileNative, compileWithCache, detectCompilers, discoverNativeTestFiles, discoverNativeTests, discoverNativeTestsFromFile, formatBenchmarkCompare, formatBenchmarkResult, formatBenchmarkTraditionalCompare, formatNativeTestResults, free, freeRaw, getInstalledPackageDir, getProjectRoot, getRegistryRoot, getSourceLine, installPackage, installPackageEnforcingTrust, listPackages, loadNative, loadNativeDevHot, loadNativeWithBindings, loadRegistry, index as native, readRelaxJson, removePackage, resolveRegistryImport, runNativeTests, updateIndex };
439
+ export { type BenchmarkOptions, type BenchmarkResult, type ExecutionMode, type HotReloadHandle, type HotReloadOptions, type InstallOptions, type InstallResult, InvalidFreeError, type IsolationMode, MemoryError, type NativeAddress, NativeBuffer, type NativeBuildOptions, NativePointer, type NativeTestCase, type NativeTestKind, type NativeTestResult, NullPointerError, type Ownership, type RawAllocation, type RelaxConfig, type TraditionalBenchmarkResult, UseAfterFreeError, alloc, allocRaw, benchmarkCompareSyncVsWorker, benchmarkCompareTraditionalVsRelaxnative, benchmarkJsFunction, benchmarkNativeFunction, compileNative, compileWithCache, detectCompilers, discoverNativeTestFiles, discoverNativeTests, discoverNativeTestsFromFile, formatBenchmarkCompare, formatBenchmarkResult, formatBenchmarkTraditionalCompare, formatNativeTestResults, free, freeRaw, getInstalledPackageDir, getProjectRoot, getRegistryRoot, getSourceLine, installPackage, installPackageEnforcingTrust, listPackages, loadNative, loadNativeDevHot, loadNativeWithBindings, loadRegistry, index as native, readRelaxJson, removePackage, resolveRegistryImport, runNativeTests, updateIndex };
package/dist/index.js CHANGED
@@ -24,7 +24,7 @@ import {
24
24
  runNativeTests,
25
25
  trustPolicy,
26
26
  updateIndex
27
- } from "./chunk-ZTBXEEMF.js";
27
+ } from "./chunk-2KRTGQYD.js";
28
28
  import {
29
29
  alloc,
30
30
  allocRaw,
@@ -37,8 +37,8 @@ import {
37
37
  loadNativeDevHot,
38
38
  loadNativeWithBindings,
39
39
  memory_exports
40
- } from "./chunk-GVGWP3E2.js";
41
- import "./chunk-CRQZJC5B.js";
40
+ } from "./chunk-UGGUZN4H.js";
41
+ import "./chunk-HBO7F7P4.js";
42
42
  import {
43
43
  InvalidFreeError,
44
44
  MemoryError,
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  alloc,
3
3
  loadNative
4
- } from "../chunk-GVGWP3E2.js";
5
- import "../chunk-CRQZJC5B.js";
4
+ } from "../chunk-UGGUZN4H.js";
5
+ import "../chunk-HBO7F7P4.js";
6
6
  import "../chunk-LLZ4I4OR.js";
7
7
  import "../chunk-MLKGABMK.js";
8
8
 
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  wrapFunctions
3
- } from "../chunk-CRQZJC5B.js";
3
+ } from "../chunk-HBO7F7P4.js";
4
4
  import {
5
5
  loadFfi
6
6
  } from "../chunk-LLZ4I4OR.js";
@@ -75,6 +75,39 @@ import { createRequire as createRequire2 } from "module";
75
75
  function reply(msg) {
76
76
  if (process.send) process.send(msg);
77
77
  }
78
+ function reviveArg(a) {
79
+ if (!a || typeof a !== "object") return a;
80
+ if (a.__relaxnative_typedarray === true && a.bytes) {
81
+ const buf = Buffer.isBuffer(a.bytes) ? a.bytes : a.bytes?.type === "Buffer" && Array.isArray(a.bytes?.data) ? Buffer.from(a.bytes.data) : Array.isArray(a.bytes) ? Buffer.from(a.bytes) : Buffer.from([]);
82
+ const u8 = new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength);
83
+ const ab = u8.slice().buffer;
84
+ switch (a.type) {
85
+ case "Uint8Array":
86
+ return new Uint8Array(ab);
87
+ case "Int8Array":
88
+ return new Int8Array(ab);
89
+ case "Uint16Array":
90
+ return new Uint16Array(ab);
91
+ case "Int16Array":
92
+ return new Int16Array(ab);
93
+ case "Uint32Array":
94
+ return new Uint32Array(ab);
95
+ case "Int32Array":
96
+ return new Int32Array(ab);
97
+ case "BigInt64Array":
98
+ return new BigInt64Array(ab);
99
+ case "BigUint64Array":
100
+ return new BigUint64Array(ab);
101
+ case "Float32Array":
102
+ return new Float32Array(ab);
103
+ case "Float64Array":
104
+ return new Float64Array(ab);
105
+ default:
106
+ return new Uint8Array(ab);
107
+ }
108
+ }
109
+ return a;
110
+ }
78
111
  process.on("message", async (msg) => {
79
112
  try {
80
113
  if (!msg || typeof msg.id !== "number") return;
@@ -139,8 +172,22 @@ process.on("message", async (msg) => {
139
172
  return;
140
173
  }
141
174
  try {
142
- const result = await fn(...msg.args);
143
- reply({ id: msg.id, ok: true, result });
175
+ const boxedArgs = Array.isArray(msg.args) ? msg.args : [];
176
+ const revivedArgs = Array.isArray(msg.args) ? msg.args.map(reviveArg) : msg.args;
177
+ const result = await fn(...revivedArgs);
178
+ if (Array.isArray(revivedArgs) && Array.isArray(boxedArgs)) {
179
+ for (let i = 0; i < revivedArgs.length; i++) {
180
+ const revived = revivedArgs[i];
181
+ const boxed = boxedArgs[i];
182
+ if (boxed?.__relaxnative_typedarray === true && revived && ArrayBuffer.isView(revived)) {
183
+ const view = revived;
184
+ boxed.bytes = Buffer.from(
185
+ view.buffer.slice(view.byteOffset, view.byteOffset + view.byteLength)
186
+ );
187
+ }
188
+ }
189
+ }
190
+ reply({ id: msg.id, ok: true, result, args: boxedArgs });
144
191
  } finally {
145
192
  guards.restore();
146
193
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "relaxnative",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "type": "module",
5
5
  "description": "Zero-config native C/C++/Rust execution for Node.js",
6
6
  "license": "MIT",
@@ -37,9 +37,11 @@
37
37
  ],
38
38
  "scripts": {
39
39
  "build": "tsup src/index.ts src/cli.ts src/worker/workerEntry.ts src/worker/processEntry.ts src/esmLoader.ts src/memory/memory.selftest.ts --format esm --dts",
40
- "test": "vitest --run --pool=threads --maxWorkers=1",
41
- "test:inband": "vitest --run --pool=threads --maxWorkers=1",
42
- "test:native": "vitest --run --pool=threads --maxWorkers=1 src/memory/memory.test.ts",
40
+ "test": "vitest --run",
41
+ "test:inband": "vitest --run --pool=forks --maxWorkers=1",
42
+ "test:native": "vitest --run --pool=forks --maxWorkers=1 src/memory/memory.test.ts",
43
+ "test:threads": "vitest --run --pool=threads --maxWorkers=1",
44
+ "test:forks": "vitest --run --pool=forks --maxWorkers=1",
43
45
  "selftest:memory": "npm run build && node dist/memory/memory.selftest.js",
44
46
  "prepack": "npm run build",
45
47
  "release:beta": "npm publish --tag beta",