knitting 0.1.55 → 0.1.56

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 (138) hide show
  1. package/knitting.d.ts +6 -797
  2. package/knitting.js +6 -9780
  3. package/map.md +12 -8
  4. package/package.json +14 -6
  5. package/process-shared-buffer.d.ts +1 -0
  6. package/process-shared-buffer.js +1 -0
  7. package/shared-memory.d.ts +1 -155
  8. package/shared-memory.js +1 -1342
  9. package/src/api.d.ts +69 -0
  10. package/src/api.js +619 -0
  11. package/src/common/envelope.d.ts +17 -0
  12. package/src/common/envelope.js +22 -0
  13. package/src/common/module-url.d.ts +1 -0
  14. package/src/common/module-url.js +24 -0
  15. package/src/common/node-compat.d.ts +20 -0
  16. package/src/common/node-compat.js +24 -0
  17. package/src/common/path-canonical.d.ts +6 -0
  18. package/src/common/path-canonical.js +41 -0
  19. package/src/common/runtime.d.ts +15 -0
  20. package/src/common/runtime.js +91 -0
  21. package/src/common/shared-buffer-region.d.ts +11 -0
  22. package/src/common/shared-buffer-region.js +21 -0
  23. package/src/common/shared-buffer-text.d.ts +16 -0
  24. package/src/common/shared-buffer-text.js +65 -0
  25. package/src/common/task-source.d.ts +3 -0
  26. package/src/common/task-source.js +84 -0
  27. package/src/common/task-symbol.d.ts +1 -0
  28. package/src/common/task-symbol.js +1 -0
  29. package/src/common/with-resolvers.d.ts +9 -0
  30. package/src/common/with-resolvers.js +23 -0
  31. package/src/common/worker-runtime.d.ts +42 -0
  32. package/src/common/worker-runtime.js +61 -0
  33. package/src/connections/buffer-reference-native.d.ts +56 -0
  34. package/src/connections/buffer-reference-native.js +217 -0
  35. package/src/connections/buffer-reference.d.ts +78 -0
  36. package/src/connections/buffer-reference.js +461 -0
  37. package/src/connections/bun.d.ts +22 -0
  38. package/src/connections/bun.js +214 -0
  39. package/src/connections/deno.d.ts +22 -0
  40. package/src/connections/deno.js +205 -0
  41. package/src/connections/file-descriptor.d.ts +39 -0
  42. package/src/connections/file-descriptor.js +161 -0
  43. package/src/connections/index.d.ts +4 -0
  44. package/src/connections/index.js +4 -0
  45. package/src/connections/node-addons.d.ts +5 -0
  46. package/src/connections/node-addons.js +44 -0
  47. package/src/connections/node-buffer-pointer.d.ts +20 -0
  48. package/src/connections/node-buffer-pointer.js +16 -0
  49. package/src/connections/node.d.ts +30 -0
  50. package/src/connections/node.js +62 -0
  51. package/src/connections/numeric-array.d.ts +5 -0
  52. package/src/connections/numeric-array.js +17 -0
  53. package/src/connections/package-assets.d.ts +2 -0
  54. package/src/connections/package-assets.js +45 -0
  55. package/src/connections/posix.d.ts +32 -0
  56. package/src/connections/posix.js +77 -0
  57. package/src/connections/process-shared-buffer.d.ts +75 -0
  58. package/src/connections/process-shared-buffer.js +279 -0
  59. package/src/connections/shared-array-buffer-payload.d.ts +36 -0
  60. package/src/connections/shared-array-buffer-payload.js +235 -0
  61. package/src/connections/types.d.ts +50 -0
  62. package/src/connections/types.js +37 -0
  63. package/src/connections/windows.d.ts +28 -0
  64. package/src/connections/windows.js +224 -0
  65. package/src/debug/env-diff.d.ts +26 -0
  66. package/src/debug/env-diff.js +49 -0
  67. package/src/debug/gate.d.ts +18 -0
  68. package/src/debug/gate.js +69 -0
  69. package/src/debug/handle.d.ts +23 -0
  70. package/src/debug/handle.js +48 -0
  71. package/src/error.d.ts +13 -0
  72. package/src/error.js +49 -0
  73. package/src/ipc/tools/ring-queue.d.ts +33 -0
  74. package/src/ipc/tools/ring-queue.js +159 -0
  75. package/src/ipc/transport/shared-memory.d.ts +23 -0
  76. package/src/ipc/transport/shared-memory.js +35 -0
  77. package/src/memory/byte-carpet.d.ts +73 -0
  78. package/src/memory/byte-carpet.js +157 -0
  79. package/src/memory/lock.d.ts +203 -0
  80. package/src/memory/lock.js +741 -0
  81. package/src/memory/payload-config.d.ts +31 -0
  82. package/src/memory/payload-config.js +67 -0
  83. package/src/memory/payloadCodec.d.ts +46 -0
  84. package/src/memory/payloadCodec.js +1377 -0
  85. package/src/memory/regionRegistry.d.ts +17 -0
  86. package/src/memory/regionRegistry.js +285 -0
  87. package/src/memory/shared-buffer-io.d.ts +55 -0
  88. package/src/memory/shared-buffer-io.js +403 -0
  89. package/src/permission/index.d.ts +2 -0
  90. package/src/permission/index.js +2 -0
  91. package/src/permission/protocol.d.ts +166 -0
  92. package/src/permission/protocol.js +650 -0
  93. package/src/runtime/balancer.d.ts +19 -0
  94. package/src/runtime/balancer.js +149 -0
  95. package/src/runtime/dispatcher.d.ts +40 -0
  96. package/src/runtime/dispatcher.js +142 -0
  97. package/src/runtime/inline-executor.d.ts +10 -0
  98. package/src/runtime/inline-executor.js +282 -0
  99. package/src/runtime/pool.d.ts +39 -0
  100. package/src/runtime/pool.js +404 -0
  101. package/src/runtime/process-worker.d.ts +92 -0
  102. package/src/runtime/process-worker.js +673 -0
  103. package/src/runtime/tx-queue.d.ts +26 -0
  104. package/src/runtime/tx-queue.js +155 -0
  105. package/src/shared/abortSignal.d.ts +23 -0
  106. package/src/shared/abortSignal.js +134 -0
  107. package/src/types.d.ts +357 -0
  108. package/src/types.js +2 -0
  109. package/src/utils/http.d.ts +29 -0
  110. package/src/utils/http.js +100 -0
  111. package/src/worker/bootstrap.d.ts +5 -0
  112. package/src/worker/bootstrap.js +78 -0
  113. package/src/worker/composable-runners.d.ts +12 -0
  114. package/src/worker/composable-runners.js +97 -0
  115. package/src/worker/loop.d.ts +2 -0
  116. package/src/worker/loop.js +382 -0
  117. package/src/worker/process-worker-bootstrap.d.ts +8 -0
  118. package/src/worker/process-worker-bootstrap.js +160 -0
  119. package/src/worker/rx-queue.d.ts +25 -0
  120. package/src/worker/rx-queue.js +173 -0
  121. package/src/worker/safety/index.d.ts +4 -0
  122. package/src/worker/safety/index.js +4 -0
  123. package/src/worker/safety/performance.d.ts +1 -0
  124. package/src/worker/safety/performance.js +17 -0
  125. package/src/worker/safety/process.d.ts +2 -0
  126. package/src/worker/safety/process.js +79 -0
  127. package/src/worker/safety/startup.d.ts +16 -0
  128. package/src/worker/safety/startup.js +30 -0
  129. package/src/worker/safety/worker-data.d.ts +2 -0
  130. package/src/worker/safety/worker-data.js +36 -0
  131. package/src/worker/task-loader.d.ts +27 -0
  132. package/src/worker/task-loader.js +70 -0
  133. package/src/worker/timers.d.ts +18 -0
  134. package/src/worker/timers.js +116 -0
  135. package/unsafe.d.ts +1 -71
  136. package/unsafe.js +1 -878
  137. package/utils.d.ts +1 -31
  138. package/utils.js +1 -116
