apcore-js 0.19.0 → 0.21.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 +110 -9
- package/dist/acl.d.ts +18 -0
- package/dist/acl.d.ts.map +1 -1
- package/dist/acl.js +54 -17
- package/dist/acl.js.map +1 -1
- package/dist/async-task.d.ts +70 -16
- package/dist/async-task.d.ts.map +1 -1
- package/dist/async-task.js +212 -72
- package/dist/async-task.js.map +1 -1
- package/dist/builtin-steps.d.ts +16 -5
- package/dist/builtin-steps.d.ts.map +1 -1
- package/dist/builtin-steps.js +45 -28
- package/dist/builtin-steps.js.map +1 -1
- package/dist/config.d.ts +38 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +163 -33
- package/dist/config.js.map +1 -1
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +12 -1
- package/dist/context.js.map +1 -1
- package/dist/errors.d.ts +32 -10
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +55 -16
- package/dist/errors.js.map +1 -1
- package/dist/events/circuit-breaker.d.ts +45 -0
- package/dist/events/circuit-breaker.d.ts.map +1 -0
- package/dist/events/circuit-breaker.js +115 -0
- package/dist/events/circuit-breaker.js.map +1 -0
- package/dist/events/emitter.d.ts +22 -1
- package/dist/events/emitter.d.ts.map +1 -1
- package/dist/events/emitter.js +66 -2
- package/dist/events/emitter.js.map +1 -1
- package/dist/events/index.d.ts +4 -2
- package/dist/events/index.d.ts.map +1 -1
- package/dist/events/index.js +3 -2
- package/dist/events/index.js.map +1 -1
- package/dist/events/subscribers.d.ts +33 -1
- package/dist/events/subscribers.d.ts.map +1 -1
- package/dist/events/subscribers.js +124 -1
- package/dist/events/subscribers.js.map +1 -1
- package/dist/executor.d.ts +10 -2
- package/dist/executor.d.ts.map +1 -1
- package/dist/executor.js +173 -52
- package/dist/executor.js.map +1 -1
- package/dist/generated/version.d.ts +1 -1
- package/dist/generated/version.js +1 -1
- package/dist/index.d.ts +35 -25
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +23 -17
- package/dist/index.js.map +1 -1
- package/dist/middleware/base.d.ts +25 -3
- package/dist/middleware/base.d.ts.map +1 -1
- package/dist/middleware/base.js +24 -0
- package/dist/middleware/base.js.map +1 -1
- package/dist/middleware/circuit-breaker.d.ts +54 -0
- package/dist/middleware/circuit-breaker.d.ts.map +1 -0
- package/dist/middleware/circuit-breaker.js +168 -0
- package/dist/middleware/circuit-breaker.js.map +1 -0
- package/dist/middleware/context-namespace.d.ts +30 -0
- package/dist/middleware/context-namespace.d.ts.map +1 -0
- package/dist/middleware/context-namespace.js +38 -0
- package/dist/middleware/context-namespace.js.map +1 -0
- package/dist/middleware/index.d.ts +7 -1
- package/dist/middleware/index.d.ts.map +1 -1
- package/dist/middleware/index.js +4 -1
- package/dist/middleware/index.js.map +1 -1
- package/dist/middleware/manager.d.ts +11 -4
- package/dist/middleware/manager.d.ts.map +1 -1
- package/dist/middleware/manager.js +25 -9
- package/dist/middleware/manager.js.map +1 -1
- package/dist/middleware/platform-notify.d.ts +8 -4
- package/dist/middleware/platform-notify.d.ts.map +1 -1
- package/dist/middleware/platform-notify.js +11 -7
- package/dist/middleware/platform-notify.js.map +1 -1
- package/dist/middleware/tracing.d.ts +50 -0
- package/dist/middleware/tracing.d.ts.map +1 -0
- package/dist/middleware/tracing.js +89 -0
- package/dist/middleware/tracing.js.map +1 -0
- package/dist/module.d.ts +94 -2
- package/dist/module.d.ts.map +1 -1
- package/dist/module.js +99 -2
- package/dist/module.js.map +1 -1
- package/dist/observability/batch-span-processor.d.ts +48 -0
- package/dist/observability/batch-span-processor.d.ts.map +1 -0
- package/dist/observability/batch-span-processor.js +89 -0
- package/dist/observability/batch-span-processor.js.map +1 -0
- package/dist/observability/context-logger.d.ts +54 -1
- package/dist/observability/context-logger.d.ts.map +1 -1
- package/dist/observability/context-logger.js +270 -6
- package/dist/observability/context-logger.js.map +1 -1
- package/dist/observability/error-history.d.ts +36 -7
- package/dist/observability/error-history.d.ts.map +1 -1
- package/dist/observability/error-history.js +169 -50
- package/dist/observability/error-history.js.map +1 -1
- package/dist/observability/index.d.ts +16 -5
- package/dist/observability/index.d.ts.map +1 -1
- package/dist/observability/index.js +8 -3
- package/dist/observability/index.js.map +1 -1
- package/dist/observability/metrics.d.ts +14 -1
- package/dist/observability/metrics.d.ts.map +1 -1
- package/dist/observability/metrics.js +23 -2
- package/dist/observability/metrics.js.map +1 -1
- package/dist/observability/prometheus-exporter.d.ts +37 -0
- package/dist/observability/prometheus-exporter.d.ts.map +1 -0
- package/dist/observability/prometheus-exporter.js +135 -0
- package/dist/observability/prometheus-exporter.js.map +1 -0
- package/dist/observability/storage.d.ts +43 -0
- package/dist/observability/storage.d.ts.map +1 -0
- package/dist/observability/storage.js +58 -0
- package/dist/observability/storage.js.map +1 -0
- package/dist/observability/store.d.ts +29 -0
- package/dist/observability/store.d.ts.map +1 -0
- package/dist/observability/store.js +36 -0
- package/dist/observability/store.js.map +1 -0
- package/dist/observability/usage-exporter.d.ts +58 -0
- package/dist/observability/usage-exporter.d.ts.map +1 -0
- package/dist/observability/usage-exporter.js +86 -0
- package/dist/observability/usage-exporter.js.map +1 -0
- package/dist/observability/usage.d.ts +18 -1
- package/dist/observability/usage.d.ts.map +1 -1
- package/dist/observability/usage.js +25 -3
- package/dist/observability/usage.js.map +1 -1
- package/dist/pipeline-config.d.ts +11 -0
- package/dist/pipeline-config.d.ts.map +1 -1
- package/dist/pipeline-config.js +36 -10
- package/dist/pipeline-config.js.map +1 -1
- package/dist/pipeline.d.ts +123 -2
- package/dist/pipeline.d.ts.map +1 -1
- package/dist/pipeline.js +249 -50
- package/dist/pipeline.js.map +1 -1
- package/dist/registry/index.d.ts +2 -0
- package/dist/registry/index.d.ts.map +1 -1
- package/dist/registry/index.js +1 -0
- package/dist/registry/index.js.map +1 -1
- package/dist/registry/multi-class.d.ts +71 -0
- package/dist/registry/multi-class.d.ts.map +1 -0
- package/dist/registry/multi-class.js +120 -0
- package/dist/registry/multi-class.js.map +1 -0
- package/dist/registry/registry.d.ts +246 -5
- package/dist/registry/registry.d.ts.map +1 -1
- package/dist/registry/registry.js +485 -16
- package/dist/registry/registry.js.map +1 -1
- package/dist/schema/annotations.d.ts.map +1 -1
- package/dist/schema/annotations.js +1 -0
- package/dist/schema/annotations.js.map +1 -1
- package/dist/schema/constants.d.ts +9 -0
- package/dist/schema/constants.d.ts.map +1 -0
- package/dist/schema/constants.js +9 -0
- package/dist/schema/constants.js.map +1 -0
- package/dist/schema/index.d.ts +1 -1
- package/dist/schema/index.d.ts.map +1 -1
- package/dist/schema/index.js +1 -1
- package/dist/schema/index.js.map +1 -1
- package/dist/schema/loader.d.ts +27 -3
- package/dist/schema/loader.d.ts.map +1 -1
- package/dist/schema/loader.js +137 -32
- package/dist/schema/loader.js.map +1 -1
- package/dist/schema/types.d.ts +4 -0
- package/dist/schema/types.d.ts.map +1 -1
- package/dist/schema/types.js.map +1 -1
- package/dist/schema/validator.d.ts +9 -0
- package/dist/schema/validator.d.ts.map +1 -1
- package/dist/schema/validator.js +153 -4
- package/dist/schema/validator.js.map +1 -1
- package/dist/sys-modules/audit.d.ts +50 -0
- package/dist/sys-modules/audit.d.ts.map +1 -0
- package/dist/sys-modules/audit.js +89 -0
- package/dist/sys-modules/audit.js.map +1 -0
- package/dist/sys-modules/control.d.ts +32 -4
- package/dist/sys-modules/control.d.ts.map +1 -1
- package/dist/sys-modules/control.js +196 -25
- package/dist/sys-modules/control.js.map +1 -1
- package/dist/sys-modules/index.d.ts +7 -2
- package/dist/sys-modules/index.d.ts.map +1 -1
- package/dist/sys-modules/index.js +3 -1
- package/dist/sys-modules/index.js.map +1 -1
- package/dist/sys-modules/overrides.d.ts +58 -0
- package/dist/sys-modules/overrides.d.ts.map +1 -0
- package/dist/sys-modules/overrides.js +106 -0
- package/dist/sys-modules/overrides.js.map +1 -0
- package/dist/sys-modules/registration.d.ts +17 -12
- package/dist/sys-modules/registration.d.ts.map +1 -1
- package/dist/sys-modules/registration.js +134 -23
- package/dist/sys-modules/registration.js.map +1 -1
- package/dist/sys-modules/toggle.d.ts +7 -2
- package/dist/sys-modules/toggle.d.ts.map +1 -1
- package/dist/sys-modules/toggle.js +61 -5
- package/dist/sys-modules/toggle.js.map +1 -1
- package/dist/trace-context.d.ts +47 -9
- package/dist/trace-context.d.ts.map +1 -1
- package/dist/trace-context.js +139 -16
- package/dist/trace-context.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CircuitBreakerMiddleware — per-(module_id, caller_id) rolling-window circuit breaker (Issue #42).
|
|
3
|
+
*
|
|
4
|
+
* State machine:
|
|
5
|
+
* CLOSED → (error_rate >= open_threshold, window full) → OPEN
|
|
6
|
+
* OPEN → (recovery_window_ms elapsed) → HALF_OPEN
|
|
7
|
+
* HALF_OPEN → (probe success) → CLOSED (emits apcore.circuit.closed)
|
|
8
|
+
* HALF_OPEN → (probe failure) → OPEN (emits apcore.circuit.opened)
|
|
9
|
+
*/
|
|
10
|
+
import { CircuitBreakerOpenError } from '../errors.js';
|
|
11
|
+
import { createEvent } from '../events/emitter.js';
|
|
12
|
+
import { Middleware } from './base.js';
|
|
13
|
+
export const CTX_CIRCUIT_STATE = '_apcore.mw.circuit.state';
|
|
14
|
+
export var CircuitState;
|
|
15
|
+
(function (CircuitState) {
|
|
16
|
+
CircuitState["CLOSED"] = "CLOSED";
|
|
17
|
+
CircuitState["OPEN"] = "OPEN";
|
|
18
|
+
CircuitState["HALF_OPEN"] = "HALF_OPEN";
|
|
19
|
+
})(CircuitState || (CircuitState = {}));
|
|
20
|
+
class RollingWindow {
|
|
21
|
+
_cap;
|
|
22
|
+
_buf;
|
|
23
|
+
_head = 0;
|
|
24
|
+
_len = 0;
|
|
25
|
+
_errors = 0;
|
|
26
|
+
constructor(_cap) {
|
|
27
|
+
this._cap = _cap;
|
|
28
|
+
this._buf = new Array(_cap).fill(false);
|
|
29
|
+
}
|
|
30
|
+
record(isError) {
|
|
31
|
+
if (this._len < this._cap) {
|
|
32
|
+
this._buf[this._len++] = isError;
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
const evicted = this._buf[this._head];
|
|
36
|
+
this._buf[this._head] = isError;
|
|
37
|
+
this._head = (this._head + 1) % this._cap;
|
|
38
|
+
if (evicted)
|
|
39
|
+
this._errors--;
|
|
40
|
+
}
|
|
41
|
+
if (isError)
|
|
42
|
+
this._errors++;
|
|
43
|
+
}
|
|
44
|
+
get errorRate() {
|
|
45
|
+
return this._len === 0 ? 0 : this._errors / this._len;
|
|
46
|
+
}
|
|
47
|
+
get length() {
|
|
48
|
+
return this._len;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
export class CircuitBreakerMiddleware extends Middleware {
|
|
52
|
+
_openThreshold;
|
|
53
|
+
_recoveryWindowMs;
|
|
54
|
+
_windowSize;
|
|
55
|
+
_emitter;
|
|
56
|
+
_circuits = new Map();
|
|
57
|
+
constructor(options = {}) {
|
|
58
|
+
super(options.priority ?? 100);
|
|
59
|
+
this._openThreshold = options.openThreshold ?? 0.5;
|
|
60
|
+
this._recoveryWindowMs = options.recoveryWindowMs ?? 30000;
|
|
61
|
+
this._windowSize = options.windowSize ?? 10;
|
|
62
|
+
this._emitter = options.emitter ?? null;
|
|
63
|
+
}
|
|
64
|
+
_key(moduleId, callerId) {
|
|
65
|
+
return `${moduleId}:${callerId ?? ''}`;
|
|
66
|
+
}
|
|
67
|
+
_getRecord(moduleId, callerId) {
|
|
68
|
+
const key = this._key(moduleId, callerId);
|
|
69
|
+
if (!this._circuits.has(key)) {
|
|
70
|
+
this._circuits.set(key, {
|
|
71
|
+
state: CircuitState.CLOSED,
|
|
72
|
+
window: new RollingWindow(this._windowSize),
|
|
73
|
+
openedAt: null,
|
|
74
|
+
probeInFlight: false,
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
return this._circuits.get(key);
|
|
78
|
+
}
|
|
79
|
+
_maybeHalfOpen(record) {
|
|
80
|
+
if (record.state === CircuitState.OPEN && record.openedAt !== null) {
|
|
81
|
+
if (Date.now() - record.openedAt >= this._recoveryWindowMs) {
|
|
82
|
+
record.state = CircuitState.HALF_OPEN;
|
|
83
|
+
record.probeInFlight = false;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
_openCircuit(moduleId, callerId, record) {
|
|
88
|
+
record.state = CircuitState.OPEN;
|
|
89
|
+
record.openedAt = Date.now();
|
|
90
|
+
record.probeInFlight = false;
|
|
91
|
+
console.warn(`[apcore:middleware] Circuit OPEN for module '${moduleId}' (caller: ${callerId ?? 'unknown'})`);
|
|
92
|
+
this._emit('apcore.circuit.opened', moduleId, callerId, 'warn');
|
|
93
|
+
}
|
|
94
|
+
_closeCircuit(moduleId, callerId, record) {
|
|
95
|
+
record.state = CircuitState.CLOSED;
|
|
96
|
+
record.openedAt = null;
|
|
97
|
+
record.probeInFlight = false;
|
|
98
|
+
console.warn(`[apcore:middleware] Circuit CLOSED for module '${moduleId}' (caller: ${callerId ?? 'unknown'})`);
|
|
99
|
+
this._emit('apcore.circuit.closed', moduleId, callerId, 'info');
|
|
100
|
+
}
|
|
101
|
+
_emit(eventType, moduleId, callerId, severity) {
|
|
102
|
+
if (!this._emitter)
|
|
103
|
+
return;
|
|
104
|
+
try {
|
|
105
|
+
this._emitter.emit(createEvent(eventType, moduleId, severity, { callerId: callerId ?? null }));
|
|
106
|
+
}
|
|
107
|
+
catch (err) {
|
|
108
|
+
console.warn(`[apcore:middleware] Circuit event emission failed for '${eventType}':`, err);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
before(moduleId, _inputs, context) {
|
|
112
|
+
const callerId = context.callerId;
|
|
113
|
+
const record = this._getRecord(moduleId, callerId);
|
|
114
|
+
this._maybeHalfOpen(record);
|
|
115
|
+
context.data[CTX_CIRCUIT_STATE] = record.state;
|
|
116
|
+
if (record.state === CircuitState.OPEN) {
|
|
117
|
+
throw new CircuitBreakerOpenError(moduleId, callerId);
|
|
118
|
+
}
|
|
119
|
+
if (record.state === CircuitState.HALF_OPEN) {
|
|
120
|
+
if (record.probeInFlight) {
|
|
121
|
+
throw new CircuitBreakerOpenError(moduleId, callerId);
|
|
122
|
+
}
|
|
123
|
+
record.probeInFlight = true;
|
|
124
|
+
}
|
|
125
|
+
return null;
|
|
126
|
+
}
|
|
127
|
+
after(moduleId, _inputs, _output, context) {
|
|
128
|
+
const callerId = context.callerId;
|
|
129
|
+
const record = this._getRecord(moduleId, callerId);
|
|
130
|
+
record.window.record(false);
|
|
131
|
+
if (record.state === CircuitState.HALF_OPEN) {
|
|
132
|
+
this._closeCircuit(moduleId, callerId, record);
|
|
133
|
+
context.data[CTX_CIRCUIT_STATE] = CircuitState.CLOSED;
|
|
134
|
+
}
|
|
135
|
+
return null;
|
|
136
|
+
}
|
|
137
|
+
onError(moduleId, _inputs, error, context) {
|
|
138
|
+
if (error instanceof CircuitBreakerOpenError) {
|
|
139
|
+
return null;
|
|
140
|
+
}
|
|
141
|
+
const callerId = context.callerId;
|
|
142
|
+
const record = this._getRecord(moduleId, callerId);
|
|
143
|
+
record.window.record(true);
|
|
144
|
+
if (record.state === CircuitState.HALF_OPEN) {
|
|
145
|
+
this._openCircuit(moduleId, callerId, record);
|
|
146
|
+
context.data[CTX_CIRCUIT_STATE] = CircuitState.OPEN;
|
|
147
|
+
}
|
|
148
|
+
else if (record.state === CircuitState.CLOSED) {
|
|
149
|
+
if (record.window.length >= this._windowSize &&
|
|
150
|
+
record.window.errorRate >= this._openThreshold) {
|
|
151
|
+
this._openCircuit(moduleId, callerId, record);
|
|
152
|
+
context.data[CTX_CIRCUIT_STATE] = CircuitState.OPEN;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
return null;
|
|
156
|
+
}
|
|
157
|
+
/** Return the current circuit state for a given (moduleId, callerId) pair. */
|
|
158
|
+
getState(moduleId, callerId = null) {
|
|
159
|
+
const record = this._getRecord(moduleId, callerId);
|
|
160
|
+
this._maybeHalfOpen(record);
|
|
161
|
+
return record.state;
|
|
162
|
+
}
|
|
163
|
+
/** Manually reset the circuit to CLOSED (e.g., for operator override or tests). */
|
|
164
|
+
reset(moduleId, callerId = null) {
|
|
165
|
+
this._circuits.delete(this._key(moduleId, callerId));
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
//# sourceMappingURL=circuit-breaker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"circuit-breaker.js","sourceRoot":"","sources":["../../src/middleware/circuit-breaker.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Context namespace utilities for apcore middleware hardening (Issue #42).
|
|
3
|
+
*
|
|
4
|
+
* Namespace rules:
|
|
5
|
+
* - _apcore.* — reserved for framework use only
|
|
6
|
+
* - ext.* — reserved for user extensions
|
|
7
|
+
* - All other keys are allowed (legacy compatibility)
|
|
8
|
+
*/
|
|
9
|
+
export type ContextKeyWriter = 'framework' | 'user';
|
|
10
|
+
export interface ContextKeyValidation {
|
|
11
|
+
readonly valid: boolean;
|
|
12
|
+
readonly warning: boolean;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Validate whether a context key write is allowed for the given writer role.
|
|
16
|
+
*
|
|
17
|
+
* Rules (PROTOCOL_SPEC §Middleware Architecture Hardening §1.1):
|
|
18
|
+
* - User middleware MUST NOT write `_apcore.*` keys.
|
|
19
|
+
* - Framework MUST NOT write `ext.*` keys.
|
|
20
|
+
*/
|
|
21
|
+
export declare function validateContextKey(writer: ContextKeyWriter, key: string): ContextKeyValidation;
|
|
22
|
+
/**
|
|
23
|
+
* Detect whether a function is an async function at call time using
|
|
24
|
+
* `handler.constructor.name === 'AsyncFunction'`.
|
|
25
|
+
*
|
|
26
|
+
* This is the TypeScript-safe equivalent of Python's `inspect.iscoroutinefunction`.
|
|
27
|
+
* Do NOT use `handler() instanceof Promise` — that calls the function and is too late.
|
|
28
|
+
*/
|
|
29
|
+
export declare function isAsyncHandler(handler: Function): boolean;
|
|
30
|
+
//# sourceMappingURL=context-namespace.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context-namespace.d.ts","sourceRoot":"","sources":["../../src/middleware/context-namespace.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,MAAM,MAAM,gBAAgB,GAAG,WAAW,GAAG,MAAM,CAAC;AAEpD,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;CAC3B;AAKD;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,gBAAgB,EACxB,GAAG,EAAE,MAAM,GACV,oBAAoB,CAQtB;AAED;;;;;;GAMG;AAEH,wBAAgB,cAAc,CAAC,OAAO,EAAE,QAAQ,GAAG,OAAO,CAEzD"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Context namespace utilities for apcore middleware hardening (Issue #42).
|
|
3
|
+
*
|
|
4
|
+
* Namespace rules:
|
|
5
|
+
* - _apcore.* — reserved for framework use only
|
|
6
|
+
* - ext.* — reserved for user extensions
|
|
7
|
+
* - All other keys are allowed (legacy compatibility)
|
|
8
|
+
*/
|
|
9
|
+
const APCORE_NS_PREFIX = '_apcore.';
|
|
10
|
+
const EXT_NS_PREFIX = 'ext.';
|
|
11
|
+
/**
|
|
12
|
+
* Validate whether a context key write is allowed for the given writer role.
|
|
13
|
+
*
|
|
14
|
+
* Rules (PROTOCOL_SPEC §Middleware Architecture Hardening §1.1):
|
|
15
|
+
* - User middleware MUST NOT write `_apcore.*` keys.
|
|
16
|
+
* - Framework MUST NOT write `ext.*` keys.
|
|
17
|
+
*/
|
|
18
|
+
export function validateContextKey(writer, key) {
|
|
19
|
+
if (writer === 'user' && key.startsWith(APCORE_NS_PREFIX)) {
|
|
20
|
+
return { valid: false, warning: true };
|
|
21
|
+
}
|
|
22
|
+
if (writer === 'framework' && key.startsWith(EXT_NS_PREFIX)) {
|
|
23
|
+
return { valid: false, warning: true };
|
|
24
|
+
}
|
|
25
|
+
return { valid: true, warning: false };
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Detect whether a function is an async function at call time using
|
|
29
|
+
* `handler.constructor.name === 'AsyncFunction'`.
|
|
30
|
+
*
|
|
31
|
+
* This is the TypeScript-safe equivalent of Python's `inspect.iscoroutinefunction`.
|
|
32
|
+
* Do NOT use `handler() instanceof Promise` — that calls the function and is too late.
|
|
33
|
+
*/
|
|
34
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
|
|
35
|
+
export function isAsyncHandler(handler) {
|
|
36
|
+
return handler.constructor.name === 'AsyncFunction';
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=context-namespace.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context-namespace.js","sourceRoot":"","sources":["../../src/middleware/context-namespace.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AASH,MAAM,gBAAgB,GAAG,UAAU,CAAC;AACpC,MAAM,aAAa,GAAG,MAAM,CAAC;AAE7B;;;;;;GAMG;AACH,MAAM,UAAU,kBAAkB,CAChC,MAAwB,EACxB,GAAW;IAEX,IAAI,MAAM,KAAK,MAAM,IAAI,GAAG,CAAC,UAAU,CAAC,gBAAgB,CAAC,EAAE,CAAC;QAC1D,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IACzC,CAAC;IACD,IAAI,MAAM,KAAK,WAAW,IAAI,GAAG,CAAC,UAAU,CAAC,aAAa,CAAC,EAAE,CAAC;QAC5D,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IACzC,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;AACzC,CAAC;AAED;;;;;;GAMG;AACH,sEAAsE;AACtE,MAAM,UAAU,cAAc,CAAC,OAAiB;IAC9C,OAAO,OAAO,CAAC,WAAW,CAAC,IAAI,KAAK,eAAe,CAAC;AACtD,CAAC"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { Middleware } from './base.js';
|
|
1
|
+
export { Middleware, RetrySignal } from './base.js';
|
|
2
2
|
export { MiddlewareManager, MiddlewareChainError } from './manager.js';
|
|
3
3
|
export { BeforeMiddleware, AfterMiddleware } from './adapters.js';
|
|
4
4
|
export type { BeforeCallback, AfterCallback } from './adapters.js';
|
|
@@ -8,4 +8,10 @@ export { RetryHintMiddleware, RetryMiddleware, CTX_RETRY_COUNT_PREFIX, CTX_RETRY
|
|
|
8
8
|
export type { RetryConfig } from './retry.js';
|
|
9
9
|
export { ErrorHistoryMiddleware } from './error-history.js';
|
|
10
10
|
export { PlatformNotifyMiddleware } from './platform-notify.js';
|
|
11
|
+
export { CircuitBreakerMiddleware, CircuitState as MiddlewareCircuitState, CTX_CIRCUIT_STATE, } from './circuit-breaker.js';
|
|
12
|
+
export type { CircuitBreakerOptions } from './circuit-breaker.js';
|
|
13
|
+
export { TracingMiddleware, CTX_TRACING_SPAN_ID } from './tracing.js';
|
|
14
|
+
export type { OtelTracer, OtelSpan, TracingMiddlewareOptions } from './tracing.js';
|
|
15
|
+
export { validateContextKey, isAsyncHandler } from './context-namespace.js';
|
|
16
|
+
export type { ContextKeyWriter, ContextKeyValidation } from './context-namespace.js';
|
|
11
17
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/middleware/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/middleware/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACpD,OAAO,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AACvE,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAClE,YAAY,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AACnE,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AACjD,YAAY,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,EAAE,mBAAmB,EAAE,eAAe,EAAE,sBAAsB,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAClH,YAAY,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AAC5D,OAAO,EAAE,wBAAwB,EAAE,MAAM,sBAAsB,CAAC;AAChE,OAAO,EACL,wBAAwB,EACxB,YAAY,IAAI,sBAAsB,EACtC,iBAAiB,GAClB,MAAM,sBAAsB,CAAC;AAC9B,YAAY,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAClE,OAAO,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AACtE,YAAY,EAAE,UAAU,EAAE,QAAQ,EAAE,wBAAwB,EAAE,MAAM,cAAc,CAAC;AACnF,OAAO,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAC5E,YAAY,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC"}
|
package/dist/middleware/index.js
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
|
-
export { Middleware } from './base.js';
|
|
1
|
+
export { Middleware, RetrySignal } from './base.js';
|
|
2
2
|
export { MiddlewareManager, MiddlewareChainError } from './manager.js';
|
|
3
3
|
export { BeforeMiddleware, AfterMiddleware } from './adapters.js';
|
|
4
4
|
export { LoggingMiddleware } from './logging.js';
|
|
5
5
|
export { RetryHintMiddleware, RetryMiddleware, CTX_RETRY_COUNT_PREFIX, CTX_RETRY_DELAY_PREFIX } from './retry.js';
|
|
6
6
|
export { ErrorHistoryMiddleware } from './error-history.js';
|
|
7
7
|
export { PlatformNotifyMiddleware } from './platform-notify.js';
|
|
8
|
+
export { CircuitBreakerMiddleware, CircuitState as MiddlewareCircuitState, CTX_CIRCUIT_STATE, } from './circuit-breaker.js';
|
|
9
|
+
export { TracingMiddleware, CTX_TRACING_SPAN_ID } from './tracing.js';
|
|
10
|
+
export { validateContextKey, isAsyncHandler } from './context-namespace.js';
|
|
8
11
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/middleware/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/middleware/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACpD,OAAO,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AACvE,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAElE,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAEjD,OAAO,EAAE,mBAAmB,EAAE,eAAe,EAAE,sBAAsB,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAElH,OAAO,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AAC5D,OAAO,EAAE,wBAAwB,EAAE,MAAM,sBAAsB,CAAC;AAChE,OAAO,EACL,wBAAwB,EACxB,YAAY,IAAI,sBAAsB,EACtC,iBAAiB,GAClB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAEtE,OAAO,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC"}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import type { Context } from '../context.js';
|
|
5
5
|
import { ModuleError } from '../errors.js';
|
|
6
|
-
import { Middleware } from './base.js';
|
|
6
|
+
import { Middleware, RetrySignal } from './base.js';
|
|
7
7
|
export declare class MiddlewareChainError extends ModuleError {
|
|
8
8
|
static readonly DEFAULT_RETRYABLE: boolean | null;
|
|
9
9
|
readonly original: Error;
|
|
@@ -15,8 +15,15 @@ export declare class MiddlewareManager {
|
|
|
15
15
|
add(middleware: Middleware): void;
|
|
16
16
|
remove(middleware: Middleware): boolean;
|
|
17
17
|
snapshot(): Middleware[];
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
18
|
+
/**
|
|
19
|
+
* Run all `before` hooks in priority-descending order, awaiting any Promise
|
|
20
|
+
* a middleware returns.
|
|
21
|
+
*
|
|
22
|
+
* Always-async (sync finding A-D-403) — matches apcore-rust's design and
|
|
23
|
+
* removes the silent-Promise-into-currentInputs trap.
|
|
24
|
+
*/
|
|
25
|
+
executeBefore(moduleId: string, inputs: Record<string, unknown>, context: Context): Promise<[Record<string, unknown>, Middleware[]]>;
|
|
26
|
+
executeAfter(moduleId: string, inputs: Record<string, unknown>, output: Record<string, unknown>, context: Context): Promise<Record<string, unknown>>;
|
|
27
|
+
executeOnError(moduleId: string, inputs: Record<string, unknown>, error: Error, context: Context, executedMiddlewares: Middleware[]): Promise<Record<string, unknown> | RetrySignal | null>;
|
|
21
28
|
}
|
|
22
29
|
//# sourceMappingURL=manager.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../../src/middleware/manager.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../../src/middleware/manager.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAEpD,qBAAa,oBAAqB,SAAQ,WAAW;IACnD,gBAAyB,iBAAiB,EAAE,OAAO,GAAG,IAAI,CAAS;IAEnE,QAAQ,CAAC,QAAQ,EAAE,KAAK,CAAC;IACzB,QAAQ,CAAC,mBAAmB,EAAE,UAAU,EAAE,CAAC;gBAE/B,QAAQ,EAAE,KAAK,EAAE,mBAAmB,EAAE,UAAU,EAAE;CAM/D;AAED,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,YAAY,CAAoB;IAExC,GAAG,CAAC,UAAU,EAAE,UAAU,GAAG,IAAI;IAcjC,MAAM,CAAC,UAAU,EAAE,UAAU,GAAG,OAAO;IAUvC,QAAQ,IAAI,UAAU,EAAE;IAIxB;;;;;;OAMG;IACG,aAAa,CACjB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,OAAO,EAAE,OAAO,GACf,OAAO,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,UAAU,EAAE,CAAC,CAAC;IAoB7C,YAAY,CAChB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,OAAO,EAAE,OAAO,GACf,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAe7B,cAAc,CAClB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,KAAK,EAAE,KAAK,EACZ,OAAO,EAAE,OAAO,EAChB,mBAAmB,EAAE,UAAU,EAAE,GAChC,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,WAAW,GAAG,IAAI,CAAC;CAwBzD"}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* MiddlewareManager -- onion model execution engine for the middleware pipeline.
|
|
3
3
|
*/
|
|
4
4
|
import { ModuleError } from '../errors.js';
|
|
5
|
+
import { RetrySignal } from './base.js';
|
|
5
6
|
export class MiddlewareChainError extends ModuleError {
|
|
6
7
|
static DEFAULT_RETRYABLE = false;
|
|
7
8
|
original;
|
|
@@ -40,15 +41,22 @@ export class MiddlewareManager {
|
|
|
40
41
|
snapshot() {
|
|
41
42
|
return [...this._middlewares];
|
|
42
43
|
}
|
|
43
|
-
|
|
44
|
+
/**
|
|
45
|
+
* Run all `before` hooks in priority-descending order, awaiting any Promise
|
|
46
|
+
* a middleware returns.
|
|
47
|
+
*
|
|
48
|
+
* Always-async (sync finding A-D-403) — matches apcore-rust's design and
|
|
49
|
+
* removes the silent-Promise-into-currentInputs trap.
|
|
50
|
+
*/
|
|
51
|
+
async executeBefore(moduleId, inputs, context) {
|
|
44
52
|
let currentInputs = inputs;
|
|
45
53
|
const executedMiddlewares = [];
|
|
46
54
|
const middlewares = this.snapshot();
|
|
47
55
|
for (const mw of middlewares) {
|
|
48
56
|
executedMiddlewares.push(mw);
|
|
49
57
|
try {
|
|
50
|
-
const result = mw.before(moduleId, currentInputs, context);
|
|
51
|
-
if (result !== null) {
|
|
58
|
+
const result = await mw.before(moduleId, currentInputs, context);
|
|
59
|
+
if (result !== null && result !== undefined) {
|
|
52
60
|
currentInputs = result;
|
|
53
61
|
}
|
|
54
62
|
}
|
|
@@ -58,23 +66,31 @@ export class MiddlewareManager {
|
|
|
58
66
|
}
|
|
59
67
|
return [currentInputs, executedMiddlewares];
|
|
60
68
|
}
|
|
61
|
-
executeAfter(moduleId, inputs, output, context) {
|
|
69
|
+
async executeAfter(moduleId, inputs, output, context) {
|
|
62
70
|
let currentOutput = output;
|
|
63
71
|
const middlewares = this.snapshot();
|
|
64
72
|
// Fail-fast: propagate the first error immediately (matches Python/Rust behaviour).
|
|
65
73
|
for (let i = middlewares.length - 1; i >= 0; i--) {
|
|
66
|
-
const result = middlewares[i].after(moduleId, inputs, currentOutput, context);
|
|
67
|
-
if (result !== null) {
|
|
74
|
+
const result = await middlewares[i].after(moduleId, inputs, currentOutput, context);
|
|
75
|
+
if (result !== null && result !== undefined) {
|
|
68
76
|
currentOutput = result;
|
|
69
77
|
}
|
|
70
78
|
}
|
|
71
79
|
return currentOutput;
|
|
72
80
|
}
|
|
73
|
-
executeOnError(moduleId, inputs, error, context, executedMiddlewares) {
|
|
81
|
+
async executeOnError(moduleId, inputs, error, context, executedMiddlewares) {
|
|
74
82
|
for (let i = executedMiddlewares.length - 1; i >= 0; i--) {
|
|
75
83
|
try {
|
|
76
|
-
const result = executedMiddlewares[i].onError(moduleId, inputs, error, context);
|
|
77
|
-
|
|
84
|
+
const result = await executedMiddlewares[i].onError(moduleId, inputs, error, context);
|
|
85
|
+
// Strict recovery type check (sync finding A-D-404):
|
|
86
|
+
// only a non-null object or a RetrySignal counts as recovery.
|
|
87
|
+
// `undefined` (typical of arrow functions without a return) does NOT trigger recovery.
|
|
88
|
+
if (result !== null
|
|
89
|
+
&& result !== undefined
|
|
90
|
+
&& (result instanceof RetrySignal || (typeof result === 'object'))) {
|
|
91
|
+
// RetrySignal short-circuits and propagates up to the executor's
|
|
92
|
+
// call() loop, which re-runs the pipeline with new inputs.
|
|
93
|
+
// Plain objects become the recovery output. (sync finding A-D-017)
|
|
78
94
|
return result;
|
|
79
95
|
}
|
|
80
96
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"manager.js","sourceRoot":"","sources":["../../src/middleware/manager.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"manager.js","sourceRoot":"","sources":["../../src/middleware/manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,10 +2,14 @@
|
|
|
2
2
|
* PlatformNotifyMiddleware -- threshold sensor with hysteresis.
|
|
3
3
|
*
|
|
4
4
|
* Monitors error rates and latency, emits threshold events with hysteresis.
|
|
5
|
-
* Emits error_threshold_exceeded when a module's error rate
|
|
6
|
-
* configured threshold, latency_threshold_exceeded
|
|
7
|
-
* exceeds the limit, and apcore.health.recovered when a
|
|
8
|
-
* module recovers below threshold * 0.5.
|
|
5
|
+
* Emits apcore.health.error_threshold_exceeded when a module's error rate
|
|
6
|
+
* crosses the configured threshold, apcore.health.latency_threshold_exceeded
|
|
7
|
+
* when p99 latency exceeds the limit, and apcore.health.recovered when a
|
|
8
|
+
* previously alerted module recovers below threshold * 0.5.
|
|
9
|
+
*
|
|
10
|
+
* During the deprecation window legacy aliases (`error_threshold_exceeded`,
|
|
11
|
+
* `latency_threshold_exceeded`) are emitted alongside the canonical names
|
|
12
|
+
* with `deprecated: true` in the payload (Issue #36).
|
|
9
13
|
*/
|
|
10
14
|
import type { Context } from '../context.js';
|
|
11
15
|
import type { EventEmitter } from '../events/emitter.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"platform-notify.d.ts","sourceRoot":"","sources":["../../src/middleware/platform-notify.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"platform-notify.d.ts","sourceRoot":"","sources":["../../src/middleware/platform-notify.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAEzD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAEpE,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAEvC,qBAAa,wBAAyB,SAAQ,UAAU;IACtD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAe;IACxC,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAA0B;IAC5D,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAS;IAC7C,OAAO,CAAC,QAAQ,CAAC,sBAAsB,CAAS;IAChD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAuC;gBAG9D,YAAY,EAAE,YAAY,EAC1B,gBAAgB,GAAE,gBAAgB,GAAG,IAAW,EAChD,kBAAkB,GAAE,MAAY,EAChC,qBAAqB,GAAE,MAAa;IAS7B,KAAK,CACZ,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAChC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAChC,QAAQ,EAAE,OAAO,GAChB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAMxB,OAAO,CACd,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAChC,MAAM,EAAE,KAAK,EACb,QAAQ,EAAE,OAAO,GAChB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IASjC,OAAO,CAAC,WAAW;IASnB,OAAO,CAAC,iBAAiB;IAKzB,OAAO,CAAC,wBAAwB;IAgBhC,OAAO,CAAC,sBAAsB;IAmB9B,OAAO,CAAC,cAAc;IAKtB,OAAO,CAAC,mBAAmB;CAe5B"}
|
|
@@ -2,12 +2,16 @@
|
|
|
2
2
|
* PlatformNotifyMiddleware -- threshold sensor with hysteresis.
|
|
3
3
|
*
|
|
4
4
|
* Monitors error rates and latency, emits threshold events with hysteresis.
|
|
5
|
-
* Emits error_threshold_exceeded when a module's error rate
|
|
6
|
-
* configured threshold, latency_threshold_exceeded
|
|
7
|
-
* exceeds the limit, and apcore.health.recovered when a
|
|
8
|
-
* module recovers below threshold * 0.5.
|
|
5
|
+
* Emits apcore.health.error_threshold_exceeded when a module's error rate
|
|
6
|
+
* crosses the configured threshold, apcore.health.latency_threshold_exceeded
|
|
7
|
+
* when p99 latency exceeds the limit, and apcore.health.recovered when a
|
|
8
|
+
* previously alerted module recovers below threshold * 0.5.
|
|
9
|
+
*
|
|
10
|
+
* During the deprecation window legacy aliases (`error_threshold_exceeded`,
|
|
11
|
+
* `latency_threshold_exceeded`) are emitted alongside the canonical names
|
|
12
|
+
* with `deprecated: true` in the payload (Issue #36).
|
|
9
13
|
*/
|
|
10
|
-
import { createEvent } from '../events/emitter.js';
|
|
14
|
+
import { createEvent, emitWithLegacy } from '../events/emitter.js';
|
|
11
15
|
import { computeModuleErrorRate, estimateP99FromHistogram } from '../observability/metrics-utils.js';
|
|
12
16
|
import { Middleware } from './base.js';
|
|
13
17
|
export class PlatformNotifyMiddleware extends Middleware {
|
|
@@ -53,7 +57,7 @@ export class PlatformNotifyMiddleware extends Middleware {
|
|
|
53
57
|
const errorRate = this._computeErrorRate(moduleId);
|
|
54
58
|
const alerted = this._getAlerted(moduleId);
|
|
55
59
|
if (errorRate >= this._errorRateThreshold && !alerted.has('error_rate')) {
|
|
56
|
-
this._emitter.
|
|
60
|
+
emitWithLegacy(this._emitter, 'apcore.health.error_threshold_exceeded', 'error_threshold_exceeded', moduleId, 'error', { error_rate: errorRate, threshold: this._errorRateThreshold });
|
|
57
61
|
alerted.add('error_rate');
|
|
58
62
|
}
|
|
59
63
|
}
|
|
@@ -65,7 +69,7 @@ export class PlatformNotifyMiddleware extends Middleware {
|
|
|
65
69
|
return;
|
|
66
70
|
const p99Ms = this._estimateP99Ms(moduleId);
|
|
67
71
|
if (p99Ms >= this._latencyP99ThresholdMs) {
|
|
68
|
-
this._emitter.
|
|
72
|
+
emitWithLegacy(this._emitter, 'apcore.health.latency_threshold_exceeded', 'latency_threshold_exceeded', moduleId, 'warn', { p99_latency_ms: p99Ms, threshold: this._latencyP99ThresholdMs });
|
|
69
73
|
alerted.add('latency');
|
|
70
74
|
}
|
|
71
75
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"platform-notify.js","sourceRoot":"","sources":["../../src/middleware/platform-notify.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"platform-notify.js","sourceRoot":"","sources":["../../src/middleware/platform-notify.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TracingMiddleware — OpenTelemetry-compatible span lifecycle management (Issue #42).
|
|
3
|
+
*
|
|
4
|
+
* Behaviour:
|
|
5
|
+
* - before(): creates a span named after the module_id, sets apcore.* attributes,
|
|
6
|
+
* and stores the span_id in context.data["_apcore.mw.tracing.span_id"].
|
|
7
|
+
* - after(): ends the span with status OK.
|
|
8
|
+
* - onError(): ends the span with status ERROR.
|
|
9
|
+
* - If @opentelemetry/api is not installed (and no tracer is injected), all methods
|
|
10
|
+
* are silent no-ops.
|
|
11
|
+
*/
|
|
12
|
+
import type { Context } from '../context.js';
|
|
13
|
+
import { Middleware } from './base.js';
|
|
14
|
+
export declare const CTX_TRACING_SPAN_ID = "_apcore.mw.tracing.span_id";
|
|
15
|
+
export interface OtelSpan {
|
|
16
|
+
spanContext(): {
|
|
17
|
+
spanId: string;
|
|
18
|
+
};
|
|
19
|
+
setAttribute(key: string, value: string): void;
|
|
20
|
+
setStatus(status: {
|
|
21
|
+
code: number;
|
|
22
|
+
message?: string;
|
|
23
|
+
}): void;
|
|
24
|
+
end(): void;
|
|
25
|
+
}
|
|
26
|
+
export interface OtelTracer {
|
|
27
|
+
startSpan(name: string, options?: Record<string, unknown>): OtelSpan;
|
|
28
|
+
}
|
|
29
|
+
export interface TracingMiddlewareOptions {
|
|
30
|
+
/** OTel service name used when initialising the default tracer. Default: 'apcore' */
|
|
31
|
+
serviceName?: string;
|
|
32
|
+
/**
|
|
33
|
+
* Inject a custom tracer (primarily for testing).
|
|
34
|
+
* When provided this takes precedence over auto-detected OTel.
|
|
35
|
+
* Pass `null` to force no-op mode even if OTel is installed.
|
|
36
|
+
*/
|
|
37
|
+
tracer?: OtelTracer | null;
|
|
38
|
+
/** Middleware priority (0–1000). Default: 800 */
|
|
39
|
+
priority?: number;
|
|
40
|
+
}
|
|
41
|
+
export declare class TracingMiddleware extends Middleware {
|
|
42
|
+
private readonly _tracer;
|
|
43
|
+
constructor(options?: TracingMiddlewareOptions);
|
|
44
|
+
/** Type-safe accessor for the active span stored by before(). */
|
|
45
|
+
private _activeSpan;
|
|
46
|
+
before(moduleId: string, _inputs: Record<string, unknown>, context: Context): Record<string, unknown> | null;
|
|
47
|
+
after(_moduleId: string, _inputs: Record<string, unknown>, _output: Record<string, unknown>, context: Context): Record<string, unknown> | null;
|
|
48
|
+
onError(_moduleId: string, _inputs: Record<string, unknown>, error: Error, context: Context): Record<string, unknown> | null;
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=tracing.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tracing.d.ts","sourceRoot":"","sources":["../../src/middleware/tracing.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAEvC,eAAO,MAAM,mBAAmB,+BAA+B,CAAC;AAUhE,MAAM,WAAW,QAAQ;IACvB,WAAW,IAAI;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAClC,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/C,SAAS,CAAC,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAC5D,GAAG,IAAI,IAAI,CAAC;CACb;AAED,MAAM,WAAW,UAAU;IACzB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,QAAQ,CAAC;CACtE;AAaD,MAAM,WAAW,wBAAwB;IACvC,qFAAqF;IACrF,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;OAIG;IACH,MAAM,CAAC,EAAE,UAAU,GAAG,IAAI,CAAC;IAC3B,iDAAiD;IACjD,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,qBAAa,iBAAkB,SAAQ,UAAU;IAC/C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAoB;gBAEhC,OAAO,GAAE,wBAA6B;IAWlD,iEAAiE;IACjE,OAAO,CAAC,WAAW;IAUV,MAAM,CACb,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAChC,OAAO,EAAE,OAAO,GACf,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAkBxB,KAAK,CACZ,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAChC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAChC,OAAO,EAAE,OAAO,GACf,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IASxB,OAAO,CACd,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAChC,KAAK,EAAE,KAAK,EACZ,OAAO,EAAE,OAAO,GACf,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;CAQlC"}
|