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.
- package/LICENSE +202 -0
- package/README.md +632 -0
- package/knitting.d.ts +4 -0
- package/knitting.js +5 -0
- package/map.md +264 -0
- package/package.json +77 -0
- package/prebuilds/darwin-arm64-node-127/knitting_shared_memory.node +0 -0
- package/prebuilds/darwin-arm64-node-127/knitting_shm.node +0 -0
- package/prebuilds/darwin-arm64-node-137/knitting_shared_memory.node +0 -0
- package/prebuilds/darwin-arm64-node-137/knitting_shm.node +0 -0
- package/prebuilds/darwin-x64-node-127/knitting_shared_memory.node +0 -0
- package/prebuilds/darwin-x64-node-127/knitting_shm.node +0 -0
- package/prebuilds/darwin-x64-node-137/knitting_shared_memory.node +0 -0
- package/prebuilds/darwin-x64-node-137/knitting_shm.node +0 -0
- package/prebuilds/linux-x64-node-127/knitting_shared_memory.node +0 -0
- package/prebuilds/linux-x64-node-127/knitting_shm.node +0 -0
- package/prebuilds/linux-x64-node-137/knitting_shared_memory.node +0 -0
- package/prebuilds/linux-x64-node-137/knitting_shm.node +0 -0
- package/process-shared-buffer.d.ts +1 -0
- package/process-shared-buffer.js +1 -0
- package/scripts/build-native-addons.ts +295 -0
- package/src/api.d.ts +55 -0
- package/src/api.js +384 -0
- package/src/common/envelope.d.ts +11 -0
- package/src/common/envelope.js +8 -0
- package/src/common/module-url.d.ts +1 -0
- package/src/common/module-url.js +24 -0
- package/src/common/node-compat.d.ts +20 -0
- package/src/common/node-compat.js +24 -0
- package/src/common/path-canonical.d.ts +6 -0
- package/src/common/path-canonical.js +41 -0
- package/src/common/runtime.d.ts +15 -0
- package/src/common/runtime.js +91 -0
- package/src/common/shared-buffer-region.d.ts +11 -0
- package/src/common/shared-buffer-region.js +21 -0
- package/src/common/shared-buffer-text.d.ts +16 -0
- package/src/common/shared-buffer-text.js +65 -0
- package/src/common/task-source.d.ts +2 -0
- package/src/common/task-source.js +79 -0
- package/src/common/task-symbol.d.ts +1 -0
- package/src/common/task-symbol.js +1 -0
- package/src/common/with-resolvers.d.ts +9 -0
- package/src/common/with-resolvers.js +23 -0
- package/src/common/worker-runtime.d.ts +40 -0
- package/src/common/worker-runtime.js +52 -0
- package/src/connections/bun.d.ts +20 -0
- package/src/connections/bun.js +159 -0
- package/src/connections/deno.d.ts +20 -0
- package/src/connections/deno.js +150 -0
- package/src/connections/file-descriptor.d.ts +37 -0
- package/src/connections/file-descriptor.js +139 -0
- package/src/connections/index.d.ts +3 -0
- package/src/connections/index.js +3 -0
- package/src/connections/node-addons.d.ts +5 -0
- package/src/connections/node-addons.js +43 -0
- package/src/connections/node.d.ts +29 -0
- package/src/connections/node.js +59 -0
- package/src/connections/posix.d.ts +31 -0
- package/src/connections/posix.js +71 -0
- package/src/connections/process-shared-buffer.d.ts +67 -0
- package/src/connections/process-shared-buffer.js +267 -0
- package/src/connections/types.d.ts +48 -0
- package/src/connections/types.js +37 -0
- package/src/error.d.ts +13 -0
- package/src/error.js +49 -0
- package/src/ipc/tools/ring-queue.d.ts +33 -0
- package/src/ipc/tools/ring-queue.js +159 -0
- package/src/ipc/transport/shared-memory.d.ts +25 -0
- package/src/ipc/transport/shared-memory.js +35 -0
- package/src/knitting_shared_memory.cc +436 -0
- package/src/knitting_shm.cc +476 -0
- package/src/memory/byte-carpet.d.ts +73 -0
- package/src/memory/byte-carpet.js +157 -0
- package/src/memory/lock.d.ts +190 -0
- package/src/memory/lock.js +856 -0
- package/src/memory/payload-config.d.ts +22 -0
- package/src/memory/payload-config.js +67 -0
- package/src/memory/payloadCodec.d.ts +46 -0
- package/src/memory/payloadCodec.js +1157 -0
- package/src/memory/regionRegistry.d.ts +17 -0
- package/src/memory/regionRegistry.js +285 -0
- package/src/memory/shared-buffer-io.d.ts +53 -0
- package/src/memory/shared-buffer-io.js +380 -0
- package/src/permission/index.d.ts +2 -0
- package/src/permission/index.js +2 -0
- package/src/permission/protocol.d.ts +166 -0
- package/src/permission/protocol.js +640 -0
- package/src/runtime/balancer.d.ts +19 -0
- package/src/runtime/balancer.js +149 -0
- package/src/runtime/dispatcher.d.ts +34 -0
- package/src/runtime/dispatcher.js +142 -0
- package/src/runtime/inline-executor.d.ts +10 -0
- package/src/runtime/inline-executor.js +270 -0
- package/src/runtime/pool.d.ts +43 -0
- package/src/runtime/pool.js +922 -0
- package/src/runtime/tx-queue.d.ts +25 -0
- package/src/runtime/tx-queue.js +144 -0
- package/src/shared/abortSignal.d.ts +23 -0
- package/src/shared/abortSignal.js +126 -0
- package/src/types.d.ts +283 -0
- package/src/types.js +2 -0
- package/src/worker/composable-runners.d.ts +12 -0
- package/src/worker/composable-runners.js +105 -0
- package/src/worker/loop.d.ts +2 -0
- package/src/worker/loop.js +453 -0
- package/src/worker/rx-queue.d.ts +22 -0
- package/src/worker/rx-queue.js +124 -0
- package/src/worker/safety/index.d.ts +4 -0
- package/src/worker/safety/index.js +4 -0
- package/src/worker/safety/performance.d.ts +1 -0
- package/src/worker/safety/performance.js +17 -0
- package/src/worker/safety/process.d.ts +2 -0
- package/src/worker/safety/process.js +79 -0
- package/src/worker/safety/startup.d.ts +16 -0
- package/src/worker/safety/startup.js +30 -0
- package/src/worker/safety/worker-data.d.ts +2 -0
- package/src/worker/safety/worker-data.js +36 -0
- package/src/worker/task-loader.d.ts +26 -0
- package/src/worker/task-loader.js +66 -0
- package/src/worker/timers.d.ts +18 -0
- package/src/worker/timers.js +97 -0
package/src/api.d.ts
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { endpointSymbol } from "./common/task-symbol.js";
|
|
2
|
+
import type { Args, AbortSignalConfig, AbortSignalOption, AbortSignalToolkit, CreatePool, FixPoint, MaybePromise, Pool, TaskInput, ReturnFixed, ImportTaskOptions, TaskTimeout, tasks } from "./types.js";
|
|
3
|
+
type ToListAndIds = {
|
|
4
|
+
list: string[];
|
|
5
|
+
ids: number[];
|
|
6
|
+
at: number[];
|
|
7
|
+
};
|
|
8
|
+
type ToListAndIdsFn = (args: tasks) => ToListAndIds;
|
|
9
|
+
type CreatePoolFactory = (options: CreatePool) => <T extends tasks>(tasks: T) => Pool<T>;
|
|
10
|
+
type InferredTaskFunction = (...args: any[]) => MaybePromise<Args>;
|
|
11
|
+
type InferredTaskInput<F extends InferredTaskFunction, AS extends AbortSignalOption> = Parameters<F> extends [] ? void : AS extends undefined ? Parameters<F> extends [infer A] ? A extends TaskInput ? A : never : never : Parameters<F> extends [infer A] ? A extends TaskInput ? A : never : Parameters<F> extends [infer A, AbortSignalToolkit<AS>] ? A extends TaskInput ? A : never : never;
|
|
12
|
+
type InferredTaskOutput<F extends InferredTaskFunction> = Awaited<ReturnType<F>> extends infer R ? R extends Blob ? never : R extends Args ? R : never : never;
|
|
13
|
+
type InferredTaskShape<F extends InferredTaskFunction, AS extends AbortSignalOption> = [
|
|
14
|
+
InferredTaskInput<F, AS>
|
|
15
|
+
] extends [never] ? never : [InferredTaskOutput<F>] extends [never] ? never : {
|
|
16
|
+
readonly f: F;
|
|
17
|
+
readonly timeout?: TaskTimeout;
|
|
18
|
+
} & (AS extends undefined ? {
|
|
19
|
+
readonly abortSignal?: undefined;
|
|
20
|
+
} : {
|
|
21
|
+
readonly abortSignal: AS;
|
|
22
|
+
});
|
|
23
|
+
export declare const isMain: boolean;
|
|
24
|
+
export { endpointSymbol as endpointSymbol };
|
|
25
|
+
/**
|
|
26
|
+
* With this information we can recreate the logical order of
|
|
27
|
+
* relevant exported functions from a file, also it helps to
|
|
28
|
+
* track a task before naming, ` export ` elements have to be declared
|
|
29
|
+
* at top level and without branching, we take advantage of this to
|
|
30
|
+
* correctly map them.
|
|
31
|
+
*
|
|
32
|
+
*/
|
|
33
|
+
export declare const toListAndIds: ToListAndIdsFn;
|
|
34
|
+
export declare const createPool: CreatePoolFactory;
|
|
35
|
+
/**
|
|
36
|
+
* Define a worker task.
|
|
37
|
+
*
|
|
38
|
+
* Input may be a direct value or a native Promise of that value.
|
|
39
|
+
* Thenables/PromiseLike values are treated as plain values.
|
|
40
|
+
*/
|
|
41
|
+
export declare function task<F extends InferredTaskFunction>(I: InferredTaskShape<F, undefined>): ReturnFixed<InferredTaskInput<F, undefined>, InferredTaskOutput<F>, undefined>;
|
|
42
|
+
export declare function task<F extends InferredTaskFunction>(I: InferredTaskShape<F, true>): ReturnFixed<InferredTaskInput<F, true>, InferredTaskOutput<F>, true>;
|
|
43
|
+
export declare function task<AS extends AbortSignalConfig, F extends InferredTaskFunction>(I: InferredTaskShape<F, AS>): ReturnFixed<InferredTaskInput<F, AS>, InferredTaskOutput<F>, AS>;
|
|
44
|
+
export declare function task<A extends TaskInput = void, B extends Args = void>(I: FixPoint<A, B, true>): ReturnFixed<A, B, true>;
|
|
45
|
+
export declare function task<A extends TaskInput = void, B extends Args = void, AS extends AbortSignalConfig = AbortSignalConfig>(I: FixPoint<A, B, AS>): ReturnFixed<A, B, AS>;
|
|
46
|
+
export declare function task<A extends TaskInput = void, B extends Args = void>(I: FixPoint<A, B, undefined>): ReturnFixed<A, B, undefined>;
|
|
47
|
+
/**
|
|
48
|
+
* Define a task whose worker-side function is imported dynamically from `href`.
|
|
49
|
+
*
|
|
50
|
+
* This keeps module import/evaluation inside the worker, so worker permission
|
|
51
|
+
* policies apply to that import path.
|
|
52
|
+
*/
|
|
53
|
+
export declare function importTask<A extends TaskInput = void, B extends Args = void>(options: ImportTaskOptions<A, B, true>): ReturnFixed<A, B, true>;
|
|
54
|
+
export declare function importTask<A extends TaskInput = void, B extends Args = void, AS extends AbortSignalConfig = AbortSignalConfig>(options: ImportTaskOptions<A, B, AS>): ReturnFixed<A, B, AS>;
|
|
55
|
+
export declare function importTask<A extends TaskInput = void, B extends Args = void>(options: ImportTaskOptions<A, B, undefined>): ReturnFixed<A, B, undefined>;
|
package/src/api.js
ADDED
|
@@ -0,0 +1,384 @@
|
|
|
1
|
+
var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExtension) || function (path, preserveJsx) {
|
|
2
|
+
if (typeof path === "string" && /^\.\.?\//.test(path)) {
|
|
3
|
+
return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {
|
|
4
|
+
return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js");
|
|
5
|
+
});
|
|
6
|
+
}
|
|
7
|
+
return path;
|
|
8
|
+
};
|
|
9
|
+
import { getCallerFilePath } from "./common/task-source.js";
|
|
10
|
+
import { genTaskID } from "./common/task-source.js";
|
|
11
|
+
import { toModuleUrl } from "./common/module-url.js";
|
|
12
|
+
import { endpointSymbol } from "./common/task-symbol.js";
|
|
13
|
+
import { spawnWorkerContext } from "./runtime/pool.js";
|
|
14
|
+
import { RUNTIME_IS_MAIN_THREAD, RUNTIME_WORKER_DATA, } from "./common/worker-runtime.js";
|
|
15
|
+
import { resolvePermissionProtocol, toRuntimePermissionFlags, } from "./permission/index.js";
|
|
16
|
+
import { getNodeProcess } from "./common/node-compat.js";
|
|
17
|
+
import { managerMethod } from "./runtime/balancer.js";
|
|
18
|
+
import { createInlineExecutor } from "./runtime/inline-executor.js";
|
|
19
|
+
const MAX_FUNCTION_ID = 0xFFFF;
|
|
20
|
+
const MAX_FUNCTION_COUNT = MAX_FUNCTION_ID + 1;
|
|
21
|
+
export const isMain = RUNTIME_IS_MAIN_THREAD;
|
|
22
|
+
export { endpointSymbol as endpointSymbol };
|
|
23
|
+
/**
|
|
24
|
+
* With this information we can recreate the logical order of
|
|
25
|
+
* relevant exported functions from a file, also it helps to
|
|
26
|
+
* track a task before naming, ` export ` elements have to be declared
|
|
27
|
+
* at top level and without branching, we take advantage of this to
|
|
28
|
+
* correctly map them.
|
|
29
|
+
*
|
|
30
|
+
*/
|
|
31
|
+
export const toListAndIds = (args) => {
|
|
32
|
+
const result = Object.values(args)
|
|
33
|
+
.reduce((acc, v) => (acc[0].add(v.importedFrom),
|
|
34
|
+
acc[1].add(v.id),
|
|
35
|
+
acc[2].add(v.at),
|
|
36
|
+
acc), [
|
|
37
|
+
new Set(),
|
|
38
|
+
new Set(),
|
|
39
|
+
new Set()
|
|
40
|
+
]);
|
|
41
|
+
return {
|
|
42
|
+
list: [...result[0]],
|
|
43
|
+
ids: [...result[1]],
|
|
44
|
+
at: [...result[2]],
|
|
45
|
+
};
|
|
46
|
+
};
|
|
47
|
+
export const createPool = ({ threads, debug, inliner, balancer, payload, payloadInitialBytes, payloadMaxBytes, bufferMode, maxPayloadBytes, abortSignalCapacity, source, worker, workerExecArgv, permission, dispatcher, host, }) => (tasks) => {
|
|
48
|
+
/**
|
|
49
|
+
* This functions is only available in the main thread.
|
|
50
|
+
* Also triggers when debug extra is enabled.
|
|
51
|
+
*/
|
|
52
|
+
if (RUNTIME_IS_MAIN_THREAD === false) {
|
|
53
|
+
if ((debug?.extras === true)) {
|
|
54
|
+
console.warn("createPool has been called with : " + JSON.stringify(RUNTIME_WORKER_DATA));
|
|
55
|
+
}
|
|
56
|
+
const notMainThreadError = () => {
|
|
57
|
+
throw new Error("createPool can only be called in the main thread.");
|
|
58
|
+
};
|
|
59
|
+
const throwingProxyTarget = function () {
|
|
60
|
+
return notMainThreadError();
|
|
61
|
+
};
|
|
62
|
+
const throwingProxyHandler = {
|
|
63
|
+
get: function () {
|
|
64
|
+
return notMainThreadError;
|
|
65
|
+
},
|
|
66
|
+
};
|
|
67
|
+
const mainThreadOnlyProxy = new Proxy(throwingProxyTarget, throwingProxyHandler);
|
|
68
|
+
//@ts-ignore
|
|
69
|
+
return {
|
|
70
|
+
shutdown: mainThreadOnlyProxy,
|
|
71
|
+
call: mainThreadOnlyProxy,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
const { list, ids, at } = toListAndIds(tasks), listOfFunctions = Object.entries(tasks).map(([k, v]) => ({
|
|
75
|
+
...v,
|
|
76
|
+
name: k,
|
|
77
|
+
}))
|
|
78
|
+
.sort((a, b) => a.name.localeCompare(b.name));
|
|
79
|
+
if (listOfFunctions.length > MAX_FUNCTION_COUNT) {
|
|
80
|
+
throw new RangeError(`Too many tasks: received ${listOfFunctions.length}. ` +
|
|
81
|
+
`Maximum is ${MAX_FUNCTION_COUNT} (Uint16 function IDs: 0..${MAX_FUNCTION_ID}).`);
|
|
82
|
+
}
|
|
83
|
+
const usingInliner = typeof inliner === "object" && inliner != null;
|
|
84
|
+
const totalNumberOfThread = (threads ?? 1) +
|
|
85
|
+
(usingInliner ? 1 : 0);
|
|
86
|
+
const permissionProtocol = resolvePermissionProtocol({
|
|
87
|
+
permission: permission ?? {
|
|
88
|
+
mode: "strict",
|
|
89
|
+
allowImport: true,
|
|
90
|
+
},
|
|
91
|
+
modules: list,
|
|
92
|
+
});
|
|
93
|
+
const permissionExecArgv = toRuntimePermissionFlags(permissionProtocol);
|
|
94
|
+
const nodeProcess = getNodeProcess();
|
|
95
|
+
const allowedFlags = nodeProcess?.allowedNodeEnvironmentFlags ?? null;
|
|
96
|
+
const isNodePermissionFlag = (flag) => {
|
|
97
|
+
const key = flag.split("=", 1)[0];
|
|
98
|
+
return key === "--permission" ||
|
|
99
|
+
key === "--experimental-permission" ||
|
|
100
|
+
key === "--allow-fs-read" ||
|
|
101
|
+
key === "--allow-fs-write" ||
|
|
102
|
+
key === "--allow-worker" ||
|
|
103
|
+
key === "--allow-child-process" ||
|
|
104
|
+
key === "--allow-addons" ||
|
|
105
|
+
key === "--allow-wasi";
|
|
106
|
+
};
|
|
107
|
+
const stripNodePermissionFlags = (flags) => flags?.filter((flag) => !isNodePermissionFlag(flag));
|
|
108
|
+
const dedupeFlags = (flags) => {
|
|
109
|
+
const out = [];
|
|
110
|
+
const seen = new Set();
|
|
111
|
+
for (const flag of flags) {
|
|
112
|
+
if (seen.has(flag))
|
|
113
|
+
continue;
|
|
114
|
+
seen.add(flag);
|
|
115
|
+
out.push(flag);
|
|
116
|
+
}
|
|
117
|
+
return out;
|
|
118
|
+
};
|
|
119
|
+
const sanitizeExecArgv = (flags) => {
|
|
120
|
+
if (!flags || flags.length === 0)
|
|
121
|
+
return undefined;
|
|
122
|
+
if (!allowedFlags)
|
|
123
|
+
return flags;
|
|
124
|
+
const filtered = flags.filter((flag) => {
|
|
125
|
+
const key = flag.split("=", 1)[0];
|
|
126
|
+
return allowedFlags.has(key);
|
|
127
|
+
});
|
|
128
|
+
return filtered.length > 0 ? filtered : undefined;
|
|
129
|
+
};
|
|
130
|
+
const inheritedExecArgv = Array.isArray(nodeProcess?.execArgv)
|
|
131
|
+
? nodeProcess.execArgv
|
|
132
|
+
: undefined;
|
|
133
|
+
const defaultExecArgvCandidate = workerExecArgv ??
|
|
134
|
+
(inheritedExecArgv
|
|
135
|
+
? (allowedFlags?.has("--expose-gc") === true
|
|
136
|
+
? (inheritedExecArgv.includes("--expose-gc")
|
|
137
|
+
? inheritedExecArgv
|
|
138
|
+
: [...inheritedExecArgv, "--expose-gc"])
|
|
139
|
+
: inheritedExecArgv)
|
|
140
|
+
: undefined);
|
|
141
|
+
const defaultExecArgv = permissionProtocol?.unsafe === true
|
|
142
|
+
? stripNodePermissionFlags(defaultExecArgvCandidate)
|
|
143
|
+
: defaultExecArgvCandidate;
|
|
144
|
+
const combinedExecArgv = dedupeFlags([
|
|
145
|
+
...permissionExecArgv,
|
|
146
|
+
...(defaultExecArgv ?? []),
|
|
147
|
+
]);
|
|
148
|
+
const execArgv = sanitizeExecArgv(combinedExecArgv.length > 0 ? combinedExecArgv : undefined);
|
|
149
|
+
const hostDispatcher = host ?? dispatcher;
|
|
150
|
+
const usesAbortSignal = listOfFunctions.some((fn) => fn.abortSignal !== undefined);
|
|
151
|
+
const hardTimeoutMs = Number.isFinite(worker?.hardTimeoutMs)
|
|
152
|
+
? Math.max(1, Math.floor(worker?.hardTimeoutMs))
|
|
153
|
+
: undefined;
|
|
154
|
+
let workers = Array.from({
|
|
155
|
+
length: threads ?? 1,
|
|
156
|
+
}).map((_, thread) => spawnWorkerContext({
|
|
157
|
+
list,
|
|
158
|
+
ids,
|
|
159
|
+
at,
|
|
160
|
+
thread,
|
|
161
|
+
debug,
|
|
162
|
+
totalNumberOfThread,
|
|
163
|
+
source,
|
|
164
|
+
workerOptions: worker,
|
|
165
|
+
workerExecArgv: execArgv,
|
|
166
|
+
host: hostDispatcher,
|
|
167
|
+
payload,
|
|
168
|
+
payloadInitialBytes,
|
|
169
|
+
payloadMaxBytes,
|
|
170
|
+
bufferMode,
|
|
171
|
+
maxPayloadBytes,
|
|
172
|
+
abortSignalCapacity,
|
|
173
|
+
usesAbortSignal,
|
|
174
|
+
permission: permissionProtocol,
|
|
175
|
+
}));
|
|
176
|
+
if (usingInliner) {
|
|
177
|
+
const mainThread = createInlineExecutor({
|
|
178
|
+
tasks,
|
|
179
|
+
genTaskID,
|
|
180
|
+
batchSize: inliner?.batchSize ?? 1,
|
|
181
|
+
});
|
|
182
|
+
if (inliner?.position === "first") {
|
|
183
|
+
workers = [
|
|
184
|
+
//@ts-ignore
|
|
185
|
+
mainThread,
|
|
186
|
+
...workers,
|
|
187
|
+
];
|
|
188
|
+
}
|
|
189
|
+
else {
|
|
190
|
+
workers.push(
|
|
191
|
+
//@ts-ignore
|
|
192
|
+
mainThread);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
const inlinerIndex = usingInliner
|
|
196
|
+
? (inliner?.position === "first" ? 0 : workers.length - 1)
|
|
197
|
+
: -1;
|
|
198
|
+
const inlinerDispatchThreshold = Number.isFinite(inliner?.dispatchThreshold)
|
|
199
|
+
? Math.max(1, Math.floor(inliner?.dispatchThreshold ?? 1))
|
|
200
|
+
: 1;
|
|
201
|
+
let closing = false;
|
|
202
|
+
let closePromise;
|
|
203
|
+
let shutdownPromise;
|
|
204
|
+
const closePoolNow = () => {
|
|
205
|
+
if (closePromise)
|
|
206
|
+
return closePromise;
|
|
207
|
+
closing = true;
|
|
208
|
+
closePromise = Promise.allSettled(workers.map((context) => context.kills()))
|
|
209
|
+
.then(() => undefined);
|
|
210
|
+
return closePromise;
|
|
211
|
+
};
|
|
212
|
+
const wrapGuardedInvoke = ({ invoke, taskName, }) => (args) => {
|
|
213
|
+
if (closing) {
|
|
214
|
+
return Promise.reject(new Error("Pool is shut down"));
|
|
215
|
+
}
|
|
216
|
+
const pending = invoke(args);
|
|
217
|
+
if (!hardTimeoutMs)
|
|
218
|
+
return pending;
|
|
219
|
+
return new Promise((resolve, reject) => {
|
|
220
|
+
let settled = false;
|
|
221
|
+
const timeoutId = setTimeout(() => {
|
|
222
|
+
if (settled)
|
|
223
|
+
return;
|
|
224
|
+
settled = true;
|
|
225
|
+
reject(new Error(`Task hard timeout after ${hardTimeoutMs}ms (${taskName}); pool force-shutdown`));
|
|
226
|
+
void closePoolNow();
|
|
227
|
+
}, hardTimeoutMs);
|
|
228
|
+
pending.then((value) => {
|
|
229
|
+
if (settled)
|
|
230
|
+
return;
|
|
231
|
+
settled = true;
|
|
232
|
+
clearTimeout(timeoutId);
|
|
233
|
+
resolve(value);
|
|
234
|
+
}, (error) => {
|
|
235
|
+
if (settled)
|
|
236
|
+
return;
|
|
237
|
+
settled = true;
|
|
238
|
+
clearTimeout(timeoutId);
|
|
239
|
+
reject(error);
|
|
240
|
+
});
|
|
241
|
+
});
|
|
242
|
+
};
|
|
243
|
+
const shutdownWithDelay = (delayMs) => {
|
|
244
|
+
if (closePromise)
|
|
245
|
+
return closePromise;
|
|
246
|
+
if (shutdownPromise)
|
|
247
|
+
return shutdownPromise;
|
|
248
|
+
const ms = Number.isFinite(delayMs)
|
|
249
|
+
? Math.max(0, Math.floor(delayMs))
|
|
250
|
+
: 0;
|
|
251
|
+
shutdownPromise = (async () => {
|
|
252
|
+
if (closePromise)
|
|
253
|
+
return await closePromise;
|
|
254
|
+
if (ms > 0) {
|
|
255
|
+
await new Promise((resolve) => setTimeout(resolve, ms));
|
|
256
|
+
}
|
|
257
|
+
if (closePromise)
|
|
258
|
+
return await closePromise;
|
|
259
|
+
await closePoolNow();
|
|
260
|
+
})();
|
|
261
|
+
return shutdownPromise;
|
|
262
|
+
};
|
|
263
|
+
const indexedFunctions = listOfFunctions.map((fn, index) => ({
|
|
264
|
+
name: fn.name,
|
|
265
|
+
index,
|
|
266
|
+
timeout: fn.timeout,
|
|
267
|
+
abortSignal: fn.abortSignal,
|
|
268
|
+
}));
|
|
269
|
+
const callHandlers = new Map();
|
|
270
|
+
for (const { name } of indexedFunctions) {
|
|
271
|
+
callHandlers.set(name, []);
|
|
272
|
+
}
|
|
273
|
+
for (const worker of workers) {
|
|
274
|
+
for (const { name, index, timeout, abortSignal } of indexedFunctions) {
|
|
275
|
+
callHandlers.get(name).push(wrapGuardedInvoke({
|
|
276
|
+
taskName: name,
|
|
277
|
+
invoke: worker.call({
|
|
278
|
+
fnNumber: index,
|
|
279
|
+
timeout,
|
|
280
|
+
abortSignal,
|
|
281
|
+
}),
|
|
282
|
+
}));
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
const useDirectHandler = (threads ?? 1) === 1 && !usingInliner;
|
|
286
|
+
const buildInvoker = (handlers) => useDirectHandler
|
|
287
|
+
? handlers[0]
|
|
288
|
+
: managerMethod({
|
|
289
|
+
contexts: workers,
|
|
290
|
+
balancer,
|
|
291
|
+
handlers,
|
|
292
|
+
inlinerGate: usingInliner
|
|
293
|
+
? {
|
|
294
|
+
index: inlinerIndex,
|
|
295
|
+
threshold: inlinerDispatchThreshold,
|
|
296
|
+
}
|
|
297
|
+
: undefined,
|
|
298
|
+
});
|
|
299
|
+
const callEntries = Array.from(callHandlers.entries(), ([name, handlers]) => [name, buildInvoker(handlers)]);
|
|
300
|
+
return {
|
|
301
|
+
shutdown: shutdownWithDelay,
|
|
302
|
+
call: Object.fromEntries(callEntries),
|
|
303
|
+
};
|
|
304
|
+
};
|
|
305
|
+
const SINGLE_TASK_KEY = "__task__";
|
|
306
|
+
const DEFAULT_IMPORT_EXPORT_NAME = "default";
|
|
307
|
+
const createSingleTaskPool = (single, options) => {
|
|
308
|
+
const pool = createPool(options ?? {})({
|
|
309
|
+
[SINGLE_TASK_KEY]: single,
|
|
310
|
+
});
|
|
311
|
+
return {
|
|
312
|
+
call: pool.call[SINGLE_TASK_KEY],
|
|
313
|
+
shutdown: pool.shutdown,
|
|
314
|
+
};
|
|
315
|
+
};
|
|
316
|
+
const buildTaskDefinitionFromCaller = (input, callerHref, at) => {
|
|
317
|
+
const importedFrom = new URL(callerHref).href;
|
|
318
|
+
const out = ({
|
|
319
|
+
...input,
|
|
320
|
+
id: genTaskID(),
|
|
321
|
+
importedFrom,
|
|
322
|
+
at,
|
|
323
|
+
[endpointSymbol]: true,
|
|
324
|
+
});
|
|
325
|
+
out.createPool = (options) => {
|
|
326
|
+
if (RUNTIME_IS_MAIN_THREAD === false) {
|
|
327
|
+
return out;
|
|
328
|
+
}
|
|
329
|
+
return createSingleTaskPool(out, options);
|
|
330
|
+
};
|
|
331
|
+
return out;
|
|
332
|
+
};
|
|
333
|
+
const buildTaskDefinition = (input, callerOffset) => {
|
|
334
|
+
const [href, at] = getCallerFilePath(callerOffset);
|
|
335
|
+
return buildTaskDefinitionFromCaller(input, href, at);
|
|
336
|
+
};
|
|
337
|
+
const resolveImportHref = (href, callerHref) => {
|
|
338
|
+
try {
|
|
339
|
+
return new URL(href, callerHref).href;
|
|
340
|
+
}
|
|
341
|
+
catch {
|
|
342
|
+
return toModuleUrl(href);
|
|
343
|
+
}
|
|
344
|
+
};
|
|
345
|
+
const createImportedTaskFn = (href, exportName) => {
|
|
346
|
+
let cachedFn;
|
|
347
|
+
let cachedLoad;
|
|
348
|
+
const loadFn = async () => {
|
|
349
|
+
if (cachedFn)
|
|
350
|
+
return cachedFn;
|
|
351
|
+
if (!cachedLoad) {
|
|
352
|
+
cachedLoad = import(__rewriteRelativeImportExtension(href)).then((module) => {
|
|
353
|
+
const record = module;
|
|
354
|
+
const selected = exportName === DEFAULT_IMPORT_EXPORT_NAME
|
|
355
|
+
? record.default
|
|
356
|
+
: record[exportName];
|
|
357
|
+
if (typeof selected !== "function") {
|
|
358
|
+
const available = Object.keys(record).join(", ");
|
|
359
|
+
throw new TypeError(`importTask expected export "${exportName}" from "${href}" to be a function.` +
|
|
360
|
+
` Available exports: ${available || "(none)"}`);
|
|
361
|
+
}
|
|
362
|
+
cachedFn = selected;
|
|
363
|
+
return cachedFn;
|
|
364
|
+
});
|
|
365
|
+
}
|
|
366
|
+
return cachedLoad;
|
|
367
|
+
};
|
|
368
|
+
return (async (...args) => {
|
|
369
|
+
const fn = await loadFn();
|
|
370
|
+
return fn(...args);
|
|
371
|
+
});
|
|
372
|
+
};
|
|
373
|
+
export function task(I) {
|
|
374
|
+
return buildTaskDefinition(I, 4);
|
|
375
|
+
}
|
|
376
|
+
export function importTask(options) {
|
|
377
|
+
const [callerHref, at] = getCallerFilePath(3);
|
|
378
|
+
const { href, name = DEFAULT_IMPORT_EXPORT_NAME, ...rest } = options;
|
|
379
|
+
const resolvedHref = resolveImportHref(href, callerHref);
|
|
380
|
+
return buildTaskDefinitionFromCaller({
|
|
381
|
+
...rest,
|
|
382
|
+
f: createImportedTaskFn(resolvedHref, name),
|
|
383
|
+
}, callerHref, at);
|
|
384
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
type EnvelopeHeaderPrimitive = string | number | boolean | null;
|
|
2
|
+
type EnvelopeHeaderValue = EnvelopeHeaderPrimitive | EnvelopeHeaderValue[] | {
|
|
3
|
+
[key: string]: EnvelopeHeaderValue;
|
|
4
|
+
};
|
|
5
|
+
export type EnvelopeHeader = EnvelopeHeaderValue;
|
|
6
|
+
export declare class Envelope<H extends EnvelopeHeader = EnvelopeHeader> {
|
|
7
|
+
readonly header: H;
|
|
8
|
+
readonly payload: ArrayBuffer;
|
|
9
|
+
constructor(header: H, payload: ArrayBuffer);
|
|
10
|
+
}
|
|
11
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const toModuleUrl: (specifier: string) => string;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { pathToFileURL } from "node:url";
|
|
2
|
+
const WINDOWS_DRIVE_PATH = /^[A-Za-z]:[\\/]/;
|
|
3
|
+
const WINDOWS_UNC_PATH = /^\\\\[^\\/?]+\\[^\\/?]+/;
|
|
4
|
+
const encodeFilePath = (path) => encodeURI(path)
|
|
5
|
+
.replace(/\?/g, "%3F")
|
|
6
|
+
.replace(/#/g, "%23");
|
|
7
|
+
export const toModuleUrl = (specifier) => {
|
|
8
|
+
if (WINDOWS_DRIVE_PATH.test(specifier)) {
|
|
9
|
+
const normalized = specifier.replace(/\\/g, "/");
|
|
10
|
+
return `file:///${encodeFilePath(normalized)}`;
|
|
11
|
+
}
|
|
12
|
+
if (WINDOWS_UNC_PATH.test(specifier)) {
|
|
13
|
+
const normalized = specifier
|
|
14
|
+
.replace(/^\\\\+/, "")
|
|
15
|
+
.replace(/\\/g, "/");
|
|
16
|
+
return `file://${encodeFilePath(normalized)}`;
|
|
17
|
+
}
|
|
18
|
+
try {
|
|
19
|
+
return new URL(specifier).href;
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
return pathToFileURL(specifier).href;
|
|
23
|
+
}
|
|
24
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export type NodeProcessLike = {
|
|
2
|
+
getBuiltinModule?: (id: string) => unknown;
|
|
3
|
+
versions?: {
|
|
4
|
+
node?: string;
|
|
5
|
+
};
|
|
6
|
+
platform?: string;
|
|
7
|
+
allowedNodeEnvironmentFlags?: ReadonlySet<string>;
|
|
8
|
+
execArgv?: string[];
|
|
9
|
+
execPath?: string;
|
|
10
|
+
cwd?: () => string;
|
|
11
|
+
env?: Record<string, string | undefined>;
|
|
12
|
+
on?: (event: string, handler: (...args: unknown[]) => void) => unknown;
|
|
13
|
+
};
|
|
14
|
+
export type NodeCallSiteLike = {
|
|
15
|
+
getFileName?: () => string | null | undefined;
|
|
16
|
+
getFunctionName?: () => string | null | undefined;
|
|
17
|
+
getMethodName?: () => string | null | undefined;
|
|
18
|
+
};
|
|
19
|
+
export declare const getNodeProcess: () => NodeProcessLike | undefined;
|
|
20
|
+
export declare const getNodeBuiltinModule: <T>(specifier: string) => T | undefined;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
const nodeProcess = (() => {
|
|
2
|
+
const candidate = globalThis
|
|
3
|
+
.process;
|
|
4
|
+
return typeof candidate?.versions?.node === "string" ? candidate : undefined;
|
|
5
|
+
})();
|
|
6
|
+
export const getNodeProcess = () => nodeProcess;
|
|
7
|
+
export const getNodeBuiltinModule = (specifier) => {
|
|
8
|
+
const getter = nodeProcess?.getBuiltinModule;
|
|
9
|
+
if (typeof getter !== "function")
|
|
10
|
+
return undefined;
|
|
11
|
+
try {
|
|
12
|
+
return getter.call(nodeProcess, specifier);
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
}
|
|
16
|
+
if (!specifier.startsWith("node:"))
|
|
17
|
+
return undefined;
|
|
18
|
+
try {
|
|
19
|
+
return getter.call(nodeProcess, specifier.slice(5));
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
return undefined;
|
|
23
|
+
}
|
|
24
|
+
};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { existsSync, realpathSync, } from "node:fs";
|
|
2
|
+
import { basename as pathBasename, dirname as pathDirname, join as pathJoin, resolve as pathResolve, } from "node:path";
|
|
3
|
+
export const toCanonicalPath = (candidate, fsApi = {
|
|
4
|
+
existsSync,
|
|
5
|
+
realpathSync: realpathSync.native ?? realpathSync,
|
|
6
|
+
}) => {
|
|
7
|
+
const absolute = pathResolve(candidate);
|
|
8
|
+
const { existsSync, realpathSync } = fsApi;
|
|
9
|
+
if (typeof realpathSync === "function") {
|
|
10
|
+
try {
|
|
11
|
+
return pathResolve(realpathSync(absolute));
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
else {
|
|
17
|
+
return absolute;
|
|
18
|
+
}
|
|
19
|
+
if (typeof existsSync !== "function")
|
|
20
|
+
return absolute;
|
|
21
|
+
const missingSegments = [];
|
|
22
|
+
let cursor = absolute;
|
|
23
|
+
while (!existsSync(cursor)) {
|
|
24
|
+
const parent = pathDirname(cursor);
|
|
25
|
+
if (parent === cursor)
|
|
26
|
+
return absolute;
|
|
27
|
+
missingSegments.push(pathBasename(cursor));
|
|
28
|
+
cursor = parent;
|
|
29
|
+
}
|
|
30
|
+
let base = cursor;
|
|
31
|
+
try {
|
|
32
|
+
base = realpathSync(cursor);
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
}
|
|
36
|
+
let rebuilt = base;
|
|
37
|
+
for (let i = missingSegments.length - 1; i >= 0; i--) {
|
|
38
|
+
rebuilt = pathJoin(rebuilt, missingSegments[i]);
|
|
39
|
+
}
|
|
40
|
+
return pathResolve(rebuilt);
|
|
41
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
type RuntimeName = "deno" | "bun" | "node" | "unknown";
|
|
2
|
+
export declare const IS_DENO: boolean;
|
|
3
|
+
export declare const IS_BUN: boolean;
|
|
4
|
+
export declare const IS_NODE: boolean;
|
|
5
|
+
export declare const RUNTIME: RuntimeName;
|
|
6
|
+
export declare const SET_IMMEDIATE: typeof setImmediate & ((cb: () => void) => void);
|
|
7
|
+
export declare const HAS_SHARED_WASM_MEMORY: boolean;
|
|
8
|
+
export declare const createWasmSharedArrayBuffer: (byteLength: number, maxByteLength?: number) => SharedArrayBuffer;
|
|
9
|
+
export declare const HAS_SAB_GROW: boolean;
|
|
10
|
+
export declare const createSharedArrayBuffer: (byteLength: number, maxByteLength?: number) => SharedArrayBuffer;
|
|
11
|
+
export declare const isWasmSharedArrayBuffer: (sab: SharedArrayBuffer) => boolean;
|
|
12
|
+
export declare const isGrowableSharedArrayBuffer: (sab: SharedArrayBuffer) => boolean;
|
|
13
|
+
export declare const sharedArrayBufferMaxByteLength: (sab: SharedArrayBuffer) => number;
|
|
14
|
+
export declare const growSharedArrayBuffer: (sab: SharedArrayBuffer, byteLength: number) => SharedArrayBuffer;
|
|
15
|
+
export {};
|