@@ -0,0 +1,461 @@
1
+ import { RUNTIME } from "../common/runtime.js";
2
+ import { getNodeProcess } from "../common/node-compat.js";
3
+ import { RUNTIME_IS_MAIN_THREAD } from "../common/worker-runtime.js";
4
+ import { loadNodeBufferPointerAddon } from "./node-buffer-pointer.js";
5
+ import { getBufferReferenceCapabilities, } from "./buffer-reference-native.js";
6
+ export const BUFFER_REFERENCE_KIND = "knitting.bufferReference";
7
+ /** Named values for the `unsafe.BufferReferenceReturn` pool option. */
8
+ export const BufferReferenceReturn = {
9
+ /** Safe default: Deno/Bun copy the returned bytes so they outlive the worker. */
10
+ Copy: "copy",
11
+ /** Zero-copy: borrow the worker's backing store until the reference is released. */
12
+ Borrow: "borrow",
13
+ };
14
+ export const BUFFER_REFERENCE_NUMERIC_TRANSFER = Symbol.for("knitting.bufferReference.numericTransfer");
15
+ export const BUFFER_REFERENCE_RETURN_RELEASE_TOKEN = Symbol.for("knitting.bufferReference.returnReleaseToken");
16
+ const EXTERNAL_PAYLOAD_BRAND = Symbol.for("knitting.payloadCodec");
17
+ export const BUFFER_REFERENCE_CODEC_ID = BUFFER_REFERENCE_KIND;
18
+ const BUFFER_REFERENCE_RETURN_RELEASE_MESSAGE_KEY = "__knittingBufferReferenceRelease";
19
+ const getRuntime = () => {
20
+ if (RUNTIME === "deno" || RUNTIME === "bun" || RUNTIME === "node") {
21
+ return RUNTIME;
22
+ }
23
+ throw new Error(`BufferReference cannot run in runtime "${RUNTIME}"`);
24
+ };
25
+ const getProcessId = () => {
26
+ const proc = getNodeProcess();
27
+ if (proc !== undefined && typeof proc.pid === "number")
28
+ return proc.pid;
29
+ const deno = globalThis.Deno;
30
+ if (typeof deno?.pid === "number")
31
+ return deno.pid;
32
+ return 0;
33
+ };
34
+ const PROCESS_ORIGIN = `${RUNTIME}:${getProcessId()}`;
35
+ const NUMERIC_WORD_MASK = 0xffffffffn;
36
+ const RUNTIME_NODE = 1;
37
+ const RUNTIME_DENO = 2;
38
+ const RUNTIME_BUN = 3;
39
+ const PAYLOAD_TRANSPORT_FINALIZER = Symbol.for("knitting.payloadCodec.transportFinalizer");
40
+ let currentReturnReleaser;
41
+ const encodeRuntime = (runtime) => {
42
+ switch (runtime) {
43
+ case "node":
44
+ return RUNTIME_NODE;
45
+ case "deno":
46
+ return RUNTIME_DENO;
47
+ case "bun":
48
+ return RUNTIME_BUN;
49
+ }
50
+ };
51
+ const decodeRuntime = (runtime) => {
52
+ switch (runtime) {
53
+ case RUNTIME_NODE:
54
+ return "node";
55
+ case RUNTIME_DENO:
56
+ return "deno";
57
+ case RUNTIME_BUN:
58
+ return "bun";
59
+ default:
60
+ return undefined;
61
+ }
62
+ };
63
+ const splitU64 = (value) => [
64
+ Number(value & NUMERIC_WORD_MASK) >>> 0,
65
+ Number((value >> 32n) & NUMERIC_WORD_MASK) >>> 0,
66
+ ];
67
+ const joinU64 = (low, high) => (BigInt(high >>> 0) << 32n) | BigInt(low >>> 0);
68
+ const readOriginPid = (origin) => {
69
+ const separator = origin.indexOf(":");
70
+ if (separator < 0)
71
+ return undefined;
72
+ const pid = Number(origin.slice(separator + 1));
73
+ return Number.isInteger(pid) && pid >= 0 && pid <= 0xffffffff
74
+ ? pid >>> 0
75
+ : undefined;
76
+ };
77
+ const numericMetadataToMetadata = (words) => {
78
+ const runtime = decodeRuntime(words[6] ?? 0);
79
+ if (runtime === undefined) {
80
+ throw new TypeError("Invalid BufferReference numeric runtime");
81
+ }
82
+ const originPid = words[7];
83
+ if (originPid === undefined ||
84
+ !Number.isInteger(originPid) ||
85
+ originPid < 0) {
86
+ throw new TypeError("Invalid BufferReference numeric origin");
87
+ }
88
+ return {
89
+ kind: BUFFER_REFERENCE_KIND,
90
+ origin: `${runtime}:${originPid >>> 0}`,
91
+ runtime,
92
+ pointer: joinU64(words[0] ?? 0, words[1] ?? 0).toString(),
93
+ token: joinU64(words[2] ?? 0, words[3] ?? 0).toString(),
94
+ byteOffset: words[4] ?? 0,
95
+ byteLength: words[5] ?? 0,
96
+ };
97
+ };
98
+ export const withBufferReferenceReturnReleaser = (releaser, run) => {
99
+ if (releaser === undefined)
100
+ return run();
101
+ const previous = currentReturnReleaser;
102
+ currentReturnReleaser = releaser;
103
+ try {
104
+ return run();
105
+ }
106
+ finally {
107
+ currentReturnReleaser = previous;
108
+ }
109
+ };
110
+ export const createBufferReferenceReturnReleaseMessage = (token) => ({
111
+ [BUFFER_REFERENCE_RETURN_RELEASE_MESSAGE_KEY]: token.toString(),
112
+ });
113
+ export const readBufferReferenceReturnReleaseMessage = (value) => {
114
+ if (value === null || typeof value !== "object")
115
+ return undefined;
116
+ const raw = value[BUFFER_REFERENCE_RETURN_RELEASE_MESSAGE_KEY];
117
+ if (typeof raw !== "string")
118
+ return undefined;
119
+ try {
120
+ const token = BigInt(raw);
121
+ return token > 0n ? token : undefined;
122
+ }
123
+ catch {
124
+ return undefined;
125
+ }
126
+ };
127
+ // Backstop for references that never flow through the transport.
128
+ const producerFinalizer = typeof FinalizationRegistry === "function"
129
+ ? new FinalizationRegistry(({ token, release }) => {
130
+ try {
131
+ release(token);
132
+ }
133
+ catch {
134
+ // best effort
135
+ }
136
+ })
137
+ : undefined;
138
+ const borrowedReturnFinalizer = typeof FinalizationRegistry === "function"
139
+ ? new FinalizationRegistry(({ token, release }) => {
140
+ try {
141
+ release(token);
142
+ }
143
+ catch {
144
+ // best effort
145
+ }
146
+ })
147
+ : undefined;
148
+ const isSharedArrayBufferInstance = (value) => typeof SharedArrayBuffer === "function" && value instanceof SharedArrayBuffer;
149
+ const assertMovableSource = (source) => {
150
+ if (isSharedArrayBufferInstance(source)) {
151
+ throw new TypeError("BufferReference expects ArrayBuffer memory; SharedArrayBuffer is already shared and cannot be detached");
152
+ }
153
+ if (ArrayBuffer.isView(source)) {
154
+ if (isSharedArrayBufferInstance(source.buffer)) {
155
+ throw new TypeError("BufferReference expects ArrayBuffer-backed views; SharedArrayBuffer is already shared and cannot be detached");
156
+ }
157
+ return;
158
+ }
159
+ if (!(source instanceof ArrayBuffer)) {
160
+ throw new TypeError("BufferReference expects an ArrayBuffer or typed-array view");
161
+ }
162
+ };
163
+ const isDetached = (buffer) => buffer.detached === true ||
164
+ buffer.byteLength === 0;
165
+ const detachArrayBufferBestEffort = (runtime, buffer) => {
166
+ if (isDetached(buffer))
167
+ return true;
168
+ if (runtime === "node") {
169
+ try {
170
+ return loadNodeBufferPointerAddon().detachArrayBuffer(buffer);
171
+ }
172
+ catch {
173
+ // fall through to the JS detach paths
174
+ }
175
+ }
176
+ const transferable = buffer;
177
+ try {
178
+ if (typeof transferable.transferToFixedLength === "function") {
179
+ transferable.transferToFixedLength(0);
180
+ return isDetached(buffer);
181
+ }
182
+ if (typeof transferable.transfer === "function") {
183
+ transferable.transfer(0);
184
+ return isDetached(buffer);
185
+ }
186
+ }
187
+ catch {
188
+ // fall through
189
+ }
190
+ try {
191
+ if (typeof structuredClone === "function") {
192
+ structuredClone(buffer, { transfer: [buffer] });
193
+ return isDetached(buffer);
194
+ }
195
+ }
196
+ catch {
197
+ // give up
198
+ }
199
+ return false;
200
+ };
201
+ export const isBufferReferenceMetadata = (value) => {
202
+ if (value === null || typeof value !== "object")
203
+ return false;
204
+ const meta = value;
205
+ return (meta.kind === BUFFER_REFERENCE_KIND &&
206
+ typeof meta.origin === "string" &&
207
+ (meta.runtime === "node" || meta.runtime === "deno" ||
208
+ meta.runtime === "bun") &&
209
+ typeof meta.pointer === "string" &&
210
+ typeof meta.token === "string" &&
211
+ typeof meta.byteOffset === "number" &&
212
+ Number.isInteger(meta.byteOffset) &&
213
+ meta.byteOffset >= 0 &&
214
+ typeof meta.byteLength === "number" &&
215
+ Number.isInteger(meta.byteLength) &&
216
+ meta.byteLength >= 0);
217
+ };
218
+ /**
219
+ * Zero-copy handle for moving ArrayBuffer bytes to/from **thread** workers.
220
+ *
221
+ * Construction detaches the source. Consumers materialize the moved region in
222
+ * their isolate: owning on Node, alias/copy on Deno/Bun. Return a
223
+ * `BufferReference` for large binary results to avoid copying back through the
224
+ * transport. Use `ProcessSharedBuffer` across process boundaries.
225
+ */
226
+ export class BufferReference {
227
+ [EXTERNAL_PAYLOAD_BRAND] = BUFFER_REFERENCE_CODEC_ID;
228
+ runtime;
229
+ origin;
230
+ pointer;
231
+ byteOffset;
232
+ byteLength;
233
+ #token;
234
+ #isProducer;
235
+ #finalizerToken;
236
+ #materializedRegions;
237
+ #owned;
238
+ #borrowedReturnReleaser;
239
+ #borrowedReturnFinalizerToken;
240
+ #transportRefs = 0;
241
+ #released = false;
242
+ constructor(source, meta) {
243
+ if (meta !== undefined) {
244
+ // Consumer side: rebuilt from metadata, materializes via the pointer/token.
245
+ this.runtime = meta.runtime;
246
+ this.origin = meta.origin;
247
+ this.pointer = BigInt(meta.pointer);
248
+ this.byteOffset = meta.byteOffset;
249
+ this.byteLength = meta.byteLength;
250
+ this.#token = BigInt(meta.token);
251
+ this.#isProducer = false;
252
+ return;
253
+ }
254
+ if (source === undefined) {
255
+ throw new TypeError("BufferReference requires a buffer source");
256
+ }
257
+ assertMovableSource(source);
258
+ const caps = getBufferReferenceCapabilities();
259
+ const produced = caps.produce(source); // detaches the source
260
+ this.runtime = getRuntime();
261
+ this.origin = PROCESS_ORIGIN;
262
+ this.pointer = produced.pointer;
263
+ this.byteOffset = produced.byteOffset;
264
+ this.byteLength = produced.byteLength;
265
+ this.#token = produced.token;
266
+ this.#isProducer = true;
267
+ this.#finalizerToken = {};
268
+ producerFinalizer?.register(this, { token: this.#token, release: caps.release }, this.#finalizerToken);
269
+ }
270
+ static fromMetadata(meta) {
271
+ if (!isBufferReferenceMetadata(meta)) {
272
+ throw new TypeError("Invalid BufferReferenceMetadata");
273
+ }
274
+ return new BufferReference(undefined, meta);
275
+ }
276
+ toMetadata() {
277
+ this.#assertActive();
278
+ return {
279
+ kind: BUFFER_REFERENCE_KIND,
280
+ origin: this.origin,
281
+ runtime: this.runtime,
282
+ pointer: this.pointer.toString(),
283
+ token: this.#token.toString(),
284
+ byteOffset: this.byteOffset,
285
+ byteLength: this.byteLength,
286
+ };
287
+ }
288
+ [BUFFER_REFERENCE_NUMERIC_TRANSFER]() {
289
+ this.#assertActive();
290
+ const originPid = readOriginPid(this.origin);
291
+ if (originPid === undefined ||
292
+ this.byteOffset > 0xffffffff ||
293
+ this.byteLength > 0xffffffff) {
294
+ return undefined;
295
+ }
296
+ const [pointerLow, pointerHigh] = splitU64(this.pointer);
297
+ const [tokenLow, tokenHigh] = splitU64(this.#token);
298
+ return [
299
+ pointerLow,
300
+ pointerHigh,
301
+ tokenLow,
302
+ tokenHigh,
303
+ this.byteOffset >>> 0,
304
+ this.byteLength >>> 0,
305
+ encodeRuntime(this.runtime),
306
+ originPid,
307
+ ];
308
+ }
309
+ get isLocal() {
310
+ return this.origin === PROCESS_ORIGIN && this.runtime === RUNTIME;
311
+ }
312
+ #assertLocal() {
313
+ if (this.origin !== PROCESS_ORIGIN) {
314
+ throw new Error(`BufferReference cannot cross a process boundary (origin ${this.origin} ` +
315
+ `!= ${PROCESS_ORIGIN}). Use ProcessSharedBuffer for cross-process memory.`);
316
+ }
317
+ if (this.runtime !== RUNTIME) {
318
+ throw new Error(`BufferReference runtime mismatch: produced on ${this.runtime}, ` +
319
+ `materializing on ${RUNTIME}.`);
320
+ }
321
+ }
322
+ #assertActive() {
323
+ if (this.#released) {
324
+ throw new Error("BufferReference has been released");
325
+ }
326
+ }
327
+ /** Prepare a returned reference before the worker-side producer hold drains. */
328
+ claimOwnership(releaser = currentReturnReleaser) {
329
+ if (this.#owned !== undefined || this.#borrowedReturnReleaser !== undefined ||
330
+ this.#released)
331
+ return this;
332
+ this.#assertLocal();
333
+ const caps = getBufferReferenceCapabilities();
334
+ const input = {
335
+ token: this.#token,
336
+ pointer: this.pointer,
337
+ byteOffset: this.byteOffset,
338
+ byteLength: this.byteLength,
339
+ };
340
+ if (releaser !== undefined) {
341
+ this.#borrowedReturnReleaser = releaser;
342
+ this.#borrowedReturnFinalizerToken = {};
343
+ borrowedReturnFinalizer?.register(this, { token: this.#token, release: releaser }, this.#borrowedReturnFinalizerToken);
344
+ return this;
345
+ }
346
+ this.#owned = caps.adopt(input, caps.supportsOwningAdopt ? undefined : { copy: true });
347
+ return this;
348
+ }
349
+ #materialize() {
350
+ this.#assertActive();
351
+ if (this.#owned !== undefined)
352
+ return this.#owned;
353
+ this.#assertLocal();
354
+ const region = getBufferReferenceCapabilities().adopt({
355
+ token: this.#token,
356
+ pointer: this.pointer,
357
+ byteOffset: this.byteOffset,
358
+ byteLength: this.byteLength,
359
+ });
360
+ if (this.#borrowedReturnReleaser !== undefined) {
361
+ this.#owned = region;
362
+ return region;
363
+ }
364
+ (this.#materializedRegions ??= []).push(region);
365
+ return region;
366
+ }
367
+ toArrayBuffer() {
368
+ const region = this.#materialize();
369
+ if (region.byteOffset === 0 && region.buffer.byteLength === region.byteLength) {
370
+ return region.buffer;
371
+ }
372
+ return region.buffer.slice(region.byteOffset, region.byteOffset + region.byteLength);
373
+ }
374
+ toUint8Array() {
375
+ const region = this.#materialize();
376
+ return new Uint8Array(region.buffer, region.byteOffset, region.byteLength);
377
+ }
378
+ /** The source is moved on construction, so it is never retained here. */
379
+ get source() {
380
+ return undefined;
381
+ }
382
+ release() {
383
+ if (this.#released)
384
+ return;
385
+ this.#released = true;
386
+ const regions = this.#materializedRegions;
387
+ this.#materializedRegions = undefined;
388
+ if (regions !== undefined) {
389
+ for (let i = 0; i < regions.length; i++) {
390
+ detachArrayBufferBestEffort(this.runtime, regions[i].buffer);
391
+ }
392
+ }
393
+ if (this.#borrowedReturnFinalizerToken !== undefined) {
394
+ borrowedReturnFinalizer?.unregister(this.#borrowedReturnFinalizerToken);
395
+ this.#borrowedReturnFinalizerToken = undefined;
396
+ }
397
+ const borrowedReturnReleaser = this.#borrowedReturnReleaser;
398
+ this.#borrowedReturnReleaser = undefined;
399
+ if (borrowedReturnReleaser !== undefined) {
400
+ const owned = this.#owned;
401
+ this.#owned = undefined;
402
+ if (owned !== undefined) {
403
+ detachArrayBufferBestEffort(this.runtime, owned.buffer);
404
+ }
405
+ try {
406
+ borrowedReturnReleaser(this.#token);
407
+ }
408
+ catch {
409
+ // best effort
410
+ }
411
+ }
412
+ if (this.#finalizerToken !== undefined) {
413
+ producerFinalizer?.unregister(this.#finalizerToken);
414
+ this.#finalizerToken = undefined;
415
+ }
416
+ // Only the producer owns the registry hold; consumers must not drop it.
417
+ if (this.#isProducer) {
418
+ try {
419
+ getBufferReferenceCapabilities().release(this.#token);
420
+ }
421
+ catch {
422
+ // best effort
423
+ }
424
+ }
425
+ }
426
+ [Symbol.dispose]() {
427
+ this.release();
428
+ }
429
+ [PAYLOAD_TRANSPORT_FINALIZER]() {
430
+ if (this.#released)
431
+ return undefined;
432
+ this.#transportRefs++;
433
+ let finalized = false;
434
+ const finalizer = (() => {
435
+ if (finalized)
436
+ return;
437
+ finalized = true;
438
+ this.#transportRefs--;
439
+ if (this.#transportRefs <= 0)
440
+ this.release();
441
+ });
442
+ if (this.#isProducer) {
443
+ finalizer[BUFFER_REFERENCE_RETURN_RELEASE_TOKEN] = this.#token;
444
+ }
445
+ return finalizer;
446
+ }
447
+ }
448
+ const codecGlobal = globalThis;
449
+ const codecs = codecGlobal.__KNITTING_PAYLOAD_CODECS__ ??= Object.create(null);
450
+ codecs[BUFFER_REFERENCE_CODEC_ID] = {
451
+ decode: (metadata) => {
452
+ const ref = BufferReference.fromMetadata(metadata);
453
+ // Host decodes are return values; claim before the worker drains.
454
+ // Worker decodes are forward inputs and stay lazy for the call.
455
+ return RUNTIME_IS_MAIN_THREAD ? ref.claimOwnership() : ref;
456
+ },
457
+ decodeNumeric: (metadata) => {
458
+ const ref = BufferReference.fromMetadata(numericMetadataToMetadata(metadata));
459
+ return RUNTIME_IS_MAIN_THREAD ? ref.claimOwnership() : ref;
460
+ },
461
+ };
@@ -0,0 +1,22 @@
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 unlinkBunSharedMemory: (name: string, libc?: BunLibc) => boolean;
20
+ export declare const createBunPosixConnectionPrimitives: (libc?: BunLibc) => SharedMemoryConnectionPrimitives<SharedMemoryMapping<ArrayBuffer>>;
21
+ export declare const createBunConnectionPrimitives: (libc?: BunLibc) => SharedMemoryConnectionPrimitives<SharedMemoryMapping<ArrayBuffer>>;
22
+ export {};
@@ -0,0 +1,214 @@
1
+ import { DARWIN_O_CREAT, DARWIN_O_EXCL, DARWIN_SHM_MODE, LINUX_O_CREAT, LINUX_O_EXCL, setCloseOnExec, detectPosixPlatform, encodeCString, getPosixLibcPath, makeDarwinSharedMemoryName, MAP_SHARED, O_RDWR, POSIX_SHM_MODE, PROT_READ, PROT_WRITE, toPosixSharedMemoryName, } from "./posix.js";
2
+ import { expectFd, expectPositiveSize, readCreateName, readCreateMode, readRequiredCreateName, readCreateSize, } from "./types.js";
3
+ import { createBunWindowsConnectionPrimitives, isWindowsRuntime, } from "./windows.js";
4
+ const FFIType = {
5
+ i32: 5,
6
+ i64: 7,
7
+ u32: 6,
8
+ usize: 8,
9
+ ptr: 12,
10
+ };
11
+ const getBunFFI = () => {
12
+ const ffi = globalThis.Bun?.FFI;
13
+ if (typeof ffi?.dlopen !== "function" ||
14
+ typeof ffi?.toArrayBuffer !== "function") {
15
+ throw new Error("Bun FFI is not available in this runtime");
16
+ }
17
+ return ffi;
18
+ };
19
+ export const openBunLibc = () => getBunFFI().dlopen(getPosixLibcPath(), {
20
+ ...getBunCreateSymbols(),
21
+ ftruncate: {
22
+ args: [FFIType.i32, FFIType.i64],
23
+ returns: FFIType.i32,
24
+ },
25
+ dup: {
26
+ args: [FFIType.i32],
27
+ returns: FFIType.i32,
28
+ },
29
+ fcntl: {
30
+ args: [FFIType.i32, FFIType.i32, FFIType.i32],
31
+ returns: FFIType.i32,
32
+ },
33
+ mmap: {
34
+ args: [
35
+ FFIType.ptr,
36
+ FFIType.usize,
37
+ FFIType.i32,
38
+ FFIType.i32,
39
+ FFIType.i32,
40
+ FFIType.i64,
41
+ ],
42
+ returns: FFIType.ptr,
43
+ },
44
+ munmap: {
45
+ args: [FFIType.ptr, FFIType.usize],
46
+ returns: FFIType.i32,
47
+ },
48
+ close: {
49
+ args: [FFIType.i32],
50
+ returns: FFIType.i32,
51
+ },
52
+ });
53
+ const getBunCreateSymbols = (platform = detectPosixPlatform()) => platform === "darwin"
54
+ ? {
55
+ shm_open: {
56
+ args: [FFIType.ptr, FFIType.i32, FFIType.u32],
57
+ returns: FFIType.i32,
58
+ },
59
+ shm_unlink: {
60
+ args: [FFIType.ptr],
61
+ returns: FFIType.i32,
62
+ },
63
+ }
64
+ : {
65
+ memfd_create: {
66
+ args: [FFIType.ptr, FFIType.u32],
67
+ returns: FFIType.i32,
68
+ },
69
+ shm_open: {
70
+ args: [FFIType.ptr, FFIType.i32, FFIType.u32],
71
+ returns: FFIType.i32,
72
+ },
73
+ shm_unlink: {
74
+ args: [FFIType.ptr],
75
+ returns: FFIType.i32,
76
+ },
77
+ };
78
+ const checkResult = (result, message) => {
79
+ if (result < 0)
80
+ throw new Error(message);
81
+ return result;
82
+ };
83
+ const isBunMmapFailed = (pointer) => !pointer || pointer < 0 || pointer >= Number.MAX_SAFE_INTEGER;
84
+ const createBunSharedMemoryFd = (name, platform, libc) => {
85
+ if (platform === "darwin") {
86
+ const shmOpen = libc.symbols.shm_open;
87
+ const shmUnlink = libc.symbols.shm_unlink;
88
+ if (shmOpen === undefined || shmUnlink === undefined) {
89
+ throw new Error("shm_open symbols are not available");
90
+ }
91
+ const shmName = encodeCString(makeDarwinSharedMemoryName(name, "bun"));
92
+ const fd = checkResult(shmOpen(shmName, O_RDWR | DARWIN_O_CREAT | DARWIN_O_EXCL, DARWIN_SHM_MODE), "shm_open failed");
93
+ shmUnlink(shmName);
94
+ try {
95
+ return setCloseOnExec(libc, fd);
96
+ }
97
+ catch (error) {
98
+ libc.symbols.close(fd);
99
+ throw error;
100
+ }
101
+ }
102
+ const memfdCreate = libc.symbols.memfd_create;
103
+ if (memfdCreate === undefined) {
104
+ throw new Error("memfd_create symbol is not available");
105
+ }
106
+ const fd = checkResult(memfdCreate(encodeCString(name), 0), "memfd_create failed");
107
+ try {
108
+ return setCloseOnExec(libc, fd);
109
+ }
110
+ catch (error) {
111
+ libc.symbols.close(fd);
112
+ throw error;
113
+ }
114
+ };
115
+ const createNamedBunSharedMemoryFd = (name, mode, platform, libc) => {
116
+ const shmOpen = libc.symbols.shm_open;
117
+ if (shmOpen === undefined) {
118
+ throw new Error("shm_open symbol is not available");
119
+ }
120
+ const createFlags = platform === "darwin" ? DARWIN_O_CREAT : LINUX_O_CREAT;
121
+ const exclusiveFlags = platform === "darwin" ? DARWIN_O_EXCL : LINUX_O_EXCL;
122
+ const flags = mode === "create"
123
+ ? O_RDWR | createFlags | exclusiveFlags
124
+ : O_RDWR;
125
+ const fd = checkResult(shmOpen(encodeCString(toPosixSharedMemoryName(name)), flags, platform === "darwin" ? DARWIN_SHM_MODE : POSIX_SHM_MODE), "shm_open failed");
126
+ try {
127
+ return setCloseOnExec(libc, fd);
128
+ }
129
+ catch (error) {
130
+ libc.symbols.close(fd);
131
+ throw error;
132
+ }
133
+ };
134
+ export const mapBunSharedMemory = (options, libc = openBunLibc()) => {
135
+ const sourceFd = options.name === undefined ? expectFd(options.fd) : -1;
136
+ const size = expectPositiveSize(options.size);
137
+ let fd = sourceFd;
138
+ if (options.name !== undefined) {
139
+ fd = createNamedBunSharedMemoryFd(options.name, "open", detectPosixPlatform(), libc);
140
+ }
141
+ else if (options.duplicateFd !== false) {
142
+ fd = checkResult(libc.symbols.dup(sourceFd), "dup(fd) failed");
143
+ try {
144
+ setCloseOnExec(libc, fd);
145
+ }
146
+ catch (error) {
147
+ libc.symbols.close(fd);
148
+ throw error;
149
+ }
150
+ }
151
+ const pointer = libc.symbols.mmap(null, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0n);
152
+ if (isBunMmapFailed(pointer)) {
153
+ if (options.duplicateFd !== false)
154
+ libc.symbols.close(fd);
155
+ throw new Error("mmap failed");
156
+ }
157
+ const arrayBuffer = getBunFFI().toArrayBuffer(pointer, 0, size);
158
+ return {
159
+ runtime: "bun",
160
+ fd,
161
+ name: options.name,
162
+ size,
163
+ byteLength: arrayBuffer.byteLength,
164
+ buffer: arrayBuffer,
165
+ kind: "external-array-buffer",
166
+ arrayBuffer,
167
+ unsafePointer: pointer,
168
+ close: () => {
169
+ libc.symbols.munmap(pointer, size);
170
+ libc.symbols.close(fd);
171
+ },
172
+ };
173
+ };
174
+ export const createBunSharedMemory = (options, libc = openBunLibc()) => {
175
+ const size = expectPositiveSize(readCreateSize(options));
176
+ const mode = readCreateMode(options);
177
+ const name = mode === "anonymous"
178
+ ? readCreateName(options, "knitting_shared_memory")
179
+ : readRequiredCreateName(options);
180
+ const platform = detectPosixPlatform();
181
+ const fd = mode === "anonymous"
182
+ ? createBunSharedMemoryFd(name, platform, libc)
183
+ : createNamedBunSharedMemoryFd(name, mode, platform, libc);
184
+ try {
185
+ if (mode !== "open") {
186
+ checkResult(libc.symbols.ftruncate(fd, BigInt(size)), "ftruncate failed");
187
+ }
188
+ const mapping = mapBunSharedMemory({ fd, size, duplicateFd: false }, libc);
189
+ if (mode !== "anonymous") {
190
+ return { ...mapping, name };
191
+ }
192
+ return mapping;
193
+ }
194
+ catch (error) {
195
+ libc.symbols.close(fd);
196
+ throw error;
197
+ }
198
+ };
199
+ export const unlinkBunSharedMemory = (name, libc = openBunLibc()) => {
200
+ const shmUnlink = libc.symbols.shm_unlink;
201
+ if (shmUnlink === undefined) {
202
+ throw new Error("shm_unlink symbol is not available");
203
+ }
204
+ return shmUnlink(encodeCString(toPosixSharedMemoryName(name))) === 0;
205
+ };
206
+ export const createBunPosixConnectionPrimitives = (libc = openBunLibc()) => ({
207
+ runtime: "bun",
208
+ createSharedMemory: (options) => createBunSharedMemory(options, libc),
209
+ mapSharedMemory: (options) => mapBunSharedMemory(options, libc),
210
+ unlinkSharedMemory: (name) => unlinkBunSharedMemory(name, libc),
211
+ });
212
+ export const createBunConnectionPrimitives = (libc) => isWindowsRuntime()
213
+ ? createBunWindowsConnectionPrimitives()
214
+ : createBunPosixConnectionPrimitives(libc);