actly 1.1.5 → 1.2.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.
- package/README.md +232 -434
- package/dist/core/act.cjs +353 -35
- package/dist/core/act.d.ts.map +1 -1
- package/dist/core/act.js +355 -37
- package/dist/core/act.js.map +1 -1
- package/dist/core/executor.cjs +2 -0
- package/dist/core/executor.d.ts +6 -1
- package/dist/core/executor.d.ts.map +1 -1
- package/dist/core/executor.js +2 -0
- package/dist/core/executor.js.map +1 -1
- package/dist/core/health.cjs +34 -0
- package/dist/core/health.d.ts +18 -0
- package/dist/core/health.d.ts.map +1 -0
- package/dist/core/health.js +28 -0
- package/dist/core/health.js.map +1 -0
- package/dist/core/shutdown.cjs +60 -0
- package/dist/core/shutdown.d.ts +8 -0
- package/dist/core/shutdown.d.ts.map +1 -0
- package/dist/core/shutdown.js +56 -0
- package/dist/core/shutdown.js.map +1 -0
- package/dist/core/tenant.cjs +71 -0
- package/dist/core/tenant.d.ts +29 -0
- package/dist/core/tenant.d.ts.map +1 -0
- package/dist/core/tenant.js +68 -0
- package/dist/core/tenant.js.map +1 -0
- package/dist/errors.cjs +182 -0
- package/dist/errors.d.ts +151 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +171 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.cjs +44 -4
- package/dist/index.d.ts +17 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +17 -1
- package/dist/index.js.map +1 -1
- package/dist/observability.cjs +45 -0
- package/dist/observability.d.ts +145 -0
- package/dist/observability.d.ts.map +1 -0
- package/dist/observability.js +43 -0
- package/dist/observability.js.map +1 -0
- package/dist/policies/bulkhead.cjs +97 -0
- package/dist/policies/bulkhead.d.ts +3 -0
- package/dist/policies/bulkhead.d.ts.map +1 -0
- package/dist/policies/bulkhead.js +95 -0
- package/dist/policies/bulkhead.js.map +1 -0
- package/dist/policies/cache.cjs +168 -31
- package/dist/policies/cache.d.ts +17 -4
- package/dist/policies/cache.d.ts.map +1 -1
- package/dist/policies/cache.js +168 -31
- package/dist/policies/cache.js.map +1 -1
- package/dist/policies/circuitBreaker.cjs +85 -0
- package/dist/policies/circuitBreaker.d.ts +3 -0
- package/dist/policies/circuitBreaker.d.ts.map +1 -0
- package/dist/policies/circuitBreaker.js +83 -0
- package/dist/policies/circuitBreaker.js.map +1 -0
- package/dist/policies/dedupe.cjs +74 -45
- package/dist/policies/dedupe.d.ts +10 -28
- package/dist/policies/dedupe.d.ts.map +1 -1
- package/dist/policies/dedupe.js +74 -45
- package/dist/policies/dedupe.js.map +1 -1
- package/dist/policies/rateLimit.cjs +35 -0
- package/dist/policies/rateLimit.d.ts +3 -0
- package/dist/policies/rateLimit.d.ts.map +1 -0
- package/dist/policies/rateLimit.js +33 -0
- package/dist/policies/rateLimit.js.map +1 -0
- package/dist/policies/retry.cjs +45 -8
- package/dist/policies/retry.d.ts.map +1 -1
- package/dist/policies/retry.js +45 -8
- package/dist/policies/retry.js.map +1 -1
- package/dist/policies/timeout.cjs +25 -53
- package/dist/policies/timeout.d.ts +2 -33
- package/dist/policies/timeout.d.ts.map +1 -1
- package/dist/policies/timeout.js +31 -48
- package/dist/policies/timeout.js.map +1 -1
- package/dist/state/store.cjs +3 -3
- package/dist/state/store.d.ts +3 -3
- package/dist/state/store.js +3 -3
- package/dist/stores/memory.cjs +126 -53
- package/dist/stores/memory.d.ts +35 -16
- package/dist/stores/memory.d.ts.map +1 -1
- package/dist/stores/memory.js +125 -53
- package/dist/stores/memory.js.map +1 -1
- package/dist/types/index.d.ts +176 -3
- package/dist/types/index.d.ts.map +1 -1
- package/dist/utils/abort.cjs +108 -38
- package/dist/utils/abort.d.ts +43 -19
- package/dist/utils/abort.d.ts.map +1 -1
- package/dist/utils/abort.js +108 -38
- package/dist/utils/abort.js.map +1 -1
- package/dist/utils/abortPool.cjs +26 -0
- package/dist/utils/abortPool.d.ts +4 -0
- package/dist/utils/abortPool.d.ts.map +1 -0
- package/dist/utils/abortPool.js +22 -0
- package/dist/utils/abortPool.js.map +1 -0
- package/dist/utils/backoff.cjs +12 -1
- package/dist/utils/backoff.d.ts.map +1 -1
- package/dist/utils/backoff.js +12 -1
- package/dist/utils/backoff.js.map +1 -1
- package/dist/utils/key.cjs +77 -0
- package/dist/utils/key.d.ts +29 -0
- package/dist/utils/key.d.ts.map +1 -0
- package/dist/utils/key.js +75 -0
- package/dist/utils/key.js.map +1 -0
- package/dist/utils/limits.cjs +40 -0
- package/dist/utils/limits.d.ts +39 -0
- package/dist/utils/limits.d.ts.map +1 -0
- package/dist/utils/limits.js +38 -0
- package/dist/utils/limits.js.map +1 -0
- package/dist/utils/sanitize.cjs +29 -0
- package/dist/utils/sanitize.d.ts +3 -0
- package/dist/utils/sanitize.d.ts.map +1 -0
- package/dist/utils/sanitize.js +26 -0
- package/dist/utils/sanitize.js.map +1 -0
- package/dist/utils/validate.cjs +90 -16
- package/dist/utils/validate.d.ts +11 -0
- package/dist/utils/validate.d.ts.map +1 -1
- package/dist/utils/validate.js +85 -16
- package/dist/utils/validate.js.map +1 -1
- package/package.json +6 -5
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Actly error taxonomy.
|
|
3
|
+
*
|
|
4
|
+
* Six classes (one abstract base + five concrete). Each carries a stable
|
|
5
|
+
* `code` field so consumers can switch on strings instead of brittle
|
|
6
|
+
* `instanceof` chains across realm boundaries (e.g. errors serialised
|
|
7
|
+
* over IPC).
|
|
8
|
+
*
|
|
9
|
+
* # Why these six?
|
|
10
|
+
*
|
|
11
|
+
* - `ActlyError` — abstract base for `instanceof ActlyError` checks
|
|
12
|
+
* - `ActlyAbortError` — caller / signal cancellation
|
|
13
|
+
* - `TimeoutError` — per-attempt deadline
|
|
14
|
+
* - `TotalTimeoutError` — operation-wide budget
|
|
15
|
+
* - `RetryExhaustedError`— last attempt's error wrapped with context
|
|
16
|
+
* - `ValidationError` — programmer error (invalid options)
|
|
17
|
+
*
|
|
18
|
+
* NO circuit/bulkhead/rate-limit errors — those policies don't exist in
|
|
19
|
+
* core. Adding orphan error classes violates the "every feature must map
|
|
20
|
+
* to a real runtime failure mode" rule.
|
|
21
|
+
*
|
|
22
|
+
* # `code` field
|
|
23
|
+
*
|
|
24
|
+
* Stable string identifier. Use this for switch statements and telemetry
|
|
25
|
+
* tags. The class name can change across versions; `code` won't.
|
|
26
|
+
*/
|
|
27
|
+
/** Base class for all actly errors. Enables `instanceof ActlyError` checks. */
|
|
28
|
+
export declare abstract class ActlyError extends Error {
|
|
29
|
+
/** Stable string identifier. Use for telemetry / switch statements. */
|
|
30
|
+
abstract readonly code: string;
|
|
31
|
+
/** The key associated with the failure, if applicable. */
|
|
32
|
+
readonly key?: string;
|
|
33
|
+
constructor(message: string, options?: {
|
|
34
|
+
key?: string;
|
|
35
|
+
cause?: unknown;
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Thrown when the caller's signal, per-attempt timeout, or total timeout
|
|
40
|
+
* aborts the operation.
|
|
41
|
+
*
|
|
42
|
+
* `cause` carries the original abort reason (e.g. user-supplied
|
|
43
|
+
* `controller.abort(new Error('user-cancelled'))` → cause.message is
|
|
44
|
+
* 'user-cancelled').
|
|
45
|
+
*
|
|
46
|
+
* Wraps the raw abort reason in a typed error so consumers can
|
|
47
|
+
* `instanceof`-check it consistently across all abort sources.
|
|
48
|
+
*/
|
|
49
|
+
export declare class ActlyAbortError extends ActlyError {
|
|
50
|
+
readonly code: "ACTLY_ABORT";
|
|
51
|
+
constructor(options?: {
|
|
52
|
+
key?: string;
|
|
53
|
+
cause?: unknown;
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Thrown when a per-attempt `timeout` deadline fires.
|
|
58
|
+
*
|
|
59
|
+
* Carries the configured `ms` so callers can log/alert precisely:
|
|
60
|
+
*
|
|
61
|
+
* ```ts
|
|
62
|
+
* if (!result.ok && result.error instanceof TimeoutError) {
|
|
63
|
+
* console.log(`attempt timed out after ${result.error.ms}ms`)
|
|
64
|
+
* }
|
|
65
|
+
* ```
|
|
66
|
+
*/
|
|
67
|
+
export declare class TimeoutError extends ActlyError {
|
|
68
|
+
readonly code: "ACTLY_TIMEOUT";
|
|
69
|
+
readonly ms: number;
|
|
70
|
+
constructor(ms: number, options?: {
|
|
71
|
+
key?: string;
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Thrown when the operation-wide `totalTimeout` budget fires.
|
|
76
|
+
*
|
|
77
|
+
* Distinct from `TimeoutError` (per-attempt) so callers can `instanceof`-check
|
|
78
|
+
* which deadline fired.
|
|
79
|
+
*/
|
|
80
|
+
export declare class TotalTimeoutError extends ActlyError {
|
|
81
|
+
readonly code: "ACTLY_TOTAL_TIMEOUT";
|
|
82
|
+
readonly ms: number;
|
|
83
|
+
constructor(ms: number, options?: {
|
|
84
|
+
key?: string;
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Thrown when all retry attempts are exhausted. The `lastError` is the
|
|
89
|
+
* final attempt's error; `errors` is the array of all attempt errors
|
|
90
|
+
* (useful for debugging patterns across retries).
|
|
91
|
+
*
|
|
92
|
+
* Wraps retry exhaustion with context so consumers can distinguish "single
|
|
93
|
+
* fn error" from "retry exhausted after N attempts".
|
|
94
|
+
*
|
|
95
|
+
* # When is this thrown vs the raw error?
|
|
96
|
+
*
|
|
97
|
+
* `retryPolicy` throws `RetryExhaustedError` when:
|
|
98
|
+
* - `attempts > 1` AND
|
|
99
|
+
* - all attempts failed AND
|
|
100
|
+
* - the default `shouldRetry` (or user-supplied predicate) returned `true`
|
|
101
|
+
* for at least one failure
|
|
102
|
+
*
|
|
103
|
+
* If the user's `shouldRetry` returns `false` on the first attempt, the
|
|
104
|
+
* raw error is thrown (no retries happened — not "exhausted").
|
|
105
|
+
*/
|
|
106
|
+
export declare class RetryExhaustedError extends ActlyError {
|
|
107
|
+
readonly code: "ACTLY_RETRY_EXHAUSTED";
|
|
108
|
+
readonly attempts: number;
|
|
109
|
+
readonly lastError: unknown;
|
|
110
|
+
readonly errors: readonly unknown[];
|
|
111
|
+
constructor(options: {
|
|
112
|
+
key?: string;
|
|
113
|
+
attempts: number;
|
|
114
|
+
lastError: unknown;
|
|
115
|
+
errors: readonly unknown[];
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Thrown on invalid option shapes / keys / store contracts. Programmer
|
|
120
|
+
* errors — these surface synchronously, NOT as `ActFailure`, because the
|
|
121
|
+
* caller's code is broken.
|
|
122
|
+
*
|
|
123
|
+
* Wraps the underlying `TypeError` / `RangeError` so consumers catching
|
|
124
|
+
* `ActlyError` get a consistent type for all actly-thrown errors.
|
|
125
|
+
*/
|
|
126
|
+
export declare class ValidationError extends ActlyError {
|
|
127
|
+
readonly code: "ACTLY_VALIDATION";
|
|
128
|
+
constructor(message: string, options?: {
|
|
129
|
+
field?: string;
|
|
130
|
+
});
|
|
131
|
+
readonly field?: string;
|
|
132
|
+
}
|
|
133
|
+
/** Thrown when a circuit breaker is open and blocks the call. */
|
|
134
|
+
export declare class CircuitBreakerOpenError extends ActlyError {
|
|
135
|
+
readonly code: "ACTLY_CIRCUIT_OPEN";
|
|
136
|
+
readonly key: string;
|
|
137
|
+
constructor(key: string, ms: number);
|
|
138
|
+
}
|
|
139
|
+
/** Thrown when a bulkhead is full (maxConcurrent reached, queue timed out). */
|
|
140
|
+
export declare class BulkheadOverflowError extends ActlyError {
|
|
141
|
+
readonly code: "ACTLY_BULKHEAD_FULL";
|
|
142
|
+
readonly key: string;
|
|
143
|
+
constructor(key: string, maxConcurrent: number);
|
|
144
|
+
}
|
|
145
|
+
/** Thrown when a rate limit is exceeded. */
|
|
146
|
+
export declare class RateLimitError extends ActlyError {
|
|
147
|
+
readonly code: "ACTLY_RATE_LIMIT";
|
|
148
|
+
readonly key: string;
|
|
149
|
+
constructor(key: string, maxCalls: number, windowMs: number);
|
|
150
|
+
}
|
|
151
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,+EAA+E;AAC/E,8BAAsB,UAAW,SAAQ,KAAK;IAC5C,uEAAuE;IACvE,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IAC9B,0DAA0D;IAC1D,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAA;gBAET,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,GAAG,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE;CAUzE;AAED;;;;;;;;;;GAUG;AACH,qBAAa,eAAgB,SAAQ,UAAU;IAC7C,QAAQ,CAAC,IAAI,EAAG,aAAa,CAAS;gBAE1B,OAAO,CAAC,EAAE;QAAE,GAAG,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE;CAKxD;AAED;;;;;;;;;;GAUG;AACH,qBAAa,YAAa,SAAQ,UAAU;IAC1C,QAAQ,CAAC,IAAI,EAAG,eAAe,CAAS;IACxC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;gBAEP,EAAE,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE;CAInD;AAED;;;;;GAKG;AACH,qBAAa,iBAAkB,SAAQ,UAAU;IAC/C,QAAQ,CAAC,IAAI,EAAG,qBAAqB,CAAS;IAC9C,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;gBAEP,EAAE,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE;CAInD;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,qBAAa,mBAAoB,SAAQ,UAAU;IACjD,QAAQ,CAAC,IAAI,EAAG,uBAAuB,CAAS;IAChD,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAA;IAC3B,QAAQ,CAAC,MAAM,EAAE,SAAS,OAAO,EAAE,CAAA;gBAEvB,OAAO,EAAE;QACnB,GAAG,CAAC,EAAE,MAAM,CAAA;QACZ,QAAQ,EAAE,MAAM,CAAA;QAChB,SAAS,EAAE,OAAO,CAAA;QAClB,MAAM,EAAE,SAAS,OAAO,EAAE,CAAA;KAC3B;CAWF;AAED;;;;;;;GAOG;AACH,qBAAa,eAAgB,SAAQ,UAAU;IAC7C,QAAQ,CAAC,IAAI,EAAG,kBAAkB,CAAS;gBAE/B,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE;IAMzD,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CACxB;AAID,iEAAiE;AACjE,qBAAa,uBAAwB,SAAQ,UAAU;IACrD,QAAQ,CAAC,IAAI,EAAG,oBAAoB,CAAS;IAC7C,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;gBAER,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM;CAIpC;AAED,+EAA+E;AAC/E,qBAAa,qBAAsB,SAAQ,UAAU;IACnD,QAAQ,CAAC,IAAI,EAAG,qBAAqB,CAAS;IAC9C,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;gBAER,GAAG,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM;CAI/C;AAED,4CAA4C;AAC5C,qBAAa,cAAe,SAAQ,UAAU;IAC5C,QAAQ,CAAC,IAAI,EAAG,kBAAkB,CAAS;IAC3C,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;gBAER,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM;CAI5D"}
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Actly error taxonomy.
|
|
3
|
+
*
|
|
4
|
+
* Six classes (one abstract base + five concrete). Each carries a stable
|
|
5
|
+
* `code` field so consumers can switch on strings instead of brittle
|
|
6
|
+
* `instanceof` chains across realm boundaries (e.g. errors serialised
|
|
7
|
+
* over IPC).
|
|
8
|
+
*
|
|
9
|
+
* # Why these six?
|
|
10
|
+
*
|
|
11
|
+
* - `ActlyError` — abstract base for `instanceof ActlyError` checks
|
|
12
|
+
* - `ActlyAbortError` — caller / signal cancellation
|
|
13
|
+
* - `TimeoutError` — per-attempt deadline
|
|
14
|
+
* - `TotalTimeoutError` — operation-wide budget
|
|
15
|
+
* - `RetryExhaustedError`— last attempt's error wrapped with context
|
|
16
|
+
* - `ValidationError` — programmer error (invalid options)
|
|
17
|
+
*
|
|
18
|
+
* NO circuit/bulkhead/rate-limit errors — those policies don't exist in
|
|
19
|
+
* core. Adding orphan error classes violates the "every feature must map
|
|
20
|
+
* to a real runtime failure mode" rule.
|
|
21
|
+
*
|
|
22
|
+
* # `code` field
|
|
23
|
+
*
|
|
24
|
+
* Stable string identifier. Use this for switch statements and telemetry
|
|
25
|
+
* tags. The class name can change across versions; `code` won't.
|
|
26
|
+
*/
|
|
27
|
+
/** Base class for all actly errors. Enables `instanceof ActlyError` checks. */
|
|
28
|
+
export class ActlyError extends Error {
|
|
29
|
+
/** The key associated with the failure, if applicable. */
|
|
30
|
+
key;
|
|
31
|
+
constructor(message, options) {
|
|
32
|
+
super(message, options?.cause !== undefined ? { cause: options.cause } : undefined);
|
|
33
|
+
this.name = new.target.name;
|
|
34
|
+
if (options?.key !== undefined) {
|
|
35
|
+
Object.defineProperty(this, 'key', { value: options.key, enumerable: true });
|
|
36
|
+
}
|
|
37
|
+
// Restore prototype chain after Error inheritance (TS es2022 target
|
|
38
|
+
// may strip it). This ensures `instanceof` works correctly.
|
|
39
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Thrown when the caller's signal, per-attempt timeout, or total timeout
|
|
44
|
+
* aborts the operation.
|
|
45
|
+
*
|
|
46
|
+
* `cause` carries the original abort reason (e.g. user-supplied
|
|
47
|
+
* `controller.abort(new Error('user-cancelled'))` → cause.message is
|
|
48
|
+
* 'user-cancelled').
|
|
49
|
+
*
|
|
50
|
+
* Wraps the raw abort reason in a typed error so consumers can
|
|
51
|
+
* `instanceof`-check it consistently across all abort sources.
|
|
52
|
+
*/
|
|
53
|
+
export class ActlyAbortError extends ActlyError {
|
|
54
|
+
code = 'ACTLY_ABORT';
|
|
55
|
+
constructor(options) {
|
|
56
|
+
const causeMsg = options?.cause instanceof Error ? options.cause.message : String(options?.cause ?? 'aborted');
|
|
57
|
+
super(`Actly operation aborted: ${causeMsg}`, options);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Thrown when a per-attempt `timeout` deadline fires.
|
|
62
|
+
*
|
|
63
|
+
* Carries the configured `ms` so callers can log/alert precisely:
|
|
64
|
+
*
|
|
65
|
+
* ```ts
|
|
66
|
+
* if (!result.ok && result.error instanceof TimeoutError) {
|
|
67
|
+
* console.log(`attempt timed out after ${result.error.ms}ms`)
|
|
68
|
+
* }
|
|
69
|
+
* ```
|
|
70
|
+
*/
|
|
71
|
+
export class TimeoutError extends ActlyError {
|
|
72
|
+
code = 'ACTLY_TIMEOUT';
|
|
73
|
+
ms;
|
|
74
|
+
constructor(ms, options) {
|
|
75
|
+
super(`ACT timed out after ${ms}ms`, options);
|
|
76
|
+
this.ms = ms;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Thrown when the operation-wide `totalTimeout` budget fires.
|
|
81
|
+
*
|
|
82
|
+
* Distinct from `TimeoutError` (per-attempt) so callers can `instanceof`-check
|
|
83
|
+
* which deadline fired.
|
|
84
|
+
*/
|
|
85
|
+
export class TotalTimeoutError extends ActlyError {
|
|
86
|
+
code = 'ACTLY_TOTAL_TIMEOUT';
|
|
87
|
+
ms;
|
|
88
|
+
constructor(ms, options) {
|
|
89
|
+
super(`ACT total timeout exceeded after ${ms}ms`, options);
|
|
90
|
+
this.ms = ms;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Thrown when all retry attempts are exhausted. The `lastError` is the
|
|
95
|
+
* final attempt's error; `errors` is the array of all attempt errors
|
|
96
|
+
* (useful for debugging patterns across retries).
|
|
97
|
+
*
|
|
98
|
+
* Wraps retry exhaustion with context so consumers can distinguish "single
|
|
99
|
+
* fn error" from "retry exhausted after N attempts".
|
|
100
|
+
*
|
|
101
|
+
* # When is this thrown vs the raw error?
|
|
102
|
+
*
|
|
103
|
+
* `retryPolicy` throws `RetryExhaustedError` when:
|
|
104
|
+
* - `attempts > 1` AND
|
|
105
|
+
* - all attempts failed AND
|
|
106
|
+
* - the default `shouldRetry` (or user-supplied predicate) returned `true`
|
|
107
|
+
* for at least one failure
|
|
108
|
+
*
|
|
109
|
+
* If the user's `shouldRetry` returns `false` on the first attempt, the
|
|
110
|
+
* raw error is thrown (no retries happened — not "exhausted").
|
|
111
|
+
*/
|
|
112
|
+
export class RetryExhaustedError extends ActlyError {
|
|
113
|
+
code = 'ACTLY_RETRY_EXHAUSTED';
|
|
114
|
+
attempts;
|
|
115
|
+
lastError;
|
|
116
|
+
errors;
|
|
117
|
+
constructor(options) {
|
|
118
|
+
const lastMsg = options.lastError instanceof Error ? options.lastError.message : String(options.lastError);
|
|
119
|
+
super(`ACT retry exhausted after ${options.attempts} attempts; last error: ${lastMsg}`, { key: options.key, cause: options.lastError });
|
|
120
|
+
this.attempts = options.attempts;
|
|
121
|
+
this.lastError = options.lastError;
|
|
122
|
+
this.errors = options.errors;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Thrown on invalid option shapes / keys / store contracts. Programmer
|
|
127
|
+
* errors — these surface synchronously, NOT as `ActFailure`, because the
|
|
128
|
+
* caller's code is broken.
|
|
129
|
+
*
|
|
130
|
+
* Wraps the underlying `TypeError` / `RangeError` so consumers catching
|
|
131
|
+
* `ActlyError` get a consistent type for all actly-thrown errors.
|
|
132
|
+
*/
|
|
133
|
+
export class ValidationError extends ActlyError {
|
|
134
|
+
code = 'ACTLY_VALIDATION';
|
|
135
|
+
constructor(message, options) {
|
|
136
|
+
super(message);
|
|
137
|
+
if (options?.field !== undefined) {
|
|
138
|
+
Object.defineProperty(this, 'field', { value: options.field, enumerable: true });
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
field;
|
|
142
|
+
}
|
|
143
|
+
// ─── Hardening error classes ─────────────────────────────────────────────────
|
|
144
|
+
/** Thrown when a circuit breaker is open and blocks the call. */
|
|
145
|
+
export class CircuitBreakerOpenError extends ActlyError {
|
|
146
|
+
code = 'ACTLY_CIRCUIT_OPEN';
|
|
147
|
+
key;
|
|
148
|
+
constructor(key, ms) {
|
|
149
|
+
super(`Circuit breaker open for key "${key}" — retry after ${ms}ms`);
|
|
150
|
+
this.key = key;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
/** Thrown when a bulkhead is full (maxConcurrent reached, queue timed out). */
|
|
154
|
+
export class BulkheadOverflowError extends ActlyError {
|
|
155
|
+
code = 'ACTLY_BULKHEAD_FULL';
|
|
156
|
+
key;
|
|
157
|
+
constructor(key, maxConcurrent) {
|
|
158
|
+
super(`Bulkhead full for key "${key}" — maxConcurrent ${maxConcurrent} reached`);
|
|
159
|
+
this.key = key;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
/** Thrown when a rate limit is exceeded. */
|
|
163
|
+
export class RateLimitError extends ActlyError {
|
|
164
|
+
code = 'ACTLY_RATE_LIMIT';
|
|
165
|
+
key;
|
|
166
|
+
constructor(key, maxCalls, windowMs) {
|
|
167
|
+
super(`Rate limit exceeded for key "${key}" — ${maxCalls} calls per ${windowMs}ms`);
|
|
168
|
+
this.key = key;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"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"}
|
package/dist/index.cjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
// ─── Primary API ──────────────────────────────────────────────────────────────
|
|
3
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
-
exports.TotalTimeoutError = exports.TimeoutError = exports.isAsyncStore = exports.isSyncStore = exports.InMemoryStore = exports.REQUIRES_SYNC_STORE = exports.execute = exports.withStore = exports.invalidate = exports.act = void 0;
|
|
4
|
+
exports.poolSize = exports.releaseController = exports.acquireController = exports.sanitizeError = exports.sanitizeErrorMessage = exports.createAsyncTenantStore = exports.createTenantStore = exports.drain = exports.createHealthCheck = exports.RateLimitError = exports.BulkheadOverflowError = exports.CircuitBreakerOpenError = exports.LIMITS = exports.computeDelay = exports.sanitizeKey = exports.isAbortError = exports.linkSignal = exports.sleep = exports.raceAbort = exports.anySignal = exports.ValidationError = exports.RetryExhaustedError = exports.TotalTimeoutError = exports.TimeoutError = exports.ActlyAbortError = exports.ActlyError = exports.isAsyncStore = exports.isSyncStore = exports.InMemoryStore = exports.REQUIRES_SYNC_STORE = exports.execute = exports.withStore = exports.invalidate = exports.act = void 0;
|
|
5
5
|
var act_js_1 = require("./core/act.js");
|
|
6
6
|
Object.defineProperty(exports, "act", { enumerable: true, get: function () { return act_js_1.act; } });
|
|
7
7
|
Object.defineProperty(exports, "invalidate", { enumerable: true, get: function () { return act_js_1.invalidate; } });
|
|
@@ -17,6 +17,46 @@ var base_js_1 = require("./stores/base.js");
|
|
|
17
17
|
Object.defineProperty(exports, "isSyncStore", { enumerable: true, get: function () { return base_js_1.isSyncStore; } });
|
|
18
18
|
Object.defineProperty(exports, "isAsyncStore", { enumerable: true, get: function () { return base_js_1.isAsyncStore; } });
|
|
19
19
|
// ─── Error classes ────────────────────────────────────────────────────────────
|
|
20
|
-
var
|
|
21
|
-
Object.defineProperty(exports, "
|
|
22
|
-
Object.defineProperty(exports, "
|
|
20
|
+
var errors_js_1 = require("./errors.js");
|
|
21
|
+
Object.defineProperty(exports, "ActlyError", { enumerable: true, get: function () { return errors_js_1.ActlyError; } });
|
|
22
|
+
Object.defineProperty(exports, "ActlyAbortError", { enumerable: true, get: function () { return errors_js_1.ActlyAbortError; } });
|
|
23
|
+
Object.defineProperty(exports, "TimeoutError", { enumerable: true, get: function () { return errors_js_1.TimeoutError; } });
|
|
24
|
+
Object.defineProperty(exports, "TotalTimeoutError", { enumerable: true, get: function () { return errors_js_1.TotalTimeoutError; } });
|
|
25
|
+
Object.defineProperty(exports, "RetryExhaustedError", { enumerable: true, get: function () { return errors_js_1.RetryExhaustedError; } });
|
|
26
|
+
Object.defineProperty(exports, "ValidationError", { enumerable: true, get: function () { return errors_js_1.ValidationError; } });
|
|
27
|
+
// ─── Utilities (for custom policy authors) ────────────────────────────────────
|
|
28
|
+
var abort_js_1 = require("./utils/abort.js");
|
|
29
|
+
Object.defineProperty(exports, "anySignal", { enumerable: true, get: function () { return abort_js_1.anySignal; } });
|
|
30
|
+
Object.defineProperty(exports, "raceAbort", { enumerable: true, get: function () { return abort_js_1.raceAbort; } });
|
|
31
|
+
Object.defineProperty(exports, "sleep", { enumerable: true, get: function () { return abort_js_1.sleep; } });
|
|
32
|
+
Object.defineProperty(exports, "linkSignal", { enumerable: true, get: function () { return abort_js_1.linkSignal; } });
|
|
33
|
+
Object.defineProperty(exports, "isAbortError", { enumerable: true, get: function () { return abort_js_1.isAbortError; } });
|
|
34
|
+
var key_js_1 = require("./utils/key.js");
|
|
35
|
+
Object.defineProperty(exports, "sanitizeKey", { enumerable: true, get: function () { return key_js_1.sanitizeKey; } });
|
|
36
|
+
var backoff_js_1 = require("./utils/backoff.js");
|
|
37
|
+
Object.defineProperty(exports, "computeDelay", { enumerable: true, get: function () { return backoff_js_1.computeDelay; } });
|
|
38
|
+
var limits_js_1 = require("./utils/limits.js");
|
|
39
|
+
Object.defineProperty(exports, "LIMITS", { enumerable: true, get: function () { return limits_js_1.LIMITS; } });
|
|
40
|
+
// ─── Hardening: new error classes ────────────────────────────────────────────
|
|
41
|
+
var errors_js_2 = require("./errors.js");
|
|
42
|
+
Object.defineProperty(exports, "CircuitBreakerOpenError", { enumerable: true, get: function () { return errors_js_2.CircuitBreakerOpenError; } });
|
|
43
|
+
Object.defineProperty(exports, "BulkheadOverflowError", { enumerable: true, get: function () { return errors_js_2.BulkheadOverflowError; } });
|
|
44
|
+
Object.defineProperty(exports, "RateLimitError", { enumerable: true, get: function () { return errors_js_2.RateLimitError; } });
|
|
45
|
+
// ─── Hardening: health check & graceful shutdown ─────────────────────────────
|
|
46
|
+
var health_js_1 = require("./core/health.js");
|
|
47
|
+
Object.defineProperty(exports, "createHealthCheck", { enumerable: true, get: function () { return health_js_1.createHealthCheck; } });
|
|
48
|
+
var shutdown_js_1 = require("./core/shutdown.js");
|
|
49
|
+
Object.defineProperty(exports, "drain", { enumerable: true, get: function () { return shutdown_js_1.drain; } });
|
|
50
|
+
// ─── Hardening: tenant isolation ─────────────────────────────────────────────
|
|
51
|
+
var tenant_js_1 = require("./core/tenant.js");
|
|
52
|
+
Object.defineProperty(exports, "createTenantStore", { enumerable: true, get: function () { return tenant_js_1.createTenantStore; } });
|
|
53
|
+
Object.defineProperty(exports, "createAsyncTenantStore", { enumerable: true, get: function () { return tenant_js_1.createAsyncTenantStore; } });
|
|
54
|
+
// ─── Hardening: error sanitization ───────────────────────────────────────────
|
|
55
|
+
var sanitize_js_1 = require("./utils/sanitize.js");
|
|
56
|
+
Object.defineProperty(exports, "sanitizeErrorMessage", { enumerable: true, get: function () { return sanitize_js_1.sanitizeErrorMessage; } });
|
|
57
|
+
Object.defineProperty(exports, "sanitizeError", { enumerable: true, get: function () { return sanitize_js_1.sanitizeError; } });
|
|
58
|
+
// ─── Hardening: AbortController pool ─────────────────────────────────────────
|
|
59
|
+
var abortPool_js_1 = require("./utils/abortPool.js");
|
|
60
|
+
Object.defineProperty(exports, "acquireController", { enumerable: true, get: function () { return abortPool_js_1.acquireController; } });
|
|
61
|
+
Object.defineProperty(exports, "releaseController", { enumerable: true, get: function () { return abortPool_js_1.releaseController; } });
|
|
62
|
+
Object.defineProperty(exports, "poolSize", { enumerable: true, get: function () { return abortPool_js_1.poolSize; } });
|
package/dist/index.d.ts
CHANGED
|
@@ -4,7 +4,22 @@ export { execute, REQUIRES_SYNC_STORE, } from './core/executor.js';
|
|
|
4
4
|
export { InMemoryStore } from './stores/memory.js';
|
|
5
5
|
export type { InMemoryStoreOptions } from './stores/memory.js';
|
|
6
6
|
export { isSyncStore, isAsyncStore, } from './stores/base.js';
|
|
7
|
-
export { TimeoutError, TotalTimeoutError, } from './
|
|
8
|
-
export type {
|
|
7
|
+
export { ActlyError, ActlyAbortError, TimeoutError, TotalTimeoutError, RetryExhaustedError, ValidationError, } from './errors.js';
|
|
8
|
+
export type { ActlyEventType, ActlyEventBase, AttemptEvent, RetryEvent, CacheHitEvent, CacheMissEvent, DedupeJoinEvent, TimeoutEvent, FinalSuccessEvent, FinalFailureEvent, ActlyEvent, ObservabilityHooks, } from './observability.js';
|
|
9
|
+
export type { ActFn, ActResult, ActSuccess, ActFailure, ActSource, ActOptions, RetryOptions, TimeoutOptions, DedupeOptions, CacheOptions, PolicyApplier, PolicyContext, RunMeta, StateStore, // alias for SyncStateStore (backwards compat)
|
|
9
10
|
SyncStateStore, AsyncStateStore, AnyStateStore, } from './types/index.js';
|
|
11
|
+
export { anySignal, raceAbort, sleep, linkSignal, isAbortError, } from './utils/abort.js';
|
|
12
|
+
export { sanitizeKey, } from './utils/key.js';
|
|
13
|
+
export { computeDelay, } from './utils/backoff.js';
|
|
14
|
+
export { LIMITS, } from './utils/limits.js';
|
|
15
|
+
export type { Limits } from './utils/limits.js';
|
|
16
|
+
export { CircuitBreakerOpenError, BulkheadOverflowError, RateLimitError, } from './errors.js';
|
|
17
|
+
export { createHealthCheck, } from './core/health.js';
|
|
18
|
+
export type { HealthStatus } from './core/health.js';
|
|
19
|
+
export { drain, } from './core/shutdown.js';
|
|
20
|
+
export { createTenantStore, createAsyncTenantStore, } from './core/tenant.js';
|
|
21
|
+
export type { TenantStoreOptions, TenantManager } from './core/tenant.js';
|
|
22
|
+
export { sanitizeErrorMessage, sanitizeError, } from './utils/sanitize.js';
|
|
23
|
+
export { acquireController, releaseController, poolSize, } from './utils/abortPool.js';
|
|
24
|
+
export type { CircuitBreakerOptions, BulkheadOptions, RateLimitOptions, HedgeOptions, FallbackOptions, AuditOptions, AuditEntry, } from './types/index.js';
|
|
10
25
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,GAAG,EACH,UAAU,EACV,SAAS,GACV,MAAM,eAAe,CAAA;AAEtB,YAAY,EACV,aAAa,EACb,cAAc,GACf,MAAM,eAAe,CAAA;AAItB,OAAO,EACL,OAAO,EACP,mBAAmB,GACpB,MAAM,oBAAoB,CAAA;AAI3B,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAClD,YAAY,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAA;AAE9D,OAAO,EACL,WAAW,EACX,YAAY,GACb,MAAM,kBAAkB,CAAA;AAIzB,OAAO,EACL,YAAY,EACZ,iBAAiB,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,GAAG,EACH,UAAU,EACV,SAAS,GACV,MAAM,eAAe,CAAA;AAEtB,YAAY,EACV,aAAa,EACb,cAAc,GACf,MAAM,eAAe,CAAA;AAItB,OAAO,EACL,OAAO,EACP,mBAAmB,GACpB,MAAM,oBAAoB,CAAA;AAI3B,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAClD,YAAY,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAA;AAE9D,OAAO,EACL,WAAW,EACX,YAAY,GACb,MAAM,kBAAkB,CAAA;AAIzB,OAAO,EACL,UAAU,EACV,eAAe,EACf,YAAY,EACZ,iBAAiB,EACjB,mBAAmB,EACnB,eAAe,GAChB,MAAM,aAAa,CAAA;AAIpB,YAAY,EACV,cAAc,EACd,cAAc,EACd,YAAY,EACZ,UAAU,EACV,aAAa,EACb,cAAc,EACd,eAAe,EACf,YAAY,EACZ,iBAAiB,EACjB,iBAAiB,EACjB,UAAU,EACV,kBAAkB,GACnB,MAAM,oBAAoB,CAAA;AAI3B,YAAY,EAEV,KAAK,EACL,SAAS,EACT,UAAU,EACV,UAAU,EACV,SAAS,EACT,UAAU,EAGV,YAAY,EACZ,cAAc,EACd,aAAa,EACb,YAAY,EAGZ,aAAa,EACb,aAAa,EACb,OAAO,EAGP,UAAU,EAAS,8CAA8C;AACjE,cAAc,EACd,eAAe,EACf,aAAa,GACd,MAAM,kBAAkB,CAAA;AAIzB,OAAO,EACL,SAAS,EACT,SAAS,EACT,KAAK,EACL,UAAU,EACV,YAAY,GACb,MAAM,kBAAkB,CAAA;AAEzB,OAAO,EACL,WAAW,GACZ,MAAM,gBAAgB,CAAA;AAEvB,OAAO,EACL,YAAY,GACb,MAAM,oBAAoB,CAAA;AAE3B,OAAO,EACL,MAAM,GACP,MAAM,mBAAmB,CAAA;AAE1B,YAAY,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAA;AAI/C,OAAO,EACL,uBAAuB,EACvB,qBAAqB,EACrB,cAAc,GACf,MAAM,aAAa,CAAA;AAIpB,OAAO,EACL,iBAAiB,GAClB,MAAM,kBAAkB,CAAA;AACzB,YAAY,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAA;AAEpD,OAAO,EACL,KAAK,GACN,MAAM,oBAAoB,CAAA;AAI3B,OAAO,EACL,iBAAiB,EACjB,sBAAsB,GACvB,MAAM,kBAAkB,CAAA;AACzB,YAAY,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAA;AAIzE,OAAO,EACL,oBAAoB,EACpB,aAAa,GACd,MAAM,qBAAqB,CAAA;AAI5B,OAAO,EACL,iBAAiB,EACjB,iBAAiB,EACjB,QAAQ,GACT,MAAM,sBAAsB,CAAA;AAI7B,YAAY,EACV,qBAAqB,EACrB,eAAe,EACf,gBAAgB,EAChB,YAAY,EACZ,eAAe,EACf,YAAY,EACZ,UAAU,GACX,MAAM,kBAAkB,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -6,5 +6,21 @@ export { execute, REQUIRES_SYNC_STORE, } from './core/executor.js';
|
|
|
6
6
|
export { InMemoryStore } from './stores/memory.js';
|
|
7
7
|
export { isSyncStore, isAsyncStore, } from './stores/base.js';
|
|
8
8
|
// ─── Error classes ────────────────────────────────────────────────────────────
|
|
9
|
-
export { TimeoutError, TotalTimeoutError, } from './
|
|
9
|
+
export { ActlyError, ActlyAbortError, TimeoutError, TotalTimeoutError, RetryExhaustedError, ValidationError, } from './errors.js';
|
|
10
|
+
// ─── Utilities (for custom policy authors) ────────────────────────────────────
|
|
11
|
+
export { anySignal, raceAbort, sleep, linkSignal, isAbortError, } from './utils/abort.js';
|
|
12
|
+
export { sanitizeKey, } from './utils/key.js';
|
|
13
|
+
export { computeDelay, } from './utils/backoff.js';
|
|
14
|
+
export { LIMITS, } from './utils/limits.js';
|
|
15
|
+
// ─── Hardening: new error classes ────────────────────────────────────────────
|
|
16
|
+
export { CircuitBreakerOpenError, BulkheadOverflowError, RateLimitError, } from './errors.js';
|
|
17
|
+
// ─── Hardening: health check & graceful shutdown ─────────────────────────────
|
|
18
|
+
export { createHealthCheck, } from './core/health.js';
|
|
19
|
+
export { drain, } from './core/shutdown.js';
|
|
20
|
+
// ─── Hardening: tenant isolation ─────────────────────────────────────────────
|
|
21
|
+
export { createTenantStore, createAsyncTenantStore, } from './core/tenant.js';
|
|
22
|
+
// ─── Hardening: error sanitization ───────────────────────────────────────────
|
|
23
|
+
export { sanitizeErrorMessage, sanitizeError, } from './utils/sanitize.js';
|
|
24
|
+
// ─── Hardening: AbortController pool ─────────────────────────────────────────
|
|
25
|
+
export { acquireController, releaseController, poolSize, } from './utils/abortPool.js';
|
|
10
26
|
//# 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,iFAAiF;AAEjF,OAAO,EACL,GAAG,EACH,UAAU,EACV,SAAS,GACV,MAAM,eAAe,CAAA;AAOtB,iFAAiF;AAEjF,OAAO,EACL,OAAO,EACP,mBAAmB,GACpB,MAAM,oBAAoB,CAAA;AAE3B,iFAAiF;AAEjF,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAGlD,OAAO,EACL,WAAW,EACX,YAAY,GACb,MAAM,kBAAkB,CAAA;AAEzB,iFAAiF;AAEjF,OAAO,EACL,YAAY,EACZ,iBAAiB,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,iFAAiF;AAEjF,OAAO,EACL,GAAG,EACH,UAAU,EACV,SAAS,GACV,MAAM,eAAe,CAAA;AAOtB,iFAAiF;AAEjF,OAAO,EACL,OAAO,EACP,mBAAmB,GACpB,MAAM,oBAAoB,CAAA;AAE3B,iFAAiF;AAEjF,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAGlD,OAAO,EACL,WAAW,EACX,YAAY,GACb,MAAM,kBAAkB,CAAA;AAEzB,iFAAiF;AAEjF,OAAO,EACL,UAAU,EACV,eAAe,EACf,YAAY,EACZ,iBAAiB,EACjB,mBAAmB,EACnB,eAAe,GAChB,MAAM,aAAa,CAAA;AAgDpB,iFAAiF;AAEjF,OAAO,EACL,SAAS,EACT,SAAS,EACT,KAAK,EACL,UAAU,EACV,YAAY,GACb,MAAM,kBAAkB,CAAA;AAEzB,OAAO,EACL,WAAW,GACZ,MAAM,gBAAgB,CAAA;AAEvB,OAAO,EACL,YAAY,GACb,MAAM,oBAAoB,CAAA;AAE3B,OAAO,EACL,MAAM,GACP,MAAM,mBAAmB,CAAA;AAI1B,gFAAgF;AAEhF,OAAO,EACL,uBAAuB,EACvB,qBAAqB,EACrB,cAAc,GACf,MAAM,aAAa,CAAA;AAEpB,gFAAgF;AAEhF,OAAO,EACL,iBAAiB,GAClB,MAAM,kBAAkB,CAAA;AAGzB,OAAO,EACL,KAAK,GACN,MAAM,oBAAoB,CAAA;AAE3B,gFAAgF;AAEhF,OAAO,EACL,iBAAiB,EACjB,sBAAsB,GACvB,MAAM,kBAAkB,CAAA;AAGzB,gFAAgF;AAEhF,OAAO,EACL,oBAAoB,EACpB,aAAa,GACd,MAAM,qBAAqB,CAAA;AAE5B,gFAAgF;AAEhF,OAAO,EACL,iBAAiB,EACjB,iBAAiB,EACjB,QAAQ,GACT,MAAM,sBAAsB,CAAA"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Observability hooks.
|
|
4
|
+
*
|
|
5
|
+
* Eight event types covering the entire lifecycle of an `act()` call.
|
|
6
|
+
*
|
|
7
|
+
* # Contract
|
|
8
|
+
*
|
|
9
|
+
* When `options.observability` is `null`/`undefined` (the common case),
|
|
10
|
+
* no event objects are allocated and no function calls are made. The
|
|
11
|
+
* hot path is a single null-check per policy decision.
|
|
12
|
+
*
|
|
13
|
+
* When hooks ARE registered, events are allocated lazily — only when the
|
|
14
|
+
* corresponding event actually fires. A cache hit doesn't allocate an
|
|
15
|
+
* `onRetry` event, for example.
|
|
16
|
+
*
|
|
17
|
+
* # Event shape
|
|
18
|
+
*
|
|
19
|
+
* Every event carries `key`, `traceId`, and `timestamp` for correlation.
|
|
20
|
+
* Event-specific fields are on the same object (no nesting) for flat
|
|
21
|
+
* destructuring in user code.
|
|
22
|
+
*
|
|
23
|
+
* # Ordering
|
|
24
|
+
*
|
|
25
|
+
* For a successful fresh call with retries:
|
|
26
|
+
* onAttempt (1) → onAttempt (2) → onRetry (1→2) → onAttempt (3) → onFinalSuccess
|
|
27
|
+
*
|
|
28
|
+
* For a cache hit:
|
|
29
|
+
* onCacheHit → onFinalSuccess
|
|
30
|
+
*
|
|
31
|
+
* For a dedupe joiner:
|
|
32
|
+
* onDedupeJoin → onFinalSuccess (or onFinalFailure)
|
|
33
|
+
*
|
|
34
|
+
* For a timeout:
|
|
35
|
+
* onAttempt → onTimeout → onFinalFailure
|
|
36
|
+
*/
|
|
37
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
38
|
+
exports.hasObservers = hasObservers;
|
|
39
|
+
/**
|
|
40
|
+
* Quick null-check helper. Policies call this once at decision points; if
|
|
41
|
+
* it returns false, no further observability work is done.
|
|
42
|
+
*/
|
|
43
|
+
function hasObservers(ctx) {
|
|
44
|
+
return ctx.observability != null;
|
|
45
|
+
}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Observability hooks.
|
|
3
|
+
*
|
|
4
|
+
* Eight event types covering the entire lifecycle of an `act()` call.
|
|
5
|
+
*
|
|
6
|
+
* # Contract
|
|
7
|
+
*
|
|
8
|
+
* When `options.observability` is `null`/`undefined` (the common case),
|
|
9
|
+
* no event objects are allocated and no function calls are made. The
|
|
10
|
+
* hot path is a single null-check per policy decision.
|
|
11
|
+
*
|
|
12
|
+
* When hooks ARE registered, events are allocated lazily — only when the
|
|
13
|
+
* corresponding event actually fires. A cache hit doesn't allocate an
|
|
14
|
+
* `onRetry` event, for example.
|
|
15
|
+
*
|
|
16
|
+
* # Event shape
|
|
17
|
+
*
|
|
18
|
+
* Every event carries `key`, `traceId`, and `timestamp` for correlation.
|
|
19
|
+
* Event-specific fields are on the same object (no nesting) for flat
|
|
20
|
+
* destructuring in user code.
|
|
21
|
+
*
|
|
22
|
+
* # Ordering
|
|
23
|
+
*
|
|
24
|
+
* For a successful fresh call with retries:
|
|
25
|
+
* onAttempt (1) → onAttempt (2) → onRetry (1→2) → onAttempt (3) → onFinalSuccess
|
|
26
|
+
*
|
|
27
|
+
* For a cache hit:
|
|
28
|
+
* onCacheHit → onFinalSuccess
|
|
29
|
+
*
|
|
30
|
+
* For a dedupe joiner:
|
|
31
|
+
* onDedupeJoin → onFinalSuccess (or onFinalFailure)
|
|
32
|
+
*
|
|
33
|
+
* For a timeout:
|
|
34
|
+
* onAttempt → onTimeout → onFinalFailure
|
|
35
|
+
*/
|
|
36
|
+
import type { ActSource } from './types/index.js';
|
|
37
|
+
/** Stable discriminator for telemetry. */
|
|
38
|
+
export type ActlyEventType = 'attempt' | 'retry' | 'cache-hit' | 'cache-miss' | 'dedupe-join' | 'timeout' | 'final-success' | 'final-failure';
|
|
39
|
+
/** Common fields on every event. */
|
|
40
|
+
export interface ActlyEventBase {
|
|
41
|
+
/** The `key` passed to `act()`. */
|
|
42
|
+
readonly key: string;
|
|
43
|
+
/** Auto-generated trace ID (or user-supplied via `options.traceId`). */
|
|
44
|
+
readonly traceId: string;
|
|
45
|
+
/** Event timestamp (ms since epoch). */
|
|
46
|
+
readonly timestamp: number;
|
|
47
|
+
/** Discriminator for switch statements. */
|
|
48
|
+
readonly type: ActlyEventType;
|
|
49
|
+
}
|
|
50
|
+
export interface AttemptEvent extends ActlyEventBase {
|
|
51
|
+
readonly type: 'attempt';
|
|
52
|
+
/** 1-based attempt number. */
|
|
53
|
+
readonly attempt: number;
|
|
54
|
+
/** Duration of this attempt in ms (set after attempt settles). */
|
|
55
|
+
readonly durationMs?: number;
|
|
56
|
+
/** Error from this attempt, if it failed. */
|
|
57
|
+
readonly error?: unknown;
|
|
58
|
+
}
|
|
59
|
+
export interface RetryEvent extends ActlyEventBase {
|
|
60
|
+
readonly type: 'retry';
|
|
61
|
+
/** The attempt that just failed. */
|
|
62
|
+
readonly attempt: number;
|
|
63
|
+
/** The delay (ms) before the next attempt. */
|
|
64
|
+
readonly delayMs: number;
|
|
65
|
+
/** Error that triggered the retry. */
|
|
66
|
+
readonly error: unknown;
|
|
67
|
+
}
|
|
68
|
+
export interface CacheHitEvent extends ActlyEventBase {
|
|
69
|
+
readonly type: 'cache-hit';
|
|
70
|
+
/** Age of the cached value in ms. */
|
|
71
|
+
readonly ageMs: number;
|
|
72
|
+
}
|
|
73
|
+
export interface CacheMissEvent extends ActlyEventBase {
|
|
74
|
+
readonly type: 'cache-miss';
|
|
75
|
+
}
|
|
76
|
+
export interface DedupeJoinEvent extends ActlyEventBase {
|
|
77
|
+
readonly type: 'dedupe-join';
|
|
78
|
+
/** This caller's position in the joiner queue (1 = first joiner). */
|
|
79
|
+
readonly joinerPosition: number;
|
|
80
|
+
}
|
|
81
|
+
export interface TimeoutEvent extends ActlyEventBase {
|
|
82
|
+
readonly type: 'timeout';
|
|
83
|
+
/** Which deadline fired. */
|
|
84
|
+
readonly kind: 'per-attempt' | 'total';
|
|
85
|
+
/** The configured ms. */
|
|
86
|
+
readonly ms: number;
|
|
87
|
+
}
|
|
88
|
+
export interface FinalSuccessEvent extends ActlyEventBase {
|
|
89
|
+
readonly type: 'final-success';
|
|
90
|
+
/** Where the value came from. */
|
|
91
|
+
readonly source: ActSource;
|
|
92
|
+
/** Total attempts made (0 for cache hit). */
|
|
93
|
+
readonly attempts: number;
|
|
94
|
+
/** Total wall-clock duration of the act() call. */
|
|
95
|
+
readonly durationMs: number;
|
|
96
|
+
}
|
|
97
|
+
export interface FinalFailureEvent extends ActlyEventBase {
|
|
98
|
+
readonly type: 'final-failure';
|
|
99
|
+
/** Total attempts made. */
|
|
100
|
+
readonly attempts: number;
|
|
101
|
+
/** Total wall-clock duration of the act() call. */
|
|
102
|
+
readonly durationMs: number;
|
|
103
|
+
/** Stable reason for failure — use for telemetry tags. */
|
|
104
|
+
readonly failedBy: 'abort' | 'timeout' | 'total-timeout' | 'retry-exhausted' | 'fn-error' | 'validation';
|
|
105
|
+
/** The final error. */
|
|
106
|
+
readonly error: unknown;
|
|
107
|
+
}
|
|
108
|
+
export type ActlyEvent = AttemptEvent | RetryEvent | CacheHitEvent | CacheMissEvent | DedupeJoinEvent | TimeoutEvent | FinalSuccessEvent | FinalFailureEvent;
|
|
109
|
+
/**
|
|
110
|
+
* User-supplied observability hooks. All optional. When absent, zero
|
|
111
|
+
* overhead is incurred on the hot path.
|
|
112
|
+
*/
|
|
113
|
+
export interface ObservabilityHooks {
|
|
114
|
+
onAttempt?: (event: AttemptEvent) => void;
|
|
115
|
+
onRetry?: (event: RetryEvent) => void;
|
|
116
|
+
onCacheHit?: (event: CacheHitEvent) => void;
|
|
117
|
+
onCacheMiss?: (event: CacheMissEvent) => void;
|
|
118
|
+
onDedupeJoin?: (event: DedupeJoinEvent) => void;
|
|
119
|
+
onTimeout?: (event: TimeoutEvent) => void;
|
|
120
|
+
onFinalSuccess?: (event: FinalSuccessEvent) => void;
|
|
121
|
+
onFinalFailure?: (event: FinalFailureEvent) => void;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Internal: thread observability through the policy chain without changing
|
|
125
|
+
* every policy's signature. We attach it to `PolicyContext` as an optional
|
|
126
|
+
* field — policies that emit events check for its presence.
|
|
127
|
+
*
|
|
128
|
+
* `traceId` is also stored here so policies can include it in events.
|
|
129
|
+
*/
|
|
130
|
+
export interface ObservabilityContext {
|
|
131
|
+
traceId: string;
|
|
132
|
+
hooks: ObservabilityHooks;
|
|
133
|
+
/** Counter for dedupe joiner position. Per-key, but we approximate by call. */
|
|
134
|
+
joinerCounter: number;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Quick null-check helper. Policies call this once at decision points; if
|
|
138
|
+
* it returns false, no further observability work is done.
|
|
139
|
+
*/
|
|
140
|
+
export declare function hasObservers(ctx: {
|
|
141
|
+
observability?: ObservabilityContext;
|
|
142
|
+
}): ctx is {
|
|
143
|
+
observability: ObservabilityContext;
|
|
144
|
+
};
|
|
145
|
+
//# sourceMappingURL=observability.d.ts.map
|