knitting 0.1.56 → 0.1.61

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 (101) hide show
  1. package/BROWSER.md +134 -0
  2. package/README.md +347 -46
  3. package/knitting.browser.d.ts +6 -0
  4. package/knitting.browser.js +1 -0
  5. package/knitting.d.ts +3 -2
  6. package/knitting.js +3 -3
  7. package/map.md +21 -9
  8. package/package.json +17 -2
  9. package/prebuilds/darwin-arm64-node-127/knitting_buffer_pointer.node +0 -0
  10. package/prebuilds/darwin-arm64-node-127/knitting_shared_memory.node +0 -0
  11. package/prebuilds/darwin-arm64-node-127/knitting_shm.node +0 -0
  12. package/prebuilds/darwin-arm64-node-137/knitting_buffer_pointer.node +0 -0
  13. package/prebuilds/darwin-arm64-node-137/knitting_shared_memory.node +0 -0
  14. package/prebuilds/darwin-arm64-node-137/knitting_shm.node +0 -0
  15. package/prebuilds/win32-x64/knitting_windows_shared_memory.dll +0 -0
  16. package/prebuilds/win32-x64-node-127/knitting_buffer_pointer.node +0 -0
  17. package/prebuilds/win32-x64-node-127/knitting_shared_memory.node +0 -0
  18. package/prebuilds/win32-x64-node-127/knitting_shm.node +0 -0
  19. package/prebuilds/win32-x64-node-137/knitting_buffer_pointer.node +0 -0
  20. package/prebuilds/win32-x64-node-137/knitting_shared_memory.node +0 -0
  21. package/prebuilds/win32-x64-node-137/knitting_shm.node +0 -0
  22. package/scripts/build-compiled-worker.ts +276 -0
  23. package/scripts/compiled-worker/porffor.d.ts +5 -0
  24. package/scripts/compiled-worker/runtime.ts +529 -0
  25. package/scripts/compiled-worker/task-shim.ts +32 -0
  26. package/src/api.d.ts +24 -1
  27. package/src/api.js +311 -27
  28. package/src/common/module-url.d.ts +1 -0
  29. package/src/common/module-url.js +30 -2
  30. package/src/common/node-compat.d.ts +2 -0
  31. package/src/common/path-canonical.js +20 -6
  32. package/src/common/runtime.d.ts +3 -1
  33. package/src/common/runtime.js +25 -4
  34. package/src/common/task-source.d.ts +2 -0
  35. package/src/common/task-source.js +17 -1
  36. package/src/common/worker-runtime.js +16 -7
  37. package/src/connections/buffer-reference-native.js +25 -1
  38. package/src/connections/buffer-reference.d.ts +23 -2
  39. package/src/connections/buffer-reference.js +143 -29
  40. package/src/connections/bun.d.ts +1 -1
  41. package/src/connections/bun.js +25 -14
  42. package/src/connections/deno.d.ts +3 -1
  43. package/src/connections/deno.js +35 -14
  44. package/src/connections/external-array-buffer.d.ts +2 -0
  45. package/src/connections/external-array-buffer.js +33 -0
  46. package/src/connections/node-addons.d.ts +11 -0
  47. package/src/connections/node-addons.js +49 -1
  48. package/src/connections/node-ffi-api.d.ts +19 -0
  49. package/src/connections/node-ffi-api.js +28 -0
  50. package/src/connections/node-ffi.d.ts +27 -0
  51. package/src/connections/node-ffi.js +262 -0
  52. package/src/connections/node.d.ts +1 -1
  53. package/src/connections/node.js +20 -20
  54. package/src/connections/package-assets.js +25 -15
  55. package/src/connections/posix.d.ts +42 -0
  56. package/src/connections/posix.js +101 -0
  57. package/src/connections/process-shared-buffer.d.ts +1 -0
  58. package/src/connections/process-shared-buffer.js +11 -45
  59. package/src/connections/types.d.ts +4 -0
  60. package/src/connections/windows.d.ts +19 -10
  61. package/src/connections/windows.js +87 -66
  62. package/src/error.d.ts +7 -6
  63. package/src/error.js +8 -7
  64. package/src/memory/lock.d.ts +112 -77
  65. package/src/memory/lock.js +314 -87
  66. package/src/memory/payloadCodec.d.ts +11 -2
  67. package/src/memory/payloadCodec.js +129 -37
  68. package/src/memory/regionRegistry.d.ts +1 -3
  69. package/src/memory/regionRegistry.js +16 -14
  70. package/src/permission/compatibility.d.ts +28 -0
  71. package/src/permission/compatibility.js +239 -0
  72. package/src/permission/index.d.ts +2 -0
  73. package/src/permission/index.js +1 -0
  74. package/src/permission/protocol.d.ts +1 -0
  75. package/src/permission/protocol.js +59 -15
  76. package/src/runtime/compiled-artifact.d.ts +21 -0
  77. package/src/runtime/compiled-artifact.js +260 -0
  78. package/src/runtime/compiled-builder.d.ts +8 -0
  79. package/src/runtime/compiled-builder.js +42 -0
  80. package/src/runtime/compiled-worker.d.ts +27 -0
  81. package/src/runtime/compiled-worker.js +562 -0
  82. package/src/runtime/dispatcher.js +9 -0
  83. package/src/runtime/inline-executor.js +27 -15
  84. package/src/runtime/pool.d.ts +121 -5
  85. package/src/runtime/pool.js +263 -49
  86. package/src/runtime/process-worker.d.ts +3 -13
  87. package/src/runtime/process-worker.js +97 -101
  88. package/src/runtime/tx-queue.d.ts +18 -2
  89. package/src/runtime/tx-queue.js +56 -16
  90. package/src/runtime/worker-common.d.ts +13 -0
  91. package/src/runtime/worker-common.js +102 -0
  92. package/src/types.d.ts +89 -9
  93. package/src/worker/composable-runners.js +3 -2
  94. package/src/worker/loop.d.ts +1 -0
  95. package/src/worker/loop.js +52 -17
  96. package/src/worker/rx-queue.d.ts +11 -1
  97. package/src/worker/rx-queue.js +4 -1
  98. package/src/worker/task-loader.d.ts +5 -4
  99. package/src/worker/task-loader.js +13 -7
  100. package/src/worker/timers.d.ts +8 -1
  101. package/src/worker/timers.js +28 -23
