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 { type Task, type Lock2 } from "../memory/lock.js";
1
+ import { type Lock2, type Task } from "../memory/lock.js";
2
2
  import type { AbortSignalOption, TaskTimeout } from "../types.js";
3
3
  import { type SignalAbortStore } from "../shared/abortSignal.js";
4
4
  type RawArguments = unknown;
@@ -9,10 +9,11 @@ type CreateHostTxQueueArgs = {
9
9
  max?: number;
10
10
  lock: Lock2;
11
11
  returnLock: Lock2;
12
+ releaseBufferReferenceReturn?: (token: bigint) => void;
12
13
  abortSignals?: Pick<SignalAbortStore, "getSignal" | "setSignal" | "resetSignal" | "closeNow">;
13
14
  now?: () => number;
14
15
  };
15
- export declare function createHostTxQueue({ max, lock, returnLock, abortSignals, now, }: CreateHostTxQueueArgs): {
16
+ export declare function createHostTxQueue({ max, lock, returnLock, releaseBufferReferenceReturn, abortSignals, now, }: CreateHostTxQueueArgs): {
16
17
  rejectAll: (reason: string) => void;
17
18
  hasPendingFrames: () => boolean;
18
19
  txIdle: () => boolean;
@@ -1,6 +1,7 @@
1
- import { makeTask, resetTaskLocalFlags, TaskIndex, } from "../memory/lock.js";
1
+ import { makeTask, resetTaskLocalFlags, runTaskFinalizers, TaskIndex, } from "../memory/lock.js";
2
2
  import { withResolvers } from "../common/with-resolvers.js";
3
3
  import { AbortSignalPoolExhausted, OneShotDeferred, } from "../shared/abortSignal.js";
4
+ import { withBufferReferenceReturnReleaser } from "../connections/buffer-reference.js";
4
5
  const SLOT_INDEX_MASK = 31;
5
6
  const SLOT_META_MASK = 0x07ffffff;
6
7
  const SLOT_META_SHIFT = 5;
@@ -10,7 +11,7 @@ const FUNCTION_META_SHIFT = 16;
10
11
  const ABORT_SIGNAL_META_OFFSET = 1;
11
12
  const NO_ABORT_SIGNAL = -1;
12
13
  const p_now = performance.now.bind(performance);
13
- export function createHostTxQueue({ max, lock, returnLock, abortSignals, now, }) {
14
+ export function createHostTxQueue({ max, lock, returnLock, releaseBufferReferenceReturn, abortSignals, now, }) {
14
15
  const PLACE_HOLDER = (_) => {
15
16
  throw ("UNREACHABLE FROM PLACE HOLDER (main)");
16
17
  };
@@ -26,7 +27,6 @@ export function createHostTxQueue({ max, lock, returnLock, abortSignals, now, })
26
27
  const initialSize = max ?? 10;
27
28
  const queue = Array.from({ length: initialSize }, (_, index) => newSlot(index));
28
29
  const freeSockets = Array.from({ length: initialSize }, (_, i) => i);
29
- // Local count
30
30
  const freePush = (id) => freeSockets.push(id);
31
31
  const freePop = () => freeSockets.pop();
32
32
  const queuePush = (task) => queue.push(task);
@@ -40,13 +40,16 @@ export function createHostTxQueue({ max, lock, returnLock, abortSignals, now, })
40
40
  onResolved: (task) => {
41
41
  inUsed = (inUsed - 1) | 0;
42
42
  resetTaskLocalFlags(task);
43
+ runTaskFinalizers(task);
43
44
  task.value = null;
44
45
  task.resolve = PLACE_HOLDER;
45
46
  task.reject = PLACE_HOLDER;
46
47
  freePush(task[TaskIndex.ID]);
47
48
  },
48
49
  });
49
- // Helpers
50
+ const completeFrame = releaseBufferReferenceReturn === undefined
51
+ ? resolveReturn
52
+ : () => withBufferReferenceReturnReleaser(releaseBufferReferenceReturn, resolveReturn);
50
53
  const txIdle = () => getPendingFrameCount() === 0 && inUsed === getPendingPromiseCount();
51
54
  const rejectAll = (reason) => {
52
55
  for (let index = 0; index < queue.length; index++) {
@@ -57,6 +60,7 @@ export function createHostTxQueue({ max, lock, returnLock, abortSignals, now, })
57
60
  }
58
61
  catch {
59
62
  }
63
+ runTaskFinalizers(slot);
60
64
  slot.resolve = PLACE_HOLDER;
61
65
  slot.reject = PLACE_HOLDER;
62
66
  queue[index] = newSlot(index);
@@ -73,13 +77,13 @@ export function createHostTxQueue({ max, lock, returnLock, abortSignals, now, })
73
77
  rejectAll,
74
78
  hasPendingFrames,
75
79
  txIdle,
76
- completeFrame: resolveReturn,
80
+ completeFrame,
77
81
  enqueue: (functionID, timeout, abortSignal) => {
78
82
  const HAS_TIMER = timeout !== undefined;
79
83
  const functionIDMasked = functionID & FUNCTION_ID_MASK;
80
- const USE_SIGNAL = abortSignal !== undefined && abortSignals !== undefined;
84
+ const USE_SIGNAL = abortSignal !== undefined &&
85
+ abortSignals !== undefined;
81
86
  return (rawArgs) => {
82
- // Expanding size if needed
83
87
  if (inUsed === queue.length) {
84
88
  const newSize = inUsed + 32;
85
89
  let current = queue.length;
@@ -101,19 +105,19 @@ export function createHostTxQueue({ max, lock, returnLock, abortSignals, now, })
101
105
  new OneShotDeferred(deferred, () => resetSignal(maybeSignal), () => {
102
106
  abortSignals.setSignal(maybeSignal);
103
107
  });
104
- const encodedSignalMeta = ((maybeSignal + ABORT_SIGNAL_META_OFFSET) & FUNCTION_META_MASK) >>> 0;
108
+ const encodedSignalMeta = ((maybeSignal + ABORT_SIGNAL_META_OFFSET) & FUNCTION_META_MASK) >>>
109
+ 0;
105
110
  slot[TaskIndex.FunctionID] =
106
- ((encodedSignalMeta << FUNCTION_META_SHIFT) | functionIDMasked) >>> 0;
111
+ ((encodedSignalMeta << FUNCTION_META_SHIFT) | functionIDMasked) >>>
112
+ 0;
107
113
  }
108
- // Set info
109
114
  slot.value = rawArgs;
110
115
  slot[TaskIndex.ID] = index;
111
116
  slot.resolve = deferred.resolve;
112
117
  slot.reject = deferred.reject;
113
118
  if (HAS_TIMER) {
114
- slot[TaskIndex.slotBuffer] =
115
- ((slot[TaskIndex.slotBuffer] & SLOT_INDEX_MASK) |
116
- ((((nowTime() >>> 0) & SLOT_META_MASK) << SLOT_META_SHIFT) >>> 0)) >>> 0;
119
+ slot[TaskIndex.slotBuffer] = ((slot[TaskIndex.slotBuffer] & SLOT_INDEX_MASK) |
120
+ ((((nowTime() >>> 0) & SLOT_META_MASK) << SLOT_META_SHIFT) >>> 0)) >>> 0;
117
121
  }
118
122
  void publish(slot);
119
123
  inUsed = (inUsed + 1) | 0;
@@ -132,6 +136,7 @@ export function createHostTxQueue({ max, lock, returnLock, abortSignals, now, })
132
136
  catch {
133
137
  }
134
138
  resetTaskLocalFlags(task);
139
+ runTaskFinalizers(task);
135
140
  task.value = null;
136
141
  task.resolve = PLACE_HOLDER;
137
142
  task.reject = PLACE_HOLDER;
package/src/types.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { endpointSymbol } from "./common/task-symbol.js";
2
- import type { Envelope } from "./common/envelope.js";
2
+ import type { Envelope, EnvelopeBody, EnvelopeHeader } from "./common/envelope.js";
3
3
  import type { LockBufferTextCompat, SharedBufferTextCompat } from "./common/shared-buffer-text.js";
4
4
  import type { SharedBufferRegion, SharedBufferSource } from "./common/shared-buffer-region.js";
5
5
  import type { PayloadBufferMode, PayloadBufferOptions } from "./memory/payload-config.js";
@@ -32,8 +32,18 @@ type WorkerData = {
32
32
  lock: LockBuffers;
33
33
  returnLock: LockBuffers;
34
34
  payloadConfig?: PayloadBufferOptions;
35
+ bufferReferenceReturn?: "copy" | "borrow";
35
36
  permission?: ResolvedPermissionProtocol;
36
37
  };
38
+ type UnsafeOptions = {
39
+ /**
40
+ * Experimental `BufferReference` return lifetime.
41
+ *
42
+ * `"copy"` is safe after worker release. `"borrow"` skips the Deno/Bun copy,
43
+ * but must be released before producer shutdown and must not outlive its ref.
44
+ */
45
+ BufferReferenceReturn?: "copy" | "borrow";
46
+ };
37
47
  type LockBuffers = {
38
48
  headers: SharedBufferSource;
39
49
  headerSlotStrideU32?: number;
@@ -49,11 +59,14 @@ interface JSONObject {
49
59
  interface JSONArray extends Array<JSONValue> {
50
60
  }
51
61
  type Serializable = string | object | number | boolean | bigint;
52
- type ValidInput = bigint | void | JSONValue | symbol | ArrayBuffer | Uint8Array | Int32Array | Float64Array | BigInt64Array | BigUint64Array | DataView | Error | Date | Envelope;
62
+ type ValidInput = bigint | void | JSONValue | symbol | ArrayBuffer | Uint8Array | Int32Array | Float64Array | BigInt64Array | BigUint64Array | DataView | Error | Date | Envelope<EnvelopeHeader, EnvelopeBody>;
53
63
  type Args = ValidInput | Serializable;
54
64
  type MaybePromise<T> = T | Promise<T>;
65
+ /** Blob payloads are not supported; pass ArrayBuffer/typed arrays instead. */
55
66
  type NoBlob<T> = T extends Blob ? never : T;
67
+ /** Task input may be a direct value or native Promise; thenables are plain values. */
56
68
  type TaskInput = NoBlob<Args> | Promise<NoBlob<Args>>;
69
+ /** Per-call timeout. A number is milliseconds; object form can return a default. */
57
70
  type TaskTimeout = number | {
58
71
  time: number;
59
72
  maybe?: true;
@@ -66,6 +79,7 @@ type BivariantCallback<Args extends unknown[], R> = {
66
79
  type AbortSignalConfig = {
67
80
  readonly hasAborted: true;
68
81
  };
82
+ /** `true` or config injects an abort toolkit as the task's second parameter. */
69
83
  type AbortSignalOption = true | AbortSignalConfig | undefined;
70
84
  type AbortSignalMethods<AS extends AbortSignalOption> = AS extends undefined ? never : {
71
85
  hasAborted: () => boolean;
@@ -88,13 +102,16 @@ type tasks = Record<string, Composed<any, any, AbortSignalOption> | TaskFunction
88
102
  type ComposedWithKey = Composed<any, any, AbortSignalOption> & {
89
103
  name: string;
90
104
  };
91
- type PromiseWrapped<F extends (...args: any[]) => any, AS extends AbortSignalOption = undefined> = (...args: PromisifyCallArgs<F, AS>) => (AS extends undefined ? Promise<Awaited<ReturnType<F>>> : PromiseWithMaybeReject<Awaited<ReturnType<F>>>);
105
+ type PromiseWrapped<F extends (...args: any[]) => any, AS extends AbortSignalOption = undefined> = (...args: PromisifyCallArgs<F, AS>) => AS extends undefined ? Promise<Awaited<ReturnType<F>>> : PromiseWithMaybeReject<Awaited<ReturnType<F>>>;
92
106
  type PromiseInput<T> = T | Promise<T>;
93
107
  type PromisifyArgs<T extends unknown[]> = {
94
108
  [K in keyof T]: PromiseInput<T[K]>;
95
109
  };
96
110
  type NormalizeUndefinedSingleArg<T extends unknown[]> = T extends [undefined] ? [] | [undefined] : T;
97
- type AbortAwareCallArgs<T extends unknown[]> = T extends [...infer Head, AbortSignalToolkit<any>] ? NormalizeUndefinedSingleArg<Head> : NormalizeUndefinedSingleArg<T>;
111
+ type AbortAwareCallArgs<T extends unknown[]> = T extends [
112
+ ...infer Head,
113
+ AbortSignalToolkit<any>
114
+ ] ? NormalizeUndefinedSingleArg<Head> : NormalizeUndefinedSingleArg<T>;
98
115
  type HostCallArgs<F extends (...args: any[]) => any, AS extends AbortSignalOption> = AS extends undefined ? Parameters<F> : AbortAwareCallArgs<Parameters<F>>;
99
116
  type PromisifyCallArgs<F extends (...args: any[]) => any, AS extends AbortSignalOption> = HostCallArgs<F, AS> extends infer T ? T extends unknown[] ? PromisifyArgs<T> : never : never;
100
117
  type TaskCallable<T> = T extends TaskLike<any> ? T["f"] : T extends TaskFunctionLike ? T : never;
@@ -105,7 +122,9 @@ type FunctionMapType<T extends Record<string, TaskLike<any> | TaskFunctionLike>>
105
122
  [K in keyof T]: PromiseWrapped<TaskCallable<T[K]>, AbortSignalOfTask<T[K]>>;
106
123
  };
107
124
  interface FixPointBase<A extends TaskInput, B extends Args, AS extends AbortSignalOption = undefined> {
125
+ /** Worker function. It receives one value; use a tuple/object for many inputs. */
108
126
  readonly f: TaskFn<A, B, AS>;
127
+ /** Soft call timeout. Use `worker.hardTimeoutMs` for runaway CPU walls. */
109
128
  readonly timeout?: TaskTimeout;
110
129
  }
111
130
  type FixPoint<A extends TaskInput, B extends Args, AS extends AbortSignalOption = undefined> = FixPointBase<A, B, AS> & (AS extends undefined ? {
@@ -114,37 +133,39 @@ type FixPoint<A extends TaskInput, B extends Args, AS extends AbortSignalOption
114
133
  readonly abortSignal: AS;
115
134
  });
116
135
  type ImportTaskOptions<A extends TaskInput = void, B extends Args = void, AS extends AbortSignalOption = undefined> = Omit<FixPoint<A, B, AS>, "f"> & {
136
+ /** Module imported by the worker only. Relative paths resolve from caller. */
117
137
  readonly href: string;
138
+ /** Plain function export name. Defaults to `"default"`; do not target `task()`. */
118
139
  readonly name?: string;
119
140
  };
120
141
  type SecondPart = {
121
142
  readonly [endpointSymbol]: true;
122
143
  readonly id: number;
123
- /**
124
- * IMPORTANT: `at` helps to create a `createPool` because we dont know
125
- * the name of the variable at runtime, so basically this gets the logical order
126
- * of the exported file, so no matter the name the worker can track which ` task `
127
- * to track
128
- */
144
+ /** Logical export order used to match worker tasks before names are known. */
129
145
  readonly at: number;
130
146
  readonly importedFrom: string;
131
147
  /**
132
- * Marks a task whose worker-side function is imported dynamically (via
133
- * `importTask`). Such tasks must never run on the host inliner lane: their
134
- * module import is meant to happen inside the worker so worker permission
135
- * policies apply. The pool routes them to worker lanes only, even when the
136
- * inliner is enabled for other tasks.
148
+ * Imported tasks stay on worker lanes so imports run under worker permissions.
137
149
  */
138
150
  readonly imported?: boolean;
139
151
  };
140
152
  type SingleTaskPool<A extends TaskInput = Args, B extends Args = Args, AS extends AbortSignalOption = undefined> = {
153
+ /** Invoke the single task. Arguments may be native Promises. */
141
154
  call: PromiseWrapped<TaskFn<A, B, AS>, AS>;
155
+ /** Await worker teardown now. `using` disposes at scope exit without awaiting. */
142
156
  shutdown: (delayMs?: number) => Promise<void>;
157
+ /** Starts shutdown at scope exit. Use `shutdown()` when you must await it. */
143
158
  [Symbol.dispose]: () => void;
144
159
  };
145
160
  type Pool<T extends Record<string, TaskLike<any> | TaskFunctionLike>> = {
161
+ /** Await worker teardown now. `using` disposes at scope exit without awaiting. */
146
162
  shutdown: (delayMs?: number) => Promise<void>;
163
+ /** Starts shutdown at scope exit. Use `shutdown()` when you must await it. */
147
164
  [Symbol.dispose]: () => void;
165
+ /**
166
+ * Typed task callers. Each call accepts the task input or a native Promise.
167
+ * Thrown errors/rejections reject here as Error objects with cause chains.
168
+ */
148
169
  call: FunctionMapType<T>;
149
170
  };
150
171
  type ReturnFixed<A extends TaskInput = undefined, B extends Args = undefined, AS extends AbortSignalOption = undefined> = FixPoint<A, B, AS> & SecondPart & {
@@ -171,12 +192,13 @@ type Balancer = BalancerStrategy | {
171
192
  */
172
193
  strategy?: BalancerStrategy;
173
194
  };
174
- type DebugOptions = {
175
- extras?: boolean;
176
- logMain?: boolean;
177
- logHref?: boolean;
178
- logImportedUrl?: boolean;
195
+ /** Debug namespaces for host setup, worker state, imports, globals, and lifecycle. */
196
+ type DebugNamespace = "host" | "globals" | "signals" | "imports" | "lifecycle";
197
+ type DebugFlags = {
198
+ [Namespace in DebugNamespace]?: boolean;
179
199
  };
200
+ /** Pass `true` for all debug, or enable namespaces by name. */
201
+ type DebugOptions = boolean | DebugFlags;
180
202
  type WorkerBootstrapContext = {
181
203
  readonly thread: number;
182
204
  readonly totalNumberOfThread: number;
@@ -208,7 +230,7 @@ type WorkerSettings = {
208
230
  /**
209
231
  * Experimental worker runtime.
210
232
  * "thread" uses Worker/worker_threads. "process" spawns another JavaScript
211
- * runtime and shares one inherited fd-backed memory mapping.
233
+ * runtime, useful for process isolation, bwrap, and containers.
212
234
  */
213
235
  runtime?: "thread" | "process";
214
236
  /**
@@ -276,38 +298,21 @@ type DispatcherSettings = {
276
298
  maxBackoffMs?: number;
277
299
  };
278
300
  type CreatePool = {
301
+ /** Number of workers. Default: 1. */
279
302
  threads?: number;
280
- /**
281
- * @deprecated Too risky with processes, need to rewrite or delete.
282
- */
303
+ /** Add a host inline lane for regular tasks. Imported tasks still use workers. */
283
304
  inliner?: Inliner;
284
305
  balancer?: Balancer;
285
306
  worker?: WorkerSettings;
286
307
  /**
287
- * Payload transport settings.
308
+ * Payload transport settings. Default dynamic payload cap is about 8 MiB
309
+ * (`payloadMaxByteLength >> 3`, with a 64 MiB growth cap).
288
310
  */
289
311
  payload?: PayloadBufferOptions;
290
312
  /**
291
- * Initial payload SharedArrayBuffer size (bytes) per worker direction.
292
- * Defaults to 4 MiB when growable SAB is available, otherwise defaults to
293
- * `payloadMaxBytes`.
294
- * @deprecated Use `payload.payloadInitialBytes`.
313
+ * Experimental unsafe options.
295
314
  */
296
- payloadInitialBytes?: number;
297
- /**
298
- * Maximum payload SharedArrayBuffer size (bytes) per worker direction.
299
- * Defaults to 64 MiB.
300
- * @deprecated Use `payload.payloadMaxByteLength`.
301
- */
302
- payloadMaxBytes?: number;
303
- /**
304
- * @deprecated Use `payload.mode`.
305
- */
306
- bufferMode?: PayloadBufferMode;
307
- /**
308
- * @deprecated Use `payload.maxPayloadBytes`.
309
- */
310
- maxPayloadBytes?: number;
315
+ unsafe?: UnsafeOptions;
311
316
  /**
312
317
  * Abort-aware signal pool capacity.
313
318
  * Defaults to `258`.
@@ -324,19 +329,18 @@ type CreatePool = {
324
329
  workerExecArgv?: string[];
325
330
  /**
326
331
  * Runtime permission protocol.
327
- * Omit to use strict defaults with `allowImport: true`.
332
+ * Omit to use strict defaults with `allowImport: true`; worker console is
333
+ * quiet unless `permission: { console: true }`.
334
+ *
335
+ * Task code cannot terminate the host: process/Deno exit APIs are blocked.
328
336
  * Use `"strict"` (default for object mode) or `"unsafe"`.
329
337
  * Accepts object form for fine-grained permission controls.
330
338
  */
331
339
  permission?: PermissionProtocolInput;
332
- /**
333
- * @deprecated Use `host` instead.
334
- */
335
- dispatcher?: DispatcherSettings;
336
340
  debug?: DebugOptions;
337
341
  source?: string;
338
342
  };
339
- export type { WorkerCall as WorkerCall, WorkerInvoke as WorkerInvoke, WorkerContext as WorkerContext, CreateContext as CreateContext, WorkerData as WorkerData, LockBuffers as LockBuffers, ValidInput as ValidInput, Args as Args, MaybePromise as MaybePromise, TaskInput as TaskInput, TaskTimeout as TaskTimeout, TaskFn as TaskFn, AbortSignalConfig as AbortSignalConfig, AbortSignalOption as AbortSignalOption, AbortSignalMethods as AbortSignalMethods, AbortSignalToolkit as AbortSignalToolkit, Composed as Composed, tasks as tasks, ComposedWithKey as ComposedWithKey, FunctionMapType as FunctionMapType, FixPoint as FixPoint, ImportTaskOptions as ImportTaskOptions, SecondPart as SecondPart, SingleTaskPool as SingleTaskPool, Pool as Pool, ReturnFixed as ReturnFixed, External as External, Inliner as Inliner, BalancerStrategy as BalancerStrategy, Balancer as Balancer, DebugOptions as DebugOptions, WorkerBootstrapContext as WorkerBootstrapContext, WorkerBootstrapFunction as WorkerBootstrapFunction, WorkerBootstrapOptions as WorkerBootstrapOptions, WorkerSettings as WorkerSettings, ProcessSharedMemoryMode as ProcessSharedMemoryMode, ProcessSharedMemorySettings as ProcessSharedMemorySettings, WorkerTimers as WorkerTimers, DispatcherSettings as DispatcherSettings, CreatePool as CreatePool, PayloadBufferMode as PayloadBufferMode, PayloadBufferOptions as PayloadBufferOptions, PermissionProtocol as PermissionProtocol, PermissionProtocolInput as PermissionProtocolInput, ResolvedPermissionProtocol as ResolvedPermissionProtocol, Envelope as Envelope, SharedBufferTextCompat as SharedBufferTextCompat, LockBufferTextCompat as LockBufferTextCompat, SharedBufferRegion as SharedBufferRegion, SharedBufferSource as SharedBufferSource, };
343
+ export type { AbortSignalConfig as AbortSignalConfig, AbortSignalMethods as AbortSignalMethods, AbortSignalOption as AbortSignalOption, AbortSignalToolkit as AbortSignalToolkit, Args as Args, Balancer as Balancer, BalancerStrategy as BalancerStrategy, Composed as Composed, ComposedWithKey as ComposedWithKey, CreateContext as CreateContext, CreatePool as CreatePool, DebugNamespace as DebugNamespace, DebugOptions as DebugOptions, DispatcherSettings as DispatcherSettings, Envelope as Envelope, EnvelopeBody as EnvelopeBody, EnvelopeHeader as EnvelopeHeader, External as External, FixPoint as FixPoint, FunctionMapType as FunctionMapType, ImportTaskOptions as ImportTaskOptions, Inliner as Inliner, LockBuffers as LockBuffers, LockBufferTextCompat as LockBufferTextCompat, MaybePromise as MaybePromise, PayloadBufferMode as PayloadBufferMode, PayloadBufferOptions as PayloadBufferOptions, PermissionProtocol as PermissionProtocol, PermissionProtocolInput as PermissionProtocolInput, Pool as Pool, ProcessSharedMemoryMode as ProcessSharedMemoryMode, ProcessSharedMemorySettings as ProcessSharedMemorySettings, ResolvedPermissionProtocol as ResolvedPermissionProtocol, ReturnFixed as ReturnFixed, SecondPart as SecondPart, SharedBufferRegion as SharedBufferRegion, SharedBufferSource as SharedBufferSource, SharedBufferTextCompat as SharedBufferTextCompat, SingleTaskPool as SingleTaskPool, TaskFn as TaskFn, TaskInput as TaskInput, tasks as tasks, TaskTimeout as TaskTimeout, ValidInput as ValidInput, WorkerBootstrapContext as WorkerBootstrapContext, WorkerBootstrapFunction as WorkerBootstrapFunction, WorkerBootstrapOptions as WorkerBootstrapOptions, WorkerCall as WorkerCall, WorkerContext as WorkerContext, WorkerData as WorkerData, WorkerInvoke as WorkerInvoke, WorkerSettings as WorkerSettings, WorkerTimers as WorkerTimers, };
340
344
  export type { Task as Task } from "./memory/lock.js";
341
345
  export { LockBound as LockBound, PayloadBuffer as PayloadBuffer, PayloadSignal as PayloadSignal, TaskIndex as TaskIndex, } from "./memory/lock.js";
342
346
  export type { RegisterMalloc as RegisterMalloc } from "./memory/regionRegistry.js";
@@ -0,0 +1,29 @@
1
+ export type BufferLike = ArrayBuffer | SharedArrayBuffer | ArrayBufferView;
2
+ export type NumberFormat = "f64" | "f32" | "i32";
3
+ export type NumberBufferOptions = {
4
+ format?: NumberFormat;
5
+ };
6
+ /** View ArrayBuffer/SharedArrayBuffer/typed-array bytes as Uint8Array. */
7
+ export declare const bufferToBytes: (source: BufferLike) => Uint8Array;
8
+ /** Copy bytes into a SharedArrayBuffer for zero-copy worker inputs. */
9
+ export declare const bytesToBuffer: (source: BufferLike) => SharedArrayBuffer;
10
+ /** Decode UTF-8 bytes from ArrayBuffer/SharedArrayBuffer/typed-array input. */
11
+ export declare const bufferToString: (source: BufferLike) => string;
12
+ /** Encode UTF-8 text into a SharedArrayBuffer. */
13
+ export declare const stringToBuffer: (text: string) => SharedArrayBuffer;
14
+ /** Decode JSON from UTF-8 bytes. */
15
+ export declare const bufferToJson: <T = unknown>(source: BufferLike) => T;
16
+ /** Encode JSON into a SharedArrayBuffer. */
17
+ export declare const jsonToBuffer: (value: unknown) => SharedArrayBuffer;
18
+ /** Encode numbers into a SharedArrayBuffer (`f64` by default). */
19
+ export declare const numbersToBuffer: (numbers: ArrayLike<number>, options?: NumberBufferOptions) => SharedArrayBuffer;
20
+ /** Decode numeric typed-array views from worker-friendly byte buffers. */
21
+ export declare function bufferToNumbers(source: BufferLike, options?: {
22
+ format?: "f64";
23
+ }): Float64Array;
24
+ export declare function bufferToNumbers(source: BufferLike, options: {
25
+ format: "f32";
26
+ }): Float32Array;
27
+ export declare function bufferToNumbers(source: BufferLike, options: {
28
+ format: "i32";
29
+ }): Int32Array;
@@ -0,0 +1,100 @@
1
+ const nodeBuffer = globalThis.Buffer;
2
+ const hasNodeBuffer = typeof nodeBuffer?.from === "function" &&
3
+ typeof nodeBuffer?.byteLength === "function";
4
+ const textEncoder = new TextEncoder();
5
+ const textDecoder = new TextDecoder();
6
+ const hasSharedArrayBuffer = typeof SharedArrayBuffer === "function";
7
+ const isSharedArrayBuffer = (value) => hasSharedArrayBuffer && value instanceof SharedArrayBuffer;
8
+ const BYTES_PER_ELEMENT = {
9
+ f64: 8,
10
+ f32: 4,
11
+ i32: 4,
12
+ };
13
+ const toBytes = (source) => {
14
+ if (source instanceof Uint8Array)
15
+ return source;
16
+ if (ArrayBuffer.isView(source)) {
17
+ return new Uint8Array(source.buffer, source.byteOffset, source.byteLength);
18
+ }
19
+ if (source instanceof ArrayBuffer || isSharedArrayBuffer(source)) {
20
+ return new Uint8Array(source);
21
+ }
22
+ throw new TypeError("Expected an ArrayBuffer, SharedArrayBuffer, or typed-array view.");
23
+ };
24
+ /** View ArrayBuffer/SharedArrayBuffer/typed-array bytes as Uint8Array. */
25
+ export const bufferToBytes = (source) => toBytes(source);
26
+ /** Copy bytes into a SharedArrayBuffer for zero-copy worker inputs. */
27
+ export const bytesToBuffer = (source) => {
28
+ const bytes = toBytes(source);
29
+ const sab = new SharedArrayBuffer(bytes.byteLength);
30
+ new Uint8Array(sab).set(bytes);
31
+ return sab;
32
+ };
33
+ const makeNumberView = (format, buffer, byteOffset, length) => {
34
+ switch (format) {
35
+ case "f64":
36
+ return new Float64Array(buffer, byteOffset, length);
37
+ case "f32":
38
+ return new Float32Array(buffer, byteOffset, length);
39
+ case "i32":
40
+ return new Int32Array(buffer, byteOffset, length);
41
+ }
42
+ };
43
+ /** Decode UTF-8 bytes from ArrayBuffer/SharedArrayBuffer/typed-array input. */
44
+ export const bufferToString = (source) => {
45
+ const bytes = toBytes(source);
46
+ if (hasNodeBuffer) {
47
+ return nodeBuffer
48
+ .from(bytes.buffer, bytes.byteOffset, bytes.byteLength)
49
+ .toString("utf8");
50
+ }
51
+ return textDecoder.decode(bytes);
52
+ };
53
+ /** Encode UTF-8 text into a SharedArrayBuffer. */
54
+ export const stringToBuffer = (text) => {
55
+ if (typeof text !== "string") {
56
+ throw new TypeError("stringToBuffer expects a string.");
57
+ }
58
+ if (hasNodeBuffer) {
59
+ const byteLength = nodeBuffer.byteLength(text, "utf8");
60
+ const sab = new SharedArrayBuffer(byteLength);
61
+ nodeBuffer.from(sab).write(text, "utf8");
62
+ return sab;
63
+ }
64
+ const encoded = textEncoder.encode(text);
65
+ const sab = new SharedArrayBuffer(encoded.byteLength);
66
+ new Uint8Array(sab).set(encoded);
67
+ return sab;
68
+ };
69
+ /** Decode JSON from UTF-8 bytes. */
70
+ export const bufferToJson = (source) => JSON.parse(bufferToString(source));
71
+ /** Encode JSON into a SharedArrayBuffer. */
72
+ export const jsonToBuffer = (value) => {
73
+ const text = JSON.stringify(value);
74
+ if (typeof text !== "string") {
75
+ throw new TypeError("jsonToBuffer: value is not JSON-serializable (stringify returned undefined).");
76
+ }
77
+ return stringToBuffer(text);
78
+ };
79
+ /** Encode numbers into a SharedArrayBuffer (`f64` by default). */
80
+ export const numbersToBuffer = (numbers, options) => {
81
+ const format = options?.format ?? "f64";
82
+ const sab = new SharedArrayBuffer(numbers.length * BYTES_PER_ELEMENT[format]);
83
+ makeNumberView(format, sab, 0, numbers.length).set(numbers);
84
+ return sab;
85
+ };
86
+ export function bufferToNumbers(source, options) {
87
+ const format = options?.format ?? "f64";
88
+ const bytesPer = BYTES_PER_ELEMENT[format];
89
+ const bytes = toBytes(source);
90
+ if (bytes.byteLength % bytesPer !== 0) {
91
+ throw new RangeError(`bufferToNumbers: byte length ${bytes.byteLength} is not a multiple of ` +
92
+ `${bytesPer} for format "${format}".`);
93
+ }
94
+ const length = bytes.byteLength / bytesPer;
95
+ if (bytes.byteOffset % bytesPer === 0) {
96
+ return makeNumberView(format, bytes.buffer, bytes.byteOffset, length);
97
+ }
98
+ const copy = bytes.slice();
99
+ return makeNumberView(format, copy.buffer, 0, length);
100
+ }