margin-ts 0.6.1 → 0.7.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/dist/index.js CHANGED
@@ -8,7 +8,8 @@
8
8
  * Copyright (c) 2026 Cope Labs LLC. MIT License.
9
9
  */
10
10
  Object.defineProperty(exports, "__esModule", { value: true });
11
- exports.DEFAULT_SUITE_THRESHOLDS = exports.suiteHealthString = exports.classifySuite = exports.EXPRESS_THRESHOLDS = exports.marginHealthRoute = exports.marginMiddleware = exports.classifyAnomaly = exports.ANOMALY_SEVERITY = exports.AnomalyState = exports.classifyDrift = exports.DriftDirection = exports.DriftState = exports.Parser = exports.expressionToDict = exports.expressionToString = exports.degraded = exports.healthOf = exports.createExpression = exports.correctionIsActive = exports.observationFromDict = exports.observationToDict = exports.observationToAtom = exports.observationSigma = exports.Op = exports.classify = exports.isAblated = exports.isIntact = exports.createThresholds = exports.SEVERITY = exports.Health = exports.minConfidence = exports.confidenceLt = exports.confidenceGte = exports.confidenceRank = exports.Confidence = void 0;
11
+ exports.marginPoll = exports.marginSSEHandler = exports.marginSSE = exports.broadcast = exports.StreamingMonitor = exports.DEFAULT_NEXTJS_THRESHOLDS = exports.resetRoutes = exports.marginHealthAppHandler = exports.marginHealthHandler = exports.withMarginApp = exports.withMargin = exports.DEFAULT_SUITE_THRESHOLDS = exports.suiteHealthString = exports.classifySuite = exports.EXPRESS_THRESHOLDS = exports.marginHealthRoute = exports.marginMiddleware = exports.classifyAnomaly = exports.ANOMALY_SEVERITY = exports.AnomalyState = exports.classifyDrift = exports.DriftDirection = exports.DriftState = exports.Parser = exports.expressionToDict = exports.expressionToString = exports.intact = exports.absent = exports.degraded = exports.healthOf = exports.createExpression = exports.correctionIsActive = exports.observationFromDict = exports.observationToDict = exports.observationToAtom = exports.observationSigma = exports.isAbsent = exports.Op = exports.Absence = exports.classify = exports.isAblated = exports.isIntact = exports.createThresholds = exports.SEVERITY = exports.Health = exports.minConfidence = exports.confidenceLt = exports.confidenceGte = exports.confidenceRank = exports.Confidence = void 0;
12
+ exports.resetClients = exports.connectedClients = void 0;
12
13
  var confidence_js_1 = require("./confidence.js");
13
14
  Object.defineProperty(exports, "Confidence", { enumerable: true, get: function () { return confidence_js_1.Confidence; } });
14
15
  Object.defineProperty(exports, "confidenceRank", { enumerable: true, get: function () { return confidence_js_1.confidenceRank; } });
