knitting 0.1.46

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 (121) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +632 -0
  3. package/knitting.d.ts +4 -0
  4. package/knitting.js +5 -0
  5. package/map.md +264 -0
  6. package/package.json +77 -0
  7. package/prebuilds/darwin-arm64-node-127/knitting_shared_memory.node +0 -0
  8. package/prebuilds/darwin-arm64-node-127/knitting_shm.node +0 -0
  9. package/prebuilds/darwin-arm64-node-137/knitting_shared_memory.node +0 -0
  10. package/prebuilds/darwin-arm64-node-137/knitting_shm.node +0 -0
  11. package/prebuilds/darwin-x64-node-127/knitting_shared_memory.node +0 -0
  12. package/prebuilds/darwin-x64-node-127/knitting_shm.node +0 -0
  13. package/prebuilds/darwin-x64-node-137/knitting_shared_memory.node +0 -0
  14. package/prebuilds/darwin-x64-node-137/knitting_shm.node +0 -0
  15. package/prebuilds/linux-x64-node-127/knitting_shared_memory.node +0 -0
  16. package/prebuilds/linux-x64-node-127/knitting_shm.node +0 -0
  17. package/prebuilds/linux-x64-node-137/knitting_shared_memory.node +0 -0
  18. package/prebuilds/linux-x64-node-137/knitting_shm.node +0 -0
  19. package/process-shared-buffer.d.ts +1 -0
  20. package/process-shared-buffer.js +1 -0
  21. package/scripts/build-native-addons.ts +295 -0
  22. package/src/api.d.ts +55 -0
  23. package/src/api.js +384 -0
  24. package/src/common/envelope.d.ts +11 -0
  25. package/src/common/envelope.js +8 -0
  26. package/src/common/module-url.d.ts +1 -0
  27. package/src/common/module-url.js +24 -0
  28. package/src/common/node-compat.d.ts +20 -0
  29. package/src/common/node-compat.js +24 -0
  30. package/src/common/path-canonical.d.ts +6 -0
  31. package/src/common/path-canonical.js +41 -0
  32. package/src/common/runtime.d.ts +15 -0
  33. package/src/common/runtime.js +91 -0
  34. package/src/common/shared-buffer-region.d.ts +11 -0
  35. package/src/common/shared-buffer-region.js +21 -0
  36. package/src/common/shared-buffer-text.d.ts +16 -0
  37. package/src/common/shared-buffer-text.js +65 -0
  38. package/src/common/task-source.d.ts +2 -0
  39. package/src/common/task-source.js +79 -0
  40. package/src/common/task-symbol.d.ts +1 -0
  41. package/src/common/task-symbol.js +1 -0
  42. package/src/common/with-resolvers.d.ts +9 -0
  43. package/src/common/with-resolvers.js +23 -0
  44. package/src/common/worker-runtime.d.ts +40 -0
  45. package/src/common/worker-runtime.js +52 -0
  46. package/src/connections/bun.d.ts +20 -0
  47. package/src/connections/bun.js +159 -0
  48. package/src/connections/deno.d.ts +20 -0
  49. package/src/connections/deno.js +150 -0
  50. package/src/connections/file-descriptor.d.ts +37 -0
  51. package/src/connections/file-descriptor.js +139 -0
  52. package/src/connections/index.d.ts +3 -0
  53. package/src/connections/index.js +3 -0
  54. package/src/connections/node-addons.d.ts +5 -0
  55. package/src/connections/node-addons.js +43 -0
  56. package/src/connections/node.d.ts +29 -0
  57. package/src/connections/node.js +59 -0
  58. package/src/connections/posix.d.ts +31 -0
  59. package/src/connections/posix.js +71 -0
  60. package/src/connections/process-shared-buffer.d.ts +67 -0
  61. package/src/connections/process-shared-buffer.js +267 -0
  62. package/src/connections/types.d.ts +48 -0
  63. package/src/connections/types.js +37 -0
  64. package/src/error.d.ts +13 -0
  65. package/src/error.js +49 -0
  66. package/src/ipc/tools/ring-queue.d.ts +33 -0
  67. package/src/ipc/tools/ring-queue.js +159 -0
  68. package/src/ipc/transport/shared-memory.d.ts +25 -0
  69. package/src/ipc/transport/shared-memory.js +35 -0
  70. package/src/knitting_shared_memory.cc +436 -0
  71. package/src/knitting_shm.cc +476 -0
  72. package/src/memory/byte-carpet.d.ts +73 -0
  73. package/src/memory/byte-carpet.js +157 -0
  74. package/src/memory/lock.d.ts +190 -0
  75. package/src/memory/lock.js +856 -0
  76. package/src/memory/payload-config.d.ts +22 -0
  77. package/src/memory/payload-config.js +67 -0
  78. package/src/memory/payloadCodec.d.ts +46 -0
  79. package/src/memory/payloadCodec.js +1157 -0
  80. package/src/memory/regionRegistry.d.ts +17 -0
  81. package/src/memory/regionRegistry.js +285 -0
  82. package/src/memory/shared-buffer-io.d.ts +53 -0
  83. package/src/memory/shared-buffer-io.js +380 -0
  84. package/src/permission/index.d.ts +2 -0
  85. package/src/permission/index.js +2 -0
  86. package/src/permission/protocol.d.ts +166 -0
  87. package/src/permission/protocol.js +640 -0
  88. package/src/runtime/balancer.d.ts +19 -0
  89. package/src/runtime/balancer.js +149 -0
  90. package/src/runtime/dispatcher.d.ts +34 -0
  91. package/src/runtime/dispatcher.js +142 -0
  92. package/src/runtime/inline-executor.d.ts +10 -0
  93. package/src/runtime/inline-executor.js +270 -0
  94. package/src/runtime/pool.d.ts +43 -0
  95. package/src/runtime/pool.js +922 -0
  96. package/src/runtime/tx-queue.d.ts +25 -0
  97. package/src/runtime/tx-queue.js +144 -0
  98. package/src/shared/abortSignal.d.ts +23 -0
  99. package/src/shared/abortSignal.js +126 -0
  100. package/src/types.d.ts +283 -0
  101. package/src/types.js +2 -0
  102. package/src/worker/composable-runners.d.ts +12 -0
  103. package/src/worker/composable-runners.js +105 -0
  104. package/src/worker/loop.d.ts +2 -0
  105. package/src/worker/loop.js +453 -0
  106. package/src/worker/rx-queue.d.ts +22 -0
  107. package/src/worker/rx-queue.js +124 -0
  108. package/src/worker/safety/index.d.ts +4 -0
  109. package/src/worker/safety/index.js +4 -0
  110. package/src/worker/safety/performance.d.ts +1 -0
  111. package/src/worker/safety/performance.js +17 -0
  112. package/src/worker/safety/process.d.ts +2 -0
  113. package/src/worker/safety/process.js +79 -0
  114. package/src/worker/safety/startup.d.ts +16 -0
  115. package/src/worker/safety/startup.js +30 -0
  116. package/src/worker/safety/worker-data.d.ts +2 -0
  117. package/src/worker/safety/worker-data.js +36 -0
  118. package/src/worker/task-loader.d.ts +26 -0
  119. package/src/worker/task-loader.js +66 -0
  120. package/src/worker/timers.d.ts +18 -0
  121. package/src/worker/timers.js +97 -0
