performance-helpers 1.0.0 → 1.0.1

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 (287) hide show
  1. package/README.md +12 -2
  2. package/package.json +146 -1
  3. package/src/index.js +1 -0
  4. package/.eslintrc.cjs +0 -22
  5. package/.nojekyll +0 -0
  6. package/.prettierrc +0 -6
  7. package/CONTRIBUTING.md +0 -178
  8. package/assets/1_Caching.md +0 -4
  9. package/assets/2_Parallelizing.md +0 -18
  10. package/assets/3_Logging.md +0 -3
  11. package/assets/404.md +0 -3
  12. package/assets/4_Utils.md +0 -10
  13. package/assets/logo.png +0 -0
  14. package/assets/navigation.md +0 -10
  15. package/bench/README.md +0 -97
  16. package/bench/results.json +0 -94
  17. package/bench/results.md +0 -233
  18. package/bench/run.js +0 -2639
  19. package/bench/worker.js +0 -43
  20. package/docs/README.md +0 -38
  21. package/docs/docs-typedoc.json +0 -38714
  22. package/docs/helpers/constants/README.md +0 -34
  23. package/docs/helpers/constants/variables/DEFAULT_AUTOSCALE_BACKOFF_MAX_MULTIPLIER.md +0 -9
  24. package/docs/helpers/constants/variables/DEFAULT_AUTOSCALE_COOLDOWN_MS.md +0 -9
  25. package/docs/helpers/constants/variables/DEFAULT_AUTOSCALE_INTERVAL_MS.md +0 -9
  26. package/docs/helpers/constants/variables/DEFAULT_AUTOSCALE_MIN_INTERVAL_MS.md +0 -9
  27. package/docs/helpers/constants/variables/DEFAULT_BACKPRESSURE_QUEUE_CAPACITY.md +0 -9
  28. package/docs/helpers/constants/variables/DEFAULT_BACKPRESSURE_REFILL_INTERVAL_MS.md +0 -9
  29. package/docs/helpers/constants/variables/DEFAULT_BATCH_MAX_SIZE.md +0 -9
  30. package/docs/helpers/constants/variables/DEFAULT_CACHE_DEFAULT_TTL_MS.md +0 -9
  31. package/docs/helpers/constants/variables/DEFAULT_CACHE_MAX_POOL_SIZE.md +0 -9
  32. package/docs/helpers/constants/variables/DEFAULT_CACHE_MAX_WEIGHT_BYTES.md +0 -9
  33. package/docs/helpers/constants/variables/DEFAULT_HISTOGRAM_BUCKET_COUNT.md +0 -9
  34. package/docs/helpers/constants/variables/DEFAULT_HISTOGRAM_MAX_VALUE.md +0 -9
  35. package/docs/helpers/constants/variables/DEFAULT_MAX_CLEANUP_PER_TICK.md +0 -9
  36. package/docs/helpers/constants/variables/DEFAULT_QUEUE_CAPACITY.md +0 -9
  37. package/docs/helpers/constants/variables/DEFAULT_REAPER_MIN_INTERVAL_MS.md +0 -9
  38. package/docs/helpers/constants/variables/DEFAULT_REFILL_INTERVAL_MS.md +0 -9
  39. package/docs/helpers/constants/variables/DEFAULT_RETRY_BASE_DELAY_MS.md +0 -9
  40. package/docs/helpers/constants/variables/DEFAULT_RETRY_MAX_DELAY_MS.md +0 -9
  41. package/docs/helpers/constants/variables/DEFAULT_TIMEOUT_MS.md +0 -9
  42. package/docs/helpers/constants/variables/ENCODE_CACHE_LARGE_KEY_LENGTH.md +0 -9
  43. package/docs/helpers/constants/variables/MAX_DEEP_EQUAL_DEPTH.md +0 -9
  44. package/docs/helpers/constants/variables/MS_PER_MIN.md +0 -9
  45. package/docs/helpers/constants/variables/MS_PER_SEC.md +0 -9
  46. package/docs/helpers/constants/variables/default.md +0 -103
  47. package/docs/helpers/jsdoc-types/README.md +0 -33
  48. package/docs/helpers/jsdoc-types/interfaces/BufferDecoder.md +0 -23
  49. package/docs/helpers/jsdoc-types/interfaces/BufferEncoder.md +0 -23
  50. package/docs/helpers/jsdoc-types/interfaces/CacheNode.md +0 -43
  51. package/docs/helpers/jsdoc-types/interfaces/CommonPoolOptions.md +0 -31
  52. package/docs/helpers/jsdoc-types/interfaces/PendingResponseEntry.md +0 -51
  53. package/docs/helpers/jsdoc-types/interfaces/PostMessageOptions.md +0 -39
  54. package/docs/helpers/jsdoc-types/interfaces/PowerBatchOptions.md +0 -13
  55. package/docs/helpers/jsdoc-types/interfaces/PowerCacheOptions.md +0 -115
  56. package/docs/helpers/jsdoc-types/interfaces/PowerChunkingOptions.md +0 -31
  57. package/docs/helpers/jsdoc-types/interfaces/PowerCircuitOptions.md +0 -45
  58. package/docs/helpers/jsdoc-types/interfaces/PowerDeadlineOptions.md +0 -101
  59. package/docs/helpers/jsdoc-types/interfaces/PowerDeferOptions.md +0 -13
  60. package/docs/helpers/jsdoc-types/interfaces/PowerEventBusOptions.md +0 -19
  61. package/docs/helpers/jsdoc-types/interfaces/PowerLatchOptions.md +0 -23
  62. package/docs/helpers/jsdoc-types/interfaces/PowerLoggerOptions.md +0 -51
  63. package/docs/helpers/jsdoc-types/interfaces/PowerObserverOptions.md +0 -25
  64. package/docs/helpers/jsdoc-types/interfaces/PowerPoolOptions.md +0 -85
  65. package/docs/helpers/jsdoc-types/interfaces/PowerQueueOptions.md +0 -13
  66. package/docs/helpers/jsdoc-types/interfaces/PowerRetryOptions.md +0 -83
  67. package/docs/helpers/jsdoc-types/interfaces/PowerSlidingWindowOptions.md +0 -19
  68. package/docs/helpers/jsdoc-types/interfaces/PowerTTLMapOptions.md +0 -27
  69. package/docs/helpers/jsdoc-types/interfaces/PowerThrottleOptions.md +0 -31
  70. package/docs/helpers/jsdoc-types/interfaces/WorkerObj.md +0 -55
  71. package/docs/helpers/powerBackpressure/README.md +0 -17
  72. package/docs/helpers/powerBackpressure/classes/PowerBackpressure.md +0 -368
  73. package/docs/helpers/powerBatch/README.md +0 -17
  74. package/docs/helpers/powerBatch/classes/PowerBatch.md +0 -139
  75. package/docs/helpers/powerBuffer/README.md +0 -26
  76. package/docs/helpers/powerBuffer/functions/b2o.md +0 -25
  77. package/docs/helpers/powerBuffer/functions/o2b.md +0 -23
  78. package/docs/helpers/powerBuffer/functions/o2u8.md +0 -33
  79. package/docs/helpers/powerBuffer/functions/u82o.md +0 -30
  80. package/docs/helpers/powerBulkhead/README.md +0 -17
  81. package/docs/helpers/powerBulkhead/classes/PowerBulkhead.md +0 -302
  82. package/docs/helpers/powerCache/README.md +0 -29
  83. package/docs/helpers/powerCache/classes/PowerCache.md +0 -933
  84. package/docs/helpers/powerCache/classes/PowerMemoizer.md +0 -244
  85. package/docs/helpers/powerCache/classes/PowerTimedCache.md +0 -302
  86. package/docs/helpers/powerCache/functions/simpleArgsKey.md +0 -31
  87. package/docs/helpers/powerChunking/README.md +0 -17
  88. package/docs/helpers/powerChunking/classes/PowerChunker.md +0 -78
  89. package/docs/helpers/powerCircuit/README.md +0 -23
  90. package/docs/helpers/powerCircuit/classes/PowerCircuit.md +0 -167
  91. package/docs/helpers/powerDeadline/README.md +0 -23
  92. package/docs/helpers/powerDeadline/classes/PowerDeadline.md +0 -88
  93. package/docs/helpers/powerDefer/README.md +0 -17
  94. package/docs/helpers/powerDefer/classes/PowerDefer.md +0 -134
  95. package/docs/helpers/powerEventBus/README.md +0 -23
  96. package/docs/helpers/powerEventBus/classes/PowerEventBus.md +0 -330
  97. package/docs/helpers/powerHistogram/README.md +0 -17
  98. package/docs/helpers/powerHistogram/classes/PowerHistogram.md +0 -285
  99. package/docs/helpers/powerLatch/README.md +0 -17
  100. package/docs/helpers/powerLatch/classes/PowerLatch.md +0 -264
  101. package/docs/helpers/powerLogger/README.md +0 -17
  102. package/docs/helpers/powerLogger/classes/PowerLogger.md +0 -290
  103. package/docs/helpers/powerObserver/README.md +0 -23
  104. package/docs/helpers/powerObserver/classes/PowerObserver.md +0 -213
  105. package/docs/helpers/powerPermitGate/README.md +0 -11
  106. package/docs/helpers/powerPermitGate/classes/PowerPermitGate.md +0 -248
  107. package/docs/helpers/powerPool/README.md +0 -36
  108. package/docs/helpers/powerPool/classes/PowerPool.md +0 -973
  109. package/docs/helpers/powerPool/classes/PowerPoolShutdownError.md +0 -67
  110. package/docs/helpers/powerQueue/README.md +0 -11
  111. package/docs/helpers/powerQueue/classes/PowerQueue.md +0 -302
  112. package/docs/helpers/powerRateLimit/README.md +0 -17
  113. package/docs/helpers/powerRateLimit/classes/PowerRateLimit.md +0 -187
  114. package/docs/helpers/powerRetry/README.md +0 -23
  115. package/docs/helpers/powerRetry/classes/PowerRetry.md +0 -106
  116. package/docs/helpers/powerScheduler/README.md +0 -11
  117. package/docs/helpers/powerScheduler/classes/PowerScheduler.md +0 -135
  118. package/docs/helpers/powerSemaphore/README.md +0 -17
  119. package/docs/helpers/powerSemaphore/classes/PowerSemaphore.md +0 -173
  120. package/docs/helpers/powerSlidingWindow/README.md +0 -11
  121. package/docs/helpers/powerSlidingWindow/classes/PowerSlidingWindow.md +0 -83
  122. package/docs/helpers/powerSubscriberSet/README.md +0 -15
  123. package/docs/helpers/powerSubscriberSet/classes/PowerSubscriberSet.md +0 -251
  124. package/docs/helpers/powerSubscriberSet/functions/cleanupWeakRefs.md +0 -21
  125. package/docs/helpers/powerTTLMap/README.md +0 -17
  126. package/docs/helpers/powerTTLMap/classes/PowerTTLMap.md +0 -326
  127. package/docs/helpers/powerThrottle/README.md +0 -17
  128. package/docs/helpers/powerThrottle/classes/PowerThrottle.md +0 -216
  129. package/docs/index/README.md +0 -205
  130. package/docs/utils/errors/README.md +0 -12
  131. package/docs/utils/errors/functions/formatErrorObj.md +0 -30
  132. package/docs/utils/errors/functions/normalizeError.md +0 -50
  133. package/docs/utils/now/README.md +0 -19
  134. package/docs/utils/now/functions/measureAsync.md +0 -37
  135. package/docs/utils/now/functions/measureSync.md +0 -54
  136. package/docs/utils/now/functions/nowMs.md +0 -24
  137. package/guides/autoscale.md +0 -80
  138. package/guides/errors.md +0 -41
  139. package/guides/metaGuide.md +0 -440
  140. package/guides/now.md +0 -56
  141. package/guides/powerBackpressure.md +0 -110
  142. package/guides/powerBatch.md +0 -82
  143. package/guides/powerBuffer.md +0 -86
  144. package/guides/powerBulkhead.md +0 -61
  145. package/guides/powerCache.md +0 -269
  146. package/guides/powerChunking.md +0 -130
  147. package/guides/powerCircuit.md +0 -84
  148. package/guides/powerDeadline.md +0 -99
  149. package/guides/powerDefer.md +0 -56
  150. package/guides/powerEventBus.md +0 -89
  151. package/guides/powerHistogram.md +0 -71
  152. package/guides/powerLatch.md +0 -94
  153. package/guides/powerLogger.md +0 -129
  154. package/guides/powerObserver.md +0 -65
  155. package/guides/powerPermitGate.md +0 -52
  156. package/guides/powerPool.md +0 -321
  157. package/guides/powerQueue.md +0 -112
  158. package/guides/powerRateLimit.md +0 -37
  159. package/guides/powerRetry.md +0 -54
  160. package/guides/powerScheduler.md +0 -41
  161. package/guides/powerSemaphore.md +0 -65
  162. package/guides/powerSlidingWindow.md +0 -63
  163. package/guides/powerSubscriberSet.md +0 -48
  164. package/guides/powerTTLMap.md +0 -58
  165. package/guides/powerThrottle.md +0 -152
  166. package/index.html +0 -57
  167. package/results.json +0 -6692
  168. package/scripts/find-missing-jsdoc.js +0 -62
  169. package/scripts/modernize-optional-chaining.cjs +0 -36
  170. package/scripts/pool-debug.mjs +0 -29
  171. package/scripts/repro_powercache.js +0 -14
  172. package/scripts/static-audit-exports.cjs +0 -93
  173. package/scripts/static-audit-exports.json +0 -518
  174. package/test/powerBackpressure.test.js +0 -114
  175. package/test/powerBatch.branches.extra.test.js +0 -122
  176. package/test/powerBatch.test.js +0 -79
  177. package/test/powerBuffer.test.js +0 -125
  178. package/test/powerBulkhead.test.js +0 -210
  179. package/test/powerCache.branches.test.js +0 -233
  180. package/test/powerCache.bulk.test.js +0 -31
  181. package/test/powerCache.getorset.test.js +0 -110
  182. package/test/powerCache.hitRate.test.js +0 -35
  183. package/test/powerCache.inflight.test.js +0 -24
  184. package/test/powerCache.iterator.test.js +0 -18
  185. package/test/powerCache.misses.test.js +0 -52
  186. package/test/powerCache.more.test.js +0 -118
  187. package/test/powerCache.test.js +0 -37
  188. package/test/powerCache.timeout.test.js +0 -25
  189. package/test/powerCache.touch.test.js +0 -46
  190. package/test/powerChunking.branches.extra.test.js +0 -155
  191. package/test/powerChunking.errors.test.js +0 -177
  192. package/test/powerChunking.test.js +0 -39
  193. package/test/powerCircuit.observability.test.js +0 -71
  194. package/test/powerCircuit.test.js +0 -74
  195. package/test/powerDeadline.test.js +0 -140
  196. package/test/powerDefer.test.js +0 -55
  197. package/test/powerErrors.test.js +0 -32
  198. package/test/powerEventBus.branches.extra.test.js +0 -70
  199. package/test/powerEventBus.extra.test.js +0 -72
  200. package/test/powerEventBus.max.test.js +0 -43
  201. package/test/powerEventBus.more.test.js +0 -121
  202. package/test/powerEventBus.once_off.test.js +0 -17
  203. package/test/powerEventBus.test.js +0 -74
  204. package/test/powerEventBus.uncovered.test.js +0 -57
  205. package/test/powerEventBus.weak.test.js +0 -18
  206. package/test/powerHistogram.test.js +0 -73
  207. package/test/powerLatch.branches.extra.test.js +0 -115
  208. package/test/powerLatch.test.js +0 -57
  209. package/test/powerLogger.branches.test.js +0 -98
  210. package/test/powerLogger.formatter.name.test.js +0 -58
  211. package/test/powerLogger.json.test.js +0 -88
  212. package/test/powerLogger.output.test.js +0 -81
  213. package/test/powerLogger.table.debug.test.js +0 -77
  214. package/test/powerLogger.test.js +0 -59
  215. package/test/powerMemoizer.memoize.test.js +0 -100
  216. package/test/powerMemoizer.test.js +0 -85
  217. package/test/powerObserver.test.js +0 -129
  218. package/test/powerPermitGate.test.js +0 -66
  219. package/test/powerPool.autoTransfer.test.js +0 -100
  220. package/test/powerPool.autoscale.extra.test.js +0 -88
  221. package/test/powerPool.autoscale.test.js +0 -136
  222. package/test/powerPool.awaitDefaultTimeout.test.js +0 -52
  223. package/test/powerPool.awaitTimeout.test.js +0 -22
  224. package/test/powerPool.batch.test.js +0 -170
  225. package/test/powerPool.branches.extra2.test.js +0 -42
  226. package/test/powerPool.branches.test.js +0 -102
  227. package/test/powerPool.browser.messageerror.test.js +0 -45
  228. package/test/powerPool.correlation.test.js +0 -26
  229. package/test/powerPool.correlationId.test.js +0 -63
  230. package/test/powerPool.dispose.test.js +0 -49
  231. package/test/powerPool.drain.test.js +0 -57
  232. package/test/powerPool.events.test.js +0 -131
  233. package/test/powerPool.more.extra.test.js +0 -99
  234. package/test/powerPool.more.test.js +0 -283
  235. package/test/powerPool.node.messageerror.test.js +0 -46
  236. package/test/powerPool.postMessage.promise.test.js +0 -83
  237. package/test/powerPool.queueHigh.test.js +0 -55
  238. package/test/powerPool.queueSaturation.test.js +0 -51
  239. package/test/powerPool.rapidResize.test.js +0 -55
  240. package/test/powerPool.resize.overload.test.js +0 -65
  241. package/test/powerPool.resize.test.js +0 -70
  242. package/test/powerPool.shutdown.test.js +0 -38
  243. package/test/powerPool.stats.test.js +0 -40
  244. package/test/powerPool.stopThePress.test.js +0 -94
  245. package/test/powerPool.terminateShutdown.test.js +0 -22
  246. package/test/powerPool.test.js +0 -525
  247. package/test/powerPool.timers.test.js +0 -55
  248. package/test/powerPool.uncovered.test.js +0 -407
  249. package/test/powerPool.workerId.test.js +0 -47
  250. package/test/powerQueue.iterators.test.js +0 -67
  251. package/test/powerQueue.saturation.test.js +0 -18
  252. package/test/powerQueue.test.js +0 -48
  253. package/test/powerQueue.unshiftMany.test.js +0 -49
  254. package/test/powerRateLimit.atomic.test.js +0 -80
  255. package/test/powerRateLimit.extra.test.js +0 -145
  256. package/test/powerRateLimit.functions.test.js +0 -106
  257. package/test/powerRateLimit.test.js +0 -38
  258. package/test/powerRetry.attemptTimeout.test.js +0 -51
  259. package/test/powerRetry.test.js +0 -121
  260. package/test/powerScheduler.test.js +0 -126
  261. package/test/powerSemaphore.test.js +0 -108
  262. package/test/powerSlidingWindow.pool.test.js +0 -55
  263. package/test/powerSlidingWindow.test.js +0 -25
  264. package/test/powerSubscriberSet.test.js +0 -125
  265. package/test/powerTTLMap.test.js +0 -125
  266. package/test/powerThrottle.pool.test.js +0 -54
  267. package/test/powerThrottle.refill.test.js +0 -22
  268. package/test/powerThrottle.reserve.test.js +0 -46
  269. package/test/powerThrottle.test.js +0 -45
  270. package/test/powerTimedCache.test.js +0 -73
  271. package/test/umd.bundle.branches.test.js +0 -100
  272. package/test/umd.bundle.cache-timers.test.js +0 -48
  273. package/test/umd.bundle.exhaustive.test.js +0 -158
  274. package/test/umd.bundle.fuzz.test.js +0 -86
  275. package/test/umd.bundle.hasEqual.more.test.js +0 -68
  276. package/test/umd.bundle.hasEqual.test.js +0 -104
  277. package/test/umd.bundle.logger-extra.test.js +0 -48
  278. package/test/umd.bundle.more-coverage-2.test.js +0 -67
  279. package/test/umd.bundle.pool.test.js +0 -134
  280. package/test/umd.bundle.test.js +0 -265
  281. package/test/utils.measure.test.js +0 -49
  282. package/test/utils.now.extra.test.js +0 -30
  283. package/test/utils.now.more.test.js +0 -57
  284. package/tsconfig.json +0 -16
  285. package/typedoc.json +0 -25
  286. package/vite.config.js +0 -31
  287. package/vitest.config.js +0 -17
