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
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { getNodeProcess } from "./node-compat.js";
|
|
2
|
+
const globals = globalThis;
|
|
3
|
+
const nodeProcess = getNodeProcess();
|
|
4
|
+
export const IS_DENO = typeof globals.Deno?.version?.deno === "string";
|
|
5
|
+
export const IS_BUN = typeof globals.Bun?.version === "string";
|
|
6
|
+
export const IS_NODE = typeof nodeProcess?.versions?.node === "string";
|
|
7
|
+
export const RUNTIME = (IS_DENO ? "deno" : IS_BUN ? "bun" : IS_NODE ? "node" : "unknown");
|
|
8
|
+
export const SET_IMMEDIATE = typeof globals.setImmediate === "function" ? globals.setImmediate : undefined;
|
|
9
|
+
const WASM_MEMORY_PAGE_BYTES = 64 * 1024;
|
|
10
|
+
const wasmSharedBufferMemory = new WeakMap();
|
|
11
|
+
const wasmSharedBufferMaxByteLength = new WeakMap();
|
|
12
|
+
const hasSharedWasmMemory = (() => {
|
|
13
|
+
if (typeof WebAssembly?.Memory !== "function")
|
|
14
|
+
return false;
|
|
15
|
+
try {
|
|
16
|
+
void new WebAssembly.Memory({ initial: 0, maximum: 1, shared: true });
|
|
17
|
+
return true;
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
})();
|
|
23
|
+
export const HAS_SHARED_WASM_MEMORY = hasSharedWasmMemory;
|
|
24
|
+
const roundupWasmPages = (byteLength) => Math.ceil(Math.max(0, byteLength) / WASM_MEMORY_PAGE_BYTES);
|
|
25
|
+
const createSharedWasmBuffer = (byteLength, maxByteLength) => {
|
|
26
|
+
const memory = new WebAssembly.Memory({
|
|
27
|
+
initial: roundupWasmPages(byteLength),
|
|
28
|
+
maximum: Math.max(roundupWasmPages(byteLength), roundupWasmPages(maxByteLength)),
|
|
29
|
+
shared: true,
|
|
30
|
+
});
|
|
31
|
+
const buffer = memory.buffer;
|
|
32
|
+
wasmSharedBufferMemory.set(buffer, memory);
|
|
33
|
+
wasmSharedBufferMaxByteLength.set(buffer, maxByteLength);
|
|
34
|
+
return buffer;
|
|
35
|
+
};
|
|
36
|
+
export const createWasmSharedArrayBuffer = (byteLength, maxByteLength = byteLength) => {
|
|
37
|
+
if (hasSharedWasmMemory) {
|
|
38
|
+
return createSharedWasmBuffer(byteLength, maxByteLength);
|
|
39
|
+
}
|
|
40
|
+
return new SharedArrayBuffer(byteLength);
|
|
41
|
+
};
|
|
42
|
+
const HAS_NATIVE_SAB_GROW = typeof SharedArrayBuffer === "function" &&
|
|
43
|
+
typeof SharedArrayBuffer.prototype.grow === "function";
|
|
44
|
+
export const HAS_SAB_GROW = HAS_NATIVE_SAB_GROW || hasSharedWasmMemory;
|
|
45
|
+
export const createSharedArrayBuffer = (byteLength, maxByteLength) => {
|
|
46
|
+
if (HAS_NATIVE_SAB_GROW && typeof maxByteLength === "number") {
|
|
47
|
+
return new SharedArrayBuffer(byteLength, { maxByteLength });
|
|
48
|
+
}
|
|
49
|
+
if (hasSharedWasmMemory && typeof maxByteLength === "number") {
|
|
50
|
+
return createSharedWasmBuffer(byteLength, maxByteLength);
|
|
51
|
+
}
|
|
52
|
+
return new SharedArrayBuffer(byteLength);
|
|
53
|
+
};
|
|
54
|
+
export const isWasmSharedArrayBuffer = (sab) => wasmSharedBufferMemory.has(sab);
|
|
55
|
+
export const isGrowableSharedArrayBuffer = (sab) => {
|
|
56
|
+
const value = sab;
|
|
57
|
+
return (HAS_NATIVE_SAB_GROW &&
|
|
58
|
+
typeof value.grow === "function" &&
|
|
59
|
+
value.growable === true) ||
|
|
60
|
+
wasmSharedBufferMemory.has(sab);
|
|
61
|
+
};
|
|
62
|
+
export const sharedArrayBufferMaxByteLength = (sab) => {
|
|
63
|
+
const value = sab;
|
|
64
|
+
if (typeof value.maxByteLength === "number") {
|
|
65
|
+
return value.maxByteLength;
|
|
66
|
+
}
|
|
67
|
+
return wasmSharedBufferMaxByteLength.get(sab) ?? sab.byteLength;
|
|
68
|
+
};
|
|
69
|
+
export const growSharedArrayBuffer = (sab, byteLength) => {
|
|
70
|
+
const native = sab;
|
|
71
|
+
if (typeof native.grow === "function") {
|
|
72
|
+
native.grow(byteLength);
|
|
73
|
+
return sab;
|
|
74
|
+
}
|
|
75
|
+
const memory = wasmSharedBufferMemory.get(sab);
|
|
76
|
+
if (memory == null) {
|
|
77
|
+
throw new TypeError("SharedArrayBuffer is not growable");
|
|
78
|
+
}
|
|
79
|
+
const currentBuffer = memory.buffer;
|
|
80
|
+
if (currentBuffer.byteLength >= byteLength) {
|
|
81
|
+
return currentBuffer;
|
|
82
|
+
}
|
|
83
|
+
const targetPages = roundupWasmPages(byteLength);
|
|
84
|
+
const currentPages = roundupWasmPages(currentBuffer.byteLength);
|
|
85
|
+
memory.grow(targetPages - currentPages);
|
|
86
|
+
const nextBuffer = memory.buffer;
|
|
87
|
+
const maxByteLength = wasmSharedBufferMaxByteLength.get(sab) ?? currentBuffer.byteLength;
|
|
88
|
+
wasmSharedBufferMemory.set(nextBuffer, memory);
|
|
89
|
+
wasmSharedBufferMaxByteLength.set(nextBuffer, maxByteLength);
|
|
90
|
+
return nextBuffer;
|
|
91
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export type SharedBuffer = SharedArrayBuffer | ArrayBuffer;
|
|
2
|
+
export type SharedBufferRegion = {
|
|
3
|
+
sab: SharedBuffer;
|
|
4
|
+
byteOffset: number;
|
|
5
|
+
byteLength: number;
|
|
6
|
+
};
|
|
7
|
+
export type SharedBufferSource = SharedBuffer | SharedBufferRegion;
|
|
8
|
+
export declare const isSharedBuffer: (value: unknown) => value is SharedBuffer;
|
|
9
|
+
export declare const isSharedBufferRegion: (value: unknown) => value is SharedBufferRegion;
|
|
10
|
+
export declare const isSharedBufferSource: (value: unknown) => value is SharedBufferSource;
|
|
11
|
+
export declare const toSharedBufferRegion: (value: SharedBufferSource) => SharedBufferRegion;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export const isSharedBuffer = (value) => value instanceof SharedArrayBuffer || value instanceof ArrayBuffer;
|
|
2
|
+
export const isSharedBufferRegion = (value) => {
|
|
3
|
+
if (!value || typeof value !== "object")
|
|
4
|
+
return false;
|
|
5
|
+
const candidate = value;
|
|
6
|
+
return isSharedBuffer(candidate.sab) &&
|
|
7
|
+
typeof candidate.byteOffset === "number" &&
|
|
8
|
+
Number.isInteger(candidate.byteOffset) &&
|
|
9
|
+
candidate.byteOffset >= 0 &&
|
|
10
|
+
typeof candidate.byteLength === "number" &&
|
|
11
|
+
Number.isInteger(candidate.byteLength) &&
|
|
12
|
+
candidate.byteLength >= 0;
|
|
13
|
+
};
|
|
14
|
+
export const isSharedBufferSource = (value) => isSharedBuffer(value) || isSharedBufferRegion(value);
|
|
15
|
+
export const toSharedBufferRegion = (value) => isSharedBuffer(value)
|
|
16
|
+
? {
|
|
17
|
+
sab: value,
|
|
18
|
+
byteOffset: 0,
|
|
19
|
+
byteLength: value.byteLength,
|
|
20
|
+
}
|
|
21
|
+
: value;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type SharedBufferSource } from "./shared-buffer-region.js";
|
|
2
|
+
export type SharedBufferTextCompat = {
|
|
3
|
+
encodeInto: boolean;
|
|
4
|
+
decode: boolean;
|
|
5
|
+
};
|
|
6
|
+
export type LockBufferTextCompat = {
|
|
7
|
+
headers: SharedBufferTextCompat;
|
|
8
|
+
payload: SharedBufferTextCompat;
|
|
9
|
+
};
|
|
10
|
+
export declare const isSharedBufferTextCompat: (value: unknown) => value is SharedBufferTextCompat;
|
|
11
|
+
export declare const isLockBufferTextCompat: (value: unknown) => value is LockBufferTextCompat;
|
|
12
|
+
export declare const probeSharedBufferTextCompat: (source: SharedBufferSource) => SharedBufferTextCompat;
|
|
13
|
+
export declare const probeLockBufferTextCompat: ({ headers, payload, }: {
|
|
14
|
+
headers: SharedBufferSource;
|
|
15
|
+
payload: SharedBufferSource;
|
|
16
|
+
}) => LockBufferTextCompat;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { toSharedBufferRegion, } from "./shared-buffer-region.js";
|
|
2
|
+
const textEncode = new TextEncoder();
|
|
3
|
+
const textDecode = new TextDecoder();
|
|
4
|
+
const isSharedBufferTextCompatTypeError = (error) => error instanceof TypeError;
|
|
5
|
+
const makeProbeView = (source) => {
|
|
6
|
+
const region = toSharedBufferRegion(source);
|
|
7
|
+
const probeLength = Math.min(1, region.byteLength);
|
|
8
|
+
return new Uint8Array(region.sab, region.byteOffset, probeLength);
|
|
9
|
+
};
|
|
10
|
+
export const isSharedBufferTextCompat = (value) => {
|
|
11
|
+
if (!value || typeof value !== "object")
|
|
12
|
+
return false;
|
|
13
|
+
const candidate = value;
|
|
14
|
+
return typeof candidate.encodeInto === "boolean" &&
|
|
15
|
+
typeof candidate.decode === "boolean";
|
|
16
|
+
};
|
|
17
|
+
export const isLockBufferTextCompat = (value) => {
|
|
18
|
+
if (!value || typeof value !== "object")
|
|
19
|
+
return false;
|
|
20
|
+
const candidate = value;
|
|
21
|
+
return isSharedBufferTextCompat(candidate.headers) &&
|
|
22
|
+
isSharedBufferTextCompat(candidate.payload);
|
|
23
|
+
};
|
|
24
|
+
export const probeSharedBufferTextCompat = (source) => {
|
|
25
|
+
const view = makeProbeView(source);
|
|
26
|
+
const encodeInto = (() => {
|
|
27
|
+
if (typeof textEncode.encodeInto !== "function")
|
|
28
|
+
return false;
|
|
29
|
+
const probe = view.byteLength > 0 ? view : view.subarray(0, 0);
|
|
30
|
+
const restoredByte = probe.byteLength > 0 ? probe[0] : undefined;
|
|
31
|
+
try {
|
|
32
|
+
textEncode.encodeInto(probe.byteLength > 0 ? "a" : "", probe);
|
|
33
|
+
return true;
|
|
34
|
+
}
|
|
35
|
+
catch (error) {
|
|
36
|
+
if (!isSharedBufferTextCompatTypeError(error))
|
|
37
|
+
throw error;
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
finally {
|
|
41
|
+
if (restoredByte !== undefined) {
|
|
42
|
+
probe[0] = restoredByte;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
})();
|
|
46
|
+
const decode = (() => {
|
|
47
|
+
try {
|
|
48
|
+
textDecode.decode(view);
|
|
49
|
+
return true;
|
|
50
|
+
}
|
|
51
|
+
catch (error) {
|
|
52
|
+
if (!isSharedBufferTextCompatTypeError(error))
|
|
53
|
+
throw error;
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
})();
|
|
57
|
+
return {
|
|
58
|
+
encodeInto,
|
|
59
|
+
decode,
|
|
60
|
+
};
|
|
61
|
+
};
|
|
62
|
+
export const probeLockBufferTextCompat = ({ headers, payload, }) => ({
|
|
63
|
+
headers: probeSharedBufferTextCompat(headers),
|
|
64
|
+
payload: probeSharedBufferTextCompat(payload),
|
|
65
|
+
});
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { toModuleUrl } from "./module-url.js";
|
|
2
|
+
export const genTaskID = ((counter) => () => counter++)(0);
|
|
3
|
+
const INTERNAL_CALLER_HINTS = [
|
|
4
|
+
"/src/common/task-source.ts",
|
|
5
|
+
"\\src\\common\\task-source.ts",
|
|
6
|
+
"/src/api.ts",
|
|
7
|
+
"\\src\\api.ts",
|
|
8
|
+
];
|
|
9
|
+
const INTERNAL_CALLER_FUNCTIONS = new Set([
|
|
10
|
+
"collectStackFrames",
|
|
11
|
+
"resolveCallerHref",
|
|
12
|
+
"getCallerFilePath",
|
|
13
|
+
"buildTaskDefinition",
|
|
14
|
+
"buildTaskDefinitionFromCaller",
|
|
15
|
+
"task",
|
|
16
|
+
"importTask",
|
|
17
|
+
]);
|
|
18
|
+
const isDefined = (value) => value !== undefined;
|
|
19
|
+
const isInternalCallerFrame = (file) => INTERNAL_CALLER_HINTS.some((hint) => file.includes(hint));
|
|
20
|
+
const isRuntimeInternalFrame = (file) => file.startsWith("node:") ||
|
|
21
|
+
file.startsWith("native:") ||
|
|
22
|
+
file.startsWith("bun:") ||
|
|
23
|
+
file.startsWith("internal/");
|
|
24
|
+
const isInternalCallerFunction = (functionName, methodName) => (functionName !== undefined && INTERNAL_CALLER_FUNCTIONS.has(functionName)) ||
|
|
25
|
+
(methodName !== undefined && INTERNAL_CALLER_FUNCTIONS.has(methodName));
|
|
26
|
+
const collectStackFrames = () => {
|
|
27
|
+
const ErrorCtor = Error;
|
|
28
|
+
const original = ErrorCtor.prepareStackTrace;
|
|
29
|
+
try {
|
|
30
|
+
ErrorCtor.prepareStackTrace = (_error, stack) => stack;
|
|
31
|
+
const stack = new Error().stack;
|
|
32
|
+
if (!Array.isArray(stack))
|
|
33
|
+
return [];
|
|
34
|
+
const frames = stack
|
|
35
|
+
.map((site) => {
|
|
36
|
+
try {
|
|
37
|
+
const file = site?.getFileName?.();
|
|
38
|
+
if (typeof file !== "string" || file.length === 0)
|
|
39
|
+
return undefined;
|
|
40
|
+
return {
|
|
41
|
+
file,
|
|
42
|
+
functionName: site?.getFunctionName?.() ?? undefined,
|
|
43
|
+
methodName: site?.getMethodName?.() ?? undefined,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
return undefined;
|
|
48
|
+
}
|
|
49
|
+
})
|
|
50
|
+
.filter(isDefined);
|
|
51
|
+
return frames;
|
|
52
|
+
}
|
|
53
|
+
finally {
|
|
54
|
+
ErrorCtor.prepareStackTrace = original;
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
const isInternalFrame = (frame) => isRuntimeInternalFrame(frame.file) ||
|
|
58
|
+
isInternalCallerFrame(frame.file) ||
|
|
59
|
+
isInternalCallerFunction(frame.functionName, frame.methodName);
|
|
60
|
+
const resolveCallerHref = (offset) => {
|
|
61
|
+
const frames = collectStackFrames();
|
|
62
|
+
const direct = frames[offset];
|
|
63
|
+
const caller = (direct && !isInternalFrame(direct)
|
|
64
|
+
? direct.file
|
|
65
|
+
: undefined) ??
|
|
66
|
+
frames.find((frame) => !isInternalFrame(frame))?.file ??
|
|
67
|
+
frames.find((frame) => !isRuntimeInternalFrame(frame.file))?.file;
|
|
68
|
+
if (!caller) {
|
|
69
|
+
throw new Error("Unable to determine caller file.");
|
|
70
|
+
}
|
|
71
|
+
return toModuleUrl(caller);
|
|
72
|
+
};
|
|
73
|
+
const linkingMap = new Map();
|
|
74
|
+
export const getCallerFilePath = (offset = 3) => {
|
|
75
|
+
const href = resolveCallerHref(offset);
|
|
76
|
+
const at = linkingMap.get(href) ?? 0;
|
|
77
|
+
linkingMap.set(href, at + 1);
|
|
78
|
+
return [href, at];
|
|
79
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const endpointSymbol: unique symbol;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const endpointSymbol = Symbol.for("task");
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export type PromiseWithMaybeReject<T> = Promise<T> & {
|
|
2
|
+
reject: (reason?: unknown) => void;
|
|
3
|
+
};
|
|
4
|
+
export type Deferred<T> = {
|
|
5
|
+
promise: PromiseWithMaybeReject<T>;
|
|
6
|
+
resolve: (value: T | PromiseLike<T>) => void;
|
|
7
|
+
reject: (reason?: unknown) => void;
|
|
8
|
+
};
|
|
9
|
+
export declare const withResolvers: <T = unknown>() => Deferred<T>;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
const attachReject = (promise, reject) => {
|
|
2
|
+
const deferredPromise = promise;
|
|
3
|
+
deferredPromise.reject = reject;
|
|
4
|
+
return deferredPromise;
|
|
5
|
+
};
|
|
6
|
+
export const withResolvers = () => {
|
|
7
|
+
const native = Promise.withResolvers;
|
|
8
|
+
if (typeof native === "function") {
|
|
9
|
+
const deferred = native.call(Promise);
|
|
10
|
+
return {
|
|
11
|
+
promise: attachReject(deferred.promise, deferred.reject),
|
|
12
|
+
resolve: deferred.resolve,
|
|
13
|
+
reject: deferred.reject,
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
let resolve;
|
|
17
|
+
let reject;
|
|
18
|
+
const promise = attachReject(new Promise((res, rej) => {
|
|
19
|
+
resolve = res;
|
|
20
|
+
reject = rej;
|
|
21
|
+
}), reject);
|
|
22
|
+
return { promise, resolve, reject };
|
|
23
|
+
};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
type RuntimePortMessageHandler = (message: unknown) => void;
|
|
2
|
+
export type RuntimeMessagePortLike = {
|
|
3
|
+
postMessage: (message: unknown) => void;
|
|
4
|
+
close?: () => void;
|
|
5
|
+
start?: () => void;
|
|
6
|
+
on?: (event: string, handler: (...args: unknown[]) => void) => void;
|
|
7
|
+
onmessage?: ((event: {
|
|
8
|
+
data?: unknown;
|
|
9
|
+
}) => void) | null;
|
|
10
|
+
addEventListener?: (type: string, listener: (event: {
|
|
11
|
+
data?: unknown;
|
|
12
|
+
error?: unknown;
|
|
13
|
+
message?: unknown;
|
|
14
|
+
}) => void) => void;
|
|
15
|
+
removeEventListener?: (type: string, listener: (event: {
|
|
16
|
+
data?: unknown;
|
|
17
|
+
error?: unknown;
|
|
18
|
+
message?: unknown;
|
|
19
|
+
}) => void) => void;
|
|
20
|
+
};
|
|
21
|
+
export type RuntimeWorkerLike = RuntimeMessagePortLike & {
|
|
22
|
+
terminate: () => unknown;
|
|
23
|
+
};
|
|
24
|
+
export type RuntimeMessageChannelLike = {
|
|
25
|
+
port1: RuntimeMessagePortLike;
|
|
26
|
+
port2: RuntimeMessagePortLike;
|
|
27
|
+
};
|
|
28
|
+
export declare const RUNTIME_PROCESS_WORKER_ENV = "KNITTING_PROCESS_WORKER";
|
|
29
|
+
export declare const RUNTIME_PROCESS_WORKER_BOOT_ENV = "KNITTING_PROCESS_WORKER_BOOT";
|
|
30
|
+
export declare const RUNTIME_PROCESS_WORKER_BOOT_VERSION = 1;
|
|
31
|
+
export declare const RUNTIME_IS_PROCESS_WORKER: boolean;
|
|
32
|
+
export declare const RUNTIME_WORKER: new (specifier: string | URL, options?: Record<string, unknown>) => RuntimeWorkerLike;
|
|
33
|
+
export declare const RUNTIME_MESSAGE_CHANNEL: new () => RuntimeMessageChannelLike;
|
|
34
|
+
export declare const HAS_NODE_WORKER_THREADS: boolean;
|
|
35
|
+
export declare const RUNTIME_IS_MAIN_THREAD: boolean;
|
|
36
|
+
export declare const RUNTIME_WORKER_DATA: unknown;
|
|
37
|
+
export declare const RUNTIME_PARENT_PORT: RuntimeMessagePortLike;
|
|
38
|
+
export declare const createRuntimeMessageChannel: () => RuntimeMessageChannelLike;
|
|
39
|
+
export declare const addRuntimeDataListener: (target: RuntimeMessagePortLike, handler: RuntimePortMessageHandler) => void;
|
|
40
|
+
export {};
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { getNodeBuiltinModule, getNodeProcess } from "./node-compat.js";
|
|
2
|
+
export const RUNTIME_PROCESS_WORKER_ENV = "KNITTING_PROCESS_WORKER";
|
|
3
|
+
export const RUNTIME_PROCESS_WORKER_BOOT_ENV = "KNITTING_PROCESS_WORKER_BOOT";
|
|
4
|
+
export const RUNTIME_PROCESS_WORKER_BOOT_VERSION = 1;
|
|
5
|
+
const nodeProcess = getNodeProcess();
|
|
6
|
+
export const RUNTIME_IS_PROCESS_WORKER = nodeProcess?.env?.[RUNTIME_PROCESS_WORKER_ENV] === "1";
|
|
7
|
+
const workerThreads = getNodeBuiltinModule("node:worker_threads");
|
|
8
|
+
const isWorkerGlobalScope = () => {
|
|
9
|
+
const scopeCtor = globalThis.WorkerGlobalScope;
|
|
10
|
+
if (typeof scopeCtor !== "function")
|
|
11
|
+
return false;
|
|
12
|
+
try {
|
|
13
|
+
return globalThis instanceof
|
|
14
|
+
scopeCtor;
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
export const RUNTIME_WORKER = workerThreads?.Worker ??
|
|
21
|
+
(globalThis.Worker);
|
|
22
|
+
export const RUNTIME_MESSAGE_CHANNEL = workerThreads?.MessageChannel ??
|
|
23
|
+
(globalThis
|
|
24
|
+
.MessageChannel);
|
|
25
|
+
export const HAS_NODE_WORKER_THREADS = workerThreads != null;
|
|
26
|
+
export const RUNTIME_IS_MAIN_THREAD = RUNTIME_IS_PROCESS_WORKER
|
|
27
|
+
? false
|
|
28
|
+
: workerThreads?.isMainThread ?? !isWorkerGlobalScope();
|
|
29
|
+
export const RUNTIME_WORKER_DATA = workerThreads?.workerData;
|
|
30
|
+
export const RUNTIME_PARENT_PORT = workerThreads?.parentPort ??
|
|
31
|
+
(RUNTIME_IS_PROCESS_WORKER && typeof nodeProcess?.send === "function"
|
|
32
|
+
? {
|
|
33
|
+
postMessage: (message) => nodeProcess.send(message),
|
|
34
|
+
}
|
|
35
|
+
: undefined);
|
|
36
|
+
export const createRuntimeMessageChannel = () => {
|
|
37
|
+
if (typeof RUNTIME_MESSAGE_CHANNEL !== "function") {
|
|
38
|
+
throw new Error("MessageChannel is not available in this runtime");
|
|
39
|
+
}
|
|
40
|
+
return new RUNTIME_MESSAGE_CHANNEL();
|
|
41
|
+
};
|
|
42
|
+
export const addRuntimeDataListener = (target, handler) => {
|
|
43
|
+
if (typeof target.on === "function") {
|
|
44
|
+
target.on("message", handler);
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
if (typeof target.addEventListener === "function") {
|
|
48
|
+
target.addEventListener("message", (event) => handler(event?.data));
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
target.onmessage = (event) => handler(event?.data);
|
|
52
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { type CreateSharedMemoryOptions, type MapSharedMemoryOptions, type SharedMemoryConnectionPrimitives, type SharedMemoryMapping } from "./types.js";
|
|
2
|
+
type BunPointer = number;
|
|
3
|
+
type BunLibc = {
|
|
4
|
+
symbols: {
|
|
5
|
+
memfd_create?: (name: Uint8Array, flags: number) => number;
|
|
6
|
+
shm_open?: (name: Uint8Array, flags: number, mode: number) => number;
|
|
7
|
+
shm_unlink?: (name: Uint8Array) => number;
|
|
8
|
+
ftruncate: (fd: number, length: bigint) => number;
|
|
9
|
+
dup: (fd: number) => number;
|
|
10
|
+
fcntl: (fd: number, cmd: number, arg: number) => number;
|
|
11
|
+
mmap: (address: null, length: number, protection: number, flags: number, fd: number, offset: bigint) => BunPointer;
|
|
12
|
+
munmap: (address: BunPointer, length: number) => number;
|
|
13
|
+
close: (fd: number) => number;
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
export declare const openBunLibc: () => BunLibc;
|
|
17
|
+
export declare const mapBunSharedMemory: (options: MapSharedMemoryOptions, libc?: BunLibc) => SharedMemoryMapping<ArrayBuffer>;
|
|
18
|
+
export declare const createBunSharedMemory: (options: number | CreateSharedMemoryOptions, libc?: BunLibc) => SharedMemoryMapping<ArrayBuffer>;
|
|
19
|
+
export declare const createBunConnectionPrimitives: (libc?: BunLibc) => SharedMemoryConnectionPrimitives<SharedMemoryMapping<ArrayBuffer>>;
|
|
20
|
+
export {};
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import { DARWIN_O_CREAT, DARWIN_O_EXCL, DARWIN_SHM_MODE, setCloseOnExec, detectPosixPlatform, encodeCString, getPosixLibcPath, makeDarwinSharedMemoryName, MAP_SHARED, O_RDWR, PROT_READ, PROT_WRITE, } from "./posix.js";
|
|
2
|
+
import { expectFd, expectPositiveSize, readCreateName, readCreateSize, } from "./types.js";
|
|
3
|
+
const FFIType = {
|
|
4
|
+
i32: 5,
|
|
5
|
+
i64: 7,
|
|
6
|
+
u32: 6,
|
|
7
|
+
usize: 8,
|
|
8
|
+
ptr: 12,
|
|
9
|
+
};
|
|
10
|
+
const getBunFFI = () => {
|
|
11
|
+
const ffi = globalThis.Bun?.FFI;
|
|
12
|
+
if (typeof ffi?.dlopen !== "function" ||
|
|
13
|
+
typeof ffi?.toArrayBuffer !== "function") {
|
|
14
|
+
throw new Error("Bun FFI is not available in this runtime");
|
|
15
|
+
}
|
|
16
|
+
return ffi;
|
|
17
|
+
};
|
|
18
|
+
export const openBunLibc = () => getBunFFI().dlopen(getPosixLibcPath(), {
|
|
19
|
+
...getBunCreateSymbols(),
|
|
20
|
+
ftruncate: {
|
|
21
|
+
args: [FFIType.i32, FFIType.i64],
|
|
22
|
+
returns: FFIType.i32,
|
|
23
|
+
},
|
|
24
|
+
dup: {
|
|
25
|
+
args: [FFIType.i32],
|
|
26
|
+
returns: FFIType.i32,
|
|
27
|
+
},
|
|
28
|
+
fcntl: {
|
|
29
|
+
args: [FFIType.i32, FFIType.i32, FFIType.i32],
|
|
30
|
+
returns: FFIType.i32,
|
|
31
|
+
},
|
|
32
|
+
mmap: {
|
|
33
|
+
args: [
|
|
34
|
+
FFIType.ptr,
|
|
35
|
+
FFIType.usize,
|
|
36
|
+
FFIType.i32,
|
|
37
|
+
FFIType.i32,
|
|
38
|
+
FFIType.i32,
|
|
39
|
+
FFIType.i64,
|
|
40
|
+
],
|
|
41
|
+
returns: FFIType.ptr,
|
|
42
|
+
},
|
|
43
|
+
munmap: {
|
|
44
|
+
args: [FFIType.ptr, FFIType.usize],
|
|
45
|
+
returns: FFIType.i32,
|
|
46
|
+
},
|
|
47
|
+
close: {
|
|
48
|
+
args: [FFIType.i32],
|
|
49
|
+
returns: FFIType.i32,
|
|
50
|
+
},
|
|
51
|
+
});
|
|
52
|
+
const getBunCreateSymbols = (platform = detectPosixPlatform()) => platform === "darwin"
|
|
53
|
+
? {
|
|
54
|
+
shm_open: {
|
|
55
|
+
args: [FFIType.ptr, FFIType.i32, FFIType.u32],
|
|
56
|
+
returns: FFIType.i32,
|
|
57
|
+
},
|
|
58
|
+
shm_unlink: {
|
|
59
|
+
args: [FFIType.ptr],
|
|
60
|
+
returns: FFIType.i32,
|
|
61
|
+
},
|
|
62
|
+
}
|
|
63
|
+
: {
|
|
64
|
+
memfd_create: {
|
|
65
|
+
args: [FFIType.ptr, FFIType.u32],
|
|
66
|
+
returns: FFIType.i32,
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
const checkResult = (result, message) => {
|
|
70
|
+
if (result < 0)
|
|
71
|
+
throw new Error(message);
|
|
72
|
+
return result;
|
|
73
|
+
};
|
|
74
|
+
const isBunMmapFailed = (pointer) => !pointer || pointer < 0 || pointer >= Number.MAX_SAFE_INTEGER;
|
|
75
|
+
const createBunSharedMemoryFd = (name, platform, libc) => {
|
|
76
|
+
if (platform === "darwin") {
|
|
77
|
+
const shmOpen = libc.symbols.shm_open;
|
|
78
|
+
const shmUnlink = libc.symbols.shm_unlink;
|
|
79
|
+
if (shmOpen === undefined || shmUnlink === undefined) {
|
|
80
|
+
throw new Error("shm_open symbols are not available");
|
|
81
|
+
}
|
|
82
|
+
const shmName = encodeCString(makeDarwinSharedMemoryName(name, "bun"));
|
|
83
|
+
const fd = checkResult(shmOpen(shmName, O_RDWR | DARWIN_O_CREAT | DARWIN_O_EXCL, DARWIN_SHM_MODE), "shm_open failed");
|
|
84
|
+
shmUnlink(shmName);
|
|
85
|
+
try {
|
|
86
|
+
return setCloseOnExec(libc, fd);
|
|
87
|
+
}
|
|
88
|
+
catch (error) {
|
|
89
|
+
libc.symbols.close(fd);
|
|
90
|
+
throw error;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
const memfdCreate = libc.symbols.memfd_create;
|
|
94
|
+
if (memfdCreate === undefined) {
|
|
95
|
+
throw new Error("memfd_create symbol is not available");
|
|
96
|
+
}
|
|
97
|
+
const fd = checkResult(memfdCreate(encodeCString(name), 0), "memfd_create failed");
|
|
98
|
+
try {
|
|
99
|
+
return setCloseOnExec(libc, fd);
|
|
100
|
+
}
|
|
101
|
+
catch (error) {
|
|
102
|
+
libc.symbols.close(fd);
|
|
103
|
+
throw error;
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
export const mapBunSharedMemory = (options, libc = openBunLibc()) => {
|
|
107
|
+
const sourceFd = expectFd(options.fd);
|
|
108
|
+
const size = expectPositiveSize(options.size);
|
|
109
|
+
let fd = sourceFd;
|
|
110
|
+
if (options.duplicateFd !== false) {
|
|
111
|
+
fd = checkResult(libc.symbols.dup(sourceFd), "dup(fd) failed");
|
|
112
|
+
try {
|
|
113
|
+
setCloseOnExec(libc, fd);
|
|
114
|
+
}
|
|
115
|
+
catch (error) {
|
|
116
|
+
libc.symbols.close(fd);
|
|
117
|
+
throw error;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
const pointer = libc.symbols.mmap(null, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0n);
|
|
121
|
+
if (isBunMmapFailed(pointer)) {
|
|
122
|
+
if (options.duplicateFd !== false)
|
|
123
|
+
libc.symbols.close(fd);
|
|
124
|
+
throw new Error("mmap failed");
|
|
125
|
+
}
|
|
126
|
+
const arrayBuffer = getBunFFI().toArrayBuffer(pointer, 0, size);
|
|
127
|
+
return {
|
|
128
|
+
runtime: "bun",
|
|
129
|
+
fd,
|
|
130
|
+
size,
|
|
131
|
+
byteLength: arrayBuffer.byteLength,
|
|
132
|
+
buffer: arrayBuffer,
|
|
133
|
+
kind: "external-array-buffer",
|
|
134
|
+
arrayBuffer,
|
|
135
|
+
unsafePointer: pointer,
|
|
136
|
+
close: () => {
|
|
137
|
+
libc.symbols.munmap(pointer, size);
|
|
138
|
+
libc.symbols.close(fd);
|
|
139
|
+
},
|
|
140
|
+
};
|
|
141
|
+
};
|
|
142
|
+
export const createBunSharedMemory = (options, libc = openBunLibc()) => {
|
|
143
|
+
const size = expectPositiveSize(readCreateSize(options));
|
|
144
|
+
const name = readCreateName(options, "knitting_shared_memory");
|
|
145
|
+
const fd = createBunSharedMemoryFd(name, detectPosixPlatform(), libc);
|
|
146
|
+
try {
|
|
147
|
+
checkResult(libc.symbols.ftruncate(fd, BigInt(size)), "ftruncate failed");
|
|
148
|
+
return mapBunSharedMemory({ fd, size, duplicateFd: false }, libc);
|
|
149
|
+
}
|
|
150
|
+
catch (error) {
|
|
151
|
+
libc.symbols.close(fd);
|
|
152
|
+
throw error;
|
|
153
|
+
}
|
|
154
|
+
};
|
|
155
|
+
export const createBunConnectionPrimitives = (libc = openBunLibc()) => ({
|
|
156
|
+
runtime: "bun",
|
|
157
|
+
createSharedMemory: (options) => createBunSharedMemory(options, libc),
|
|
158
|
+
mapSharedMemory: (options) => mapBunSharedMemory(options, libc),
|
|
159
|
+
});
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { type CreateSharedMemoryOptions, type MapSharedMemoryOptions, type SharedMemoryConnectionPrimitives, type SharedMemoryMapping } from "./types.js";
|
|
2
|
+
type DenoLibc = {
|
|
3
|
+
symbols: {
|
|
4
|
+
memfd_create?: (name: Uint8Array, flags: number) => number;
|
|
5
|
+
shm_open?: (name: Uint8Array, flags: number, mode: number) => number;
|
|
6
|
+
shm_unlink?: (name: Uint8Array) => number;
|
|
7
|
+
ftruncate: (fd: number, length: bigint) => number;
|
|
8
|
+
dup: (fd: number) => number;
|
|
9
|
+
fcntl: (fd: number, cmd: number, arg: number) => number;
|
|
10
|
+
mmap: (address: null, length: number, protection: number, flags: number, fd: number, offset: bigint) => unknown;
|
|
11
|
+
munmap: (address: unknown, length: number) => number;
|
|
12
|
+
close: (fd: number) => number;
|
|
13
|
+
};
|
|
14
|
+
close: () => void;
|
|
15
|
+
};
|
|
16
|
+
export declare const openDenoLibc: () => DenoLibc;
|
|
17
|
+
export declare const mapDenoSharedMemory: (options: MapSharedMemoryOptions, libc?: DenoLibc) => SharedMemoryMapping<ArrayBuffer>;
|
|
18
|
+
export declare const createDenoSharedMemory: (options: number | CreateSharedMemoryOptions, libc?: DenoLibc) => SharedMemoryMapping<ArrayBuffer>;
|
|
19
|
+
export declare const createDenoConnectionPrimitives: (libc?: DenoLibc) => SharedMemoryConnectionPrimitives<SharedMemoryMapping<ArrayBuffer>>;
|
|
20
|
+
export {};
|