knitting 0.1.51 → 0.1.53

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 (69) hide show
  1. package/README.md +213 -54
  2. package/knitting.d.ts +1 -0
  3. package/map.md +15 -3
  4. package/package.json +14 -2
  5. package/prebuilds/darwin-arm64-node-127/knitting_buffer_pointer.node +0 -0
  6. package/prebuilds/darwin-arm64-node-137/knitting_buffer_pointer.node +0 -0
  7. package/prebuilds/darwin-x64-node-127/knitting_buffer_pointer.node +0 -0
  8. package/prebuilds/darwin-x64-node-137/knitting_buffer_pointer.node +0 -0
  9. package/prebuilds/linux-x64-node-127/knitting_buffer_pointer.node +0 -0
  10. package/prebuilds/linux-x64-node-137/knitting_buffer_pointer.node +0 -0
  11. package/prebuilds/win32-x64/knitting_windows_shared_memory.dll +0 -0
  12. package/prebuilds/win32-x64-node-127/knitting_buffer_pointer.node +0 -0
  13. package/prebuilds/win32-x64-node-127/knitting_shared_memory.node +0 -0
  14. package/prebuilds/win32-x64-node-127/knitting_shm.node +0 -0
  15. package/prebuilds/win32-x64-node-137/knitting_buffer_pointer.node +0 -0
  16. package/prebuilds/win32-x64-node-137/knitting_shared_memory.node +0 -0
  17. package/prebuilds/win32-x64-node-137/knitting_shm.node +0 -0
  18. package/scripts/build-native-addons.ts +5 -0
  19. package/src/api.d.ts +29 -16
  20. package/src/api.js +98 -28
  21. package/src/common/envelope.d.ts +9 -3
  22. package/src/common/envelope.js +14 -0
  23. package/src/common/worker-runtime.d.ts +2 -0
  24. package/src/common/worker-runtime.js +9 -0
  25. package/src/connections/buffer-reference-native.d.ts +56 -0
  26. package/src/connections/buffer-reference-native.js +217 -0
  27. package/src/connections/buffer-reference.d.ts +78 -0
  28. package/src/connections/buffer-reference.js +461 -0
  29. package/src/connections/index.d.ts +1 -0
  30. package/src/connections/index.js +1 -0
  31. package/src/connections/node-addons.d.ts +1 -1
  32. package/src/connections/node-buffer-pointer.d.ts +20 -0
  33. package/src/connections/node-buffer-pointer.js +16 -0
  34. package/src/connections/process-shared-buffer.d.ts +6 -0
  35. package/src/connections/process-shared-buffer.js +6 -0
  36. package/src/connections/shared-array-buffer-payload.d.ts +36 -0
  37. package/src/connections/shared-array-buffer-payload.js +235 -0
  38. package/src/debug/env-diff.d.ts +26 -0
  39. package/src/debug/env-diff.js +49 -0
  40. package/src/debug/gate.d.ts +18 -0
  41. package/src/debug/gate.js +69 -0
  42. package/src/debug/handle.d.ts +23 -0
  43. package/src/debug/handle.js +48 -0
  44. package/src/ipc/transport/shared-memory.d.ts +1 -3
  45. package/src/knitting_buffer_pointer.cc +425 -0
  46. package/src/memory/lock.d.ts +12 -1
  47. package/src/memory/lock.js +47 -4
  48. package/src/memory/payload-config.d.ts +9 -0
  49. package/src/memory/payloadCodec.js +220 -37
  50. package/src/permission/protocol.d.ts +1 -1
  51. package/src/permission/protocol.js +30 -20
  52. package/src/runtime/pool.d.ts +3 -5
  53. package/src/runtime/pool.js +18 -18
  54. package/src/runtime/process-worker.js +5 -2
  55. package/src/runtime/tx-queue.d.ts +3 -2
  56. package/src/runtime/tx-queue.js +18 -13
  57. package/src/types.d.ts +54 -50
  58. package/src/utils/http.d.ts +29 -0
  59. package/src/utils/http.js +100 -0
  60. package/src/worker/loop.js +76 -14
  61. package/src/worker/rx-queue.d.ts +4 -1
  62. package/src/worker/rx-queue.js +53 -4
  63. package/src/worker/safety/startup.d.ts +2 -3
  64. package/src/worker/safety/startup.js +1 -4
  65. package/src/worker/timers.js +7 -2
  66. package/unsafe.d.ts +1 -0
  67. package/unsafe.js +1 -0
  68. package/utils.d.ts +1 -0
  69. package/utils.js +1 -0
