@componentor/fs 3.0.51 → 3.0.52

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/dist/index.js CHANGED
@@ -362,7 +362,12 @@ var OP = {
362
362
  var SAB_OFFSETS = {
363
363
  // Int32 - bytes in this chunk
364
364
  TOTAL_LEN: 16,
365
- // Int32 - reserved
365
+ // Int32 - 0-based chunk index
366
+ HEARTBEAT: 28,
367
+ // Int32 - liveness counter; the relay worker bumps this ~1×/s
368
+ // while its event loop is alive (incl. mid-await of a
369
+ // long op) so a spin-waiting main thread can tell
370
+ // "slow" from "dead". Never written by the main thread.
366
371
  HEADER_SIZE: 32
367
372
  // Data payload starts here
368
373
  };
@@ -2556,19 +2561,37 @@ var DEFAULT_SAB_SIZE = 2 * 1024 * 1024;
2556
2561
  var instanceRegistry = /* @__PURE__ */ new Map();
2557
2562
  var HEADER_SIZE = SAB_OFFSETS.HEADER_SIZE;
2558
2563
  var _canAtomicsWait = typeof globalThis.WorkerGlobalScope !== "undefined";
2559
- var SPIN_TIMEOUT_MS = 1e4;
2560
- function spinWait(arr, index, value) {
2564
+ var SAB_HEARTBEAT_INDEX = SAB_OFFSETS.HEARTBEAT >> 2;
2565
+ var SPIN_STALL_TIMEOUT_MS = 2e4;
2566
+ var SPIN_NO_HEARTBEAT_TIMEOUT_MS = 3e4;
2567
+ function spinWait(arr, index, value, heartbeatArr) {
2561
2568
  if (_canAtomicsWait) {
2562
2569
  Atomics.wait(arr, index, value);
2563
- } else {
2570
+ return;
2571
+ }
2572
+ if (!heartbeatArr) {
2564
2573
  const start = performance.now();
2565
2574
  while (Atomics.load(arr, index) === value) {
2566
- if (performance.now() - start > SPIN_TIMEOUT_MS) {
2575
+ if (performance.now() - start > SPIN_NO_HEARTBEAT_TIMEOUT_MS) {
2567
2576
  throw new Error(
2568
- `VFS sync operation timed out after ${SPIN_TIMEOUT_MS / 1e3}s \u2014 SharedWorker may be unresponsive`
2577
+ `VFS sync operation timed out after ${SPIN_NO_HEARTBEAT_TIMEOUT_MS / 1e3}s \u2014 relay worker did not respond`
2569
2578
  );
2570
2579
  }
2571
2580
  }
2581
+ return;
2582
+ }
2583
+ let lastBeat = Atomics.load(heartbeatArr, SAB_HEARTBEAT_INDEX);
2584
+ let lastProgress = performance.now();
2585
+ while (Atomics.load(arr, index) === value) {
2586
+ const beat = Atomics.load(heartbeatArr, SAB_HEARTBEAT_INDEX);
2587
+ if (beat !== lastBeat) {
2588
+ lastBeat = beat;
2589
+ lastProgress = performance.now();
2590
+ } else if (performance.now() - lastProgress > SPIN_STALL_TIMEOUT_MS) {
2591
+ throw new Error(
2592
+ `VFS sync operation aborted: relay worker heartbeat stalled for ${SPIN_STALL_TIMEOUT_MS / 1e3}s \u2014 worker is unresponsive`
2593
+ );
2594
+ }
2572
2595
  }
2573
2596
  }
2574
2597
  var VFSFileSystem = class {
@@ -3041,7 +3064,7 @@ var VFSFileSystem = class {
3041
3064
  if (signal === -1) {
3042
3065
  throw this.initError ?? new Error("VFS initialization failed");
3043
3066
  }
3044
- spinWait(this.readySignal, 0, 0);
3067
+ spinWait(this.readySignal, 0, 0, this.ctrl);
3045
3068
  const finalSignal = Atomics.load(this.readySignal, 0);
3046
3069
  if (finalSignal === -1) {
3047
3070
  throw this.initError ?? new Error("VFS initialization failed");
@@ -3055,7 +3078,8 @@ var VFSFileSystem = class {
3055
3078
  const maxChunk = this.sab.byteLength - HEADER_SIZE;
3056
3079
  const requestBytes = new Uint8Array(requestBuf);
3057
3080
  const totalLenView = new BigUint64Array(this.sab, SAB_OFFSETS.TOTAL_LEN, 1);
3058
- if (requestBytes.byteLength <= maxChunk) {
3081
+ const multiChunkRequest = requestBytes.byteLength > maxChunk;
3082
+ if (!multiChunkRequest) {
3059
3083
  new Uint8Array(this.sab, HEADER_SIZE, requestBytes.byteLength).set(requestBytes);
3060
3084
  Atomics.store(this.ctrl, 3, requestBytes.byteLength);
3061
3085
  Atomics.store(totalLenView, 0, BigInt(requestBytes.byteLength));
@@ -3079,11 +3103,11 @@ var VFSFileSystem = class {
3079
3103
  Atomics.notify(this.ctrl, 0);
3080
3104
  sent += chunkSize;
3081
3105
  if (sent < requestBytes.byteLength) {
3082
- spinWait(this.ctrl, 0, sent === chunkSize ? SIGNAL.REQUEST : SIGNAL.CHUNK);
3106
+ spinWait(this.ctrl, 0, sent === chunkSize ? SIGNAL.REQUEST : SIGNAL.CHUNK, this.ctrl);
3083
3107
  }
3084
3108
  }
3085
3109
  }
3086
- spinWait(this.ctrl, 0, SIGNAL.REQUEST);
3110
+ spinWait(this.ctrl, 0, multiChunkRequest ? SIGNAL.CHUNK : SIGNAL.REQUEST, this.ctrl);
3087
3111
  const signal = Atomics.load(this.ctrl, 0);
3088
3112
  const respChunkLen = Atomics.load(this.ctrl, 3);
3089
3113
  const respTotalLen = Number(Atomics.load(totalLenView, 0));
@@ -3099,7 +3123,7 @@ var VFSFileSystem = class {
3099
3123
  while (received < respTotalLen) {
3100
3124
  Atomics.store(this.ctrl, 0, SIGNAL.CHUNK_ACK);
3101
3125
  Atomics.notify(this.ctrl, 0);
3102
- spinWait(this.ctrl, 0, SIGNAL.CHUNK_ACK);
3126
+ spinWait(this.ctrl, 0, SIGNAL.CHUNK_ACK, this.ctrl);
3103
3127
  const nextLen = Atomics.load(this.ctrl, 3);
3104
3128
  responseBytes.set(new Uint8Array(this.sab, HEADER_SIZE, nextLen), received);
3105
3129
  received += nextLen;