@@ -14,6 +14,107 @@ export const F_GETFD = 1;
14
14
  export const F_SETFD = 2;
15
15
  export const FD_CLOEXEC = 1;
16
16
  export const encodeCString = (value) => new TextEncoder().encode(`${value}\0`);
17
+ // libc exposes errno through a function returning its address: `__error()` on
18
+ // macOS, `__errno_location()` on Linux. FFI callers read the int behind it to
19
+ // turn a bare -1 into something diagnosable.
20
+ export const getErrnoSymbolName = (platform) => platform === "darwin" ? "__error" : "__errno_location";
21
+ // Only the codes shm_open/mmap/ftruncate/dup realistically return; anything
22
+ // else prints as a bare number.
23
+ const ERRNO_NAMES = {
24
+ 1: "EPERM",
25
+ 2: "ENOENT",
26
+ 9: "EBADF",
27
+ 12: "ENOMEM",
28
+ 13: "EACCES",
29
+ 17: "EEXIST",
30
+ 22: "EINVAL",
31
+ 24: "EMFILE",
32
+ 28: "ENOSPC",
33
+ };
34
+ const PLATFORM_ERRNO_NAMES = {
35
+ darwin: { 45: "ENOTSUP", 63: "ENAMETOOLONG" },
36
+ linux: { 36: "ENAMETOOLONG", 95: "ENOTSUP" },
37
+ };
38
+ const isNullPointer = (pointer) => pointer === null || pointer === undefined || pointer === 0 || pointer === 0n;
39
+ /**
40
+ * Wraps a bound `__error`/`__errno_location` into a reader that never throws.
41
+ * Runtimes differ only in how they turn the returned address into an int.
42
+ */
43
+ export const makeErrnoReader = (locate, readInt32) => {
44
+ if (locate === undefined)
45
+ return () => undefined;
46
+ return () => {
47
+ try {
48
+ const pointer = locate();
49
+ return isNullPointer(pointer) ? undefined : readInt32(pointer);
50
+ }
51
+ catch {
52
+ return undefined;
53
+ }
54
+ };
55
+ };
56
+ const describeErrno = (errno, platform) => {
57
+ if (errno === undefined)
58
+ return "errno unavailable";
59
+ const name = PLATFORM_ERRNO_NAMES[platform][errno] ?? ERRNO_NAMES[errno];
60
+ return name === undefined ? `errno ${errno}` : `${name} (${errno})`;
61
+ };
62
+ /**
63
+ * Builds `<message>: EACCES (13)`, reading errno as late as possible, or the
64
+ * bare message when the runtime has no errno reader.
65
+ */
66
+ export const posixError = (message, errno, platform = detectPosixPlatform()) => errno === undefined
67
+ ? new Error(message)
68
+ : new Error(`${message}: ${describeErrno(errno(), platform)}`);
69
+ export const checkPosixResult = (result, message, errno, platform) => {
70
+ if (result < 0)
71
+ throw posixError(message, errno, platform);
72
+ return result;
73
+ };
74
+ const detectArch = () => globalThis
75
+ .Deno?.build?.arch ??
76
+ globalThis
77
+ .process?.arch ??
78
+ "";
79
+ /**
80
+ * Whether `shm_open`'s mode argument has to be delivered on the stack.
81
+ *
82
+ * macOS declares `shm_open(const char *, int, ...)` variadic and its libc
83
+ * wrapper reads the mode with `va_arg`. Apple's arm64 ABI passes variadic
84
+ * arguments on the stack, not in registers, so the mode a fixed-arity FFI call
85
+ * leaves in a register is never read: the segment is created with whatever the
86
+ * stack happened to hold. The creator's own descriptor still works, so the
87
+ * damage only surfaces when the name is opened again and fails with EACCES —
88
+ * and because the value comes from uninitialized stack, unrelated changes to
89
+ * the calling code can flip it between working and not.
90
+ *
91
+ * Declaring six extra register arguments moves the mode into the first stack
92
+ * slot, which is exactly where `va_arg` looks. Linux (fixed prototype) and
93
+ * x86-64 macOS (variadic arguments in registers) both want the plain form.
94
+ */
95
+ export const shmOpenModeIsStackPassed = (platform = detectPosixPlatform()) => platform === "darwin" && /arm64|aarch64/.test(detectArch());
96
+ /** Fills x2–x7 so the mode becomes the first stack argument. */
97
+ export const SHM_OPEN_STACK_PAD = [0, 0, 0, 0, 0, 0];
98
+ /**
99
+ * Proves a freshly created macOS segment can be reopened by name, closing the
100
+ * owner descriptor and throwing if it cannot.
101
+ *
102
+ * Without this, a mode that failed to apply produces a confusing EACCES in
103
+ * whichever process later opens the name, far from the call that caused it.
104
+ * No-ops off macOS, where the mode always applies.
105
+ */
106
+ export const assertNamedSharedMemoryIsReopenable = (platform, ownerFd, reopen, close, errno) => {
107
+ if (platform !== "darwin")
108
+ return;
109
+ const probe = reopen();
110
+ if (probe >= 0) {
111
+ close(probe);
112
+ return;
113
+ }
114
+ const error = posixError("created shared memory could not be reopened by name", errno, platform);
115
+ close(ownerFd);
116
+ throw error;
117
+ };
17
118
  export const setCloseOnExec = (libc, fd) => {
18
119
  const flags = libc.symbols.fcntl(fd, F_GETFD, 0);
19
120
  if (flags < 0) {
@@ -71,5 +71,6 @@ export declare class ProcessSharedBuffer {
71
71
  stringifyMetadata(): string;
72
72
  toString(): string;
73
73
  }
74
+ export declare const isProcessSharedBufferValue: (value: unknown) => value is ProcessSharedBuffer;
74
75
  export declare const parseProcessSharedBufferMetadata: (input: unknown) => ProcessSharedBufferMetadata;
75
76
  export {};
@@ -1,10 +1,8 @@
1
- import { getNodeBuiltinModule } from "../common/node-compat.js";
2
1
  import { FileDescriptor, } from "./file-descriptor.js";
3
2
  import { RUNTIME } from "../common/runtime.js";
4
3
  import { createBunConnectionPrimitives } from "./bun.js";
5
4
  import { createDenoConnectionPrimitives } from "./deno.js";
6
- import { loadNodeNativeAddon } from "./node-addons.js";
7
- import { expectFd, expectPositiveSize, readCreateMode, readCreateName, readRequiredCreateName, readCreateSize, } from "./types.js";
5
+ import { createNodeConnectionPrimitives } from "./node.js";
8
6
  export const PROCESS_SHARED_BUFFER_BRAND = Symbol.for("knitting.processSharedBuffer");
9
7
  export const PROCESS_SHARED_BUFFER_NUMERIC_TRANSFER = Symbol.for("knitting.processSharedBuffer.numericTransfer");
10
8
  const EXTERNAL_PAYLOAD_BRAND = Symbol.for("knitting.payloadCodec");
@@ -39,51 +37,15 @@ const decodeKind = (value) => {
39
37
  }
40
38
  };
41
39
  let defaultPrimitives;
42
- const fromDefaultNodeNativeMapping = (mapped) => {
43
- const mapping = {
44
- runtime: "node",
45
- fd: mapped.fd,
46
- size: mapped.size,
47
- byteLength: mapped.sab.byteLength,
48
- buffer: mapped.sab,
49
- kind: "shared-array-buffer",
50
- sab: mapped.sab,
51
- baseAddressMod64: mapped.baseAddressMod64,
52
- };
53
- if (mapped.name !== undefined && mapped.name.length > 0) {
54
- mapping.name = mapped.name;
55
- }
56
- return mapping;
57
- };
58
- const createDefaultNodePrimitives = () => {
59
- const nodeModule = getNodeBuiltinModule("node:module");
60
- if (nodeModule === undefined) {
61
- throw new TypeError("ProcessSharedBuffer needs connection primitives in this runtime");
62
- }
63
- const require = nodeModule.createRequire(import.meta.url);
64
- const addon = loadNodeNativeAddon(require, "knitting_shared_memory");
65
- return {
66
- createSharedMemory: (options) => {
67
- const size = expectPositiveSize(readCreateSize(options));
68
- const mode = readCreateMode(options);
69
- const name = mode === "anonymous"
70
- ? readCreateName(options, "knitting_shared_memory")
71
- : readRequiredCreateName(options);
72
- return fromDefaultNodeNativeMapping(addon.createSharedMemory(size, name, mode));
73
- },
74
- mapSharedMemory: (options) => {
75
- const fd = expectFd(options.fd);
76
- const size = expectPositiveSize(options.size);
77
- return fromDefaultNodeNativeMapping(addon.mapSharedMemory(fd, size, options.name));
78
- },
79
- };
80
- };
40
+ const processSharedBufferInstances = new WeakSet();
81
41
  const createDefaultPrimitives = () => {
82
42
  if (RUNTIME === "bun")
83
43
  return createBunConnectionPrimitives();
84
44
  if (RUNTIME === "deno")
85
45
  return createDenoConnectionPrimitives();
86
- return createDefaultNodePrimitives();
46
+ if (RUNTIME === "node")
47
+ return createNodeConnectionPrimitives();
48
+ throw new TypeError("ProcessSharedBuffer needs connection primitives in this runtime");
87
49
  };
88
50
  export const setDefaultProcessSharedBufferPrimitives = (primitives) => {
89
51
  defaultPrimitives = primitives;
@@ -136,6 +98,7 @@ export class ProcessSharedBuffer {
136
98
  this.descriptor = descriptor;
137
99
  this.byteOffset = byteOffset;
138
100
  this.byteLength = byteLength;
101
+ processSharedBufferInstances.add(this);
139
102
  }
140
103
  static create(options, creator = getDefaultProcessSharedBufferPrimitives()) {
141
104
  return ProcessSharedBuffer.fromMapping(creator.createSharedMemory(options));
@@ -251,6 +214,9 @@ export class ProcessSharedBuffer {
251
214
  return this.stringify();
252
215
  }
253
216
  }
217
+ export const isProcessSharedBufferValue = (value) => value !== null &&
218
+ typeof value === "object" &&
219
+ processSharedBufferInstances.has(value);
254
220
  export const parseProcessSharedBufferMetadata = (input) => {
255
221
  const value = typeof input === "string" ? JSON.parse(input) : input;
256
222
  if (!isRecord(value)) {
@@ -271,8 +237,8 @@ export const parseProcessSharedBufferMetadata = (input) => {
271
237
  };
272
238
  };
273
239
  const processSharedBufferGlobal = globalThis;
274
- const codecs = processSharedBufferGlobal.__KNITTING_PAYLOAD_CODECS__ ??=
275
- Object.create(null);
240
+ const codecs = processSharedBufferGlobal.__KNITTING_PAYLOAD_CODECS__ ??= Object
241
+ .create(null);
276
242
  codecs[PROCESS_SHARED_BUFFER_CODEC_ID] = {
277
243
  decode: (metadata) => ProcessSharedBuffer.fromMetadata(metadata),
278
244
  decodeNumeric: (metadata) => ProcessSharedBuffer[PROCESS_SHARED_BUFFER_NUMERIC_TRANSFER](metadata),
@@ -31,6 +31,10 @@ export type MapSharedMemoryOptions = {
31
31
  fd: number;
32
32
  name?: string;
33
33
  size: number;
34
+ /**
35
+ * When false, map the supplied descriptor directly. Ownership transfers to
36
+ * the returned mapping only after mapping succeeds; failures leave it open.
37
+ */
34
38
  duplicateFd?: boolean;
35
39
  };
36
40
  export type SharedMemoryConnectionPrimitives<Mapping extends SharedMemoryMapping = SharedMemoryMapping> = {
@@ -1,28 +1,37 @@
1
+ import { type NodeFfiLibrary } from "./node-ffi-api.js";
1
2
  import { type CreateSharedMemoryOptions, type MapSharedMemoryOptions, type SharedMemoryConnectionPrimitives, type SharedMemoryMapping } from "./types.js";
3
+ declare const WINDOWS_CREATE_SHARED_MEMORY = "knitting_windows_create_shared_memory";
4
+ declare const WINDOWS_MAP_SHARED_MEMORY = "knitting_windows_map_shared_memory";
5
+ declare const WINDOWS_CLOSE_SHARED_MEMORY = "knitting_windows_close_shared_memory";
6
+ type WindowsSharedMemorySymbols = {
7
+ [WINDOWS_CREATE_SHARED_MEMORY]: (size: bigint, name: Uint16Array, mode: number, out: Uint8Array) => number;
8
+ [WINDOWS_MAP_SHARED_MEMORY]: (handle: bigint, size: bigint, name: Uint16Array, out: Uint8Array) => number;
9
+ [WINDOWS_CLOSE_SHARED_MEMORY]: (mapping: Uint8Array) => number;
10
+ };
2
11
  type DenoWindowsLibrary = {
3
- symbols: {
4
- knitting_windows_create_shared_memory: (size: bigint, name: Uint16Array, mode: number, out: Uint8Array) => number;
5
- knitting_windows_map_shared_memory: (handle: bigint, size: bigint, name: Uint16Array, out: Uint8Array) => number;
6
- knitting_windows_close_shared_memory: (mapping: Uint8Array) => number;
7
- };
12
+ symbols: WindowsSharedMemorySymbols;
8
13
  close: () => void;
9
14
  };
10
15
  type BunWindowsLibrary = {
11
- symbols: {
12
- knitting_windows_create_shared_memory: (size: bigint, name: Uint16Array, mode: number, out: Uint8Array) => number;
13
- knitting_windows_map_shared_memory: (handle: bigint, size: bigint, name: Uint16Array, out: Uint8Array) => number;
14
- knitting_windows_close_shared_memory: (mapping: Uint8Array) => number;
15
- };
16
+ symbols: WindowsSharedMemorySymbols;
17
+ };
18
+ type NodeWindowsLibrary = {
19
+ functions: WindowsSharedMemorySymbols;
20
+ lib: NodeFfiLibrary;
16
21
  };
17
22
  export declare const isWindowsRuntime: () => boolean;
18
23
  export declare const windowsSharedMemoryPrebuildPath: () => string;
19
24
  export declare const makeWindowsAnonymousSharedMemoryName: (runtime: string) => string;
20
25
  export declare const openDenoWindowsSharedMemoryLibrary: () => DenoWindowsLibrary;
21
26
  export declare const openBunWindowsSharedMemoryLibrary: () => BunWindowsLibrary;
27
+ export declare const openNodeWindowsSharedMemoryLibrary: () => NodeWindowsLibrary;
22
28
  export declare const createDenoWindowsSharedMemory: (options: number | CreateSharedMemoryOptions, lib?: DenoWindowsLibrary) => SharedMemoryMapping<ArrayBuffer>;
23
29
  export declare const mapDenoWindowsSharedMemory: (options: MapSharedMemoryOptions, lib?: DenoWindowsLibrary) => SharedMemoryMapping<ArrayBuffer>;
24
30
  export declare const createDenoWindowsConnectionPrimitives: (lib?: DenoWindowsLibrary) => SharedMemoryConnectionPrimitives<SharedMemoryMapping<ArrayBuffer>>;
25
31
  export declare const createBunWindowsSharedMemory: (options: number | CreateSharedMemoryOptions, lib?: BunWindowsLibrary) => SharedMemoryMapping<ArrayBuffer>;
26
32
  export declare const mapBunWindowsSharedMemory: (options: MapSharedMemoryOptions, lib?: BunWindowsLibrary) => SharedMemoryMapping<ArrayBuffer>;
27
33
  export declare const createBunWindowsConnectionPrimitives: (lib?: BunWindowsLibrary) => SharedMemoryConnectionPrimitives<SharedMemoryMapping<ArrayBuffer>>;
34
+ export declare const createNodeWindowsSharedMemory: (options: number | CreateSharedMemoryOptions, lib?: NodeWindowsLibrary) => SharedMemoryMapping<ArrayBuffer>;
35
+ export declare const mapNodeWindowsSharedMemory: (options: MapSharedMemoryOptions, lib?: NodeWindowsLibrary) => SharedMemoryMapping<ArrayBuffer>;
36
+ export declare const createNodeWindowsConnectionPrimitives: (lib?: NodeWindowsLibrary) => SharedMemoryConnectionPrimitives<SharedMemoryMapping<ArrayBuffer>>;
28
37
  export {};
@@ -1,4 +1,6 @@
1
1
  import { resolveKnittingPackageAsset } from "./package-assets.js";
2
+ import { requireDetachedExternalArrayBuffer } from "./external-array-buffer.js";
3
+ import { getNodeFfi, } from "./node-ffi-api.js";
2
4
  import { expectFd, expectPositiveSize, readCreateMode, readCreateSize, readRequiredCreateName, } from "./types.js";
3
5
  const WINDOWS_CREATE_MODE_CREATE = 1;
4
6
  const WINDOWS_CREATE_MODE_OPEN = 2;
@@ -7,6 +9,9 @@ const POINTER_OFFSET = 0;
7
9
  const HANDLE_OFFSET = 8;
8
10
  const SIZE_OFFSET = 16;
9
11
  const BASE_ADDRESS_MOD_64_OFFSET = 24;
12
+ const WINDOWS_CREATE_SHARED_MEMORY = "knitting_windows_create_shared_memory";
13
+ const WINDOWS_MAP_SHARED_MEMORY = "knitting_windows_map_shared_memory";
14
+ const WINDOWS_CLOSE_SHARED_MEMORY = "knitting_windows_close_shared_memory";
10
15
  const FFIType = {
11
16
  i32: 5,
12
17
  u32: 6,
@@ -105,34 +110,59 @@ const checkWindowsResult = (result, message) => {
105
110
  }
106
111
  };
107
112
  const createRecord = () => new Uint8Array(WINDOWS_MAPPING_RECORD_BYTES);
108
- export const openDenoWindowsSharedMemoryLibrary = () => getDeno().dlopen(windowsSharedMemoryPrebuildPath(), {
109
- knitting_windows_create_shared_memory: {
113
+ const DENO_WINDOWS_SYMBOLS = {
114
+ [WINDOWS_CREATE_SHARED_MEMORY]: {
110
115
  parameters: ["u64", "buffer", "u32", "buffer"],
111
116
  result: "i32",
112
117
  },
113
- knitting_windows_map_shared_memory: {
118
+ [WINDOWS_MAP_SHARED_MEMORY]: {
114
119
  parameters: ["u64", "u64", "buffer", "buffer"],
115
120
  result: "i32",
116
121
  },
117
- knitting_windows_close_shared_memory: {
122
+ [WINDOWS_CLOSE_SHARED_MEMORY]: {
118
123
  parameters: ["buffer"],
119
124
  result: "i32",
120
125
  },
121
- });
122
- export const openBunWindowsSharedMemoryLibrary = () => getBunFFI().dlopen(windowsSharedMemoryPrebuildPath(), {
123
- knitting_windows_create_shared_memory: {
126
+ };
127
+ const BUN_WINDOWS_SYMBOLS = {
128
+ [WINDOWS_CREATE_SHARED_MEMORY]: {
124
129
  args: [FFIType.i64, FFIType.ptr, FFIType.u32, FFIType.ptr],
125
130
  returns: FFIType.i32,
126
131
  },
127
- knitting_windows_map_shared_memory: {
132
+ [WINDOWS_MAP_SHARED_MEMORY]: {
128
133
  args: [FFIType.i64, FFIType.i64, FFIType.ptr, FFIType.ptr],
129
134
  returns: FFIType.i32,
130
135
  },
131
- knitting_windows_close_shared_memory: {
136
+ [WINDOWS_CLOSE_SHARED_MEMORY]: {
132
137
  args: [FFIType.ptr],
133
138
  returns: FFIType.i32,
134
139
  },
135
- });
140
+ };
141
+ const NODE_WINDOWS_SYMBOLS = {
142
+ [WINDOWS_CREATE_SHARED_MEMORY]: {
143
+ arguments: ["u64", "pointer", "u32", "pointer"],
144
+ return: "i32",
145
+ },
146
+ [WINDOWS_MAP_SHARED_MEMORY]: {
147
+ arguments: ["u64", "u64", "pointer", "pointer"],
148
+ return: "i32",
149
+ },
150
+ [WINDOWS_CLOSE_SHARED_MEMORY]: {
151
+ arguments: ["pointer"],
152
+ return: "i32",
153
+ },
154
+ };
155
+ export const openDenoWindowsSharedMemoryLibrary = () => getDeno().dlopen(windowsSharedMemoryPrebuildPath(), DENO_WINDOWS_SYMBOLS);
156
+ export const openBunWindowsSharedMemoryLibrary = () => getBunFFI().dlopen(windowsSharedMemoryPrebuildPath(), BUN_WINDOWS_SYMBOLS);
157
+ let cachedNodeWindowsLibrary;
158
+ export const openNodeWindowsSharedMemoryLibrary = () => {
159
+ if (cachedNodeWindowsLibrary !== undefined) {
160
+ return cachedNodeWindowsLibrary;
161
+ }
162
+ const opened = getNodeFfi().dlopen(windowsSharedMemoryPrebuildPath(), NODE_WINDOWS_SYMBOLS);
163
+ cachedNodeWindowsLibrary = opened;
164
+ return opened;
165
+ };
136
166
  const closeWindowsMapping = (record, closeSharedMemory) => {
137
167
  let closed = false;
138
168
  return () => {
@@ -142,6 +172,19 @@ const closeWindowsMapping = (record, closeSharedMemory) => {
142
172
  checkWindowsResult(closeSharedMemory(record), "knitting_windows_close_shared_memory");
143
173
  };
144
174
  };
175
+ const makeWindowsMapping = (runtime, mapping, name, arrayBuffer, unsafePointer, close) => ({
176
+ runtime,
177
+ fd: fdFromHandle(mapping.handle),
178
+ name,
179
+ size: mapping.size,
180
+ byteLength: arrayBuffer.byteLength,
181
+ buffer: arrayBuffer,
182
+ kind: "external-array-buffer",
183
+ arrayBuffer,
184
+ unsafePointer,
185
+ baseAddressMod64: mapping.baseAddressMod64,
186
+ close,
187
+ });
145
188
  const fromDenoWindowsRecord = (record, name, lib) => {
146
189
  const mapping = readWindowsNativeMapping(record);
147
190
  const pointer = getDeno().UnsafePointer?.create(mapping.address);
@@ -150,19 +193,7 @@ const fromDenoWindowsRecord = (record, name, lib) => {
150
193
  }
151
194
  const arrayBuffer = new (getDeno().UnsafePointerView)(pointer)
152
195
  .getArrayBuffer(mapping.size);
153
- return {
154
- runtime: "deno",
155
- fd: fdFromHandle(mapping.handle),
156
- name,
157
- size: mapping.size,
158
- byteLength: arrayBuffer.byteLength,
159
- buffer: arrayBuffer,
160
- kind: "external-array-buffer",
161
- arrayBuffer,
162
- unsafePointer: pointer,
163
- baseAddressMod64: mapping.baseAddressMod64,
164
- close: closeWindowsMapping(record, lib.symbols.knitting_windows_close_shared_memory),
165
- };
196
+ return makeWindowsMapping("deno", mapping, name, arrayBuffer, pointer, closeWindowsMapping(record, lib.symbols[WINDOWS_CLOSE_SHARED_MEMORY]));
166
197
  };
167
198
  const fromBunWindowsRecord = (record, name, lib) => {
168
199
  const mapping = readWindowsNativeMapping(record);
@@ -170,55 +201,45 @@ const fromBunWindowsRecord = (record, name, lib) => {
170
201
  throw new RangeError("Windows mapping pointer is too large for Bun FFI");
171
202
  }
172
203
  const arrayBuffer = getBunFFI().toArrayBuffer(Number(mapping.address), 0, mapping.size);
173
- return {
174
- runtime: "bun",
175
- fd: fdFromHandle(mapping.handle),
176
- name,
177
- size: mapping.size,
178
- byteLength: arrayBuffer.byteLength,
179
- buffer: arrayBuffer,
180
- kind: "external-array-buffer",
181
- arrayBuffer,
182
- unsafePointer: Number(mapping.address),
183
- baseAddressMod64: mapping.baseAddressMod64,
184
- close: closeWindowsMapping(record, lib.symbols.knitting_windows_close_shared_memory),
185
- };
186
- };
187
- export const createDenoWindowsSharedMemory = (options, lib = openDenoWindowsSharedMemoryLibrary()) => {
188
- const size = expectPositiveSize(readCreateSize(options));
189
- const { mode, name } = readWindowsCreate(options, "deno");
190
- const record = createRecord();
191
- checkWindowsResult(lib.symbols.knitting_windows_create_shared_memory(BigInt(size), encodeWideCString(name), mode, record), "knitting_windows_create_shared_memory");
192
- return fromDenoWindowsRecord(record, name, lib);
204
+ return makeWindowsMapping("bun", mapping, name, arrayBuffer, Number(mapping.address), closeWindowsMapping(record, lib.symbols[WINDOWS_CLOSE_SHARED_MEMORY]));
193
205
  };
194
- export const mapDenoWindowsSharedMemory = (options, lib = openDenoWindowsSharedMemoryLibrary()) => {
195
- const fd = expectFd(options.fd);
196
- const size = expectPositiveSize(options.size);
197
- const record = createRecord();
198
- checkWindowsResult(lib.symbols.knitting_windows_map_shared_memory(BigInt(fd), BigInt(size), encodeWideCString(options.name), record), "knitting_windows_map_shared_memory");
199
- return fromDenoWindowsRecord(record, options.name, lib);
206
+ const fromNodeWindowsRecord = (record, name, lib) => {
207
+ const mapping = readWindowsNativeMapping(record);
208
+ const arrayBuffer = getNodeFfi().toArrayBuffer(mapping.address, mapping.size, false);
209
+ let closed = false;
210
+ return makeWindowsMapping("node", mapping, name, arrayBuffer, mapping.address, () => {
211
+ if (closed)
212
+ return;
213
+ requireDetachedExternalArrayBuffer(arrayBuffer);
214
+ checkWindowsResult(lib.functions[WINDOWS_CLOSE_SHARED_MEMORY](record), WINDOWS_CLOSE_SHARED_MEMORY);
215
+ closed = true;
216
+ });
200
217
  };
201
- export const createDenoWindowsConnectionPrimitives = (lib = openDenoWindowsSharedMemoryLibrary()) => ({
202
- runtime: "deno",
203
- createSharedMemory: (options) => createDenoWindowsSharedMemory(options, lib),
204
- mapSharedMemory: (options) => mapDenoWindowsSharedMemory(options, lib),
205
- });
206
- export const createBunWindowsSharedMemory = (options, lib = openBunWindowsSharedMemoryLibrary()) => {
218
+ const createWindowsSharedMemory = (options, runtime, lib, createSharedMemory, fromRecord) => {
207
219
  const size = expectPositiveSize(readCreateSize(options));
208
- const { mode, name } = readWindowsCreate(options, "bun");
220
+ const { mode, name } = readWindowsCreate(options, runtime);
209
221
  const record = createRecord();
210
- checkWindowsResult(lib.symbols.knitting_windows_create_shared_memory(BigInt(size), encodeWideCString(name), mode, record), "knitting_windows_create_shared_memory");
211
- return fromBunWindowsRecord(record, name, lib);
222
+ checkWindowsResult(createSharedMemory(BigInt(size), encodeWideCString(name), mode, record), WINDOWS_CREATE_SHARED_MEMORY);
223
+ return fromRecord(record, name, lib);
212
224
  };
213
- export const mapBunWindowsSharedMemory = (options, lib = openBunWindowsSharedMemoryLibrary()) => {
225
+ const mapWindowsSharedMemory = (options, lib, mapSharedMemory, fromRecord) => {
214
226
  const fd = expectFd(options.fd);
215
227
  const size = expectPositiveSize(options.size);
216
228
  const record = createRecord();
217
- checkWindowsResult(lib.symbols.knitting_windows_map_shared_memory(BigInt(fd), BigInt(size), encodeWideCString(options.name), record), "knitting_windows_map_shared_memory");
218
- return fromBunWindowsRecord(record, options.name, lib);
219
- };
220
- export const createBunWindowsConnectionPrimitives = (lib = openBunWindowsSharedMemoryLibrary()) => ({
221
- runtime: "bun",
222
- createSharedMemory: (options) => createBunWindowsSharedMemory(options, lib),
223
- mapSharedMemory: (options) => mapBunWindowsSharedMemory(options, lib),
229
+ checkWindowsResult(mapSharedMemory(BigInt(fd), BigInt(size), encodeWideCString(options.name), record), WINDOWS_MAP_SHARED_MEMORY);
230
+ return fromRecord(record, options.name, lib);
231
+ };
232
+ export const createDenoWindowsSharedMemory = (options, lib = openDenoWindowsSharedMemoryLibrary()) => createWindowsSharedMemory(options, "deno", lib, lib.symbols[WINDOWS_CREATE_SHARED_MEMORY], fromDenoWindowsRecord);
233
+ export const mapDenoWindowsSharedMemory = (options, lib = openDenoWindowsSharedMemoryLibrary()) => mapWindowsSharedMemory(options, lib, lib.symbols[WINDOWS_MAP_SHARED_MEMORY], fromDenoWindowsRecord);
234
+ const createWindowsConnectionPrimitives = (runtime, lib, createSharedMemory, mapSharedMemory) => ({
235
+ runtime,
236
+ createSharedMemory: (options) => createSharedMemory(options, lib),
237
+ mapSharedMemory: (options) => mapSharedMemory(options, lib),
224
238
  });
239
+ export const createDenoWindowsConnectionPrimitives = (lib = openDenoWindowsSharedMemoryLibrary()) => createWindowsConnectionPrimitives("deno", lib, createDenoWindowsSharedMemory, mapDenoWindowsSharedMemory);
240
+ export const createBunWindowsSharedMemory = (options, lib = openBunWindowsSharedMemoryLibrary()) => createWindowsSharedMemory(options, "bun", lib, lib.symbols[WINDOWS_CREATE_SHARED_MEMORY], fromBunWindowsRecord);
241
+ export const mapBunWindowsSharedMemory = (options, lib = openBunWindowsSharedMemoryLibrary()) => mapWindowsSharedMemory(options, lib, lib.symbols[WINDOWS_MAP_SHARED_MEMORY], fromBunWindowsRecord);
242
+ export const createBunWindowsConnectionPrimitives = (lib = openBunWindowsSharedMemoryLibrary()) => createWindowsConnectionPrimitives("bun", lib, createBunWindowsSharedMemory, mapBunWindowsSharedMemory);
243
+ export const createNodeWindowsSharedMemory = (options, lib = openNodeWindowsSharedMemoryLibrary()) => createWindowsSharedMemory(options, "node", lib, lib.functions[WINDOWS_CREATE_SHARED_MEMORY], fromNodeWindowsRecord);
244
+ export const mapNodeWindowsSharedMemory = (options, lib = openNodeWindowsSharedMemoryLibrary()) => mapWindowsSharedMemory(options, lib, lib.functions[WINDOWS_MAP_SHARED_MEMORY], fromNodeWindowsRecord);
245
+ export const createNodeWindowsConnectionPrimitives = (lib = openNodeWindowsSharedMemoryLibrary()) => createWindowsConnectionPrimitives("node", lib, createNodeWindowsSharedMemory, mapNodeWindowsSharedMemory);
package/src/error.d.ts CHANGED
@@ -1,10 +1,11 @@
1
1
  import { type PromisePayloadHandler, type Task } from "./memory/lock.js";
2
- export declare enum ErrorKnitting {
3
- Function = 0,
4
- Symbol = 1,
5
- Json = 2,
6
- Serializable = 3
7
- }
2
+ export declare const ErrorKnitting: {
3
+ readonly Function: 0;
4
+ readonly Symbol: 1;
5
+ readonly Json: 2;
6
+ readonly Serializable: 3;
7
+ };
8
+ export type ErrorKnitting = typeof ErrorKnitting[keyof typeof ErrorKnitting];
8
9
  export declare const encoderError: ({ task, type, onPromise, detail, }: {
9
10
  task: Task;
10
11
  type: ErrorKnitting;
package/src/error.js CHANGED
@@ -1,12 +1,13 @@
1
1
  import { beginPromisePayload, finishPromisePayload, TaskFlag, TaskIndex, } from "./memory/lock.js";
2
2
  import { RUNTIME_IS_MAIN_THREAD } from "./common/worker-runtime.js";
3
- export var ErrorKnitting;
4
- (function (ErrorKnitting) {
5
- ErrorKnitting[ErrorKnitting["Function"] = 0] = "Function";
6
- ErrorKnitting[ErrorKnitting["Symbol"] = 1] = "Symbol";
7
- ErrorKnitting[ErrorKnitting["Json"] = 2] = "Json";
8
- ErrorKnitting[ErrorKnitting["Serializable"] = 3] = "Serializable";
9
- })(ErrorKnitting || (ErrorKnitting = {}));
3
+ // const object, not `enum`: Andromeda's Nova engine can't parse `enum`. Same
4
+ // value access and emit on Node/Deno/Bun.
5
+ export const ErrorKnitting = {
6
+ Function: 0,
7
+ Symbol: 1,
8
+ Json: 2,
9
+ Serializable: 3,
10
+ };
10
11
  const reasonFrom = (task, type, detail) => {
11
12
  switch (type) {
12
13
  case ErrorKnitting.Function: {