@nmtjs/common 0.16.1 → 0.17.0-beta.2

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.md CHANGED
@@ -4,4 +4,4 @@ Permission is hereby granted, free of charge, to any person obtaining a copy of
4
4
 
5
5
  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6
6
 
7
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
7
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package/README.md CHANGED
@@ -1,9 +1,49 @@
1
1
  # NeemataJS - RPC application server for real-time applications (proof of concept)
2
2
 
3
3
  ### Built with following in mind:
4
+
4
5
  - transport-agnostic (like WebSockets, WebTransport, .etc)
5
6
  - format-agnostic (like JSON, MessagePack, BSON, .etc)
6
7
  - binary data streaming and event subscriptions
7
8
  - contract-based API
8
9
  - end-to-end type safety
9
- - CPU-intensive task execution on separate workers
10
+ - CPU-intensive task execution on separate workers
11
+
12
+ ## Neem CLI draft
13
+
14
+ `neem build` compiles config, app entries, plugin entries, and plugin-declared
15
+ artifacts into `dist` by default. It writes an internal `neem.manifest.json`
16
+ with relative artifact paths.
17
+
18
+ `neem start` consumes an existing built output directory. It reads the manifest
19
+ for executable artifacts and serialized runtime config, registers built plugin
20
+ hooks, and starts app workers in production mode.
21
+
22
+ `neem dev` uses `.neem` by default as a build-like watched output directory. It
23
+ uses the same manifest shape as `start`, restarts app workers after successful
24
+ config/app rebuilds, reloads plugin hooks after plugin entry rebuilds, and keeps
25
+ existing workers alive on rebuild errors.
26
+
27
+ ## Service integration tests
28
+
29
+ Service-backed package integration tests live beside package owners under
30
+ `packages/*/tests/integration`.
31
+
32
+ Local services:
33
+
34
+ ```sh
35
+ docker compose up -d --wait redis valkey kafka
36
+ ```
37
+
38
+ Run required service tests:
39
+
40
+ ```sh
41
+ NMTJS_REQUIRE_SERVICE_TESTS=1 \
42
+ REDIS_URL=redis://localhost:6379 \
43
+ VALKEY_URL=redis://localhost:6380 \
44
+ KAFKA_BROKERS=localhost:9092 \
45
+ pnpm run test:integration:services
46
+ ```
47
+
48
+ Without service env, these tests skip in normal package/root test runs. In CI,
49
+ `NMTJS_REQUIRE_SERVICE_TESTS=1` makes missing service env fail instead of skip.
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Little helper to combine multiple AbortSignals into one,
3
+ * with handling of null or undefined values.
4
+ */
5
+ export declare function anyAbortSignal(...signals: (globalThis.AbortSignal | undefined | null)[]): globalThis.AbortSignal;
@@ -1,4 +1,3 @@
1
- /// <reference lib="dom" />
2
1
  /**
3
2
  * Little helper to combine multiple AbortSignals into one,
4
3
  * with handling of null or undefined values.
@@ -12,7 +11,7 @@ export function anyAbortSignal(...signals) {
12
11
  return filtered[0];
13
12
  }
14
13
  else {
15
- return AbortSignal.any(filtered);
14
+ return globalThis.AbortSignal.any(filtered);
16
15
  }
17
16
  }
18
- //# sourceMappingURL=abortSignal.js.map
17
+ //# sourceMappingURL=abort-signal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"abort-signal.js","sourceRoot":"","sources":["../src/abort-signal.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,UAAU,cAAc,CAC5B,GAAG,OAAsD;IAEzD,MAAM,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,OAAO,CAA6B,CAAA;IACpE,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1B,MAAM,IAAI,KAAK,CAAC,0BAA0B,CAAC,CAAA;IAC7C,CAAC;SAAM,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACjC,OAAO,QAAQ,CAAC,CAAC,CAAC,CAAA;IACpB,CAAC;SAAM,CAAC;QACN,OAAO,UAAU,CAAC,WAAW,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;IAC7C,CAAC;AACH,CAAC"}
@@ -0,0 +1,13 @@
1
+ export type SerializedError = {
2
+ readonly name?: string;
3
+ readonly message: string;
4
+ readonly stack?: string;
5
+ readonly cause?: SerializedError;
6
+ };
7
+ export declare const MAX_SERIALIZED_ERROR_DEPTH = 5;
8
+ export type SerializeErrorOptions = {
9
+ depth?: number;
10
+ omitUndefinedStack?: boolean;
11
+ fallback?: (value: unknown) => SerializedError;
12
+ };
13
+ export declare function serializeError(value: unknown, options?: SerializeErrorOptions): SerializedError;
package/dist/error.js ADDED
@@ -0,0 +1,20 @@
1
+ // Depth-limited so a cyclic cause chain cannot recurse forever.
2
+ export const MAX_SERIALIZED_ERROR_DEPTH = 5;
3
+ export function serializeError(value, options = {}) {
4
+ const { depth = MAX_SERIALIZED_ERROR_DEPTH, omitUndefinedStack = false, fallback, } = options;
5
+ if (value instanceof Error) {
6
+ const cause = value.cause;
7
+ return {
8
+ name: value.name,
9
+ message: value.message,
10
+ ...(omitUndefinedStack && value.stack === undefined
11
+ ? {}
12
+ : { stack: value.stack }),
13
+ ...(cause === undefined || depth <= 0
14
+ ? {}
15
+ : { cause: serializeError(cause, { ...options, depth: depth - 1 }) }),
16
+ };
17
+ }
18
+ return fallback ? fallback(value) : { message: String(value) };
19
+ }
20
+ //# sourceMappingURL=error.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"error.js","sourceRoot":"","sources":["../src/error.ts"],"names":[],"mappings":"AAOA,gEAAgE;AAChE,MAAM,CAAC,MAAM,0BAA0B,GAAG,CAAC,CAAA;AAU3C,MAAM,UAAU,cAAc,CAC5B,KAAc,EACd,OAAO,GAA0B,EAAE;IAEnC,MAAM,EACJ,KAAK,GAAG,0BAA0B,EAClC,kBAAkB,GAAG,KAAK,EAC1B,QAAQ,GACT,GAAG,OAAO,CAAA;IAEX,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;QAC3B,MAAM,KAAK,GAAI,KAA8C,CAAC,KAAK,CAAA;QACnE,OAAO;YACL,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,GAAG,CAAC,kBAAkB,IAAI,KAAK,CAAC,KAAK,KAAK,SAAS;gBACjD,CAAC,CAAC,EAAE;gBACJ,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,CAAC;YAC3B,GAAG,CAAC,KAAK,KAAK,SAAS,IAAI,KAAK,IAAI,CAAC;gBACnC,CAAC,CAAC,EAAE;gBACJ,CAAC,CAAC,EAAE,KAAK,EAAE,cAAc,CAAC,KAAK,EAAE,EAAE,GAAG,OAAO,EAAE,KAAK,EAAE,KAAK,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC;SACxE,CAAA;IACH,CAAC;IAED,OAAO,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,KAAK,CAAC,EAAE,CAAA;AAChE,CAAC"}
package/dist/index.d.ts CHANGED
@@ -1,5 +1,9 @@
1
- export * from './abortSignal.ts';
1
+ export * from './abort-signal.ts';
2
2
  export * from './constants.ts';
3
+ export * from './error.ts';
4
+ export * from './operation-queue.ts';
5
+ export * from './pool.ts';
6
+ export * from './semaphore.ts';
3
7
  export * from './streams.ts';
4
8
  export * from './types.ts';
5
9
  export * from './utils.ts';
package/dist/index.js CHANGED
@@ -1,5 +1,9 @@
1
- export * from './abortSignal.js';
1
+ export * from './abort-signal.js';
2
2
  export * from './constants.js';
3
+ export * from './error.js';
4
+ export * from './operation-queue.js';
5
+ export * from './pool.js';
6
+ export * from './semaphore.js';
3
7
  export * from './streams.js';
4
8
  export * from './types.js';
5
9
  export * from './utils.js';
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAA;AAChC,cAAc,gBAAgB,CAAA;AAC9B,cAAc,cAAc,CAAA;AAC5B,cAAc,YAAY,CAAA;AAC1B,cAAc,YAAY,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAA;AACjC,cAAc,gBAAgB,CAAA;AAC9B,cAAc,YAAY,CAAA;AAC1B,cAAc,sBAAsB,CAAA;AACpC,cAAc,WAAW,CAAA;AACzB,cAAc,gBAAgB,CAAA;AAC9B,cAAc,cAAc,CAAA;AAC5B,cAAc,YAAY,CAAA;AAC1B,cAAc,YAAY,CAAA"}
@@ -0,0 +1,26 @@
1
+ import type { MaybePromise } from './types.ts';
2
+ export type OperationQueueStrategy = 'serial' | 'latest';
3
+ export type OperationQueueOptions = {
4
+ strategy?: OperationQueueStrategy;
5
+ };
6
+ export declare class OperationSupersededError extends Error {
7
+ constructor(message?: string);
8
+ }
9
+ export declare class OperationQueue {
10
+ private readonly strategy;
11
+ private tail;
12
+ private count;
13
+ private runningLatest;
14
+ private latestOperation;
15
+ private readonly idleWaiters;
16
+ constructor({ strategy }?: OperationQueueOptions);
17
+ get pending(): number;
18
+ get busy(): boolean;
19
+ run<T>(task: () => MaybePromise<T>): Promise<T>;
20
+ waitIdle(): Promise<void>;
21
+ private runSerial;
22
+ private runLatest;
23
+ private runLatestOperations;
24
+ private runLatestOperation;
25
+ private finishOperation;
26
+ }
@@ -0,0 +1,102 @@
1
+ import { createFuture } from './utils.js';
2
+ export class OperationSupersededError extends Error {
3
+ constructor(message = 'Operation superseded') {
4
+ super(message);
5
+ this.name = 'OperationSupersededError';
6
+ }
7
+ }
8
+ export class OperationQueue {
9
+ strategy;
10
+ tail = Promise.resolve();
11
+ count = 0;
12
+ runningLatest = false;
13
+ latestOperation;
14
+ idleWaiters = new Set();
15
+ constructor({ strategy = 'serial' } = {}) {
16
+ this.strategy = strategy;
17
+ }
18
+ get pending() {
19
+ return this.count;
20
+ }
21
+ get busy() {
22
+ return this.count > 0;
23
+ }
24
+ run(task) {
25
+ return this.strategy === 'latest'
26
+ ? this.runLatest(task)
27
+ : this.runSerial(task);
28
+ }
29
+ async waitIdle() {
30
+ if (!this.busy)
31
+ return;
32
+ await new Promise((resolve) => {
33
+ this.idleWaiters.add(resolve);
34
+ });
35
+ }
36
+ runSerial(task) {
37
+ this.count++;
38
+ const result = this.tail.then(task, task);
39
+ this.tail = result
40
+ .catch(() => undefined)
41
+ .finally(() => {
42
+ this.finishOperation();
43
+ });
44
+ return result;
45
+ }
46
+ runLatest(task) {
47
+ this.count++;
48
+ const { operation, promise } = createQueuedOperation(task);
49
+ if (this.runningLatest) {
50
+ const previous = this.latestOperation;
51
+ if (previous) {
52
+ previous.reject(new OperationSupersededError());
53
+ this.finishOperation();
54
+ }
55
+ this.latestOperation = operation;
56
+ return promise;
57
+ }
58
+ this.runningLatest = true;
59
+ void this.runLatestOperations(operation);
60
+ return promise;
61
+ }
62
+ async runLatestOperations(operation) {
63
+ let current = operation;
64
+ while (current) {
65
+ await this.runLatestOperation(current);
66
+ current = this.latestOperation;
67
+ this.latestOperation = undefined;
68
+ }
69
+ this.runningLatest = false;
70
+ }
71
+ async runLatestOperation(operation) {
72
+ try {
73
+ operation.resolve(await operation.task());
74
+ }
75
+ catch (error) {
76
+ operation.reject(error);
77
+ }
78
+ finally {
79
+ this.finishOperation();
80
+ }
81
+ }
82
+ finishOperation() {
83
+ this.count--;
84
+ if (this.count > 0)
85
+ return;
86
+ for (const resolve of this.idleWaiters)
87
+ resolve();
88
+ this.idleWaiters.clear();
89
+ }
90
+ }
91
+ function createQueuedOperation(task) {
92
+ const future = createFuture();
93
+ return {
94
+ operation: {
95
+ task: task,
96
+ resolve: future.resolve,
97
+ reject: future.reject,
98
+ },
99
+ promise: future.promise,
100
+ };
101
+ }
102
+ //# sourceMappingURL=operation-queue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"operation-queue.js","sourceRoot":"","sources":["../src/operation-queue.ts"],"names":[],"mappings":"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"}
package/dist/pool.d.ts ADDED
@@ -0,0 +1,18 @@
1
+ interface PoolOptions {
2
+ timeout?: number;
3
+ }
4
+ export declare class PoolError extends Error {
5
+ }
6
+ export declare class Pool<T = unknown> {
7
+ #private;
8
+ private readonly options;
9
+ constructor(options?: PoolOptions);
10
+ add(item: T): void;
11
+ remove(item: T): void;
12
+ capture(timeout?: number | undefined): Promise<T>;
13
+ next(exclusive?: boolean, timeout?: number | undefined): Promise<T>;
14
+ release(item: T): undefined;
15
+ isFree(item: T): boolean;
16
+ get items(): T[];
17
+ }
18
+ export {};
package/dist/pool.js ADDED
@@ -0,0 +1,106 @@
1
+ export class PoolError extends Error {
2
+ }
3
+ // Ported from https://github.com/metarhia/metautil
4
+ export class Pool {
5
+ options;
6
+ #items = [];
7
+ #free = [];
8
+ #queue = [];
9
+ #current = 0;
10
+ #size = 0;
11
+ #available = 0;
12
+ constructor(options = {}) {
13
+ this.options = options;
14
+ }
15
+ add(item) {
16
+ if (this.#items.includes(item))
17
+ throw new PoolError('Item already exists');
18
+ this.#size++;
19
+ this.#available++;
20
+ this.#items.push(item);
21
+ this.#free.push(true);
22
+ }
23
+ remove(item) {
24
+ if (this.#size === 0)
25
+ throw new PoolError('Pool is empty');
26
+ const index = this.#items.indexOf(item);
27
+ if (index < 0)
28
+ throw new PoolError('Item is not in the pool');
29
+ const isCaptured = this.isFree(item);
30
+ if (isCaptured)
31
+ this.#available--;
32
+ this.#size--;
33
+ this.#current--;
34
+ this.#items.splice(index, 1);
35
+ this.#free.splice(index, 1);
36
+ }
37
+ capture(timeout = this.options.timeout) {
38
+ return this.next(true, timeout);
39
+ }
40
+ async next(exclusive = false, timeout = this.options.timeout) {
41
+ if (this.#size === 0)
42
+ throw new PoolError('Pool is empty');
43
+ if (this.#available === 0) {
44
+ return new Promise((resolve, reject) => {
45
+ const waiting = {
46
+ resolve: (item) => {
47
+ if (exclusive)
48
+ this.#capture(item);
49
+ resolve(item);
50
+ },
51
+ timer: undefined,
52
+ };
53
+ if (timeout) {
54
+ waiting.timer = setTimeout(() => {
55
+ waiting.resolve = undefined;
56
+ this.#queue.shift();
57
+ reject(new PoolError('Next item timeout'));
58
+ }, timeout);
59
+ }
60
+ this.#queue.push(waiting);
61
+ });
62
+ }
63
+ let item;
64
+ let free = false;
65
+ do {
66
+ item = this.#items[this.#current];
67
+ free = this.#free[this.#current];
68
+ this.#current++;
69
+ if (this.#current >= this.#size)
70
+ this.#current = 0;
71
+ } while (typeof item === 'undefined' || !free);
72
+ if (exclusive)
73
+ this.#capture(item);
74
+ return item;
75
+ }
76
+ release(item) {
77
+ const index = this.#items.indexOf(item);
78
+ if (index < 0)
79
+ throw new PoolError('Unexpected item');
80
+ if (this.#free[index])
81
+ throw new PoolError('Unable to release not captured item');
82
+ if (this.#queue.length > 0) {
83
+ const { resolve, timer } = this.#queue.shift();
84
+ clearTimeout(timer);
85
+ if (resolve)
86
+ return void setTimeout(resolve, 0, item);
87
+ }
88
+ this.#free[index] = true;
89
+ this.#available++;
90
+ }
91
+ isFree(item) {
92
+ const index = this.#items.indexOf(item);
93
+ if (index < 0)
94
+ return false;
95
+ return this.#free[index];
96
+ }
97
+ get items() {
98
+ return [...this.#items];
99
+ }
100
+ #capture(item) {
101
+ const index = this.#items.indexOf(item);
102
+ this.#free[index] = false;
103
+ this.#available--;
104
+ }
105
+ }
106
+ //# sourceMappingURL=pool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pool.js","sourceRoot":"","sources":["../src/pool.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ export declare class SemaphoreError extends Error {
2
+ }
3
+ export declare class Semaphore {
4
+ private readonly size;
5
+ private readonly timeout;
6
+ private counter;
7
+ private readonly queue;
8
+ constructor(concurrency: number, size?: number, timeout?: number);
9
+ enter(): Promise<void>;
10
+ leave(): void;
11
+ get isEmpty(): boolean;
12
+ get queueLength(): number;
13
+ }
@@ -0,0 +1,56 @@
1
+ export class SemaphoreError extends Error {
2
+ }
3
+ // Ported from https://github.com/metarhia/metautil
4
+ export class Semaphore {
5
+ size;
6
+ timeout;
7
+ counter;
8
+ queue = [];
9
+ constructor(concurrency, size = 0, timeout = 0) {
10
+ this.size = size;
11
+ this.timeout = timeout;
12
+ this.counter = concurrency;
13
+ }
14
+ enter() {
15
+ if (this.counter > 0) {
16
+ this.counter--;
17
+ return Promise.resolve();
18
+ }
19
+ else if (this.queue.length >= this.size) {
20
+ return Promise.reject(new SemaphoreError('Queue is full'));
21
+ }
22
+ else {
23
+ return new Promise((resolve, reject) => {
24
+ const waiting = { resolve };
25
+ waiting.timer = setTimeout(() => {
26
+ waiting.resolve = undefined;
27
+ this.queue.shift();
28
+ reject(new SemaphoreError('Timeout'));
29
+ }, this.timeout);
30
+ this.queue.push(waiting);
31
+ });
32
+ }
33
+ }
34
+ leave() {
35
+ if (this.queue.length === 0) {
36
+ this.counter++;
37
+ }
38
+ else {
39
+ const item = this.queue.shift();
40
+ if (item) {
41
+ const { resolve, timer } = item;
42
+ if (timer)
43
+ clearTimeout(timer);
44
+ if (resolve)
45
+ setTimeout(resolve, 0);
46
+ }
47
+ }
48
+ }
49
+ get isEmpty() {
50
+ return this.queue.length === 0;
51
+ }
52
+ get queueLength() {
53
+ return this.queue.length;
54
+ }
55
+ }
56
+ //# sourceMappingURL=semaphore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"semaphore.js","sourceRoot":"","sources":["../src/semaphore.ts"],"names":[],"mappings":"AAOA,MAAM,OAAO,cAAe,SAAQ,KAAK;CAAG;AAE5C,mDAAmD;AACnD,MAAM,OAAO,SAAS;IAOD,IAAI;IACJ,OAAO;IAPlB,OAAO,CAAQ;IAEN,KAAK,GAAyB,EAAE,CAAA;IAEjD,YACE,WAAmB,EACF,IAAI,GAAW,CAAC,EAChB,OAAO,GAAW,CAAC;oBADnB,IAAI;uBACJ,OAAO;QAExB,IAAI,CAAC,OAAO,GAAG,WAAW,CAAA;IAC5B,CAAC;IAED,KAAK;QACH,IAAI,IAAI,CAAC,OAAO,GAAG,CAAC,EAAE,CAAC;YACrB,IAAI,CAAC,OAAO,EAAE,CAAA;YACd,OAAO,OAAO,CAAC,OAAO,EAAE,CAAA;QAC1B,CAAC;aAAM,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;YAC1C,OAAO,OAAO,CAAC,MAAM,CAAC,IAAI,cAAc,CAAC,eAAe,CAAC,CAAC,CAAA;QAC5D,CAAC;aAAM,CAAC;YACN,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;gBACrC,MAAM,OAAO,GAAuB,EAAE,OAAO,EAAE,CAAA;gBAC/C,OAAO,CAAC,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE;oBAC9B,OAAO,CAAC,OAAO,GAAG,SAAS,CAAA;oBAC3B,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAA;oBAClB,MAAM,CAAC,IAAI,cAAc,CAAC,SAAS,CAAC,CAAC,CAAA;gBACvC,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,CAAA;gBAChB,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;YAC1B,CAAC,CAAC,CAAA;QACJ,CAAC;IACH,CAAC;IAED,KAAK;QACH,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC5B,IAAI,CAAC,OAAO,EAAE,CAAA;QAChB,CAAC;aAAM,CAAC;YACN,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAA;YAC/B,IAAI,IAAI,EAAE,CAAC;gBACT,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,IAAI,CAAA;gBAC/B,IAAI,KAAK;oBAAE,YAAY,CAAC,KAAK,CAAC,CAAA;gBAC9B,IAAI,OAAO;oBAAE,UAAU,CAAC,OAAO,EAAE,CAAC,CAAC,CAAA;YACrC,CAAC;QACH,CAAC;IACH,CAAC;IAED,IAAI,OAAO;QACT,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,CAAA;IAChC,CAAC;IAED,IAAI,WAAW;QACb,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,CAAA;IAC1B,CAAC;CACF"}
package/dist/streams.d.ts CHANGED
@@ -1,15 +1,15 @@
1
1
  import type { MaybePromise } from './types.ts';
2
2
  export interface DuplexStreamOptions<O = unknown, I = O> {
3
- start?: (controller: ReadableStreamDefaultController<O>) => void;
4
- pull?: (controller: ReadableStreamDefaultController<O>) => MaybePromise<void>;
3
+ start?: (controller: globalThis.ReadableStreamDefaultController<O>) => void;
4
+ pull?: (controller: globalThis.ReadableStreamDefaultController<O>) => MaybePromise<void>;
5
5
  cancel?: (reason: unknown) => void;
6
6
  transform?: (chunk: I) => O;
7
7
  close?: () => void;
8
- readableStrategy?: QueuingStrategy<O>;
9
- writableStrategy?: QueuingStrategy<I>;
8
+ readableStrategy?: globalThis.QueuingStrategy<O>;
9
+ writableStrategy?: globalThis.QueuingStrategy<I>;
10
10
  }
11
11
  export declare class DuplexStream<O = unknown, I = O> {
12
- readonly readable: ReadableStream<O>;
13
- readonly writable: WritableStream<I>;
12
+ readonly readable: globalThis.ReadableStream<O>;
13
+ readonly writable: globalThis.WritableStream<I>;
14
14
  constructor(options?: DuplexStreamOptions<O, I>);
15
15
  }
package/dist/streams.js CHANGED
@@ -3,11 +3,11 @@ export class DuplexStream {
3
3
  readable;
4
4
  writable;
5
5
  constructor(options = {}) {
6
- this.readable = new ReadableStream({
6
+ this.readable = new globalThis.ReadableStream({
7
7
  cancel: options.cancel,
8
8
  start: (controller) => {
9
9
  // @ts-expect-error
10
- this.writable = new WritableStream({
10
+ this.writable = new globalThis.WritableStream({
11
11
  write: (_chunk) => {
12
12
  const chunk = options?.transform
13
13
  ? options?.transform(_chunk)
@@ -1 +1 @@
1
- {"version":3,"file":"streams.js","sourceRoot":"","sources":["../src/streams.ts"],"names":[],"mappings":"AAAA,0DAA0D;AAc1D,MAAM,OAAO,YAAY;IACd,QAAQ,CAAmB;IAC3B,QAAQ,CAAoB;IAErC,YAAY,OAAO,GAA8B,EAAE;QACjD,IAAI,CAAC,QAAQ,GAAG,IAAI,cAAc,CAChC;YACE,MAAM,EAAE,OAAO,CAAC,MAAM;YACtB,KAAK,EAAE,CAAC,UAAU,EAAE,EAAE;gBACpB,mBAAmB;gBACnB,IAAI,CAAC,QAAQ,GAAG,IAAI,cAAc,CAChC;oBACE,KAAK,EAAE,CAAC,MAAM,EAAE,EAAE;wBAChB,MAAM,KAAK,GAAG,OAAO,EAAE,SAAS;4BAC9B,CAAC,CAAC,OAAO,EAAE,SAAS,CAAC,MAAM,CAAC;4BAC5B,CAAC,CAAC,MAAM,CAAA;wBACV,UAAU,CAAC,OAAO,CAAC,KAAU,CAAC,CAAA;oBAChC,CAAC;oBACD,KAAK,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,MAAM,CAAC;oBAC3C,KAAK,EAAE,GAAG,EAAE;wBACV,OAAO,EAAE,KAAK,EAAE,EAAE,CAAA;wBAClB,IAAI,CAAC;4BACH,UAAU,CAAC,KAAK,EAAE,CAAA;wBACpB,CAAC;wBAAC,MAAM,CAAC;4BACP,sDAAsD;wBACxD,CAAC;oBACH,CAAC;iBACF,EACD,OAAO,CAAC,gBAAgB,CACzB,CAAA;gBACD,OAAO,CAAC,KAAK,EAAE,CAAC,UAAU,CAAC,CAAA;YAC7B,CAAC;YACD,IAAI,EAAE,OAAO,EAAE,IAAI;SACpB,EACD,OAAO,CAAC,gBAAgB,CACzB,CAAA;IACH,CAAC;CACF"}
1
+ {"version":3,"file":"streams.js","sourceRoot":"","sources":["../src/streams.ts"],"names":[],"mappings":"AAAA,0DAA0D;AAgB1D,MAAM,OAAO,YAAY;IACd,QAAQ,CAA8B;IACtC,QAAQ,CAA+B;IAEhD,YAAY,OAAO,GAA8B,EAAE;QACjD,IAAI,CAAC,QAAQ,GAAG,IAAI,UAAU,CAAC,cAAc,CAC3C;YACE,MAAM,EAAE,OAAO,CAAC,MAAM;YACtB,KAAK,EAAE,CAAC,UAAU,EAAE,EAAE;gBACpB,mBAAmB;gBACnB,IAAI,CAAC,QAAQ,GAAG,IAAI,UAAU,CAAC,cAAc,CAC3C;oBACE,KAAK,EAAE,CAAC,MAAM,EAAE,EAAE;wBAChB,MAAM,KAAK,GAAG,OAAO,EAAE,SAAS;4BAC9B,CAAC,CAAC,OAAO,EAAE,SAAS,CAAC,MAAM,CAAC;4BAC5B,CAAC,CAAC,MAAM,CAAA;wBACV,UAAU,CAAC,OAAO,CAAC,KAAU,CAAC,CAAA;oBAChC,CAAC;oBACD,KAAK,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,MAAM,CAAC;oBAC3C,KAAK,EAAE,GAAG,EAAE;wBACV,OAAO,EAAE,KAAK,EAAE,EAAE,CAAA;wBAClB,IAAI,CAAC;4BACH,UAAU,CAAC,KAAK,EAAE,CAAA;wBACpB,CAAC;wBAAC,MAAM,CAAC;4BACP,sDAAsD;wBACxD,CAAC;oBACH,CAAC;iBACF,EACD,OAAO,CAAC,gBAAgB,CACzB,CAAA;gBACD,OAAO,CAAC,KAAK,EAAE,CAAC,UAAU,CAAC,CAAA;YAC7B,CAAC;YACD,IAAI,EAAE,OAAO,EAAE,IAAI;SACpB,EACD,OAAO,CAAC,gBAAgB,CACzB,CAAA;IACH,CAAC;CACF"}
package/dist/types.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  declare const TSErrorSymbol: unique symbol;
2
2
  export type TSError<ErrorMessage extends string = string, TagType = never> = `TS Error: ${ErrorMessage}` & {
3
3
  [TSErrorSymbol]: true;
4
+ readonly __tag?: TagType;
4
5
  };
5
6
  export interface TypeProvider {
6
7
  readonly input: unknown;
package/dist/utils.d.ts CHANGED
@@ -11,25 +11,18 @@ export declare function range(count: number, start?: number): {
11
11
  };
12
12
  };
13
13
  };
14
- export declare function debounce(cb: Callback, delay: number): ((...args: any[]) => void) & {
15
- clear: () => any;
16
- };
17
- export interface Future<T = any> {
18
- promise: Promise<T>;
19
- resolve: (value: T) => void;
20
- reject: (error: any) => void;
21
- }
14
+ export type Future<T = any> = PromiseWithResolvers<T>;
22
15
  export declare function createFuture<T>(): Future<T>;
23
- export declare function onAbort<T extends Callback>(signal: AbortSignal, cb: T, reason?: any): () => void;
16
+ export declare function onAbort<T extends Callback>(signal: globalThis.AbortSignal, cb: T, reason?: any): () => void;
24
17
  export declare function withTimeout(value: Promise<any>, timeout: number, timeoutError: Error): Promise<any>;
25
18
  export declare function tryCaptureStackTrace(depth?: number): string | undefined;
26
19
  export declare function isGeneratorFunction(value: any): value is GeneratorFunction;
27
20
  export declare function isAsyncGeneratorFunction(value: any): value is AsyncGeneratorFunction;
28
21
  export declare function isAsyncIterable(value: any): value is AsyncIterable<unknown>;
29
22
  export declare function throwError(message: string, ErrorClass?: ErrorConstructor): never;
30
- export declare function once(target: EventTarget, event: string): Promise<void>;
31
- export declare function onceAborted(signal: AbortSignal): Promise<void>;
32
- export declare function isAbortError(error: any): boolean;
23
+ export declare function once(target: globalThis.EventTarget, event: string): Promise<void>;
24
+ export declare function onceAborted(signal: globalThis.AbortSignal): Promise<void>;
25
+ export declare function isAbortError(error: any): error is Error;
33
26
  /**
34
27
  * Very simple pattern matching function.
35
28
  */
