@astroscope/node 2.1.1 → 3.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.
Files changed (65) hide show
  1. package/README.md +8 -5
  2. package/dist/boot.d.ts +2 -2
  3. package/dist/boot.d.ts.map +1 -1
  4. package/dist/csrf-middleware-entrypoint.d.ts +1 -2
  5. package/dist/csrf-middleware-entrypoint.d.ts.map +1 -1
  6. package/dist/csrf-middleware-entrypoint.js +1 -1
  7. package/dist/dev-middleware-entrypoint.d.ts +1 -2
  8. package/dist/dev-middleware-entrypoint.d.ts.map +1 -1
  9. package/dist/{prepare-CXZsyAVk.js → duplicate-slashes-C6hmOLl9.js} +94 -38
  10. package/dist/duplicate-slashes-C6hmOLl9.js.map +1 -0
  11. package/dist/{excludes-pE23EbmQ.js → excludes-10eDopVB.js} +18 -4
  12. package/dist/excludes-10eDopVB.js.map +1 -0
  13. package/dist/{excludes-BDiE3eyp.d.ts → excludes-rvkVGg6B.d.ts} +11 -3
  14. package/dist/excludes-rvkVGg6B.d.ts.map +1 -0
  15. package/dist/excludes.d.ts +2 -2
  16. package/dist/excludes.js +2 -2
  17. package/dist/graph-DdAxiaxa.js +35 -0
  18. package/dist/graph-DdAxiaxa.js.map +1 -0
  19. package/dist/health.d.ts +3 -4
  20. package/dist/health.d.ts.map +1 -1
  21. package/dist/image-endpoint.d.ts +1 -2
  22. package/dist/image-endpoint.d.ts.map +1 -1
  23. package/dist/index.d.ts +3 -3
  24. package/dist/index.d.ts.map +1 -1
  25. package/dist/index.js +38 -117
  26. package/dist/index.js.map +1 -1
  27. package/dist/islands-middleware-entrypoint.d.ts +1 -2
  28. package/dist/islands-middleware-entrypoint.d.ts.map +1 -1
  29. package/dist/islands-middleware-entrypoint.js +3 -1
  30. package/dist/islands-middleware-entrypoint.js.map +1 -1
  31. package/dist/islands.d.ts +56 -1
  32. package/dist/islands.d.ts.map +1 -0
  33. package/dist/islands.js +3 -1
  34. package/dist/log/index.d.ts +5 -5
  35. package/dist/log/index.d.ts.map +1 -1
  36. package/dist/native.d.ts +5 -6
  37. package/dist/native.d.ts.map +1 -1
  38. package/dist/{prerendered-DVjzWNbW.js → prerendered-Z-Qi-FFK.js} +4 -4
  39. package/dist/prerendered-Z-Qi-FFK.js.map +1 -0
  40. package/dist/request-route-DcnZOOM4.js.map +1 -1
  41. package/dist/route-islands-B53rE5MH.js +73 -0
  42. package/dist/route-islands-B53rE5MH.js.map +1 -0
  43. package/dist/route-middleware-entrypoint.d.ts +1 -2
  44. package/dist/route-middleware-entrypoint.d.ts.map +1 -1
  45. package/dist/route-store-neUA2nBb.d.ts.map +1 -1
  46. package/dist/routes-D1o_WrJ5.js +39 -0
  47. package/dist/routes-D1o_WrJ5.js.map +1 -0
  48. package/dist/server.d.ts +2 -3
  49. package/dist/server.d.ts.map +1 -1
  50. package/dist/server.js +68 -45
  51. package/dist/server.js.map +1 -1
  52. package/dist/telemetry-B9aziFyQ.js +202 -0
  53. package/dist/telemetry-B9aziFyQ.js.map +1 -0
  54. package/dist/telemetry.d.ts +68 -0
  55. package/dist/telemetry.d.ts.map +1 -0
  56. package/dist/telemetry.js +2 -0
  57. package/dist/transform-Bz5z5w2Y.js +594 -0
  58. package/dist/transform-Bz5z5w2Y.js.map +1 -0
  59. package/package.json +13 -11
  60. package/dist/excludes-BDiE3eyp.d.ts.map +0 -1
  61. package/dist/excludes-pE23EbmQ.js.map +0 -1
  62. package/dist/prepare-CXZsyAVk.js.map +0 -1
  63. package/dist/prerendered-DVjzWNbW.js.map +0 -1
  64. package/dist/transform-BqV8SOEm.js +0 -195
  65. package/dist/transform-BqV8SOEm.js.map +0 -1