@@ -0,0 +1,25 @@
1
+ import { type Task, type Lock2 } from "../memory/lock.js";
2
+ import type { AbortSignalOption, TaskTimeout } from "../types.js";
3
+ import { type SignalAbortStore } from "../shared/abortSignal.js";
4
+ type RawArguments = unknown;
5
+ type FunctionID = number;
6
+ type QueueTask = Task;
7
+ export type MultiQueue = ReturnType<typeof createHostTxQueue>;
8
+ type CreateHostTxQueueArgs = {
9
+ max?: number;
10
+ lock: Lock2;
11
+ returnLock: Lock2;
12
+ abortSignals?: Pick<SignalAbortStore, "getSignal" | "resetSignal" | "closeNow">;
13
+ now?: () => number;
14
+ };
15
+ export declare function createHostTxQueue({ max, lock, returnLock, abortSignals, now, }: CreateHostTxQueueArgs): {
16
+ rejectAll: (reason: string) => void;
17
+ hasPendingFrames: () => boolean;
18
+ txIdle: () => boolean;
19
+ completeFrame: () => number;
20
+ enqueue: (functionID: FunctionID, timeout?: TaskTimeout, abortSignal?: AbortSignalOption) => (rawArgs: RawArguments) => Promise<never> | import("../common/with-resolvers.js").PromiseWithMaybeReject<unknown>;
21
+ flushToWorker: () => boolean;
22
+ enqueueKnown: (task: QueueTask) => boolean;
23
+ settlePromisePayload: (task: QueueTask, isRejected: boolean, value: unknown) => boolean;
24
+ };
25
+ export {};
@@ -0,0 +1,144 @@
1
+ import { makeTask, resetTaskLocalFlags, TaskIndex, } from "../memory/lock.js";
2
+ import { withResolvers } from "../common/with-resolvers.js";
3
+ import { AbortSignalPoolExhausted, OneShotDeferred, } from "../shared/abortSignal.js";
4
+ const SLOT_INDEX_MASK = 31;
5
+ const SLOT_META_MASK = 0x07ffffff;
6
+ const SLOT_META_SHIFT = 5;
7
+ const FUNCTION_ID_MASK = 0xffff;
8
+ const FUNCTION_META_MASK = 0xffff;
9
+ const FUNCTION_META_SHIFT = 16;
10
+ const ABORT_SIGNAL_META_OFFSET = 1;
11
+ const NO_ABORT_SIGNAL = -1;
12
+ const p_now = performance.now.bind(performance);
13
+ export function createHostTxQueue({ max, lock, returnLock, abortSignals, now, }) {
14
+ const PLACE_HOLDER = (_) => {
15
+ throw ("UNREACHABLE FROM PLACE HOLDER (main)");
16
+ };
17
+ const newSlot = (id) => {
18
+ const task = makeTask();
19
+ task[TaskIndex.ID] = id;
20
+ task[TaskIndex.FunctionID] = 0;
21
+ task.value = null;
22
+ task.resolve = PLACE_HOLDER;
23
+ task.reject = PLACE_HOLDER;
24
+ return task;
25
+ };
26
+ const initialSize = max ?? 10;
27
+ const queue = Array.from({ length: initialSize }, (_, index) => newSlot(index));
28
+ const freeSockets = Array.from({ length: initialSize }, (_, i) => i);
29
+ // Local count
30
+ const freePush = (id) => freeSockets.push(id);
31
+ const freePop = () => freeSockets.pop();
32
+ const queuePush = (task) => queue.push(task);
33
+ const { publish, flushPending, hasPendingFrames, getPendingFrameCount, getPendingPromiseCount, resetPendingState, } = lock;
34
+ let inUsed = 0 | 0;
35
+ const resetSignal = abortSignals?.resetSignal;
36
+ const nowTime = now ?? p_now;
37
+ const resolveReturn = returnLock.resolveHost({
38
+ queue,
39
+ activeRejectPlaceholder: PLACE_HOLDER,
40
+ onResolved: (task) => {
41
+ inUsed = (inUsed - 1) | 0;
42
+ resetTaskLocalFlags(task);
43
+ task.value = null;
44
+ task.resolve = PLACE_HOLDER;
45
+ task.reject = PLACE_HOLDER;
46
+ freePush(task[TaskIndex.ID]);
47
+ },
48
+ });
49
+ // Helpers
50
+ const txIdle = () => getPendingFrameCount() === 0 && inUsed === getPendingPromiseCount();
51
+ const rejectAll = (reason) => {
52
+ for (let index = 0; index < queue.length; index++) {
53
+ const slot = queue[index];
54
+ if (slot.reject !== PLACE_HOLDER) {
55
+ try {
56
+ slot.reject(reason);
57
+ }
58
+ catch {
59
+ }
60
+ slot.resolve = PLACE_HOLDER;
61
+ slot.reject = PLACE_HOLDER;
62
+ queue[index] = newSlot(index);
63
+ }
64
+ }
65
+ resetPendingState();
66
+ inUsed = 0 | 0;
67
+ };
68
+ const flushToWorker = () => flushPending();
69
+ const enqueueKnown = (task) => {
70
+ return publish(task);
71
+ };
72
+ return {
73
+ rejectAll,
74
+ hasPendingFrames,
75
+ txIdle,
76
+ completeFrame: resolveReturn,
77
+ enqueue: (functionID, timeout, abortSignal) => {
78
+ const HAS_TIMER = timeout !== undefined;
79
+ const functionIDMasked = functionID & FUNCTION_ID_MASK;
80
+ const USE_SIGNAL = abortSignal !== undefined && abortSignals !== undefined;
81
+ return (rawArgs) => {
82
+ // Expanding size if needed
83
+ if (inUsed === queue.length) {
84
+ const newSize = inUsed + 32;
85
+ let current = queue.length;
86
+ while (newSize > current) {
87
+ queuePush(newSlot(current));
88
+ freePush(current);
89
+ current++;
90
+ }
91
+ }
92
+ const index = freePop();
93
+ const slot = queue[index];
94
+ const deferred = withResolvers();
95
+ slot[TaskIndex.FunctionID] = functionIDMasked;
96
+ if (USE_SIGNAL) {
97
+ const maybeSignal = abortSignals.getSignal();
98
+ if (maybeSignal === abortSignals.closeNow) {
99
+ return Promise.reject(AbortSignalPoolExhausted);
100
+ }
101
+ new OneShotDeferred(deferred, () => resetSignal(maybeSignal));
102
+ const encodedSignalMeta = ((maybeSignal + ABORT_SIGNAL_META_OFFSET) & FUNCTION_META_MASK) >>> 0;
103
+ slot[TaskIndex.FunctionID] =
104
+ ((encodedSignalMeta << FUNCTION_META_SHIFT) | functionIDMasked) >>> 0;
105
+ }
106
+ // Set info
107
+ slot.value = rawArgs;
108
+ slot[TaskIndex.ID] = index;
109
+ slot.resolve = deferred.resolve;
110
+ slot.reject = deferred.reject;
111
+ if (HAS_TIMER) {
112
+ slot[TaskIndex.slotBuffer] =
113
+ ((slot[TaskIndex.slotBuffer] & SLOT_INDEX_MASK) |
114
+ ((((nowTime() >>> 0) & SLOT_META_MASK) << SLOT_META_SHIFT) >>> 0)) >>> 0;
115
+ }
116
+ void publish(slot);
117
+ inUsed = (inUsed + 1) | 0;
118
+ return deferred.promise;
119
+ };
120
+ },
121
+ flushToWorker,
122
+ enqueueKnown,
123
+ settlePromisePayload: (task, isRejected, value) => {
124
+ if (task.reject === PLACE_HOLDER)
125
+ return false;
126
+ if (isRejected) {
127
+ try {
128
+ task.reject(value);
129
+ }
130
+ catch {
131
+ }
132
+ resetTaskLocalFlags(task);
133
+ task.value = null;
134
+ task.resolve = PLACE_HOLDER;
135
+ task.reject = PLACE_HOLDER;
136
+ inUsed = (inUsed - 1) | 0;
137
+ freePush(task[TaskIndex.ID]);
138
+ return false;
139
+ }
140
+ task.value = value;
141
+ return enqueueKnown(task);
142
+ },
143
+ };
144
+ }
@@ -0,0 +1,23 @@
1
+ import { withResolvers } from "../common/with-resolvers.js";
2
+ import { type SharedBufferSource } from "../common/shared-buffer-region.js";
3
+ export declare const AbortSignalPoolExhausted: unique symbol;
4
+ export declare const EnqueuedAbortSignal: unique symbol;
5
+ export type SignalAbortStore = ReturnType<typeof signalAbortFactory>;
6
+ export type SetSignalResult = -1 | 0 | 1;
7
+ export declare const signalAbortFactory: ({ sab, maxSignals, }: {
8
+ sab: SharedBufferSource;
9
+ maxSignals?: number;
10
+ }) => {
11
+ max: number;
12
+ closeNow: number;
13
+ getSignal: () => number;
14
+ setSignal: (signal: number) => SetSignalResult;
15
+ abortAll: () => number;
16
+ hasAborted: (signal: number) => boolean;
17
+ resetSignal: (signal: number) => boolean;
18
+ inUseCount: () => number;
19
+ };
20
+ export declare class OneShotDeferred<T> {
21
+ #private;
22
+ constructor(deferred: ReturnType<typeof withResolvers<T>>, onSettle: () => void);
23
+ }
@@ -0,0 +1,126 @@
1
+ import { toSharedBufferRegion, } from "../common/shared-buffer-region.js";
2
+ const SLOT_BITS = 32;
3
+ const SLOT_MASK = SLOT_BITS - 1;
4
+ export const AbortSignalPoolExhausted = Symbol.for("knitting.abortSignal.poolExhausted");
5
+ export const EnqueuedAbortSignal = Symbol.for("knitting.abortSignal.enqueuedSignal");
6
+ export const signalAbortFactory = ({ sab, maxSignals, }) => {
7
+ const sabRegion = toSharedBufferRegion(sab);
8
+ const atomicView = new Uint32Array(sabRegion.sab, sabRegion.byteOffset, sabRegion.byteLength / Uint32Array.BYTES_PER_ELEMENT);
9
+ const size = atomicView.length;
10
+ const inUse = new Uint32Array(size);
11
+ const physicalMax = size * SLOT_BITS;
12
+ const max = (() => {
13
+ if (!Number.isFinite(maxSignals))
14
+ return physicalMax;
15
+ const parsed = Math.floor(maxSignals);
16
+ if (parsed <= 0)
17
+ return physicalMax;
18
+ return Math.min(parsed, physicalMax);
19
+ })();
20
+ const closeNow = max + 1;
21
+ let current = 0;
22
+ let cursor = 0;
23
+ const getSignal = () => {
24
+ if (current >= max)
25
+ return closeNow;
26
+ for (let step = 0; step < size; step++) {
27
+ const word = (cursor + step) % size;
28
+ const wordBase = word << 5;
29
+ const remaining = max - wordBase;
30
+ if (remaining <= 0)
31
+ continue;
32
+ const allowedMask = remaining >= SLOT_BITS
33
+ ? 0xFFFFFFFF
34
+ : ((1 << remaining) - 1) >>> 0;
35
+ const freeBits = ((~inUse[word]) & allowedMask) >>> 0;
36
+ if (freeBits === 0)
37
+ continue;
38
+ const bit = (freeBits & -freeBits) >>> 0;
39
+ inUse[word] = (inUse[word] | bit) >>> 0;
40
+ current = (current + 1) | 0;
41
+ cursor = (word + 1) % size;
42
+ // Recycled slot must start in "not aborted" state.
43
+ Atomics.and(atomicView, word, ~bit);
44
+ const bitIndex = 31 - Math.clz32(bit);
45
+ return (word << 5) + bitIndex;
46
+ }
47
+ return closeNow;
48
+ };
49
+ const setSignal = (signal) => {
50
+ // 0 => sentinel "abort because pool/size is exhausted"
51
+ if (signal === closeNow)
52
+ return 0;
53
+ // -1 => invalid signal id
54
+ if (!Number.isInteger(signal))
55
+ return -1;
56
+ if (signal < 0 || signal >= max)
57
+ return -1;
58
+ // 1 => signal bit was set as aborted
59
+ const word = signal >>> 5;
60
+ const bit = 1 << (signal & SLOT_MASK);
61
+ Atomics.or(atomicView, word, bit);
62
+ return 1;
63
+ };
64
+ const abortAll = () => {
65
+ for (let word = 0; word < size; word++) {
66
+ Atomics.store(atomicView, word, inUse[word]);
67
+ }
68
+ return current;
69
+ };
70
+ const hasAborted = (signal) => {
71
+ if (signal === closeNow)
72
+ return true;
73
+ if (!Number.isInteger(signal))
74
+ return false;
75
+ if (signal < 0 || signal >= max)
76
+ return false;
77
+ const word = signal >>> 5;
78
+ const bit = 1 << (signal & SLOT_MASK);
79
+ return (Atomics.load(atomicView, word) & bit) !== 0;
80
+ };
81
+ const resetSignal = (signal) => {
82
+ if (signal === closeNow)
83
+ return false;
84
+ if (!Number.isInteger(signal))
85
+ return false;
86
+ if (signal < 0 || signal >= max)
87
+ return false;
88
+ const word = signal >>> 5;
89
+ const bit = 1 << (signal & SLOT_MASK);
90
+ const used = (inUse[word] & bit) !== 0;
91
+ if (!used)
92
+ return false;
93
+ inUse[word] = (inUse[word] & ~bit) >>> 0;
94
+ if (current > 0)
95
+ current = (current - 1) | 0;
96
+ cursor = word;
97
+ // Clear aborted flag for future reuse.
98
+ Atomics.and(atomicView, word, ~bit);
99
+ return true;
100
+ };
101
+ return {
102
+ max,
103
+ closeNow,
104
+ getSignal,
105
+ setSignal,
106
+ abortAll,
107
+ hasAborted,
108
+ resetSignal,
109
+ inUseCount: () => current,
110
+ };
111
+ };
112
+ export class OneShotDeferred {
113
+ #triggered = false;
114
+ constructor(deferred, onSettle) {
115
+ const settleOnce = (fn) => (...args) => {
116
+ if (this.#triggered)
117
+ return;
118
+ this.#triggered = true;
119
+ onSettle();
120
+ fn(...args);
121
+ };
122
+ deferred.resolve = settleOnce(deferred.resolve);
123
+ deferred.reject = settleOnce(deferred.reject);
124
+ deferred.promise.reject = deferred.reject;
125
+ }
126
+ }
package/src/types.d.ts ADDED
@@ -0,0 +1,283 @@
1
+ import { endpointSymbol } from "./common/task-symbol.js";
2
+ import type { Envelope } from "./common/envelope.js";
3
+ import type { LockBufferTextCompat, SharedBufferTextCompat } from "./common/shared-buffer-text.js";
4
+ import type { SharedBufferRegion, SharedBufferSource } from "./common/shared-buffer-region.js";
5
+ import type { PayloadBufferMode, PayloadBufferOptions } from "./memory/payload-config.js";
6
+ import type { PermissionProtocol, PermissionProtocolInput, ResolvedPermissionProtocol } from "./permission/protocol.js";
7
+ type WorkerCall = {
8
+ fnNumber: number;
9
+ timeout?: TaskTimeout;
10
+ abortSignal?: AbortSignalOption;
11
+ };
12
+ type WorkerInvoke = (args: Uint8Array) => Promise<unknown>;
13
+ interface WorkerContext {
14
+ txIdle(): boolean;
15
+ call(descriptor: WorkerCall): WorkerInvoke;
16
+ kills(): Promise<void>;
17
+ }
18
+ type CreateContext = WorkerContext;
19
+ type WorkerData = {
20
+ sab: SharedBufferSource;
21
+ abortSignalSAB?: SharedBufferSource;
22
+ abortSignalMax?: number;
23
+ list: string[];
24
+ ids: number[];
25
+ thread: number;
26
+ totalNumberOfThread: number;
27
+ debug?: DebugOptions;
28
+ startAt: number;
29
+ workerOptions?: WorkerSettings;
30
+ at: number[];
31
+ lock: LockBuffers;
32
+ returnLock: LockBuffers;
33
+ payloadConfig?: PayloadBufferOptions;
34
+ permission?: ResolvedPermissionProtocol;
35
+ };
36
+ type LockBuffers = {
37
+ headers: SharedBufferSource;
38
+ headerSlotStrideU32?: number;
39
+ lockSector: SharedBufferSource;
40
+ payload: SharedBufferSource;
41
+ payloadSector: SharedBufferSource;
42
+ textCompat?: LockBufferTextCompat;
43
+ };
44
+ type JSONValue = string | number | boolean | null | JSONArray | JSONObject;
45
+ interface JSONObject {
46
+ [key: string]: JSONValue;
47
+ }
48
+ interface JSONArray extends Array<JSONValue> {
49
+ }
50
+ type Serializable = string | object | number | boolean | bigint;
51
+ type ValidInput = bigint | void | JSONValue | symbol | ArrayBuffer | Uint8Array | Int32Array | Float64Array | BigInt64Array | BigUint64Array | DataView | Error | Date | Envelope;
52
+ type Args = ValidInput | Serializable;
53
+ type MaybePromise<T> = T | Promise<T>;
54
+ type NoBlob<T> = T extends Blob ? never : T;
55
+ type TaskInput = NoBlob<Args> | Promise<NoBlob<Args>>;
56
+ type TaskTimeout = number | {
57
+ time: number;
58
+ maybe?: true;
59
+ default?: unknown;
60
+ error?: unknown;
61
+ };
62
+ type BivariantCallback<Args extends unknown[], R> = {
63
+ bivarianceHack(...args: Args): R;
64
+ }["bivarianceHack"];
65
+ type AbortSignalConfig = {
66
+ readonly hasAborted: true;
67
+ };
68
+ type AbortSignalOption = true | AbortSignalConfig | undefined;
69
+ type AbortSignalMethods<AS extends AbortSignalOption> = AS extends undefined ? never : {
70
+ hasAborted: () => boolean;
71
+ };
72
+ type AbortSignalToolkit<AS extends AbortSignalOption> = AbortSignalMethods<AS>;
73
+ type TaskFn<A extends TaskInput, B extends Args, AS extends AbortSignalOption = undefined> = BivariantCallback<AS extends undefined ? [NoBlob<Awaited<A>>] : [NoBlob<Awaited<A>>, AbortSignalToolkit<AS>], MaybePromise<NoBlob<B>>>;
74
+ type PromiseWithMaybeReject<T> = Promise<T> & {
75
+ reject: (reason?: unknown) => void;
76
+ };
77
+ type TaskLike<AS extends AbortSignalOption = AbortSignalOption> = {
78
+ readonly f: (...args: any[]) => any;
79
+ } & (AS extends undefined ? {
80
+ readonly abortSignal?: undefined;
81
+ } : {
82
+ readonly abortSignal: AS;
83
+ });
84
+ type Composed<A extends TaskInput = Args, B extends Args = Args, AS extends AbortSignalOption = undefined> = FixPoint<A, B, AS> & SecondPart;
85
+ type tasks = Record<string, Composed<any, any, AbortSignalOption>>;
86
+ type ComposedWithKey = Composed<any, any, AbortSignalOption> & {
87
+ name: string;
88
+ };
89
+ 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>>>);
90
+ type PromiseInput<T> = T | Promise<T>;
91
+ type PromisifyArgs<T extends unknown[]> = {
92
+ [K in keyof T]: PromiseInput<T[K]>;
93
+ };
94
+ type NormalizeUndefinedSingleArg<T extends unknown[]> = T extends [undefined] ? [] | [undefined] : T;
95
+ type AbortAwareCallArgs<T extends unknown[]> = T extends [...infer Head, AbortSignalToolkit<any>] ? NormalizeUndefinedSingleArg<Head> : NormalizeUndefinedSingleArg<T>;
96
+ type HostCallArgs<F extends (...args: any[]) => any, AS extends AbortSignalOption> = AS extends undefined ? Parameters<F> : AbortAwareCallArgs<Parameters<F>>;
97
+ type PromisifyCallArgs<F extends (...args: any[]) => any, AS extends AbortSignalOption> = HostCallArgs<F, AS> extends infer T ? T extends unknown[] ? PromisifyArgs<T> : never : never;
98
+ type AbortSignalOfTask<T extends TaskLike<any>> = T extends {
99
+ readonly abortSignal: infer AS;
100
+ } ? Extract<AS, AbortSignalOption> : undefined;
101
+ type FunctionMapType<T extends Record<string, TaskLike<any>>> = {
102
+ [K in keyof T]: PromiseWrapped<T[K]["f"], AbortSignalOfTask<T[K]>>;
103
+ };
104
+ interface FixPointBase<A extends TaskInput, B extends Args, AS extends AbortSignalOption = undefined> {
105
+ readonly f: TaskFn<A, B, AS>;
106
+ readonly timeout?: TaskTimeout;
107
+ }
108
+ type FixPoint<A extends TaskInput, B extends Args, AS extends AbortSignalOption = undefined> = FixPointBase<A, B, AS> & (AS extends undefined ? {
109
+ readonly abortSignal?: undefined;
110
+ } : {
111
+ readonly abortSignal: AS;
112
+ });
113
+ type ImportTaskOptions<A extends TaskInput = void, B extends Args = void, AS extends AbortSignalOption = undefined> = Omit<FixPoint<A, B, AS>, "f"> & {
114
+ readonly href: string;
115
+ readonly name?: string;
116
+ };
117
+ type SecondPart = {
118
+ readonly [endpointSymbol]: true;
119
+ readonly id: number;
120
+ /**
121
+ * IMPORTANT: `at` helps to create a `createPool` because we dont know
122
+ * the name of the variable at runtime, so basically this gets the logical order
123
+ * of the exported file, so no matter the name the worker can track which ` task `
124
+ * to track
125
+ */
126
+ readonly at: number;
127
+ readonly importedFrom: string;
128
+ };
129
+ type SingleTaskPool<A extends TaskInput = Args, B extends Args = Args, AS extends AbortSignalOption = undefined> = {
130
+ call: PromiseWrapped<TaskFn<A, B, AS>, AS>;
131
+ shutdown: (delayMs?: number) => Promise<void>;
132
+ };
133
+ type Pool<T extends Record<string, TaskLike<any>>> = {
134
+ shutdown: (delayMs?: number) => Promise<void>;
135
+ call: FunctionMapType<T>;
136
+ };
137
+ type ReturnFixed<A extends TaskInput = undefined, B extends Args = undefined, AS extends AbortSignalOption = undefined> = FixPoint<A, B, AS> & SecondPart & {
138
+ createPool: (options?: CreatePool) => SingleTaskPool<A, B, AS>;
139
+ };
140
+ type External = unknown;
141
+ type Inliner = {
142
+ position?: "first" | "last";
143
+ /**
144
+ * Inline tasks per event loop tick.
145
+ * Defaults to 1 when inliner is enabled.
146
+ */
147
+ batchSize?: number;
148
+ /**
149
+ * Minimum in-flight calls before routing can use the inline host lane.
150
+ * Defaults to 1 (inline lane available immediately).
151
+ */
152
+ dispatchThreshold?: number;
153
+ };
154
+ type BalancerStrategy = "roundRobin" | "robinRound" | "firstIdle" | "randomLane" | "firstIdleOrRandom";
155
+ type Balancer = BalancerStrategy | {
156
+ /**
157
+ * Optional. Defaults to "roundRobin".
158
+ */
159
+ strategy?: BalancerStrategy;
160
+ };
161
+ type DebugOptions = {
162
+ extras?: boolean;
163
+ logMain?: boolean;
164
+ logHref?: boolean;
165
+ logImportedUrl?: boolean;
166
+ };
167
+ type WorkerSettings = {
168
+ resolveAfterFinishingAll?: true;
169
+ /**
170
+ * Experimental worker runtime.
171
+ * "thread" uses Worker/worker_threads. "process" spawns another JavaScript
172
+ * runtime and shares one inherited fd-backed memory mapping.
173
+ */
174
+ runtime?: "thread" | "process";
175
+ /**
176
+ * Runtime executable to use when runtime is "process". Defaults to "bun".
177
+ */
178
+ processRuntime?: "bun" | "deno" | "node";
179
+ /**
180
+ * Command argv to prepend before the process worker runtime command.
181
+ * Useful for wrappers such as systemd-run, cgexec, nice, or taskset.
182
+ *
183
+ * Example:
184
+ * ["systemd-run", "--scope", "-p", "MemoryMax=500M", "-p", "CPUQuota=25%"]
185
+ */
186
+ processCommandPrefix?: string[];
187
+ timers?: WorkerTimers;
188
+ /**
189
+ * Hard task execution timeout in milliseconds.
190
+ * When exceeded, the pool is force-shutdown to stop runaway CPU tasks.
191
+ */
192
+ hardTimeoutMs?: number;
193
+ };
194
+ type WorkerTimers = {
195
+ /**
196
+ * Busy-spin budget before parking (microseconds).
197
+ */
198
+ spinMicroseconds?: number;
199
+ /**
200
+ * Atomics.wait timeout when parked (milliseconds).
201
+ */
202
+ parkMs?: number;
203
+ /**
204
+ * Atomics.pause duration during spin (nanoseconds).
205
+ * Set to 0 (or less) to disable pause calls.
206
+ */
207
+ pauseNanoseconds?: number;
208
+ };
209
+ type DispatcherSettings = {
210
+ /**
211
+ * How many immediate notify loops before backoff kicks in.
212
+ */
213
+ stallFreeLoops?: number;
214
+ /**
215
+ * Max backoff delay (milliseconds).
216
+ */
217
+ maxBackoffMs?: number;
218
+ };
219
+ type CreatePool = {
220
+ threads?: number;
221
+ /**
222
+ * @deprecated Too risky with processes, need to rewrite or delete.
223
+ */
224
+ inliner?: Inliner;
225
+ balancer?: Balancer;
226
+ worker?: WorkerSettings;
227
+ /**
228
+ * Payload transport settings.
229
+ */
230
+ payload?: PayloadBufferOptions;
231
+ /**
232
+ * Initial payload SharedArrayBuffer size (bytes) per worker direction.
233
+ * Defaults to 4 MiB when growable SAB is available, otherwise defaults to
234
+ * `payloadMaxBytes`.
235
+ * @deprecated Use `payload.payloadInitialBytes`.
236
+ */
237
+ payloadInitialBytes?: number;
238
+ /**
239
+ * Maximum payload SharedArrayBuffer size (bytes) per worker direction.
240
+ * Defaults to 64 MiB.
241
+ * @deprecated Use `payload.payloadMaxByteLength`.
242
+ */
243
+ payloadMaxBytes?: number;
244
+ /**
245
+ * @deprecated Use `payload.mode`.
246
+ */
247
+ bufferMode?: PayloadBufferMode;
248
+ /**
249
+ * @deprecated Use `payload.maxPayloadBytes`.
250
+ */
251
+ maxPayloadBytes?: number;
252
+ /**
253
+ * Abort-aware signal pool capacity.
254
+ * Defaults to `258`.
255
+ */
256
+ abortSignalCapacity?: number;
257
+ /**
258
+ * Host dispatcher backoff and scheduling options.
259
+ */
260
+ host?: DispatcherSettings;
261
+ /**
262
+ * Extra Node.js execArgv flags for worker threads (e.g. ["--expose-gc"]).
263
+ * Defaults to process.execArgv plus "--expose-gc" when allowed.
264
+ */
265
+ workerExecArgv?: string[];
266
+ /**
267
+ * Runtime permission protocol.
268
+ * Omit to use strict defaults with `allowImport: true`.
269
+ * Use `"strict"` (default for object mode) or `"unsafe"`.
270
+ * Accepts object form for fine-grained permission controls.
271
+ */
272
+ permission?: PermissionProtocolInput;
273
+ /**
274
+ * @deprecated Use `host` instead.
275
+ */
276
+ dispatcher?: DispatcherSettings;
277
+ debug?: DebugOptions;
278
+ source?: string;
279
+ };
280
+ 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, WorkerSettings as WorkerSettings, 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, };
281
+ export type { Task as Task } from "./memory/lock.js";
282
+ export { LockBound as LockBound, PayloadBuffer as PayloadBuffer, PayloadSignal as PayloadSignal, TaskIndex as TaskIndex, } from "./memory/lock.js";
283
+ export type { RegisterMalloc as RegisterMalloc } from "./memory/regionRegistry.js";
package/src/types.js ADDED
@@ -0,0 +1,2 @@
1
+ import { endpointSymbol } from "./common/task-symbol.js";
2
+ export { LockBound as LockBound, PayloadBuffer as PayloadBuffer, PayloadSignal as PayloadSignal, TaskIndex as TaskIndex, } from "./memory/lock.js";
@@ -0,0 +1,12 @@
1
+ import { type Task } from "../memory/lock.js";
2
+ import type { TimeoutSpec } from "./task-loader.js";
3
+ type WorkerJob = (args: unknown, abortToolkit?: unknown) => unknown;
4
+ type SlotRunner = (slot: Task) => unknown;
5
+ type HasAborted = (signal: number) => boolean;
6
+ export declare const composeWorkerRunner: ({ job, timeout, hasAborted, now, }: {
7
+ job: WorkerJob;
8
+ timeout?: TimeoutSpec;
9
+ hasAborted?: HasAborted;
10
+ now?: () => number;
11
+ }) => SlotRunner;
12
+ export {};