@@ -1,4 +1,4 @@
1
- import { createRuntimeMessageChannel, RUNTIME_IS_MAIN_THREAD, RUNTIME_IS_PROCESS_WORKER, RUNTIME_PARENT_PORT, RUNTIME_WORKER_DATA, } from "../common/worker-runtime.js";
1
+ import { addRuntimeDataListener, createRuntimeMessageChannel, RUNTIME_IS_MAIN_THREAD, RUNTIME_IS_PROCESS_WORKER, RUNTIME_PARENT_PORT, RUNTIME_WORKER_DATA, } from "../common/worker-runtime.js";
2
2
  import { isSharedBufferSource } from "../common/shared-buffer-region.js";
3
3
  import { isLockBufferTextCompat } from "../common/shared-buffer-text.js";
4
4
  import { createWorkerRxQueue } from "./rx-queue.js";
@@ -12,6 +12,8 @@ import { assertWorkerImportsResolved, assertWorkerSharedMemoryBootData, installP
12
12
  import { signalAbortFactory } from "../shared/abortSignal.js";
13
13
  import { runWorkerBootstrap } from "./bootstrap.js";
14
14
  import { getProcessWorkerNativeWaitU32, installProcessWorkerBootstrap, } from "./process-worker-bootstrap.js";
15
+ import { readBufferReferenceReturnReleaseMessage, } from "../connections/buffer-reference.js";
16
+ import { resolveDebugNamespaces } from "../debug/gate.js";
15
17
  const WORKER_FATAL_MESSAGE_KEY = "__knittingWorkerFatal";
16
18
  const reportWorkerStartupFatal = (error) => {
17
19
  const message = String(error?.message ?? error);
@@ -48,14 +50,37 @@ const reportWorkerStartupFatal = (error) => {
48
50
  }
49
51
  }
50
52
  };