@@ -0,0 +1,202 @@
1
+ import { maybeThen } from "@entwico/dash";
2
+ import { SpanStatusCode, ValueType, context, createNoopMeter, metrics, trace } from "@opentelemetry/api";
3
+ //#region src/observability/telemetry/gauges.ts
4
+ /**
5
+ * Gauges have no "first use" to bind on: their callback must be registered on
6
+ * a real meter, and a meter obtained before the SDK started is a no-op
7
+ * forever. A creation that lands on the no-op meter is parked here and retried
8
+ * by the SDK right after `sdk.start()`. Keyed on `globalThis` so the
9
+ * vite-runner and native module instances share one list.
10
+ */
11
+ const STORE_KEY = Symbol.for("@astroscope/node/telemetry.gauges");
12
+ function getPending() {
13
+ const g = globalThis;
14
+ let pending = g[STORE_KEY];
15
+ if (!pending) {
16
+ pending = [];
17
+ g[STORE_KEY] = pending;
18
+ }
19
+ return pending;
20
+ }
21
+ function registerGauge(bind) {
22
+ if (!bind()) getPending().push(bind);
23
+ }
24
+ function bindGauges() {
25
+ const pending = getPending();
26
+ for (const bind of pending.splice(0)) if (!bind()) pending.push(bind);
27
+ }
28
+ //#endregion
29
+ //#region src/observability/telemetry/telemetry.ts
30
+ /**
31
+ * The telemetry seam for the astroscope packages — internal api, not for app
32
+ * code (which uses `@opentelemetry/api` against the same SDK). Instruments
33
+ * bind to the SDK meter lazily (a meter obtained before `startTelemetry()` is
34
+ * a no-op forever, so a handle keeps trying until a real meter answers),
35
+ * names, units and buckets have one owner, and no package needs its own
36
+ * `@opentelemetry/api` copy. Without a started SDK — dev by default, or
37
+ * `telemetry: false` — every call resolves to the api's no-op implementation.
38
+ * @internal
39
+ */
40
+ const DEFAULT_SCOPE = "@astroscope/node";
41
+ const noopMeter = createNoopMeter();
42
+ const NOOP_HISTOGRAM = noopMeter.createHistogram("noop");
43
+ const NOOP_COUNTER = noopMeter.createCounter("noop");
44
+ const NOOP_UP_DOWN_COUNTER = noopMeter.createUpDownCounter("noop");
45
+ const NOOP_OBSERVABLE_GAUGE = noopMeter.createObservableGauge("noop");
46
+ /**
47
+ * Bucket boundaries in seconds for the three kinds of durations the platform
48
+ * measures: `http` is the semconv set for server requests, `io` covers one
49
+ * outbound call (1 ms – 2.5 s), `compute` a synchronous render (10 µs – 50 ms).
50
+ */
51
+ const DURATION_BUCKETS = {
52
+ http: [
53
+ .005,
54
+ .01,
55
+ .025,
56
+ .05,
57
+ .075,
58
+ .1,
59
+ .25,
60
+ .5,
61
+ .75,
62
+ 1,
63
+ 2.5,
64
+ 5,
65
+ 7.5,
66
+ 10
67
+ ],
68
+ io: [
69
+ .001,
70
+ .0025,
71
+ .005,
72
+ .01,
73
+ .025,
74
+ .05,
75
+ .1,
76
+ .25,
77
+ .5,
78
+ 1,
79
+ 2.5
80
+ ],
81
+ compute: [
82
+ 1e-5,
83
+ 5e-5,
84
+ 1e-4,
85
+ 25e-5,
86
+ 5e-4,
87
+ .001,
88
+ .0025,
89
+ .005,
90
+ .01,
91
+ .05
92
+ ]
93
+ };
94
+ function getMeter(options) {
95
+ return metrics.getMeter(options.scope ?? DEFAULT_SCOPE);
96
+ }
97
+ function describe(options) {
98
+ return {
99
+ ...options.description && { description: options.description },
100
+ ...options.unit && { unit: options.unit }
101
+ };
102
+ }
103
+ function bindLazily(create, noop) {
104
+ let instrument;
105
+ return () => {
106
+ if (instrument === void 0) {
107
+ const created = create();
108
+ if (created === noop) return;
109
+ instrument = created;
110
+ }
111
+ return instrument;
112
+ };
113
+ }
114
+ function createHistogram(name, options) {
115
+ const bound = bindLazily(() => getMeter(options).createHistogram(name, {
116
+ ...describe(options),
117
+ valueType: ValueType.DOUBLE,
118
+ advice: { explicitBucketBoundaries: [...options.buckets] }
119
+ }), NOOP_HISTOGRAM);
120
+ return { record: (value, attributes) => bound()?.record(value, attributes) };
121
+ }
122
+ function createCounter(name, options = {}) {
123
+ const bound = bindLazily(() => getMeter(options).createCounter(name, {
124
+ ...describe(options),
125
+ valueType: ValueType.INT
126
+ }), NOOP_COUNTER);
127
+ return { add: (value, attributes) => bound()?.add(value, attributes) };
128
+ }
129
+ function createUpDownCounter(name, options = {}) {
130
+ const bound = bindLazily(() => getMeter(options).createUpDownCounter(name, {
131
+ ...describe(options),
132
+ valueType: ValueType.INT
133
+ }), NOOP_UP_DOWN_COUNTER);
134
+ return { add: (value, attributes) => bound()?.add(value, attributes) };
135
+ }
136
+ /**
137
+ * An asynchronous gauge: `observe` runs at every collection (the Prometheus
138
+ * scrape) and reports the current values. Registered with the SDK when it
139
+ * starts, so calling this at module level is fine.
140
+ */
141
+ function createObservableGauge(name, options, observe) {
142
+ registerGauge(() => {
143
+ const gauge = getMeter(options).createObservableGauge(name, {
144
+ ...describe(options),
145
+ valueType: ValueType.DOUBLE
146
+ });
147
+ if (gauge === NOOP_OBSERVABLE_GAUGE) return false;
148
+ gauge.addCallback((result) => observe({ observe: (value, attributes) => result.observe(value, attributes) }));
149
+ return true;
150
+ });
151
+ }
152
+ /** the `error.type` attribute value for a thrown value: the error's class, else its type */
153
+ function errorType(error) {
154
+ if (error instanceof Error) return error.constructor.name || error.name || "Error";
155
+ return typeof error;
156
+ }
157
+ /** starts a span the caller ends itself; `withSpan` for work that is one function */
158
+ function startSpan(name, options = {}) {
159
+ const parent = options.parent ?? context.active();
160
+ const span = trace.getTracer(options.scope ?? DEFAULT_SCOPE).startSpan(name, {
161
+ ...options.attributes && { attributes: options.attributes },
162
+ ...options.kind !== void 0 && { kind: options.kind }
163
+ }, parent);
164
+ return {
165
+ span,
166
+ context: trace.setSpan(parent, span)
167
+ };
168
+ }
169
+ function endSpan(span, error, failed) {
170
+ if (failed) span.setStatus({
171
+ code: SpanStatusCode.ERROR,
172
+ message: error instanceof Error ? error.message : "unknown error"
173
+ });
174
+ else span.setStatus({ code: SpanStatusCode.OK });
175
+ span.end();
176
+ }
177
+ /**
178
+ * Runs `fn` inside a span: status from the outcome, the span active for
179
+ * everything `fn` awaits. A synchronous `fn` stays synchronous — no promise
180
+ * is allocated on the common path.
181
+ */
182
+ function withSpan(name, options, fn) {
183
+ const { span, context: spanContext } = startSpan(name, options);
184
+ let result;
185
+ try {
186
+ result = context.with(spanContext, fn);
187
+ } catch (error) {
188
+ endSpan(span, error, true);
189
+ throw error;
190
+ }
191
+ return maybeThen(result, (value) => {
192
+ endSpan(span, void 0, false);
193
+ return value;
194
+ }, (error) => {
195
+ endSpan(span, error, true);
196
+ throw error;
197
+ });
198
+ }
199
+ //#endregion
200
+ export { createUpDownCounter as a, withSpan as c, createObservableGauge as i, bindGauges as l, createCounter as n, errorType as o, createHistogram as r, startSpan as s, DURATION_BUCKETS as t };
201
+
202
+ //# sourceMappingURL=telemetry-B9aziFyQ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"telemetry-B9aziFyQ.js","names":[],"sources":["../src/observability/telemetry/gauges.ts","../src/observability/telemetry/telemetry.ts"],"sourcesContent":["/**\n * Gauges have no \"first use\" to bind on: their callback must be registered on\n * a real meter, and a meter obtained before the SDK started is a no-op\n * forever. A creation that lands on the no-op meter is parked here and retried\n * by the SDK right after `sdk.start()`. Keyed on `globalThis` so the\n * vite-runner and native module instances share one list.\n */\n\nconst STORE_KEY = Symbol.for('@astroscope/node/telemetry.gauges');\n\n/** returns whether the instrument bound to a real meter */\ntype Bind = () => boolean;\n\nfunction getPending(): Bind[] {\n const g = globalThis as Record<symbol, unknown>;\n let pending = g[STORE_KEY] as Bind[] | undefined;\n\n if (!pending) {\n pending = [];\n g[STORE_KEY] = pending;\n }\n\n return pending;\n}\n\nexport function registerGauge(bind: Bind): void {\n if (!bind()) {\n getPending().push(bind);\n }\n}\n\nexport function bindGauges(): void {\n const pending = getPending();\n\n for (const bind of pending.splice(0)) {\n if (!bind()) {\n pending.push(bind);\n }\n }\n}\n","import { type MaybePromise, maybeThen } from '@entwico/dash';\nimport {\n type Attributes,\n type Context,\n type Counter,\n type Histogram,\n type Meter,\n type Span,\n type SpanKind,\n SpanStatusCode,\n type UpDownCounter,\n ValueType,\n context,\n createNoopMeter,\n metrics,\n trace,\n} from '@opentelemetry/api';\nimport { registerGauge } from './gauges.js';\n\n/**\n * The telemetry seam for the astroscope packages — internal api, not for app\n * code (which uses `@opentelemetry/api` against the same SDK). Instruments\n * bind to the SDK meter lazily (a meter obtained before `startTelemetry()` is\n * a no-op forever, so a handle keeps trying until a real meter answers),\n * names, units and buckets have one owner, and no package needs its own\n * `@opentelemetry/api` copy. Without a started SDK — dev by default, or\n * `telemetry: false` — every call resolves to the api's no-op implementation.\n * @internal\n */\n\nconst DEFAULT_SCOPE = '@astroscope/node';\n\n// the no-op meter hands out singletons — the tell for \"no SDK registered yet\"\nconst noopMeter = createNoopMeter();\nconst NOOP_HISTOGRAM = noopMeter.createHistogram('noop');\nconst NOOP_COUNTER = noopMeter.createCounter('noop');\nconst NOOP_UP_DOWN_COUNTER = noopMeter.createUpDownCounter('noop');\nconst NOOP_OBSERVABLE_GAUGE = noopMeter.createObservableGauge('noop');\n\nexport interface InstrumentOptions {\n /** instrumentation scope, `@astroscope/<package>`; defaults to `@astroscope/node` */\n scope?: string | undefined;\n description?: string | undefined;\n /** UCUM unit, e.g. `s`, `{request}` */\n unit?: string | undefined;\n}\n\nexport interface HistogramOptions extends InstrumentOptions {\n /** explicit bucket boundaries; the SDK default set starts at 5, useless for seconds */\n buckets: readonly number[];\n}\n\nexport interface HistogramHandle {\n record(value: number, attributes?: Attributes | undefined): void;\n}\n\nexport interface CounterHandle {\n add(value: number, attributes?: Attributes | undefined): void;\n}\n\n/** what an observable gauge callback reports: one value per attribute set */\nexport interface ObservableHandle {\n observe(value: number, attributes?: Attributes | undefined): void;\n}\n\n/**\n * Bucket boundaries in seconds for the three kinds of durations the platform\n * measures: `http` is the semconv set for server requests, `io` covers one\n * outbound call (1 ms – 2.5 s), `compute` a synchronous render (10 µs – 50 ms).\n */\nexport const DURATION_BUCKETS = {\n http: [0.005, 0.01, 0.025, 0.05, 0.075, 0.1, 0.25, 0.5, 0.75, 1, 2.5, 5, 7.5, 10],\n io: [0.001, 0.0025, 0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5],\n compute: [0.00001, 0.00005, 0.0001, 0.00025, 0.0005, 0.001, 0.0025, 0.005, 0.01, 0.05],\n} as const satisfies Record<string, readonly number[]>;\n\nfunction getMeter(options: InstrumentOptions): Meter {\n return metrics.getMeter(options.scope ?? DEFAULT_SCOPE);\n}\n\nfunction describe(options: InstrumentOptions): { description?: string; unit?: string } {\n return {\n ...(options.description && { description: options.description }),\n ...(options.unit && { unit: options.unit }),\n };\n}\n\n// binds on first use after a real meter is registered; until then every use\n// creates a no-op instrument and drops the value\nfunction bindLazily<T>(create: () => T, noop: T): () => T | undefined {\n let instrument: T | undefined;\n\n return () => {\n if (instrument === undefined) {\n const created = create();\n\n if (created === noop) {\n return undefined;\n }\n\n instrument = created;\n }\n\n return instrument;\n };\n}\n\nexport function createHistogram(name: string, options: HistogramOptions): HistogramHandle {\n const bound = bindLazily<Histogram>(\n () =>\n getMeter(options).createHistogram(name, {\n ...describe(options),\n valueType: ValueType.DOUBLE,\n advice: { explicitBucketBoundaries: [...options.buckets] },\n }),\n NOOP_HISTOGRAM,\n );\n\n return { record: (value, attributes) => bound()?.record(value, attributes) };\n}\n\nexport function createCounter(name: string, options: InstrumentOptions = {}): CounterHandle {\n const bound = bindLazily<Counter>(\n () => getMeter(options).createCounter(name, { ...describe(options), valueType: ValueType.INT }),\n NOOP_COUNTER,\n );\n\n return { add: (value, attributes) => bound()?.add(value, attributes) };\n}\n\nexport function createUpDownCounter(name: string, options: InstrumentOptions = {}): CounterHandle {\n const bound = bindLazily<UpDownCounter>(\n () => getMeter(options).createUpDownCounter(name, { ...describe(options), valueType: ValueType.INT }),\n NOOP_UP_DOWN_COUNTER,\n );\n\n return { add: (value, attributes) => bound()?.add(value, attributes) };\n}\n\n/**\n * An asynchronous gauge: `observe` runs at every collection (the Prometheus\n * scrape) and reports the current values. Registered with the SDK when it\n * starts, so calling this at module level is fine.\n */\nexport function createObservableGauge(\n name: string,\n options: InstrumentOptions,\n observe: (result: ObservableHandle) => void,\n): void {\n registerGauge(() => {\n const gauge = getMeter(options).createObservableGauge(name, { ...describe(options), valueType: ValueType.DOUBLE });\n\n if (gauge === NOOP_OBSERVABLE_GAUGE) {\n return false;\n }\n\n gauge.addCallback((result) => observe({ observe: (value, attributes) => result.observe(value, attributes) }));\n\n return true;\n });\n}\n\n/** the `error.type` attribute value for a thrown value: the error's class, else its type */\nexport function errorType(error: unknown): string {\n if (error instanceof Error) {\n return error.constructor.name || error.name || 'Error';\n }\n\n return typeof error;\n}\n\nexport interface SpanOptions {\n /** instrumentation scope, `@astroscope/<package>`; defaults to `@astroscope/node` */\n scope?: string | undefined;\n attributes?: Attributes | undefined;\n kind?: SpanKind | undefined;\n /** parent context; defaults to the active one (the request span inside a request) */\n parent?: Context | undefined;\n}\n\nexport interface StartedSpan {\n span: Span;\n /** the context with `span` active — pass as `parent` to nest children */\n context: Context;\n}\n\n/** starts a span the caller ends itself; `withSpan` for work that is one function */\nexport function startSpan(name: string, options: SpanOptions = {}): StartedSpan {\n const parent = options.parent ?? context.active();\n const span = trace.getTracer(options.scope ?? DEFAULT_SCOPE).startSpan(\n name,\n {\n ...(options.attributes && { attributes: options.attributes }),\n ...(options.kind !== undefined && { kind: options.kind }),\n },\n parent,\n );\n\n return { span, context: trace.setSpan(parent, span) };\n}\n\nfunction endSpan(span: Span, error: unknown, failed: boolean): void {\n if (failed) {\n span.setStatus({ code: SpanStatusCode.ERROR, message: error instanceof Error ? error.message : 'unknown error' });\n } else {\n span.setStatus({ code: SpanStatusCode.OK });\n }\n\n span.end();\n}\n\n/**\n * Runs `fn` inside a span: status from the outcome, the span active for\n * everything `fn` awaits. A synchronous `fn` stays synchronous — no promise\n * is allocated on the common path.\n */\nexport function withSpan<T>(name: string, options: SpanOptions, fn: () => MaybePromise<T>): MaybePromise<T> {\n const { span, context: spanContext } = startSpan(name, options);\n let result: MaybePromise<T>;\n\n try {\n result = context.with(spanContext, fn);\n } catch (error) {\n endSpan(span, error, true);\n\n throw error;\n }\n\n return maybeThen(\n result,\n (value) => {\n endSpan(span, undefined, false);\n\n return value;\n },\n (error: unknown) => {\n endSpan(span, error, true);\n\n throw error;\n },\n );\n}\n"],"mappings":"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"}
@@ -0,0 +1,68 @@
1
+ import { MaybePromise } from "@entwico/dash";
2
+ import { Attributes, Context, Span, SpanKind } from "@opentelemetry/api";
3
+ //#region src/observability/telemetry/telemetry.d.ts
4
+ export interface InstrumentOptions {
5
+ /** instrumentation scope, `@astroscope/<package>`; defaults to `@astroscope/node` */
6
+ scope?: string | undefined;
7
+ description?: string | undefined;
8
+ /** UCUM unit, e.g. `s`, `{request}` */
9
+ unit?: string | undefined;
10
+ }
11
+ export interface HistogramOptions extends InstrumentOptions {
12
+ /** explicit bucket boundaries; the SDK default set starts at 5, useless for seconds */
13
+ buckets: readonly number[];
14
+ }
15
+ export interface HistogramHandle {
16
+ record(value: number, attributes?: Attributes | undefined): void;
17
+ }
18
+ export interface CounterHandle {
19
+ add(value: number, attributes?: Attributes | undefined): void;
20
+ }
21
+ /** what an observable gauge callback reports: one value per attribute set */
22
+ export interface ObservableHandle {
23
+ observe(value: number, attributes?: Attributes | undefined): void;
24
+ }
25
+ /**
26
+ * Bucket boundaries in seconds for the three kinds of durations the platform
27
+ * measures: `http` is the semconv set for server requests, `io` covers one
28
+ * outbound call (1 ms – 2.5 s), `compute` a synchronous render (10 µs – 50 ms).
29
+ */
30
+ export declare const DURATION_BUCKETS: {
31
+ readonly http: readonly [0.005, 0.01, 0.025, 0.05, 0.075, 0.1, 0.25, 0.5, 0.75, 1, 2.5, 5, 7.5, 10];
32
+ readonly io: readonly [0.001, 0.0025, 0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5];
33
+ readonly compute: readonly [0.00001, 0.00005, 0.0001, 0.00025, 0.0005, 0.001, 0.0025, 0.005, 0.01, 0.05];
34
+ };
35
+ export declare function createHistogram(name: string, options: HistogramOptions): HistogramHandle;
36
+ export declare function createCounter(name: string, options?: InstrumentOptions): CounterHandle;
37
+ export declare function createUpDownCounter(name: string, options?: InstrumentOptions): CounterHandle;
38
+ /**
39
+ * An asynchronous gauge: `observe` runs at every collection (the Prometheus
40
+ * scrape) and reports the current values. Registered with the SDK when it
41
+ * starts, so calling this at module level is fine.
42
+ */
43
+ export declare function createObservableGauge(name: string, options: InstrumentOptions, observe: (result: ObservableHandle) => void): void;
44
+ /** the `error.type` attribute value for a thrown value: the error's class, else its type */
45
+ export declare function errorType(error: unknown): string;
46
+ export interface SpanOptions {
47
+ /** instrumentation scope, `@astroscope/<package>`; defaults to `@astroscope/node` */
48
+ scope?: string | undefined;
49
+ attributes?: Attributes | undefined;
50
+ kind?: SpanKind | undefined;
51
+ /** parent context; defaults to the active one (the request span inside a request) */
52
+ parent?: Context | undefined;
53
+ }
54
+ export interface StartedSpan {
55
+ span: Span;
56
+ /** the context with `span` active — pass as `parent` to nest children */
57
+ context: Context;
58
+ }
59
+ /** starts a span the caller ends itself; `withSpan` for work that is one function */
60
+ export declare function startSpan(name: string, options?: SpanOptions): StartedSpan;
61
+ /**
62
+ * Runs `fn` inside a span: status from the outcome, the span active for
63
+ * everything `fn` awaits. A synchronous `fn` stays synchronous — no promise
64
+ * is allocated on the common path.
65
+ */
66
+ export declare function withSpan<T>(name: string, options: SpanOptions, fn: () => MaybePromise<T>): MaybePromise<T>;
67
+ //#endregion
68
+ //# sourceMappingURL=telemetry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"telemetry.d.ts","names":[],"sources":["../src/observability/telemetry/telemetry.ts"],"mappings":";;;iBAuCiB;;EAEf;EACA;;EAEA;;iBAGe,yBAAyB;;EAExC;;iBAGe;EACf,OAAO,eAAe,aAAa;;iBAGpB;EACf,IAAI,eAAe,aAAa;;;iBAIjB;EACf,QAAQ,eAAe,aAAa;;;;;;;qBAQzB;;;;;wBAqCG,gBAAgB,cAAc,SAAS,mBAAmB;wBAc1D,cAAc,cAAc,UAAS,oBAAyB;wBAS9D,oBAAoB,cAAc,UAAS,oBAAyB;;;;;;wBAcpE,sBACd,cACA,SAAS,mBACT,UAAU,QAAQ;;wBAgBJ,UAAU;iBAQT;;EAEf;EACA,aAAa;EACb,OAAO;;EAEP,SAAS;;iBAGM;EACf,MAAM;;EAEN,SAAS;;;wBAIK,UAAU,cAAc,UAAS,cAAmB;;;;;;wBA6BpD,SAAS,GAAG,cAAc,SAAS,aAAa,UAAU,aAAa,KAAK,aAAa"}
@@ -0,0 +1,2 @@
1
+ import { a as createUpDownCounter, c as withSpan, i as createObservableGauge, n as createCounter, o as errorType, r as createHistogram, s as startSpan, t as DURATION_BUCKETS } from "./telemetry-B9aziFyQ.js";
2
+ export { DURATION_BUCKETS, createCounter, createHistogram, createObservableGauge, createUpDownCounter, errorType, startSpan, withSpan };