actly 1.0.2 → 1.1.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 (44) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +380 -0
  3. package/dist/core/act.cjs +5 -3
  4. package/dist/core/act.d.ts.map +1 -1
  5. package/dist/core/act.js +4 -2
  6. package/dist/core/act.js.map +1 -1
  7. package/dist/core/executor.cjs +16 -0
  8. package/dist/core/executor.d.ts +9 -7
  9. package/dist/core/executor.d.ts.map +1 -1
  10. package/dist/core/executor.js +15 -0
  11. package/dist/core/executor.js.map +1 -1
  12. package/dist/index.cjs +2 -2
  13. package/dist/index.d.ts +3 -2
  14. package/dist/index.d.ts.map +1 -1
  15. package/dist/index.js +1 -1
  16. package/dist/index.js.map +1 -1
  17. package/dist/policies/cache.cjs +27 -7
  18. package/dist/policies/cache.d.ts +5 -0
  19. package/dist/policies/cache.d.ts.map +1 -1
  20. package/dist/policies/cache.js +27 -7
  21. package/dist/policies/cache.js.map +1 -1
  22. package/dist/policies/dedupe.cjs +24 -9
  23. package/dist/policies/dedupe.d.ts +7 -0
  24. package/dist/policies/dedupe.d.ts.map +1 -1
  25. package/dist/policies/dedupe.js +24 -9
  26. package/dist/policies/dedupe.js.map +1 -1
  27. package/dist/state/store.cjs +4 -38
  28. package/dist/state/store.d.ts +1 -12
  29. package/dist/state/store.d.ts.map +1 -1
  30. package/dist/state/store.js +3 -37
  31. package/dist/state/store.js.map +1 -1
  32. package/dist/stores/base.cjs +20 -0
  33. package/dist/stores/base.d.ts +112 -0
  34. package/dist/stores/base.d.ts.map +1 -0
  35. package/dist/stores/base.js +17 -0
  36. package/dist/stores/base.js.map +1 -0
  37. package/dist/stores/memory.cjs +91 -0
  38. package/dist/stores/memory.d.ts +58 -0
  39. package/dist/stores/memory.d.ts.map +1 -0
  40. package/dist/stores/memory.js +88 -0
  41. package/dist/stores/memory.js.map +1 -0
  42. package/dist/types/index.d.ts +20 -8
  43. package/dist/types/index.d.ts.map +1 -1
  44. package/package.json +1 -1
