actly 1.0.2 → 1.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/README.md +612 -0
- package/dist/core/act.cjs +187 -37
- package/dist/core/act.d.ts +81 -10
- package/dist/core/act.d.ts.map +1 -1
- package/dist/core/act.js +184 -36
- package/dist/core/act.js.map +1 -1
- package/dist/core/executor.cjs +30 -4
- package/dist/core/executor.d.ts +33 -11
- package/dist/core/executor.d.ts.map +1 -1
- package/dist/core/executor.js +29 -4
- package/dist/core/executor.js.map +1 -1
- package/dist/index.cjs +15 -5
- package/dist/index.d.ts +9 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -5
- package/dist/index.js.map +1 -1
- package/dist/policies/cache.cjs +91 -7
- package/dist/policies/cache.d.ts +30 -3
- package/dist/policies/cache.d.ts.map +1 -1
- package/dist/policies/cache.js +91 -7
- package/dist/policies/cache.js.map +1 -1
- package/dist/policies/dedupe.cjs +79 -16
- package/dist/policies/dedupe.d.ts +39 -7
- package/dist/policies/dedupe.d.ts.map +1 -1
- package/dist/policies/dedupe.js +79 -16
- package/dist/policies/dedupe.js.map +1 -1
- package/dist/policies/retry.cjs +65 -25
- package/dist/policies/retry.d.ts +25 -2
- package/dist/policies/retry.d.ts.map +1 -1
- package/dist/policies/retry.js +65 -25
- package/dist/policies/retry.js.map +1 -1
- package/dist/policies/timeout.cjs +87 -17
- package/dist/policies/timeout.d.ts +28 -8
- package/dist/policies/timeout.d.ts.map +1 -1
- package/dist/policies/timeout.js +87 -17
- package/dist/policies/timeout.js.map +1 -1
- package/dist/state/store.cjs +11 -38
- package/dist/state/store.d.ts +10 -12
- package/dist/state/store.d.ts.map +1 -1
- package/dist/state/store.js +10 -37
- package/dist/state/store.js.map +1 -1
- package/dist/stores/base.cjs +20 -0
- package/dist/stores/base.d.ts +88 -0
- package/dist/stores/base.d.ts.map +1 -0
- package/dist/stores/base.js +17 -0
- package/dist/stores/base.js.map +1 -0
- package/dist/stores/memory.cjs +140 -0
- package/dist/stores/memory.d.ts +79 -0
- package/dist/stores/memory.d.ts.map +1 -0
- package/dist/stores/memory.js +137 -0
- package/dist/stores/memory.js.map +1 -0
- package/dist/types/index.d.ts +151 -34
- package/dist/types/index.d.ts.map +1 -1
- package/dist/utils/abort.cjs +142 -0
- package/dist/utils/abort.d.ts +55 -0
- package/dist/utils/abort.d.ts.map +1 -0
- package/dist/utils/abort.js +136 -0
- package/dist/utils/abort.js.map +1 -0
- package/dist/utils/backoff.cjs +43 -0
- package/dist/utils/backoff.d.ts +14 -0
- package/dist/utils/backoff.d.ts.map +1 -0
- package/dist/utils/backoff.js +41 -0
- package/dist/utils/backoff.js.map +1 -0
- package/dist/utils/validate.cjs +79 -0
- package/dist/utils/validate.d.ts +15 -0
- package/dist/utils/validate.d.ts.map +1 -0
- package/dist/utils/validate.js +72 -0
- package/dist/utils/validate.js.map +1 -0
- package/package.json +19 -37
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.InMemoryStore = void 0;
|
|
4
|
+
function isUnrefable(t) {
|
|
5
|
+
return typeof t.unref === 'function';
|
|
6
|
+
}
|
|
7
|
+
// ─── Implementation ───────────────────────────────────────────────────────────
|
|
8
|
+
/**
|
|
9
|
+
* Reference `SyncStateStore` implementation backed by a `Map`.
|
|
10
|
+
*
|
|
11
|
+
* # LRU semantics
|
|
12
|
+
*
|
|
13
|
+
* `Map` iteration order is insertion order, so we implement LRU by
|
|
14
|
+
* `delete` + `set` on every access — the most-recently-touched key ends up
|
|
15
|
+
* at the end of the iteration, and the oldest is `entries.keys().next().value`.
|
|
16
|
+
*
|
|
17
|
+
* # Expiry
|
|
18
|
+
*
|
|
19
|
+
* Lazy on `get()` / `has()`: expired entries are deleted when touched.
|
|
20
|
+
* Background sweep (optional) reclaims entries that are never re-read.
|
|
21
|
+
*/
|
|
22
|
+
class InMemoryStore {
|
|
23
|
+
_sync = true;
|
|
24
|
+
entries = new Map();
|
|
25
|
+
maxSize;
|
|
26
|
+
cleanupTimer;
|
|
27
|
+
constructor(options = {}) {
|
|
28
|
+
const { autoCleanup = false, cleanupIntervalMs = 30_000, maxSize = Number.POSITIVE_INFINITY, } = options;
|
|
29
|
+
if (!Number.isFinite(maxSize) || maxSize <= 0) {
|
|
30
|
+
// Infinity is allowed (unbounded); any other non-positive finite value
|
|
31
|
+
// is a programmer error.
|
|
32
|
+
if (maxSize !== Number.POSITIVE_INFINITY) {
|
|
33
|
+
throw new RangeError(`Actly: InMemoryStore maxSize must be a positive finite number or Infinity, got ${maxSize}`);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
this.maxSize = maxSize;
|
|
37
|
+
if (autoCleanup) {
|
|
38
|
+
const timer = setInterval(() => this._sweep(), cleanupIntervalMs);
|
|
39
|
+
if (isUnrefable(timer))
|
|
40
|
+
timer.unref();
|
|
41
|
+
this.cleanupTimer = timer;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
get(key) {
|
|
45
|
+
const entry = this.entries.get(key);
|
|
46
|
+
if (!entry)
|
|
47
|
+
return undefined;
|
|
48
|
+
if (entry.expiresAt !== null && Date.now() > entry.expiresAt) {
|
|
49
|
+
this.entries.delete(key);
|
|
50
|
+
return undefined;
|
|
51
|
+
}
|
|
52
|
+
// LRU refresh: move to most-recent position.
|
|
53
|
+
// delete + set is the canonical pattern for reordering a Map.
|
|
54
|
+
this.entries.delete(key);
|
|
55
|
+
this.entries.set(key, entry);
|
|
56
|
+
return entry.value;
|
|
57
|
+
}
|
|
58
|
+
set(key, value, ttlMs) {
|
|
59
|
+
// Evict if at capacity AND adding a new key (updates don't grow size).
|
|
60
|
+
if (!this.entries.has(key) && this.entries.size >= this.maxSize) {
|
|
61
|
+
const oldest = this.entries.keys().next().value;
|
|
62
|
+
if (oldest !== undefined)
|
|
63
|
+
this.entries.delete(oldest);
|
|
64
|
+
}
|
|
65
|
+
const expiresAt = ttlMs != null && ttlMs > 0 ? Date.now() + ttlMs : null;
|
|
66
|
+
// delete + set ensures the key is moved to the most-recent position
|
|
67
|
+
// even on update, keeping LRU order consistent.
|
|
68
|
+
this.entries.delete(key);
|
|
69
|
+
this.entries.set(key, { value, expiresAt });
|
|
70
|
+
}
|
|
71
|
+
delete(key) {
|
|
72
|
+
this.entries.delete(key);
|
|
73
|
+
}
|
|
74
|
+
has(key) {
|
|
75
|
+
// Inline the expiry check to avoid the LRU side-effect of get().
|
|
76
|
+
// `has()` should be a pure query, not a touch.
|
|
77
|
+
const entry = this.entries.get(key);
|
|
78
|
+
if (!entry)
|
|
79
|
+
return false;
|
|
80
|
+
if (entry.expiresAt !== null && Date.now() > entry.expiresAt) {
|
|
81
|
+
this.entries.delete(key);
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
return true;
|
|
85
|
+
}
|
|
86
|
+
clear() {
|
|
87
|
+
this.entries.clear();
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Return the count of live (non-expired) entries.
|
|
91
|
+
*
|
|
92
|
+
* Pure query — does NOT touch LRU order. Expired entries discovered during
|
|
93
|
+
* the scan are evicted opportunistically (they were already invisible to
|
|
94
|
+
* `get()`, so eviction has no observable effect beyond memory reclamation).
|
|
95
|
+
*
|
|
96
|
+
* Two-pass to avoid mutating the Map during iteration (spec-safe).
|
|
97
|
+
*/
|
|
98
|
+
size() {
|
|
99
|
+
const now = Date.now();
|
|
100
|
+
const expired = [];
|
|
101
|
+
let count = 0;
|
|
102
|
+
for (const [key, entry] of this.entries) {
|
|
103
|
+
if (entry.expiresAt !== null && entry.expiresAt <= now) {
|
|
104
|
+
expired.push(key);
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
count++;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
for (const key of expired)
|
|
111
|
+
this.entries.delete(key);
|
|
112
|
+
return count;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Stop the background cleanup timer and release internal state.
|
|
116
|
+
* Safe to call multiple times — subsequent calls are no-ops.
|
|
117
|
+
*/
|
|
118
|
+
destroy() {
|
|
119
|
+
if (this.cleanupTimer !== undefined) {
|
|
120
|
+
clearInterval(this.cleanupTimer);
|
|
121
|
+
this.cleanupTimer = undefined;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Sweep all entries and remove those past their expiry time.
|
|
126
|
+
* Called by the autoCleanup interval; not part of the public contract.
|
|
127
|
+
*/
|
|
128
|
+
_sweep() {
|
|
129
|
+
const now = Date.now();
|
|
130
|
+
const expired = [];
|
|
131
|
+
for (const [key, entry] of this.entries) {
|
|
132
|
+
if (entry.expiresAt !== null && now > entry.expiresAt) {
|
|
133
|
+
expired.push(key);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
for (const key of expired)
|
|
137
|
+
this.entries.delete(key);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
exports.InMemoryStore = InMemoryStore;
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import type { SyncStateStore } from './base.js';
|
|
2
|
+
export interface InMemoryStoreOptions {
|
|
3
|
+
/**
|
|
4
|
+
* Periodically sweep and remove expired entries in the background.
|
|
5
|
+
*
|
|
6
|
+
* Disabled by default. The store evicts lazily on `get()` / `has()` access,
|
|
7
|
+
* which is sufficient for most use cases. Enable `autoCleanup` when the
|
|
8
|
+
* store is long-lived and accumulates many TTL'd entries that are never
|
|
9
|
+
* re-read — for example, a server-side cache that receives write-heavy
|
|
10
|
+
* traffic with low subsequent read rates.
|
|
11
|
+
*/
|
|
12
|
+
autoCleanup?: boolean;
|
|
13
|
+
/**
|
|
14
|
+
* Interval between background sweeps in milliseconds.
|
|
15
|
+
* Defaults to 30 000 (30 seconds). Ignored when `autoCleanup` is false.
|
|
16
|
+
*/
|
|
17
|
+
cleanupIntervalMs?: number;
|
|
18
|
+
/**
|
|
19
|
+
* Maximum number of live entries the store will hold.
|
|
20
|
+
*
|
|
21
|
+
* When `set()` would exceed this limit, the least-recently-used entry is
|
|
22
|
+
* evicted before the new one is inserted (LRU semantics). Updates to an
|
|
23
|
+
* existing key do not trigger eviction.
|
|
24
|
+
*
|
|
25
|
+
* Defaults to `Infinity` (unbounded). Set a finite value for long-running
|
|
26
|
+
* caches with high-cardinality keys to bound memory usage.
|
|
27
|
+
*
|
|
28
|
+
* The LRU order is updated on `get()` and `set()` — both move the accessed
|
|
29
|
+
* key to the most-recent position.
|
|
30
|
+
*/
|
|
31
|
+
maxSize?: number;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Reference `SyncStateStore` implementation backed by a `Map`.
|
|
35
|
+
*
|
|
36
|
+
* # LRU semantics
|
|
37
|
+
*
|
|
38
|
+
* `Map` iteration order is insertion order, so we implement LRU by
|
|
39
|
+
* `delete` + `set` on every access — the most-recently-touched key ends up
|
|
40
|
+
* at the end of the iteration, and the oldest is `entries.keys().next().value`.
|
|
41
|
+
*
|
|
42
|
+
* # Expiry
|
|
43
|
+
*
|
|
44
|
+
* Lazy on `get()` / `has()`: expired entries are deleted when touched.
|
|
45
|
+
* Background sweep (optional) reclaims entries that are never re-read.
|
|
46
|
+
*/
|
|
47
|
+
export declare class InMemoryStore implements SyncStateStore {
|
|
48
|
+
readonly _sync: true;
|
|
49
|
+
private readonly entries;
|
|
50
|
+
private readonly maxSize;
|
|
51
|
+
private cleanupTimer;
|
|
52
|
+
constructor(options?: InMemoryStoreOptions);
|
|
53
|
+
get<T>(key: string): T | undefined;
|
|
54
|
+
set<T>(key: string, value: T, ttlMs?: number): void;
|
|
55
|
+
delete(key: string): void;
|
|
56
|
+
has(key: string): boolean;
|
|
57
|
+
clear(): void;
|
|
58
|
+
/**
|
|
59
|
+
* Return the count of live (non-expired) entries.
|
|
60
|
+
*
|
|
61
|
+
* Pure query — does NOT touch LRU order. Expired entries discovered during
|
|
62
|
+
* the scan are evicted opportunistically (they were already invisible to
|
|
63
|
+
* `get()`, so eviction has no observable effect beyond memory reclamation).
|
|
64
|
+
*
|
|
65
|
+
* Two-pass to avoid mutating the Map during iteration (spec-safe).
|
|
66
|
+
*/
|
|
67
|
+
size(): number;
|
|
68
|
+
/**
|
|
69
|
+
* Stop the background cleanup timer and release internal state.
|
|
70
|
+
* Safe to call multiple times — subsequent calls are no-ops.
|
|
71
|
+
*/
|
|
72
|
+
destroy(): void;
|
|
73
|
+
/**
|
|
74
|
+
* Sweep all entries and remove those past their expiry time.
|
|
75
|
+
* Called by the autoCleanup interval; not part of the public contract.
|
|
76
|
+
*/
|
|
77
|
+
private _sweep;
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=memory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../../src/stores/memory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,WAAW,CAAA;AAwB/C,MAAM,WAAW,oBAAoB;IACnC;;;;;;;;OAQG;IACH,WAAW,CAAC,EAAE,OAAO,CAAA;IAErB;;;OAGG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAE1B;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAID;;;;;;;;;;;;;GAaG;AACH,qBAAa,aAAc,YAAW,cAAc;IAClD,QAAQ,CAAC,KAAK,EAAG,IAAI,CAAS;IAE9B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAoC;IAC5D,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAQ;IAChC,OAAO,CAAC,YAAY,CAA4C;gBAEpD,OAAO,GAAE,oBAAyB;IA0B9C,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,CAAC,GAAG,SAAS;IAiBlC,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI;IAcnD,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAIzB,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAYzB,KAAK,IAAI,IAAI;IAIb;;;;;;;;OAQG;IACH,IAAI,IAAI,MAAM;IAiBd;;;OAGG;IACH,OAAO,IAAI,IAAI;IAOf;;;OAGG;IACH,OAAO,CAAC,MAAM;CAUf"}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
function isUnrefable(t) {
|
|
2
|
+
return typeof t.unref === 'function';
|
|
3
|
+
}
|
|
4
|
+
// ─── Implementation ───────────────────────────────────────────────────────────
|
|
5
|
+
/**
|
|
6
|
+
* Reference `SyncStateStore` implementation backed by a `Map`.
|
|
7
|
+
*
|
|
8
|
+
* # LRU semantics
|
|
9
|
+
*
|
|
10
|
+
* `Map` iteration order is insertion order, so we implement LRU by
|
|
11
|
+
* `delete` + `set` on every access — the most-recently-touched key ends up
|
|
12
|
+
* at the end of the iteration, and the oldest is `entries.keys().next().value`.
|
|
13
|
+
*
|
|
14
|
+
* # Expiry
|
|
15
|
+
*
|
|
16
|
+
* Lazy on `get()` / `has()`: expired entries are deleted when touched.
|
|
17
|
+
* Background sweep (optional) reclaims entries that are never re-read.
|
|
18
|
+
*/
|
|
19
|
+
export class InMemoryStore {
|
|
20
|
+
_sync = true;
|
|
21
|
+
entries = new Map();
|
|
22
|
+
maxSize;
|
|
23
|
+
cleanupTimer;
|
|
24
|
+
constructor(options = {}) {
|
|
25
|
+
const { autoCleanup = false, cleanupIntervalMs = 30_000, maxSize = Number.POSITIVE_INFINITY, } = options;
|
|
26
|
+
if (!Number.isFinite(maxSize) || maxSize <= 0) {
|
|
27
|
+
// Infinity is allowed (unbounded); any other non-positive finite value
|
|
28
|
+
// is a programmer error.
|
|
29
|
+
if (maxSize !== Number.POSITIVE_INFINITY) {
|
|
30
|
+
throw new RangeError(`Actly: InMemoryStore maxSize must be a positive finite number or Infinity, got ${maxSize}`);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
this.maxSize = maxSize;
|
|
34
|
+
if (autoCleanup) {
|
|
35
|
+
const timer = setInterval(() => this._sweep(), cleanupIntervalMs);
|
|
36
|
+
if (isUnrefable(timer))
|
|
37
|
+
timer.unref();
|
|
38
|
+
this.cleanupTimer = timer;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
get(key) {
|
|
42
|
+
const entry = this.entries.get(key);
|
|
43
|
+
if (!entry)
|
|
44
|
+
return undefined;
|
|
45
|
+
if (entry.expiresAt !== null && Date.now() > entry.expiresAt) {
|
|
46
|
+
this.entries.delete(key);
|
|
47
|
+
return undefined;
|
|
48
|
+
}
|
|
49
|
+
// LRU refresh: move to most-recent position.
|
|
50
|
+
// delete + set is the canonical pattern for reordering a Map.
|
|
51
|
+
this.entries.delete(key);
|
|
52
|
+
this.entries.set(key, entry);
|
|
53
|
+
return entry.value;
|
|
54
|
+
}
|
|
55
|
+
set(key, value, ttlMs) {
|
|
56
|
+
// Evict if at capacity AND adding a new key (updates don't grow size).
|
|
57
|
+
if (!this.entries.has(key) && this.entries.size >= this.maxSize) {
|
|
58
|
+
const oldest = this.entries.keys().next().value;
|
|
59
|
+
if (oldest !== undefined)
|
|
60
|
+
this.entries.delete(oldest);
|
|
61
|
+
}
|
|
62
|
+
const expiresAt = ttlMs != null && ttlMs > 0 ? Date.now() + ttlMs : null;
|
|
63
|
+
// delete + set ensures the key is moved to the most-recent position
|
|
64
|
+
// even on update, keeping LRU order consistent.
|
|
65
|
+
this.entries.delete(key);
|
|
66
|
+
this.entries.set(key, { value, expiresAt });
|
|
67
|
+
}
|
|
68
|
+
delete(key) {
|
|
69
|
+
this.entries.delete(key);
|
|
70
|
+
}
|
|
71
|
+
has(key) {
|
|
72
|
+
// Inline the expiry check to avoid the LRU side-effect of get().
|
|
73
|
+
// `has()` should be a pure query, not a touch.
|
|
74
|
+
const entry = this.entries.get(key);
|
|
75
|
+
if (!entry)
|
|
76
|
+
return false;
|
|
77
|
+
if (entry.expiresAt !== null && Date.now() > entry.expiresAt) {
|
|
78
|
+
this.entries.delete(key);
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
81
|
+
return true;
|
|
82
|
+
}
|
|
83
|
+
clear() {
|
|
84
|
+
this.entries.clear();
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Return the count of live (non-expired) entries.
|
|
88
|
+
*
|
|
89
|
+
* Pure query — does NOT touch LRU order. Expired entries discovered during
|
|
90
|
+
* the scan are evicted opportunistically (they were already invisible to
|
|
91
|
+
* `get()`, so eviction has no observable effect beyond memory reclamation).
|
|
92
|
+
*
|
|
93
|
+
* Two-pass to avoid mutating the Map during iteration (spec-safe).
|
|
94
|
+
*/
|
|
95
|
+
size() {
|
|
96
|
+
const now = Date.now();
|
|
97
|
+
const expired = [];
|
|
98
|
+
let count = 0;
|
|
99
|
+
for (const [key, entry] of this.entries) {
|
|
100
|
+
if (entry.expiresAt !== null && entry.expiresAt <= now) {
|
|
101
|
+
expired.push(key);
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
count++;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
for (const key of expired)
|
|
108
|
+
this.entries.delete(key);
|
|
109
|
+
return count;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Stop the background cleanup timer and release internal state.
|
|
113
|
+
* Safe to call multiple times — subsequent calls are no-ops.
|
|
114
|
+
*/
|
|
115
|
+
destroy() {
|
|
116
|
+
if (this.cleanupTimer !== undefined) {
|
|
117
|
+
clearInterval(this.cleanupTimer);
|
|
118
|
+
this.cleanupTimer = undefined;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Sweep all entries and remove those past their expiry time.
|
|
123
|
+
* Called by the autoCleanup interval; not part of the public contract.
|
|
124
|
+
*/
|
|
125
|
+
_sweep() {
|
|
126
|
+
const now = Date.now();
|
|
127
|
+
const expired = [];
|
|
128
|
+
for (const [key, entry] of this.entries) {
|
|
129
|
+
if (entry.expiresAt !== null && now > entry.expiresAt) {
|
|
130
|
+
expired.push(key);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
for (const key of expired)
|
|
134
|
+
this.entries.delete(key);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
//# sourceMappingURL=memory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory.js","sourceRoot":"","sources":["../../src/stores/memory.ts"],"names":[],"mappings":"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"}
|
package/dist/types/index.d.ts
CHANGED
|
@@ -1,51 +1,131 @@
|
|
|
1
|
-
/**
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
/**
|
|
2
|
+
* The async function ACT wraps.
|
|
3
|
+
*
|
|
4
|
+
* Receives an {@link AbortSignal} that fires when:
|
|
5
|
+
* - the caller aborts via `options.signal`,
|
|
6
|
+
* - the per-attempt {@link TimeoutOptions} fires,
|
|
7
|
+
* - the operation-wide {@link ActOptions.totalTimeout} fires.
|
|
8
|
+
*
|
|
9
|
+
* Cooperative cancellation: pass `signal` through to `fetch`, `AbortController`,
|
|
10
|
+
* database drivers, or any primitive that accepts one. If you ignore it, ACT
|
|
11
|
+
* will still return promptly (the outer promise rejects), but the underlying
|
|
12
|
+
* work will keep running in the background — leaking resources until it
|
|
13
|
+
* settles on its own.
|
|
14
|
+
*
|
|
15
|
+
* Backwards compatible: `() => Promise<T>` is assignable to this type, so
|
|
16
|
+
* existing call sites continue to compile and run. They simply forgo
|
|
17
|
+
* cancellation.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* // Cooperative
|
|
21
|
+
* act('user:42', async (signal) => {
|
|
22
|
+
* return fetch(`/api/users/42`, { signal })
|
|
23
|
+
* }, { timeout: { ms: 5_000 } })
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* // Legacy (still works, signal ignored)
|
|
27
|
+
* act('user:42', () => fetchUser(42))
|
|
28
|
+
*/
|
|
29
|
+
export type ActFn<T> = (signal: AbortSignal) => Promise<T> | T;
|
|
30
|
+
/** Where a successful result came from. */
|
|
4
31
|
export type ActSource = 'fresh' | 'cache';
|
|
5
32
|
export interface ActSuccess<T> {
|
|
6
33
|
ok: true;
|
|
7
34
|
value: T;
|
|
8
35
|
source: ActSource;
|
|
9
|
-
/**
|
|
36
|
+
/**
|
|
37
|
+
* Number of attempts made before success.
|
|
38
|
+
*
|
|
39
|
+
* - Fresh success on first try: `1`
|
|
40
|
+
* - Fresh success after N retries: `N`
|
|
41
|
+
* - Cache hit: `0` (no work was performed)
|
|
42
|
+
* - Dedupe joiner: mirrors the originator's attempt count
|
|
43
|
+
*/
|
|
10
44
|
attempts: number;
|
|
11
45
|
}
|
|
12
46
|
export interface ActFailure {
|
|
13
47
|
ok: false;
|
|
14
48
|
error: unknown;
|
|
15
|
-
/**
|
|
49
|
+
/**
|
|
50
|
+
* Number of attempts made before final failure.
|
|
51
|
+
* For dedupe joiners: mirrors the originator's attempt count.
|
|
52
|
+
*/
|
|
16
53
|
attempts: number;
|
|
17
54
|
}
|
|
18
55
|
export type ActResult<T> = ActSuccess<T> | ActFailure;
|
|
19
56
|
export interface RetryOptions {
|
|
20
|
-
/**
|
|
57
|
+
/**
|
|
58
|
+
* Total number of attempts including the first call.
|
|
59
|
+
* Must be an integer >= 1.
|
|
60
|
+
*
|
|
61
|
+
* `attempts: 1` is a no-op (equivalent to omitting `retry`); the policy
|
|
62
|
+
* is not added to the chain. This is intentional — adding a policy that
|
|
63
|
+
* never retries is pure overhead.
|
|
64
|
+
*/
|
|
21
65
|
attempts: number;
|
|
22
|
-
/**
|
|
66
|
+
/**
|
|
67
|
+
* Base delay between attempts in milliseconds. Defaults to 0 (no delay).
|
|
68
|
+
* Must be a non-negative finite number.
|
|
69
|
+
*/
|
|
23
70
|
delayMs?: number;
|
|
24
71
|
/**
|
|
25
72
|
* How the base delay grows per attempt:
|
|
26
|
-
* - 'none' -> always delayMs
|
|
27
|
-
* - 'linear' -> delayMs * attempt
|
|
28
|
-
* - 'exponential' -> delayMs * 2^(attempt-1)
|
|
73
|
+
* - `'none'` -> always `delayMs`
|
|
74
|
+
* - `'linear'` -> `delayMs * attempt`
|
|
75
|
+
* - `'exponential'` -> `delayMs * 2^(attempt-1)`
|
|
76
|
+
*
|
|
77
|
+
* The computed delay is then capped by {@link maxDelay} and jittered by
|
|
78
|
+
* {@link jitter} before being slept.
|
|
79
|
+
*
|
|
80
|
+
* Defaults to `'none'`.
|
|
29
81
|
*/
|
|
30
82
|
backoff?: 'none' | 'linear' | 'exponential';
|
|
83
|
+
/**
|
|
84
|
+
* Hard cap on the computed delay. Defaults to `Infinity`.
|
|
85
|
+
*
|
|
86
|
+
* Without a cap, `exponential` backoff with `delayMs: 1000` and
|
|
87
|
+
* `attempts: 10` would sleep 8.5 minutes between attempts 9 and 10
|
|
88
|
+
* (256 seconds). Set `maxDelay` to something sane (e.g. 30_000) to
|
|
89
|
+
* bound worst-case latency.
|
|
90
|
+
*/
|
|
91
|
+
maxDelay?: number;
|
|
92
|
+
/**
|
|
93
|
+
* Jitter strategy applied to the (post-`maxDelay`) delay.
|
|
94
|
+
*
|
|
95
|
+
* - `'none'` -> no jitter, return delay as-is
|
|
96
|
+
* - `'full'` -> `random() * delay` (default; best for thundering-herd prevention)
|
|
97
|
+
* - `'equal'` -> `delay/2 + random() * delay/2`
|
|
98
|
+
* - `'decorrelated'` -> `base + random() * (delay - base)`
|
|
99
|
+
*
|
|
100
|
+
* Defaults to `'full'`. Jitter prevents synchronised retry storms when
|
|
101
|
+
* many callers fail at the same instant (e.g. after an upstream outage
|
|
102
|
+
* recovers) — without it, all callers retry on the same tick.
|
|
103
|
+
*/
|
|
104
|
+
jitter?: 'none' | 'full' | 'equal' | 'decorrelated';
|
|
31
105
|
/**
|
|
32
106
|
* Predicate called after each failure, before the next attempt.
|
|
33
|
-
* Return false to stop retrying immediately and surface the error.
|
|
107
|
+
* Return `false` to stop retrying immediately and surface the error.
|
|
108
|
+
*
|
|
109
|
+
* Called for every failure including the last attempt (so observers stay
|
|
110
|
+
* informed); the return value is only consulted when there are remaining
|
|
111
|
+
* attempts.
|
|
34
112
|
*
|
|
35
113
|
* Use this to skip retries for errors that are definitively non-recoverable
|
|
36
114
|
* (e.g. HTTP 4xx, AuthError, ValidationError).
|
|
37
115
|
*
|
|
116
|
+
* Default behaviour: retry on every error except `AbortError` (which
|
|
117
|
+
* indicates the caller or a timeout cancelled the operation).
|
|
118
|
+
*
|
|
38
119
|
* @param error The error thrown by the most recent attempt.
|
|
39
120
|
* @param attempt The 1-based number of the attempt that just failed.
|
|
40
|
-
*
|
|
41
|
-
* @example
|
|
42
|
-
* shouldRetry: (err, attempt) =>
|
|
43
|
-
* !(err instanceof HttpError && err.status < 500)
|
|
44
121
|
*/
|
|
45
122
|
shouldRetry?: (error: unknown, attempt: number) => boolean;
|
|
46
123
|
}
|
|
47
124
|
export interface TimeoutOptions {
|
|
48
|
-
/**
|
|
125
|
+
/**
|
|
126
|
+
* Abort after this many milliseconds.
|
|
127
|
+
* Must be a positive finite number.
|
|
128
|
+
*/
|
|
49
129
|
ms: number;
|
|
50
130
|
}
|
|
51
131
|
export interface DedupeOptions {
|
|
@@ -54,63 +134,100 @@ export interface DedupeOptions {
|
|
|
54
134
|
* Opt-in: be explicit when you want this behaviour.
|
|
55
135
|
*/
|
|
56
136
|
enabled: boolean;
|
|
137
|
+
/**
|
|
138
|
+
* Safety-net TTL for the in-flight entry, in milliseconds.
|
|
139
|
+
*
|
|
140
|
+
* If the originator's promise does not settle within this window, the
|
|
141
|
+
* entry is removed from the store so subsequent callers can start fresh.
|
|
142
|
+
* Originator's promise continues in the background until it settles or
|
|
143
|
+
* an outer timeout fires.
|
|
144
|
+
*
|
|
145
|
+
* Default: `Infinity` (no safety net). Pair with `timeout` or
|
|
146
|
+
* `totalTimeout` for proper cancellation in production.
|
|
147
|
+
*/
|
|
148
|
+
inflightTtl?: number;
|
|
57
149
|
}
|
|
58
150
|
export interface CacheOptions {
|
|
59
|
-
/** Keep a successful result for this many
|
|
151
|
+
/** Keep a successful result for this many milliseconds. Must be > 0. */
|
|
60
152
|
ttl: number;
|
|
61
153
|
}
|
|
62
154
|
export interface ActOptions {
|
|
63
155
|
retry?: RetryOptions;
|
|
156
|
+
/** Per-attempt deadline. Each retry gets a fresh clock. */
|
|
64
157
|
timeout?: TimeoutOptions;
|
|
65
158
|
/**
|
|
66
159
|
* Collapse concurrent calls with the same key into one in-flight Promise.
|
|
67
160
|
*
|
|
68
161
|
* Shorthand: `dedupe: true`
|
|
69
|
-
* Full form: `dedupe: { enabled: true }`
|
|
70
|
-
*
|
|
71
|
-
* Both are equivalent. The object form exists for forward compatibility.
|
|
162
|
+
* Full form: `dedupe: { enabled: true, inflightTtl: 30_000 }`
|
|
72
163
|
*/
|
|
73
164
|
dedupe?: boolean | DedupeOptions;
|
|
74
165
|
cache?: CacheOptions;
|
|
75
166
|
/**
|
|
76
167
|
* Hard budget over the ENTIRE operation — including all retry attempts,
|
|
77
|
-
* delays, and the
|
|
168
|
+
* delays, and the per-attempt timeout.
|
|
78
169
|
*
|
|
79
170
|
* Distinct from `timeout`, which resets the clock on every attempt.
|
|
80
171
|
* Use both together to express: "each attempt may take at most X ms,
|
|
81
172
|
* but the whole thing must finish within Y ms."
|
|
82
173
|
*
|
|
83
|
-
* Rejects with TotalTimeoutError if the
|
|
174
|
+
* Rejects with {@link TotalTimeoutError} if the budget fires.
|
|
84
175
|
*/
|
|
85
176
|
totalTimeout?: TimeoutOptions;
|
|
177
|
+
/**
|
|
178
|
+
* Caller-provided cancellation signal.
|
|
179
|
+
*
|
|
180
|
+
* When this signal aborts:
|
|
181
|
+
* - if the operation has not yet started, it rejects immediately with
|
|
182
|
+
* the signal's `reason`,
|
|
183
|
+
* - if it is in progress, the inner {@link ActFn} receives an aborted
|
|
184
|
+
* signal (cooperative cancellation),
|
|
185
|
+
* - if it has already settled, the result is returned as normal.
|
|
186
|
+
*
|
|
187
|
+
* Combined with `timeout` / `totalTimeout`, this gives you full control
|
|
188
|
+
* over cancellation from outside `act()`.
|
|
189
|
+
*/
|
|
190
|
+
signal?: AbortSignal;
|
|
86
191
|
}
|
|
87
192
|
/**
|
|
88
193
|
* Mutable bag mutated in-place during execution.
|
|
89
194
|
* Policies annotate it; act() reads the final state to build ActResult.
|
|
195
|
+
*
|
|
196
|
+
* For dedupe joiners: the bag is copied from the originator's bag after the
|
|
197
|
+
* in-flight promise settles (success or failure), so `attempts` reflects
|
|
198
|
+
* the real effort, not the default `1`.
|
|
90
199
|
*/
|
|
91
200
|
export interface RunMeta {
|
|
92
201
|
attempts: number;
|
|
93
202
|
source: ActSource;
|
|
94
203
|
}
|
|
95
|
-
/** Everything a policy receives about the current run */
|
|
204
|
+
/** Everything a policy receives about the current run. */
|
|
96
205
|
export interface PolicyContext {
|
|
97
206
|
key: string;
|
|
98
|
-
store:
|
|
207
|
+
store: AnyStateStore;
|
|
99
208
|
meta: RunMeta;
|
|
100
209
|
}
|
|
101
210
|
/**
|
|
102
211
|
* The ONLY shape the executor knows about policies.
|
|
103
212
|
*
|
|
104
|
-
* A policy wraps ActFn<T
|
|
105
|
-
*
|
|
106
|
-
*
|
|
213
|
+
* A policy wraps `ActFn<T>` and returns a new `ActFn<T>`. It may intercept
|
|
214
|
+
* before, after, or instead of the inner call. The executor never imports
|
|
215
|
+
* a concrete policy — only this type.
|
|
107
216
|
*/
|
|
108
217
|
export type PolicyApplier<T> = (fn: ActFn<T>, ctx: PolicyContext) => ActFn<T>;
|
|
109
|
-
|
|
110
|
-
export
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
218
|
+
import type { SyncStateStore, AsyncStateStore } from '../stores/base.js';
|
|
219
|
+
export type { SyncStateStore, AsyncStateStore };
|
|
220
|
+
/**
|
|
221
|
+
* Public store type. v1.1+: alias for `SyncStateStore`.
|
|
222
|
+
*
|
|
223
|
+
* Kept for backwards compatibility — every v1.0 consumer typed against
|
|
224
|
+
* `StateStore` continues to compile without changes. A future major version
|
|
225
|
+
* may widen this to `SyncStateStore | AsyncStateStore`.
|
|
226
|
+
*/
|
|
227
|
+
export type StateStore = SyncStateStore;
|
|
228
|
+
/**
|
|
229
|
+
* Union of sync and async stores. Used internally by `PolicyContext` and
|
|
230
|
+
* exported for consumers building custom policy chains or store adapters.
|
|
231
|
+
*/
|
|
232
|
+
export type AnyStateStore = SyncStateStore | AsyncStateStore;
|
|
116
233
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAEA
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"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"}
|