mustardscript 0.1.0 → 0.1.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 (96) hide show
  1. package/README.md +62 -20
  2. package/SECURITY.md +1 -1
  3. package/dist/index.js +2 -0
  4. package/dist/lib/executor.js +16 -1
  5. package/dist/lib/policy.js +301 -22
  6. package/dist/lib/progress.js +499 -113
  7. package/dist/lib/runtime.js +109 -40
  8. package/dist/lib/structured.js +327 -11
  9. package/dist/native-loader.js +11 -12
  10. package/index.d.ts +54 -6
  11. package/mustard.d.ts +23 -1
  12. package/package.json +34 -25
  13. package/Cargo.lock +0 -1579
  14. package/Cargo.toml +0 -40
  15. package/crates/mustard/Cargo.toml +0 -31
  16. package/crates/mustard/src/cancellation.rs +0 -28
  17. package/crates/mustard/src/diagnostic.rs +0 -145
  18. package/crates/mustard/src/ir.rs +0 -435
  19. package/crates/mustard/src/lib.rs +0 -21
  20. package/crates/mustard/src/limits.rs +0 -22
  21. package/crates/mustard/src/parser/expressions.rs +0 -723
  22. package/crates/mustard/src/parser/mod.rs +0 -115
  23. package/crates/mustard/src/parser/operators.rs +0 -105
  24. package/crates/mustard/src/parser/patterns.rs +0 -123
  25. package/crates/mustard/src/parser/scope.rs +0 -107
  26. package/crates/mustard/src/parser/statements.rs +0 -298
  27. package/crates/mustard/src/parser/tests/acceptance.rs +0 -339
  28. package/crates/mustard/src/parser/tests/mod.rs +0 -2
  29. package/crates/mustard/src/parser/tests/rejections.rs +0 -107
  30. package/crates/mustard/src/runtime/accounting.rs +0 -613
  31. package/crates/mustard/src/runtime/api.rs +0 -192
  32. package/crates/mustard/src/runtime/async_runtime/mod.rs +0 -5
  33. package/crates/mustard/src/runtime/async_runtime/promises.rs +0 -246
  34. package/crates/mustard/src/runtime/async_runtime/reactions.rs +0 -400
  35. package/crates/mustard/src/runtime/async_runtime/scheduler.rs +0 -224
  36. package/crates/mustard/src/runtime/builtins/arrays.rs +0 -1205
  37. package/crates/mustard/src/runtime/builtins/collections.rs +0 -573
  38. package/crates/mustard/src/runtime/builtins/install.rs +0 -501
  39. package/crates/mustard/src/runtime/builtins/intl.rs +0 -553
  40. package/crates/mustard/src/runtime/builtins/mod.rs +0 -25
  41. package/crates/mustard/src/runtime/builtins/objects.rs +0 -405
  42. package/crates/mustard/src/runtime/builtins/primitives.rs +0 -859
  43. package/crates/mustard/src/runtime/builtins/promises.rs +0 -335
  44. package/crates/mustard/src/runtime/builtins/regexp.rs +0 -356
  45. package/crates/mustard/src/runtime/builtins/strings.rs +0 -803
  46. package/crates/mustard/src/runtime/builtins/support.rs +0 -561
  47. package/crates/mustard/src/runtime/bytecode.rs +0 -123
  48. package/crates/mustard/src/runtime/compiler/assignments.rs +0 -690
  49. package/crates/mustard/src/runtime/compiler/bindings.rs +0 -92
  50. package/crates/mustard/src/runtime/compiler/context.rs +0 -46
  51. package/crates/mustard/src/runtime/compiler/control.rs +0 -342
  52. package/crates/mustard/src/runtime/compiler/expressions.rs +0 -372
  53. package/crates/mustard/src/runtime/compiler/mod.rs +0 -173
  54. package/crates/mustard/src/runtime/compiler/statements.rs +0 -459
  55. package/crates/mustard/src/runtime/conversions/boundary.rs +0 -293
  56. package/crates/mustard/src/runtime/conversions/coercions.rs +0 -217
  57. package/crates/mustard/src/runtime/conversions/errors.rs +0 -118
  58. package/crates/mustard/src/runtime/conversions/mod.rs +0 -14
  59. package/crates/mustard/src/runtime/conversions/operators.rs +0 -334
  60. package/crates/mustard/src/runtime/env.rs +0 -355
  61. package/crates/mustard/src/runtime/exceptions.rs +0 -377
  62. package/crates/mustard/src/runtime/gc.rs +0 -595
  63. package/crates/mustard/src/runtime/mod.rs +0 -318
  64. package/crates/mustard/src/runtime/properties.rs +0 -1762
  65. package/crates/mustard/src/runtime/serialization.rs +0 -127
  66. package/crates/mustard/src/runtime/shared.rs +0 -108
  67. package/crates/mustard/src/runtime/snapshot_validation_tests.rs +0 -93
  68. package/crates/mustard/src/runtime/state.rs +0 -652
  69. package/crates/mustard/src/runtime/tests/async_host.rs +0 -104
  70. package/crates/mustard/src/runtime/tests/collections.rs +0 -50
  71. package/crates/mustard/src/runtime/tests/diagnostics.rs +0 -36
  72. package/crates/mustard/src/runtime/tests/exceptions.rs +0 -122
  73. package/crates/mustard/src/runtime/tests/execution.rs +0 -553
  74. package/crates/mustard/src/runtime/tests/gc.rs +0 -533
  75. package/crates/mustard/src/runtime/tests/mod.rs +0 -56
  76. package/crates/mustard/src/runtime/tests/serialization.rs +0 -170
  77. package/crates/mustard/src/runtime/validation/bytecode.rs +0 -484
  78. package/crates/mustard/src/runtime/validation/mod.rs +0 -14
  79. package/crates/mustard/src/runtime/validation/policy.rs +0 -94
  80. package/crates/mustard/src/runtime/validation/snapshot.rs +0 -406
  81. package/crates/mustard/src/runtime/validation/walk.rs +0 -206
  82. package/crates/mustard/src/runtime/vm.rs +0 -1016
  83. package/crates/mustard/src/span.rs +0 -22
  84. package/crates/mustard/src/structured.rs +0 -107
  85. package/crates/mustard-bridge/Cargo.toml +0 -17
  86. package/crates/mustard-bridge/src/codec.rs +0 -46
  87. package/crates/mustard-bridge/src/dto.rs +0 -99
  88. package/crates/mustard-bridge/src/lib.rs +0 -12
  89. package/crates/mustard-bridge/src/operations.rs +0 -142
  90. package/crates/mustard-node/Cargo.toml +0 -24
  91. package/crates/mustard-node/build.rs +0 -3
  92. package/crates/mustard-node/src/lib.rs +0 -236
  93. package/crates/mustard-sidecar/Cargo.toml +0 -21
  94. package/crates/mustard-sidecar/src/lib.rs +0 -134
  95. package/crates/mustard-sidecar/src/main.rs +0 -36
  96. package/dist/install.js +0 -117
