@autter/runtime-node 1.9.0 → 1.10.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.
@@ -355,7 +355,9 @@ interface OtlpSinkOptions {
355
355
  * OTLP/HTTP JSON export to `${endpoint}/v1/logs`. Bounded exactly like
356
356
  * 1.4.0: 1000 records / 4 MiB buffered, 256 KiB per record, batches of 50
357
357
  * (≤ 512 KiB), 3 attempts within a 10 s deadline, exponential back-off
358
- * on failure, undelivered records reported at shutdown.
358
+ * on failure, undelivered records reported at shutdown. A 429 or 5xx is
359
+ * retried after its Retry-After (else 500 ms, 1 s); any other 4xx is not
360
+ * retried within the flush.
359
361
  */
360
362
  declare function otlpSink(options?: OtlpSinkOptions): RuntimeSink;
361
363
  interface ConsoleSinkOptions {
@@ -355,7 +355,9 @@ interface OtlpSinkOptions {
355
355
  * OTLP/HTTP JSON export to `${endpoint}/v1/logs`. Bounded exactly like
356
356
  * 1.4.0: 1000 records / 4 MiB buffered, 256 KiB per record, batches of 50
357
357
  * (≤ 512 KiB), 3 attempts within a 10 s deadline, exponential back-off
358
- * on failure, undelivered records reported at shutdown.
358
+ * on failure, undelivered records reported at shutdown. A 429 or 5xx is
359
+ * retried after its Retry-After (else 500 ms, 1 s); any other 4xx is not
360
+ * retried within the flush.
359
361
  */
360
362
  declare function otlpSink(options?: OtlpSinkOptions): RuntimeSink;
361
363
  interface ConsoleSinkOptions {
package/dist/testing.cjs CHANGED
@@ -2,22 +2,22 @@
2
2
 
3
3
 
4
4
 
5
- var _chunkYWTIKZSIcjs = require('./chunk-YWTIKZSI.cjs');
6
- require('./chunk-BHYHORUD.cjs');
5
+ var _chunkSTOXJZ7Zcjs = require('./chunk-STOXJZ7Z.cjs');
6
+ require('./chunk-S6WJ5YLP.cjs');
7
7
 
8
8
  // src/testing.ts
9
9
  function captureRuntime() {
10
- const sink = _chunkYWTIKZSIcjs.memorySink.call(void 0, );
11
- const remove = _chunkYWTIKZSIcjs.addRuntimeSink.call(void 0, sink);
10
+ const sink = _chunkSTOXJZ7Zcjs.memorySink.call(void 0, );
11
+ const remove = _chunkSTOXJZ7Zcjs.addRuntimeSink.call(void 0, sink);
12
12
  return {
13
13
  get events() {
14
14
  return [...sink.events];
15
15
  },
16
16
  get operations() {
17
- return sink.events.filter(_chunkYWTIKZSIcjs.isSummary);
17
+ return sink.events.filter(_chunkSTOXJZ7Zcjs.isSummary);
18
18
  },
19
19
  get logs() {
20
- return sink.events.filter((event) => !_chunkYWTIKZSIcjs.isSummary.call(void 0, event));
20
+ return sink.events.filter((event) => !_chunkSTOXJZ7Zcjs.isSummary.call(void 0, event));
21
21
  },
22
22
  get exceptions() {
23
23
  return [...sink.exceptions];
@@ -98,7 +98,7 @@ var OperationExpectation = class {
98
98
  }
99
99
  };
100
100
  function expectOperation(source, name) {
101
- const events = Array.isArray(source) ? source.filter(_chunkYWTIKZSIcjs.isSummary) : source.operations;
101
+ const events = Array.isArray(source) ? source.filter(_chunkSTOXJZ7Zcjs.isSummary) : source.operations;
102
102
  const matches = events.filter((event2) => {
103
103
  const actual = String(_nullishCoalesce(event2.attributes["autter.operation.name"], () => ( "")));
104
104
  return typeof name === "string" ? actual === name : name.test(actual);
@@ -118,4 +118,4 @@ function expectOperation(source, name) {
118
118
 
119
119
 
120
120
 
121
- exports.captureRuntime = captureRuntime; exports.expectOperation = expectOperation; exports.memorySink = _chunkYWTIKZSIcjs.memorySink;
121
+ exports.captureRuntime = captureRuntime; exports.expectOperation = expectOperation; exports.memorySink = _chunkSTOXJZ7Zcjs.memorySink;
@@ -1,5 +1,5 @@
1
- import { R as RuntimeEvent, a as RuntimeOutcome, C as CapturedException } from './sinks-CLtQFPnn.cjs';
2
- export { M as MemorySink, m as memorySink } from './sinks-CLtQFPnn.cjs';
1
+ import { R as RuntimeEvent, a as RuntimeOutcome, C as CapturedException } from './sinks-BfUoE96B.cjs';
2
+ export { M as MemorySink, m as memorySink } from './sinks-BfUoE96B.cjs';
3
3
 
4
4
  /**
5
5
  * Test helpers — `@autter/runtime-node/testing`. No ingester, no network:
package/dist/testing.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { R as RuntimeEvent, a as RuntimeOutcome, C as CapturedException } from './sinks-CLtQFPnn.js';
2
- export { M as MemorySink, m as memorySink } from './sinks-CLtQFPnn.js';
1
+ import { R as RuntimeEvent, a as RuntimeOutcome, C as CapturedException } from './sinks-BfUoE96B.js';
2
+ export { M as MemorySink, m as memorySink } from './sinks-BfUoE96B.js';
3
3
 
4
4
  /**
5
5
  * Test helpers — `@autter/runtime-node/testing`. No ingester, no network:
package/dist/testing.js CHANGED
@@ -2,8 +2,8 @@ import {
2
2
  addRuntimeSink,
3
3
  isSummary,
4
4
  memorySink
5
- } from "./chunk-HHKQ3UCH.js";
6
- import "./chunk-ZKM76SDP.js";
5
+ } from "./chunk-V65UY6LU.js";
6
+ import "./chunk-KWAJIELR.js";
7
7
 
8
8
  // src/testing.ts
9
9
  function captureRuntime() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@autter/runtime-node",
3
- "version": "1.9.0",
3
+ "version": "1.10.0",
4
4
  "description": "Autter Runtime for Node.js: request wide events, coded errors, operation logging, same-origin browser relay and a curated OpenTelemetry server tracker",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -53,6 +53,7 @@
53
53
  "@types/node": "^22.10.0",
54
54
  "bunyan": "^1.8.15",
55
55
  "express": "^4.21.2",
56
+ "express5": "npm:express@^5.3.0",
56
57
  "fastify": "^5.12.5",
57
58
  "koa": "^3.2.1",
58
59
  "pino": "^10.4.0",
@@ -1,202 +0,0 @@
1
- "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
2
-
3
-
4
-
5
-
6
-
7
-
8
- var _chunkBHYHORUDcjs = require('./chunk-BHYHORUD.cjs');
9
-
10
- // src/doctor.ts
11
- var _fs = require('fs');
12
- var _path = require('path');
13
- var SDK_PACKAGES = ["@autter/runtime-node", "@autter/runtime-next", "@autter/runtime-browser"];
14
- var DEFAULT_ENDPOINT = "https://otlp.autter.dev";
15
- function resolveEndpoint(flag, env = process.env) {
16
- return (flag || env.AUTTER_ENDPOINT || env.AUTTER_RUNTIME_ENDPOINT || env.OTEL_EXPORTER_OTLP_ENDPOINT || DEFAULT_ENDPOINT).replace(/\/$/, "");
17
- }
18
- function installedSdks(cwd) {
19
- const found = /* @__PURE__ */ new Map();
20
- for (let dir = cwd; ; dir = _path.dirname.call(void 0, dir)) {
21
- for (const name of SDK_PACKAGES) {
22
- if (found.has(name)) continue;
23
- const file = _path.join.call(void 0, dir, "node_modules", ...name.split("/"), "package.json");
24
- if (!_fs.existsSync.call(void 0, file)) continue;
25
- try {
26
- const version = JSON.parse(_fs.readFileSync.call(void 0, file, "utf8")).version;
27
- if (typeof version === "string") found.set(name, version);
28
- } catch (e) {
29
- }
30
- }
31
- if (_path.dirname.call(void 0, dir) === dir) break;
32
- }
33
- if (!found.has(_chunkBHYHORUDcjs.SDK_IDENTITY.name)) found.set(_chunkBHYHORUDcjs.SDK_IDENTITY.name, _chunkBHYHORUDcjs.SDK_IDENTITY.version);
34
- return [...found].map(([name, version]) => ({ name, version }));
35
- }
36
- function featuresInUse(sdks) {
37
- return _chunkBHYHORUDcjs.COMPAT_MANIFEST.features.filter(
38
- (feature) => sdks.some((sdk) => {
39
- const min = feature.sdks[sdk.name];
40
- return min !== void 0 && _chunkBHYHORUDcjs.versionAtLeast.call(void 0, sdk.version, min) === true;
41
- })
42
- ).map((feature) => feature.id);
43
- }
44
- async function checkKey(endpoint, key, timeoutMs) {
45
- const res = await _chunkBHYHORUDcjs.compatRequest.call(void 0, "POST", `${endpoint}/v1/traces`, {
46
- body: JSON.stringify({ resourceSpans: [] }),
47
- headers: { authorization: `Bearer ${key}` },
48
- unref: false,
49
- timeoutMs
50
- });
51
- if (!res) return "unknown";
52
- if (res.status >= 200 && res.status < 300) return "accepted";
53
- if (res.status === 401) return "rejected";
54
- if (res.status === 403) return "client_key";
55
- if (res.status === 503) return "storage_unavailable";
56
- return "unknown";
57
- }
58
- async function runDoctor(options = {}) {
59
- const endpoint = resolveEndpoint(options.endpoint);
60
- const timeoutMs = _nullishCoalesce(options.timeoutMs, () => ( 5e3));
61
- const sdks = installedSdks(_nullishCoalesce(options.cwd, () => ( process.cwd())));
62
- const features = _optionalChain([options, 'access', _ => _.features, 'optionalAccess', _2 => _2.length]) ? options.features : featuresInUse(sdks);
63
- const routes = [
64
- ...new Set(
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
- )
67
- ];
68
- const { info, error } = await _chunkBHYHORUDcjs.fetchIngesterCompat.call(void 0, endpoint, { probeRoutes: routes, unref: false, timeoutMs });
69
- const issues = [];
70
- const seen = /* @__PURE__ */ new Set();
71
- const add = (issue) => {
72
- const key2 = `${issue.feature}:${issue.kind}:${issue.component}`;
73
- if (!seen.has(key2)) {
74
- seen.add(key2);
75
- issues.push(issue);
76
- }
77
- };
78
- _chunkBHYHORUDcjs.evaluateCompat.call(void 0, { features, ingester: info }).forEach(add);
79
- for (const sdk of sdks) {
80
- if (_optionalChain([options, 'access', _7 => _7.features, 'optionalAccess', _8 => _8.length])) {
81
- _chunkBHYHORUDcjs.evaluateCompat.call(void 0, { features: options.features, ingester: null, sdk }).forEach(add);
82
- }
83
- }
84
- const key = options.key ? await checkKey(endpoint, options.key, timeoutMs) : void 0;
85
- const featureRows = features.flatMap((id) => {
86
- const feature = _chunkBHYHORUDcjs.COMPAT_MANIFEST.features.find((f) => f.id === id);
87
- if (!feature) return [];
88
- const bad = issues.some((issue) => issue.feature === id);
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;
90
- return [{ id, title: feature.title, status: bad ? "incompatible" : known ? "ok" : "unknown" }];
91
- });
92
- const exitCode = !info ? 2 : issues.length || key === "rejected" || key === "client_key" || key === "storage_unavailable" ? 1 : 0;
93
- return {
94
- endpoint,
95
- sdks,
96
- ingester: info,
97
- ...error && !info ? { ingesterError: error } : {},
98
- ...key ? { key } : {},
99
- features: featureRows,
100
- issues,
101
- exitCode
102
- };
103
- }
104
- function formatDoctorReport(report) {
105
- const lines = [];
106
- lines.push(`Autter Runtime doctor`);
107
- lines.push(` endpoint ${report.endpoint}`);
108
- for (const sdk of report.sdks) lines.push(` sdk ${sdk.name}@${sdk.version}`);
109
- if (!report.ingester) {
110
- lines.push(` ingester unreachable or unidentified (${_nullishCoalesce(report.ingesterError, () => ( "unknown error"))})`);
111
- } else if (report.ingester.version) {
112
- lines.push(` ingester @autter/otlp-ingester@${report.ingester.version}`);
113
- const schema = report.ingester.schema;
114
- if (schema) {
115
- lines.push(
116
- ` schema ${schema.status}${schema.applied.length ? ` (level ${schema.applied[schema.applied.length - 1]})` : ""}`
117
- );
118
- }
119
- } else {
120
- lines.push(` ingester 1.4.0 or older (no /v1/compat endpoint; upgrade for a full report)`);
121
- }
122
- if (report.key) {
123
- const text = {
124
- accepted: "accepted",
125
- rejected: "REJECTED (401): check AUTTER_RUNTIME_KEY",
126
- client_key: "is a client/browser key; server SDKs need a server key",
127
- storage_unavailable: "accepted, but the ingester's ClickHouse is unavailable (503)",
128
- unknown: "could not be verified"
129
- }[report.key];
130
- lines.push(` key ${text}`);
131
- }
132
- if (report.features.length) {
133
- lines.push("", "Features");
134
- for (const feature of report.features) {
135
- const mark = feature.status === "ok" ? "ok " : feature.status === "incompatible" ? "FAIL" : "?? ";
136
- lines.push(` ${mark} ${feature.title} (${feature.id})`);
137
- }
138
- }
139
- if (report.issues.length) {
140
- lines.push("", "Problems");
141
- for (const issue of report.issues) lines.push(` - ${issue.message}`);
142
- }
143
- lines.push(
144
- "",
145
- report.exitCode === 0 ? "Compatible." : report.exitCode === 1 ? "Incompatible: see the problems above." : "Could not check the ingester. Pass --endpoint <url> (or set AUTTER_ENDPOINT)."
146
- );
147
- return lines.join("\n");
148
- }
149
- var DOCTOR_USAGE = `Usage: npx @autter/runtime-node doctor [options]
150
-
151
- Checks that your Autter SDKs, ingester and ClickHouse schema versions match.
152
-
153
- Options:
154
- --endpoint <url> Ingester base URL (default: $AUTTER_ENDPOINT, $OTEL_EXPORTER_OTLP_ENDPOINT, or ${DEFAULT_ENDPOINT})
155
- --key <key> Also verify an ingest key (default: $AUTTER_RUNTIME_KEY)
156
- --features <a,b> Only check these features (${_chunkBHYHORUDcjs.COMPAT_MANIFEST.features.map((f) => f.id).join(", ")})
157
- --json Machine-readable output
158
- --timeout <ms> Per-request timeout (default 5000)
159
-
160
- Exit codes: 0 compatible, 1 mismatch or rejected key, 2 ingester unreachable.`;
161
- function parseDoctorArgs(argv, env = process.env) {
162
- const options = {};
163
- for (let i = 0; i < argv.length; i++) {
164
- const arg = argv[i];
165
- const [flag, inline] = arg.includes("=") ? [arg.slice(0, arg.indexOf("=")), arg.slice(arg.indexOf("=") + 1)] : [arg, void 0];
166
- const value = () => _nullishCoalesce(inline, () => ( argv[++i]));
167
- switch (flag) {
168
- case "-h":
169
- case "--help":
170
- return { help: true };
171
- case "--endpoint":
172
- options.endpoint = value();
173
- break;
174
- case "--key":
175
- options.key = value();
176
- break;
177
- case "--features":
178
- options.features = (_nullishCoalesce(value(), () => ( ""))).split(",").map((f) => f.trim()).filter(Boolean);
179
- break;
180
- case "--json":
181
- options.json = true;
182
- break;
183
- case "--timeout": {
184
- const ms = Number(value());
185
- if (!Number.isFinite(ms) || ms <= 0) return { error: "--timeout needs a positive number of ms" };
186
- options.timeoutMs = ms;
187
- break;
188
- }
189
- default:
190
- return { error: `unknown option ${arg}` };
191
- }
192
- }
193
- if (!options.key && env.AUTTER_RUNTIME_KEY) options.key = env.AUTTER_RUNTIME_KEY;
194
- return options;
195
- }
196
-
197
-
198
-
199
-
200
-
201
-
202
- exports.runDoctor = runDoctor; exports.formatDoctorReport = formatDoctorReport; exports.DOCTOR_USAGE = DOCTOR_USAGE; exports.parseDoctorArgs = parseDoctorArgs;
@@ -1,202 +0,0 @@
1
- import {
2
- COMPAT_MANIFEST,
3
- SDK_IDENTITY,
4
- compatRequest,
5
- evaluateCompat,
6
- fetchIngesterCompat,
7
- versionAtLeast
8
- } from "./chunk-ZKM76SDP.js";
9
-
10
- // src/doctor.ts
11
- import { existsSync, readFileSync } from "fs";
12
- import { dirname, join } from "path";
13
- var SDK_PACKAGES = ["@autter/runtime-node", "@autter/runtime-next", "@autter/runtime-browser"];
14
- var DEFAULT_ENDPOINT = "https://otlp.autter.dev";
15
- function resolveEndpoint(flag, env = process.env) {
16
- return (flag || env.AUTTER_ENDPOINT || env.AUTTER_RUNTIME_ENDPOINT || env.OTEL_EXPORTER_OTLP_ENDPOINT || DEFAULT_ENDPOINT).replace(/\/$/, "");
17
- }
18
- function installedSdks(cwd) {
19
- const found = /* @__PURE__ */ new Map();
20
- for (let dir = cwd; ; dir = dirname(dir)) {
21
- for (const name of SDK_PACKAGES) {
22
- if (found.has(name)) continue;
23
- const file = join(dir, "node_modules", ...name.split("/"), "package.json");
24
- if (!existsSync(file)) continue;
25
- try {
26
- const version = JSON.parse(readFileSync(file, "utf8")).version;
27
- if (typeof version === "string") found.set(name, version);
28
- } catch {
29
- }
30
- }
31
- if (dirname(dir) === dir) break;
32
- }
33
- if (!found.has(SDK_IDENTITY.name)) found.set(SDK_IDENTITY.name, SDK_IDENTITY.version);
34
- return [...found].map(([name, version]) => ({ name, version }));
35
- }
36
- function featuresInUse(sdks) {
37
- return COMPAT_MANIFEST.features.filter(
38
- (feature) => sdks.some((sdk) => {
39
- const min = feature.sdks[sdk.name];
40
- return min !== void 0 && versionAtLeast(sdk.version, min) === true;
41
- })
42
- ).map((feature) => feature.id);
43
- }
44
- async function checkKey(endpoint, key, timeoutMs) {
45
- const res = await compatRequest("POST", `${endpoint}/v1/traces`, {
46
- body: JSON.stringify({ resourceSpans: [] }),
47
- headers: { authorization: `Bearer ${key}` },
48
- unref: false,
49
- timeoutMs
50
- });
51
- if (!res) return "unknown";
52
- if (res.status >= 200 && res.status < 300) return "accepted";
53
- if (res.status === 401) return "rejected";
54
- if (res.status === 403) return "client_key";
55
- if (res.status === 503) return "storage_unavailable";
56
- return "unknown";
57
- }
58
- async function runDoctor(options = {}) {
59
- const endpoint = resolveEndpoint(options.endpoint);
60
- const timeoutMs = options.timeoutMs ?? 5e3;
61
- const sdks = installedSdks(options.cwd ?? process.cwd());
62
- const features = options.features?.length ? options.features : featuresInUse(sdks);
63
- const routes = [
64
- ...new Set(
65
- features.map((id) => COMPAT_MANIFEST.features.find((f) => f.id === id)?.route).filter((route) => Boolean(route))
66
- )
67
- ];
68
- const { info, error } = await fetchIngesterCompat(endpoint, { probeRoutes: routes, unref: false, timeoutMs });
69
- const issues = [];
70
- const seen = /* @__PURE__ */ new Set();
71
- const add = (issue) => {
72
- const key2 = `${issue.feature}:${issue.kind}:${issue.component}`;
73
- if (!seen.has(key2)) {
74
- seen.add(key2);
75
- issues.push(issue);
76
- }
77
- };
78
- evaluateCompat({ features, ingester: info }).forEach(add);
79
- for (const sdk of sdks) {
80
- if (options.features?.length) {
81
- evaluateCompat({ features: options.features, ingester: null, sdk }).forEach(add);
82
- }
83
- }
84
- const key = options.key ? await checkKey(endpoint, options.key, timeoutMs) : void 0;
85
- const featureRows = features.flatMap((id) => {
86
- const feature = COMPAT_MANIFEST.features.find((f) => f.id === id);
87
- if (!feature) return [];
88
- const bad = issues.some((issue) => issue.feature === id);
89
- const known = info?.version != null || feature.route !== void 0 && info?.routes?.[feature.route] !== void 0;
90
- return [{ id, title: feature.title, status: bad ? "incompatible" : known ? "ok" : "unknown" }];
91
- });
92
- const exitCode = !info ? 2 : issues.length || key === "rejected" || key === "client_key" || key === "storage_unavailable" ? 1 : 0;
93
- return {
94
- endpoint,
95
- sdks,
96
- ingester: info,
97
- ...error && !info ? { ingesterError: error } : {},
98
- ...key ? { key } : {},
99
- features: featureRows,
100
- issues,
101
- exitCode
102
- };
103
- }
104
- function formatDoctorReport(report) {
105
- const lines = [];
106
- lines.push(`Autter Runtime doctor`);
107
- lines.push(` endpoint ${report.endpoint}`);
108
- for (const sdk of report.sdks) lines.push(` sdk ${sdk.name}@${sdk.version}`);
109
- if (!report.ingester) {
110
- lines.push(` ingester unreachable or unidentified (${report.ingesterError ?? "unknown error"})`);
111
- } else if (report.ingester.version) {
112
- lines.push(` ingester @autter/otlp-ingester@${report.ingester.version}`);
113
- const schema = report.ingester.schema;
114
- if (schema) {
115
- lines.push(
116
- ` schema ${schema.status}${schema.applied.length ? ` (level ${schema.applied[schema.applied.length - 1]})` : ""}`
117
- );
118
- }
119
- } else {
120
- lines.push(` ingester 1.4.0 or older (no /v1/compat endpoint; upgrade for a full report)`);
121
- }
122
- if (report.key) {
123
- const text = {
124
- accepted: "accepted",
125
- rejected: "REJECTED (401): check AUTTER_RUNTIME_KEY",
126
- client_key: "is a client/browser key; server SDKs need a server key",
127
- storage_unavailable: "accepted, but the ingester's ClickHouse is unavailable (503)",
128
- unknown: "could not be verified"
129
- }[report.key];
130
- lines.push(` key ${text}`);
131
- }
132
- if (report.features.length) {
133
- lines.push("", "Features");
134
- for (const feature of report.features) {
135
- const mark = feature.status === "ok" ? "ok " : feature.status === "incompatible" ? "FAIL" : "?? ";
136
- lines.push(` ${mark} ${feature.title} (${feature.id})`);
137
- }
138
- }
139
- if (report.issues.length) {
140
- lines.push("", "Problems");
141
- for (const issue of report.issues) lines.push(` - ${issue.message}`);
142
- }
143
- lines.push(
144
- "",
145
- report.exitCode === 0 ? "Compatible." : report.exitCode === 1 ? "Incompatible: see the problems above." : "Could not check the ingester. Pass --endpoint <url> (or set AUTTER_ENDPOINT)."
146
- );
147
- return lines.join("\n");
148
- }
149
- var DOCTOR_USAGE = `Usage: npx @autter/runtime-node doctor [options]
150
-
151
- Checks that your Autter SDKs, ingester and ClickHouse schema versions match.
152
-
153
- Options:
154
- --endpoint <url> Ingester base URL (default: $AUTTER_ENDPOINT, $OTEL_EXPORTER_OTLP_ENDPOINT, or ${DEFAULT_ENDPOINT})
155
- --key <key> Also verify an ingest key (default: $AUTTER_RUNTIME_KEY)
156
- --features <a,b> Only check these features (${COMPAT_MANIFEST.features.map((f) => f.id).join(", ")})
157
- --json Machine-readable output
158
- --timeout <ms> Per-request timeout (default 5000)
159
-
160
- Exit codes: 0 compatible, 1 mismatch or rejected key, 2 ingester unreachable.`;
161
- function parseDoctorArgs(argv, env = process.env) {
162
- const options = {};
163
- for (let i = 0; i < argv.length; i++) {
164
- const arg = argv[i];
165
- const [flag, inline] = arg.includes("=") ? [arg.slice(0, arg.indexOf("=")), arg.slice(arg.indexOf("=") + 1)] : [arg, void 0];
166
- const value = () => inline ?? argv[++i];
167
- switch (flag) {
168
- case "-h":
169
- case "--help":
170
- return { help: true };
171
- case "--endpoint":
172
- options.endpoint = value();
173
- break;
174
- case "--key":
175
- options.key = value();
176
- break;
177
- case "--features":
178
- options.features = (value() ?? "").split(",").map((f) => f.trim()).filter(Boolean);
179
- break;
180
- case "--json":
181
- options.json = true;
182
- break;
183
- case "--timeout": {
184
- const ms = Number(value());
185
- if (!Number.isFinite(ms) || ms <= 0) return { error: "--timeout needs a positive number of ms" };
186
- options.timeoutMs = ms;
187
- break;
188
- }
189
- default:
190
- return { error: `unknown option ${arg}` };
191
- }
192
- }
193
- if (!options.key && env.AUTTER_RUNTIME_KEY) options.key = env.AUTTER_RUNTIME_KEY;
194
- return options;
195
- }
196
-
197
- export {
198
- runDoctor,
199
- formatDoctorReport,
200
- DOCTOR_USAGE,
201
- parseDoctorArgs
202
- };