@nxtedition/shared 4.0.1 → 4.0.3

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/README.md CHANGED
@@ -23,10 +23,10 @@ npm install @nxtedition/shared
23
23
  ## Usage
24
24
 
25
25
  ```js
26
- import { State, Reader, Writer } from '@nxtedition/shared'
26
+ import { SharedStateBuffer, Reader, Writer } from '@nxtedition/shared'
27
27
 
28
- // Allocate shared memory (pass state.buffer to a worker thread)
29
- const state = new State(1024 * 1024) // 1 MB ring buffer
28
+ // Allocate shared memory (pass state to a worker thread)
29
+ const state = new SharedStateBuffer(1024 * 1024) // 1 MB ring buffer
30
30
 
31
31
  // --- Writer side (e.g. main thread) ---
32
32
  const w = new Writer(state)
@@ -87,12 +87,12 @@ if (!ok) {
87
87
 
88
88
  ```js
89
89
  // main.js
90
- import { State, Writer } from '@nxtedition/shared'
90
+ import { SharedStateBuffer, Writer } from '@nxtedition/shared'
91
91
  import { Worker } from 'node:worker_threads'
92
92
 
93
- const state = new State(1024 * 1024)
93
+ const state = new SharedStateBuffer(1024 * 1024)
94
94
  const worker = new Worker('./reader-worker.js', {
95
- workerData: state.buffer,
95
+ workerData: state,
96
96
  })
97
97
 
98
98
  const w = new Writer(state)
@@ -117,20 +117,17 @@ poll()
117
117
 
118
118
  ## API
119
119
 
120
- ### `new State(size: number)` / `new State(buffer: SharedArrayBuffer)`
120
+ ### `new SharedStateBuffer(size: number)`
121
121
 
122
- Allocates or wraps a shared memory buffer for the ring buffer. The first 128 bytes are reserved for state (read/write pointers); the rest is the data region.
122
+ Extends `SharedArrayBuffer`. Allocates a shared memory buffer for the ring buffer. The first 128 bytes are reserved for state (read/write pointers); the rest is the data region. Overhead (length header + alignment + next-header slot) is added automatically so that a single write of `size` bytes is always guaranteed to fit.
123
123
 
124
- - **size** — Data capacity in bytes (must be a positive integer, max ~2 GB)
125
- - **buffer** — An existing `SharedArrayBuffer` to wrap
124
+ - **size** — Maximum payload size in bytes for a single write (must be a positive integer, max ~2 GB)
126
125
 
127
- #### `state.buffer`
126
+ Since `SharedStateBuffer` extends `SharedArrayBuffer`, pass it directly to a worker thread.
128
127
 
129
- The underlying `SharedArrayBuffer`. Pass this to a worker thread to share the ring buffer.
128
+ ### `new Reader(sharedBuffer: SharedArrayBuffer)`
130
129
 
131
- ### `new Reader(state: State | SharedArrayBuffer)`
132
-
133
- Creates a reader for the ring buffer. Accepts a `State` instance or a `SharedArrayBuffer` directly (shorthand for `new Reader(new State(buf))`).
130
+ Creates a reader for the ring buffer.
134
131
 
135
132
  #### `reader.readSome(next, opaque?)`
136
133
 
@@ -147,9 +144,9 @@ Return `false` from the callback to stop reading early. Returns the number of me
147
144
 
148
145
  Messages are batched: up to 1024 items or 256 KiB per call.
149
146
 
150
- ### `new Writer(state: State | SharedArrayBuffer, options?)`
147
+ ### `new Writer(sharedBuffer: SharedArrayBuffer, options?)`
151
148
 
152
- Creates a writer for the ring buffer. Accepts a `State` instance or a `SharedArrayBuffer` directly (shorthand for `new Writer(new State(buf))`).
149
+ Creates a writer for the ring buffer.
153
150
 
154
151
  **Options:**
155
152
 
package/lib/index.d.ts CHANGED
@@ -11,21 +11,21 @@ export interface WriterOptions {
11
11
  };
12
12
  }
13
13
  /**
14
- * Shared ring buffer state. Allocates or wraps a SharedArrayBuffer where the
15
- * first 128 bytes are reserved for read/write pointers and the rest is the
16
- * data region.
14
+ * Shared ring buffer state. Extends SharedArrayBuffer where the first 128
15
+ * bytes are reserved for read/write pointers and the rest is the data region.
16
+ *
17
+ * The `size` parameter is the guaranteed max payload for a single write.
18
+ * Overhead (length header + alignment + next-header slot) is added automatically.
17
19
  */