@@ -7,71 +7,123 @@ const {
7
7
  throwIfAborted,
8
8
  withCancellationSignal,
9
9
  } = require('./cancellation.js');
10
+ const { resolveExecutionContext } = require('./policy.js');
10
11
  const {
11
- createExecutionPolicy,
12
- encodeSnapshotPolicy,
13
- snapshotIdentity,
14
- snapshotToken,
15
- } = require('./policy.js');
16
- const {
17
- encodeResumePayloadCancel,
18
- encodeResumePayloadError,
19
- encodeResumePayloadValue,
20
- encodeStartOptions,
12
+ encodeResumePayloadCancelBuffer,
13
+ encodeResumePayloadErrorBuffer,
14
+ encodeResumePayloadValueBuffer,
15
+ encodeStartOptionsBuffer,
16
+ encodeStructuredInputsBuffer,
21
17
  } = require('./structured.js');
22
18
 
23
19
  function createMustardClass({ native, materializeStep, parseStep }) {
20
+ const programHandleRegistry =
21
+ typeof FinalizationRegistry === 'function'
22
+ ? new FinalizationRegistry((programHandle) => {
23
+ try {
24
+ callNative(native.releaseProgram, programHandle);
25
+ } catch {
26
+ // Best-effort cleanup only; process shutdown can race native teardown.
27
+ }
28
+ })
29
+ : null;
30
+
24
31
  function compileProgram(code) {
25
32
  return callNative(native.compileProgram, code);
26
33
  }
27
34
 
35
+ function releaseProgram(programHandle) {
36
+ callNative(native.releaseProgram, programHandle);
37
+ }
38
+
28
39
  return class Mustard {
29
40
  constructor(code, options = {}) {
30
- this._program = compileProgram(code);
41
+ this._programHandle = compileProgram(code);
42
+ this._program = null;
31
43
  this._inputNames = options.inputs ?? [];
44
+ this._programHandleToken = {};
45
+ programHandleRegistry?.register(this, this._programHandle, this._programHandleToken);
32
46
  }
33
47
 
34
48
  static validateProgram(code) {
35
- compileProgram(code);
49
+ const programHandle = compileProgram(code);
50
+ releaseProgram(programHandle);
51
+ }
52
+
53
+ _ensureProgramHandle() {
54
+ if (this._programHandle !== null) {
55
+ return this._programHandle;
56
+ }
57
+ const programHandle = callNative(native.loadProgram, this._program);
58
+ this._programHandle = programHandle;
59
+ this._programHandleToken = {};
60
+ programHandleRegistry?.register(this, programHandle, this._programHandleToken);
61
+ return programHandle;
36
62
  }
37
63
 
38
64
  async run(options = {}) {
39
65
  const signal = getAbortSignal(options, 'run options');
40
66
  throwIfAborted(signal);
41
- const { hostHandlers, policy, snapshotKey } = createExecutionPolicy(options);
67
+ const { hostHandlers, policy, nativeContextHandle } = resolveExecutionContext(
68
+ options,
69
+ 'run options',
70
+ );
71
+ const programHandle = this._ensureProgramHandle();
72
+ const startProgram =
73
+ typeof nativeContextHandle === 'string' && nativeContextHandle.length > 0
74
+ ? native.startProgramWithExecutionContextHandleBuffer
75
+ : native.startProgramWithSnapshotHandleBuffer;
76
+ const startArgs =
77
+ typeof nativeContextHandle === 'string' && nativeContextHandle.length > 0
78
+ ? [programHandle, nativeContextHandle, encodeStructuredInputsBuffer(options.inputs)]
79
+ : [programHandle, encodeStartOptionsBuffer(options.inputs, policy)];
42
80
  let step = parseStep(
43
81
  withCancellationSignal(
44
82
  native,
45
- native.startProgram,
46
- [this._program, encodeStartOptions(options.inputs, policy)],
83
+ startProgram,
84
+ startArgs,
47
85
  signal,
48
86
  ),
49
87
  );
50
88
  while (step.type === 'suspended') {
51
- const capability = hostHandlers[step.capability];
52
- if (typeof capability !== 'function') {
53
- throw new Error(`Missing capability: ${step.capability}`);
54
- }
55
- const outcome = await settleCapabilityInvocation(capability, step.args, signal);
56
- const snapshotId = snapshotIdentity(step.snapshot);
57
- const policyJson = encodeSnapshotPolicy(policy, {
58
- snapshotId,
59
- snapshotKey,
60
- snapshotToken: snapshotToken(step.snapshot, snapshotKey, snapshotId),
61
- });
62
- if (outcome.type === 'cancelled') {
89
+ const snapshotHandle = step.snapshotHandle;
90
+ try {
91
+ const capability = hostHandlers[step.capability];
92
+ if (typeof capability !== 'function') {
93
+ throw new Error(`Missing capability: ${step.capability}`);
94
+ }
95
+ const outcome = await settleCapabilityInvocation(capability, step.args, signal);
96
+ if (outcome.type === 'cancelled') {
97
+ step = parseStep(
98
+ callNative(
99
+ native.resumeSnapshotHandleBuffer,
100
+ snapshotHandle,
101
+ encodeResumePayloadCancelBuffer(),
102
+ ),
103
+ );
104
+ continue;
105
+ }
106
+ const payload =
107
+ outcome.type === 'value'
108
+ ? encodeResumePayloadValueBuffer(outcome.value)
109
+ : encodeResumePayloadErrorBuffer(outcome.error);
63
110
  step = parseStep(
64
- callNative(native.resumeProgram, step.snapshot, encodeResumePayloadCancel(), policyJson),
111
+ withCancellationSignal(
112
+ native,
113
+ native.resumeSnapshotHandleBuffer,
114
+ [snapshotHandle, payload],
115
+ signal,
116
+ ),
65
117
  );
66
- continue;
118
+ } finally {
119
+ if (typeof snapshotHandle === 'string' && snapshotHandle.length > 0) {
120
+ try {
121
+ callNative(native.releaseSnapshotHandle, snapshotHandle);
122
+ } catch {
123
+ // Best-effort cleanup only.
124
+ }
125
+ }
67
126
  }
68
- const payload =
69
- outcome.type === 'value'
70
- ? encodeResumePayloadValue(outcome.value)
71
- : encodeResumePayloadError(outcome.error);
72
- step = parseStep(
73
- withCancellationSignal(native, native.resumeProgram, [step.snapshot, payload, policyJson], signal),
74
- );
75
127
  }
76
128
  return step.value;
77
129
  }
@@ -79,26 +131,43 @@ function createMustardClass({ native, materializeStep, parseStep }) {
79
131
  start(options = {}) {
80
132
  const signal = getAbortSignal(options, 'start options');
81
133
  throwIfAborted(signal);
82
- const { policy, snapshotKey } = createExecutionPolicy(options);
134
+ const { policy, snapshotKey, nativeContextHandle } = resolveExecutionContext(
135
+ options,
136
+ 'start options',
137
+ );
138
+ const programHandle = this._ensureProgramHandle();
139
+ const startProgram =
140
+ typeof nativeContextHandle === 'string' && nativeContextHandle.length > 0
141
+ ? native.startProgramWithExecutionContextHandleBuffer
142
+ : native.startProgramWithSnapshotHandleBuffer;
143
+ const startArgs =
144
+ typeof nativeContextHandle === 'string' && nativeContextHandle.length > 0
145
+ ? [programHandle, nativeContextHandle, encodeStructuredInputsBuffer(options.inputs)]
146
+ : [programHandle, encodeStartOptionsBuffer(options.inputs, policy)];
83
147
  const step = parseStep(
84
148
  withCancellationSignal(
85
149
  native,
86
- native.startProgram,
87
- [this._program, encodeStartOptions(options.inputs, policy)],
150
+ startProgram,
151
+ startArgs,
88
152
  signal,
89
153
  ),
90
154
  );
91
- return materializeStep(step, policy, snapshotKey);
155
+ return materializeStep(step, policy, snapshotKey, programHandle);
92
156
  }
93
157
 
94
158
  dump() {
159
+ if (this._program === null) {
160
+ this._program = Buffer.from(callNative(native.dumpProgram, this._ensureProgramHandle()));
161
+ }
95
162
  return Buffer.from(this._program);
96
163
  }
97
164
 
98
165
  static load(buffer) {
99
166
  const instance = Object.create(Mustard.prototype);
100
167
  instance._program = Buffer.from(buffer);
168
+ instance._programHandle = null;
101
169
  instance._inputNames = [];
170
+ instance._programHandleToken = {};
102
171
  return instance;
103
172
  }
104
173
  };
@@ -4,6 +4,104 @@ const { types } = require('node:util');
4
4
 
5
5
  const HOST_BOUNDARY_MAX_DEPTH = 128;
6
6
  const HOST_BOUNDARY_MAX_ARRAY_LENGTH = 1_000_000;
7
+ const encodedStartOptionsSuffixCache = new WeakMap();
8
+ const encodedStartOptionsBinarySuffixCache = new WeakMap();
9
+ const BOUNDARY_BINARY_MAGIC = Buffer.from([0x4d, 0x53, 0x42, 0x01]);
10
+ const BOUNDARY_BINARY_KIND = Object.freeze({
11
+ START_OPTIONS: 1,
12
+ STRUCTURED_INPUTS: 2,
13
+ RESUME_PAYLOAD: 3,
14
+ });
15
+ const STRUCTURED_BINARY_TAG = Object.freeze({
16
+ UNDEFINED: 0,
17
+ NULL: 1,
18
+ HOLE: 2,
19
+ BOOL_FALSE: 3,
20
+ BOOL_TRUE: 4,
21
+ STRING: 5,
22
+ NUMBER_FINITE: 6,
23
+ NUMBER_NAN: 7,
24
+ NUMBER_INFINITY: 8,
25
+ NUMBER_NEG_INFINITY: 9,
26
+ NUMBER_NEG_ZERO: 10,
27
+ ARRAY: 11,
28
+ OBJECT: 12,
29
+ });
30
+ const RESUME_BINARY_TAG = Object.freeze({
31
+ VALUE: 0,
32
+ ERROR: 1,
33
+ CANCELLED: 2,
34
+ });
35
+ const LIMIT_FIELD_LAYOUT = Object.freeze([
36
+ ['instruction_budget', 1 << 0],
37
+ ['heap_limit_bytes', 1 << 1],
38
+ ['allocation_budget', 1 << 2],
39
+ ['call_depth_limit', 1 << 3],
40
+ ['max_outstanding_host_calls', 1 << 4],
41
+ ]);
42
+
43
+ class BinaryWriter {
44
+ constructor(initialSize = 256) {
45
+ this._buffer = Buffer.allocUnsafe(initialSize);
46
+ this._offset = 0;
47
+ }
48
+
49
+ _ensureCapacity(additionalBytes) {
50
+ const required = this._offset + additionalBytes;
51
+ if (required <= this._buffer.length) {
52
+ return;
53
+ }
54
+ let nextLength = this._buffer.length;
55
+ while (nextLength < required) {
56
+ nextLength *= 2;
57
+ }
58
+ const nextBuffer = Buffer.allocUnsafe(nextLength);
59
+ this._buffer.copy(nextBuffer, 0, 0, this._offset);
60
+ this._buffer = nextBuffer;
61
+ }
62
+
63
+ writeHeader(kind) {
64
+ this.writeBuffer(BOUNDARY_BINARY_MAGIC);
65
+ this.writeU8(kind);
66
+ }
67
+
68
+ writeBuffer(value) {
69
+ const buffer = Buffer.from(value);
70
+ this._ensureCapacity(buffer.length);
71
+ buffer.copy(this._buffer, this._offset);
72
+ this._offset += buffer.length;
73
+ }
74
+
75
+ writeU8(value) {
76
+ this._ensureCapacity(1);
77
+ this._buffer.writeUInt8(value, this._offset);
78
+ this._offset += 1;
79
+ }
80
+
81
+ writeU32(value) {
82
+ this._ensureCapacity(4);
83
+ this._buffer.writeUInt32LE(value >>> 0, this._offset);
84
+ this._offset += 4;
85
+ }
86
+
87
+ writeF64(value) {
88
+ this._ensureCapacity(8);
89
+ this._buffer.writeDoubleLE(value, this._offset);
90
+ this._offset += 8;
91
+ }
92
+
93
+ writeString(value) {
94
+ const byteLength = Buffer.byteLength(value, 'utf8');
95
+ this.writeU32(byteLength);
96
+ this._ensureCapacity(byteLength);
97
+ this._buffer.write(value, this._offset, byteLength, 'utf8');
98
+ this._offset += byteLength;
99
+ }
100
+
101
+ toBuffer() {
102
+ return Buffer.from(this._buffer.subarray(0, this._offset));
103
+ }
104
+ }
7
105
 
8
106
  function assertBoundaryDepth(depth, label) {
9
107
  if (depth > HOST_BOUNDARY_MAX_DEPTH) {
@@ -73,15 +171,22 @@ function isAccessorDescriptor(descriptor) {
73
171
 
74
172
  function enumerateDataProperties(value) {
75
173
  assertNotProxy(value);
76
- return Object.entries(Object.getOwnPropertyDescriptors(value)).filter(([, descriptor]) => {
77
- if (!descriptor.enumerable) {
78
- return false;
174
+ const keys = Object.keys(value);
175
+ const entries = new Array(keys.length);
176
+ let entryCount = 0;
177
+ for (const key of keys) {
178
+ const descriptor = Object.getOwnPropertyDescriptor(value, key);
179
+ if (descriptor === undefined) {
180
+ continue;
79
181
  }
80
182
  if (isAccessorDescriptor(descriptor)) {
81
183
  throw new TypeError('host objects with accessors cannot cross the host boundary');
82
184
  }
83
- return true;
84
- });
185
+ entries[entryCount] = [key, descriptor];
186
+ entryCount += 1;
187
+ }
188
+ entries.length = entryCount;
189
+ return entries;
85
190
  }
86
191
 
87
192
  function enterStructuredTraversal(value, traversal) {
@@ -218,16 +323,178 @@ function decodeStructured(value, depth = 1) {
218
323
  throw new TypeError(`Unsupported structured value: ${JSON.stringify(value)}`);
219
324
  }
220
325
 
221
- function encodeStartOptions(inputs = {}, policy) {
326
+ function getEncodedStartOptionsSuffix(policy) {
327
+ let cached = encodedStartOptionsSuffixCache.get(policy);
328
+ if (cached !== undefined) {
329
+ return cached;
330
+ }
331
+ cached =
332
+ `,"capabilities":${JSON.stringify(policy.capabilities)}` +
333
+ `,"limits":${JSON.stringify(policy.limits)}}`;
334
+ encodedStartOptionsSuffixCache.set(policy, cached);
335
+ return cached;
336
+ }
337
+
338
+ function writeLimitValue(writer, value) {
339
+ writer.writeF64(value);
340
+ }
341
+
342
+ function writeEncodedLimits(writer, limits = {}) {
343
+ let mask = 0;
344
+ for (const [field, bit] of LIMIT_FIELD_LAYOUT) {
345
+ if (limits[field] !== undefined) {
346
+ mask |= bit;
347
+ }
348
+ }
349
+ writer.writeU8(mask);
350
+ for (const [field, bit] of LIMIT_FIELD_LAYOUT) {
351
+ if ((mask & bit) !== 0) {
352
+ writeLimitValue(writer, limits[field]);
353
+ }
354
+ }
355
+ }
356
+
357
+ function writeEncodedCapabilities(writer, capabilities = []) {
358
+ writer.writeU32(capabilities.length);
359
+ for (const capability of capabilities) {
360
+ writer.writeString(capability);
361
+ }
362
+ }
363
+
364
+ function getEncodedStartOptionsBinarySuffix(policy) {
365
+ let cached = encodedStartOptionsBinarySuffixCache.get(policy);
366
+ if (cached !== undefined) {
367
+ return cached;
368
+ }
369
+ const writer = new BinaryWriter();
370
+ writeEncodedCapabilities(writer, policy.capabilities);
371
+ writeEncodedLimits(writer, policy.limits);
372
+ cached = writer.toBuffer();
373
+ encodedStartOptionsBinarySuffixCache.set(policy, cached);
374
+ return cached;
375
+ }
376
+
377
+ function writeStructured(value, writer, traversal = { active: new WeakSet() }, depth = 1) {
378
+ assertBoundaryDepth(depth, 'host boundary');
379
+ if (value === undefined) {
380
+ writer.writeU8(STRUCTURED_BINARY_TAG.UNDEFINED);
381
+ return;
382
+ }
383
+ if (value === null) {
384
+ writer.writeU8(STRUCTURED_BINARY_TAG.NULL);
385
+ return;
386
+ }
387
+ if (typeof value === 'boolean') {
388
+ writer.writeU8(value ? STRUCTURED_BINARY_TAG.BOOL_TRUE : STRUCTURED_BINARY_TAG.BOOL_FALSE);
389
+ return;
390
+ }
391
+ if (typeof value === 'number') {
392
+ if (Number.isNaN(value)) {
393
+ writer.writeU8(STRUCTURED_BINARY_TAG.NUMBER_NAN);
394
+ return;
395
+ }
396
+ if (Object.is(value, -0)) {
397
+ writer.writeU8(STRUCTURED_BINARY_TAG.NUMBER_NEG_ZERO);
398
+ return;
399
+ }
400
+ if (value === Infinity) {
401
+ writer.writeU8(STRUCTURED_BINARY_TAG.NUMBER_INFINITY);
402
+ return;
403
+ }
404
+ if (value === -Infinity) {
405
+ writer.writeU8(STRUCTURED_BINARY_TAG.NUMBER_NEG_INFINITY);
406
+ return;
407
+ }
408
+ writer.writeU8(STRUCTURED_BINARY_TAG.NUMBER_FINITE);
409
+ writer.writeF64(value);
410
+ return;
411
+ }
412
+ if (typeof value === 'string') {
413
+ writer.writeU8(STRUCTURED_BINARY_TAG.STRING);
414
+ writer.writeString(value);
415
+ return;
416
+ }
417
+ if (Array.isArray(value)) {
418
+ assertNotProxy(value);
419
+ assertBoundaryArrayLength(value.length, 'host boundary');
420
+ writer.writeU8(STRUCTURED_BINARY_TAG.ARRAY);
421
+ writer.writeU32(value.length);
422
+ const leave = enterStructuredTraversal(value, traversal);
423
+ try {
424
+ for (let index = 0; index < value.length; index += 1) {
425
+ const descriptor = Object.getOwnPropertyDescriptor(value, String(index));
426
+ if (descriptor === undefined) {
427
+ writer.writeU8(STRUCTURED_BINARY_TAG.HOLE);
428
+ continue;
429
+ }
430
+ if (isAccessorDescriptor(descriptor)) {
431
+ throw new TypeError('host objects with accessors cannot cross the host boundary');
432
+ }
433
+ writeStructured(descriptor.value, writer, traversal, depth + 1);
434
+ }
435
+ } finally {
436
+ leave();
437
+ }
438
+ return;
439
+ }
440
+ if (typeof value === 'object') {
441
+ if (!isPlainStructuredObject(value)) {
442
+ throw new TypeError(
443
+ 'Unsupported host value: only plain objects and arrays can cross the host boundary',
444
+ );
445
+ }
446
+ writer.writeU8(STRUCTURED_BINARY_TAG.OBJECT);
447
+ const entries = enumerateDataProperties(value);
448
+ writer.writeU32(entries.length);
449
+ const leave = enterStructuredTraversal(value, traversal);
450
+ try {
451
+ for (const [key, descriptor] of entries) {
452
+ writer.writeString(key);
453
+ writeStructured(descriptor.value, writer, traversal, depth + 1);
454
+ }
455
+ } finally {
456
+ leave();
457
+ }
458
+ return;
459
+ }
460
+ throw new TypeError('Unsupported host value');
461
+ }
462
+
463
+ function writeStructuredInputEntries(writer, inputs = {}) {
464
+ const entries = enumerateDataProperties(inputs);
465
+ writer.writeU32(entries.length);
466
+ for (const [key, descriptor] of entries) {
467
+ writer.writeString(key);
468
+ writeStructured(descriptor.value, writer);
469
+ }
470
+ }
471
+
472
+ function encodeStructuredInputs(inputs = {}) {
222
473
  const encodedInputs = {};
223
474
  for (const [key, descriptor] of enumerateDataProperties(inputs)) {
224
475
  defineEnumerableProperty(encodedInputs, key, encodeStructured(descriptor.value));
225
476
  }
226
- return JSON.stringify({
227
- inputs: encodedInputs,
228
- capabilities: policy.capabilities,
229
- limits: policy.limits,
230
- });
477
+ return JSON.stringify(encodedInputs);
478
+ }
479
+
480
+ function encodeStartOptions(inputs = {}, policy) {
481
+ const encodedInputs = encodeStructuredInputs(inputs);
482
+ return `{"inputs":${encodedInputs}${getEncodedStartOptionsSuffix(policy)}`;
483
+ }
484
+
485
+ function encodeStructuredInputsBuffer(inputs = {}) {
486
+ const writer = new BinaryWriter();
487
+ writer.writeHeader(BOUNDARY_BINARY_KIND.STRUCTURED_INPUTS);
488
+ writeStructuredInputEntries(writer, inputs);
489
+ return writer.toBuffer();
490
+ }
491
+
492
+ function encodeStartOptionsBuffer(inputs = {}, policy) {
493
+ const writer = new BinaryWriter();
494
+ writer.writeHeader(BOUNDARY_BINARY_KIND.START_OPTIONS);
495
+ writeStructuredInputEntries(writer, inputs);
496
+ writer.writeBuffer(getEncodedStartOptionsBinarySuffix(policy));
497
+ return writer.toBuffer();
231
498
  }
232
499
 
233
500
  function encodeResumePayloadValue(value) {
@@ -237,6 +504,14 @@ function encodeResumePayloadValue(value) {
237
504
  });
238
505
  }
239
506
 
507
+ function encodeResumePayloadValueBuffer(value) {
508
+ const writer = new BinaryWriter();
509
+ writer.writeHeader(BOUNDARY_BINARY_KIND.RESUME_PAYLOAD);
510
+ writer.writeU8(RESUME_BINARY_TAG.VALUE);
511
+ writeStructured(value, writer);
512
+ return writer.toBuffer();
513
+ }
514
+
240
515
  function readOwnDataProperty(value, key, label) {
241
516
  const descriptor = Object.getOwnPropertyDescriptor(value, key);
242
517
  if (descriptor === undefined) {
@@ -266,19 +541,60 @@ function encodeResumePayloadError(error) {
266
541
  });
267
542
  }
268
543
 
544
+ function encodeResumePayloadErrorBuffer(error) {
545
+ const source = error instanceof Error ? error : Object(error);
546
+ assertNotProxy(source);
547
+ const name = readOwnDataProperty(source, 'name', 'host errors');
548
+ const message = readOwnDataProperty(source, 'message', 'host errors');
549
+ const code = readOwnDataProperty(source, 'code', 'host errors');
550
+ const details = readOwnDataProperty(source, 'details', 'host errors');
551
+ const writer = new BinaryWriter();
552
+ writer.writeHeader(BOUNDARY_BINARY_KIND.RESUME_PAYLOAD);
553
+ writer.writeU8(RESUME_BINARY_TAG.ERROR);
554
+ writer.writeString(typeof name === 'string' ? name : 'Error');
555
+ writer.writeString(typeof message === 'string' ? message : '');
556
+ if (typeof code === 'string') {
557
+ writer.writeU8(1);
558
+ writer.writeString(code);
559
+ } else {
560
+ writer.writeU8(0);
561
+ }
562
+ if (details === undefined) {
563
+ writer.writeU8(0);
564
+ } else {
565
+ writer.writeU8(1);
566
+ writeStructured(details, writer);
567
+ }
568
+ return writer.toBuffer();
569
+ }
570
+
269
571
  function encodeResumePayloadCancel() {
270
572
  return JSON.stringify({
271
573
  type: 'cancelled',
272
574
  });
273
575
  }
274
576
 
577
+ function encodeResumePayloadCancelBuffer() {
578
+ const writer = new BinaryWriter();
579
+ writer.writeHeader(BOUNDARY_BINARY_KIND.RESUME_PAYLOAD);
580
+ writer.writeU8(RESUME_BINARY_TAG.CANCELLED);
581
+ return writer.toBuffer();
582
+ }
583
+
275
584
  module.exports = {
585
+ BOUNDARY_BINARY_KIND,
276
586
  decodeStructured,
277
587
  defineEnumerableProperty,
278
588
  encodeResumePayloadCancel,
589
+ encodeResumePayloadCancelBuffer,
279
590
  encodeResumePayloadError,
591
+ encodeResumePayloadErrorBuffer,
280
592
  encodeResumePayloadValue,
593
+ encodeResumePayloadValueBuffer,
281
594
  encodeStartOptions,
595
+ encodeStartOptionsBuffer,
596
+ encodeStructuredInputs,
597
+ encodeStructuredInputsBuffer,
282
598
  encodeStructured,
283
599
  enumerateDataProperties,
284
600
  hasOwnProperty,
@@ -13,7 +13,7 @@ const PREBUILT_TARGETS = Object.freeze([
13
13
  platform: 'win32',
14
14
  arch: 'x64',
15
15
  platformArchABI: 'win32-x64-msvc',
16
- packageName: 'mustardscript-win32-x64-msvc',
16
+ packageName: '@mustardscript/binding-win32-x64-msvc',
17
17
  localFile: 'index.win32-x64-msvc.node',
18
18
  os: ['win32'],
19
19
  cpu: ['x64'],
@@ -23,7 +23,7 @@ const PREBUILT_TARGETS = Object.freeze([
23
23
  platform: 'darwin',
24
24
  arch: 'x64',
25
25
  platformArchABI: 'darwin-x64',
26
- packageName: 'mustardscript-darwin-x64',
26
+ packageName: '@mustardscript/binding-darwin-x64',
27
27
  localFile: 'index.darwin-x64.node',
28
28
  os: ['darwin'],
29
29
  cpu: ['x64'],
@@ -33,7 +33,7 @@ const PREBUILT_TARGETS = Object.freeze([
33
33
  platform: 'darwin',
34
34
  arch: 'arm64',
35
35
  platformArchABI: 'darwin-arm64',
36
- packageName: 'mustardscript-darwin-arm64',
36
+ packageName: '@mustardscript/binding-darwin-arm64',
37
37
  localFile: 'index.darwin-arm64.node',
38
38
  os: ['darwin'],
39
39
  cpu: ['arm64'],
@@ -43,7 +43,7 @@ const PREBUILT_TARGETS = Object.freeze([
43
43
  platform: 'linux',
44
44
  arch: 'x64',
45
45
  platformArchABI: 'linux-x64-gnu',
46
- packageName: 'mustardscript-linux-x64-gnu',
46
+ packageName: '@mustardscript/binding-linux-x64-gnu',
47
47
  localFile: 'index.linux-x64-gnu.node',
48
48
  os: ['linux'],
49
49
  cpu: ['x64'],
@@ -90,11 +90,7 @@ function getCurrentPrebuiltTarget() {
90
90
  }
91
91
 
92
92
  function getLocalBuildOutputFile() {
93
- return getCurrentPrebuiltTarget()?.localFile ?? 'index.node';
94
- }
95
-
96
- function getLocalBinaryFilenames() {
97
- return [...new Set([getLocalBuildOutputFile(), 'index.node'])];
93
+ return getCurrentPrebuiltTarget()?.localFile ?? null;
98
94
  }
99
95
 
100
96
  function validatePrebuiltPackageManifest(manifest, target, packageJsonPath) {
@@ -155,7 +151,11 @@ function localBinaryCandidates(searchRoot = packageRoot()) {
155
151
  continue;
156
152
  }
157
153
 
158
- for (const filename of getLocalBinaryFilenames()) {
154
+ const localFile = getLocalBuildOutputFile();
155
+ if (!localFile) {
156
+ continue;
157
+ }
158
+ for (const filename of [localFile]) {
159
159
  const candidate = path.join(root, filename);
160
160
  const stats = fs.statSync(candidate, { throwIfNoEntry: false });
161
161
  if (stats?.isFile()) {
@@ -211,14 +211,13 @@ function loadNative(options = {}) {
211
211
  : `${process.platform}-${process.arch}`;
212
212
  throw new AggregateError(
213
213
  loadErrors,
214
- `Unable to locate a MustardScript native addon for ${platformHint}. Install a matching optional prebuilt package or allow the source build to run.`,
214
+ `Unable to locate a MustardScript native addon for ${platformHint}. Install a matching prebuilt package for this platform.`,
215
215
  );
216
216
  }
217
217
 
218
218
  module.exports = {
219
219
  PREBUILT_TARGETS,
220
220
  getCurrentPrebuiltTarget,
221
- getLocalBinaryFilenames,
222
221
  getLocalBuildOutputFile,
223
222
  localBinaryCandidates,
224
223
  resolveNativeAddonPath,