package/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2025 ACT contributors
3
+ Copyright (c) 2026 ACT contributors
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md ADDED
@@ -0,0 +1,380 @@
1
+ # actly
2
+
3
+ **Reliability primitive for async functions.**
4
+ Retry. Timeout. Dedupe. Cache. Composable, typed, zero-throw.
5
+
6
+ ```bash
7
+ npm install actly
8
+ ```
9
+
10
+ > Requires Node 18+. Ships ESM + CJS. Zero dependencies.
11
+
12
+ ---
13
+
14
+ ## The problem
15
+
16
+ Every async call can fail. Networks blip. Services time out. The same UI mounts three times and fires the same fetch in parallel. You need retry logic, but not for 4xx errors. You need timeouts, but not the kind that let retry loops run forever.
17
+
18
+ These patterns are solved the same way every time. `actly` solves them once.
19
+
20
+ ---
21
+
22
+ ## Quick start
23
+
24
+ ```ts
25
+ import { act } from 'actly'
26
+
27
+ const result = await act('user:42', () => fetchUser(42))
28
+
29
+ if (result.ok) {
30
+ console.log(result.value) // T
31
+ console.log(result.source) // 'fresh' | 'cache'
32
+ console.log(result.attempts) // number
33
+ } else {
34
+ console.error(result.error) // unknown — never throws
35
+ }
36
+ ```
37
+
38
+ `act` always resolves. It never rejects. You check `.ok` and move on.
39
+
40
+ ---
41
+
42
+ ## API
43
+
44
+ ```ts
45
+ act<T>(key: string, fn: () => Promise<T>, options?: ActOptions): Promise<ActResult<T>>
46
+ ```
47
+
48
+ | Argument | Type | Description |
49
+ |---|---|---|
50
+ | `key` | `string` | Stable, unique identifier. Scopes dedupe and cache state. |
51
+ | `fn` | `() => Promise<T>` | The async function to execute. |
52
+ | `options` | `ActOptions` | All optional. See policies below. |
53
+
54
+ ### Result shape
55
+
56
+ ```ts
57
+ type ActResult<T> =
58
+ | { ok: true; value: T; source: 'fresh' | 'cache'; attempts: number }
59
+ | { ok: false; error: unknown; attempts: number }
60
+ ```
61
+
62
+ ---
63
+
64
+ ## Policies
65
+
66
+ All policies are optional and compose freely. The execution order is **fixed**:
67
+
68
+ ```
69
+ totalTimeout → cache → dedupe → retry → timeout
70
+ ```
71
+
72
+ ### Retry
73
+
74
+ ```ts
75
+ const result = await act('payments:charge', () => chargeCard(payload), {
76
+ retry: {
77
+ attempts: 3, // total attempts (including first)
78
+ delayMs: 200, // base delay between attempts (ms)
79
+ backoff: 'exponential' // 'none' | 'linear' | 'exponential'
80
+ },
81
+ })
82
+ ```
83
+
84
+ `result.attempts` tells you how many tries it took.
85
+
86
+ #### Selective retry with `shouldRetry`
87
+
88
+ By default, every error triggers a retry. Use `shouldRetry` to skip retrying permanent errors — a `404` will never recover, a `503` might.
89
+
90
+ ```ts
91
+ const result = await act('api:resource', () => fetchResource(id), {
92
+ retry: {
93
+ attempts: 4,
94
+ delayMs: 150,
95
+ backoff: 'exponential',
96
+ shouldRetry: (err, attempt) => {
97
+ if (err instanceof HttpError && err.status < 500) return false
98
+ return true
99
+ },
100
+ },
101
+ })
102
+ ```
103
+
104
+ `shouldRetry(error, attempt)` receives the error and the 1-based attempt number. Return `false` to surface the error immediately. Not called on the final attempt — that always surfaces.
105
+
106
+ ---
107
+
108
+ ### Timeout
109
+
110
+ Per-attempt deadline. Each retry gets a fresh clock.
111
+
112
+ ```ts
113
+ import { act, TimeoutError } from 'actly'
114
+
115
+ const result = await act('geo:lookup', () => lookupCoords(ip), {
116
+ timeout: { ms: 3_000 },
117
+ })
118
+
119
+ if (!result.ok && result.error instanceof TimeoutError) {
120
+ console.log(`timed out after ${result.error.ms}ms`)
121
+ }
122
+ ```
123
+
124
+ ---
125
+
126
+ ### Total timeout
127
+
128
+ Hard budget over the **entire** operation — all attempts, delays, and per-attempt timeouts combined. The per-attempt `timeout` resets on retry; `totalTimeout` does not.
129
+
130
+ ```ts
131
+ import { act, TimeoutError, TotalTimeoutError } from 'actly'
132
+
133
+ const result = await act('search:query', () => runQuery(q), {
134
+ retry: { attempts: 5, delayMs: 100, backoff: 'linear' },
135
+ timeout: { ms: 2_000 }, // per attempt
136
+ totalTimeout: { ms: 8_000 }, // whole operation
137
+ })
138
+
139
+ if (!result.ok) {
140
+ if (result.error instanceof TotalTimeoutError) {
141
+ console.log(`budget exhausted after ${result.error.ms}ms`)
142
+ } else if (result.error instanceof TimeoutError) {
143
+ console.log(`last attempt timed out after ${result.error.ms}ms`)
144
+ }
145
+ }
146
+ ```
147
+
148
+ `TotalTimeoutError` and `TimeoutError` are separate classes — `instanceof` distinguishes which deadline fired.
149
+
150
+ ---
151
+
152
+ ### Dedupe
153
+
154
+ Concurrent calls with the same key collapse into one in-flight Promise. The first caller executes; the rest wait and receive the same result. After settlement, the next call starts fresh.
155
+
156
+ ```ts
157
+ const result = await act('config:load', () => loadRemoteConfig(), {
158
+ dedupe: true,
159
+ })
160
+ ```
161
+
162
+ `dedupe: { enabled: true }` is also valid — object form for forward compatibility.
163
+
164
+ > **Note:** Deduped callers (those that joined an in-flight Promise) always receive `attempts: 1` in their result, because the retry counter belongs to the originating call. This is a known trade-off.
165
+
166
+ ---
167
+
168
+ ### Cache
169
+
170
+ Stores successful results for `ttl` milliseconds. Failures are never cached. A cache hit short-circuits everything — dedupe, retry, and timeout are all skipped.
171
+
172
+ ```ts
173
+ const result = await act('flags:all', () => fetchFeatureFlags(), {
174
+ cache: { ttl: 60_000 },
175
+ })
176
+
177
+ console.log(result.source) // 'fresh' on miss, 'cache' on hit
178
+ ```
179
+
180
+ ---
181
+
182
+ ### Combining policies
183
+
184
+ ```ts
185
+ const result = await act('product:detail', () => fetchProduct(id), {
186
+ totalTimeout: { ms: 10_000 }, // outermost wall
187
+ cache: { ttl: 30_000 }, // short-circuits on hit
188
+ dedupe: true, // collapses concurrent calls
189
+ retry: { attempts: 3, delayMs: 100, backoff: 'linear' },
190
+ timeout: { ms: 3_000 }, // per attempt
191
+ })
192
+ ```
193
+
194
+ ---
195
+
196
+ ## Options reference
197
+
198
+ ```ts
199
+ interface ActOptions {
200
+ retry?: RetryOptions
201
+ timeout?: TimeoutOptions // per-attempt
202
+ totalTimeout?: TimeoutOptions // entire operation
203
+ dedupe?: boolean | DedupeOptions
204
+ cache?: CacheOptions
205
+ }
206
+
207
+ interface RetryOptions {
208
+ attempts: number
209
+ delayMs?: number
210
+ backoff?: 'none' | 'linear' | 'exponential'
211
+ shouldRetry?: (error: unknown, attempt: number) => boolean
212
+ }
213
+
214
+ interface TimeoutOptions { ms: number }
215
+ interface DedupeOptions { enabled: boolean }
216
+ interface CacheOptions { ttl: number }
217
+ ```
218
+
219
+ ---
220
+
221
+ ## Exported values
222
+
223
+ ```ts
224
+ import {
225
+ act, // primary function
226
+ InMemoryStore, // isolated store for SSR / tests
227
+ TimeoutError, // per-attempt deadline (.ms)
228
+ TotalTimeoutError, // total budget exhausted (.ms)
229
+ } from 'actly'
230
+ ```
231
+
232
+ ---
233
+
234
+ ## Exported types
235
+
236
+ ```ts
237
+ import type {
238
+ ActResult, ActSuccess, ActFailure, ActSource,
239
+ ActOptions, ActFn,
240
+ RetryOptions, TimeoutOptions, DedupeOptions, CacheOptions,
241
+ // v1.1 — store interfaces
242
+ SyncStateStore,
243
+ AsyncStateStore,
244
+ InMemoryStoreOptions,
245
+ // v1.0 alias — still valid, zero migration needed
246
+ StateStore,
247
+ } from 'actly'
248
+ ```
249
+
250
+ ---
251
+
252
+ ## Custom store
253
+
254
+ By default `act` uses a module-level `InMemoryStore`. For SSR request isolation or test control, instantiate your own:
255
+
256
+ ```ts
257
+ import { InMemoryStore } from 'actly'
258
+
259
+ // Basic
260
+ const store = new InMemoryStore()
261
+
262
+ // With background cleanup (useful for long-lived server-side stores)
263
+ const store = new InMemoryStore({
264
+ autoCleanup: true,
265
+ cleanupIntervalMs: 60_000, // sweep every 60s (default: 30s)
266
+ })
267
+
268
+ // Always call destroy() when done to prevent timer leaks
269
+ store.destroy()
270
+ ```
271
+
272
+ `InMemoryStore` satisfies `SyncStateStore`. Use it with `execute()` directly for full control.
273
+
274
+ ### Async store (v1.1+)
275
+
276
+ For external cache backends (Redis, Upstash, etc.), implement `AsyncStateStore`:
277
+
278
+ ```ts
279
+ import type { AsyncStateStore } from 'actly'
280
+
281
+ class RedisStore implements AsyncStateStore {
282
+ readonly _sync = false as const
283
+
284
+ async get<T>(key: string): Promise<T | undefined> { /* ... */ }
285
+ async set<T>(key: string, value: T, ttlMs?: number): Promise<void> { /* ... */ }
286
+ async delete(key: string): Promise<void> { /* ... */ }
287
+ async has(key: string): Promise<boolean> { /* ... */ }
288
+ async clear(): Promise<void> { /* ... */ }
289
+ async size(): Promise<number> { /* ... */ }
290
+ }
291
+ ```
292
+
293
+ > `AsyncStateStore` is compatible with `cache` only. Using it with `dedupe` is a TypeScript error and a runtime error — dedupe requires synchronous store access. See `SyncStateStore` docs for the reason.
294
+
295
+ ---
296
+
297
+ ## Store interfaces
298
+
299
+ ```ts
300
+ interface SyncStateStore {
301
+ readonly _sync: true
302
+ get<T>(key: string): T | undefined
303
+ set<T>(key: string, value: T, ttlMs?: number): void
304
+ delete(key: string): void
305
+ has(key: string): boolean
306
+ clear(): void
307
+ size(): number
308
+ }
309
+
310
+ interface AsyncStateStore {
311
+ readonly _sync: false
312
+ get<T>(key: string): Promise<T | undefined>
313
+ set<T>(key: string, value: T, ttlMs?: number): Promise<void>
314
+ delete(key: string): Promise<void>
315
+ has(key: string): Promise<boolean>
316
+ clear(): Promise<void>
317
+ size(): Promise<number>
318
+ }
319
+ ```
320
+
321
+ The `_sync` discriminant is read at runtime by the executor to enforce the dedupe constraint. Set it as a `readonly` literal — `true as const` or `false as const`.
322
+
323
+ ---
324
+
325
+ ## Zero-throw contract
326
+
327
+ `act()` always resolves. Under any condition — network error, thrown exception, timeout, total budget exhaustion — the result is an `ActFailure`, not a rejected promise. This contract holds across all versions.
328
+
329
+ ---
330
+
331
+ ## Philosophy
332
+
333
+ One function. One return type. No exceptions in userland.
334
+
335
+ The key is your responsibility. Make it stable and specific. `user:42` is good. `fetch` is not.
336
+
337
+ Policies are composable but intentionally constrained. There is no builder API, no middleware system, no hooks. If you need something `act` doesn't do, write a wrapper around it — that's the right boundary.
338
+
339
+ ---
340
+
341
+ ## Changelog
342
+
343
+ ### v1.1.0 — 2026-06-01
344
+
345
+ **New features**
346
+
347
+ - **`AsyncStateStore` interface** — plug in any async key-value backend (Redis, Upstash, Cloudflare KV). Compatible with `cache` policy. Using with `dedupe` is a compile-time and runtime error by design.
348
+ - **`SyncStateStore` interface** — the canonical public name for what was previously the internal store shape. `StateStore` is preserved as an alias with zero breakage for existing code.
349
+ - **`InMemoryStore` is now a public export** — construct isolated stores for SSR request isolation, per-test control, or multi-tenant scenarios. Accepts `InMemoryStoreOptions`.
350
+ - **`InMemoryStoreOptions`** — opt-in `autoCleanup` with configurable `cleanupIntervalMs`. Call `destroy()` to stop the background timer and prevent leaks.
351
+ - **`TotalTimeoutError`** — new error class thrown when `totalTimeout` fires. Distinct from `TimeoutError` (per-attempt) so `instanceof` tells you which deadline fired.
352
+ - **`totalTimeout` option** — hard wall-clock budget over the entire operation including all retry attempts and delays. Use alongside `timeout` to express both per-attempt and total constraints.
353
+ - **`dedupe: true` shorthand** — equivalent to `dedupe: { enabled: true }`. Object form still valid for forward compatibility.
354
+ - **`isSyncStore()` / `isAsyncStore()` type guards** — exported from `actly` for consumers building custom policy chains or store adapters.
355
+
356
+ **Internal improvements**
357
+
358
+ - Executor validates sync-store requirement at chain-build time — async store + `dedupePolicy` throws immediately with a clear message instead of producing silent correctness failures.
359
+ - `dedupePolicy` tagged with `REQUIRES_SYNC_STORE` symbol — allows executor to detect the constraint without importing the policy module (avoids circular deps).
360
+ - `cachePolicy` now branches sync/async paths — fast synchronous path for `InMemoryStore`, async-await path for external stores.
361
+
362
+ **Non-breaking changes**
363
+
364
+ - `StateStore` preserved as type alias for `SyncStateStore` — all v1.0 code compiles without changes.
365
+ - All new exports are purely additive.
366
+
367
+ ---
368
+
369
+ ### v1.0.1
370
+
371
+ - Initial stable release.
372
+ - `act()`, `retry`, `timeout`, `totalTimeout`, `dedupe`, `cache`.
373
+ - `TimeoutError` exported for `instanceof` checks.
374
+ - Zero dependencies. ESM + CJS. Node 18+.
375
+
376
+ ---
377
+
378
+ ## License
379
+
380
+ MIT
package/dist/core/act.cjs CHANGED
@@ -6,11 +6,13 @@ const retry_js_1 = require("../policies/retry.js");
6
6
  const timeout_js_1 = require("../policies/timeout.js");
