bytekit 2.2.0 → 2.4.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.
Files changed (97) hide show
  1. package/dist/cli/ddd-boilerplate.d.ts.map +1 -1
  2. package/dist/cli/ddd-boilerplate.js +4 -1
  3. package/dist/cli/ddd-boilerplate.js.map +1 -1
  4. package/dist/cli/index.d.ts.map +1 -1
  5. package/dist/cli/index.js +11 -5
  6. package/dist/cli/index.js.map +1 -1
  7. package/dist/cli/swagger-generator.d.ts.map +1 -1
  8. package/dist/cli/swagger-generator.js +9 -0
  9. package/dist/cli/swagger-generator.js.map +1 -1
  10. package/dist/cli/type-generator.d.ts.map +1 -1
  11. package/dist/cli/type-generator.js +5 -0
  12. package/dist/cli/type-generator.js.map +1 -1
  13. package/dist/utils/async/index.d.ts +8 -0
  14. package/dist/utils/async/index.d.ts.map +1 -1
  15. package/dist/utils/async/index.js +4 -0
  16. package/dist/utils/async/index.js.map +1 -1
  17. package/dist/utils/async/pipeline.d.ts +164 -0
  18. package/dist/utils/async/pipeline.d.ts.map +1 -0
  19. package/dist/utils/async/pipeline.js +154 -0
  20. package/dist/utils/async/pipeline.js.map +1 -0
  21. package/dist/utils/async/promise-pool.d.ts +59 -0
  22. package/dist/utils/async/promise-pool.d.ts.map +1 -0
  23. package/dist/utils/async/promise-pool.js +130 -0
  24. package/dist/utils/async/promise-pool.js.map +1 -0
  25. package/dist/utils/async/request-batcher.d.ts +82 -0
  26. package/dist/utils/async/request-batcher.d.ts.map +1 -0
  27. package/dist/utils/async/request-batcher.js +179 -0
  28. package/dist/utils/async/request-batcher.js.map +1 -0
  29. package/dist/utils/async/request-queue.d.ts +115 -0
  30. package/dist/utils/async/request-queue.d.ts.map +1 -0
  31. package/dist/utils/async/request-queue.js +236 -0
  32. package/dist/utils/async/request-queue.js.map +1 -0
  33. package/dist/utils/async/throttle.d.ts.map +1 -1
  34. package/dist/utils/async/throttle.js +1 -0
  35. package/dist/utils/async/throttle.js.map +1 -1
  36. package/dist/utils/core/ApiClient.d.ts +22 -1
  37. package/dist/utils/core/ApiClient.d.ts.map +1 -1
  38. package/dist/utils/core/ApiClient.js +64 -4
  39. package/dist/utils/core/ApiClient.js.map +1 -1
  40. package/dist/utils/core/ErrorBoundary.d.ts.map +1 -1
  41. package/dist/utils/core/ErrorBoundary.js +18 -5
  42. package/dist/utils/core/ErrorBoundary.js.map +1 -1
  43. package/dist/utils/core/Logger.d.ts +191 -0
  44. package/dist/utils/core/Logger.d.ts.map +1 -1
  45. package/dist/utils/core/Logger.js +155 -0
  46. package/dist/utils/core/Logger.js.map +1 -1
  47. package/dist/utils/core/Profiler.d.ts +41 -0
  48. package/dist/utils/core/Profiler.d.ts.map +1 -1
  49. package/dist/utils/core/Profiler.js +59 -0
  50. package/dist/utils/core/Profiler.js.map +1 -1
  51. package/dist/utils/core/RateLimiter.d.ts.map +1 -1
  52. package/dist/utils/core/RateLimiter.js +2 -0
  53. package/dist/utils/core/RateLimiter.js.map +1 -1
  54. package/dist/utils/core/ResponseValidator.d.ts +56 -0
  55. package/dist/utils/core/ResponseValidator.d.ts.map +1 -1
  56. package/dist/utils/core/ResponseValidator.js +28 -0
  57. package/dist/utils/core/ResponseValidator.js.map +1 -1
  58. package/dist/utils/core/RetryPolicy.d.ts +144 -0
  59. package/dist/utils/core/RetryPolicy.d.ts.map +1 -1
  60. package/dist/utils/core/RetryPolicy.js +108 -0
  61. package/dist/utils/core/RetryPolicy.js.map +1 -1
  62. package/dist/utils/helpers/CacheManager.d.ts.map +1 -1
  63. package/dist/utils/helpers/CacheManager.js +5 -0
  64. package/dist/utils/helpers/CacheManager.js.map +1 -1
  65. package/dist/utils/helpers/CompressionUtils.d.ts.map +1 -1
  66. package/dist/utils/helpers/CompressionUtils.js +21 -4
  67. package/dist/utils/helpers/CompressionUtils.js.map +1 -1
  68. package/dist/utils/helpers/CryptoUtils.d.ts.map +1 -1
  69. package/dist/utils/helpers/CryptoUtils.js +15 -3
  70. package/dist/utils/helpers/CryptoUtils.js.map +1 -1
  71. package/dist/utils/helpers/EnvManager.d.ts +46 -0
  72. package/dist/utils/helpers/EnvManager.d.ts.map +1 -1
  73. package/dist/utils/helpers/EnvManager.js +46 -0
  74. package/dist/utils/helpers/EnvManager.js.map +1 -1
  75. package/dist/utils/helpers/EventEmitter.d.ts.map +1 -1
  76. package/dist/utils/helpers/EventEmitter.js +0 -3
  77. package/dist/utils/helpers/EventEmitter.js.map +1 -1
  78. package/dist/utils/helpers/FileUploadHelper.d.ts +68 -1
  79. package/dist/utils/helpers/FileUploadHelper.d.ts.map +1 -1
  80. package/dist/utils/helpers/FileUploadHelper.js +72 -19
  81. package/dist/utils/helpers/FileUploadHelper.js.map +1 -1
  82. package/dist/utils/helpers/StorageUtils.d.ts +62 -0
  83. package/dist/utils/helpers/StorageUtils.d.ts.map +1 -1
  84. package/dist/utils/helpers/StorageUtils.js +62 -0
  85. package/dist/utils/helpers/StorageUtils.js.map +1 -1
  86. package/dist/utils/helpers/StreamingHelper.d.ts.map +1 -1
  87. package/dist/utils/helpers/StreamingHelper.js +16 -6
  88. package/dist/utils/helpers/StreamingHelper.js.map +1 -1
  89. package/dist/utils/helpers/UrlHelper.d.ts +30 -0
  90. package/dist/utils/helpers/UrlHelper.d.ts.map +1 -1
  91. package/dist/utils/helpers/UrlHelper.js +23 -1
  92. package/dist/utils/helpers/UrlHelper.js.map +1 -1
  93. package/dist/utils/helpers/WebSocketHelper.d.ts +30 -0
  94. package/dist/utils/helpers/WebSocketHelper.d.ts.map +1 -1
  95. package/dist/utils/helpers/WebSocketHelper.js +117 -5
  96. package/dist/utils/helpers/WebSocketHelper.js.map +1 -1
  97. package/package.json +5 -1
