@vielzeug/arsenal 1.1.1 → 2.0.0

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 (294) hide show
  1. package/README.md +31 -75
  2. package/dist/_dev.cjs +1 -1
  3. package/dist/_dev.cjs.map +1 -1
  4. package/dist/_dev.js +2 -5
  5. package/dist/_dev.js.map +1 -1
  6. package/dist/array/chunk.cjs +1 -1
  7. package/dist/array/chunk.cjs.map +1 -1
  8. package/dist/array/chunk.d.ts +2 -1
  9. package/dist/array/chunk.d.ts.map +1 -1
  10. package/dist/array/chunk.js +5 -7
  11. package/dist/array/chunk.js.map +1 -1
  12. package/dist/array/compare.cjs +1 -1
  13. package/dist/array/compare.cjs.map +1 -1
  14. package/dist/array/compare.d.ts.map +1 -1
  15. package/dist/array/compare.js +13 -14
  16. package/dist/array/compare.js.map +1 -1
  17. package/dist/array/index.cjs +1 -0
  18. package/dist/array/index.js +29 -0
  19. package/dist/array/search.cjs +1 -1
  20. package/dist/array/search.cjs.map +1 -1
  21. package/dist/array/search.d.ts +8 -77
  22. package/dist/array/search.d.ts.map +1 -1
  23. package/dist/array/search.js +21 -38
  24. package/dist/array/search.js.map +1 -1
  25. package/dist/array/sort.cjs +1 -1
  26. package/dist/array/sort.cjs.map +1 -1
  27. package/dist/array/sort.d.ts +1 -1
  28. package/dist/array/sort.d.ts.map +1 -1
  29. package/dist/array/sort.js +9 -10
  30. package/dist/array/sort.js.map +1 -1
  31. package/dist/arsenal.cjs +1 -1
  32. package/dist/arsenal.cjs.map +1 -1
  33. package/dist/arsenal.iife.js +1 -1
  34. package/dist/arsenal.iife.js.map +1 -1
  35. package/dist/arsenal.js +1 -1
  36. package/dist/arsenal.js.map +1 -1
  37. package/dist/async/attempt.cjs +1 -1
  38. package/dist/async/attempt.cjs.map +1 -1
  39. package/dist/async/attempt.d.ts +3 -8
  40. package/dist/async/attempt.d.ts.map +1 -1
  41. package/dist/async/attempt.js +3 -10
  42. package/dist/async/attempt.js.map +1 -1
  43. package/dist/async/index.cjs +1 -0
  44. package/dist/async/index.d.ts +1 -1
  45. package/dist/async/index.d.ts.map +1 -1
  46. package/dist/async/index.js +9 -0
  47. package/dist/async/parallel.cjs +1 -1
  48. package/dist/async/parallel.cjs.map +1 -1
  49. package/dist/async/parallel.d.ts +1 -1
  50. package/dist/async/parallel.d.ts.map +1 -1
  51. package/dist/async/parallel.js +15 -16
  52. package/dist/async/parallel.js.map +1 -1
  53. package/dist/async/retry.cjs +1 -1
  54. package/dist/async/retry.cjs.map +1 -1
  55. package/dist/async/retry.d.ts +1 -1
  56. package/dist/async/retry.d.ts.map +1 -1
  57. package/dist/async/retry.js +14 -15
  58. package/dist/async/retry.js.map +1 -1
  59. package/dist/async/taskPool.cjs +2 -0
  60. package/dist/async/taskPool.cjs.map +1 -0
  61. package/dist/async/taskPool.d.ts +14 -0
  62. package/dist/async/taskPool.d.ts.map +1 -0
  63. package/dist/async/taskPool.js +51 -0
  64. package/dist/async/taskPool.js.map +1 -0
  65. package/dist/cache/cache.cjs +2 -0
  66. package/dist/cache/cache.cjs.map +1 -0
  67. package/dist/cache/cache.d.ts +17 -0
  68. package/dist/cache/cache.d.ts.map +1 -0
  69. package/dist/cache/cache.js +59 -0
  70. package/dist/cache/cache.js.map +1 -0
  71. package/dist/cache/index.cjs +1 -0
  72. package/dist/cache/index.d.ts +1 -1
  73. package/dist/cache/index.d.ts.map +1 -1
  74. package/dist/cache/index.js +3 -0
  75. package/dist/cache/memo.cjs +1 -1
  76. package/dist/cache/memo.cjs.map +1 -1
  77. package/dist/cache/memo.d.ts +2 -2
  78. package/dist/cache/memo.js +24 -23
  79. package/dist/cache/memo.js.map +1 -1
  80. package/dist/errors.cjs +1 -1
  81. package/dist/errors.cjs.map +1 -1
  82. package/dist/errors.d.ts +0 -7
  83. package/dist/errors.d.ts.map +1 -1
  84. package/dist/errors.js +2 -2
  85. package/dist/errors.js.map +1 -1
  86. package/dist/function/debounce.cjs +1 -1
  87. package/dist/function/debounce.cjs.map +1 -1
  88. package/dist/function/debounce.js +15 -17
  89. package/dist/function/debounce.js.map +1 -1
  90. package/dist/function/index.cjs +1 -0
  91. package/dist/function/index.d.ts +0 -2
  92. package/dist/function/index.d.ts.map +1 -1
  93. package/dist/function/index.js +8 -0
  94. package/dist/function/pipe.cjs +1 -1
  95. package/dist/function/pipe.cjs.map +1 -1
  96. package/dist/function/pipe.js +1 -1
  97. package/dist/function/pipe.js.map +1 -1
  98. package/dist/guards/index.cjs +1 -0
  99. package/dist/guards/index.d.ts +0 -3
  100. package/dist/guards/index.d.ts.map +1 -1
  101. package/dist/guards/index.js +17 -0
  102. package/dist/guards/isEqual.cjs.map +1 -1
  103. package/dist/guards/isEqual.js.map +1 -1
  104. package/dist/index.cjs +1 -1
  105. package/dist/index.d.ts +2 -91
  106. package/dist/index.d.ts.map +1 -1
  107. package/dist/index.js +30 -118
  108. package/dist/math/allocate.cjs +1 -1
  109. package/dist/math/allocate.cjs.map +1 -1
  110. package/dist/math/allocate.d.ts +1 -1
  111. package/dist/math/allocate.d.ts.map +1 -1
  112. package/dist/math/allocate.js +13 -14
  113. package/dist/math/allocate.js.map +1 -1
  114. package/dist/math/index.cjs +1 -0
  115. package/dist/math/index.d.ts +0 -3
  116. package/dist/math/index.d.ts.map +1 -1
  117. package/dist/math/index.js +17 -0
  118. package/dist/math/mod.cjs +1 -1
  119. package/dist/math/mod.cjs.map +1 -1
  120. package/dist/math/mod.d.ts +1 -1
  121. package/dist/math/mod.d.ts.map +1 -1
  122. package/dist/math/mod.js +4 -5
  123. package/dist/math/mod.js.map +1 -1
  124. package/dist/math/range.cjs +1 -1
  125. package/dist/math/range.cjs.map +1 -1
  126. package/dist/math/range.d.ts +1 -1
  127. package/dist/math/range.d.ts.map +1 -1
  128. package/dist/math/range.js +14 -15
  129. package/dist/math/range.js.map +1 -1
  130. package/dist/math/sum.cjs +1 -1
  131. package/dist/math/sum.cjs.map +1 -1
  132. package/dist/math/sum.d.ts +2 -2
  133. package/dist/math/sum.d.ts.map +1 -1
  134. package/dist/math/sum.js +6 -7
  135. package/dist/math/sum.js.map +1 -1
  136. package/dist/object/getPath.cjs +1 -1
  137. package/dist/object/getPath.cjs.map +1 -1
  138. package/dist/object/getPath.d.ts +12 -42
  139. package/dist/object/getPath.d.ts.map +1 -1
  140. package/dist/object/getPath.js +21 -22
  141. package/dist/object/getPath.js.map +1 -1
  142. package/dist/object/index.cjs +1 -0
  143. package/dist/object/index.d.ts +1 -1
  144. package/dist/object/index.d.ts.map +1 -1
  145. package/dist/object/index.js +15 -0
  146. package/dist/object/merge.cjs +1 -1
  147. package/dist/object/merge.cjs.map +1 -1
  148. package/dist/object/merge.d.ts +1 -1
  149. package/dist/object/merge.d.ts.map +1 -1
  150. package/dist/object/merge.js +2 -3
  151. package/dist/object/merge.js.map +1 -1
  152. package/dist/object/prune.cjs +1 -1
  153. package/dist/object/prune.cjs.map +1 -1
  154. package/dist/object/prune.d.ts.map +1 -1
  155. package/dist/object/prune.js +22 -23
  156. package/dist/object/prune.js.map +1 -1
  157. package/dist/object/tryParseJson.cjs +2 -0
  158. package/dist/object/tryParseJson.cjs.map +1 -0
  159. package/dist/object/tryParseJson.d.ts +9 -0
  160. package/dist/object/tryParseJson.d.ts.map +1 -0
  161. package/dist/object/tryParseJson.js +18 -0
  162. package/dist/object/tryParseJson.js.map +1 -0
  163. package/dist/random/_index.cjs +2 -0
  164. package/dist/random/_index.cjs.map +1 -0
  165. package/dist/random/_index.d.ts +3 -0
  166. package/dist/random/_index.d.ts.map +1 -0
  167. package/dist/random/_index.js +10 -0
  168. package/dist/random/_index.js.map +1 -0
  169. package/dist/random/draw.cjs +1 -1
  170. package/dist/random/draw.cjs.map +1 -1
  171. package/dist/random/draw.d.ts +3 -2
  172. package/dist/random/draw.d.ts.map +1 -1
  173. package/dist/random/draw.js +12 -12
  174. package/dist/random/draw.js.map +1 -1
  175. package/dist/random/index.cjs +1 -0
  176. package/dist/random/index.d.ts +1 -0
  177. package/dist/random/index.d.ts.map +1 -1
  178. package/dist/random/index.js +5 -0
  179. package/dist/random/random.cjs +1 -1
  180. package/dist/random/random.cjs.map +1 -1
  181. package/dist/random/random.d.ts +2 -1
  182. package/dist/random/random.d.ts.map +1 -1
  183. package/dist/random/random.js +5 -6
  184. package/dist/random/random.js.map +1 -1
  185. package/dist/random/shuffle.cjs +1 -1
  186. package/dist/random/shuffle.cjs.map +1 -1
  187. package/dist/random/shuffle.d.ts +2 -1
  188. package/dist/random/shuffle.d.ts.map +1 -1
  189. package/dist/random/shuffle.js +7 -7
  190. package/dist/random/shuffle.js.map +1 -1
  191. package/dist/random/source.d.ts +4 -0
  192. package/dist/random/source.d.ts.map +1 -0
  193. package/dist/string/index.cjs +1 -0
  194. package/dist/string/index.d.ts +0 -2
  195. package/dist/string/index.d.ts.map +1 -1
  196. package/dist/string/index.js +12 -0
  197. package/dist/string/similarity.cjs +1 -1
  198. package/dist/string/similarity.cjs.map +1 -1
  199. package/dist/string/similarity.d.ts.map +1 -1
  200. package/dist/string/similarity.js +16 -17
  201. package/dist/string/similarity.js.map +1 -1
  202. package/dist/string/truncate.cjs +1 -1
  203. package/dist/string/truncate.cjs.map +1 -1
  204. package/dist/string/truncate.d.ts +2 -1
  205. package/dist/string/truncate.d.ts.map +1 -1
  206. package/dist/string/truncate.js +10 -11
  207. package/dist/string/truncate.js.map +1 -1
  208. package/dist/types.d.ts +1 -1
  209. package/dist/types.d.ts.map +1 -1
  210. package/package.json +14 -19
  211. package/dist/_common/_secureRandomIndex.cjs +0 -2
  212. package/dist/_common/_secureRandomIndex.cjs.map +0 -1
  213. package/dist/_common/_secureRandomIndex.d.ts +0 -2
  214. package/dist/_common/_secureRandomIndex.d.ts.map +0 -1
  215. package/dist/_common/_secureRandomIndex.js +0 -9
  216. package/dist/_common/_secureRandomIndex.js.map +0 -1
  217. package/dist/async/queue.cjs +0 -2
  218. package/dist/async/queue.cjs.map +0 -1
  219. package/dist/async/queue.d.ts +0 -42
  220. package/dist/async/queue.d.ts.map +0 -1
  221. package/dist/async/queue.js +0 -72
  222. package/dist/async/queue.js.map +0 -1
  223. package/dist/cache/stash.cjs +0 -2
  224. package/dist/cache/stash.cjs.map +0 -1
  225. package/dist/cache/stash.d.ts +0 -111
  226. package/dist/cache/stash.d.ts.map +0 -1
  227. package/dist/cache/stash.js +0 -92
  228. package/dist/cache/stash.js.map +0 -1
  229. package/dist/function/constant.cjs +0 -2
  230. package/dist/function/constant.cjs.map +0 -1
  231. package/dist/function/constant.d.ts +0 -5
  232. package/dist/function/constant.d.ts.map +0 -1
  233. package/dist/function/constant.js +0 -8
  234. package/dist/function/constant.js.map +0 -1
  235. package/dist/function/identity.cjs +0 -2
  236. package/dist/function/identity.cjs.map +0 -1
  237. package/dist/function/identity.d.ts +0 -5
  238. package/dist/function/identity.d.ts.map +0 -1
  239. package/dist/function/identity.js +0 -8
  240. package/dist/function/identity.js.map +0 -1
  241. package/dist/guards/isArray.cjs +0 -2
  242. package/dist/guards/isArray.cjs.map +0 -1
  243. package/dist/guards/isArray.d.ts +0 -16
  244. package/dist/guards/isArray.d.ts.map +0 -1
  245. package/dist/guards/isArray.js +0 -8
  246. package/dist/guards/isArray.js.map +0 -1
  247. package/dist/guards/isBoolean.cjs +0 -2
  248. package/dist/guards/isBoolean.cjs.map +0 -1
  249. package/dist/guards/isBoolean.d.ts +0 -23
  250. package/dist/guards/isBoolean.d.ts.map +0 -1
  251. package/dist/guards/isBoolean.js +0 -8
  252. package/dist/guards/isBoolean.js.map +0 -1
  253. package/dist/guards/isString.cjs +0 -2
  254. package/dist/guards/isString.cjs.map +0 -1
  255. package/dist/guards/isString.d.ts +0 -15
  256. package/dist/guards/isString.d.ts.map +0 -1
  257. package/dist/guards/isString.js +0 -8
  258. package/dist/guards/isString.js.map +0 -1
  259. package/dist/math/abs.cjs +0 -2
  260. package/dist/math/abs.cjs.map +0 -1
  261. package/dist/math/abs.d.ts +0 -17
  262. package/dist/math/abs.d.ts.map +0 -1
  263. package/dist/math/abs.js +0 -8
  264. package/dist/math/abs.js.map +0 -1
  265. package/dist/math/max.cjs +0 -2
  266. package/dist/math/max.cjs.map +0 -1
  267. package/dist/math/max.d.ts +0 -21
  268. package/dist/math/max.d.ts.map +0 -1
  269. package/dist/math/max.js +0 -12
  270. package/dist/math/max.js.map +0 -1
  271. package/dist/math/min.cjs +0 -2
  272. package/dist/math/min.cjs.map +0 -1
  273. package/dist/math/min.d.ts +0 -21
  274. package/dist/math/min.d.ts.map +0 -1
  275. package/dist/math/min.js +0 -12
  276. package/dist/math/min.js.map +0 -1
  277. package/dist/object/parseJSON.cjs +0 -2
  278. package/dist/object/parseJSON.cjs.map +0 -1
  279. package/dist/object/parseJSON.d.ts +0 -32
  280. package/dist/object/parseJSON.d.ts.map +0 -1
  281. package/dist/object/parseJSON.js +0 -16
  282. package/dist/object/parseJSON.js.map +0 -1
  283. package/dist/string/endsWith.cjs +0 -2
  284. package/dist/string/endsWith.cjs.map +0 -1
  285. package/dist/string/endsWith.d.ts +0 -5
  286. package/dist/string/endsWith.d.ts.map +0 -1
  287. package/dist/string/endsWith.js +0 -8
  288. package/dist/string/endsWith.js.map +0 -1
  289. package/dist/string/startsWith.cjs +0 -2
  290. package/dist/string/startsWith.cjs.map +0 -1
  291. package/dist/string/startsWith.d.ts +0 -5
  292. package/dist/string/startsWith.d.ts.map +0 -1
  293. package/dist/string/startsWith.js +0 -8
  294. package/dist/string/startsWith.js.map +0 -1