@@ -1,122 +0,0 @@
1
- import { describe, it, expect } from 'vitest';
2
- import { PowerBatch } from '../src/helpers/powerBatch.js';
3
-
4
- describe('PowerBatch branches extra', () => {
5
- it('constructor throws when handler not a function', () => {
6
- expect(() => new PowerBatch(null)).toThrow();
7
- });
8
-
9
- it('flush returns resolved promise when empty and not scheduled', async () => {
10
- const b = new PowerBatch(async () => {});
11
- // ensure empty
12
- expect(b.size).toBe(0);
13
- const res = await b.flush();
14
- expect(res).toBeUndefined();
15
- });
16
-
17
- it('add schedules handler and resolves regular add promise', async () => {
18
- let called = false;
19
- const b = new PowerBatch(async (items) => {
20
- called = true;
21
- expect(items.length).toBeGreaterThan(0);
22
- });
23
- const p = b.add(1);
24
- await p;
25
- // wait a tick for handler
26
- await new Promise((r) => setTimeout(r, 10));
27
- expect(called).toBe(true);
28
- });
29
-
30
- it('flush returns a promise that rejects when handler throws', async () => {
31
- const b = new PowerBatch(async () => {
32
- throw new Error('boom');
33
- });
34
- b.add(1);
35
- await expect(b.flush()).rejects.toThrow('boom');
36
- });
37
-
38
- it('clear rejects pending add promises and empties queue', async () => {
39
- let called = false;
40
- const b = new PowerBatch(async () => {
41
- called = true;
42
- });
43
- const promise = b.add(1);
44
- b.clear();
45
- await expect(promise).rejects.toThrow('PowerBatch cleared before flush');
46
- await new Promise((r) => setTimeout(r, 10));
47
- expect(called).toBe(false);
48
- expect(b.size).toBe(0);
49
- });
50
-
51
- it('creates a fresh pending batch for items added while the handler is running', async () => {
52
- const calls = [];
53
- let releaseFirstBatch;
54
- const firstBatchGate = new Promise((resolve) => {
55
- releaseFirstBatch = resolve;
56
- });
57
-
58
- const b = new PowerBatch(async (items) => {
59
- calls.push(items.slice());
60
- if (calls.length === 1) {
61
- await firstBatchGate;
62
- }
63
- });
64
-
65
- const first = b.add('a');
66
- await Promise.resolve();
67
- const second = b.add('b');
68
- releaseFirstBatch();
69
-
70
- await Promise.all([first, second]);
71
-
72
- expect(calls).toEqual([['a'], ['b']]);
73
- });
74
-
75
- it('normalizes invalid maxSize and scheduling options', async () => {
76
- const calls = [];
77
- const b = new PowerBatch(
78
- async (items) => {
79
- calls.push(items.slice());
80
- },
81
- { maxSize: 0, scheduling: 'invalid' }
82
- );
83
-
84
- b.add(1);
85
- b.add(2);
86
- await b.flush();
87
-
88
- expect(calls).toEqual([[1, 2]]);
89
- });
90
-
91
- it('flush re-schedules queued work if a pending batch exists but the scheduler was canceled', async () => {
92
- const calls = [];
93
- const b = new PowerBatch(async (items) => {
94
- calls.push(items.slice());
95
- });
96
-
97
- const addPromise = b.add('x');
98
- b._scheduler.cancel();
99
-
100
- await b.flush();
101
- await addPromise;
102
-
103
- expect(calls).toEqual([['x']]);
104
- });
105
-
106
- it('resolves orphaned pending promises on empty internal runs and rethrows handler errors without pending state', async () => {
107
- const b = new PowerBatch(async () => {});
108
- const pending = b.add('x');
109
- b._queue.clear();
110
-
111
- await b._runBatch();
112
- await expect(pending).resolves.toBeUndefined();
113
- expect(b._pending).toBeNull();
114
-
115
- const b2 = new PowerBatch(async () => {
116
- throw new Error('boom');
117
- });
118
- b2._queue.push('y');
119
-
120
- await expect(b2._runBatch()).rejects.toThrow('boom');
121
- });
122
- });
@@ -1,79 +0,0 @@
1
- import { describe, it, expect } from 'vitest';
2
- import { PowerBatch } from '../src/helpers/powerBatch.js';
3
-
4
- describe('PowerBatch', () => {
5
- it('coalesces synchronous adds into a single handler call', async () => {
6
- const calls = [];
7
- const handler = async (items) => {
8
- calls.push(items.slice());
9
- };
10
- const b = new PowerBatch(handler);
11
- b.add(1);
12
- b.add(2);
13
- await b.flush();
14
- expect(calls.length).toBe(1);
15
- expect(calls[0]).toEqual([1, 2]);
16
- });
17
-
18
- it('flushes immediately when maxSize is reached', async () => {
19
- const calls = [];
20
- const handler = (items) => calls.push(items.slice());
21
- const b = new PowerBatch(handler, { maxSize: 2 });
22
- b.add('a');
23
- await b.add('b'); // this should trigger immediate flush
24
- expect(calls.length).toBe(1);
25
- expect(calls[0]).toEqual(['a', 'b']);
26
- });
27
-
28
- it('flush waits for async handler completion', async () => {
29
- const calls = [];
30
- const handler = async (items) => {
31
- await new Promise((r) => setTimeout(r, 10));
32
- calls.push(items.slice());
33
- };
34
- const b = new PowerBatch(handler);
35
- b.add(42);
36
- await b.flush();
37
- expect(calls.length).toBe(1);
38
- expect(calls[0]).toEqual([42]);
39
- });
40
-
41
- it('add returns a promise that resolves after the handler completes', async () => {
42
- const calls = [];
43
- const handler = async (items) => {
44
- await new Promise((r) => setTimeout(r, 10));
45
- calls.push(items.slice());
46
- };
47
- const b = new PowerBatch(handler);
48
- const promise = b.add('x');
49
- expect(promise).toBeInstanceOf(Promise);
50
- await promise;
51
- expect(calls).toEqual([['x']]);
52
- });
53
-
54
- it('add resolves after async handler completion when maxSize triggers immediate flush', async () => {
55
- const calls = [];
56
- const handler = async (items) => {
57
- await new Promise((r) => setTimeout(r, 10));
58
- calls.push(items.slice());
59
- };
60
- const b = new PowerBatch(handler, { maxSize: 2 });
61
- const promise = b.add('a');
62
- const promise2 = b.add('b');
63
- expect(promise).toBeInstanceOf(Promise);
64
- expect(promise2).toBeInstanceOf(Promise);
65
- await Promise.all([promise, promise2]);
66
- expect(calls).toEqual([['a', 'b']]);
67
- });
68
-
69
- it('accepts scheduling option (macrotask) and preserves basic behavior', async () => {
70
- const calls = [];
71
- const handler = (items) => calls.push(items.slice());
72
- const b = new PowerBatch(handler, { scheduling: 'macrotask' });
73
- b.add('x');
74
- b.add('y');
75
- await b.flush();
76
- expect(calls.length).toBe(1);
77
- expect(calls[0]).toEqual(['x', 'y']);
78
- });
79
- });
@@ -1,125 +0,0 @@
1
- import { describe, it, expect, vi } from 'vitest';
2
-
3
- describe('powerBuffer', () => {
4
- it('encodes and decodes plain objects', async () => {
5
- const mod = await import('../src/helpers/powerBuffer.js');
6
- const { o2u8, u82o } = mod;
7
- const obj = { a: 1, b: 'x' };
8
- const u8 = o2u8(obj);
9
- expect(u8).toBeInstanceOf(Uint8Array);
10
- const decoded = u82o(u8);
11
- expect(decoded).toEqual(obj);
12
- });
13
-
14
- it('accepts ArrayBuffer and returns Uint8Array view', async () => {
15
- const { o2u8 } = await import('../src/helpers/powerBuffer.js');
16
- const buf = new ArrayBuffer(4);
17
- const view = new Uint8Array(buf);
18
- view[0] = 1;
19
- const u8 = o2u8(buf);
20
- expect(u8).toBeInstanceOf(Uint8Array);
21
- expect(u8[0]).toBe(1);
22
- });
23
-
24
- it('o2b and b2o roundtrip', async () => {
25
- const { o2b, b2o } = await import('../src/helpers/powerBuffer.js');
26
- const obj = { z: [1, 2, 3], s: 'hello' };
27
- const ab = o2b(obj);
28
- expect(ab).toBeInstanceOf(ArrayBuffer);
29
- const out = b2o(ab);
30
- expect(out).toEqual(obj);
31
- });
32
-
33
- it('falls back to Buffer-based encoder/decoder when TextEncoder/TextDecoder are absent', async () => {
34
- // Reload module with globals stubbed
35
- vi.resetModules();
36
- const origTE = global.TextEncoder;
37
- const origTD = global.TextDecoder;
38
- try {
39
- // remove TextEncoder/TextDecoder to force Buffer fallback
40
- // @ts-ignore
41
- global.TextEncoder = undefined;
42
- // @ts-ignore
43
- global.TextDecoder = undefined;
44
- const mod = await import('../src/helpers/powerBuffer.js');
45
- const { o2u8, u82o } = mod;
46
- const obj = { fallback: true };
47
- const u8 = o2u8(obj);
48
- expect(u8).toBeInstanceOf(Uint8Array);
49
- const decoded = u82o(u8);
50
- expect(decoded).toEqual(obj);
51
- } finally {
52
- // restore
53
- // @ts-ignore
54
- global.TextEncoder = origTE;
55
- // @ts-ignore
56
- global.TextDecoder = origTD;
57
- }
58
- });
59
-
60
- it('returns the same Uint8Array instance when passed through', async () => {
61
- const { o2u8 } = await import('../src/helpers/powerBuffer.js');
62
- const ua = new Uint8Array([1, 2, 3]);
63
- const out = o2u8(ua);
64
- expect(out).toBe(ua);
65
- });
66
-
67
- it('handles typed-array views and o2b produces a sliced ArrayBuffer when offset present', async () => {
68
- const mod = await import('../src/helpers/powerBuffer.js');
69
- const { o2u8, o2b } = mod;
70
- const buf = new ArrayBuffer(8);
71
- const view = new Uint8Array(buf, 2, 4);
72
- view.set([9, 8, 7, 6]);
73
- const u8 = o2u8(view);
74
- expect(u8).toBeInstanceOf(Uint8Array);
75
- const ab = o2b(view);
76
- expect(ab).toBeInstanceOf(ArrayBuffer);
77
- expect(ab.byteLength).toBe(u8.byteLength);
78
- expect(ab).not.toBe(u8.buffer);
79
- });
80
-
81
- it('u82o accepts Node Buffer and decodes to object', async () => {
82
- const { u82o } = await import('../src/helpers/powerBuffer.js');
83
- const obj = { foo: 'bar' };
84
- // Node Buffer path
85
- const buf = Buffer.from(JSON.stringify(obj));
86
- const out = u82o(buf);
87
- expect(out).toEqual(obj);
88
- });
89
-
90
- it('u82o throws for unsupported input types', async () => {
91
- const { u82o } = await import('../src/helpers/powerBuffer.js');
92
- expect(() => u82o('not-a-buffer')).toThrow(TypeError);
93
- });
94
-
95
- it('throws when no encoder/decoder available (simulated)', async () => {
96
- // reload module with globals removed so getEncoder/getDecoder return null
97
- vi.resetModules();
98
- const origTE = global.TextEncoder;
99
- const origTD = global.TextDecoder;
100
- const origBuf = global.Buffer;
101
- try {
102
- // remove global encoders/Buffer
103
- // @ts-ignore
104
- global.TextEncoder = undefined;
105
- // @ts-ignore
106
- global.TextDecoder = undefined;
107
- // @ts-ignore
108
- global.Buffer = undefined;
109
-
110
- const mod = await import('../src/helpers/powerBuffer.js');
111
- const { o2u8, u82o } = mod;
112
- expect(() => o2u8({ a: 1 })).toThrow(/No TextEncoder or Buffer available/);
113
- const u = new Uint8Array([1, 2, 3]);
114
- expect(() => u82o(u)).toThrow(/No TextDecoder or Buffer available/);
115
- } finally {
116
- // restore
117
- // @ts-ignore
118
- global.TextEncoder = origTE;
119
- // @ts-ignore
120
- global.TextDecoder = origTD;
121
- // @ts-ignore
122
- global.Buffer = origBuf;
123
- }
124
- });
125
- });
@@ -1,210 +0,0 @@
1
- import { describe, it, expect } from 'vitest';
2
- import { PowerBulkhead } from '../src/helpers/powerBulkhead.js';
3
-
4
- describe('PowerBulkhead', () => {
5
- it('exposes constructor-derived getters and saturation state', () => {
6
- const bulkhead = new PowerBulkhead({ partitions: 3, maxConcurrency: 2, queueCapacity: 4 });
7
- expect(bulkhead.partitions).toBe(3);
8
- expect(bulkhead.maxConcurrency).toBe(2);
9
- expect(bulkhead.queueCapacity).toBe(4);
10
- expect(bulkhead.isFull).toBe(false);
11
- });
12
-
13
- it('executes tasks immediately while capacity remains in a partition', async () => {
14
- const bulkhead = new PowerBulkhead({ partitions: 2, maxConcurrency: 2 });
15
- const results = await Promise.all([
16
- bulkhead.run(() => 1, { partitionKey: 'a' }),
17
- bulkhead.run(() => 2, { partitionKey: 'a' }),
18
- ]);
19
-
20
- expect(results).toEqual([1, 2]);
21
- expect(bulkhead.active).toBe(0);
22
- expect(bulkhead.pending).toBe(0);
23
- });
24
-
25
- it('queues tasks when partition concurrency is exceeded and dispatches them in FIFO order', async () => {
26
- const bulkhead = new PowerBulkhead({ partitions: 1, maxConcurrency: 1, queueCapacity: 10 });
27
- const firstTask = bulkhead.run(
28
- () =>
29
- new Promise((resolve) => {
30
- setTimeout(() => {
31
- resolve('first');
32
- }, 20);
33
- })
34
- );
35
-
36
- const secondTask = bulkhead.run(() => 'second');
37
-
38
- expect(bulkhead.pending).toBe(1);
39
- expect(secondTask).toBeInstanceOf(Promise);
40
-
41
- const result = await secondTask;
42
- expect(result).toBe('second');
43
- expect(await firstTask).toBe('first');
44
- expect(bulkhead.pending).toBe(0);
45
- expect(bulkhead.active).toBe(0);
46
- });
47
-
48
- it('updates active and pending counters as queued work starts running', async () => {
49
- const bulkhead = new PowerBulkhead({ partitions: 1, maxConcurrency: 1, queueCapacity: 10 });
50
- let releaseFirst;
51
- let resolveFirstStarted;
52
- const firstStarted = new Promise((resolve) => {
53
- resolveFirstStarted = resolve;
54
- });
55
- let resolveSecondStarted;
56
- const secondStarted = new Promise((resolve) => {
57
- resolveSecondStarted = resolve;
58
- });
59
-
60
- const firstTask = bulkhead.run(
61
- () =>
62
- new Promise((resolve) => {
63
- releaseFirst = () => resolve('first');
64
- resolveFirstStarted();
65
- })
66
- );
67
-
68
- const secondTask = bulkhead.run(async () => {
69
- resolveSecondStarted();
70
- return 'second';
71
- });
72
-
73
- expect(bulkhead.active).toBe(1);
74
- expect(bulkhead.pending).toBe(1);
75
-
76
- await firstStarted;
77
- releaseFirst();
78
- await secondStarted;
79
-
80
- expect(bulkhead.active).toBe(1);
81
- expect(bulkhead.pending).toBe(0);
82
-
83
- await expect(secondTask).resolves.toBe('second');
84
- await expect(firstTask).resolves.toBe('first');
85
- expect(bulkhead.active).toBe(0);
86
- expect(bulkhead.pending).toBe(0);
87
- });
88
-
89
- it('isolates noisy partitions so one partition queue does not block other partitions', async () => {
90
- const bulkhead = new PowerBulkhead({ partitions: 2, maxConcurrency: 1, queueCapacity: 10 });
91
- const executionOrder = [];
92
-
93
- const hot1 = bulkhead.run(
94
- () =>
95
- new Promise((resolve) => {
96
- executionOrder.push('hot-start');
97
- setTimeout(() => {
98
- executionOrder.push('hot-end');
99
- resolve('hot');
100
- }, 40);
101
- }),
102
- { partitionKey: 'hot' }
103
- );
104
-
105
- const hot2 = bulkhead.run(() => 'hot-queued', { partitionKey: 'hot' });
106
-
107
- const cold = bulkhead.run(
108
- () => {
109
- executionOrder.push('cold');
110
- return 'cold';
111
- },
112
- { partitionKey: 'cold' }
113
- );
114
-
115
- expect(bulkhead.pending).toBe(1);
116
- expect(await cold).toBe('cold');
117
- expect(await hot2).toBe('hot-queued');
118
- expect(await hot1).toBe('hot');
119
- expect(executionOrder).toEqual(['hot-start', 'cold', 'hot-end']);
120
- });
121
-
122
- it('rejects new tasks when global queue capacity is exceeded', async () => {
123
- const bulkhead = new PowerBulkhead({ partitions: 1, maxConcurrency: 1, queueCapacity: 1 });
124
-
125
- bulkhead.run(() => new Promise((resolve) => setTimeout(resolve, 20)));
126
-
127
- const queued = bulkhead.run(() => 'queued');
128
- expect(bulkhead.pending).toBe(1);
129
- expect(bulkhead.isFull).toBe(true);
130
-
131
- await expect(bulkhead.run(() => 'overflow')).rejects.toThrow('PowerBulkhead queue is full');
132
- expect(await queued).toBe('queued');
133
- });
134
-
135
- it('tryRun throws for invalid tasks and returns null when partition is busy', async () => {
136
- const bulkhead = new PowerBulkhead({ partitions: 1, maxConcurrency: 1, queueCapacity: 1 });
137
-
138
- expect(() => bulkhead.tryRun(null)).toThrow('PowerBulkhead.tryRun() requires a function');
139
-
140
- let release;
141
- let resolveStarted;
142
- const started = new Promise((resolve) => {
143
- resolveStarted = resolve;
144
- });
145
- const running = bulkhead.run(
146
- () =>
147
- new Promise((resolve) => {
148
- release = () => resolve('done');
149
- resolveStarted();
150
- })
151
- );
152
-
153
- await started;
154
-
155
- expect(bulkhead.tryRun(() => 'later')).toBeNull();
156
- release();
157
- await expect(running).resolves.toBe('done');
158
- });
159
-
160
- it('tryRun executes immediately when capacity is available', async () => {
161
- const bulkhead = new PowerBulkhead({ partitions: 2, maxConcurrency: 1 });
162
- await expect(bulkhead.tryRun(() => 'ok')).resolves.toBe('ok');
163
- expect(bulkhead.active).toBe(0);
164
- });
165
-
166
- it('drain resolves immediately when already idle', async () => {
167
- const bulkhead = new PowerBulkhead({ partitions: 2, maxConcurrency: 1 });
168
- await expect(bulkhead.drain()).resolves.toBeUndefined();
169
- });
170
-
171
- it('uses a custom partitioner when provided', async () => {
172
- const seen = [];
173
- const bulkhead = new PowerBulkhead({
174
- partitions: 2,
175
- maxConcurrency: 1,
176
- partitioner(key) {
177
- seen.push(key);
178
- return 1;
179
- },
180
- });
181
-
182
- await expect(bulkhead.run(() => 'ok', { partitionKey: 'custom' })).resolves.toBe('ok');
183
- expect(seen).toEqual(['custom']);
184
- });
185
-
186
- it('drain() resolves after all active and queued tasks finish', async () => {
187
- const bulkhead = new PowerBulkhead({ partitions: 1, maxConcurrency: 1, queueCapacity: 10 });
188
- const results = [];
189
-
190
- bulkhead.run(
191
- () =>
192
- new Promise((resolve) =>
193
- setTimeout(() => {
194
- results.push('first');
195
- resolve('first');
196
- }, 20)
197
- )
198
- );
199
-
200
- bulkhead.run(() => {
201
- results.push('second');
202
- return 'second';
203
- });
204
-
205
- await bulkhead.drain();
206
- expect(results).toEqual(['first', 'second']);
207
- expect(bulkhead.active).toBe(0);
208
- expect(bulkhead.pending).toBe(0);
209
- });
210
- });