53
+ const installBufferReferenceReleaseListener = (releaseReturnedBufferReference) => {
54
+ const handleMessage = (message) => {
55
+ const token = readBufferReferenceReturnReleaseMessage(message);
56
+ if (token !== undefined)
57
+ releaseReturnedBufferReference(token);
58
+ };
59
+ if (RUNTIME_PARENT_PORT !== undefined) {
60
+ addRuntimeDataListener(RUNTIME_PARENT_PORT, handleMessage);
61
+ return;
62
+ }
63
+ const scope = globalThis;
64
+ scope.addEventListener?.("message", (event) => {
65
+ handleMessage(event?.data);
66
+ });
67
+ };
51
68
  export const workerMainLoop = async (startupData) => {
52
69
  // Startup-only safety layer: no per-iteration checks in the hot loop.
53
70
  installTerminationGuard();
54
71
  installUnhandledRejectionSilencer();
55
72
  installPerformanceNowGuard();
56
- const { debug, sab, thread, startAt, workerOptions, lock, returnLock, abortSignalSAB, abortSignalMax, payloadConfig, permission, totalNumberOfThread, list, ids, names, at, } = startupData;
73
+ const { debug, sab, thread, startAt, workerOptions, lock, returnLock, abortSignalSAB, abortSignalMax, payloadConfig, bufferReferenceReturn, permission, totalNumberOfThread, list, ids, names, at, } = startupData;
57
74
  scrubWorkerDataSensitiveBuffers(startupData);
58
75
  assertWorkerSharedMemoryBootData({ sab, lock, returnLock });
76
+ const debugNamespaces = resolveDebugNamespaces(debug);
77
+ const dbg = debugNamespaces.size > 0
78
+ ? await import("../debug/handle.js").then((module) => module.initDebug({
79
+ name: `w${thread}`,
80
+ runtime: RUNTIME,
81
+ namespaces: debugNamespaces,
82
+ }))
83
+ : undefined;
59
84
  let Comment;
60
85
  (function (Comment) {
61
86
  Comment[Comment["thisIsAHint"] = 0] = "thisIsAHint";
@@ -66,7 +91,6 @@ export const workerMainLoop = async (startupData) => {
66
91
  },
67
92
  isMain: false,
68
93
  thread,
69
- debug,
70
94
  startTime: startAt,
71
95
  });
72
96
  const lockState = lock2({
@@ -90,8 +114,10 @@ export const workerMainLoop = async (startupData) => {
90
114
  const timers = workerOptions?.timers;
91
115
  const spinMicroseconds = timers?.spinMicroseconds ??
92
116
  Math.max(1, totalNumberOfThread) * 50;
93
- const parkMs = timers?.parkMs ??
94
- Math.max(1, totalNumberOfThread) * 50;
117
+ const parkMs = dbg !== undefined
118
+ ? Number.POSITIVE_INFINITY
119
+ : (timers?.parkMs ??
120
+ Math.max(1, totalNumberOfThread) * 50);
95
121
  const pauseSpin = (() => {
96
122
  const fn = typeof timers?.pauseNanoseconds === "number"
97
123
  ? whilePausing({ pauseInNanoseconds: timers.pauseNanoseconds })
@@ -107,6 +133,7 @@ export const workerMainLoop = async (startupData) => {
107
133
  thread,
108
134
  totalNumberOfThread,
109
135
  });
136
+ dbg?.envPhase("bootstrap");
110
137
  const listOfFunctions = await getFunctions({
111
138
  list,
112
139
  isWorker: true,
@@ -115,20 +142,24 @@ export const workerMainLoop = async (startupData) => {
115
142
  at,
116
143
  permission,
117
144
  });
118
- assertWorkerImportsResolved({ debug, list, ids, names, listOfFunctions });
145
+ dbg?.envPhase("tasks");
146
+ dbg?.log("imports", `${listOfFunctions.length} task(s) from ${list.map((spec) => spec.split(/[\\/]/).pop() || spec).join(", ")}`);
147
+ assertWorkerImportsResolved({ list, ids, names, listOfFunctions });
119
148
  const abortSignals = abortSignalSAB
120
149
  ? signalAbortFactory({
121
150
  sab: abortSignalSAB,
122
151
  maxSignals: abortSignalMax,
123
152
  })
124
153
  : undefined;
125
- const { enqueueLock, serviceBatchImmediate, hasCompleted, writeBatch, hasPending, getAwaiting, } = createWorkerRxQueue({
154
+ const { enqueueLock, serviceBatchImmediate, hasCompleted, writeBatch, hasPending, getAwaiting, drainReturnReleases, releaseReturnedBufferReference, } = createWorkerRxQueue({
126
155
  listOfFunctions,
127
156
  workerOptions,
128
157
  lock: lockState,
129
158
  returnLock: returnLockState,
159
+ borrowReturnedBufferReferences: bufferReferenceReturn === "borrow",
130
160
  hasAborted: abortSignals?.hasAborted,
131
161
  });
162
+ installBufferReferenceReleaseListener(releaseReturnedBufferReference);
132
163
  a_store(rxStatus, 0, 1);
133
164
  const WRITE_MAX = 64;
134
165
  const pauseUntil = sleepUntilChanged({
@@ -152,7 +183,7 @@ export const workerMainLoop = async (startupData) => {
152
183
  let awaitingSpins = 0;
153
184
  let lastAwaiting = 0;
154
185
  const MAX_AWAITING_MS = 10;
155
- let wakeSeq = a_load(opView, 0);
186
+ let wakeToken = a_load(opView, 0);
156
187
  const scheduleMacro = () => {
157
188
  if (isInMacro)
158
189
  return;
@@ -177,14 +208,43 @@ export const workerMainLoop = async (startupData) => {
177
208
  }
178
209
  post2(null);
179
210
  };
180
- const _enqueueLock = enqueueLock;
211
+ const traceSignals = dbg?.enabled("signals") === true;
181
212
  const _hasCompleted = hasCompleted;
182
- const _writeBatch = writeBatch;
183
213
  const _hasPending = hasPending;
184
- const _serviceBatchImmediate = serviceBatchImmediate;
185
214
  const _getAwaiting = getAwaiting;
215
+ const _drainReturnReleases = drainReturnReleases;
186
216
  const _pauseSpin = pauseSpin;
187
- const _pauseUntil = pauseUntil;
217
+ const _enqueueLock = traceSignals
218
+ ? () => {
219
+ const progressed = enqueueLock();
220
+ if (progressed) {
221
+ dbg.log("signals", "work from=host");
222
+ }
223
+ return progressed;
224
+ }
225
+ : enqueueLock;
226
+ const _writeBatch = traceSignals
227
+ ? (max) => {
228
+ const wrote = writeBatch(max);
229
+ if (wrote > 0)
230
+ dbg.log("signals", `result count=${wrote}`);
231
+ return wrote;
232
+ }
233
+ : writeBatch;
234
+ const _serviceBatchImmediate = traceSignals
235
+ ? () => {
236
+ const ran = serviceBatchImmediate();
237
+ if (ran > 0)
238
+ dbg.log("signals", `run count=${ran}`);
239
+ return ran;
240
+ }
241
+ : serviceBatchImmediate;
242
+ const _pauseUntil = traceSignals
243
+ ? (value, spinMicroseconds, parkMs) => {
244
+ dbg.log("signals", `idle token=${value}`);
245
+ pauseUntil(value, spinMicroseconds, parkMs);
246
+ }
247
+ : pauseUntil;
188
248
  const loop = () => {
189
249
  isInMacro = false;
190
250
  let progressed = true;
@@ -195,6 +255,7 @@ export const workerMainLoop = async (startupData) => {
195
255
  if (_writeBatch(WRITE_MAX) > 0)
196
256
  progressed = true;
197
257
  }
258
+ _drainReturnReleases();
198
259
  if (_hasPending()) {
199
260
  if (_serviceBatchImmediate() > 0)
200
261
  progressed = true;
@@ -214,8 +275,8 @@ export const workerMainLoop = async (startupData) => {
214
275
  _pauseSpin();
215
276
  continue;
216
277
  }
217
- _pauseUntil(wakeSeq, spinMicroseconds, parkMs);
218
- wakeSeq = a_load(opView, 0);
278
+ _pauseUntil(wakeToken, spinMicroseconds, parkMs);
279
+ wakeToken = a_load(opView, 0);
219
280
  }
220
281
  }
221
282
  };
@@ -229,6 +290,7 @@ export const workerMainLoop = async (startupData) => {
229
290
  }
230
291
  port1Any.start?.();
231
292
  port2.start?.();
293
+ dbg?.log("lifecycle", `ready: ${listOfFunctions.length} task(s) on thread ${thread}/${totalNumberOfThread}, entering dispatch loop`);
232
294
  scheduleMacro();
233
295
  };
234
296
  const isWorkerGlobalScope = () => {
@@ -6,16 +6,19 @@ type ArgumentsForCreateWorkerQueue = {
6
6
  workerOptions?: WorkerSettings;
7
7
  lock: Lock2;
8
8
  returnLock: Lock2;
9
+ borrowReturnedBufferReferences?: boolean;
9
10
  hasAborted?: (signal: number) => boolean;
10
11
  now?: () => number;
11
12
  };
12
13
  export type CreateWorkerRxQueue = ReturnType<typeof createWorkerRxQueue>;
13
- export declare const createWorkerRxQueue: ({ listOfFunctions, workerOptions, lock, returnLock, hasAborted, now, }: ArgumentsForCreateWorkerQueue) => {
14
+ export declare const createWorkerRxQueue: ({ listOfFunctions, workerOptions, lock, returnLock, borrowReturnedBufferReferences, hasAborted, now, }: ArgumentsForCreateWorkerQueue) => {
14
15
  hasCompleted: () => boolean;
15
16
  hasPending: () => boolean;
16
17
  writeBatch: (max: number) => number;
17
18
  serviceBatchImmediate: () => number;
18
19
  enqueueLock: () => boolean;
20
+ drainReturnReleases: () => void;
21
+ releaseReturnedBufferReference: (token: bigint) => void;
19
22
  hasAwaiting: () => boolean;
20
23
  getAwaiting: () => number;
21
24
  };
@@ -1,8 +1,8 @@
1
1
  import RingQueue from "../ipc/tools/ring-queue.js";
2
- import { TaskFlag, TaskIndex, } from "../memory/lock.js";
2
+ import { attachPayloadTransportFinalizer, runTaskFinalizers, TaskFlag, TaskIndex, } from "../memory/lock.js";
3
3
  import { composeWorkerRunner } from "./composable-runners.js";
4
- // Create and manage a working queue.
5
- export const createWorkerRxQueue = ({ listOfFunctions, workerOptions, lock, returnLock, hasAborted, now, }) => {
4
+ import { BUFFER_REFERENCE_RETURN_RELEASE_TOKEN } from "../connections/buffer-reference.js";
5
+ export const createWorkerRxQueue = ({ listOfFunctions, workerOptions, lock, returnLock, borrowReturnedBufferReferences, hasAborted, now, }) => {
6
6
  const PLACE_HOLDER = (_) => {
7
7
  throw ("UNREACHABLE FROM PLACE HOLDER (thread)");
8
8
  };
@@ -20,6 +20,41 @@ export const createWorkerRxQueue = ({ listOfFunctions, workerOptions, lock, retu
20
20
  const FUNCTION_ID_MASK = 0xFFFF;
21
21
  const IDX_FLAGS = TaskIndex.FlagsToHost;
22
22
  const FLAG_REJECT = TaskFlag.Reject;
23
+ // Return-payload finalizers wait until the host consumes the return.
24
+ // Quiescence (hostBits XOR workerBits == 0) lets us release them in batch.
25
+ const a_load = Atomics.load;
26
+ const returnHostBits = returnLock.hostBits;
27
+ const returnWorkerBits = returnLock.workerBits;
28
+ const deferredReleases = [];
29
+ const explicitReturnReleases = new Map();
30
+ const drainReturnReleases = () => {
31
+ if (deferredReleases.length === 0)
32
+ return;
33
+ if ((a_load(returnHostBits, 0) ^ a_load(returnWorkerBits, 0)) !== 0)
34
+ return;
35
+ for (let i = 0; i < deferredReleases.length; i++) {
36
+ try {
37
+ deferredReleases[i]();
38
+ }
39
+ catch {
40
+ // best effort
41
+ }
42
+ }
43
+ deferredReleases.length = 0;
44
+ };
45
+ const releaseReturnedBufferReference = (token) => {
46
+ const key = token.toString();
47
+ const release = explicitReturnReleases.get(key);
48
+ if (release === undefined)
49
+ return;
50
+ explicitReturnReleases.delete(key);
51
+ try {
52
+ release();
53
+ }
54
+ catch {
55
+ // best effort
56
+ }
57
+ };
23
58
  const runByIndex = listOfFunctions.reduce((acc, fixed, idx) => {
24
59
  const job = jobs[idx];
25
60
  acc.push(composeWorkerRunner({
@@ -42,6 +77,7 @@ export const createWorkerRxQueue = ({ listOfFunctions, workerOptions, lock, retu
42
77
  while (task) {
43
78
  task.resolve = PLACE_HOLDER;
44
79
  task.reject = PLACE_HOLDER;
80
+ attachPayloadTransportFinalizer(task, task.value);
45
81
  toWorkPush(task);
46
82
  task = resolvedShift();
47
83
  }
@@ -56,11 +92,23 @@ export const createWorkerRxQueue = ({ listOfFunctions, workerOptions, lock, retu
56
92
  slot[IDX_FLAGS] = shouldReject ? FLAG_REJECT : 0;
57
93
  if (!encodeReturnSafe(slot))
58
94
  return false;
95
+ // Preserve return finalizers past slot recycle; release after drain.
96
+ if (slot.finalize !== undefined) {
97
+ const token = slot.finalize[BUFFER_REFERENCE_RETURN_RELEASE_TOKEN];
98
+ if (token === undefined || borrowReturnedBufferReferences !== true) {
99
+ deferredReleases.push(slot.finalize);
100
+ }
101
+ else {
102
+ explicitReturnReleases.set(token.toString(), slot.finalize);
103
+ }
104
+ slot.finalize = undefined;
105
+ }
59
106
  hasAnythingFinished--;
60
107
  recyclePush(slot);
61
108
  return true;
62
109
  };
63
110
  const settleNow = (slot, isError, value, wasAwaited) => {
111
+ runTaskFinalizers(slot);
64
112
  slot.value = value;
65
113
  hasAnythingFinished++;
66
114
  if (wasAwaited && awaiting > 0)
@@ -99,7 +147,6 @@ export const createWorkerRxQueue = ({ listOfFunctions, workerOptions, lock, retu
99
147
  try {
100
148
  const fnIndex = slot[TaskIndex.FunctionID] & FUNCTION_ID_MASK;
101
149
  const result = runByIndex[fnIndex](slot);
102
- // Slot 0 is reused for response flags; clear request FunctionID value.
103
150
  slot[IDX_FLAGS] = 0;
104
151
  slot.value = null;
105
152
  if (result instanceof Promise) {
@@ -118,6 +165,8 @@ export const createWorkerRxQueue = ({ listOfFunctions, workerOptions, lock, retu
118
165
  return processed;
119
166
  },
120
167
  enqueueLock,
168
+ drainReturnReleases,
169
+ releaseReturnedBufferReference,
121
170
  hasAwaiting: () => awaiting > 0,
122
171
  getAwaiting: () => awaiting,
123
172
  };
@@ -1,17 +1,16 @@
1
1
  import { type SharedBufferSource } from "../../common/shared-buffer-region.js";
2
- import type { DebugOptions, LockBuffers } from "../../types.js";
2
+ import type { LockBuffers } from "../../types.js";
3
3
  type SharedMemoryBootData = {
4
4
  sab: SharedBufferSource | undefined;
5
5
  lock: LockBuffers | undefined;
6
6
  returnLock: LockBuffers | undefined;
7
7
  };
8
8
  type ImportedFunctionsState = {
9
- debug: DebugOptions | undefined;
10
9
  list: string[];
11
10
  ids: number[];
12
11
  names?: string[];
13
12
  listOfFunctions: readonly unknown[];
14
13
  };
15
14
  export declare const assertWorkerSharedMemoryBootData: ({ sab, lock, returnLock }: SharedMemoryBootData) => void;
16
- export declare const assertWorkerImportsResolved: ({ debug, list, ids, names, listOfFunctions }: ImportedFunctionsState) => void;
15
+ export declare const assertWorkerImportsResolved: ({ list, ids, names, listOfFunctions }: ImportedFunctionsState) => void;
17
16
  export {};
@@ -17,10 +17,7 @@ export const assertWorkerSharedMemoryBootData = ({ sab, lock, returnLock }) => {
17
17
  throw new Error("worker missing return lock SABs");
18
18
  }
19
19
  };
20
- export const assertWorkerImportsResolved = ({ debug, list, ids, names, listOfFunctions }) => {
21
- if (debug?.logImportedUrl === true) {
22
- console.log(list);
23
- }
20
+ export const assertWorkerImportsResolved = ({ list, ids, names, listOfFunctions }) => {
24
21
  if (listOfFunctions.length > 0 &&
25
22
  (names === undefined || listOfFunctions.length === names.length))
26
23
  return;
@@ -50,7 +50,7 @@ const isPlainNodeWindows = runtimeGlobals.process?.platform === "win32" &&
50
50
  // full parkMs (up to seconds); the long park with no wake is what made CI
51
51
  // runners appear to hang. The native wait already polls internally, so this is
52
52
  // just bounding each poll slice.
53
- const nativeWaitTimeoutMs = (parkMs) => isPlainNodeWindows ? 1 : parkMs ?? 60;
53
+ const nativeWaitTimeoutMs = (parkMs) => isPlainNodeWindows ? 1 : Number.isFinite(parkMs) ? parkMs : 60;
54
54
  export const whilePausing = ({ pauseInNanoseconds }) => {
55
55
  const forNanoseconds = pauseInNanoseconds ?? DEFAULT_PAUSE_TIME;
56
56
  if (!a_pause || forNanoseconds <= 0)
@@ -101,10 +101,15 @@ export const sleepUntilChanged = ({ at, opView, pauseInNanoseconds, rxStatus, tx
101
101
  else if (useSharedMemoryWait &&
102
102
  a_wait &&
103
103
  opView.buffer instanceof SharedArrayBuffer) {
104
+ // This is the notify-able path: a host Atomics.notify on opView wakes it.
105
+ // An infinite parkMs (debug) is intentional here — the worker blocks until
106
+ // a real signal instead of re-polling on a timeout.
104
107
  a_wait(opView, at, value, parkMs ?? 60);
105
108
  }
106
109
  else if (a_wait && waitFallbackView) {
107
- a_wait(waitFallbackView, 0, 0, parkMs ?? 1);
110
+ // waitFallbackView is never notified — this wait only ever times out and
111
+ // re-polls, so it must stay finite or the worker would hang forever.
112
+ a_wait(waitFallbackView, 0, 0, Number.isFinite(parkMs) ? parkMs : 1);
108
113
  }
109
114
  a_store(rxStatus, 0, 1);
110
115
  };
package/unsafe.d.ts ADDED
@@ -0,0 +1 @@
1
+ export { BUFFER_REFERENCE_CODEC_ID, BUFFER_REFERENCE_KIND, BufferReference, type BufferReferenceMetadata, BufferReferenceReturn, type BufferReferenceRuntime, isBufferReferenceMetadata, } from "./src/connections/buffer-reference.js";
package/unsafe.js ADDED
@@ -0,0 +1 @@
1
+ export { BUFFER_REFERENCE_CODEC_ID, BUFFER_REFERENCE_KIND, BufferReference, BufferReferenceReturn, isBufferReferenceMetadata, } from "./src/connections/buffer-reference.js";
package/utils.d.ts ADDED
@@ -0,0 +1 @@
1
+ export { type BufferLike, bufferToBytes, bufferToJson, bufferToNumbers, bufferToString, bytesToBuffer, jsonToBuffer, type NumberBufferOptions, type NumberFormat, numbersToBuffer, stringToBuffer, } from "./src/utils/http.js";
package/utils.js ADDED
@@ -0,0 +1 @@
1
+ export { bufferToBytes, bufferToJson, bufferToNumbers, bufferToString, bytesToBuffer, jsonToBuffer, numbersToBuffer, stringToBuffer, } from "./src/utils/http.js";