@@ -1 +0,0 @@
1
- {"version":3,"file":"_secureRandomIndex.js","names":[],"sources":["../../src/_common/_secureRandomIndex.ts"],"sourcesContent":["/**\n * Returns a cryptographically random integer in `[0, exclusiveMax)` via `crypto.getRandomValues`.\n * Shared by `random()`, `shuffle()`, and `drawMany()` — the single source of truth for converting\n * a random `Uint32` into a bounded index.\n *\n * Module-private: underscore-prefixed file is excluded from barrel exports.\n * @internal\n */\nexport function secureRandomIndex(exclusiveMax: number): number {\n // Divide by 0x100000000 (not 0xffffffff) to produce [0, 1) instead of [0, 1]\n const randomValue = crypto.getRandomValues(new Uint32Array(1))[0]! / 0x100000000;\n\n return Math.floor(randomValue * exclusiveMax);\n}\n"],"mappings":";AAQA,SAAgB,EAAkB,GAA8B;CAE9D,IAAM,IAAc,OAAO,gCAAgB,IAAI,YAAY,CAAC,CAAC,CAAC,CAAC,KAAM;CAErE,OAAO,KAAK,MAAM,IAAc,CAAY;AAC9C"}
@@ -1,2 +0,0 @@
1
- const e=require("../errors.cjs");function t(t={}){let{concurrency:n=1}=t;if(n<1)throw new e.ArsenalValidationError(`Concurrency must be at least 1`);let r=0,i=!1,a=null,o=null,s=[],c=new Set,l=()=>{r===0&&s.length===0&&o&&(o(),a=null,o=null)},u=e=>{for(let t of c)t(e)},d=()=>{if(!i){for(i=!0;r<n&&s.length>0;){let e=s.shift();r++,Promise.resolve().then(()=>e.fn()).then(t=>{u({ok:!0,value:t}),e.resolve(t)}).catch(t=>{u({error:t,ok:!1}),e.reject(t)}).finally(()=>{r--,d(),l()})}i=!1,l()}};return{get active(){return r},add:(e,t)=>{let{promise:n,reject:r,resolve:i}=Promise.withResolvers(),a=t?.priority??0,o={fn:e,priority:a,reject:r,resolve:i},c=s.length;for(;c>0&&s[c-1].priority<a;)c--;return s.splice(c,0,o),d(),n},clear:e=>{let t=e??Error(`Queue cleared`);for(let e of s.splice(0))e.reject(t);l()},onIdle:()=>{if(r===0&&s.length===0)return Promise.resolve();if(!a){let e=Promise.withResolvers();a=e.promise,o=e.resolve}return a},onSettled:e=>(c.add(e),()=>{c.delete(e)}),get pending(){return s.length},get size(){return r+s.length}}}exports.queue=t;
2
- //# sourceMappingURL=queue.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"queue.cjs","names":[],"sources":["../../src/async/queue.ts"],"sourcesContent":["import type { AttemptResult } from './attempt';\n\nimport { ArsenalValidationError } from '../errors';\n\n/**\n * Creates a promise queue that processes promises sequentially with optional concurrency limit.\n *\n * @example\n * ```ts\n * const requestQueue = queue({ concurrency: 2 });\n *\n * requestQueue.add(() => fetch('/api/1'));\n * requestQueue.add(() => fetch('/api/2'));\n * requestQueue.add(() => fetch('/api/3'));\n *\n * await requestQueue.onIdle(); // Wait for all tasks to complete\n * ```\n *\n * @param options - Queue configuration\n * @param options.concurrency - Maximum number of concurrent promises (default: 1)\n * @returns Queue instance with add, onIdle, clear, and onSettled methods\n */\nexport type QueueSettledCallback<T = unknown> = (result: AttemptResult<T>) => void;\n\nexport interface Queue {\n /** Adds a task to the queue. Returns a promise that resolves/rejects with the task result. */\n add<T>(fn: () => Promise<T>, options?: { priority?: number }): Promise<T>;\n /** Clears all pending tasks, rejecting them with the given reason. Running tasks are unaffected. */\n clear(reason?: unknown): void;\n /** Returns a promise that resolves when the queue becomes idle (no active or pending tasks). */\n onIdle(): Promise<void>;\n /** Subscribes to settled results (both resolved and rejected). Returns an unsubscribe function. */\n onSettled<T>(cb: QueueSettledCallback<T>): () => void;\n /** Number of currently running tasks. */\n readonly active: number;\n /** Number of tasks waiting to run. */\n readonly pending: number;\n /** Total tasks (active + pending). */\n readonly size: number;\n}\n\nexport function queue(options: { concurrency?: number } = {}): Queue {\n const { concurrency = 1 } = options;\n\n if (concurrency < 1) throw new ArsenalValidationError('Concurrency must be at least 1');\n\n let activeCount = 0;\n let isDraining = false;\n let idlePromise: Promise<void> | null = null;\n let idleResolve: (() => void) | null = null;\n\n const tasks: Array<{\n fn: () => Promise<unknown>;\n priority: number;\n reject: (error: unknown) => void;\n resolve: (value: unknown) => void;\n }> = [];\n\n const settledListeners = new Set<QueueSettledCallback>();\n\n const resolveIdle = (): void => {\n if (activeCount === 0 && tasks.length === 0 && idleResolve) {\n idleResolve();\n idlePromise = null;\n idleResolve = null;\n }\n };\n\n const notifySettled = (result: AttemptResult<unknown>): void => {\n for (const cb of settledListeners) {\n cb(result);\n }\n };\n\n const drain = (): void => {\n if (isDraining) {\n return;\n }\n\n isDraining = true;\n\n while (activeCount < concurrency && tasks.length > 0) {\n const task = tasks.shift()!;\n\n activeCount++;\n\n void Promise.resolve()\n .then(() => task.fn())\n .then((v) => {\n notifySettled({ ok: true, value: v });\n task.resolve(v);\n })\n .catch((e: unknown) => {\n notifySettled({ error: e, ok: false });\n task.reject(e);\n })\n .finally(() => {\n activeCount--;\n drain();\n resolveIdle();\n });\n }\n\n isDraining = false;\n resolveIdle();\n };\n\n return {\n /**\n * Returns the number of currently running tasks.\n */\n get active(): number {\n return activeCount;\n },\n\n /**\n * Adds a promise-returning function to the queue.\n * Tasks with a higher `priority` number run before lower-priority tasks.\n * Tasks with equal priority run in insertion order (FIFO).\n *\n * @param fn - The async function to queue.\n * @param options.priority - Task priority. Higher numbers run first. Default: 0.\n */\n add: <T>(fn: () => Promise<T>, options?: { priority?: number }): Promise<T> => {\n const { promise, reject, resolve } = Promise.withResolvers<T>();\n const priority = options?.priority ?? 0;\n\n const task = {\n fn: fn as () => Promise<unknown>,\n priority,\n reject,\n resolve: resolve as (value: unknown) => void,\n };\n\n let i = tasks.length;\n\n while (i > 0 && tasks[i - 1]!.priority < priority) {\n i--;\n }\n\n tasks.splice(i, 0, task);\n drain();\n\n return promise;\n },\n\n /**\n * Clears all pending tasks from the queue and rejects them.\n * Running tasks are not affected.\n * @param reason - The error reason for the rejection (defaults to 'Queue cleared')\n */\n clear: (reason?: unknown): void => {\n const clearReason = reason ?? new Error('Queue cleared');\n\n for (const task of tasks.splice(0)) {\n task.reject(clearReason);\n }\n\n resolveIdle();\n },\n\n /**\n * Returns a promise that resolves when the queue becomes idle.\n */\n onIdle: (): Promise<void> => {\n if (activeCount === 0 && tasks.length === 0) {\n return Promise.resolve();\n }\n\n if (!idlePromise) {\n const deferred = Promise.withResolvers<void>();\n\n idlePromise = deferred.promise;\n idleResolve = deferred.resolve;\n }\n\n return idlePromise;\n },\n\n /**\n * Subscribes to settled task results (both resolved and rejected).\n * The callback fires once per task, in completion order.\n * Returns an unsubscribe function.\n *\n * Unlike a `for await` loop, multiple subscribers are supported and\n * no results are accumulated in memory.\n *\n * @example\n * ```ts\n * const q = queue({ concurrency: 2 });\n * const unsub = q.onSettled((result) => {\n * if (result.ok) console.log(result.value);\n * else console.error(result.error);\n * });\n *\n * q.add(() => fetchUser(1));\n * q.add(() => fetchUser(2));\n *\n * await q.onIdle();\n * unsub(); // stop listening\n * ```\n */\n onSettled: <T = unknown>(cb: QueueSettledCallback<T>): (() => void) => {\n settledListeners.add(cb as QueueSettledCallback);\n\n return () => {\n settledListeners.delete(cb as QueueSettledCallback);\n };\n },\n\n /**\n * Returns the number of tasks waiting to run (queued but not yet started).\n */\n get pending(): number {\n return tasks.length;\n },\n\n /**\n * Returns the total number of tasks (active + pending).\n */\n get size(): number {\n return activeCount + tasks.length;\n },\n };\n}\n"],"mappings":"iCAyCA,SAAgB,EAAM,EAAoC,CAAC,EAAU,CACnE,GAAM,CAAE,cAAc,GAAM,EAE5B,GAAI,EAAc,EAAG,MAAM,IAAI,EAAA,uBAAuB,gCAAgC,EAEtF,IAAI,EAAc,EACd,EAAa,GACb,EAAoC,KACpC,EAAmC,KAEjC,EAKD,CAAC,EAEA,EAAmB,IAAI,IAEvB,MAA0B,CAC1B,IAAgB,GAAK,EAAM,SAAW,GAAK,IAC7C,EAAY,EACZ,EAAc,KACd,EAAc,KAElB,EAEM,EAAiB,GAAyC,CAC9D,IAAK,IAAM,KAAM,EACf,EAAG,CAAM,CAEb,EAEM,MAAoB,CACpB,MAMJ,KAFA,EAAa,GAEN,EAAc,GAAe,EAAM,OAAS,GAAG,CACpD,IAAM,EAAO,EAAM,MAAM,EAEzB,IAEA,QAAa,QAAQ,CAAC,CACnB,SAAW,EAAK,GAAG,CAAC,CAAC,CACrB,KAAM,GAAM,CACX,EAAc,CAAE,GAAI,GAAM,MAAO,CAAE,CAAC,EACpC,EAAK,QAAQ,CAAC,CAChB,CAAC,CAAC,CACD,MAAO,GAAe,CACrB,EAAc,CAAE,MAAO,EAAG,GAAI,EAAM,CAAC,EACrC,EAAK,OAAO,CAAC,CACf,CAAC,CAAC,CACD,YAAc,CACb,IACA,EAAM,EACN,EAAY,CACd,CAAC,CACL,CAEA,EAAa,GACb,EAAY,CAHZ,CAIF,EAEA,MAAO,CAIL,IAAI,QAAiB,CACnB,OAAO,CACT,EAUA,KAAS,EAAsB,IAAgD,CAC7E,GAAM,CAAE,UAAS,SAAQ,WAAY,QAAQ,cAAiB,EACxD,EAAW,GAAS,UAAY,EAEhC,EAAO,CACP,KACJ,WACA,SACS,SACX,EAEI,EAAI,EAAM,OAEd,KAAO,EAAI,GAAK,EAAM,EAAI,EAAE,CAAE,SAAW,GACvC,IAMF,OAHA,EAAM,OAAO,EAAG,EAAG,CAAI,EACvB,EAAM,EAEC,CACT,EAOA,MAAQ,GAA2B,CACjC,IAAM,EAAc,GAAc,MAAM,eAAe,EAEvD,IAAK,IAAM,KAAQ,EAAM,OAAO,CAAC,EAC/B,EAAK,OAAO,CAAW,EAGzB,EAAY,CACd,EAKA,WAA6B,CAC3B,GAAI,IAAgB,GAAK,EAAM,SAAW,EACxC,OAAO,QAAQ,QAAQ,EAGzB,GAAI,CAAC,EAAa,CAChB,IAAM,EAAW,QAAQ,cAAoB,EAE7C,EAAc,EAAS,QACvB,EAAc,EAAS,OACzB,CAEA,OAAO,CACT,EAyBA,UAAyB,IACvB,EAAiB,IAAI,CAA0B,MAElC,CACX,EAAiB,OAAO,CAA0B,CACpD,GAMF,IAAI,SAAkB,CACpB,OAAO,EAAM,MACf,EAKA,IAAI,MAAe,CACjB,OAAO,EAAc,EAAM,MAC7B,CACF,CACF"}
@@ -1,42 +0,0 @@
1
- import type { AttemptResult } from './attempt';
2
- /**
3
- * Creates a promise queue that processes promises sequentially with optional concurrency limit.
4
- *
5
- * @example
6
- * ```ts
7
- * const requestQueue = queue({ concurrency: 2 });
8
- *
9
- * requestQueue.add(() => fetch('/api/1'));
10
- * requestQueue.add(() => fetch('/api/2'));
11
- * requestQueue.add(() => fetch('/api/3'));
12
- *
13
- * await requestQueue.onIdle(); // Wait for all tasks to complete
14
- * ```
15
- *
16
- * @param options - Queue configuration
17
- * @param options.concurrency - Maximum number of concurrent promises (default: 1)
18
- * @returns Queue instance with add, onIdle, clear, and onSettled methods
19
- */
20
- export type QueueSettledCallback<T = unknown> = (result: AttemptResult<T>) => void;
21
- export interface Queue {
22
- /** Adds a task to the queue. Returns a promise that resolves/rejects with the task result. */
23
- add<T>(fn: () => Promise<T>, options?: {
24
- priority?: number;
25
- }): Promise<T>;
26
- /** Clears all pending tasks, rejecting them with the given reason. Running tasks are unaffected. */
27
- clear(reason?: unknown): void;
28
- /** Returns a promise that resolves when the queue becomes idle (no active or pending tasks). */
29
- onIdle(): Promise<void>;
30
- /** Subscribes to settled results (both resolved and rejected). Returns an unsubscribe function. */
31
- onSettled<T>(cb: QueueSettledCallback<T>): () => void;
32
- /** Number of currently running tasks. */
33
- readonly active: number;
34
- /** Number of tasks waiting to run. */
35
- readonly pending: number;
36
- /** Total tasks (active + pending). */
37
- readonly size: number;
38
- }
39
- export declare function queue(options?: {
40
- concurrency?: number;
41
- }): Queue;
42
- //# sourceMappingURL=queue.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"queue.d.ts","sourceRoot":"","sources":["../../src/async/queue.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAI/C;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,MAAM,oBAAoB,CAAC,CAAC,GAAG,OAAO,IAAI,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC;AAEnF,MAAM,WAAW,KAAK;IACpB,8FAA8F;IAC9F,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IAC1E,oGAAoG;IACpG,KAAK,CAAC,MAAM,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IAC9B,gGAAgG;IAChG,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACxB,mGAAmG;IACnG,SAAS,CAAC,CAAC,EAAE,EAAE,EAAE,oBAAoB,CAAC,CAAC,CAAC,GAAG,MAAM,IAAI,CAAC;IACtD,yCAAyC;IACzC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,sCAAsC;IACtC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,sCAAsC;IACtC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED,wBAAgB,KAAK,CAAC,OAAO,GAAE;IAAE,WAAW,CAAC,EAAE,MAAM,CAAA;CAAO,GAAG,KAAK,CAuLnE"}
@@ -1,72 +0,0 @@
1
- import { ArsenalValidationError as e } from "../errors.js";
2
- //#region src/async/queue.ts
3
- function t(t = {}) {
4
- let { concurrency: n = 1 } = t;
5
- if (n < 1) throw new e("Concurrency must be at least 1");
6
- let r = 0, i = !1, a = null, o = null, s = [], c = /* @__PURE__ */ new Set(), l = () => {
7
- r === 0 && s.length === 0 && o && (o(), a = null, o = null);
8
- }, u = (e) => {
9
- for (let t of c) t(e);
10
- }, d = () => {
11
- if (!i) {
12
- for (i = !0; r < n && s.length > 0;) {
13
- let e = s.shift();
14
- r++, Promise.resolve().then(() => e.fn()).then((t) => {
15
- u({
16
- ok: !0,
17
- value: t
18
- }), e.resolve(t);
19
- }).catch((t) => {
20
- u({
21
- error: t,
22
- ok: !1
23
- }), e.reject(t);
24
- }).finally(() => {
25
- r--, d(), l();
26
- });
27
- }
28
- i = !1, l();
29
- }
30
- };
31
- return {
32
- get active() {
33
- return r;
34
- },
35
- add: (e, t) => {
36
- let { promise: n, reject: r, resolve: i } = Promise.withResolvers(), a = t?.priority ?? 0, o = {
37
- fn: e,
38
- priority: a,
39
- reject: r,
40
- resolve: i
41
- }, c = s.length;
42
- for (; c > 0 && s[c - 1].priority < a;) c--;
43
- return s.splice(c, 0, o), d(), n;
44
- },
45
- clear: (e) => {
46
- let t = e ?? /* @__PURE__ */ Error("Queue cleared");
47
- for (let e of s.splice(0)) e.reject(t);
48
- l();
49
- },
50
- onIdle: () => {
51
- if (r === 0 && s.length === 0) return Promise.resolve();
52
- if (!a) {
53
- let e = Promise.withResolvers();
54
- a = e.promise, o = e.resolve;
55
- }
56
- return a;
57
- },
58
- onSettled: (e) => (c.add(e), () => {
59
- c.delete(e);
60
- }),
61
- get pending() {
62
- return s.length;
63
- },
64
- get size() {
65
- return r + s.length;
66
- }
67
- };
68
- }
69
- //#endregion
70
- export { t as queue };
71
-
72
- //# sourceMappingURL=queue.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"queue.js","names":[],"sources":["../../src/async/queue.ts"],"sourcesContent":["import type { AttemptResult } from './attempt';\n\nimport { ArsenalValidationError } from '../errors';\n\n/**\n * Creates a promise queue that processes promises sequentially with optional concurrency limit.\n *\n * @example\n * ```ts\n * const requestQueue = queue({ concurrency: 2 });\n *\n * requestQueue.add(() => fetch('/api/1'));\n * requestQueue.add(() => fetch('/api/2'));\n * requestQueue.add(() => fetch('/api/3'));\n *\n * await requestQueue.onIdle(); // Wait for all tasks to complete\n * ```\n *\n * @param options - Queue configuration\n * @param options.concurrency - Maximum number of concurrent promises (default: 1)\n * @returns Queue instance with add, onIdle, clear, and onSettled methods\n */\nexport type QueueSettledCallback<T = unknown> = (result: AttemptResult<T>) => void;\n\nexport interface Queue {\n /** Adds a task to the queue. Returns a promise that resolves/rejects with the task result. */\n add<T>(fn: () => Promise<T>, options?: { priority?: number }): Promise<T>;\n /** Clears all pending tasks, rejecting them with the given reason. Running tasks are unaffected. */\n clear(reason?: unknown): void;\n /** Returns a promise that resolves when the queue becomes idle (no active or pending tasks). */\n onIdle(): Promise<void>;\n /** Subscribes to settled results (both resolved and rejected). Returns an unsubscribe function. */\n onSettled<T>(cb: QueueSettledCallback<T>): () => void;\n /** Number of currently running tasks. */\n readonly active: number;\n /** Number of tasks waiting to run. */\n readonly pending: number;\n /** Total tasks (active + pending). */\n readonly size: number;\n}\n\nexport function queue(options: { concurrency?: number } = {}): Queue {\n const { concurrency = 1 } = options;\n\n if (concurrency < 1) throw new ArsenalValidationError('Concurrency must be at least 1');\n\n let activeCount = 0;\n let isDraining = false;\n let idlePromise: Promise<void> | null = null;\n let idleResolve: (() => void) | null = null;\n\n const tasks: Array<{\n fn: () => Promise<unknown>;\n priority: number;\n reject: (error: unknown) => void;\n resolve: (value: unknown) => void;\n }> = [];\n\n const settledListeners = new Set<QueueSettledCallback>();\n\n const resolveIdle = (): void => {\n if (activeCount === 0 && tasks.length === 0 && idleResolve) {\n idleResolve();\n idlePromise = null;\n idleResolve = null;\n }\n };\n\n const notifySettled = (result: AttemptResult<unknown>): void => {\n for (const cb of settledListeners) {\n cb(result);\n }\n };\n\n const drain = (): void => {\n if (isDraining) {\n return;\n }\n\n isDraining = true;\n\n while (activeCount < concurrency && tasks.length > 0) {\n const task = tasks.shift()!;\n\n activeCount++;\n\n void Promise.resolve()\n .then(() => task.fn())\n .then((v) => {\n notifySettled({ ok: true, value: v });\n task.resolve(v);\n })\n .catch((e: unknown) => {\n notifySettled({ error: e, ok: false });\n task.reject(e);\n })\n .finally(() => {\n activeCount--;\n drain();\n resolveIdle();\n });\n }\n\n isDraining = false;\n resolveIdle();\n };\n\n return {\n /**\n * Returns the number of currently running tasks.\n */\n get active(): number {\n return activeCount;\n },\n\n /**\n * Adds a promise-returning function to the queue.\n * Tasks with a higher `priority` number run before lower-priority tasks.\n * Tasks with equal priority run in insertion order (FIFO).\n *\n * @param fn - The async function to queue.\n * @param options.priority - Task priority. Higher numbers run first. Default: 0.\n */\n add: <T>(fn: () => Promise<T>, options?: { priority?: number }): Promise<T> => {\n const { promise, reject, resolve } = Promise.withResolvers<T>();\n const priority = options?.priority ?? 0;\n\n const task = {\n fn: fn as () => Promise<unknown>,\n priority,\n reject,\n resolve: resolve as (value: unknown) => void,\n };\n\n let i = tasks.length;\n\n while (i > 0 && tasks[i - 1]!.priority < priority) {\n i--;\n }\n\n tasks.splice(i, 0, task);\n drain();\n\n return promise;\n },\n\n /**\n * Clears all pending tasks from the queue and rejects them.\n * Running tasks are not affected.\n * @param reason - The error reason for the rejection (defaults to 'Queue cleared')\n */\n clear: (reason?: unknown): void => {\n const clearReason = reason ?? new Error('Queue cleared');\n\n for (const task of tasks.splice(0)) {\n task.reject(clearReason);\n }\n\n resolveIdle();\n },\n\n /**\n * Returns a promise that resolves when the queue becomes idle.\n */\n onIdle: (): Promise<void> => {\n if (activeCount === 0 && tasks.length === 0) {\n return Promise.resolve();\n }\n\n if (!idlePromise) {\n const deferred = Promise.withResolvers<void>();\n\n idlePromise = deferred.promise;\n idleResolve = deferred.resolve;\n }\n\n return idlePromise;\n },\n\n /**\n * Subscribes to settled task results (both resolved and rejected).\n * The callback fires once per task, in completion order.\n * Returns an unsubscribe function.\n *\n * Unlike a `for await` loop, multiple subscribers are supported and\n * no results are accumulated in memory.\n *\n * @example\n * ```ts\n * const q = queue({ concurrency: 2 });\n * const unsub = q.onSettled((result) => {\n * if (result.ok) console.log(result.value);\n * else console.error(result.error);\n * });\n *\n * q.add(() => fetchUser(1));\n * q.add(() => fetchUser(2));\n *\n * await q.onIdle();\n * unsub(); // stop listening\n * ```\n */\n onSettled: <T = unknown>(cb: QueueSettledCallback<T>): (() => void) => {\n settledListeners.add(cb as QueueSettledCallback);\n\n return () => {\n settledListeners.delete(cb as QueueSettledCallback);\n };\n },\n\n /**\n * Returns the number of tasks waiting to run (queued but not yet started).\n */\n get pending(): number {\n return tasks.length;\n },\n\n /**\n * Returns the total number of tasks (active + pending).\n */\n get size(): number {\n return activeCount + tasks.length;\n },\n };\n}\n"],"mappings":";;AAyCA,SAAgB,EAAM,IAAoC,CAAC,GAAU;CACnE,IAAM,EAAE,iBAAc,MAAM;CAE5B,IAAI,IAAc,GAAG,MAAM,IAAI,EAAuB,gCAAgC;CAEtF,IAAI,IAAc,GACd,IAAa,IACb,IAAoC,MACpC,IAAmC,MAEjC,IAKD,CAAC,GAEA,oBAAmB,IAAI,IAA0B,GAEjD,UAA0B;EAC9B,AAAI,MAAgB,KAAK,EAAM,WAAW,KAAK,MAC7C,EAAY,GACZ,IAAc,MACd,IAAc;CAElB,GAEM,KAAiB,MAAyC;EAC9D,KAAK,IAAM,KAAM,GACf,EAAG,CAAM;CAEb,GAEM,UAAoB;EACpB,QAMJ;QAFA,IAAa,IAEN,IAAc,KAAe,EAAM,SAAS,IAAG;IACpD,IAAM,IAAO,EAAM,MAAM;IAIzB,AAFA,KAEA,QAAa,QAAQ,CAAC,CACnB,WAAW,EAAK,GAAG,CAAC,CAAC,CACrB,MAAM,MAAM;KAEX,AADA,EAAc;MAAE,IAAI;MAAM,OAAO;KAAE,CAAC,GACpC,EAAK,QAAQ,CAAC;IAChB,CAAC,CAAC,CACD,OAAO,MAAe;KAErB,AADA,EAAc;MAAE,OAAO;MAAG,IAAI;KAAM,CAAC,GACrC,EAAK,OAAO,CAAC;IACf,CAAC,CAAC,CACD,cAAc;KAGb,AAFA,KACA,EAAM,GACN,EAAY;IACd,CAAC;GACL;GAGA,AADA,IAAa,IACb,EAAY;EAHZ;CAIF;CAEA,OAAO;EAIL,IAAI,SAAiB;GACnB,OAAO;EACT;EAUA,MAAS,GAAsB,MAAgD;GAC7E,IAAM,EAAE,YAAS,WAAQ,eAAY,QAAQ,cAAiB,GACxD,IAAW,GAAS,YAAY,GAEhC,IAAO;IACP;IACJ;IACA;IACS;GACX,GAEI,IAAI,EAAM;GAEd,OAAO,IAAI,KAAK,EAAM,IAAI,EAAE,CAAE,WAAW,IACvC;GAMF,OAHA,EAAM,OAAO,GAAG,GAAG,CAAI,GACvB,EAAM,GAEC;EACT;EAOA,QAAQ,MAA2B;GACjC,IAAM,IAAc,KAAU,gBAAI,MAAM,eAAe;GAEvD,KAAK,IAAM,KAAQ,EAAM,OAAO,CAAC,GAC/B,EAAK,OAAO,CAAW;GAGzB,EAAY;EACd;EAKA,cAA6B;GAC3B,IAAI,MAAgB,KAAK,EAAM,WAAW,GACxC,OAAO,QAAQ,QAAQ;GAGzB,IAAI,CAAC,GAAa;IAChB,IAAM,IAAW,QAAQ,cAAoB;IAG7C,AADA,IAAc,EAAS,SACvB,IAAc,EAAS;GACzB;GAEA,OAAO;EACT;EAyBA,YAAyB,OACvB,EAAiB,IAAI,CAA0B,SAElC;GACX,EAAiB,OAAO,CAA0B;EACpD;EAMF,IAAI,UAAkB;GACpB,OAAO,EAAM;EACf;EAKA,IAAI,OAAe;GACjB,OAAO,IAAc,EAAM;EAC7B;CACF;AACF"}
@@ -1,2 +0,0 @@
1
- const e=require("../errors.cjs"),t=require("../guards/isPromise.cjs");function n(n={}){let r=n.maxSize??1/0;if(r!==1/0&&(!Number.isInteger(r)||r<1))throw new e.ArsenalValidationError(`stash: maxSize must be a positive integer or Infinity, got ${r}`);let i=new Map,a=new Map,o=new Map,s=n.hash??(e=>String(e)),c=n.onEvict,l=n.ttlMs,u=n.persistence,d=0,f=new Set;function p(){if(i.size>r){let[e]=i.keys();e!==void 0&&h(e)}}function m(e){let t=a.get(e);t!==void 0&&(clearTimeout(t),a.delete(e))}function h(e){let t=i.get(e);return m(e),t&&(c?.(t.key,t.value),i.delete(e)),o.has(e)&&f.add(e),t!==void 0}function g(t,n){if(m(t),n===1/0)return;if(!Number.isFinite(n))throw new e.ArsenalValidationError(`stash: ttlMs must be a finite number or Infinity`);if(n<=0){h(t);return}if(!i.has(t))return;let r=setTimeout(()=>{a.delete(t),h(t)},n);a.set(t,r)}function _(e){return u&&typeof e==`string`?u.deserialize(e):e}function v(e){let t=i.get(s(e));return t?_(t.value):void 0}function y(e,t,n){let r=s(e),a=u?u.serialize(t):t;m(r),i.set(r,{key:e,value:a}),p();let o=n?.ttlMs??l;o!==void 0&&g(r,o)}function b(e,n,r){let a=s(e);if(i.has(a)&&!r?.forceRefresh)return v(e);let c=o.get(a);if(c&&!r?.forceRefresh)return c;let l=n();if(t.isPromise(l)){let t=d,n=l.then(i=>(o.get(a)===n&&o.delete(a),d===t&&!f.has(a)&&y(e,i,r),f.delete(a),i)).catch(e=>{throw o.get(a)===n&&o.delete(a),f.delete(a),e});return o.set(a,n),n}return y(e,l,r),l}function x(e){return h(s(e))}function S(){d++;for(let e of a.values())clearTimeout(e);if(c)for(let e of i.values())c(e.key,e.value);i.clear(),a.clear(),o.clear(),f.clear()}function*C(){for(let e of i.values())yield[e.key,_(e.value)]}return{clear:S,delete:x,entries:C,get:v,getOrSet:b,set:y,get size(){return i.size}}}exports.stash=n;
2
- //# sourceMappingURL=stash.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"stash.cjs","names":[],"sources":["../../src/cache/stash.ts"],"sourcesContent":["import { ArsenalValidationError } from '../errors';\nimport { isPromise } from '../guards/isPromise';\n\ntype CacheRecord<K, T> = {\n key: K;\n value: T;\n};\n\nexport type CachePersistence<T> = {\n /** Deserializes a stored string back into a value of type `T`. */\n deserialize: (raw: string) => T;\n /** Serializes a value to a string for internal storage. */\n serialize: (value: T) => string;\n};\n\nexport type CacheOptions<K = string, T = unknown> = {\n /**\n * Converts a key to its canonical string representation for internal storage.\n * Defaults to `String(key)` — suitable for all string, number, and symbol keys.\n * Provide a custom function for object keys or composite keys.\n */\n hash?: (key: K) => string;\n /**\n * Maximum number of entries to hold. When the store reaches capacity, the oldest\n * entry is evicted (FIFO) before inserting the new one. `onEvict` is called on\n * capacity evictions just like TTL evictions.\n *\n * Default: `Infinity` (unbounded).\n */\n maxSize?: number;\n onEvict?: (key: K, value: T) => void;\n /**\n * Optional serialization pair for persistent caches (e.g. localStorage, cross-process IPC).\n * Both `serialize` and `deserialize` must be provided together.\n *\n * @example\n * ```ts\n * const cache = stash<User>({\n * persistence: {\n * serialize: (u) => JSON.stringify(u),\n * deserialize: (raw) => JSON.parse(raw) as User,\n * },\n * });\n * ```\n */\n persistence?: CachePersistence<T>;\n /**\n * Default time-to-live for all entries in milliseconds.\n * Applied automatically to every `set()` and `getOrSet()` call unless\n * overridden per-entry via `CacheSetOptions.ttlMs`.\n *\n * Default: `undefined` (entries do not expire).\n */\n ttlMs?: number;\n};\n\nexport type CacheSetOptions = {\n /**\n * When `true`, bypasses both the cache and any in-flight promise for this key,\n * and always calls the factory. The new value replaces the old cache entry.\n * **Note:** if a prior in-flight is still pending when `forceRefresh` resolves,\n * whichever `.then` runs last will write the cache slot — ensure prior in-flight\n * tasks have settled if ordering matters.\n */\n forceRefresh?: boolean;\n ttlMs?: number;\n};\n\nexport type Stash<T, K = string> = {\n clear: () => void;\n delete: (key: K) => boolean;\n entries: () => IterableIterator<[K, T]>;\n get: (key: K) => T | undefined;\n /**\n * Returns the cached value for `key`, or invokes `factory` to produce and cache it.\n * Pass `{ forceRefresh: true }` to skip the cache and always call `factory`.\n */\n getOrSet(key: K, factory: () => T, options?: CacheSetOptions): T;\n getOrSet(key: K, factory: () => Promise<T>, options?: CacheSetOptions): Promise<T>;\n set: (key: K, value: T, options?: CacheSetOptions) => void;\n readonly size: number;\n};\n\n/**\n * Creates a generic key-value cache with TTL-based garbage collection, optional capacity\n * limit (FIFO eviction), async stampede prevention, and optional eviction callback.\n *\n * This is the single caching primitive in arsenal — use it for simple bounded caches,\n * TTL caches, or async deduplication/stampede prevention.\n *\n * @example\n * ```ts\n * // Simple string cache — no options needed for string keys\n * const myCache = stash<string>();\n * myCache.set('user:1', 'John Doe');\n * const value = myCache.get('user:1'); // 'John Doe'\n *\n * // Global TTL — all entries expire after 60 seconds unless overridden\n * const apiCache = stash<Response>({ ttlMs: 60_000 });\n * apiCache.set('data', response); // expires in 60s\n * apiCache.set('data', response, { ttlMs: 5_000 }); // override: expires in 5s\n *\n * // Async getOrSet prevents stampedes — concurrent callers share one in-flight promise\n * const user = await myCache.getOrSet('user:1', () => fetchUser(1));\n *\n * // Bounded FIFO cache\n * const fmtCache = stash<Intl.NumberFormat>({ maxSize: 64 });\n * const fmt = fmtCache.getOrSet('en-US', () => new Intl.NumberFormat('en-US'));\n *\n * // Custom key type — provide a hash function\n * const objCache = stash<Result, { id: number }>({ hash: (k) => String(k.id) });\n *\n * // Note: `undefined` is a valid cached value — if a key is set to `undefined`,\n * // `getOrSet` returns it without invoking the factory again.\n * ```\n *\n * @template T - The type of values stored in the cache.\n * @template K - The key type. Defaults to `string`.\n *\n * @throws {ArsenalValidationError} If `options.maxSize` is provided and is not a positive integer or `Infinity`.\n */\nexport function stash<T, K = string>(options: CacheOptions<K, T> = {}): Stash<T, K> {\n const maxSize = options.maxSize ?? Infinity;\n\n if (maxSize !== Infinity && (!Number.isInteger(maxSize) || maxSize < 1)) {\n throw new ArsenalValidationError(`stash: maxSize must be a positive integer or Infinity, got ${maxSize}`);\n }\n\n const store = new Map<string, CacheRecord<K, T>>();\n const gcTimers = new Map<string, ReturnType<typeof setTimeout>>();\n const inFlight = new Map<string, Promise<T>>();\n const hash = options.hash ?? ((key: K) => String(key));\n const onEvict = options.onEvict;\n const defaultTtlMs = options.ttlMs;\n const persistence = options.persistence;\n let generation = 0;\n const deletedWhileInFlight = new Set<string>();\n\n function evictOldestIfOverCapacity(): void {\n if (store.size > maxSize) {\n const [firstHash] = store.keys();\n\n if (firstHash !== undefined) {\n deleteByHash(firstHash);\n }\n }\n }\n\n function cancelGcByHash(keyHash: string): void {\n const id = gcTimers.get(keyHash);\n\n if (id !== undefined) {\n clearTimeout(id);\n gcTimers.delete(keyHash);\n }\n }\n\n function deleteByHash(keyHash: string): boolean {\n const record = store.get(keyHash);\n\n cancelGcByHash(keyHash);\n\n if (record) {\n onEvict?.(record.key, record.value);\n store.delete(keyHash);\n }\n\n if (inFlight.has(keyHash)) deletedWhileInFlight.add(keyHash);\n\n return record !== undefined;\n }\n\n function scheduleGcByHash(keyHash: string, delayMs: number): void {\n cancelGcByHash(keyHash);\n\n if (delayMs === Number.POSITIVE_INFINITY) return;\n\n if (!Number.isFinite(delayMs)) {\n throw new ArsenalValidationError('stash: ttlMs must be a finite number or Infinity');\n }\n\n if (delayMs <= 0) {\n deleteByHash(keyHash);\n\n return;\n }\n\n if (!store.has(keyHash)) return;\n\n const id = setTimeout(() => {\n gcTimers.delete(keyHash);\n deleteByHash(keyHash);\n }, delayMs);\n\n gcTimers.set(keyHash, id);\n }\n\n function deserializeValue(raw: T): T {\n if (persistence && typeof raw === 'string') return persistence.deserialize(raw);\n\n return raw;\n }\n\n function get(key: K): T | undefined {\n const record = store.get(hash(key));\n\n return record ? deserializeValue(record.value) : undefined;\n }\n\n function set(key: K, value: T, opts?: CacheSetOptions): void {\n const keyHash = hash(key);\n const stored = persistence ? (persistence.serialize(value) as unknown as T) : value;\n\n cancelGcByHash(keyHash);\n store.set(keyHash, { key, value: stored });\n evictOldestIfOverCapacity();\n\n const ttl = opts?.ttlMs ?? defaultTtlMs;\n\n if (ttl !== undefined) {\n scheduleGcByHash(keyHash, ttl);\n }\n }\n\n function getOrSet(key: K, factory: () => T | Promise<T>, opts?: CacheSetOptions): T | Promise<T> {\n const keyHash = hash(key);\n\n if (store.has(keyHash) && !opts?.forceRefresh) return get(key) as T;\n\n const pending = inFlight.get(keyHash);\n\n if (pending && !opts?.forceRefresh) return pending;\n\n const value = factory();\n\n if (isPromise(value)) {\n const capturedGeneration = generation;\n const promise: Promise<T> = value\n .then((resolved) => {\n // Only clear the in-flight slot if it's still *this* promise — an overlapping\n // `forceRefresh` call may have already replaced it with a newer in-flight promise.\n if (inFlight.get(keyHash) === promise) inFlight.delete(keyHash);\n\n if (generation === capturedGeneration && !deletedWhileInFlight.has(keyHash)) {\n set(key, resolved, opts);\n }\n\n deletedWhileInFlight.delete(keyHash);\n\n return resolved;\n })\n .catch((err: unknown) => {\n if (inFlight.get(keyHash) === promise) inFlight.delete(keyHash);\n\n deletedWhileInFlight.delete(keyHash);\n throw err;\n });\n\n inFlight.set(keyHash, promise);\n\n return promise;\n }\n\n set(key, value, opts);\n\n return value;\n }\n\n function del(key: K): boolean {\n return deleteByHash(hash(key));\n }\n\n function clear(): void {\n generation++;\n for (const id of gcTimers.values()) clearTimeout(id);\n\n if (onEvict) {\n for (const record of store.values()) {\n onEvict(record.key, record.value);\n }\n }\n\n store.clear();\n gcTimers.clear();\n inFlight.clear();\n deletedWhileInFlight.clear();\n }\n\n function* entries(): IterableIterator<[K, T]> {\n for (const record of store.values()) {\n yield [record.key, deserializeValue(record.value)];\n }\n }\n\n return {\n clear,\n delete: del,\n entries,\n get,\n getOrSet: getOrSet as Stash<T, K>['getOrSet'],\n set,\n get size() {\n return store.size;\n },\n };\n}\n"],"mappings":"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"}
@@ -1,111 +0,0 @@
1
- export type CachePersistence<T> = {
2
- /** Deserializes a stored string back into a value of type `T`. */
3
- deserialize: (raw: string) => T;
4
- /** Serializes a value to a string for internal storage. */
5
- serialize: (value: T) => string;
6
- };
7
- export type CacheOptions<K = string, T = unknown> = {
8
- /**
9
- * Converts a key to its canonical string representation for internal storage.
10
- * Defaults to `String(key)` — suitable for all string, number, and symbol keys.
11
- * Provide a custom function for object keys or composite keys.
12
- */
13
- hash?: (key: K) => string;
14
- /**
15
- * Maximum number of entries to hold. When the store reaches capacity, the oldest
16
- * entry is evicted (FIFO) before inserting the new one. `onEvict` is called on
17
- * capacity evictions just like TTL evictions.
18
- *
19
- * Default: `Infinity` (unbounded).
20
- */
21
- maxSize?: number;
22
- onEvict?: (key: K, value: T) => void;
23
- /**
24
- * Optional serialization pair for persistent caches (e.g. localStorage, cross-process IPC).
25
- * Both `serialize` and `deserialize` must be provided together.
26
- *
27
- * @example
28
- * ```ts
29
- * const cache = stash<User>({
30
- * persistence: {
31
- * serialize: (u) => JSON.stringify(u),
32
- * deserialize: (raw) => JSON.parse(raw) as User,
33
- * },
34
- * });
35
- * ```
36
- */
37
- persistence?: CachePersistence<T>;
38
- /**
39
- * Default time-to-live for all entries in milliseconds.
40
- * Applied automatically to every `set()` and `getOrSet()` call unless
41
- * overridden per-entry via `CacheSetOptions.ttlMs`.
42
- *
43
- * Default: `undefined` (entries do not expire).
44
- */
45
- ttlMs?: number;
46
- };
47
- export type CacheSetOptions = {
48
- /**
49
- * When `true`, bypasses both the cache and any in-flight promise for this key,
50
- * and always calls the factory. The new value replaces the old cache entry.
51
- * **Note:** if a prior in-flight is still pending when `forceRefresh` resolves,
52
- * whichever `.then` runs last will write the cache slot — ensure prior in-flight
53
- * tasks have settled if ordering matters.
54
- */
55
- forceRefresh?: boolean;
56
- ttlMs?: number;
57
- };
58
- export type Stash<T, K = string> = {
59
- clear: () => void;
60
- delete: (key: K) => boolean;
61
- entries: () => IterableIterator<[K, T]>;
62
- get: (key: K) => T | undefined;
63
- /**
64
- * Returns the cached value for `key`, or invokes `factory` to produce and cache it.
65
- * Pass `{ forceRefresh: true }` to skip the cache and always call `factory`.
66
- */
67
- getOrSet(key: K, factory: () => T, options?: CacheSetOptions): T;
68
- getOrSet(key: K, factory: () => Promise<T>, options?: CacheSetOptions): Promise<T>;
69
- set: (key: K, value: T, options?: CacheSetOptions) => void;
70
- readonly size: number;
71
- };
72
- /**
73
- * Creates a generic key-value cache with TTL-based garbage collection, optional capacity
74
- * limit (FIFO eviction), async stampede prevention, and optional eviction callback.
75
- *
76
- * This is the single caching primitive in arsenal — use it for simple bounded caches,
77
- * TTL caches, or async deduplication/stampede prevention.
78
- *
79
- * @example
80
- * ```ts
81
- * // Simple string cache — no options needed for string keys
82
- * const myCache = stash<string>();
83
- * myCache.set('user:1', 'John Doe');
84
- * const value = myCache.get('user:1'); // 'John Doe'
85
- *
86
- * // Global TTL — all entries expire after 60 seconds unless overridden
87
- * const apiCache = stash<Response>({ ttlMs: 60_000 });
88
- * apiCache.set('data', response); // expires in 60s
89
- * apiCache.set('data', response, { ttlMs: 5_000 }); // override: expires in 5s
90
- *
91
- * // Async getOrSet prevents stampedes — concurrent callers share one in-flight promise
92
- * const user = await myCache.getOrSet('user:1', () => fetchUser(1));
93
- *
94
- * // Bounded FIFO cache
95
- * const fmtCache = stash<Intl.NumberFormat>({ maxSize: 64 });
96
- * const fmt = fmtCache.getOrSet('en-US', () => new Intl.NumberFormat('en-US'));
97
- *
98
- * // Custom key type — provide a hash function
99
- * const objCache = stash<Result, { id: number }>({ hash: (k) => String(k.id) });
100
- *
101
- * // Note: `undefined` is a valid cached value — if a key is set to `undefined`,
102
- * // `getOrSet` returns it without invoking the factory again.
103
- * ```
104
- *
105
- * @template T - The type of values stored in the cache.
106
- * @template K - The key type. Defaults to `string`.
107
- *
108
- * @throws {ArsenalValidationError} If `options.maxSize` is provided and is not a positive integer or `Infinity`.
109
- */
110
- export declare function stash<T, K = string>(options?: CacheOptions<K, T>): Stash<T, K>;
111
- //# sourceMappingURL=stash.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"stash.d.ts","sourceRoot":"","sources":["../../src/cache/stash.ts"],"names":[],"mappings":"AAQA,MAAM,MAAM,gBAAgB,CAAC,CAAC,IAAI;IAChC,kEAAkE;IAClE,WAAW,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,CAAC,CAAC;IAChC,2DAA2D;IAC3D,SAAS,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,MAAM,CAAC;CACjC,CAAC;AAEF,MAAM,MAAM,YAAY,CAAC,CAAC,GAAG,MAAM,EAAE,CAAC,GAAG,OAAO,IAAI;IAClD;;;;OAIG;IACH,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,MAAM,CAAC;IAC1B;;;;;;OAMG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,KAAK,IAAI,CAAC;IACrC;;;;;;;;;;;;;OAaG;IACH,WAAW,CAAC,EAAE,gBAAgB,CAAC,CAAC,CAAC,CAAC;IAClC;;;;;;OAMG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B;;;;;;OAMG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,MAAM,IAAI;IACjC,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,OAAO,CAAC;IAC5B,OAAO,EAAE,MAAM,gBAAgB,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IACxC,GAAG,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,GAAG,SAAS,CAAC;IAC/B;;;OAGG;IACH,QAAQ,CAAC,GAAG,EAAE,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,CAAC,CAAC;IACjE,QAAQ,CAAC,GAAG,EAAE,CAAC,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IACnF,GAAG,EAAE,CAAC,GAAG,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,CAAC,EAAE,eAAe,KAAK,IAAI,CAAC;IAC3D,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,wBAAgB,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,MAAM,EAAE,OAAO,GAAE,YAAY,CAAC,CAAC,EAAE,CAAC,CAAM,GAAG,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAwLlF"}
@@ -1,92 +0,0 @@
1
- import { ArsenalValidationError as e } from "../errors.js";
2
- import { isPromise as t } from "../guards/isPromise.js";
3
- //#region src/cache/stash.ts
4
- function n(n = {}) {
5
- let r = n.maxSize ?? Infinity;
6
- if (r !== Infinity && (!Number.isInteger(r) || r < 1)) throw new e(`stash: maxSize must be a positive integer or Infinity, got ${r}`);
7
- let i = /* @__PURE__ */ new Map(), a = /* @__PURE__ */ new Map(), o = /* @__PURE__ */ new Map(), s = n.hash ?? ((e) => String(e)), c = n.onEvict, l = n.ttlMs, u = n.persistence, d = 0, f = /* @__PURE__ */ new Set();
8
- function p() {
9
- if (i.size > r) {
10
- let [e] = i.keys();
11
- e !== void 0 && h(e);
12
- }
13
- }
14
- function m(e) {
15
- let t = a.get(e);
16
- t !== void 0 && (clearTimeout(t), a.delete(e));
17
- }
18
- function h(e) {
19
- let t = i.get(e);
20
- return m(e), t && (c?.(t.key, t.value), i.delete(e)), o.has(e) && f.add(e), t !== void 0;
21
- }
22
- function g(t, n) {
23
- if (m(t), n === Infinity) return;
24
- if (!Number.isFinite(n)) throw new e("stash: ttlMs must be a finite number or Infinity");
25
- if (n <= 0) {
26
- h(t);
27
- return;
28
- }
29
- if (!i.has(t)) return;
30
- let r = setTimeout(() => {
31
- a.delete(t), h(t);
32
- }, n);
33
- a.set(t, r);
34
- }
35
- function _(e) {
36
- return u && typeof e == "string" ? u.deserialize(e) : e;
37
- }
38
- function v(e) {
39
- let t = i.get(s(e));
40
- return t ? _(t.value) : void 0;
41
- }
42
- function y(e, t, n) {
43
- let r = s(e), a = u ? u.serialize(t) : t;
44
- m(r), i.set(r, {
45
- key: e,
46
- value: a
47
- }), p();
48
- let o = n?.ttlMs ?? l;
49
- o !== void 0 && g(r, o);
50
- }
51
- function b(e, n, r) {
52
- let a = s(e);
53
- if (i.has(a) && !r?.forceRefresh) return v(e);
54
- let c = o.get(a);
55
- if (c && !r?.forceRefresh) return c;
56
- let l = n();
57
- if (t(l)) {
58
- let t = d, n = l.then((i) => (o.get(a) === n && o.delete(a), d === t && !f.has(a) && y(e, i, r), f.delete(a), i)).catch((e) => {
59
- throw o.get(a) === n && o.delete(a), f.delete(a), e;
60
- });
61
- return o.set(a, n), n;
62
- }
63
- return y(e, l, r), l;
64
- }
65
- function x(e) {
66
- return h(s(e));
67
- }
68
- function S() {
69
- d++;
70
- for (let e of a.values()) clearTimeout(e);
71
- if (c) for (let e of i.values()) c(e.key, e.value);
72
- i.clear(), a.clear(), o.clear(), f.clear();
73
- }
74
- function* C() {
75
- for (let e of i.values()) yield [e.key, _(e.value)];
76
- }
77
- return {
78
- clear: S,
79
- delete: x,
80
- entries: C,
81
- get: v,
82
- getOrSet: b,
83
- set: y,
84
- get size() {
85
- return i.size;
86
- }
87
- };
88
- }
89
- //#endregion
90
- export { n as stash };
91
-
92
- //# sourceMappingURL=stash.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"stash.js","names":[],"sources":["../../src/cache/stash.ts"],"sourcesContent":["import { ArsenalValidationError } from '../errors';\nimport { isPromise } from '../guards/isPromise';\n\ntype CacheRecord<K, T> = {\n key: K;\n value: T;\n};\n\nexport type CachePersistence<T> = {\n /** Deserializes a stored string back into a value of type `T`. */\n deserialize: (raw: string) => T;\n /** Serializes a value to a string for internal storage. */\n serialize: (value: T) => string;\n};\n\nexport type CacheOptions<K = string, T = unknown> = {\n /**\n * Converts a key to its canonical string representation for internal storage.\n * Defaults to `String(key)` — suitable for all string, number, and symbol keys.\n * Provide a custom function for object keys or composite keys.\n */\n hash?: (key: K) => string;\n /**\n * Maximum number of entries to hold. When the store reaches capacity, the oldest\n * entry is evicted (FIFO) before inserting the new one. `onEvict` is called on\n * capacity evictions just like TTL evictions.\n *\n * Default: `Infinity` (unbounded).\n */\n maxSize?: number;\n onEvict?: (key: K, value: T) => void;\n /**\n * Optional serialization pair for persistent caches (e.g. localStorage, cross-process IPC).\n * Both `serialize` and `deserialize` must be provided together.\n *\n * @example\n * ```ts\n * const cache = stash<User>({\n * persistence: {\n * serialize: (u) => JSON.stringify(u),\n * deserialize: (raw) => JSON.parse(raw) as User,\n * },\n * });\n * ```\n */\n persistence?: CachePersistence<T>;\n /**\n * Default time-to-live for all entries in milliseconds.\n * Applied automatically to every `set()` and `getOrSet()` call unless\n * overridden per-entry via `CacheSetOptions.ttlMs`.\n *\n * Default: `undefined` (entries do not expire).\n */\n ttlMs?: number;\n};\n\nexport type CacheSetOptions = {\n /**\n * When `true`, bypasses both the cache and any in-flight promise for this key,\n * and always calls the factory. The new value replaces the old cache entry.\n * **Note:** if a prior in-flight is still pending when `forceRefresh` resolves,\n * whichever `.then` runs last will write the cache slot — ensure prior in-flight\n * tasks have settled if ordering matters.\n */\n forceRefresh?: boolean;\n ttlMs?: number;\n};\n\nexport type Stash<T, K = string> = {\n clear: () => void;\n delete: (key: K) => boolean;\n entries: () => IterableIterator<[K, T]>;\n get: (key: K) => T | undefined;\n /**\n * Returns the cached value for `key`, or invokes `factory` to produce and cache it.\n * Pass `{ forceRefresh: true }` to skip the cache and always call `factory`.\n */\n getOrSet(key: K, factory: () => T, options?: CacheSetOptions): T;\n getOrSet(key: K, factory: () => Promise<T>, options?: CacheSetOptions): Promise<T>;\n set: (key: K, value: T, options?: CacheSetOptions) => void;\n readonly size: number;\n};\n\n/**\n * Creates a generic key-value cache with TTL-based garbage collection, optional capacity\n * limit (FIFO eviction), async stampede prevention, and optional eviction callback.\n *\n * This is the single caching primitive in arsenal — use it for simple bounded caches,\n * TTL caches, or async deduplication/stampede prevention.\n *\n * @example\n * ```ts\n * // Simple string cache — no options needed for string keys\n * const myCache = stash<string>();\n * myCache.set('user:1', 'John Doe');\n * const value = myCache.get('user:1'); // 'John Doe'\n *\n * // Global TTL — all entries expire after 60 seconds unless overridden\n * const apiCache = stash<Response>({ ttlMs: 60_000 });\n * apiCache.set('data', response); // expires in 60s\n * apiCache.set('data', response, { ttlMs: 5_000 }); // override: expires in 5s\n *\n * // Async getOrSet prevents stampedes — concurrent callers share one in-flight promise\n * const user = await myCache.getOrSet('user:1', () => fetchUser(1));\n *\n * // Bounded FIFO cache\n * const fmtCache = stash<Intl.NumberFormat>({ maxSize: 64 });\n * const fmt = fmtCache.getOrSet('en-US', () => new Intl.NumberFormat('en-US'));\n *\n * // Custom key type — provide a hash function\n * const objCache = stash<Result, { id: number }>({ hash: (k) => String(k.id) });\n *\n * // Note: `undefined` is a valid cached value — if a key is set to `undefined`,\n * // `getOrSet` returns it without invoking the factory again.\n * ```\n *\n * @template T - The type of values stored in the cache.\n * @template K - The key type. Defaults to `string`.\n *\n * @throws {ArsenalValidationError} If `options.maxSize` is provided and is not a positive integer or `Infinity`.\n */\nexport function stash<T, K = string>(options: CacheOptions<K, T> = {}): Stash<T, K> {\n const maxSize = options.maxSize ?? Infinity;\n\n if (maxSize !== Infinity && (!Number.isInteger(maxSize) || maxSize < 1)) {\n throw new ArsenalValidationError(`stash: maxSize must be a positive integer or Infinity, got ${maxSize}`);\n }\n\n const store = new Map<string, CacheRecord<K, T>>();\n const gcTimers = new Map<string, ReturnType<typeof setTimeout>>();\n const inFlight = new Map<string, Promise<T>>();\n const hash = options.hash ?? ((key: K) => String(key));\n const onEvict = options.onEvict;\n const defaultTtlMs = options.ttlMs;\n const persistence = options.persistence;\n let generation = 0;\n const deletedWhileInFlight = new Set<string>();\n\n function evictOldestIfOverCapacity(): void {\n if (store.size > maxSize) {\n const [firstHash] = store.keys();\n\n if (firstHash !== undefined) {\n deleteByHash(firstHash);\n }\n }\n }\n\n function cancelGcByHash(keyHash: string): void {\n const id = gcTimers.get(keyHash);\n\n if (id !== undefined) {\n clearTimeout(id);\n gcTimers.delete(keyHash);\n }\n }\n\n function deleteByHash(keyHash: string): boolean {\n const record = store.get(keyHash);\n\n cancelGcByHash(keyHash);\n\n if (record) {\n onEvict?.(record.key, record.value);\n store.delete(keyHash);\n }\n\n if (inFlight.has(keyHash)) deletedWhileInFlight.add(keyHash);\n\n return record !== undefined;\n }\n\n function scheduleGcByHash(keyHash: string, delayMs: number): void {\n cancelGcByHash(keyHash);\n\n if (delayMs === Number.POSITIVE_INFINITY) return;\n\n if (!Number.isFinite(delayMs)) {\n throw new ArsenalValidationError('stash: ttlMs must be a finite number or Infinity');\n }\n\n if (delayMs <= 0) {\n deleteByHash(keyHash);\n\n return;\n }\n\n if (!store.has(keyHash)) return;\n\n const id = setTimeout(() => {\n gcTimers.delete(keyHash);\n deleteByHash(keyHash);\n }, delayMs);\n\n gcTimers.set(keyHash, id);\n }\n\n function deserializeValue(raw: T): T {\n if (persistence && typeof raw === 'string') return persistence.deserialize(raw);\n\n return raw;\n }\n\n function get(key: K): T | undefined {\n const record = store.get(hash(key));\n\n return record ? deserializeValue(record.value) : undefined;\n }\n\n function set(key: K, value: T, opts?: CacheSetOptions): void {\n const keyHash = hash(key);\n const stored = persistence ? (persistence.serialize(value) as unknown as T) : value;\n\n cancelGcByHash(keyHash);\n store.set(keyHash, { key, value: stored });\n evictOldestIfOverCapacity();\n\n const ttl = opts?.ttlMs ?? defaultTtlMs;\n\n if (ttl !== undefined) {\n scheduleGcByHash(keyHash, ttl);\n }\n }\n\n function getOrSet(key: K, factory: () => T | Promise<T>, opts?: CacheSetOptions): T | Promise<T> {\n const keyHash = hash(key);\n\n if (store.has(keyHash) && !opts?.forceRefresh) return get(key) as T;\n\n const pending = inFlight.get(keyHash);\n\n if (pending && !opts?.forceRefresh) return pending;\n\n const value = factory();\n\n if (isPromise(value)) {\n const capturedGeneration = generation;\n const promise: Promise<T> = value\n .then((resolved) => {\n // Only clear the in-flight slot if it's still *this* promise — an overlapping\n // `forceRefresh` call may have already replaced it with a newer in-flight promise.\n if (inFlight.get(keyHash) === promise) inFlight.delete(keyHash);\n\n if (generation === capturedGeneration && !deletedWhileInFlight.has(keyHash)) {\n set(key, resolved, opts);\n }\n\n deletedWhileInFlight.delete(keyHash);\n\n return resolved;\n })\n .catch((err: unknown) => {\n if (inFlight.get(keyHash) === promise) inFlight.delete(keyHash);\n\n deletedWhileInFlight.delete(keyHash);\n throw err;\n });\n\n inFlight.set(keyHash, promise);\n\n return promise;\n }\n\n set(key, value, opts);\n\n return value;\n }\n\n function del(key: K): boolean {\n return deleteByHash(hash(key));\n }\n\n function clear(): void {\n generation++;\n for (const id of gcTimers.values()) clearTimeout(id);\n\n if (onEvict) {\n for (const record of store.values()) {\n onEvict(record.key, record.value);\n }\n }\n\n store.clear();\n gcTimers.clear();\n inFlight.clear();\n deletedWhileInFlight.clear();\n }\n\n function* entries(): IterableIterator<[K, T]> {\n for (const record of store.values()) {\n yield [record.key, deserializeValue(record.value)];\n }\n }\n\n return {\n clear,\n delete: del,\n entries,\n get,\n getOrSet: getOrSet as Stash<T, K>['getOrSet'],\n set,\n get size() {\n return store.size;\n },\n };\n}\n"],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- function e(e){return()=>e}exports.constant=e;
2
- //# sourceMappingURL=constant.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"constant.cjs","names":[],"sources":["../../src/function/constant.ts"],"sourcesContent":["/**\n * Returns a function that always returns the same value.\n */\nexport function constant<T>(value: T): () => T {\n return () => value;\n}\n"],"mappings":"AAGA,SAAgB,EAAY,EAAmB,CAC7C,UAAa,CACf"}
@@ -1,5 +0,0 @@
1
- /**
2
- * Returns a function that always returns the same value.
3
- */
4
- export declare function constant<T>(value: T): () => T;
5
- //# sourceMappingURL=constant.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"constant.d.ts","sourceRoot":"","sources":["../../src/function/constant.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,wBAAgB,QAAQ,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,MAAM,CAAC,CAE7C"}
@@ -1,8 +0,0 @@
1
- //#region src/function/constant.ts
2
- function e(e) {
3
- return () => e;
4
- }
5
- //#endregion
6
- export { e as constant };
7
-
8
- //# sourceMappingURL=constant.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"constant.js","names":[],"sources":["../../src/function/constant.ts"],"sourcesContent":["/**\n * Returns a function that always returns the same value.\n */\nexport function constant<T>(value: T): () => T {\n return () => value;\n}\n"],"mappings":";AAGA,SAAgB,EAAY,GAAmB;CAC7C,aAAa;AACf"}
@@ -1,2 +0,0 @@
1
- function e(e){return e}exports.identity=e;
2
- //# sourceMappingURL=identity.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"identity.cjs","names":[],"sources":["../../src/function/identity.ts"],"sourcesContent":["/**\n * Returns the same input value.\n */\nexport function identity<T>(value: T): T {\n return value;\n}\n"],"mappings":"AAGA,SAAgB,EAAY,EAAa,CACvC,OAAO,CACT"}
@@ -1,5 +0,0 @@
1
- /**
2
- * Returns the same input value.
3
- */
4
- export declare function identity<T>(value: T): T;
5
- //# sourceMappingURL=identity.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"identity.d.ts","sourceRoot":"","sources":["../../src/function/identity.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,wBAAgB,QAAQ,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,CAAC,CAEvC"}
@@ -1,8 +0,0 @@
1
- //#region src/function/identity.ts
2
- function e(e) {
3
- return e;
4
- }
5
- //#endregion
6
- export { e as identity };
7
-
8
- //# sourceMappingURL=identity.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"identity.js","names":[],"sources":["../../src/function/identity.ts"],"sourcesContent":["/**\n * Returns the same input value.\n */\nexport function identity<T>(value: T): T {\n return value;\n}\n"],"mappings":";AAGA,SAAgB,EAAY,GAAa;CACvC,OAAO;AACT"}
@@ -1,2 +0,0 @@
1
- function e(e,t){return Array.isArray(e)?t?e.every(t):!0:!1}exports.isArray=e;
2
- //# sourceMappingURL=isArray.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"isArray.cjs","names":[],"sources":["../../src/guards/isArray.ts"],"sourcesContent":["/**\n * Returns `true` if `value` is an `Array`, with an optional item-type guard.\n *\n * @example\n * ```ts\n * isArray([1, 2, 3]) // true\n * isArray('hello') // false\n * isArray([1, 2, 3], isNumber) // true — all items pass isNumber\n * isArray([1, 'x'], isNumber) // false — 'x' fails isNumber\n * ```\n *\n * @param value - The value to check.\n * @param itemGuard - Optional type guard applied to every element.\n */\nexport function isArray<T = unknown>(value: unknown, itemGuard?: (item: unknown) => item is T): value is T[] {\n if (!Array.isArray(value)) return false;\n\n if (itemGuard) return value.every(itemGuard);\n\n return true;\n}\n"],"mappings":"AAcA,SAAgB,EAAqB,EAAgB,EAAwD,CAK3G,OAJK,MAAM,QAAQ,CAAK,EAEpB,EAAkB,EAAM,MAAM,CAAS,EAEpC,GAJ2B,EAKpC"}
@@ -1,16 +0,0 @@
1
- /**
2
- * Returns `true` if `value` is an `Array`, with an optional item-type guard.
3
- *
4
- * @example
5
- * ```ts
6
- * isArray([1, 2, 3]) // true
7
- * isArray('hello') // false
8
- * isArray([1, 2, 3], isNumber) // true — all items pass isNumber
9
- * isArray([1, 'x'], isNumber) // false — 'x' fails isNumber
10
- * ```
11
- *
12
- * @param value - The value to check.
13
- * @param itemGuard - Optional type guard applied to every element.
14
- */
15
- export declare function isArray<T = unknown>(value: unknown, itemGuard?: (item: unknown) => item is T): value is T[];
16
- //# sourceMappingURL=isArray.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"isArray.d.ts","sourceRoot":"","sources":["../../src/guards/isArray.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,wBAAgB,OAAO,CAAC,CAAC,GAAG,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,IAAI,CAAC,GAAG,KAAK,IAAI,CAAC,EAAE,CAM3G"}
@@ -1,8 +0,0 @@
1
- //#region src/guards/isArray.ts
2
- function e(e, t) {
3
- return Array.isArray(e) ? t ? e.every(t) : !0 : !1;
4
- }
5
- //#endregion
6
- export { e as isArray };
7
-
8
- //# sourceMappingURL=isArray.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"isArray.js","names":[],"sources":["../../src/guards/isArray.ts"],"sourcesContent":["/**\n * Returns `true` if `value` is an `Array`, with an optional item-type guard.\n *\n * @example\n * ```ts\n * isArray([1, 2, 3]) // true\n * isArray('hello') // false\n * isArray([1, 2, 3], isNumber) // true — all items pass isNumber\n * isArray([1, 'x'], isNumber) // false — 'x' fails isNumber\n * ```\n *\n * @param value - The value to check.\n * @param itemGuard - Optional type guard applied to every element.\n */\nexport function isArray<T = unknown>(value: unknown, itemGuard?: (item: unknown) => item is T): value is T[] {\n if (!Array.isArray(value)) return false;\n\n if (itemGuard) return value.every(itemGuard);\n\n return true;\n}\n"],"mappings":";AAcA,SAAgB,EAAqB,GAAgB,GAAwD;CAK3G,OAJK,MAAM,QAAQ,CAAK,IAEpB,IAAkB,EAAM,MAAM,CAAS,IAEpC,KAJ2B;AAKpC"}
@@ -1,2 +0,0 @@
1
- function e(e){return typeof e==`boolean`}exports.isBoolean=e;
2
- //# sourceMappingURL=isBoolean.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"isBoolean.cjs","names":[],"sources":["../../src/guards/isBoolean.ts"],"sourcesContent":["/**\n * Checks if the value is a boolean.\n *\n * @example\n * ```ts\n * isBoolean(true); // true\n * isBoolean(false); // true\n * isBoolean(123); // false\n * isBoolean('hello world'); // false\n * isBoolean({}); // false\n * isBoolean([]); // false\n * isBoolean(new Date()); // false\n * isBoolean(null); // false\n * isBoolean(undefined); // false\n * isBoolean(NaN); // false\n * ```\n *\n * @param arg - The argument to be checked.\n *\n * @returns `true` if the value is a boolean, else `false`.\n */\nexport function isBoolean(arg: unknown): arg is boolean {\n return typeof arg === 'boolean';\n}\n"],"mappings":"AAqBA,SAAgB,EAAU,EAA8B,CACtD,OAAO,OAAO,GAAQ,SACxB"}
@@ -1,23 +0,0 @@
1
- /**
2
- * Checks if the value is a boolean.
3
- *
4
- * @example
5
- * ```ts
6
- * isBoolean(true); // true
7
- * isBoolean(false); // true
8
- * isBoolean(123); // false
9
- * isBoolean('hello world'); // false
10
- * isBoolean({}); // false
11
- * isBoolean([]); // false
12
- * isBoolean(new Date()); // false
13
- * isBoolean(null); // false
14
- * isBoolean(undefined); // false
15
- * isBoolean(NaN); // false
16
- * ```
17
- *
18
- * @param arg - The argument to be checked.
19
- *
20
- * @returns `true` if the value is a boolean, else `false`.
21
- */
22
- export declare function isBoolean(arg: unknown): arg is boolean;
23
- //# sourceMappingURL=isBoolean.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"isBoolean.d.ts","sourceRoot":"","sources":["../../src/guards/isBoolean.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,OAAO,GAAG,GAAG,IAAI,OAAO,CAEtD"}
@@ -1,8 +0,0 @@
1
- //#region src/guards/isBoolean.ts
2
- function e(e) {
3
- return typeof e == "boolean";
4
- }
5
- //#endregion
6
- export { e as isBoolean };
7
-
8
- //# sourceMappingURL=isBoolean.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"isBoolean.js","names":[],"sources":["../../src/guards/isBoolean.ts"],"sourcesContent":["/**\n * Checks if the value is a boolean.\n *\n * @example\n * ```ts\n * isBoolean(true); // true\n * isBoolean(false); // true\n * isBoolean(123); // false\n * isBoolean('hello world'); // false\n * isBoolean({}); // false\n * isBoolean([]); // false\n * isBoolean(new Date()); // false\n * isBoolean(null); // false\n * isBoolean(undefined); // false\n * isBoolean(NaN); // false\n * ```\n *\n * @param arg - The argument to be checked.\n *\n * @returns `true` if the value is a boolean, else `false`.\n */\nexport function isBoolean(arg: unknown): arg is boolean {\n return typeof arg === 'boolean';\n}\n"],"mappings":";AAqBA,SAAgB,EAAU,GAA8B;CACtD,OAAO,OAAO,KAAQ;AACxB"}
@@ -1,2 +0,0 @@
1
- function e(e){return typeof e==`string`}exports.isString=e;
2
- //# sourceMappingURL=isString.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"isString.cjs","names":[],"sources":["../../src/guards/isString.ts"],"sourcesContent":["/**\n * Determines if the passed value is a String.\n *\n * @example\n * ```ts\n * isString('Hello World'); // true\n * isString(42); // false\n * ```\n *\n * @param arg - The argument to be checked.\n *\n * @returns `true` if the value is a String, else `false`.\n */\nexport function isString(arg: unknown): arg is string {\n return typeof arg === 'string';\n}\n"],"mappings":"AAaA,SAAgB,EAAS,EAA6B,CACpD,OAAO,OAAO,GAAQ,QACxB"}