7
7
  const dedupe_js_1 = require("../policies/dedupe.js");
8
8
  const cache_js_1 = require("../policies/cache.js");
9
- const store_js_1 = require("../state/store.js");
9
+ const memory_js_1 = require("../stores/memory.js");
10
10
  // Module-level default store so cache and dedupe persist across calls.
11
+ // Always an InMemoryStore (SyncStateStore) — required because the default
12
+ // chain may include dedupePolicy, which mandates synchronous store access.
11
13
  // For SSR isolation or per-test control, construct an InMemoryStore and
12
- // call execute() directly it accepts any StateStore implementation.
13
- const defaultStore = new store_js_1.InMemoryStore();
14
+ // call execute() directly with an explicit store.
15
+ const defaultStore = new memory_js_1.InMemoryStore();
14
16
  /**
15
17
  * Execute fn with the given reliability policies.
16
18
  *
@@ -1 +1 @@
1
- {"version":3,"file":"act.d.ts","sourceRoot":"","sources":["../../src/core/act.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,UAAU,EAAE,SAAS,EAA0B,MAAM,mBAAmB,CAAA;AAa7F;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAsB,GAAG,CAAC,CAAC,EACzB,GAAG,EAAE,MAAM,EACX,EAAE,EAAE,KAAK,CAAC,CAAC,CAAC,EACZ,OAAO,GAAE,UAAe,GACvB,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAwCvB"}
1
+ {"version":3,"file":"act.d.ts","sourceRoot":"","sources":["../../src/core/act.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,UAAU,EAAE,SAAS,EAA0B,MAAM,mBAAmB,CAAA;AAe7F;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAsB,GAAG,CAAC,CAAC,EACzB,GAAG,EAAE,MAAM,EACX,EAAE,EAAE,KAAK,CAAC,CAAC,CAAC,EACZ,OAAO,GAAE,UAAe,GACvB,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAwCvB"}
package/dist/core/act.js CHANGED
@@ -3,10 +3,12 @@ import { retryPolicy } from '../policies/retry.js';
3
3
  import { timeoutPolicy, totalTimeoutPolicy } from '../policies/timeout.js';
4
4
  import { dedupePolicy } from '../policies/dedupe.js';
5
5
  import { cachePolicy } from '../policies/cache.js';
6
- import { InMemoryStore } from '../state/store.js';
6
+ import { InMemoryStore } from '../stores/memory.js';
7
7
  // Module-level default store so cache and dedupe persist across calls.
8
+ // Always an InMemoryStore (SyncStateStore) — required because the default
9
+ // chain may include dedupePolicy, which mandates synchronous store access.
8
10
  // For SSR isolation or per-test control, construct an InMemoryStore and
9
- // call execute() directly it accepts any StateStore implementation.
11
+ // call execute() directly with an explicit store.
10
12
  const defaultStore = new InMemoryStore();
11
13
  /**
12
14
  * Execute fn with the given reliability policies.
@@ -1 +1 @@
1
- {"version":3,"file":"act.js","sourceRoot":"","sources":["../../src/core/act.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAa,eAAe,CAAA;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAS,sBAAsB,CAAA;AACrD,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAA;AAC1E,OAAO,EAAE,YAAY,EAAE,MAAQ,uBAAuB,CAAA;AACtD,OAAO,EAAE,WAAW,EAAE,MAAS,sBAAsB,CAAA;AACrD,OAAO,EAAE,aAAa,EAAE,MAAO,mBAAmB,CAAA;AAElD,uEAAuE;AACvE,wEAAwE;AACxE,sEAAsE;AACtE,MAAM,YAAY,GAAG,IAAI,aAAa,EAAE,CAAA;AAExC;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,CAAC,KAAK,UAAU,GAAG,CACvB,GAAW,EACX,EAAY,EACZ,UAAsB,EAAE;IAExB,MAAM,IAAI,GAAY,EAAE,QAAQ,EAAE,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,CAAA;IAEtD,yEAAyE;IACzE,qCAAqC;IACrC,MAAM,MAAM,GAAG,OAAO,OAAO,CAAC,MAAM,KAAK,SAAS;QAChD,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,MAAM,EAAE;QAC7B,CAAC,CAAC,OAAO,CAAC,MAAM,CAAA;IAElB,yEAAyE;IACzE,MAAM,QAAQ,GAA4B,EAAE,CAAA;IAE5C,2EAA2E;IAC3E,8EAA8E;IAC9E,IAAI,OAAO,CAAC,YAAY,IAAI,OAAO,CAAC,YAAY,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC;QACxD,QAAQ,CAAC,IAAI,CAAC,kBAAkB,CAAI,OAAO,CAAC,YAAY,CAAC,CAAC,CAAA,CAAC,wBAAwB;IACrF,CAAC;IAED,IAAI,OAAO,CAAC,KAAK,IAAI,OAAO,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,EAAE,CAAC;QAC3C,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAI,OAAO,CAAC,KAAK,CAAC,CAAC,CAAA,CAAe,qBAAqB;IAClF,CAAC;IAED,IAAI,MAAM,EAAE,OAAO,EAAE,CAAC;QACpB,QAAQ,CAAC,IAAI,CAAC,YAAY,EAAK,CAAC,CAAA,CAA2B,iCAAiC;IAC9F,CAAC;IAED,IAAI,OAAO,CAAC,KAAK,IAAI,OAAO,CAAC,KAAK,CAAC,QAAQ,GAAG,CAAC,EAAE,CAAC;QAChD,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAI,OAAO,CAAC,KAAK,CAAC,CAAC,CAAA,CAAe,0BAA0B;IACvF,CAAC;IAED,IAAI,OAAO,CAAC,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC;QAC9C,QAAQ,CAAC,IAAI,CAAC,aAAa,CAAI,OAAO,CAAC,OAAO,CAAC,CAAC,CAAA,CAAW,mCAAmC;IAChG,CAAC;IAED,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,MAAM,OAAO,CAAC,EAAE,GAAG,EAAE,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAA;QAC7E,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,CAAA;IAC1E,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,CAAA;IACtD,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"act.js","sourceRoot":"","sources":["../../src/core/act.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAa,eAAe,CAAA;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAS,sBAAsB,CAAA;AACrD,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAA;AAC1E,OAAO,EAAE,YAAY,EAAE,MAAQ,uBAAuB,CAAA;AACtD,OAAO,EAAE,WAAW,EAAE,MAAS,sBAAsB,CAAA;AACrD,OAAO,EAAE,aAAa,EAAE,MAAO,qBAAqB,CAAA;AAEpD,uEAAuE;AACvE,0EAA0E;AAC1E,2EAA2E;AAC3E,wEAAwE;AACxE,kDAAkD;AAClD,MAAM,YAAY,GAAG,IAAI,aAAa,EAAE,CAAA;AAExC;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,CAAC,KAAK,UAAU,GAAG,CACvB,GAAW,EACX,EAAY,EACZ,UAAsB,EAAE;IAExB,MAAM,IAAI,GAAY,EAAE,QAAQ,EAAE,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,CAAA;IAEtD,yEAAyE;IACzE,qCAAqC;IACrC,MAAM,MAAM,GAAG,OAAO,OAAO,CAAC,MAAM,KAAK,SAAS;QAChD,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,MAAM,EAAE;QAC7B,CAAC,CAAC,OAAO,CAAC,MAAM,CAAA;IAElB,yEAAyE;IACzE,MAAM,QAAQ,GAA4B,EAAE,CAAA;IAE5C,2EAA2E;IAC3E,8EAA8E;IAC9E,IAAI,OAAO,CAAC,YAAY,IAAI,OAAO,CAAC,YAAY,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC;QACxD,QAAQ,CAAC,IAAI,CAAC,kBAAkB,CAAI,OAAO,CAAC,YAAY,CAAC,CAAC,CAAA,CAAC,wBAAwB;IACrF,CAAC;IAED,IAAI,OAAO,CAAC,KAAK,IAAI,OAAO,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,EAAE,CAAC;QAC3C,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAI,OAAO,CAAC,KAAK,CAAC,CAAC,CAAA,CAAe,qBAAqB;IAClF,CAAC;IAED,IAAI,MAAM,EAAE,OAAO,EAAE,CAAC;QACpB,QAAQ,CAAC,IAAI,CAAC,YAAY,EAAK,CAAC,CAAA,CAA2B,iCAAiC;IAC9F,CAAC;IAED,IAAI,OAAO,CAAC,KAAK,IAAI,OAAO,CAAC,KAAK,CAAC,QAAQ,GAAG,CAAC,EAAE,CAAC;QAChD,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAI,OAAO,CAAC,KAAK,CAAC,CAAC,CAAA,CAAe,0BAA0B;IACvF,CAAC;IAED,IAAI,OAAO,CAAC,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC;QAC9C,QAAQ,CAAC,IAAI,CAAC,aAAa,CAAI,OAAO,CAAC,OAAO,CAAC,CAAC,CAAA,CAAW,mCAAmC;IAChG,CAAC;IAED,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,MAAM,OAAO,CAAC,EAAE,GAAG,EAAE,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAA;QAC7E,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,CAAA;IAC1E,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,CAAA;IACtD,CAAC;AACH,CAAC"}
@@ -1,6 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.REQUIRES_SYNC_STORE = void 0;
3
4
  exports.execute = execute;
5
+ const base_js_1 = require("../stores/base.js");
6
+ // Symbol stamped onto PolicyApplier functions by dedupePolicy.
7
+ // Lets execute() detect a dedupe policy without importing the policy module
8
+ // (which would create a circular dep) or doing fragile name-sniffing.
9
+ exports.REQUIRES_SYNC_STORE = Symbol('actly.requiresSyncStore');
4
10
  /**
5
11
  * Pure execution engine.
6
12
  *
@@ -9,6 +15,16 @@ exports.execute = execute;
9
15
  * Policy implementations live in /policies and are wired in core/act.ts.
10
16
  */
