@ultimat3/core 2.0.0 → 4.0.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/CLAUDE.md +46 -0
- package/README.md +39 -0
- package/package.json +1 -1
- package/src/actor.ts +27 -1
- package/src/canonical-json.ts +102 -0
- package/src/config.ts +33 -10
- package/src/decimal-order.ts +76 -0
- package/src/env-example.ts +9 -1
- package/src/error-codes.ts +2 -1
- package/src/error-retry.ts +40 -14
- package/src/exports/error-contract.ts +1 -0
- package/src/image/errors.ts +1 -1
- package/src/index.ts +10 -12
- package/src/intl-cache.ts +43 -0
- package/src/lifecycle.ts +65 -24
- package/src/logger.ts +21 -2
- package/src/metrics-types.ts +102 -0
- package/src/metrics.ts +107 -92
- package/src/otlp-metric-exporter.ts +26 -3
- package/src/otlp-span-exporter.ts +28 -3
- package/src/type-pins.ts +10 -3
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
// Single responsibility: a `SpanExporter` that POSTs OTLP/HTTP JSON to a collector. Batched,
|
|
2
2
|
// because `SpanExporter.export` is one span and a request per span is a second load generator.
|
|
3
3
|
|
|
4
|
+
import { renderThrowable } from './error-render';
|
|
5
|
+
import { logger } from './logger';
|
|
4
6
|
import {
|
|
5
7
|
OTLP_SCOPE,
|
|
6
8
|
type OtlpKeyValue,
|
|
@@ -134,15 +136,38 @@ export function otlpSpanExporter(options: OtlpSpanExporterOptions = {}): OtlpSpa
|
|
|
134
136
|
const post = (batch: readonly ReadableSpan[]): Promise<void> => {
|
|
135
137
|
const first = batch[0];
|
|
136
138
|
if (first === undefined) return Promise.resolve();
|
|
137
|
-
|
|
139
|
+
let body: string;
|
|
140
|
+
try {
|
|
141
|
+
// The one synchronous throw on this path, and the only way `inflight` can reject at all:
|
|
142
|
+
// `AttributeValue` is a compile-time claim, so an attribute the app spelled as an object, a
|
|
143
|
+
// bigint or a cycle reaches `anyValue`'s `value.map(...)` as a TypeError. Dropped with a
|
|
144
|
+
// line, the same degradation `postOtlp` already applies to a collector that is down —
|
|
145
|
+
// telemetry is best-effort and must never become the process's exit code.
|
|
146
|
+
body = JSON.stringify(otlpTraceRequest(batch, first.resource));
|
|
147
|
+
} catch (failure) {
|
|
148
|
+
logger.warn('otlp span batch dropped', {
|
|
149
|
+
url,
|
|
150
|
+
spans: batch.length,
|
|
151
|
+
error: renderThrowable(failure),
|
|
152
|
+
});
|
|
153
|
+
return Promise.resolve();
|
|
154
|
+
}
|
|
138
155
|
return postOtlp({ url, headers, body, timeoutMs, fetch: send });
|
|
139
156
|
};
|
|
140
157
|
|
|
141
158
|
const drainQueue = (): Promise<void> => {
|
|
142
159
|
const batch = queue.splice(0, queue.length);
|
|
143
160
|
// Chained, not concurrent: a collector reordering batches from one process turns a parent's
|
|
144
|
-
// span arriving after its child into a broken trace on the read side.
|
|
145
|
-
|
|
161
|
+
// span arriving after its child into a broken trace on the read side. Chained on a SETTLED
|
|
162
|
+
// shadow, because a chain that carries a rejection forward is poisoned for the life of the
|
|
163
|
+
// process: `post` is never called again while the queue keeps emptying, so every later span is
|
|
164
|
+
// dropped in silence and every timer tick mints a fresh unhandled rejection — which Bun ends
|
|
165
|
+
// the process on. Same shape as `offline-queue.ts`'s drain chain.
|
|
166
|
+
const settled = inflight.then(
|
|
167
|
+
() => undefined,
|
|
168
|
+
() => undefined,
|
|
169
|
+
);
|
|
170
|
+
inflight = settled.then(() => post(batch));
|
|
146
171
|
return inflight;
|
|
147
172
|
};
|
|
148
173
|
|
package/src/type-pins.ts
CHANGED
|
@@ -52,9 +52,15 @@ type _ActorFactMapAcceptsNothing = Assert<
|
|
|
52
52
|
>;
|
|
53
53
|
|
|
54
54
|
/**
|
|
55
|
-
* The seam is additive: an actor literal
|
|
56
|
-
* optional for that reason and not only for the denial rule —
|
|
57
|
-
* a breaking change to a tier-0 type every package depends on.
|
|
55
|
+
* The seam is additive: an actor literal carrying the required members but no `facts` still is an
|
|
56
|
+
* `Actor`. `facts` is optional for that reason and not only for the denial rule — making it
|
|
57
|
+
* required would be a breaking change to a tier-0 type every package depends on.
|
|
58
|
+
*
|
|
59
|
+
* `permissions` joined the required set in 4.0.0 and is spelled here deliberately. That WAS such a
|
|
60
|
+
* breaking change, made knowingly and with a migration: policy's `PolicyActorFields` held it, so
|
|
61
|
+
* `userActor({ permissions })` silently dropped it and no builder could spell a direct grant. This
|
|
62
|
+
* pin is what makes the next one impossible to add by accident — a new required member fails here
|
|
63
|
+
* before it fails in an app.
|
|
58
64
|
*/
|
|
59
65
|
type _ActorWithoutFactsIsStillAnActor = Assert<
|
|
60
66
|
[
|
|
@@ -63,6 +69,7 @@ type _ActorWithoutFactsIsStillAnActor = Assert<
|
|
|
63
69
|
readonly id: string;
|
|
64
70
|
readonly roles: readonly string[];
|
|
65
71
|
readonly scopes: readonly string[];
|
|
72
|
+
readonly permissions: readonly string[];
|
|
66
73
|
},
|
|
67
74
|
] extends [Actor]
|
|
68
75
|
? true
|