package/dist/utils.js CHANGED
@@ -1,4 +1,3 @@
1
- /// <reference lib="dom" />
2
1
  export const noopFn = () => { };
3
2
  export function merge(...objects) {
4
3
  return Object.assign({}, ...objects);
@@ -7,7 +6,7 @@ export function unique(array) {
7
6
  return new Set(array).values();
8
7
  }
9
8
  export function defer(cb, ms = 1, ...args) {
10
- return new Promise((resolve, reject) => setTimeout(async () => {
9
+ return new Promise((resolve, reject) => globalThis.setTimeout(async () => {
11
10
  try {
12
11
  resolve(await cb(...args));
13
12
  }
@@ -33,25 +32,8 @@ export function range(count, start = 0) {
33
32
  },
34
33
  };
35
34
  }
36
- export function debounce(cb, delay) {
37
- let timer;
38
- const clear = () => timer && clearTimeout(timer);
39
- const fn = (...args) => {
40
- clear();
41
- timer = setTimeout(cb, delay, ...args);
42
- };
43
- return Object.assign(fn, { clear });
44
- }
45
- // TODO: Promise.withResolvers?
46
35
  export function createFuture() {
47
- let resolve;
48
- let reject;
49
- const promise = new Promise((res, rej) => {
50
- resolve = res;
51
- reject = rej;
52
- });
53
- // @ts-expect-error
54
- return { resolve, reject, promise };
36
+ return Promise.withResolvers();
55
37
  }
56
38
  export function onAbort(signal, cb, reason) {
57
39
  const listener = () => cb(reason ?? signal.reason);
@@ -61,11 +43,11 @@ export function onAbort(signal, cb, reason) {
61
43
  export function withTimeout(value, timeout, timeoutError) {
62
44
  return Promise.race([
63
45
  value,
64
- new Promise((_, reject) => setTimeout(reject, timeout, timeoutError)),
46
+ new Promise((_, reject) => globalThis.setTimeout(reject, timeout, timeoutError)),
65
47
  ]);
66
48
  }
67
49
  export function tryCaptureStackTrace(depth = 0) {
68
- const traceLines = new Error().stack?.split('\n');
50
+ const traceLines = new Error().stack?.split('\n').slice(depth);
69
51
  if (traceLines) {
70
52
  for (const traceLine of traceLines) {
71
53
  const trimmed = traceLine.trim();
@@ -104,7 +86,7 @@ export function isAbortError(error) {
104
86
  error.name === 'AbortError' &&
105
87
  'code' in error &&
106
88
  (error.code === 20 || error.code === 'ABORT_ERR')) ||
107
- (error instanceof Event && error.type === 'abort'));
89
+ (error instanceof globalThis.Event && error.type === 'abort'));
108
90
  }
109
91
  /**
110
92
  * Very simple pattern matching function.
package/dist/utils.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -15,12 +15,9 @@
15
15
  "LICENSE.md",
16
16
  "README.md"
17
17
  ],
18
- "version": "0.16.1",
18
+ "version": "0.17.0-beta.2",
19
19
  "repository": {
20
20
  "type": "git",
21
21
  "url": "https://github.com/neematajs/neemata"
22
- },
23
- "scripts": {
24
- "clean-build": "rm -rf ./dist"
25
22
  }
26
23
  }
@@ -1,18 +1,16 @@
1
- /// <reference lib="dom" />
2
-
3
1
  /**
4
2
  * Little helper to combine multiple AbortSignals into one,
5
3
  * with handling of null or undefined values.
6
4
  */
7
5
  export function anyAbortSignal(
8
- ...signals: (AbortSignal | undefined | null)[]
9
- ): AbortSignal {
10
- const filtered = signals.filter(Boolean) as AbortSignal[]
6
+ ...signals: (globalThis.AbortSignal | undefined | null)[]
7
+ ): globalThis.AbortSignal {
8
+ const filtered = signals.filter(Boolean) as globalThis.AbortSignal[]
11
9
  if (filtered.length === 0) {
12
10
  throw new Error('No AbortSignals provided')
13
11
  } else if (filtered.length === 1) {
14
12
  return filtered[0]
15
13
  } else {
16
- return AbortSignal.any(filtered)
14
+ return globalThis.AbortSignal.any(filtered)
17
15
  }
18
16
  }
package/src/error.ts ADDED
@@ -0,0 +1,44 @@
1
+ export type SerializedError = {
2
+ readonly name?: string
3
+ readonly message: string
4
+ readonly stack?: string
5
+ readonly cause?: SerializedError
6
+ }
7
+
8
+ // Depth-limited so a cyclic cause chain cannot recurse forever.
9
+ export const MAX_SERIALIZED_ERROR_DEPTH = 5
10
+
11
+ export type SerializeErrorOptions = {
12
+ depth?: number
13
+ // Whether to drop the `stack` key when it is undefined instead of emitting it.
14
+ omitUndefinedStack?: boolean
15
+ // Handles values that are not Error instances (callers differ: normalize vs. passthrough).
16
+ fallback?: (value: unknown) => SerializedError
17
+ }
18
+
19
+ export function serializeError(
20
+ value: unknown,
21
+ options: SerializeErrorOptions = {},
22
+ ): SerializedError {
23
+ const {
24
+ depth = MAX_SERIALIZED_ERROR_DEPTH,
25
+ omitUndefinedStack = false,
26
+ fallback,
27
+ } = options
28
+
29
+ if (value instanceof Error) {
30
+ const cause = (value as Error & { readonly cause?: unknown }).cause
31
+ return {
32
+ name: value.name,
33
+ message: value.message,
34
+ ...(omitUndefinedStack && value.stack === undefined
35
+ ? {}
36
+ : { stack: value.stack }),
37
+ ...(cause === undefined || depth <= 0
38
+ ? {}
39
+ : { cause: serializeError(cause, { ...options, depth: depth - 1 }) }),
40
+ }
41
+ }
42
+
43
+ return fallback ? fallback(value) : { message: String(value) }
44
+ }
package/src/index.ts CHANGED
@@ -1,5 +1,9 @@
1
- export * from './abortSignal.ts'
1
+ export * from './abort-signal.ts'
2
2
  export * from './constants.ts'
3
+ export * from './error.ts'
4
+ export * from './operation-queue.ts'
5
+ export * from './pool.ts'
6
+ export * from './semaphore.ts'
3
7
  export * from './streams.ts'
4
8
  export * from './types.ts'
5
9
  export * from './utils.ts'
@@ -0,0 +1,134 @@
1
+ import type { MaybePromise } from './types.ts'
2
+ import { createFuture } from './utils.ts'
3
+
4
+ export type OperationQueueStrategy = 'serial' | 'latest'
5
+
6
+ export type OperationQueueOptions = { strategy?: OperationQueueStrategy }
7
+
8
+ type QueuedOperation = {
9
+ task: () => MaybePromise<unknown>
10
+ resolve: (value: unknown) => void
11
+ reject: (error: unknown) => void
12
+ }
13
+
14
+ export class OperationSupersededError extends Error {
15
+ constructor(message = 'Operation superseded') {
16
+ super(message)
17
+ this.name = 'OperationSupersededError'
18
+ }
19
+ }
20
+
21
+ export class OperationQueue {
22
+ private readonly strategy: OperationQueueStrategy
23
+ private tail: Promise<unknown> = Promise.resolve()
24
+ private count = 0
25
+ private runningLatest = false
26
+ private latestOperation: QueuedOperation | undefined
27
+ private readonly idleWaiters = new Set<() => void>()
28
+
29
+ constructor({ strategy = 'serial' }: OperationQueueOptions = {}) {
30
+ this.strategy = strategy
31
+ }
32
+
33
+ get pending(): number {
34
+ return this.count
35
+ }
36
+
37
+ get busy(): boolean {
38
+ return this.count > 0
39
+ }
40
+
41
+ run<T>(task: () => MaybePromise<T>): Promise<T> {
42
+ return this.strategy === 'latest'
43
+ ? this.runLatest(task)
44
+ : this.runSerial(task)
45
+ }
46
+
47
+ async waitIdle(): Promise<void> {
48
+ if (!this.busy) return
49
+
50
+ await new Promise<void>((resolve) => {
51
+ this.idleWaiters.add(resolve)
52
+ })
53
+ }
54
+
55
+ private runSerial<T>(task: () => MaybePromise<T>): Promise<T> {
56
+ this.count++
57
+
58
+ const result = this.tail.then(task, task)
59
+ this.tail = result
60
+ .catch(() => undefined)
61
+ .finally(() => {
62
+ this.finishOperation()
63
+ })
64
+
65
+ return result
66
+ }
67
+
68
+ private runLatest<T>(task: () => MaybePromise<T>): Promise<T> {
69
+ this.count++
70
+
71
+ const { operation, promise } = createQueuedOperation(task)
72
+
73
+ if (this.runningLatest) {
74
+ const previous = this.latestOperation
75
+ if (previous) {
76
+ previous.reject(new OperationSupersededError())
77
+ this.finishOperation()
78
+ }
79
+ this.latestOperation = operation
80
+ return promise
81
+ }
82
+
83
+ this.runningLatest = true
84
+ void this.runLatestOperations(operation)
85
+
86
+ return promise
87
+ }
88
+
89
+ private async runLatestOperations(operation: QueuedOperation): Promise<void> {
90
+ let current: QueuedOperation | undefined = operation
91
+
92
+ while (current) {
93
+ await this.runLatestOperation(current)
94
+ current = this.latestOperation
95
+ this.latestOperation = undefined
96
+ }
97
+
98
+ this.runningLatest = false
99
+ }
100
+
101
+ private async runLatestOperation(operation: QueuedOperation): Promise<void> {
102
+ try {
103
+ operation.resolve(await operation.task())
104
+ } catch (error) {
105
+ operation.reject(error)
106
+ } finally {
107
+ this.finishOperation()
108
+ }
109
+ }
110
+
111
+ private finishOperation(): void {
112
+ this.count--
113
+ if (this.count > 0) return
114
+
115
+ for (const resolve of this.idleWaiters) resolve()
116
+ this.idleWaiters.clear()
117
+ }
118
+ }
119
+
120
+ function createQueuedOperation<T>(task: () => MaybePromise<T>): {
121
+ operation: QueuedOperation
122
+ promise: Promise<T>
123
+ } {
124
+ const future = createFuture<T>()
125
+
126
+ return {
127
+ operation: {
128
+ task: task as () => MaybePromise<unknown>,
129
+ resolve: future.resolve as (value: unknown) => void,
130
+ reject: future.reject,
131
+ },
132
+ promise: future.promise,
133
+ }
134
+ }
package/src/pool.ts ADDED
@@ -0,0 +1,111 @@
1
+ import type { Callback } from './types.ts'
2
+
3
+ interface PoolOptions {
4
+ timeout?: number
5
+ }
6
+
7
+ interface PoolQueueItem {
8
+ resolve?: Callback
9
+ timer?: ReturnType<typeof globalThis.setTimeout>
10
+ }
11
+
12
+ export class PoolError extends Error {}
13
+
14
+ // Ported from https://github.com/metarhia/metautil
15
+ export class Pool<T = unknown> {
16
+ #items: Array<T> = []
17
+ #free: Array<boolean> = []
18
+ #queue: PoolQueueItem[] = []
19
+ #current: number = 0
20
+ #size: number = 0
21
+ #available: number = 0
22
+
23
+ constructor(private readonly options: PoolOptions = {}) {}
24
+
25
+ add(item: T) {
26
+ if (this.#items.includes(item)) throw new PoolError('Item already exists')
27
+ this.#size++
28
+ this.#available++
29
+ this.#items.push(item)
30
+ this.#free.push(true)
31
+ }
32
+
33
+ remove(item: T) {
34
+ if (this.#size === 0) throw new PoolError('Pool is empty')
35
+ const index = this.#items.indexOf(item)
36
+ if (index < 0) throw new PoolError('Item is not in the pool')
37
+ const isCaptured = this.isFree(item)
38
+ if (isCaptured) this.#available--
39
+ this.#size--
40
+ this.#current--
41
+ this.#items.splice(index, 1)
42
+ this.#free.splice(index, 1)
43
+ }
44
+
45
+ capture(timeout = this.options.timeout) {
46
+ return this.next(true, timeout)
47
+ }
48
+
49
+ async next(exclusive = false, timeout = this.options.timeout): Promise<T> {
50
+ if (this.#size === 0) throw new PoolError('Pool is empty')
51
+ if (this.#available === 0) {
52
+ return new Promise((resolve, reject) => {
53
+ const waiting: PoolQueueItem = {
54
+ resolve: (item: T) => {
55
+ if (exclusive) this.#capture(item)
56
+ resolve(item)
57
+ },
58
+ timer: undefined,
59
+ }
60
+ if (timeout) {
61
+ waiting.timer = setTimeout(() => {
62
+ waiting.resolve = undefined
63
+ this.#queue.shift()
64
+ reject(new PoolError('Next item timeout'))
65
+ }, timeout)
66
+ }
67
+ this.#queue.push(waiting)
68
+ })
69
+ }
70
+ let item: T | undefined
71
+ let free = false
72
+ do {
73
+ item = this.#items[this.#current]
74
+ free = this.#free[this.#current]
75
+ this.#current++
76
+ if (this.#current >= this.#size) this.#current = 0
77
+ } while (typeof item === 'undefined' || !free)
78
+ if (exclusive) this.#capture(item)
79
+ return item
80
+ }
81
+
82
+ release(item: T) {
83
+ const index = this.#items.indexOf(item)
84
+ if (index < 0) throw new PoolError('Unexpected item')
85
+ if (this.#free[index])
86
+ throw new PoolError('Unable to release not captured item')
87
+ if (this.#queue.length > 0) {
88
+ const { resolve, timer } = this.#queue.shift()!
89
+ clearTimeout(timer)
90
+ if (resolve) return void setTimeout(resolve, 0, item)
91
+ }
92
+ this.#free[index] = true
93
+ this.#available++
94
+ }
95
+
96
+ isFree(item: T) {
97
+ const index = this.#items.indexOf(item)
98
+ if (index < 0) return false
99
+ return this.#free[index]
100
+ }
101
+
102
+ get items() {
103
+ return [...this.#items]
104
+ }
105
+
106
+ #capture(item: T) {
107
+ const index = this.#items.indexOf(item)
108
+ this.#free[index] = false
109
+ this.#available--
110
+ }
111
+ }
@@ -0,0 +1,63 @@
1
+ import type { Callback } from './types.ts'
2
+
3
+ interface SemaphoreQueueItem {
4
+ resolve?: Callback
5
+ timer?: ReturnType<typeof setTimeout>
6
+ }
7
+
8
+ export class SemaphoreError extends Error {}
9
+
10
+ // Ported from https://github.com/metarhia/metautil
11
+ export class Semaphore {
12
+ private counter: number
13
+
14
+ private readonly queue: SemaphoreQueueItem[] = []
15
+
16
+ constructor(
17
+ concurrency: number,
18
+ private readonly size: number = 0,
19
+ private readonly timeout: number = 0,
20
+ ) {
21
+ this.counter = concurrency
22
+ }
23
+
24
+ enter(): Promise<void> {
25
+ if (this.counter > 0) {
26
+ this.counter--
27
+ return Promise.resolve()
28
+ } else if (this.queue.length >= this.size) {
29
+ return Promise.reject(new SemaphoreError('Queue is full'))
30
+ } else {
31
+ return new Promise((resolve, reject) => {
32
+ const waiting: SemaphoreQueueItem = { resolve }
33
+ waiting.timer = setTimeout(() => {
34
+ waiting.resolve = undefined
35
+ this.queue.shift()
36
+ reject(new SemaphoreError('Timeout'))
37
+ }, this.timeout)
38
+ this.queue.push(waiting)
39
+ })
40
+ }
41
+ }
42
+
43
+ leave() {
44
+ if (this.queue.length === 0) {
45
+ this.counter++
46
+ } else {
47
+ const item = this.queue.shift()
48
+ if (item) {
49
+ const { resolve, timer } = item
50
+ if (timer) clearTimeout(timer)
51
+ if (resolve) setTimeout(resolve, 0)
52
+ }
53
+ }
54
+ }
55
+
56
+ get isEmpty() {
57
+ return this.queue.length === 0
58
+ }
59
+
60
+ get queueLength() {
61
+ return this.queue.length
62
+ }
63
+ }
package/src/streams.ts CHANGED
@@ -3,26 +3,28 @@
3
3
  import type { MaybePromise } from './types.ts'
4
4
 
5
5
  export interface DuplexStreamOptions<O = unknown, I = O> {
6
- start?: (controller: ReadableStreamDefaultController<O>) => void
7
- pull?: (controller: ReadableStreamDefaultController<O>) => MaybePromise<void>
6
+ start?: (controller: globalThis.ReadableStreamDefaultController<O>) => void
7
+ pull?: (
8
+ controller: globalThis.ReadableStreamDefaultController<O>,
9
+ ) => MaybePromise<void>
8
10
  cancel?: (reason: unknown) => void
9
11
  transform?: (chunk: I) => O
10
12
  close?: () => void
11
- readableStrategy?: QueuingStrategy<O>
12
- writableStrategy?: QueuingStrategy<I>
13
+ readableStrategy?: globalThis.QueuingStrategy<O>
14
+ writableStrategy?: globalThis.QueuingStrategy<I>
13
15
  }
14
16
 
15
17
  export class DuplexStream<O = unknown, I = O> {
16
- readonly readable: ReadableStream<O>
17
- readonly writable!: WritableStream<I>
18
+ readonly readable: globalThis.ReadableStream<O>
19
+ readonly writable!: globalThis.WritableStream<I>
18
20
 
19
21
  constructor(options: DuplexStreamOptions<O, I> = {}) {
20
- this.readable = new ReadableStream<O>(
22
+ this.readable = new globalThis.ReadableStream<O>(
21
23
  {
22
24
  cancel: options.cancel,
23
25
  start: (controller) => {
24
26
  // @ts-expect-error
25
- this.writable = new WritableStream<I>(
27
+ this.writable = new globalThis.WritableStream<I>(
26
28
  {
27
29
  write: (_chunk) => {
28
30
  const chunk = options?.transform
package/src/types.ts CHANGED
@@ -2,9 +2,12 @@ const TSErrorSymbol: unique symbol = Symbol('TSError')
2
2
 
3
3
  export type TSError<
4
4
  ErrorMessage extends string = string,
5
- // biome-ignore lint/correctness/noUnusedVariables: this is used to tag the type
5
+ // Used to tag the type.
6
6
  TagType = never,
7
- > = `TS Error: ${ErrorMessage}` & { [TSErrorSymbol]: true }
7
+ > = `TS Error: ${ErrorMessage}` & {
8
+ [TSErrorSymbol]: true
9
+ readonly __tag?: TagType
10
+ }
8
11
 
9
12
  export interface TypeProvider {
10
13
  readonly input: unknown
@@ -16,12 +19,8 @@ export type CallTypeProvider<T extends TypeProvider, V> = (T & {
16
19
  })['output']
17
20
 
18
21
  export type ClassConstructor<T = any, A extends any[] = any[]> =
19
- | (abstract new (
20
- ...args: A
21
- ) => T)
22
- | (new (
23
- ...args: A
24
- ) => T)
22
+ | (abstract new (...args: A) => T)
23
+ | (new (...args: A) => T)
25
24
 
26
25
  export type ClassInstance<T> = T extends ClassConstructor<infer U> ? U : never
27
26
  export type ClassConstructorArgs<T, A = never> =
@@ -40,9 +39,7 @@ export type ArrayMap<T extends readonly any[], K extends keyof T[number]> = {
40
39
  }
41
40
 
42
41
  export type UnionToIntersection<U> = (
43
- U extends any
44
- ? (k: U) => void
45
- : never
42
+ U extends any ? (k: U) => void : never
46
43
  ) extends (k: infer I) => void
47
44
  ? I
48
45
  : never
package/src/utils.ts CHANGED
@@ -1,5 +1,3 @@
1
- /// <reference lib="dom" />
2
-
3
1
  import type { Callback, Pattern } from './types.ts'
4
2
 
5
3
  export const noopFn = () => {}
@@ -18,7 +16,7 @@ export function defer<T extends Callback>(
18
16
  ...args: Parameters<T>
19
17
  ): Promise<Awaited<ReturnType<T>>> {
20
18
  return new Promise((resolve, reject) =>
21
- setTimeout(async () => {
19
+ globalThis.setTimeout(async () => {
22
20
  try {
23
21
  resolve(await cb(...args))
24
22
  } catch (error) {
@@ -45,36 +43,14 @@ export function range(count: number, start = 0) {
45
43
  }
46
44
  }
47
45
 
48
- export function debounce(cb: Callback, delay: number) {
49
- let timer: any
50
- const clear = () => timer && clearTimeout(timer)
51
- const fn = (...args: any[]) => {
52
- clear()
53
- timer = setTimeout(cb, delay, ...args)
54
- }
55
- return Object.assign(fn, { clear })
56
- }
46
+ export type Future<T = any> = PromiseWithResolvers<T>
57
47
 
58
- // TODO: Promise.withResolvers?
59
- export interface Future<T = any> {
60
- promise: Promise<T>
61
- resolve: (value: T) => void
62
- reject: (error: any) => void
63
- }
64
- // TODO: Promise.withResolvers?
65
48
  export function createFuture<T>(): Future<T> {
66
- let resolve: Future<T>['resolve']
67
- let reject: Future<T>['reject']
68
- const promise = new Promise<T>((res, rej) => {
69
- resolve = res
70
- reject = rej
71
- })
72
- // @ts-expect-error
73
- return { resolve, reject, promise }
49
+ return Promise.withResolvers<T>()
74
50
  }
75
51
 
76
52
  export function onAbort<T extends Callback>(
77
- signal: AbortSignal,
53
+ signal: globalThis.AbortSignal,
78
54
  cb: T,
79
55
  reason?: any,
80
56
  ) {
@@ -90,12 +66,14 @@ export function withTimeout(
90
66
  ) {
91
67
  return Promise.race([
92
68
  value,
93
- new Promise((_, reject) => setTimeout(reject, timeout, timeoutError)),
69
+ new Promise((_, reject) =>
70
+ globalThis.setTimeout(reject, timeout, timeoutError),
71
+ ),
94
72
  ])
95
73
  }
96
74
 
97
75
  export function tryCaptureStackTrace(depth = 0) {
98
- const traceLines = new Error().stack?.split('\n')
76
+ const traceLines = new Error().stack?.split('\n').slice(depth)
99
77
  if (traceLines) {
100
78
  for (const traceLine of traceLines) {
101
79
  const trimmed = traceLine.trim()
@@ -132,23 +110,23 @@ export function throwError(message: string, ErrorClass = Error): never {
132
110
  throw new ErrorClass(message)
133
111
  }
134
112
 
135
- export function once(target: EventTarget, event: string) {
113
+ export function once(target: globalThis.EventTarget, event: string) {
136
114
  return new Promise<void>((resolve) => {
137
115
  target.addEventListener(event, () => resolve(), { once: true })
138
116
  })
139
117
  }
140
118
 
141
- export function onceAborted(signal: AbortSignal) {
119
+ export function onceAborted(signal: globalThis.AbortSignal) {
142
120
  return once(signal, 'abort')
143
121
  }
144
122
 
145
- export function isAbortError(error) {
123
+ export function isAbortError(error: any): error is Error {
146
124
  return (
147
125
  (error instanceof Error &&
148
126
  error.name === 'AbortError' &&
149
127
  'code' in error &&
150
128
  (error.code === 20 || error.code === 'ABORT_ERR')) ||
151
- (error instanceof Event && error.type === 'abort')
129
+ (error instanceof globalThis.Event && error.type === 'abort')
152
130
  )
153
131
  }
154
132
 
@@ -1,5 +0,0 @@
1
- /**
2
- * Little helper to combine multiple AbortSignals into one,
3
- * with handling of null or undefined values.
4
- */
5
- export declare function anyAbortSignal(...signals: (AbortSignal | undefined | null)[]): AbortSignal;
@@ -1 +0,0 @@
1
- {"version":3,"file":"abortSignal.js","sourceRoot":"","sources":["../src/abortSignal.ts"],"names":[],"mappings":"AAAA,2BAA2B;AAE3B;;;GAGG;AACH,MAAM,UAAU,cAAc,CAC5B,GAAG,OAA2C;IAE9C,MAAM,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,OAAO,CAAkB,CAAA;IACzD,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1B,MAAM,IAAI,KAAK,CAAC,0BAA0B,CAAC,CAAA;IAC7C,CAAC;SAAM,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACjC,OAAO,QAAQ,CAAC,CAAC,CAAC,CAAA;IACpB,CAAC;SAAM,CAAC;QACN,OAAO,WAAW,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;IAClC,CAAC;AACH,CAAC"}