11
17
  async function execute(input) {
18
+ // Guard: if any policy in the chain requires a sync store, the provided
19
+ // store must be synchronous. An async store + dedupePolicy is a silent
20
+ // correctness failure, not just a performance issue — catch it here rather
21
+ // than letting it produce subtly wrong dedupe behaviour at runtime.
22
+ const needsSync = input.policies.some(p => p[exports.REQUIRES_SYNC_STORE]);
23
+ if (needsSync && !(0, base_js_1.isSyncStore)(input.store)) {
24
+ throw new Error('Actly: dedupePolicy requires a SyncStateStore (store._sync === true). ' +
25
+ 'The provided store does not satisfy this constraint. ' +
26
+ 'Either remove dedupe from the policy chain or use InMemoryStore.');
27
+ }
12
28
  const ctx = {
13
29
  key: input.key,
14
30
  store: input.store,
@@ -1,4 +1,5 @@
1
- import type { ActFn, PolicyApplier, StateStore, RunMeta } from '../types/index.js';
1
+ import type { ActFn, PolicyApplier, AnyStateStore, RunMeta } from '../types/index.js';
2
+ export declare const REQUIRES_SYNC_STORE: unique symbol;
2
3
  export interface ExecutorInput<T> {
3
4
  key: string;
4
5
  fn: ActFn<T>;
@@ -6,14 +7,15 @@ export interface ExecutorInput<T> {
6
7
  * Policies ordered outermost -> innermost.
7
8
  * policies[0] intercepts first; policies[last] is closest to fn.
8
9
  *
9
- * Canonical order: [cache, dedupe, retry, timeout]
10
- * cache -> a hit skips everything below it
11
- * dedupe -> collapses concurrent callers before retry fires
12
- * retry -> owns the attempt loop
13
- * timeout -> each individual attempt races against the clock
10
+ * Canonical order: [totalTimeout, cache, dedupe, retry, timeout]
11
+ * totalTimeout -> hard wall-clock budget over the entire operation
12
+ * cache -> a hit skips everything below it
13
+ * dedupe -> collapses concurrent callers before retry fires
14
+ * retry -> owns the attempt loop
15
+ * timeout -> each individual attempt races against the clock
14
16
  */
15
17
  policies: ReadonlyArray<PolicyApplier<T>>;
16
- store: StateStore;
18
+ store: AnyStateStore;
17
19
  meta: RunMeta;
18
20
  }
19
21
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"executor.d.ts","sourceRoot":"","sources":["../../src/core/executor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,KAAK,EACL,aAAa,EAEb,UAAU,EACV,OAAO,EACR,MAAM,mBAAmB,CAAA;AAE1B,MAAM,WAAW,aAAa,CAAC,CAAC;IAC9B,GAAG,EAAO,MAAM,CAAA;IAChB,EAAE,EAAQ,KAAK,CAAC,CAAC,CAAC,CAAA;IAClB;;;;;;;;;OASG;IACH,QAAQ,EAAE,aAAa,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAA;IACzC,KAAK,EAAK,UAAU,CAAA;IACpB,IAAI,EAAM,OAAO,CAAA;CAClB;AAED;;;;;;GAMG;AACH,wBAAsB,OAAO,CAAC,CAAC,EAAE,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAepE"}
1
+ {"version":3,"file":"executor.d.ts","sourceRoot":"","sources":["../../src/core/executor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,KAAK,EACL,aAAa,EAEb,aAAa,EACb,OAAO,EACR,MAAM,mBAAmB,CAAA;AAM1B,eAAO,MAAM,mBAAmB,eAAoC,CAAA;AAEpE,MAAM,WAAW,aAAa,CAAC,CAAC;IAC9B,GAAG,EAAO,MAAM,CAAA;IAChB,EAAE,EAAQ,KAAK,CAAC,CAAC,CAAC,CAAA;IAClB;;;;;;;;;;OAUG;IACH,QAAQ,EAAE,aAAa,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAA;IACzC,KAAK,EAAK,aAAa,CAAA;IACvB,IAAI,EAAM,OAAO,CAAA;CAClB;AAED;;;;;;GAMG;AACH,wBAAsB,OAAO,CAAC,CAAC,EAAE,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CA8BpE"}
@@ -1,3 +1,8 @@
1
+ import { isSyncStore } from '../stores/base.js';
2
+ // Symbol stamped onto PolicyApplier functions by dedupePolicy.
3
+ // Lets execute() detect a dedupe policy without importing the policy module
4
+ // (which would create a circular dep) or doing fragile name-sniffing.
5
+ export const REQUIRES_SYNC_STORE = Symbol('actly.requiresSyncStore');
1
6
  /**
2
7
  * Pure execution engine.
3
8
  *
@@ -6,6 +11,16 @@
6
11
  * Policy implementations live in /policies and are wired in core/act.ts.
7
12
  */
8
13
  export async function execute(input) {
14
+ // Guard: if any policy in the chain requires a sync store, the provided
15
+ // store must be synchronous. An async store + dedupePolicy is a silent
16
+ // correctness failure, not just a performance issue — catch it here rather
17
+ // than letting it produce subtly wrong dedupe behaviour at runtime.
18
+ const needsSync = input.policies.some(p => p[REQUIRES_SYNC_STORE]);
19
+ if (needsSync && !isSyncStore(input.store)) {
20
+ throw new Error('Actly: dedupePolicy requires a SyncStateStore (store._sync === true). ' +
21
+ 'The provided store does not satisfy this constraint. ' +
22
+ 'Either remove dedupe from the policy chain or use InMemoryStore.');
23
+ }
9
24
  const ctx = {
10
25
  key: input.key,
11
26
  store: input.store,
@@ -1 +1 @@
1
- {"version":3,"file":"executor.js","sourceRoot":"","sources":["../../src/core/executor.ts"],"names":[],"mappings":"AA0BA;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,OAAO,CAAI,KAAuB;IACtD,MAAM,GAAG,GAAkB;QACzB,GAAG,EAAI,KAAK,CAAC,GAAG;QAChB,KAAK,EAAE,KAAK,CAAC,KAAK;QAClB,IAAI,EAAG,KAAK,CAAC,IAAI;KAClB,CAAA;IAED,wCAAwC;IACxC,8EAA8E;IAC9E,MAAM,OAAO,GAAG,KAAK,CAAC,QAAQ,CAAC,WAAW,CACxC,CAAC,KAAK,EAAE,WAAW,EAAE,EAAE,CAAC,WAAW,CAAC,KAAK,EAAE,GAAG,CAAC,EAC/C,KAAK,CAAC,EAAE,CACT,CAAA;IAED,OAAO,OAAO,EAAE,CAAA;AAClB,CAAC"}
1
+ {"version":3,"file":"executor.js","sourceRoot":"","sources":["../../src/core/executor.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAE/C,+DAA+D;AAC/D,4EAA4E;AAC5E,sEAAsE;AACtE,MAAM,CAAC,MAAM,mBAAmB,GAAG,MAAM,CAAC,yBAAyB,CAAC,CAAA;AAqBpE;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,OAAO,CAAI,KAAuB;IACtD,wEAAwE;IACxE,uEAAuE;IACvE,2EAA2E;IAC3E,oEAAoE;IACpE,MAAM,SAAS,GAAG,KAAK,CAAC,QAAQ,CAAC,IAAI,CACnC,CAAC,CAAC,EAAE,CAAE,CAA4D,CAAC,mBAAmB,CAAC,CACxF,CAAA;IACD,IAAI,SAAS,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC;QAC3C,MAAM,IAAI,KAAK,CACb,wEAAwE;YACxE,uDAAuD;YACvD,kEAAkE,CACnE,CAAA;IACH,CAAC;IAED,MAAM,GAAG,GAAkB;QACzB,GAAG,EAAI,KAAK,CAAC,GAAG;QAChB,KAAK,EAAE,KAAK,CAAC,KAAK;QAClB,IAAI,EAAG,KAAK,CAAC,IAAI;KAClB,CAAA;IAED,wCAAwC;IACxC,8EAA8E;IAC9E,MAAM,OAAO,GAAG,KAAK,CAAC,QAAQ,CAAC,WAAW,CACxC,CAAC,KAAK,EAAE,WAAW,EAAE,EAAE,CAAC,WAAW,CAAC,KAAK,EAAE,GAAG,CAAC,EAC/C,KAAK,CAAC,EAAE,CACT,CAAA;IAED,OAAO,OAAO,EAAE,CAAA;AAClB,CAAC"}
package/dist/index.cjs CHANGED
@@ -4,8 +4,8 @@ exports.TotalTimeoutError = exports.TimeoutError = exports.InMemoryStore = expor
4
4
  var act_js_1 = require("./core/act.js");
5
5
  Object.defineProperty(exports, "act", { enumerable: true, get: function () { return act_js_1.act; } });
6
6
  // Exported so consumers can build isolated stores (e.g. per-request in SSR)
7
- var store_js_1 = require("./state/store.js");
8
- Object.defineProperty(exports, "InMemoryStore", { enumerable: true, get: function () { return store_js_1.InMemoryStore; } });
7
+ var memory_js_1 = require("./stores/memory.js");
8
+ Object.defineProperty(exports, "InMemoryStore", { enumerable: true, get: function () { return memory_js_1.InMemoryStore; } });
9
9
  // Exported so callers can instanceof-check against timeout failures
10
10
  var timeout_js_1 = require("./policies/timeout.js");
11
11
  Object.defineProperty(exports, "TimeoutError", { enumerable: true, get: function () { return timeout_js_1.TimeoutError; } });
package/dist/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  export { act } from './core/act.js';
2
- export type { ActFn, ActResult, ActSuccess, ActFailure, ActSource, ActOptions, RetryOptions, TimeoutOptions, DedupeOptions, CacheOptions, StateStore, } from './types/index.js';
3
- export { InMemoryStore } from './state/store.js';
2
+ export type { ActFn, ActResult, ActSuccess, ActFailure, ActSource, ActOptions, RetryOptions, TimeoutOptions, DedupeOptions, CacheOptions, StateStore, SyncStateStore, AsyncStateStore, } from './types/index.js';
3
+ export { InMemoryStore } from './stores/memory.js';
4
+ export type { InMemoryStoreOptions } from './stores/memory.js';
4
5
  export { TimeoutError, TotalTimeoutError } from './policies/timeout.js';
5
6
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,eAAe,CAAA;AAEnC,YAAY,EACV,KAAK,EACL,SAAS,EACT,UAAU,EACV,UAAU,EACV,SAAS,EACT,UAAU,EACV,YAAY,EACZ,cAAc,EACd,aAAa,EACb,YAAY,EACZ,UAAU,GACX,MAAM,kBAAkB,CAAA;AAGzB,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAA;AAGhD,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,eAAe,CAAA;AAEnC,YAAY,EACV,KAAK,EACL,SAAS,EACT,UAAU,EACV,UAAU,EACV,SAAS,EACT,UAAU,EACV,YAAY,EACZ,cAAc,EACd,aAAa,EACb,YAAY,EAEZ,UAAU,EAEV,cAAc,EACd,eAAe,GAChB,MAAM,kBAAkB,CAAA;AAGzB,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAClD,YAAY,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAA;AAG9D,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAA"}
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  export { act } from './core/act.js';
2
2
  // Exported so consumers can build isolated stores (e.g. per-request in SSR)
3
- export { InMemoryStore } from './state/store.js';
3
+ export { InMemoryStore } from './stores/memory.js';
4
4
  // Exported so callers can instanceof-check against timeout failures
5
5
  export { TimeoutError, TotalTimeoutError } from './policies/timeout.js';
6
6
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,eAAe,CAAA;AAgBnC,4EAA4E;AAC5E,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAA;AAEhD,oEAAoE;AACpE,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,eAAe,CAAA;AAoBnC,4EAA4E;AAC5E,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAGlD,oEAAoE;AACpE,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAA"}
@@ -1,23 +1,43 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.cachePolicy = cachePolicy;
4
+ const base_js_1 = require("../stores/base.js");
4
5
  const NS = 'cache:';
5
6
  /**
6
7
  * Short-circuits the entire downstream chain on a cache hit.
7
8
  * On a miss, runs fn and stores the result with TTL.
8
9
  *
9
10
  * Must be the OUTERMOST policy so a hit skips dedupe, timeout, and retry.
11
+ *
12
+ * Supports both SyncStateStore and AsyncStateStore. The async branch
13
+ * introduces two await points (get + set) but has no correctness
14
+ * requirement for same-tick execution — worst case is a cache stampede
15
+ * on a simultaneous miss, which is standard behaviour without locking.
10
16
  */
11
17
  function cachePolicy(opts) {
12
18
  return (fn, ctx) => async () => {
13
19
  const key = NS + ctx.key;
14
- const hit = ctx.store.get(key);
15
- if (hit) {
16
- ctx.meta.source = 'cache';
17
- return hit.value;
20
+ if ((0, base_js_1.isSyncStore)(ctx.store)) {
21
+ // Fast path — synchronous store, no await needed
22
+ const hit = ctx.store.get(key);
23
+ if (hit) {
24
+ ctx.meta.source = 'cache';
25
+ return hit.value;
26
+ }
27
+ const value = await fn();
28
+ ctx.store.set(key, { value }, opts.ttl);
29
+ return value;
30
+ }
31
+ else {
32
+ // Async store path
33
+ const hit = await ctx.store.get(key);
34
+ if (hit) {
35
+ ctx.meta.source = 'cache';
36
+ return hit.value;
37
+ }
38
+ const value = await fn();
39
+ await ctx.store.set(key, { value }, opts.ttl);
40
+ return value;
18
41
  }
19
- const value = await fn();
20
- ctx.store.set(key, { value }, opts.ttl);
21
- return value;
22
42
  };
23
43
  }
@@ -4,6 +4,11 @@ import type { CacheOptions, PolicyApplier } from '../types/index.js';
4
4
  * On a miss, runs fn and stores the result with TTL.
5
5
  *
6
6
  * Must be the OUTERMOST policy so a hit skips dedupe, timeout, and retry.
7
+ *
8
+ * Supports both SyncStateStore and AsyncStateStore. The async branch
9
+ * introduces two await points (get + set) but has no correctness
10
+ * requirement for same-tick execution — worst case is a cache stampede
11
+ * on a simultaneous miss, which is standard behaviour without locking.
7
12
  */
8
13
  export declare function cachePolicy<T>(opts: CacheOptions): PolicyApplier<T>;
9
14
  //# sourceMappingURL=cache.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../src/policies/cache.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAS,YAAY,EAAE,aAAa,EAAiB,MAAM,mBAAmB,CAAA;AAS1F;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAAE,IAAI,EAAE,YAAY,GAAG,aAAa,CAAC,CAAC,CAAC,CAenE"}
1
+ {"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../src/policies/cache.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAS,YAAY,EAAE,aAAa,EAAiB,MAAM,mBAAmB,CAAA;AAU1F;;;;;;;;;;GAUG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAAE,IAAI,EAAE,YAAY,GAAG,aAAa,CAAC,CAAC,CAAC,CA6BnE"}