@@ -23,7 +24,9 @@ Object.defineProperty(exports, "isIntact", { enumerable: true, get: function ()
23
24
  Object.defineProperty(exports, "isAblated", { enumerable: true, get: function () { return health_js_1.isAblated; } });
24
25
  Object.defineProperty(exports, "classify", { enumerable: true, get: function () { return health_js_1.classify; } });
25
26
  var observation_js_1 = require("./observation.js");
27
+ Object.defineProperty(exports, "Absence", { enumerable: true, get: function () { return observation_js_1.Absence; } });
26
28
  Object.defineProperty(exports, "Op", { enumerable: true, get: function () { return observation_js_1.Op; } });
29
+ Object.defineProperty(exports, "isAbsent", { enumerable: true, get: function () { return observation_js_1.isAbsent; } });
27
30
  Object.defineProperty(exports, "observationSigma", { enumerable: true, get: function () { return observation_js_1.observationSigma; } });
28
31
  Object.defineProperty(exports, "observationToAtom", { enumerable: true, get: function () { return observation_js_1.observationToAtom; } });
29
32
  Object.defineProperty(exports, "observationToDict", { enumerable: true, get: function () { return observation_js_1.observationToDict; } });
@@ -32,6 +35,8 @@ Object.defineProperty(exports, "correctionIsActive", { enumerable: true, get: fu
32
35
  Object.defineProperty(exports, "createExpression", { enumerable: true, get: function () { return observation_js_1.createExpression; } });
33
36
  Object.defineProperty(exports, "healthOf", { enumerable: true, get: function () { return observation_js_1.healthOf; } });
34
37
  Object.defineProperty(exports, "degraded", { enumerable: true, get: function () { return observation_js_1.degraded; } });
38
+ Object.defineProperty(exports, "absent", { enumerable: true, get: function () { return observation_js_1.absent; } });
39
+ Object.defineProperty(exports, "intact", { enumerable: true, get: function () { return observation_js_1.intact; } });
35
40
  Object.defineProperty(exports, "expressionToString", { enumerable: true, get: function () { return observation_js_1.expressionToString; } });
36
41
  Object.defineProperty(exports, "expressionToDict", { enumerable: true, get: function () { return observation_js_1.expressionToDict; } });
37
42
  Object.defineProperty(exports, "Parser", { enumerable: true, get: function () { return observation_js_1.Parser; } });
@@ -52,4 +57,19 @@ var vitest_js_1 = require("./adapters/vitest.js");
52
57
  Object.defineProperty(exports, "classifySuite", { enumerable: true, get: function () { return vitest_js_1.classifySuite; } });
53
58
  Object.defineProperty(exports, "suiteHealthString", { enumerable: true, get: function () { return vitest_js_1.suiteHealthString; } });
54
59
  Object.defineProperty(exports, "DEFAULT_SUITE_THRESHOLDS", { enumerable: true, get: function () { return vitest_js_1.DEFAULT_SUITE_THRESHOLDS; } });
60
+ var nextjs_js_1 = require("./adapters/nextjs.js");
61
+ Object.defineProperty(exports, "withMargin", { enumerable: true, get: function () { return nextjs_js_1.withMargin; } });
62
+ Object.defineProperty(exports, "withMarginApp", { enumerable: true, get: function () { return nextjs_js_1.withMarginApp; } });
63
+ Object.defineProperty(exports, "marginHealthHandler", { enumerable: true, get: function () { return nextjs_js_1.marginHealthHandler; } });
64
+ Object.defineProperty(exports, "marginHealthAppHandler", { enumerable: true, get: function () { return nextjs_js_1.marginHealthAppHandler; } });
65
+ Object.defineProperty(exports, "resetRoutes", { enumerable: true, get: function () { return nextjs_js_1.resetRoutes; } });
66
+ Object.defineProperty(exports, "DEFAULT_NEXTJS_THRESHOLDS", { enumerable: true, get: function () { return nextjs_js_1.DEFAULT_NEXTJS_THRESHOLDS; } });
67
+ var stream_js_1 = require("./adapters/stream.js");
68
+ Object.defineProperty(exports, "StreamingMonitor", { enumerable: true, get: function () { return stream_js_1.StreamingMonitor; } });
69
+ Object.defineProperty(exports, "broadcast", { enumerable: true, get: function () { return stream_js_1.broadcast; } });
70
+ Object.defineProperty(exports, "marginSSE", { enumerable: true, get: function () { return stream_js_1.marginSSE; } });
71
+ Object.defineProperty(exports, "marginSSEHandler", { enumerable: true, get: function () { return stream_js_1.marginSSEHandler; } });
72
+ Object.defineProperty(exports, "marginPoll", { enumerable: true, get: function () { return stream_js_1.marginPoll; } });
73
+ Object.defineProperty(exports, "connectedClients", { enumerable: true, get: function () { return stream_js_1.connectedClients; } });
74
+ Object.defineProperty(exports, "resetClients", { enumerable: true, get: function () { return stream_js_1.resetClients; } });
55
75
  //# 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;;;;;;;GAOG;;;AAEH,iDAAyG;AAAhG,2GAAA,UAAU,OAAA;AAAE,+GAAA,cAAc,OAAA;AAAE,8GAAA,aAAa,OAAA;AAAE,6GAAA,YAAY,OAAA;AAAE,8GAAA,aAAa,OAAA;AAE/E,yCAGqB;AAFnB,mGAAA,MAAM,OAAA;AAAE,qGAAA,QAAQ,OAAA;AAAc,6GAAA,gBAAgB,OAAA;AAC9C,qGAAA,QAAQ,OAAA;AAAE,sGAAA,SAAS,OAAA;AAAE,qGAAA,QAAQ,OAAA;AAG/B,mDAM0B;AALxB,oGAAA,EAAE,OAAA;AACF,kHAAA,gBAAgB,OAAA;AAAE,mHAAA,iBAAiB,OAAA;AAAE,mHAAA,iBAAiB,OAAA;AAAE,qHAAA,mBAAmB,OAAA;AAC3E,oHAAA,kBAAkB,OAAA;AAClB,kHAAA,gBAAgB,OAAA;AAAE,0GAAA,QAAQ,OAAA;AAAE,0GAAA,QAAQ,OAAA;AAAE,oHAAA,kBAAkB,OAAA;AAAE,kHAAA,gBAAgB,OAAA;AAC1E,wGAAA,MAAM,OAAA;AAGR,uCAGoB;AAFlB,sGAAA,UAAU,OAAA;AAAE,0GAAA,cAAc,OAAA;AAC1B,yGAAA,aAAa,OAAA;AAGf,2CAGsB;AAFpB,0GAAA,YAAY,OAAA;AAAE,8GAAA,gBAAgB,OAAA;AAC9B,6GAAA,eAAe,OAAA;AAGjB,WAAW;AACX,oDAI+B;AAH7B,8GAAA,gBAAgB,OAAA;AAAE,+GAAA,iBAAiB,OAAA;AACnC,gHAAA,kBAAkB,OAAsB;AAI1C,kDAI8B;AAH5B,0GAAA,aAAa,OAAA;AAAE,8GAAA,iBAAiB,OAAA;AAChC,qHAAA,wBAAwB,OAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;;;;;GAOG;;;;AAEH,iDAAyG;AAAhG,2GAAA,UAAU,OAAA;AAAE,+GAAA,cAAc,OAAA;AAAE,8GAAA,aAAa,OAAA;AAAE,6GAAA,YAAY,OAAA;AAAE,8GAAA,aAAa,OAAA;AAE/E,yCAGqB;AAFnB,mGAAA,MAAM,OAAA;AAAE,qGAAA,QAAQ,OAAA;AAAc,6GAAA,gBAAgB,OAAA;AAC9C,qGAAA,QAAQ,OAAA;AAAE,sGAAA,SAAS,OAAA;AAAE,qGAAA,QAAQ,OAAA;AAG/B,mDAQ0B;AAPxB,yGAAA,OAAO,OAAA;AACP,oGAAA,EAAE,OAAA;AACF,0GAAA,QAAQ,OAAA;AACR,kHAAA,gBAAgB,OAAA;AAAE,mHAAA,iBAAiB,OAAA;AAAE,mHAAA,iBAAiB,OAAA;AAAE,qHAAA,mBAAmB,OAAA;AAC3E,oHAAA,kBAAkB,OAAA;AAClB,kHAAA,gBAAgB,OAAA;AAAE,0GAAA,QAAQ,OAAA;AAAE,0GAAA,QAAQ,OAAA;AAAE,wGAAA,MAAM,OAAA;AAAE,wGAAA,MAAM,OAAA;AAAE,oHAAA,kBAAkB,OAAA;AAAE,kHAAA,gBAAgB,OAAA;AAC1F,wGAAA,MAAM,OAAA;AAGR,uCAGoB;AAFlB,sGAAA,UAAU,OAAA;AAAE,0GAAA,cAAc,OAAA;AAC1B,yGAAA,aAAa,OAAA;AAGf,2CAGsB;AAFpB,0GAAA,YAAY,OAAA;AAAE,8GAAA,gBAAgB,OAAA;AAC9B,6GAAA,eAAe,OAAA;AAGjB,WAAW;AACX,oDAI+B;AAH7B,8GAAA,gBAAgB,OAAA;AAAE,+GAAA,iBAAiB,OAAA;AACnC,gHAAA,kBAAkB,OAAsB;AAI1C,kDAI8B;AAH5B,0GAAA,aAAa,OAAA;AAAE,8GAAA,iBAAiB,OAAA;AAChC,qHAAA,wBAAwB,OAAA;AAI1B,kDAM8B;AAL5B,uGAAA,UAAU,OAAA;AAAE,0GAAA,aAAa,OAAA;AACzB,gHAAA,mBAAmB,OAAA;AAAE,mHAAA,sBAAsB,OAAA;AAC3C,wGAAA,WAAW,OAAA;AACX,sHAAA,yBAAyB,OAAA;AAI3B,kDAI8B;AAH5B,6GAAA,gBAAgB,OAAA;AAChB,sGAAA,SAAS,OAAA;AAAE,sGAAA,SAAS,OAAA;AAAE,6GAAA,gBAAgB,OAAA;AAAE,uGAAA,UAAU,OAAA;AAClD,6GAAA,gBAAgB,OAAA;AAAE,yGAAA,YAAY,OAAA"}
@@ -3,6 +3,15 @@
3
3
  */
4
4
  import { Confidence } from './confidence.js';
5
5
  import { Health, Thresholds } from './health.js';
6
+ export declare enum Absence {
7
+ NOT_MEASURED = "not_measured",
8
+ BELOW_DETECTION = "below_detection",
9
+ ABOVE_RANGE = "above_range",
10
+ SENSOR_FAILED = "sensor_failed",
11
+ REDACTED = "redacted",
12
+ NOT_APPLICABLE = "not_applicable",
13
+ PENDING = "pending"
14
+ }
6
15
  export interface Observation {
7
16
  name: string;
8
17
  health: Health;
@@ -12,7 +21,10 @@ export interface Observation {
12
21
  higherIsBetter: boolean;
13
22
  provenance: string[];
14
23
  measuredAt?: Date;
24
+ absence?: Absence;
25
+ absenceDetail?: string;
15
26
  }
27
+ export declare function isAbsent(obs: Observation): boolean;
16
28
  export declare function observationSigma(obs: Observation): number;
17
29
  export declare function observationToAtom(obs: Observation): string;
18
30
  export declare function observationToDict(obs: Observation): Record<string, unknown>;
@@ -42,6 +54,8 @@ export interface Expression {
42
54
  export declare function createExpression(observations?: Observation[], corrections?: Correction[], label?: string, step?: number): Expression;
43
55
  export declare function healthOf(expr: Expression, name: string): Health | undefined;
44
56
  export declare function degraded(expr: Expression): Observation[];
57
+ export declare function absent(expr: Expression): Observation[];
58
+ export declare function intact(expr: Expression): Observation[];
45
59
  export declare function expressionToString(expr: Expression): string;
46
60
  export declare function expressionToDict(expr: Expression): Record<string, unknown>;
47
61
  export declare class Parser {
@@ -54,6 +68,7 @@ export declare class Parser {
54
68
  label?: string;
55
69
  step?: number;
56
70
  confidences?: Record<string, Confidence>;
71
+ absences?: Record<string, Absence>;
57
72
  }): Expression;
58
73
  }
59
74
  //# sourceMappingURL=observation.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"observation.d.ts","sourceRoot":"","sources":["../src/observation.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"observation.d.ts","sourceRoot":"","sources":["../src/observation.ts"],"names":[],"mappings":"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"}
@@ -3,7 +3,8 @@
3
3
  * Observations, corrections, expressions, and parser.
4
4
  */
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.Parser = exports.Op = void 0;
6
+ exports.Parser = exports.Op = exports.Absence = void 0;
7
+ exports.isAbsent = isAbsent;
7
8
  exports.observationSigma = observationSigma;
8
9
  exports.observationToAtom = observationToAtom;
9
10
  exports.observationToDict = observationToDict;
@@ -12,10 +13,28 @@ exports.correctionIsActive = correctionIsActive;
12
13
  exports.createExpression = createExpression;
13
14
  exports.healthOf = healthOf;
14
15
  exports.degraded = degraded;
16
+ exports.absent = absent;
17
+ exports.intact = intact;
15
18
  exports.expressionToString = expressionToString;
16
19
  exports.expressionToDict = expressionToDict;
17
20
  const confidence_js_1 = require("./confidence.js");
18
21
  const health_js_1 = require("./health.js");
22
+ // -----------------------------------------------------------------------
23
+ // Absence — why a value is missing
24
+ // -----------------------------------------------------------------------
25
+ var Absence;
26
+ (function (Absence) {
27
+ Absence["NOT_MEASURED"] = "not_measured";
28
+ Absence["BELOW_DETECTION"] = "below_detection";
29
+ Absence["ABOVE_RANGE"] = "above_range";
30
+ Absence["SENSOR_FAILED"] = "sensor_failed";
31
+ Absence["REDACTED"] = "redacted";
32
+ Absence["NOT_APPLICABLE"] = "not_applicable";
33
+ Absence["PENDING"] = "pending";
34
+ })(Absence || (exports.Absence = Absence = {}));
35
+ function isAbsent(obs) {
36
+ return obs.absence !== undefined;
37
+ }
19
38
  function observationSigma(obs) {
20
39
  if (obs.baseline === 0)
21
40
  return 0;
@@ -23,6 +42,8 @@ function observationSigma(obs) {
23
42
  return obs.higherIsBetter ? raw : -raw;
24
43
  }
25
44
  function observationToAtom(obs) {
45
+ if (obs.absence !== undefined)
46
+ return `${obs.name}:ABSENT(${obs.absence})`;
26
47
  if (obs.health === health_js_1.Health.OOD)
27
48
  return `${obs.name}:${obs.health}`;
28
49
  const sigma = observationSigma(obs);
@@ -42,10 +63,14 @@ function observationToDict(obs) {
42
63
  };
43
64
  if (obs.measuredAt)
44
65
  d.measuredAt = obs.measuredAt.toISOString();
66
+ if (obs.absence !== undefined)
67
+ d.absence = obs.absence;
68
+ if (obs.absenceDetail !== undefined)
69
+ d.absenceDetail = obs.absenceDetail;
45
70
  return d;
46
71
  }
47
72
  function observationFromDict(d) {
48
- return {
73
+ const obs = {
49
74
  name: d.name,
50
75
  health: d.health,
51
76
  value: d.value,
@@ -55,6 +80,11 @@ function observationFromDict(d) {
55
80
  provenance: d.provenance ?? [],
56
81
  measuredAt: d.measuredAt ? new Date(d.measuredAt) : undefined,
57
82
  };
83
+ if (d.absence !== undefined)
84
+ obs.absence = d.absence;
85
+ if (d.absenceDetail !== undefined)
86
+ obs.absenceDetail = d.absenceDetail;
87
+ return obs;
58
88
  }
59
89
  // -----------------------------------------------------------------------
60
90
  // Correction
@@ -81,6 +111,12 @@ function healthOf(expr, name) {
81
111
  function degraded(expr) {
82
112
  return expr.observations.filter(o => o.health === health_js_1.Health.DEGRADED || o.health === health_js_1.Health.ABLATED || o.health === health_js_1.Health.RECOVERING);
83
113
  }
114
+ function absent(expr) {
115
+ return expr.observations.filter(o => isAbsent(o));
116
+ }
117
+ function intact(expr) {
118
+ return expr.observations.filter(o => o.health === health_js_1.Health.INTACT);
119
+ }
84
120
  function expressionToString(expr) {
85
121
  if (expr.observations.length === 0)
86
122
  return '[∅]';
@@ -123,8 +159,11 @@ class Parser {
123
159
  }
124
160
  parse(values, options = {}) {
125
161
  const confidences = options.confidences ?? {};
162
+ const absences = options.absences ?? {};
126
163
  const observations = [];
127
164
  for (const [name, val] of Object.entries(values)) {
165
+ if (name in absences)
166
+ continue; // handled below
128
167
  const baseline = this.baselines[name] ?? val;
129
168
  const conf = confidences[name] ?? confidence_js_1.Confidence.MODERATE;
130
169
  const t = this.thresholdsFor(name);
@@ -140,6 +179,23 @@ class Parser {
140
179
  measuredAt: undefined,
141
180
  });
142
181
  }
182
+ // Emit absent observations
183
+ for (const [name, reason] of Object.entries(absences)) {
184
+ const baseline = this.baselines[name] ?? 0;
185
+ const t = this.thresholdsFor(name);
186
+ const conf = confidences[name] ?? confidence_js_1.Confidence.INDETERMINATE;
187
+ observations.push({
188
+ name,
189
+ health: health_js_1.Health.OOD,
190
+ value: baseline,
191
+ baseline,
192
+ confidence: conf,
193
+ higherIsBetter: t.higherIsBetter !== false,
194
+ provenance: [],
195
+ measuredAt: undefined,
196
+ absence: reason,
197
+ });
198
+ }
143
199
  return createExpression(observations, [], options.label ?? '', options.step);
144
200
  }
145
201
  }
@@ -1 +1 @@
1
- {"version":3,"file":"observation.js","sourceRoot":"","sources":["../src/observation.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"observation.js","sourceRoot":"","sources":["../src/observation.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "margin-ts",
3
- "version": "0.6.1",
3
+ "version": "0.7.0",
4
4
  "description": "Typed health classification for systems that measure things. Zero dependencies.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -0,0 +1,290 @@
1
+ /**
2
+ * Next.js API route adapter for margin.
3
+ *
4
+ * One-liner health tracking for any API route:
5
+ *
6
+ * // pages/api/users.ts (Pages Router)
7
+ * import { withMargin } from 'margin-ts/adapters/nextjs';
8
+ * export default withMargin(handler);
9
+ *
10
+ * // app/api/users/route.ts (App Router)
11
+ * import { withMarginApp } from 'margin-ts/adapters/nextjs';
12
+ * export const GET = withMarginApp(handler);
13
+ *
14
+ * // Health endpoint
15
+ * // pages/api/margin/health.ts
16
+ * import { marginHealthHandler } from 'margin-ts/adapters/nextjs';
17
+ * export default marginHealthHandler();
18
+ *
19
+ * Tracks latency, error rate, and request count per route.
20
+ * Zero dependencies beyond margin-ts core.
21
+ */
22
+
23
+ import {
24
+ Confidence,
25
+ Health,
26
+ Thresholds,
27
+ createThresholds,
28
+ classify,
29
+ Observation,
30
+ createExpression,
31
+ expressionToString,
32
+ expressionToDict,
33
+ } from '../index.js';
34
+
35
+ // -----------------------------------------------------------------------
36
+ // Shared state — singleton across all wrapped routes
37
+ // -----------------------------------------------------------------------
38
+
39
+ interface RouteStats {
40
+ totalRequests: number;
41
+ totalErrors: number;
42
+ latencies: number[];
43
+ maxWindow: number;
44
+ }
45
+
46
+ const _routes = new Map<string, RouteStats>();
47
+ const _MAX_WINDOW = 200;
48
+
49
+ function getOrCreateRoute(route: string): RouteStats {
50
+ if (!_routes.has(route)) {
51
+ _routes.set(route, {
52
+ totalRequests: 0,
53
+ totalErrors: 0,
54
+ latencies: [],
55
+ maxWindow: _MAX_WINDOW,
56
+ });
57
+ }
58
+ return _routes.get(route)!;
59
+ }
60
+
61
+ function record(route: string, latencyMs: number, isError: boolean): void {
62
+ const stats = getOrCreateRoute(route);
63
+ stats.totalRequests++;
64
+ if (isError) stats.totalErrors++;
65
+ stats.latencies.push(latencyMs);
66
+ if (stats.latencies.length > stats.maxWindow) stats.latencies.shift();
67
+ }
68
+
69
+ // -----------------------------------------------------------------------
70
+ // Thresholds
71
+ // -----------------------------------------------------------------------
72
+
73
+ export interface NextjsThresholds {
74
+ p50Latency: Thresholds;
75
+ p99Latency: Thresholds;
76
+ errorRate: Thresholds;
77
+ }
78
+
79
+ export const DEFAULT_NEXTJS_THRESHOLDS: NextjsThresholds = {
80
+ p50Latency: createThresholds(100, 500, false),
81
+ p99Latency: createThresholds(500, 2000, false),
82
+ errorRate: createThresholds(0.01, 0.10, false),
83
+ };
84
+
85
+ // -----------------------------------------------------------------------
86
+ // Classification
87
+ // -----------------------------------------------------------------------
88
+
89
+ function percentile(sorted: number[], p: number): number {
90
+ if (sorted.length === 0) return 0;
91
+ const idx = Math.ceil(sorted.length * p) - 1;
92
+ return sorted[Math.max(0, Math.min(idx, sorted.length - 1))];
93
+ }
94
+
95
+ function classifyRoute(route: string, stats: RouteStats, thresholds: NextjsThresholds) {
96
+ if (stats.latencies.length < 3) return null;
97
+
98
+ const sorted = [...stats.latencies].sort((a, b) => a - b);
99
+ const p50 = percentile(sorted, 0.5);
100
+ const p99 = percentile(sorted, 0.99);
101
+ const errorRate = stats.totalRequests > 0 ? stats.totalErrors / stats.totalRequests : 0;
102
+ const now = new Date();
103
+
104
+ const observations: Observation[] = [
105
+ {
106
+ name: `${route}:p50`, health: classify(p50, Confidence.HIGH, thresholds.p50Latency),
107
+ value: p50, baseline: thresholds.p50Latency.intact, confidence: Confidence.HIGH,
108
+ higherIsBetter: false, provenance: [], measuredAt: now,
109
+ },
110
+ {
111
+ name: `${route}:p99`, health: classify(p99, Confidence.HIGH, thresholds.p99Latency),
112
+ value: p99, baseline: thresholds.p99Latency.intact, confidence: Confidence.HIGH,
113
+ higherIsBetter: false, provenance: [], measuredAt: now,
114
+ },
115
+ {
116
+ name: `${route}:errors`, health: classify(errorRate, Confidence.HIGH, thresholds.errorRate),
117
+ value: errorRate, baseline: 0.001, confidence: Confidence.HIGH,
118
+ higherIsBetter: false, provenance: [], measuredAt: now,
119
+ },
120
+ ];
121
+
122
+ return createExpression(observations, [], route);
123
+ }
124
+
125
+ // -----------------------------------------------------------------------
126
+ // Pages Router wrapper
127
+ // -----------------------------------------------------------------------
128
+
129
+ export interface WithMarginOptions {
130
+ route?: string;
131
+ thresholds?: NextjsThresholds;
132
+ }
133
+
134
+ /**
135
+ * Wrap a Pages Router API handler with margin health tracking.
136
+ *
137
+ * export default withMargin(handler);
138
+ * export default withMargin(handler, { route: '/api/users' });
139
+ */
140
+ export function withMargin(
141
+ handler: (req: any, res: any) => any,
142
+ options: WithMarginOptions = {},
143
+ ): (req: any, res: any) => any {
144
+ return async (req: any, res: any) => {
145
+ const route = options.route || req.url || '/api/unknown';
146
+ const start = Date.now();
147
+
148
+ try {
149
+ const result = await handler(req, res);
150
+ const latency = Date.now() - start;
151
+ const status = res.statusCode || 200;
152
+ record(route, latency, status >= 500);
153
+ return result;
154
+ } catch (err) {
155
+ const latency = Date.now() - start;
156
+ record(route, latency, true);
157
+ throw err;
158
+ }
159
+ };
160
+ }
161
+
162
+ // -----------------------------------------------------------------------
163
+ // App Router wrapper
164
+ // -----------------------------------------------------------------------
165
+
166
+ /**
167
+ * Wrap an App Router handler with margin health tracking.
168
+ *
169
+ * export const GET = withMarginApp(handler);
170
+ * export const POST = withMarginApp(handler, { route: '/api/users' });
171
+ */
172
+ export function withMarginApp(
173
+ handler: (req: any) => any,
174
+ options: WithMarginOptions = {},
175
+ ): (req: any) => any {
176
+ return async (req: any) => {
177
+ const route = options.route || new URL(req.url || '/', 'http://localhost').pathname;
178
+ const start = Date.now();
179
+
180
+ try {
181
+ const response = await handler(req);
182
+ const latency = Date.now() - start;
183
+ const status = response?.status || 200;
184
+ record(route, latency, status >= 500);
185
+ return response;
186
+ } catch (err) {
187
+ const latency = Date.now() - start;
188
+ record(route, latency, true);
189
+ throw err;
190
+ }
191
+ };
192
+ }
193
+
194
+ // -----------------------------------------------------------------------
195
+ // Health endpoint
196
+ // -----------------------------------------------------------------------
197
+
198
+ /**
199
+ * Pages Router: health endpoint handler.
200
+ *
201
+ * // pages/api/margin/health.ts
202
+ * import { marginHealthHandler } from 'margin-ts/adapters/nextjs';
203
+ * export default marginHealthHandler();
204
+ */
205
+ export function marginHealthHandler(thresholds?: NextjsThresholds): (req: any, res: any) => void {
206
+ const t = thresholds || DEFAULT_NEXTJS_THRESHOLDS;
207
+
208
+ return (_req: any, res: any) => {
209
+ const routeHealth: Record<string, any> = {};
210
+ let worstOverall = Health.INTACT;
211
+ const SEVERITY: Record<Health, number> = {
212
+ [Health.INTACT]: 0, [Health.RECOVERING]: 1, [Health.DEGRADED]: 2,
213
+ [Health.ABLATED]: 3, [Health.OOD]: 4,
214
+ };
215
+
216
+ for (const [route, stats] of _routes) {
217
+ const expr = classifyRoute(route, stats, t);
218
+ if (expr) {
219
+ routeHealth[route] = {
220
+ expression: expressionToString(expr),
221
+ ...expressionToDict(expr),
222
+ requests: stats.totalRequests,
223
+ errors: stats.totalErrors,
224
+ };
225
+ for (const obs of expr.observations) {
226
+ if (SEVERITY[obs.health] > SEVERITY[worstOverall]) {
227
+ worstOverall = obs.health;
228
+ }
229
+ }
230
+ }
231
+ }
232
+
233
+ res.status(200).json({
234
+ status: worstOverall,
235
+ routes: routeHealth,
236
+ totalRoutes: _routes.size,
237
+ });
238
+ };
239
+ }
240
+
241
+ /**
242
+ * App Router: health endpoint handler.
243
+ *
244
+ * // app/api/margin/health/route.ts
245
+ * import { marginHealthAppHandler } from 'margin-ts/adapters/nextjs';
246
+ * export const GET = marginHealthAppHandler();
247
+ */
248
+ export function marginHealthAppHandler(thresholds?: NextjsThresholds): (req: any) => any {
249
+ const t = thresholds || DEFAULT_NEXTJS_THRESHOLDS;
250
+
251
+ return (_req: any) => {
252
+ const routeHealth: Record<string, any> = {};
253
+ let worstOverall = Health.INTACT;
254
+ const SEVERITY: Record<Health, number> = {
255
+ [Health.INTACT]: 0, [Health.RECOVERING]: 1, [Health.DEGRADED]: 2,
256
+ [Health.ABLATED]: 3, [Health.OOD]: 4,
257
+ };
258
+
259
+ for (const [route, stats] of _routes) {
260
+ const expr = classifyRoute(route, stats, t);
261
+ if (expr) {
262
+ routeHealth[route] = {
263
+ expression: expressionToString(expr),
264
+ ...expressionToDict(expr),
265
+ requests: stats.totalRequests,
266
+ errors: stats.totalErrors,
267
+ };
268
+ for (const obs of expr.observations) {
269
+ if (SEVERITY[obs.health] > SEVERITY[worstOverall]) {
270
+ worstOverall = obs.health;
271
+ }
272
+ }
273
+ }
274
+ }
275
+
276
+ return new Response(JSON.stringify({
277
+ status: worstOverall,
278
+ routes: routeHealth,
279
+ totalRoutes: _routes.size,
280
+ }), {
281
+ status: 200,
282
+ headers: { 'Content-Type': 'application/json' },
283
+ });
284
+ };
285
+ }
286
+
287
+ /** Clear all tracked routes (for testing). */
288
+ export function resetRoutes(): void {
289
+ _routes.clear();
290
+ }