@autter/runtime-node 1.8.0 → 1.9.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 +69 -1
- package/dist/{chunk-7H3FCV4P.cjs → chunk-AN45KLWD.cjs} +11 -11
- package/dist/{chunk-MOZOUEMA.cjs → chunk-BHYHORUD.cjs} +44 -3
- package/dist/{chunk-QKY2OQSO.js → chunk-HHKQ3UCH.js} +533 -31
- package/dist/{chunk-UC3QH4PC.js → chunk-JSGGUWRD.js} +1 -1
- package/dist/{chunk-37W7YYXO.cjs → chunk-YWTIKZSI.cjs} +596 -94
- package/dist/{chunk-B5ZMOCEM.js → chunk-ZKM76SDP.js} +44 -3
- package/dist/cli.cjs +8 -8
- package/dist/cli.js +2 -2
- package/dist/index.cjs +424 -209
- package/dist/index.d.cts +75 -3
- package/dist/index.d.ts +75 -3
- package/dist/index.js +231 -16
- package/dist/{sinks-CIdlmYwy.d.cts → sinks-CLtQFPnn.d.cts} +39 -3
- package/dist/{sinks-CIdlmYwy.d.ts → sinks-CLtQFPnn.d.ts} +39 -3
- package/dist/testing.cjs +8 -8
- package/dist/testing.d.cts +2 -2
- package/dist/testing.d.ts +2 -2
- package/dist/testing.js +2 -2
- package/package.json +7 -3
package/README.md
CHANGED
|
@@ -127,7 +127,39 @@ export const POST = createBrowserRelayFetchHandler({
|
|
|
127
127
|
```
|
|
128
128
|
|
|
129
129
|
Options: `endpoint` (default `https://otlp.autter.dev`), `maxBodyBytes`
|
|
130
|
-
(default 64 KB), `
|
|
130
|
+
(default 64 KB), `perIpRateLimit` (default 120 requests a minute per client;
|
|
131
|
+
`false` when a WAF already limits the route), `trustProxy`, `redact`,
|
|
132
|
+
`compatCheck`, `onError`.
|
|
133
|
+
|
|
134
|
+
**Rate-limit key and `trustProxy`.** The relay route is public, so it limits
|
|
135
|
+
each visitor. Any caller can write anything into `X-Forwarded-For`, so by
|
|
136
|
+
default (`trustProxy: "auto"`) the relay never takes that header's first entry.
|
|
137
|
+
Proxies append the address they saw to the right of the header, or overwrite
|
|
138
|
+
it, so the relay reads it right to left and takes the first public address,
|
|
139
|
+
skipping hops on your own network. That works behind load balancers, CDNs and
|
|
140
|
+
hosting platforms with no setup:
|
|
141
|
+
|
|
142
|
+
| Where the relay runs | What `"auto"` keys |
|
|
143
|
+
| --- | --- |
|
|
144
|
+
| Node, reached directly | The connection's own address; the header is ignored |
|
|
145
|
+
| Node behind a load balancer or ingress on your network | The address that proxy appended |
|
|
146
|
+
| Next.js route handlers, Vercel, Netlify, Deno Deploy and other fetch runtimes | The rightmost public entry, which the platform's edge wrote |
|
|
147
|
+
| Cloudflare Workers | `CF-Connecting-IP` |
|
|
148
|
+
|
|
149
|
+
Other settings:
|
|
150
|
+
|
|
151
|
+
- `trustProxy: 1` (or any count) when exactly that many proxies you control
|
|
152
|
+
sit in front, such as a Node origin behind Cloudflare with no load balancer.
|
|
153
|
+
- `trustProxy: true` when every proxy in front strips client values: the
|
|
154
|
+
leftmost entry.
|
|
155
|
+
- `trustProxy: false` never reads the header: the socket address in Node, one
|
|
156
|
+
shared bucket in fetch runtimes.
|
|
157
|
+
- `clientIp: (request) => string` to supply the address yourself, for example
|
|
158
|
+
Deno's `info.remoteAddr` or Bun's `server.requestIP`.
|
|
159
|
+
|
|
160
|
+
Strings from environment variables work too (`"auto"`, `"false"`, `"2"`).
|
|
161
|
+
A fetch handler exposed straight to the internet with no proxy in front can
|
|
162
|
+
still be fooled by a forged header; set `trustProxy: false` or `clientIp` there.
|
|
131
163
|
|
|
132
164
|
## 2. Server tracker
|
|
133
165
|
|
|
@@ -276,6 +308,42 @@ settings (drop or sample by error type, message, service, environment,
|
|
|
276
308
|
route, release or source; ingester 1.9.0). The ingester also collapses a
|
|
277
309
|
looping error into one sample a minute with an exact count.
|
|
278
310
|
|
|
311
|
+
### Caught errors and deliberate fallbacks
|
|
312
|
+
|
|
313
|
+
Errors you catch and log count on their own — no `captureException` needed.
|
|
314
|
+
An `Error` passed to `console.error`, pino, winston, bunyan or
|
|
315
|
+
`runtimeLogger.error` becomes an occurrence at `error` severity, with the log
|
|
316
|
+
line as context and the error's stack, marked
|
|
317
|
+
`autter.handling: "caught"`. A log line with no error object is untouched, and
|
|
318
|
+
an error you also pass to `captureException` in the same tick is reported
|
|
319
|
+
once. A caught error never fails the request it happened in, and handled
|
|
320
|
+
occurrences stay out of your error rate — they are issues to see, not
|
|
321
|
+
failures. A burst limit per error kind keeps ten at once, then one every ten
|
|
322
|
+
seconds; the ones left out are counted.
|
|
323
|
+
|
|
324
|
+
```ts
|
|
325
|
+
initAutterServer({ ... }); // on by default
|
|
326
|
+
initAutterServer({ ..., captureLoggedErrors: false }); // off
|
|
327
|
+
initAutterServer({ ..., captureLoggedErrors: { console: false } }); // keep loggers, not console
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
When you mean to ignore an error — a fallback you chose — say so in one line:
|
|
331
|
+
|
|
332
|
+
```ts
|
|
333
|
+
try {
|
|
334
|
+
prices = await pricingService.get();
|
|
335
|
+
} catch (err) {
|
|
336
|
+
runtimeContext.degraded(err, "pricing service down, using cached prices");
|
|
337
|
+
prices = cached;
|
|
338
|
+
}
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
`runtimeContext.degraded(err, reason)` records the error at `warning`
|
|
342
|
+
severity, marked `autter.handling: "deliberate"` with the reason (grouped by
|
|
343
|
+
its code when the error is coded), and never pages anyone. The current
|
|
344
|
+
request or operation ends `degraded` unless it already failed or set its own
|
|
345
|
+
outcome — so a crash, a caught error and a deliberate fallback are told apart.
|
|
346
|
+
|
|
279
347
|
### Unhandled promise rejections
|
|
280
348
|
|
|
281
349
|
Recorded as errors (severity `error`, `autter.unhandled_rejection: true`, not
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
|
|
8
|
-
var
|
|
8
|
+
var _chunkBHYHORUDcjs = require('./chunk-BHYHORUD.cjs');
|
|
9
9
|
|
|
10
10
|
// src/doctor.ts
|
|
11
11
|
var _fs = require('fs');
|
|
@@ -30,19 +30,19 @@ function installedSdks(cwd) {
|
|
|
30
30
|
}
|
|
31
31
|
if (_path.dirname.call(void 0, dir) === dir) break;
|
|
32
32
|
}
|
|
33
|
-
if (!found.has(
|
|
33
|
+
if (!found.has(_chunkBHYHORUDcjs.SDK_IDENTITY.name)) found.set(_chunkBHYHORUDcjs.SDK_IDENTITY.name, _chunkBHYHORUDcjs.SDK_IDENTITY.version);
|
|
34
34
|
return [...found].map(([name, version]) => ({ name, version }));
|
|
35
35
|
}
|
|
36
36
|
function featuresInUse(sdks) {
|
|
37
|
-
return
|
|
37
|
+
return _chunkBHYHORUDcjs.COMPAT_MANIFEST.features.filter(
|
|
38
38
|
(feature) => sdks.some((sdk) => {
|
|
39
39
|
const min = feature.sdks[sdk.name];
|
|
40
|
-
return min !== void 0 &&
|
|
40
|
+
return min !== void 0 && _chunkBHYHORUDcjs.versionAtLeast.call(void 0, sdk.version, min) === true;
|
|
41
41
|
})
|
|
42
42
|
).map((feature) => feature.id);
|
|
43
43
|
}
|
|
44
44
|
async function checkKey(endpoint, key, timeoutMs) {
|
|
45
|
-
const res = await
|
|
45
|
+
const res = await _chunkBHYHORUDcjs.compatRequest.call(void 0, "POST", `${endpoint}/v1/traces`, {
|
|
46
46
|
body: JSON.stringify({ resourceSpans: [] }),
|
|
47
47
|
headers: { authorization: `Bearer ${key}` },
|
|
48
48
|
unref: false,
|
|
@@ -62,10 +62,10 @@ async function runDoctor(options = {}) {
|
|
|
62
62
|
const features = _optionalChain([options, 'access', _ => _.features, 'optionalAccess', _2 => _2.length]) ? options.features : featuresInUse(sdks);
|
|
63
63
|
const routes = [
|
|
64
64
|
...new Set(
|
|
65
|
-
features.map((id) => _optionalChain([
|
|
65
|
+
features.map((id) => _optionalChain([_chunkBHYHORUDcjs.COMPAT_MANIFEST, 'access', _3 => _3.features, 'access', _4 => _4.find, 'call', _5 => _5((f) => f.id === id), 'optionalAccess', _6 => _6.route])).filter((route) => Boolean(route))
|
|
66
66
|
)
|
|
67
67
|
];
|
|
68
|
-
const { info, error } = await
|
|
68
|
+
const { info, error } = await _chunkBHYHORUDcjs.fetchIngesterCompat.call(void 0, endpoint, { probeRoutes: routes, unref: false, timeoutMs });
|
|
69
69
|
const issues = [];
|
|
70
70
|
const seen = /* @__PURE__ */ new Set();
|
|
71
71
|
const add = (issue) => {
|
|
@@ -75,15 +75,15 @@ async function runDoctor(options = {}) {
|
|
|
75
75
|
issues.push(issue);
|
|
76
76
|
}
|
|
77
77
|
};
|
|
78
|
-
|
|
78
|
+
_chunkBHYHORUDcjs.evaluateCompat.call(void 0, { features, ingester: info }).forEach(add);
|
|
79
79
|
for (const sdk of sdks) {
|
|
80
80
|
if (_optionalChain([options, 'access', _7 => _7.features, 'optionalAccess', _8 => _8.length])) {
|
|
81
|
-
|
|
81
|
+
_chunkBHYHORUDcjs.evaluateCompat.call(void 0, { features: options.features, ingester: null, sdk }).forEach(add);
|
|
82
82
|
}
|
|
83
83
|
}
|
|
84
84
|
const key = options.key ? await checkKey(endpoint, options.key, timeoutMs) : void 0;
|
|
85
85
|
const featureRows = features.flatMap((id) => {
|
|
86
|
-
const feature =
|
|
86
|
+
const feature = _chunkBHYHORUDcjs.COMPAT_MANIFEST.features.find((f) => f.id === id);
|
|
87
87
|
if (!feature) return [];
|
|
88
88
|
const bad = issues.some((issue) => issue.feature === id);
|
|
89
89
|
const known = _optionalChain([info, 'optionalAccess', _9 => _9.version]) != null || feature.route !== void 0 && _optionalChain([info, 'optionalAccess', _10 => _10.routes, 'optionalAccess', _11 => _11[feature.route]]) !== void 0;
|
|
@@ -153,7 +153,7 @@ Checks that your Autter SDKs, ingester and ClickHouse schema versions match.
|
|
|
153
153
|
Options:
|
|
154
154
|
--endpoint <url> Ingester base URL (default: $AUTTER_ENDPOINT, $OTEL_EXPORTER_OTLP_ENDPOINT, or ${DEFAULT_ENDPOINT})
|
|
155
155
|
--key <key> Also verify an ingest key (default: $AUTTER_RUNTIME_KEY)
|
|
156
|
-
--features <a,b> Only check these features (${
|
|
156
|
+
--features <a,b> Only check these features (${_chunkBHYHORUDcjs.COMPAT_MANIFEST.features.map((f) => f.id).join(", ")})
|
|
157
157
|
--json Machine-readable output
|
|
158
158
|
--timeout <ms> Per-request timeout (default 5000)
|
|
159
159
|
|
|
@@ -170,6 +170,43 @@ var compat_manifest_default = {
|
|
|
170
170
|
ingester: "1.9.0",
|
|
171
171
|
migrations: ["0021-occurrence-collapsed-count"],
|
|
172
172
|
sdks: {}
|
|
173
|
+
},
|
|
174
|
+
{
|
|
175
|
+
id: "edge_request_counts",
|
|
176
|
+
title: "Edge requests counted from their request summaries",
|
|
177
|
+
ingester: "1.10.0",
|
|
178
|
+
migrations: [],
|
|
179
|
+
route: "/v1/logs",
|
|
180
|
+
sdks: { "@autter/runtime-edge": "1.3.0" }
|
|
181
|
+
},
|
|
182
|
+
{
|
|
183
|
+
id: "caught_errors",
|
|
184
|
+
title: "Caught errors and deliberate fallbacks recorded as handled occurrences",
|
|
185
|
+
ingester: "1.11.0",
|
|
186
|
+
migrations: [],
|
|
187
|
+
sdks: { "@autter/runtime-node": "1.9.0", "@autter/runtime-edge": "1.4.0", "@autter/runtime-next": "1.9.0", "@autter/runtime-browser": "1.8.0" }
|
|
188
|
+
},
|
|
189
|
+
{
|
|
190
|
+
id: "route_percentiles",
|
|
191
|
+
title: "Per-route p95 and p99 latency in the 1-minute rollups",
|
|
192
|
+
ingester: "1.11.0",
|
|
193
|
+
migrations: ["0022-route-latency-1m"],
|
|
194
|
+
sdks: {}
|
|
195
|
+
},
|
|
196
|
+
{
|
|
197
|
+
id: "server_source_maps",
|
|
198
|
+
title: "Server bundles symbolicated, with source context lines",
|
|
199
|
+
ingester: "1.11.0",
|
|
200
|
+
migrations: [],
|
|
201
|
+
route: "/v1/sourcemaps",
|
|
202
|
+
sdks: { "@autter/runtime-cli": "1.3.0", "@autter/runtime-node": "1.9.0", "@autter/runtime-edge": "1.4.0", "@autter/runtime-next": "1.9.0" }
|
|
203
|
+
},
|
|
204
|
+
{
|
|
205
|
+
id: "cause_fingerprint",
|
|
206
|
+
title: "Wrapped errors grouped with their root cause (cause-v1)",
|
|
207
|
+
ingester: "1.11.0",
|
|
208
|
+
migrations: [],
|
|
209
|
+
sdks: { "@autter/runtime-node": "1.9.0", "@autter/runtime-edge": "1.4.0", "@autter/runtime-next": "1.9.0" }
|
|
173
210
|
}
|
|
174
211
|
]
|
|
175
212
|
};
|
|
@@ -515,7 +552,7 @@ var _https = require('https');
|
|
|
515
552
|
// package.json
|
|
516
553
|
var package_default = {
|
|
517
554
|
name: "@autter/runtime-node",
|
|
518
|
-
version: "1.
|
|
555
|
+
version: "1.9.0",
|
|
519
556
|
description: "Autter Runtime for Node.js: request wide events, coded errors, operation logging, same-origin browser relay and a curated OpenTelemetry server tracker",
|
|
520
557
|
license: "MIT",
|
|
521
558
|
type: "module",
|
|
@@ -560,16 +597,20 @@ var package_default = {
|
|
|
560
597
|
"@opentelemetry/sdk-metrics": "^1.30.1",
|
|
561
598
|
"@opentelemetry/sdk-node": "^0.57.1",
|
|
562
599
|
"@opentelemetry/sdk-trace-base": "^1.30.1",
|
|
563
|
-
"@opentelemetry/semantic-conventions": "^1.28.0"
|
|
600
|
+
"@opentelemetry/semantic-conventions": "^1.28.0",
|
|
601
|
+
"require-in-the-middle": "^7.5.2"
|
|
564
602
|
},
|
|
565
603
|
devDependencies: {
|
|
566
604
|
"@autter/runtime-core": "0.0.0",
|
|
567
605
|
"@types/node": "^22.10.0",
|
|
606
|
+
bunyan: "^1.8.15",
|
|
568
607
|
express: "^4.21.2",
|
|
569
608
|
fastify: "^5.12.5",
|
|
570
609
|
koa: "^3.2.1",
|
|
610
|
+
pino: "^10.4.0",
|
|
571
611
|
tsup: "^8.3.5",
|
|
572
|
-
typescript: "^5.7.0"
|
|
612
|
+
typescript: "^5.7.0",
|
|
613
|
+
winston: "^3.19.0"
|
|
573
614
|
},
|
|
574
615
|
engines: {
|
|
575
616
|
node: ">=20"
|