18
- export declare class State {
19
- readonly buffer: SharedArrayBuffer;
20
+ export declare class SharedStateBuffer extends SharedArrayBuffer {
20
21
  constructor(size: number);
21
- constructor(buffer: SharedArrayBuffer);
22
22
  }
23
23
  /**
24
24
  * Reader for the ring buffer.
25
25
  */
26
26
  export declare class Reader {
27
27
  #private;
28
- constructor(state: State | SharedArrayBuffer);
28
+ constructor(sharedBuffer: SharedArrayBuffer);
29
29
  readSome<U>(next: (data: BufferRegion, opaque?: U) => void | boolean, opaque?: U): number;
30
30
  }
31
31
  /**
@@ -33,22 +33,25 @@ export declare class Reader {
33
33
  */
34
34
  export declare class Writer {
35
35
  #private;
36
- constructor(state: State | SharedArrayBuffer, { yield: onYield, logger }?: WriterOptions);
36
+ constructor(sharedBuffer: SharedArrayBuffer, { yield: onYield, logger }?: WriterOptions);
37
37
  /**
38
38
  * Synchronously writes a message. Blocks (via `Atomics.wait`) until buffer space is available.
39
39
  * Writing more than "len" bytes in the callback will cause undefined behavior.
40
40
  */
41
- writeSync<U>(len: number, fn: (data: BufferRegion, opaque?: U) => number, opaque?: U): void;
41
+ writeSync(len: number, fn: (data: BufferRegion) => number): void;
42
+ writeSync<U>(len: number, fn: (data: BufferRegion, opaque: U) => number, opaque: U): void;
42
43
  /**
43
44
  * Non-blocking write attempt. Returns `false` if the buffer is full.
44
45
  * Writing more than "len" bytes in the callback will cause undefined behavior.
45
46
  */
46
- tryWrite<U>(len: number, fn: (data: BufferRegion, opaque?: U) => number, opaque?: U): boolean;
47
+ tryWrite(len: number, fn: (data: BufferRegion) => number): boolean;
48
+ tryWrite<U>(len: number, fn: (data: BufferRegion, opaque: U) => number, opaque: U): boolean;
47
49
  /**
48
50
  * Batches multiple writes within the callback. The write pointer is only
49
51
  * published to the reader when cork returns, reducing atomic operation overhead.
50
52
  */
51
- cork<T>(callback?: () => T): T | undefined;
53
+ cork(): void;
54
+ cork<T>(callback: () => T): T;
52
55
  /**
53
56
  * Publishes the pending write position to the reader.
54
57
  */
package/lib/index.js CHANGED
@@ -29,38 +29,25 @@ const HWM_COUNT = 1024 // 1024 items
29
29
 
30
30
 
31
31
  /**
32
- * Shared ring buffer state. Allocates or wraps a SharedArrayBuffer where the
33
- * first 128 bytes are reserved for read/write pointers and the rest is the
34
- * data region.
32
+ * Shared ring buffer state. Extends SharedArrayBuffer where the first 128
33
+ * bytes are reserved for read/write pointers and the rest is the data region.
34
+ *
35
+ * The `size` parameter is the guaranteed max payload for a single write.
36
+ * Overhead (length header + alignment + next-header slot) is added automatically.
35
37
  */
36
- export class State {
37
- buffer
38
-
39
-
40
-
41
- constructor(sizeOrBuffer ) {
42
- if (sizeOrBuffer instanceof SharedArrayBuffer) {
43
- if (sizeOrBuffer.byteLength < STATE_BYTES + 8) {
44
- throw new RangeError('SharedArrayBuffer too small for ring buffer state')
45
- }
46
- if (sizeOrBuffer.byteLength >= 2 ** 31) {
47
- throw new RangeError('Shared buffer size exceeds maximum of 2GB')
48
- }
49
- this.buffer = sizeOrBuffer
50
- } else {
51
- const size = sizeOrBuffer
52
- if (!Number.isInteger(size)) {
53
- throw new TypeError('size must be a positive integer')
54
- }
55
- if (size <= 0) {
56
- throw new RangeError('size must be a positive integer')
57
- }
58
- if (size >= 2 ** 31 - 11) {
59
- throw new RangeError('size exceeds maximum of 2GB minus header size')
60
- }
61
- // 128 bytes for state + data region (rounded up to 4-byte boundary for Int32Array).
62
- this.buffer = new SharedArrayBuffer(STATE_BYTES + ((size + 8 + 3) & ~3))
38
+ export class SharedStateBuffer extends SharedArrayBuffer {
39
+ constructor(size ) {
40
+ if (!Number.isInteger(size)) {
41
+ throw new TypeError('size must be a positive integer')
42
+ }
43
+ if (size <= 0) {
44
+ throw new RangeError('size must be a positive integer')
45
+ }
46
+ if (size >= 2 ** 31) {
47
+ throw new RangeError('size exceeds maximum of 2GB')
63
48
  }
49
+ // Data region: aligned payload + 4-byte length header + 4-byte next-header slot.
50
+ super(STATE_BYTES + ((size + 3) & ~3) + 8)
64
51
  }
65
52
  }
66
53
 
@@ -74,8 +61,7 @@ export class Reader {
74
61
  #data
75
62
  #readPos
76
63
 
77
- constructor(state ) {
78
- const sharedBuffer = state instanceof SharedArrayBuffer ? state : state.buffer
64
+ constructor(sharedBuffer ) {
79
65
  const size = sharedBuffer.byteLength - STATE_BYTES
80
66
 
81
67
  this.#state = new Int32Array(sharedBuffer, 0, STATE_BYTES >> 2)
@@ -183,9 +169,7 @@ export class Writer {
183
169
  #logger
184
170
  #uncorkBound
185
171
 
186
- constructor(state , { yield: onYield, logger } = {}) {
187
- const sharedBuffer = state instanceof SharedArrayBuffer ? state : state.buffer
188
-
172
+ constructor(sharedBuffer , { yield: onYield, logger } = {}) {
189
173
  if (onYield != null && typeof onYield !== 'function') {
190
174
  throw new TypeError('onYield must be a function')
191
175
  }
@@ -384,7 +368,9 @@ export class Writer {
384
368
  * Synchronously writes a message. Blocks (via `Atomics.wait`) until buffer space is available.
385
369
  * Writing more than "len" bytes in the callback will cause undefined behavior.
386
370
  */
387
- writeSync (len , fn , opaque ) {
371
+
372
+
373
+ writeSync (len , fn , opaque ) {
388
374
  if (typeof len !== 'number') {
389
375
  throw new TypeError('"len" must be a non-negative number')
390
376
  }
@@ -438,7 +424,9 @@ export class Writer {
438
424
  * Non-blocking write attempt. Returns `false` if the buffer is full.
439
425
  * Writing more than "len" bytes in the callback will cause undefined behavior.
440
426
  */
441
- tryWrite (len , fn , opaque ) {
427
+
428
+
429
+ tryWrite (len , fn , opaque ) {
442
430
  if (typeof len !== 'number') {
443
431
  throw new TypeError('"len" must be a non-negative number')
444
432
  }
@@ -472,6 +460,8 @@ export class Writer {
472
460
  * Batches multiple writes within the callback. The write pointer is only
473
461
  * published to the reader when cork returns, reducing atomic operation overhead.
474
462
  */
463
+
464
+
475
465
  cork (callback ) {
476
466
  this.#corked += 1
477
467
  if (callback != null) {
@@ -486,7 +476,7 @@ export class Writer {
486
476
  /**
487
477
  * Publishes the pending write position to the reader.
488
478
  */
489
- uncork() {
479
+ uncork() {
490
480
  if (this.#corked === 0) {
491
481
  return
492
482
  }
@@ -497,7 +487,7 @@ export class Writer {
497
487
  }
498
488
  }
499
489
 
500
- flushSync() {
490
+ flushSync() {
501
491
  if (this.#pending > 0) {
502
492
  Atomics.store(this.#state, WRITE_INDEX, this.#writePos)
503
493
  this.#pending = 0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nxtedition/shared",
3
- "version": "4.0.1",
3
+ "version": "4.0.3",
4
4
  "type": "module",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",
@@ -26,5 +26,6 @@
26
26
  "oxlint-tsgolint": "^0.13.0",
27
27
  "rimraf": "^6.1.3",
28
28
  "typescript": "^5.9.3"
29
- }
29
+ },
30
+ "gitHead": "239c3eeff1f228d4d71ff6f8c884642f359065b5"
30
31
  }