@@ -0,0 +1,154 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+ // ── Pipeline class ────────────────────────────────────────────────────────────
3
+ /**
4
+ * An immutable, lazy pipeline that accumulates transformation operators and
5
+ * executes them sequentially when {@link Pipeline.process} is called.
6
+ *
7
+ * Build pipelines with the {@link pipe} factory function or by calling
8
+ * `.pipe(op)` on an existing instance. Each `.pipe()` call returns a **new**
9
+ * `Pipeline` — the original is never mutated.
10
+ *
11
+ * @template TIn - Type of the data accepted by {@link Pipeline.process}.
12
+ * @template TOut - Type of the value resolved by {@link Pipeline.process}.
13
+ *
14
+ * @example
15
+ * const pipeline = pipe(
16
+ * filter<number>((n) => n > 0),
17
+ * map<number, string>((n) => String(n)),
18
+ * );
19
+ * const result = await pipeline.process([1, -2, 3]); // ["1", "3"]
20
+ */
21
+ export class Pipeline {
22
+ /**
23
+ * @internal — Use {@link pipe} to create pipelines.
24
+ */
25
+ constructor(ops) {
26
+ /** @internal */
27
+ Object.defineProperty(this, "ops", {
28
+ enumerable: true,
29
+ configurable: true,
30
+ writable: true,
31
+ value: void 0
32
+ });
33
+ this.ops = ops;
34
+ }
35
+ /**
36
+ * Appends an operator and returns a **new** `Pipeline` instance.
37
+ * The original pipeline is not mutated.
38
+ *
39
+ * @param op - The operator to append.
40
+ * @returns A new `Pipeline<TIn, TNext>` with the operator appended.
41
+ *
42
+ * @example
43
+ * const base = pipe(filter<number>((n) => n > 0));
44
+ * const doubled = base.pipe(map<number, number>((n) => n * 2));
45
+ * // base is unchanged
46
+ */
47
+ pipe(op) {
48
+ return new Pipeline([...this.ops, op]);
49
+ }
50
+ /**
51
+ * Executes all accumulated operators sequentially, passing the output of
52
+ * each as the input to the next. Always returns a `Promise`.
53
+ *
54
+ * @param data - The initial input value.
55
+ * @returns A `Promise` that resolves to the final transformed value.
56
+ * @throws The error thrown by the first operator that rejects.
57
+ *
58
+ * @example
59
+ * const result = await pipeline.process([1, 2, 3]);
60
+ */
61
+ async process(data) {
62
+ let result = data;
63
+ for (const op of this.ops) {
64
+ result = await op(result);
65
+ }
66
+ return result;
67
+ }
68
+ }
69
+ // ── Implementation ────────────────────────────────────────────────────────────
70
+ export function pipe(...ops) {
71
+ return new Pipeline(ops);
72
+ }
73
+ // ── Operator factories ────────────────────────────────────────────────────────
74
+ /**
75
+ * Creates a pipeline operator that transforms each element of an array.
76
+ * Async mapper functions are awaited **concurrently** via `Promise.all`,
77
+ * so all items are processed in parallel. Order is preserved.
78
+ *
79
+ * @param fn - A mapping function that receives `(item, index)` and returns the
80
+ * transformed value synchronously or as a `Promise`.
81
+ * @returns A `PipelineOp<T[], U[]>`.
82
+ *
83
+ * @example
84
+ * const double = map<number, number>((n) => n * 2);
85
+ * const result = await pipe(double).process([1, 2, 3]); // [2, 4, 6]
86
+ *
87
+ * @example
88
+ * // Async map — all fetch calls run concurrently
89
+ * const enrich = map<string, { id: string; name: string }>(async (id) => {
90
+ * const res = await fetch(`/api/users/${id}`);
91
+ * return res.json();
92
+ * });
93
+ */
94
+ export function map(fn) {
95
+ return (items) => Promise.all(items.map((item, index) => fn(item, index)));
96
+ }
97
+ /**
98
+ * Creates a pipeline operator that retains only the elements for which the
99
+ * predicate returns `true` (or resolves to `true`).
100
+ * Predicate calls run **concurrently** via `Promise.all`; the original order
101
+ * of retained elements is preserved.
102
+ *
103
+ * @param fn - A predicate function that receives `(item, index)` and returns a
104
+ * `boolean` or `Promise<boolean>`.
105
+ * @returns A `PipelineOp<T[], T[]>`.
106
+ *
107
+ * @example
108
+ * const positives = filter<number>((n) => n > 0);
109
+ * const result = await pipe(positives).process([1, -2, 3]); // [1, 3]
110
+ *
111
+ * @example
112
+ * // Async filter
113
+ * const active = filter<string>(async (id) => {
114
+ * const res = await fetch(`/api/items/${id}/active`);
115
+ * return res.ok;
116
+ * });
117
+ */
118
+ export function filter(fn) {
119
+ return async (items) => {
120
+ const results = await Promise.all(items.map((item, index) => fn(item, index)));
121
+ return items.filter((_, index) => results[index]);
122
+ };
123
+ }
124
+ /**
125
+ * Creates a pipeline operator that reduces an array to a single accumulated
126
+ * value. The reducer function runs **sequentially** — each step awaits the
127
+ * previous accumulator before proceeding, ensuring deterministic results.
128
+ *
129
+ * @param fn - A reducer function that receives `(accumulator, item, index)` and
130
+ * returns the next accumulator value synchronously or as a `Promise`.
131
+ * @param initial - The initial accumulator value.
132
+ * @returns A `PipelineOp<T[], U>`.
133
+ *
134
+ * @example
135
+ * const sum = reduce<number, number>((acc, n) => acc + n, 0);
136
+ * const result = await pipe(sum).process([1, 2, 3]); // 6
137
+ *
138
+ * @example
139
+ * // Async sequential reduce
140
+ * const writeAll = reduce<string, string[]>(async (acc, id) => {
141
+ * await db.delete(id);
142
+ * return [...acc, id];
143
+ * }, []);
144
+ */
145
+ export function reduce(fn, initial) {
146
+ return async (items) => {
147
+ let acc = initial;
148
+ for (let i = 0; i < items.length; i++) {
149
+ acc = await fn(acc, items[i], i);
150
+ }
151
+ return acc;
152
+ };
153
+ }
154
+ //# sourceMappingURL=pipeline.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pipeline.js","sourceRoot":"","sources":["../../../src/utils/async/pipeline.ts"],"names":[],"mappings":"AAAA,uDAAuD;AAevD,iFAAiF;AAEjF;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,OAAO,QAAQ;IAIjB;;OAEG;IACH,YAAY,GAA2B;QANvC,gBAAgB;QACC;;;;;WAA4B;QAMzC,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;IACnB,CAAC;IAED;;;;;;;;;;;OAWG;IACH,IAAI,CAAQ,EAA2B;QACnC,OAAO,IAAI,QAAQ,CAAa,CAAC,GAAG,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC;IACvD,CAAC;IAED;;;;;;;;;;OAUG;IACH,KAAK,CAAC,OAAO,CAAC,IAAS;QACnB,IAAI,MAAM,GAAQ,IAAI,CAAC;QACvB,KAAK,MAAM,EAAE,IAAI,IAAI,CAAC,GAAG,EAAE,CAAC;YACxB,MAAM,GAAG,MAAM,EAAE,CAAC,MAAM,CAAC,CAAC;QAC9B,CAAC;QACD,OAAO,MAAc,CAAC;IAC1B,CAAC;CACJ;AAkFD,iFAAiF;AACjF,MAAM,UAAU,IAAI,CAAI,GAAG,GAA2B;IAClD,OAAO,IAAI,QAAQ,CAAS,GAAG,CAAC,CAAC;AACrC,CAAC;AAED,iFAAiF;AAEjF;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,UAAU,GAAG,CACf,EAA8C;IAE9C,OAAO,CAAC,KAAU,EAAgB,EAAE,CAChC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,EAAE,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC;AACjE,CAAC;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,UAAU,MAAM,CAClB,EAA0D;IAE1D,OAAO,KAAK,EAAE,KAAU,EAAgB,EAAE;QACtC,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,CAC7B,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,EAAE,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAC9C,CAAC;QACF,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC;IACtD,CAAC,CAAC;AACN,CAAC;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,UAAU,MAAM,CAClB,EAAsD,EACtD,OAAU;IAEV,OAAO,KAAK,EAAE,KAAU,EAAc,EAAE;QACpC,IAAI,GAAG,GAAG,OAAO,CAAC;QAClB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACpC,GAAG,GAAG,MAAM,EAAE,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QACrC,CAAC;QACD,OAAO,GAAG,CAAC;IACf,CAAC,CAAC;AACN,CAAC"}
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Options for PromisePool configuration
3
+ */
4
+ export interface PromisePoolOptions {
5
+ /** Maximum number of tasks that can run concurrently. Minimum: 1. */
6
+ concurrency: number;
7
+ /** Optional timeout in milliseconds per individual task. Must be > 0. */
8
+ timeout?: number;
9
+ /**
10
+ * Optional callback invoked when a task fails.
11
+ * Does NOT stop the pool — remaining tasks continue executing.
12
+ * @param error The error thrown by the failing task.
13
+ * @param taskIndex Zero-based index of the failing task in the original array.
14
+ */
15
+ onError?: (error: Error, taskIndex: number) => void;
16
+ }
17
+ /**
18
+ * Error thrown when a task exceeds the configured per-task timeout.
19
+ */
20
+ export declare class PoolTimeoutError extends Error {
21
+ constructor(timeoutMs: number);
22
+ }
23
+ /**
24
+ * Executes an array of async tasks with a configurable concurrency limit.
25
+ *
26
+ * Unlike `parallel()`, PromisePool:
27
+ * - Is stateful and reusable across multiple `run()` calls.
28
+ * - Does NOT fail fast: individual task errors are isolated via `onError`.
29
+ * - Supports per-task timeouts.
30
+ *
31
+ * @example
32
+ * ```typescript
33
+ * const pool = new PromisePool({ concurrency: 3, timeout: 5000 });
34
+ * const results = await pool.run([
35
+ * () => fetch("/api/1").then(r => r.json()),
36
+ * () => fetch("/api/2").then(r => r.json()),
37
+ * ]);
38
+ * ```
39
+ */
40
+ export declare class PromisePool {
41
+ private readonly options;
42
+ private running;
43
+ private queue;
44
+ constructor(options: PromisePoolOptions);
45
+ /**
46
+ * Runs an array of task factory functions with concurrency control.
47
+ * Tasks are lazy — they are not started until the pool has a free slot.
48
+ *
49
+ * @param tasks Array of functions that return Promises.
50
+ * @returns Promise resolving to an array of results in original order.
51
+ * @throws TypeError If `tasks` is not an array or any element is not a function.
52
+ */
53
+ run<T>(tasks: Array<() => Promise<T>>): Promise<T[]>;
54
+ private addTask;
55
+ private processQueue;
56
+ private executeTask;
57
+ private withTimeout;
58
+ }
59
+ //# sourceMappingURL=promise-pool.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"promise-pool.d.ts","sourceRoot":"","sources":["../../../src/utils/async/promise-pool.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,kBAAkB;IAC/B,qEAAqE;IACrE,WAAW,EAAE,MAAM,CAAC;IACpB,yEAAyE;IACzE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;;OAKG;IACH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;CACvD;AAED;;GAEG;AACH,qBAAa,gBAAiB,SAAQ,KAAK;gBAC3B,SAAS,EAAE,MAAM;CAIhC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,WAAW;IACpB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAqB;IAC7C,OAAO,CAAC,OAAO,CAAK;IACpB,OAAO,CAAC,KAAK,CAKL;gBAEI,OAAO,EAAE,kBAAkB;IAUvC;;;;;;;OAOG;IACG,GAAG,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,MAAM,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC;IAoB1D,OAAO,CAAC,OAAO;IAgBf,OAAO,CAAC,YAAY;YAWN,WAAW;IA2BzB,OAAO,CAAC,WAAW;CAYtB"}
@@ -0,0 +1,130 @@
1
+ /**
2
+ * Error thrown when a task exceeds the configured per-task timeout.
3
+ */
4
+ export class PoolTimeoutError extends Error {
5
+ constructor(timeoutMs) {
6
+ super(`Task timed out after ${timeoutMs}ms`);
7
+ this.name = "PoolTimeoutError";
8
+ }
9
+ }
10
+ /**
11
+ * Executes an array of async tasks with a configurable concurrency limit.
12
+ *
13
+ * Unlike `parallel()`, PromisePool:
14
+ * - Is stateful and reusable across multiple `run()` calls.
15
+ * - Does NOT fail fast: individual task errors are isolated via `onError`.
16
+ * - Supports per-task timeouts.
17
+ *
18
+ * @example
19
+ * ```typescript
20
+ * const pool = new PromisePool({ concurrency: 3, timeout: 5000 });
21
+ * const results = await pool.run([
22
+ * () => fetch("/api/1").then(r => r.json()),
23
+ * () => fetch("/api/2").then(r => r.json()),
24
+ * ]);
25
+ * ```
26
+ */
27
+ export class PromisePool {
28
+ constructor(options) {
29
+ Object.defineProperty(this, "options", {
30
+ enumerable: true,
31
+ configurable: true,
32
+ writable: true,
33
+ value: void 0
34
+ });
35
+ Object.defineProperty(this, "running", {
36
+ enumerable: true,
37
+ configurable: true,
38
+ writable: true,
39
+ value: 0
40
+ });
41
+ Object.defineProperty(this, "queue", {
42
+ enumerable: true,
43
+ configurable: true,
44
+ writable: true,
45
+ value: []
46
+ });
47
+ if (options.concurrency < 1) {
48
+ throw new TypeError("concurrency must be at least 1");
49
+ }
50
+ if (options.timeout !== undefined && options.timeout <= 0) {
51
+ throw new TypeError("timeout must be a positive number");
52
+ }
53
+ this.options = { ...options };
54
+ }
55
+ /**
56
+ * Runs an array of task factory functions with concurrency control.
57
+ * Tasks are lazy — they are not started until the pool has a free slot.
58
+ *
59
+ * @param tasks Array of functions that return Promises.
60
+ * @returns Promise resolving to an array of results in original order.
61
+ * @throws TypeError If `tasks` is not an array or any element is not a function.
62
+ */
63
+ async run(tasks) {
64
+ if (!Array.isArray(tasks)) {
65
+ throw new TypeError("tasks must be an array");
66
+ }
67
+ if (tasks.length === 0) {
68
+ return [];
69
+ }
70
+ for (let i = 0; i < tasks.length; i++) {
71
+ if (typeof tasks[i] !== "function") {
72
+ throw new TypeError(`Task at index ${i} is not a function`);
73
+ }
74
+ }
75
+ const results = new Array(tasks.length);
76
+ await Promise.all(tasks.map((task, index) => this.addTask(task, index, results)));
77
+ return results;
78
+ }
79
+ addTask(task, index, results) {
80
+ return new Promise((resolve, reject) => {
81
+ this.queue.push({
82
+ task: task,
83
+ resolve: resolve,
84
+ reject,
85
+ index,
86
+ });
87
+ this.processQueue(results);
88
+ });
89
+ }
90
+ processQueue(results) {
91
+ while (this.running < this.options.concurrency &&
92
+ this.queue.length > 0) {
93
+ const item = this.queue.shift();
94
+ this.running++;
95
+ this.executeTask(item, results);
96
+ }
97
+ }
98
+ async executeTask(item, results) {
99
+ try {
100
+ const promise = item.task();
101
+ const result = this.options.timeout
102
+ ? await this.withTimeout(promise, this.options.timeout)
103
+ : await promise;
104
+ results[item.index] = result;
105
+ item.resolve(result);
106
+ }
107
+ catch (error) {
108
+ if (this.options.onError) {
109
+ this.options.onError(error, item.index);
110
+ }
111
+ item.reject(error);
112
+ }
113
+ finally {
114
+ this.running--;
115
+ this.processQueue(results);
116
+ }
117
+ }
118
+ withTimeout(promise, timeoutMs) {
119
+ return new Promise((resolve, reject) => {
120
+ const timer = setTimeout(() => {
121
+ reject(new PoolTimeoutError(timeoutMs));
122
+ }, timeoutMs);
123
+ promise
124
+ .then(resolve)
125
+ .catch(reject)
126
+ .finally(() => clearTimeout(timer));
127
+ });
128
+ }
129
+ }
130
+ //# sourceMappingURL=promise-pool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"promise-pool.js","sourceRoot":"","sources":["../../../src/utils/async/promise-pool.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,82 @@
1
+ /**
2
+ * RequestBatcher — Time-window deduplication batcher for HTTP requests.
3
+ * Feature: 004-batching-system
4
+ * Zero external dependencies: Map, setTimeout/clearTimeout (built-in).
5
+ */
6
+ /** Constructor options for {@link RequestBatcher}. */
7
+ export interface BatchOptions {
8
+ /**
9
+ * Time window in milliseconds for collecting requests before dispatching.
10
+ * Must be greater than 0.
11
+ */
12
+ windowMs: number;
13
+ /**
14
+ * Maximum requests per batch. Flushes early when reached.
15
+ * Default: `Infinity`.
16
+ */
17
+ maxSize?: number;
18
+ /**
19
+ * If `true`, the window timer resets on each new request (sliding window).
20
+ * Default: `false` — fixed window: timer fires once after the first request.
21
+ */
22
+ sliding?: boolean;
23
+ /**
24
+ * Custom function to compute the batch deduplication key.
25
+ * Requests with the same key within a window are coalesced.
26
+ * Default: `"METHOD:url:serialized(body)"`.
27
+ */
28
+ keyFn?: (url: string, init: RequestInit) => string;
29
+ }
30
+ /**
31
+ * Coalesces same-key HTTP requests within a time window into a single fetch invocation.
32
+ * All callers sharing the same key receive the same resolved value.
33
+ *
34
+ * The deduplication key defaults to `"METHOD:url:serialized(body)"` and can be
35
+ * overridden via `BatchOptions.keyFn`.
36
+ *
37
+ * @example
38
+ * ```typescript
39
+ * const batcher = new RequestBatcher({ windowMs: 50 });
40
+ *
41
+ * // These three calls share the same key → fetcher invoked once
42
+ * const [a, b, c] = await Promise.all([
43
+ * batcher.add("/api/users", { method: "GET" }, fetch),
44
+ * batcher.add("/api/users", { method: "GET" }, fetch),
45
+ * batcher.add("/api/users", { method: "GET" }, fetch),
46
+ * ]);
47
+ * ```
48
+ */
49
+ export declare class RequestBatcher {
50
+ private readonly _windowMs;
51
+ private readonly _maxSize;
52
+ private readonly _sliding;
53
+ private readonly _keyFn;
54
+ private readonly _buckets;
55
+ private readonly _timers;
56
+ /**
57
+ * Creates a new RequestBatcher.
58
+ * @throws {TypeError} if `windowMs` is not greater than 0.
59
+ * @throws {TypeError} if `maxSize` is less than 1.
60
+ */
61
+ constructor(options: BatchOptions);
62
+ /**
63
+ * Adds a request to the current batch window.
64
+ * Requests with the same key (method + url + body) are coalesced —
65
+ * all callers receive the same resolved value when the window fires.
66
+ *
67
+ * @param url The request URL.
68
+ * @param init The RequestInit options (method, headers, body).
69
+ * @param fetcher The actual fetch function to invoke when the window fires.
70
+ * @returns `Promise<T>` resolving to the fetch result.
71
+ */
72
+ add<T>(url: string, init: RequestInit, fetcher: (url: string, init: RequestInit) => Promise<T>): Promise<T>;
73
+ private _dispatch;
74
+ /**
75
+ * Forces immediate dispatch of all pending batches.
76
+ * Resolves when all dispatched fetchers have settled.
77
+ */
78
+ flush(): Promise<void>;
79
+ /** Total pending requests across all batch buckets. */
80
+ get pendingCount(): number;
81
+ }
82
+ //# sourceMappingURL=request-batcher.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"request-batcher.d.ts","sourceRoot":"","sources":["../../../src/utils/async/request-batcher.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,sDAAsD;AACtD,MAAM,WAAW,YAAY;IACzB;;;OAGG;IACH,QAAQ,EAAE,MAAM,CAAC;IACjB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;;OAIG;IACH,KAAK,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,KAAK,MAAM,CAAC;CACtD;AAmCD;;;;;;;;;;;;;;;;;;GAkBG;AACH,qBAAa,cAAc;IACvB,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAU;IACnC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA6C;IACpE,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAmC;IAC5D,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAoD;IAE5E;;;;OAIG;gBACS,OAAO,EAAE,YAAY;IAajC;;;;;;;;;OASG;IACH,GAAG,CAAC,CAAC,EACD,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,WAAW,EACjB,OAAO,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,KAAK,OAAO,CAAC,CAAC,CAAC,GACxD,OAAO,CAAC,CAAC,CAAC;YAgCC,SAAS;IA4BvB;;;OAGG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAK5B,uDAAuD;IACvD,IAAI,YAAY,IAAI,MAAM,CAMzB;CACJ"}
@@ -0,0 +1,179 @@
1
+ /**
2
+ * RequestBatcher — Time-window deduplication batcher for HTTP requests.
3
+ * Feature: 004-batching-system
4
+ * Zero external dependencies: Map, setTimeout/clearTimeout (built-in).
5
+ */
6
+ function stableSerialize(body) {
7
+ if (body === undefined || body === null)
8
+ return "";
9
+ if (typeof body === "string" ||
10
+ typeof body === "number" ||
11
+ typeof body === "boolean") {
12
+ return String(body);
13
+ }
14
+ try {
15
+ return JSON.stringify(body);
16
+ }
17
+ catch {
18
+ return String(body);
19
+ }
20
+ }
21
+ function defaultKeyFn(url, init) {
22
+ const method = (init.method ?? "GET").toUpperCase();
23
+ const body = stableSerialize(init.body);
24
+ return `${method}:${url}:${body}`;
25
+ }
26
+ /**
27
+ * Coalesces same-key HTTP requests within a time window into a single fetch invocation.
28
+ * All callers sharing the same key receive the same resolved value.
29
+ *
30
+ * The deduplication key defaults to `"METHOD:url:serialized(body)"` and can be
31
+ * overridden via `BatchOptions.keyFn`.
32
+ *
33
+ * @example
34
+ * ```typescript
35
+ * const batcher = new RequestBatcher({ windowMs: 50 });
36
+ *
37
+ * // These three calls share the same key → fetcher invoked once
38
+ * const [a, b, c] = await Promise.all([
39
+ * batcher.add("/api/users", { method: "GET" }, fetch),
40
+ * batcher.add("/api/users", { method: "GET" }, fetch),
41
+ * batcher.add("/api/users", { method: "GET" }, fetch),
42
+ * ]);
43
+ * ```
44
+ */
45
+ export class RequestBatcher {
46
+ /**
47
+ * Creates a new RequestBatcher.
48
+ * @throws {TypeError} if `windowMs` is not greater than 0.
49
+ * @throws {TypeError} if `maxSize` is less than 1.
50
+ */
51
+ constructor(options) {
52
+ Object.defineProperty(this, "_windowMs", {
53
+ enumerable: true,
54
+ configurable: true,
55
+ writable: true,
56
+ value: void 0
57
+ });
58
+ Object.defineProperty(this, "_maxSize", {
59
+ enumerable: true,
60
+ configurable: true,
61
+ writable: true,
62
+ value: void 0
63
+ });
64
+ Object.defineProperty(this, "_sliding", {
65
+ enumerable: true,
66
+ configurable: true,
67
+ writable: true,
68
+ value: void 0
69
+ });
70
+ Object.defineProperty(this, "_keyFn", {
71
+ enumerable: true,
72
+ configurable: true,
73
+ writable: true,
74
+ value: void 0
75
+ });
76
+ Object.defineProperty(this, "_buckets", {
77
+ enumerable: true,
78
+ configurable: true,
79
+ writable: true,
80
+ value: new Map()
81
+ });
82
+ Object.defineProperty(this, "_timers", {
83
+ enumerable: true,
84
+ configurable: true,
85
+ writable: true,
86
+ value: new Map()
87
+ });
88
+ if (options.windowMs <= 0) {
89
+ throw new TypeError("windowMs must be > 0");
90
+ }
91
+ if (options.maxSize !== undefined && options.maxSize < 1) {
92
+ throw new TypeError("maxSize must be >= 1");
93
+ }
94
+ this._windowMs = options.windowMs;
95
+ this._maxSize = options.maxSize ?? Infinity;
96
+ this._sliding = options.sliding ?? false;
97
+ this._keyFn = options.keyFn ?? defaultKeyFn;
98
+ }
99
+ /**
100
+ * Adds a request to the current batch window.
101
+ * Requests with the same key (method + url + body) are coalesced —
102
+ * all callers receive the same resolved value when the window fires.
103
+ *
104
+ * @param url The request URL.
105
+ * @param init The RequestInit options (method, headers, body).
106
+ * @param fetcher The actual fetch function to invoke when the window fires.
107
+ * @returns `Promise<T>` resolving to the fetch result.
108
+ */
109
+ add(url, init, fetcher) {
110
+ const key = this._keyFn(url, init);
111
+ return new Promise((resolve, reject) => {
112
+ const entry = { fetcher, url, init, resolve, reject };
113
+ if (!this._buckets.has(key)) {
114
+ this._buckets.set(key, []);
115
+ }
116
+ this._buckets.get(key).push(entry);
117
+ // Sliding window: reset timer on each new request
118
+ if (this._sliding && this._timers.has(key)) {
119
+ clearTimeout(this._timers.get(key));
120
+ this._timers.delete(key);
121
+ }
122
+ // Start timer if not already running (or just cleared for sliding)
123
+ if (!this._timers.has(key)) {
124
+ const timer = setTimeout(() => {
125
+ void this._dispatch(key);
126
+ }, this._windowMs);
127
+ this._timers.set(key, timer);
128
+ }
129
+ // Early flush if maxSize reached
130
+ if (this._buckets.get(key).length >= this._maxSize) {
131
+ void this._dispatch(key);
132
+ }
133
+ });
134
+ }
135
+ async _dispatch(key) {
136
+ // Cancel the timer for this key
137
+ const timer = this._timers.get(key);
138
+ if (timer !== undefined) {
139
+ clearTimeout(timer);
140
+ this._timers.delete(key);
141
+ }
142
+ // Splice the bucket — guard against double dispatch
143
+ const entries = this._buckets.get(key);
144
+ /* v8 ignore next — defensive guard against double-dispatch; unreachable via public API */
145
+ if (!entries || entries.length === 0)
146
+ return;
147
+ this._buckets.delete(key);
148
+ // Call the first entry's fetcher once; share result with all callers
149
+ const first = entries[0];
150
+ try {
151
+ const result = await first.fetcher(first.url, first.init);
152
+ for (const entry of entries) {
153
+ entry.resolve(result);
154
+ }
155
+ }
156
+ catch (err) {
157
+ for (const entry of entries) {
158
+ entry.reject(err);
159
+ }
160
+ }
161
+ }
162
+ /**
163
+ * Forces immediate dispatch of all pending batches.
164
+ * Resolves when all dispatched fetchers have settled.
165
+ */
166
+ async flush() {
167
+ const keys = [...this._buckets.keys()];
168
+ await Promise.allSettled(keys.map((key) => this._dispatch(key)));
169
+ }
170
+ /** Total pending requests across all batch buckets. */
171
+ get pendingCount() {
172
+ let count = 0;
173
+ for (const bucket of this._buckets.values()) {
174
+ count += bucket.length;
175
+ }
176
+ return count;
177
+ }
178
+ }
179
+ //# sourceMappingURL=request-batcher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"request-batcher.js","sourceRoot":"","sources":["../../../src/utils/async/request-batcher.ts"],"names":[],"mappings":"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"}