@logbrew/sdk 0.1.13 → 0.1.14
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 +9 -0
- package/core.cjs +3 -1
- package/index.d.cts +1 -999
- package/index.d.ts +36 -0
- package/issue-diagnostics.cjs +176 -2
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -125,6 +125,13 @@ try {
|
|
|
125
125
|
service: "checkout-web",
|
|
126
126
|
runtime: "browser",
|
|
127
127
|
fingerprint: "checkout-runtime-error",
|
|
128
|
+
evidence: {
|
|
129
|
+
likelyRootCause: "The payment provider exhausted its retry budget.",
|
|
130
|
+
likelyFixArea: { file: "src/payments/gateway.js", function: "chargeOrder", line: 42 },
|
|
131
|
+
impact: { failedAction: "checkout.submit", userVisibleOutcome: "The order was not confirmed." },
|
|
132
|
+
capturedFields: ["provider.status", "retry.count"],
|
|
133
|
+
redactedFields: ["provider.message"]
|
|
134
|
+
},
|
|
128
135
|
debugIdMap: {
|
|
129
136
|
"https://cdn.example/assets/app.js": "11111111-2222-4333-8444-555555555555"
|
|
130
137
|
},
|
|
@@ -136,6 +143,8 @@ try {
|
|
|
136
143
|
|
|
137
144
|
The helper records the error name/message, a typed exception with capture mechanism and handled state, and up to 32 ordered generated `stackFrames`, with query strings, hashes, and local absolute prefixes removed. Each frame carries filename, positive line/column, a conservatively parsed function name when the runtime provides one, and an optional matched Debug ID. Applications that create frames directly may also provide bounded `function`, `module`, and `inApp` identity. Existing first-frame metadata remains available for compatible grouping and tooling. The helper also emits an `issueGroupingKey` based on source, error type, and the sanitized first frame, plus an optional app-owned `issueFingerprint` when you pass a stable, safe, low-cardinality `fingerprint`. Nested `Error.cause` chains and `AggregateError.errors` are summarized as bounded cause counts, types, and sources without copying nested messages or stacks. Raw stack text is included only with `includeErrorStack: true`.
|
|
138
145
|
|
|
146
|
+
`evidence` is explicit application knowledge, not an SDK inference. LogBrew labels `likelyRootCause` as a reported hypothesis and keeps `likelyFixArea` separate from observed frames. Field-state arrays make missing, redacted, and truncated evidence visible to API, CLI, dashboard, and agent consumers. Keep identities low-cardinality, use repository-relative file paths, and never put credentials, request bodies, personal data, or raw user input in these fields.
|
|
147
|
+
|
|
139
148
|
Use `addBreadcrumb()` for explicit navigation, state, action, or network steps that should appear on later issues. The client keeps only the most recent 64 entries and marks an issue with `breadcrumbsTruncated: true` after older entries are evicted. `clearBreadcrumbs()` removes the current history.
|
|
140
149
|
|
|
141
150
|
```js
|
package/core.cjs
CHANGED
|
@@ -138,7 +138,8 @@ const {
|
|
|
138
138
|
cloneIssueDiagnostics,
|
|
139
139
|
createIssueException,
|
|
140
140
|
validateIssueBreadcrumb,
|
|
141
|
-
validateIssueDiagnostics
|
|
141
|
+
validateIssueDiagnostics,
|
|
142
|
+
validateIssueEvidence
|
|
142
143
|
} = buildIssueDiagnosticsHelpers({ SdkError, requireTimestamp, validateIssueStackFrames });
|
|
143
144
|
const {
|
|
144
145
|
cloneTelemetryContext,
|
|
@@ -1410,6 +1411,7 @@ function createIssueAttributesFromError(error, options = {}) {
|
|
|
1410
1411
|
exception,
|
|
1411
1412
|
exceptionChain,
|
|
1412
1413
|
...(stackFrames.length > 0 ? { stackFrames } : {}),
|
|
1414
|
+
...(options.evidence === undefined ? {} : { evidence: validateIssueEvidence(options.evidence) }),
|
|
1413
1415
|
metadata: compactMetadata(metadata)
|
|
1414
1416
|
};
|
|
1415
1417
|
}
|
package/index.d.cts
CHANGED
|
@@ -1,1000 +1,2 @@
|
|
|
1
|
-
/** Metadata values that can be attached to public LogBrew event payloads. */
|
|
2
|
-
export type MetadataValue = string | number | boolean | null;
|
|
3
|
-
/** Structured metadata map shared by public LogBrew event attribute types. */
|
|
4
|
-
export type Metadata = Record<string, MetadataValue>;
|
|
5
|
-
/** Bounded service, runtime, or framework identity shared by telemetry signals. */
|
|
6
|
-
export type TelemetryNamedVersion = {
|
|
7
|
-
name: string;
|
|
8
|
-
version?: string;
|
|
9
|
-
};
|
|
10
|
-
/** Privacy-bounded resource identity shared by telemetry signals. */
|
|
11
|
-
export type TelemetryResource = {
|
|
12
|
-
service?: TelemetryNamedVersion;
|
|
13
|
-
deployment?: { environment?: string; release?: string };
|
|
14
|
-
runtime?: TelemetryNamedVersion;
|
|
15
|
-
framework?: TelemetryNamedVersion;
|
|
16
|
-
operatingSystem?: TelemetryNamedVersion & { build?: string };
|
|
17
|
-
device?: { family?: string; model?: string; architecture?: string };
|
|
18
|
-
application?: { name?: string; version?: string; build?: string };
|
|
19
|
-
};
|
|
20
|
-
/** W3C-compatible correlation identity shared by non-span telemetry. */
|
|
21
|
-
export type TelemetryTraceContext = {
|
|
22
|
-
traceId: string;
|
|
23
|
-
spanId?: string;
|
|
24
|
-
parentSpanId?: string;
|
|
25
|
-
sampled?: boolean;
|
|
26
|
-
};
|
|
27
|
-
/** Opaque application session identity. */
|
|
28
|
-
export type TelemetrySessionContext = {
|
|
29
|
-
id: string;
|
|
30
|
-
previousId?: string;
|
|
31
|
-
};
|
|
32
|
-
/** Explicit app-owned subject identity; do not send names, email addresses, or IP addresses. */
|
|
33
|
-
export type TelemetrySubjectContext = {
|
|
34
|
-
id: string;
|
|
35
|
-
kind: "anonymous" | "user";
|
|
36
|
-
};
|
|
37
|
-
/** Versioned shared context available on every LogBrew event type. */
|
|
38
|
-
export type TelemetryContext = {
|
|
39
|
-
schemaVersion: 1;
|
|
40
|
-
resource?: TelemetryResource;
|
|
41
|
-
trace?: TelemetryTraceContext;
|
|
42
|
-
session?: TelemetrySessionContext;
|
|
43
|
-
subject?: TelemetrySubjectContext;
|
|
44
|
-
/** Up to 32 low-cardinality string dimensions with safe machine keys. */
|
|
45
|
-
tags?: Record<string, string>;
|
|
46
|
-
};
|
|
47
|
-
/** Canonical user-facing severity categories accepted by LogBrew. */
|
|
48
|
-
export type Severity = "info" | "warning" | "error" | "critical";
|
|
49
|
-
/** Runtime-level aliases accepted for compatibility and normalized before send. */
|
|
50
|
-
export type SeverityAlias = "trace" | "debug" | "warn" | "fatal";
|
|
51
|
-
/** Public severity input accepted by issue and log attributes. */
|
|
52
|
-
export type SeverityInput = Severity | SeverityAlias;
|
|
53
|
-
|
|
54
|
-
/** Parsed W3C trace context from a traceparent value. */
|
|
55
|
-
export type TraceparentContext = {
|
|
56
|
-
version: string;
|
|
57
|
-
traceId: string;
|
|
58
|
-
parentSpanId: string;
|
|
59
|
-
traceFlags: string;
|
|
60
|
-
sampled: boolean;
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
/** Minimal active trace shape accepted by logger adapters for correlation metadata. */
|
|
64
|
-
export type LogCorrelationTraceContext = {
|
|
65
|
-
traceId: string;
|
|
66
|
-
spanId: string;
|
|
67
|
-
parentSpanId?: string;
|
|
68
|
-
sampled?: boolean;
|
|
69
|
-
};
|
|
70
|
-
|
|
71
|
-
/** Inputs for creating a W3C traceparent value from known trace/span ids. */
|
|
72
|
-
export type TraceparentInput = {
|
|
73
|
-
traceId: string;
|
|
74
|
-
spanId: string;
|
|
75
|
-
traceFlags?: string;
|
|
76
|
-
};
|
|
77
|
-
|
|
78
|
-
/** Privacy-bounded W3C tracestate entry for explicit propagation. */
|
|
79
|
-
export type TracestateEntry = {
|
|
80
|
-
key: string;
|
|
81
|
-
value: string;
|
|
82
|
-
};
|
|
83
|
-
|
|
84
|
-
/** W3C baggage entry for explicit propagation. */
|
|
85
|
-
export type BaggageEntry = {
|
|
86
|
-
key: string;
|
|
87
|
-
value: string;
|
|
88
|
-
properties?: string[];
|
|
89
|
-
};
|
|
90
|
-
|
|
91
|
-
/** Inputs for creating an explicit W3C trace context header carrier. */
|
|
92
|
-
export type TraceContextInput = TraceparentInput & {
|
|
93
|
-
tracestate?: string | TracestateEntry[];
|
|
94
|
-
baggage?: string | BaggageEntry[];
|
|
95
|
-
};
|
|
96
|
-
|
|
97
|
-
/** Minimal OpenTelemetry SpanContext-like shape copied by dependency-free bridge helpers. */
|
|
98
|
-
export type OpenTelemetrySpanContextLike = {
|
|
99
|
-
traceId?: unknown;
|
|
100
|
-
spanId?: unknown;
|
|
101
|
-
traceFlags?: unknown;
|
|
102
|
-
isValid?: boolean;
|
|
103
|
-
};
|
|
104
|
-
|
|
105
|
-
/** Minimal OpenTelemetry Span-like shape accepted by dependency-free bridge helpers. */
|
|
106
|
-
export type OpenTelemetrySpanLike = {
|
|
107
|
-
spanContext?: () => OpenTelemetrySpanContextLike | null | undefined;
|
|
108
|
-
getSpanContext?: () => OpenTelemetrySpanContextLike | null | undefined;
|
|
109
|
-
};
|
|
110
|
-
|
|
111
|
-
/** Minimal OpenTelemetry API-like shape used for the current active span helper. */
|
|
112
|
-
export type OpenTelemetryApiLike = {
|
|
113
|
-
trace?: {
|
|
114
|
-
getActiveSpan?: () => OpenTelemetrySpanLike | null | undefined;
|
|
115
|
-
};
|
|
116
|
-
};
|
|
117
|
-
|
|
118
|
-
/** OpenTelemetry high-resolution time tuple accepted by dependency-free ReadableSpan helpers. */
|
|
119
|
-
export type OpenTelemetryHrTimeLike = readonly [number, number];
|
|
120
|
-
|
|
121
|
-
/** Minimal OpenTelemetry event-like shape summarized from ended spans. */
|
|
122
|
-
export type OpenTelemetryTimedEventLike = {
|
|
123
|
-
name?: unknown;
|
|
124
|
-
time?: OpenTelemetryHrTimeLike | number | Date;
|
|
125
|
-
timestamp?: OpenTelemetryHrTimeLike | number | Date;
|
|
126
|
-
attributes?: Record<string, unknown>;
|
|
127
|
-
};
|
|
128
|
-
|
|
129
|
-
/** Minimal OpenTelemetry link-like shape summarized from ended spans. */
|
|
130
|
-
export type OpenTelemetrySpanLinkLike = {
|
|
131
|
-
context?: OpenTelemetrySpanContextLike | null | undefined;
|
|
132
|
-
spanContext?: OpenTelemetrySpanContextLike | null | undefined;
|
|
133
|
-
attributes?: Record<string, unknown>;
|
|
134
|
-
};
|
|
135
|
-
|
|
136
|
-
/** Minimal OpenTelemetry ReadableSpan-like shape accepted by dependency-free bridge helpers. */
|
|
137
|
-
export type OpenTelemetryReadableSpanLike = {
|
|
138
|
-
name?: unknown;
|
|
139
|
-
kind?: unknown;
|
|
140
|
-
spanContext?: () => OpenTelemetrySpanContextLike | null | undefined;
|
|
141
|
-
parentSpanContext?: OpenTelemetrySpanContextLike | null | undefined;
|
|
142
|
-
parentSpanId?: unknown;
|
|
143
|
-
startTime?: OpenTelemetryHrTimeLike | number | Date;
|
|
144
|
-
endTime?: OpenTelemetryHrTimeLike | number | Date;
|
|
145
|
-
duration?: OpenTelemetryHrTimeLike;
|
|
146
|
-
status?: { code?: unknown };
|
|
147
|
-
attributes?: Record<string, unknown>;
|
|
148
|
-
events?: OpenTelemetryTimedEventLike[];
|
|
149
|
-
links?: OpenTelemetrySpanLinkLike[];
|
|
150
|
-
resource?: { attributes?: Record<string, unknown> };
|
|
151
|
-
instrumentationScope?: { name?: unknown; version?: unknown };
|
|
152
|
-
droppedAttributesCount?: unknown;
|
|
153
|
-
droppedEventsCount?: unknown;
|
|
154
|
-
droppedLinksCount?: unknown;
|
|
155
|
-
};
|
|
156
|
-
|
|
157
|
-
/** Options for creating a LogBrew child trace from OpenTelemetry context. */
|
|
158
|
-
export type OpenTelemetryTraceContextOptions = {
|
|
159
|
-
spanId?: string;
|
|
160
|
-
spanIdFactory?: () => string;
|
|
161
|
-
};
|
|
162
|
-
|
|
163
|
-
/** Options for reading OpenTelemetry's current active span without requiring an OTel dependency. */
|
|
164
|
-
export type CurrentOpenTelemetryTraceContextOptions = OpenTelemetryTraceContextOptions & {
|
|
165
|
-
openTelemetryApi?: OpenTelemetryApiLike;
|
|
166
|
-
};
|
|
167
|
-
|
|
168
|
-
/** Options for privacy-bounded OpenTelemetry ReadableSpan conversion. */
|
|
169
|
-
export type OpenTelemetryReadableSpanOptions = {
|
|
170
|
-
/** Additional safe span attribute keys to copy; sensitive keys remain blocked. */
|
|
171
|
-
attributeKeys?: string[];
|
|
172
|
-
/** Capture unsampled spans. Defaults to false to follow common OTel processor behavior. */
|
|
173
|
-
captureUnsampled?: boolean;
|
|
174
|
-
/** Additional safe span event attribute keys to copy; sensitive keys remain blocked. */
|
|
175
|
-
eventAttributeKeys?: string[];
|
|
176
|
-
/** Include privacy-bounded span event summaries. Defaults to true. */
|
|
177
|
-
includeSpanEvents?: boolean;
|
|
178
|
-
/** Include privacy-bounded span link summaries. Defaults to true. */
|
|
179
|
-
includeSpanLinks?: boolean;
|
|
180
|
-
/** Additional safe span link attribute keys to copy; sensitive keys remain blocked. */
|
|
181
|
-
linkAttributeKeys?: string[];
|
|
182
|
-
/** Primitive app metadata merged into every converted span. */
|
|
183
|
-
metadata?: Metadata;
|
|
184
|
-
/** Additional safe resource attribute keys to copy; sensitive keys remain blocked. */
|
|
185
|
-
resourceAttributeKeys?: string[];
|
|
186
|
-
};
|
|
187
|
-
|
|
188
|
-
/** Configuration for an opt-in OpenTelemetry SpanProcessor-compatible LogBrew bridge. */
|
|
189
|
-
export type OpenTelemetrySpanProcessorConfig = OpenTelemetryReadableSpanOptions & {
|
|
190
|
-
client: LogBrewClient;
|
|
191
|
-
transport?: Transport;
|
|
192
|
-
flushOnForceFlush?: boolean;
|
|
193
|
-
/** Emit one privacy-bounded synthetic trace summary span per trace on forceFlush/shutdown. Defaults to false. */
|
|
194
|
-
includeTraceSummary?: boolean;
|
|
195
|
-
timestamp?: () => string;
|
|
196
|
-
eventIdPrefix?: string;
|
|
197
|
-
spanFilter?: (span: unknown) => boolean | void;
|
|
198
|
-
onError?: (error: unknown) => void;
|
|
199
|
-
};
|
|
200
|
-
|
|
201
|
-
/** Configuration for an opt-in OpenTelemetry SpanExporter-compatible LogBrew bridge. */
|
|
202
|
-
export type OpenTelemetrySpanExporterConfig = OpenTelemetryReadableSpanOptions & {
|
|
203
|
-
client: LogBrewClient;
|
|
204
|
-
transport?: Transport;
|
|
205
|
-
/** Flush with the provided transport during export. Defaults to true when a transport is supplied. */
|
|
206
|
-
flushOnExport?: boolean;
|
|
207
|
-
/** Emit one privacy-bounded synthetic trace summary span per exported batch. Defaults to false. */
|
|
208
|
-
includeTraceSummary?: boolean;
|
|
209
|
-
timestamp?: () => string;
|
|
210
|
-
eventIdPrefix?: string;
|
|
211
|
-
spanFilter?: (span: unknown) => boolean | void;
|
|
212
|
-
onError?: (error: unknown) => void;
|
|
213
|
-
};
|
|
214
|
-
|
|
215
|
-
/** Minimal OpenTelemetry export result shape; success is code 0, failure is code 1. */
|
|
216
|
-
export type OpenTelemetryExportResult = {
|
|
217
|
-
code: number;
|
|
218
|
-
error?: Error;
|
|
219
|
-
};
|
|
220
|
-
|
|
221
|
-
/** SpanExporter-compatible handle for app-owned OpenTelemetry processors. */
|
|
222
|
-
export type OpenTelemetrySpanExporterHandle = {
|
|
223
|
-
export(
|
|
224
|
-
spans: readonly (OpenTelemetryReadableSpanLike | unknown)[],
|
|
225
|
-
resultCallback: (result: OpenTelemetryExportResult) => void
|
|
226
|
-
): void;
|
|
227
|
-
forceFlush(): Promise<void>;
|
|
228
|
-
shutdown(): Promise<void>;
|
|
229
|
-
};
|
|
230
|
-
|
|
231
|
-
/** SpanProcessor-compatible handle for app-owned OpenTelemetry setup. */
|
|
232
|
-
export type OpenTelemetrySpanProcessorHandle = {
|
|
233
|
-
onStart(span: unknown, parentContext: unknown): void;
|
|
234
|
-
onEnd(span: OpenTelemetryReadableSpanLike | unknown): void;
|
|
235
|
-
forceFlush(): Promise<void>;
|
|
236
|
-
shutdown(): Promise<void>;
|
|
237
|
-
};
|
|
238
|
-
|
|
239
|
-
/** Span fields supplied when deriving LogBrew span attributes from traceparent. */
|
|
240
|
-
export type TraceparentSpanInput = {
|
|
241
|
-
name: string;
|
|
242
|
-
spanId: string;
|
|
243
|
-
status: "ok" | "error";
|
|
244
|
-
durationMs?: number;
|
|
245
|
-
links?: SpanLinkSummary[];
|
|
246
|
-
metadata?: Metadata;
|
|
247
|
-
events?: SpanEventSummary[];
|
|
248
|
-
};
|
|
249
|
-
|
|
250
|
-
/** Public release event attributes. */
|
|
251
|
-
export type ReleaseAttributes = {
|
|
252
|
-
version: string;
|
|
253
|
-
commit?: string;
|
|
254
|
-
notes?: string;
|
|
255
|
-
metadata?: Metadata;
|
|
256
|
-
context?: TelemetryContext;
|
|
257
|
-
};
|
|
258
|
-
|
|
259
|
-
/** Public environment event attributes. */
|
|
260
|
-
export type EnvironmentAttributes = {
|
|
261
|
-
name: string;
|
|
262
|
-
region?: string;
|
|
263
|
-
metadata?: Metadata;
|
|
264
|
-
context?: TelemetryContext;
|
|
265
|
-
};
|
|
266
|
-
|
|
267
|
-
/** Privacy-bounded generated JavaScript frame attached to an issue. */
|
|
268
|
-
export type IssueStackFrame = {
|
|
269
|
-
/** Query-free generated filename or URL with local absolute prefixes removed. */
|
|
270
|
-
filename: string;
|
|
271
|
-
/** One-based generated source line. */
|
|
272
|
-
line: number;
|
|
273
|
-
/** One-based generated source column. */
|
|
274
|
-
column: number;
|
|
275
|
-
/** Optional bounded function or method identity. */
|
|
276
|
-
function?: string;
|
|
277
|
-
/** Optional bounded module, package, or namespace identity. */
|
|
278
|
-
module?: string;
|
|
279
|
-
/** Whether application code classified this frame as app-owned. */
|
|
280
|
-
inApp?: boolean;
|
|
281
|
-
/** Optional release-artifact Debug ID matched to this generated file. */
|
|
282
|
-
debugId?: string;
|
|
283
|
-
};
|
|
284
|
-
|
|
285
|
-
/** Runtime path that captured an exception and whether it escaped that path. */
|
|
286
|
-
export type IssueExceptionMechanism = {
|
|
287
|
-
/** Stable low-cardinality capture mechanism, such as `react.error_boundary`. */
|
|
288
|
-
type: string;
|
|
289
|
-
/** False when the exception escaped the capture boundary. */
|
|
290
|
-
handled: boolean;
|
|
291
|
-
};
|
|
292
|
-
|
|
293
|
-
/** Structured exception identity attached to an issue. */
|
|
294
|
-
export type IssueException = {
|
|
295
|
-
/** Bounded runtime exception class or error type. */
|
|
296
|
-
type: string;
|
|
297
|
-
/** Capture mechanism when the SDK can determine it. */
|
|
298
|
-
mechanism?: IssueExceptionMechanism;
|
|
299
|
-
};
|
|
300
|
-
|
|
301
|
-
export type IssueExceptionRelationship =
|
|
302
|
-
| "reported"
|
|
303
|
-
| "cause"
|
|
304
|
-
| "context"
|
|
305
|
-
| "aggregate_member"
|
|
306
|
-
| "suppressed";
|
|
307
|
-
export type IssueExceptionMessageState = "captured" | "truncated" | "redacted" | "not_captured";
|
|
308
|
-
export type IssueExceptionStackFramesState = "captured" | "truncated" | "not_captured";
|
|
309
|
-
|
|
310
|
-
/** One parent-first runtime exception with its own message and structured stack state. */
|
|
311
|
-
export type IssueExceptionChainEntry = {
|
|
312
|
-
/** Contiguous zero-based node identity. */
|
|
313
|
-
id: number;
|
|
314
|
-
/** Earlier parent node. Omitted only for the reported root exception. */
|
|
315
|
-
parentId?: number;
|
|
316
|
-
relationship: IssueExceptionRelationship;
|
|
317
|
-
type: string;
|
|
318
|
-
/** Bounded message only when messageState is captured or truncated. */
|
|
319
|
-
message?: string;
|
|
320
|
-
messageState: IssueExceptionMessageState;
|
|
321
|
-
module?: string;
|
|
322
|
-
mechanism?: IssueExceptionMechanism;
|
|
323
|
-
/** This exact exception's bounded structured frames. */
|
|
324
|
-
stackFrames?: IssueStackFrame[];
|
|
325
|
-
stackFramesState: IssueExceptionStackFramesState;
|
|
326
|
-
};
|
|
327
|
-
|
|
328
|
-
/** At most eight parent-first runtime exceptions. */
|
|
329
|
-
export type IssueExceptionChain = {
|
|
330
|
-
entries: IssueExceptionChainEntry[];
|
|
331
|
-
/** True when a cycle or node cap omitted additional exceptions. */
|
|
332
|
-
truncated: boolean;
|
|
333
|
-
};
|
|
334
|
-
|
|
335
|
-
export type IssueBreadcrumbLevel = "debug" | "info" | "warning" | "error" | "critical";
|
|
336
|
-
export type IssueBreadcrumbLevelInput = IssueBreadcrumbLevel | "trace" | "log" | "warn" | "fatal";
|
|
337
|
-
export type IssueBreadcrumbDataValue = string | number | boolean | null;
|
|
338
|
-
|
|
339
|
-
/** One privacy-bounded step that happened before an issue. */
|
|
340
|
-
export type IssueBreadcrumb = {
|
|
341
|
-
/** RFC 3339 timestamp with an explicit timezone. */
|
|
342
|
-
timestamp: string;
|
|
343
|
-
/** Optional stable breadcrumb kind, such as `navigation` or `http`. */
|
|
344
|
-
type?: string;
|
|
345
|
-
/** Required low-cardinality source category. */
|
|
346
|
-
category: string;
|
|
347
|
-
level?: IssueBreadcrumbLevel;
|
|
348
|
-
/** Optional bounded display-safe description. */
|
|
349
|
-
message?: string;
|
|
350
|
-
/** At most eight flat primitive fields. Never include authentication material or raw request data. */
|
|
351
|
-
data?: Record<string, IssueBreadcrumbDataValue>;
|
|
352
|
-
};
|
|
353
|
-
|
|
354
|
-
/** Input accepted by `addBreadcrumb`; the client supplies the current timestamp when omitted. */
|
|
355
|
-
export type IssueBreadcrumbInput = Omit<IssueBreadcrumb, "timestamp" | "level"> & {
|
|
356
|
-
timestamp?: string;
|
|
357
|
-
level?: IssueBreadcrumbLevelInput;
|
|
358
|
-
};
|
|
359
|
-
|
|
360
|
-
/** Public issue event attributes. */
|
|
361
|
-
export type IssueAttributes = {
|
|
362
|
-
title: string;
|
|
363
|
-
level: SeverityInput;
|
|
364
|
-
message?: string;
|
|
365
|
-
exception?: IssueException;
|
|
366
|
-
/** Parent-first runtime exception evidence; the first node agrees with legacy exception/stackFrames. */
|
|
367
|
-
exceptionChain?: IssueExceptionChain;
|
|
368
|
-
/** Ordered privacy-bounded generated frames, capped at 32. */
|
|
369
|
-
stackFrames?: IssueStackFrame[];
|
|
370
|
-
/** Oldest-to-newest issue history, capped at the most recent 64 entries. */
|
|
371
|
-
breadcrumbs?: IssueBreadcrumb[];
|
|
372
|
-
/** True when older or invalid history was omitted before capture. */
|
|
373
|
-
breadcrumbsTruncated?: boolean;
|
|
374
|
-
metadata?: Metadata;
|
|
375
|
-
context?: TelemetryContext;
|
|
376
|
-
};
|
|
377
|
-
|
|
378
|
-
/** Options for creating privacy-bounded issue attributes from a JavaScript error. */
|
|
379
|
-
export type JavaScriptErrorIssueOptions = {
|
|
380
|
-
title?: string;
|
|
381
|
-
level?: SeverityInput;
|
|
382
|
-
message?: string;
|
|
383
|
-
metadata?: Metadata;
|
|
384
|
-
/** Stable low-cardinality capture mechanism. Defaults to `javascript.error`. */
|
|
385
|
-
mechanism?: string;
|
|
386
|
-
/** Whether the error was handled by the capture boundary. Defaults to true. */
|
|
387
|
-
handled?: boolean;
|
|
388
|
-
/** Metadata source label. Defaults to `javascript.error`. */
|
|
389
|
-
source?: string;
|
|
390
|
-
/** Active trace copied into primitive correlation metadata. */
|
|
391
|
-
trace?: LogCorrelationTraceContext | null;
|
|
392
|
-
/** Release name associated with the runtime error. */
|
|
393
|
-
release?: string;
|
|
394
|
-
/** Environment associated with the runtime error. */
|
|
395
|
-
environment?: string;
|
|
396
|
-
/** Service associated with the runtime error. */
|
|
397
|
-
service?: string;
|
|
398
|
-
/** Runtime label such as `browser`, `node`, or `react-native`. */
|
|
399
|
-
runtime?: string;
|
|
400
|
-
/** Platform label such as `web`, `ios`, or `android`. */
|
|
401
|
-
platform?: string;
|
|
402
|
-
/** Map of sanitized frame filenames or minified URLs to release-artifact Debug IDs. */
|
|
403
|
-
debugIdMap?: Record<string, string>;
|
|
404
|
-
/** Optional stable app-owned grouping fingerprint. Keep it safe and low-cardinality. */
|
|
405
|
-
fingerprint?: string;
|
|
406
|
-
/** Include raw stack text only when the app has explicitly approved it. Defaults to false. */
|
|
407
|
-
includeErrorStack?: boolean;
|
|
408
|
-
};
|
|
409
|
-
|
|
410
|
-
/** Public log event attributes. */
|
|
411
|
-
export type LogAttributes = {
|
|
412
|
-
message: string;
|
|
413
|
-
level: SeverityInput;
|
|
414
|
-
logger?: string;
|
|
415
|
-
metadata?: Metadata;
|
|
416
|
-
context?: TelemetryContext;
|
|
417
|
-
};
|
|
418
|
-
|
|
419
|
-
/** Console method names supported by the opt-in console capture helper. */
|
|
420
|
-
export type ConsoleMethodName = "debug" | "info" | "log" | "warn" | "error";
|
|
421
|
-
|
|
422
|
-
/** Minimal console-like target accepted by the opt-in console capture helper. */
|
|
423
|
-
export type ConsoleLike = Partial<Record<ConsoleMethodName, (...args: unknown[]) => void>>;
|
|
424
|
-
|
|
425
|
-
/** Configuration for opt-in console capture. */
|
|
426
|
-
export type ConsoleCaptureConfig = {
|
|
427
|
-
client: LogBrewClient;
|
|
428
|
-
console?: ConsoleLike;
|
|
429
|
-
levels?: ConsoleMethodName[];
|
|
430
|
-
logger?: string;
|
|
431
|
-
metadata?: Metadata;
|
|
432
|
-
transport?: Transport;
|
|
433
|
-
flushOnCapture?: boolean;
|
|
434
|
-
includeErrorStack?: boolean;
|
|
435
|
-
timestamp?: () => string;
|
|
436
|
-
eventIdPrefix?: string;
|
|
437
|
-
onError?: (error: unknown) => void;
|
|
438
|
-
};
|
|
439
|
-
|
|
440
|
-
/** Handle returned by opt-in console capture installation. */
|
|
441
|
-
export type ConsoleCaptureHandle = {
|
|
442
|
-
flush(): Promise<TransportResponse | null>;
|
|
443
|
-
uninstall(): void;
|
|
444
|
-
};
|
|
445
|
-
|
|
446
|
-
/** Pino JSON log record shape accepted by the optional Pino destination helper. */
|
|
447
|
-
export type PinoLogRecord = Record<string, unknown> & {
|
|
448
|
-
level?: string | number;
|
|
449
|
-
time?: string | number;
|
|
450
|
-
timestamp?: string | number;
|
|
451
|
-
msg?: unknown;
|
|
452
|
-
message?: unknown;
|
|
453
|
-
err?: unknown;
|
|
454
|
-
error?: unknown;
|
|
455
|
-
};
|
|
456
|
-
|
|
457
|
-
/** Configuration for the dependency-free Pino destination adapter. */
|
|
458
|
-
export type PinoDestinationConfig = {
|
|
459
|
-
client: LogBrewClient;
|
|
460
|
-
logger?: string;
|
|
461
|
-
metadata?: Metadata;
|
|
462
|
-
traceProvider?: () => LogCorrelationTraceContext | null | undefined;
|
|
463
|
-
transport?: Transport;
|
|
464
|
-
flushOnWrite?: boolean;
|
|
465
|
-
includeErrorStack?: boolean;
|
|
466
|
-
timestamp?: () => string;
|
|
467
|
-
eventIdPrefix?: string;
|
|
468
|
-
onError?: (error: unknown) => void;
|
|
469
|
-
};
|
|
470
|
-
|
|
471
|
-
/** Stream-like destination returned for use as Pino's output destination. */
|
|
472
|
-
export type PinoDestinationHandle = {
|
|
473
|
-
write(chunk: unknown): boolean;
|
|
474
|
-
flush(): Promise<TransportResponse | null>;
|
|
475
|
-
end(): Promise<TransportResponse | null>;
|
|
476
|
-
};
|
|
477
|
-
|
|
478
|
-
/** Winston info object shape accepted by the optional Winston transport helper. */
|
|
479
|
-
export type WinstonLogInfo = Record<string, unknown> & {
|
|
480
|
-
level?: string;
|
|
481
|
-
message?: unknown;
|
|
482
|
-
timestamp?: string | number | Date;
|
|
483
|
-
time?: string | number | Date;
|
|
484
|
-
err?: unknown;
|
|
485
|
-
error?: unknown;
|
|
486
|
-
stack?: unknown;
|
|
487
|
-
};
|
|
488
|
-
|
|
489
|
-
/** Configuration for the dependency-free Winston transport adapter. */
|
|
490
|
-
export type WinstonTransportConfig = {
|
|
491
|
-
client: LogBrewClient;
|
|
492
|
-
logger?: string;
|
|
493
|
-
metadata?: Metadata;
|
|
494
|
-
traceProvider?: () => LogCorrelationTraceContext | null | undefined;
|
|
495
|
-
transport?: Transport;
|
|
496
|
-
flushOnWrite?: boolean;
|
|
497
|
-
includeErrorStack?: boolean;
|
|
498
|
-
timestamp?: () => string;
|
|
499
|
-
eventIdPrefix?: string;
|
|
500
|
-
level?: string;
|
|
501
|
-
name?: string;
|
|
502
|
-
silent?: boolean;
|
|
503
|
-
handleExceptions?: boolean;
|
|
504
|
-
handleRejections?: boolean;
|
|
505
|
-
onError?: (error: unknown) => void;
|
|
506
|
-
};
|
|
507
|
-
|
|
508
|
-
/** Object-mode transport returned for use in a Winston logger's transports array. */
|
|
509
|
-
export type WinstonTransportHandle = {
|
|
510
|
-
level?: string;
|
|
511
|
-
name?: string;
|
|
512
|
-
silent?: boolean;
|
|
513
|
-
handleExceptions?: boolean;
|
|
514
|
-
handleRejections?: boolean;
|
|
515
|
-
log(info: WinstonLogInfo, callback?: () => void): void;
|
|
516
|
-
write(info: WinstonLogInfo): boolean;
|
|
517
|
-
flush(): Promise<TransportResponse | null>;
|
|
518
|
-
end(callback?: () => void): unknown;
|
|
519
|
-
};
|
|
520
|
-
|
|
521
|
-
/** Privacy-bounded milestone recorded inside a span. */
|
|
522
|
-
export type SpanEventSummary = {
|
|
523
|
-
name: string;
|
|
524
|
-
timestamp?: string;
|
|
525
|
-
metadata?: Metadata;
|
|
526
|
-
};
|
|
527
|
-
|
|
528
|
-
/** Privacy-bounded reference from this span to another trace/span. */
|
|
529
|
-
export type SpanLinkSummary = {
|
|
530
|
-
traceId: string;
|
|
531
|
-
spanId: string;
|
|
532
|
-
sampled?: boolean;
|
|
533
|
-
metadata?: Metadata;
|
|
534
|
-
};
|
|
535
|
-
|
|
536
|
-
/** Public span event attributes. */
|
|
537
|
-
export type SpanAttributes = {
|
|
538
|
-
name: string;
|
|
539
|
-
traceId: string;
|
|
540
|
-
spanId: string;
|
|
541
|
-
parentSpanId?: string;
|
|
542
|
-
status: "ok" | "error";
|
|
543
|
-
durationMs?: number;
|
|
544
|
-
events?: SpanEventSummary[];
|
|
545
|
-
links?: SpanLinkSummary[];
|
|
546
|
-
metadata?: Metadata;
|
|
547
|
-
context?: TelemetryContext;
|
|
548
|
-
};
|
|
549
|
-
|
|
550
|
-
/** Public action event attributes. */
|
|
551
|
-
export type ActionAttributes = {
|
|
552
|
-
name: string;
|
|
553
|
-
status: "queued" | "running" | "success" | "failure";
|
|
554
|
-
metadata?: Metadata;
|
|
555
|
-
context?: TelemetryContext;
|
|
556
|
-
};
|
|
557
|
-
|
|
558
|
-
/** Stable product-analytics event categories carried in reserved action metadata. */
|
|
559
|
-
export type ProductAnalyticsKind = "page_view" | "screen_view" | "interaction";
|
|
560
|
-
|
|
561
|
-
/** Current version of the reserved product-analytics metadata vocabulary. */
|
|
562
|
-
export declare const PRODUCT_ANALYTICS_SCHEMA_VERSION: 1;
|
|
563
|
-
|
|
564
|
-
/** Product-analytics categories understood by this SDK version. */
|
|
565
|
-
export declare const PRODUCT_ANALYTICS_KINDS: readonly ProductAnalyticsKind[];
|
|
566
|
-
|
|
567
|
-
/** App-owned product step input for agent-readable action timelines. */
|
|
568
|
-
export type ProductActionInput = string | {
|
|
569
|
-
name: string;
|
|
570
|
-
status?: ActionAttributes["status"];
|
|
571
|
-
sessionId?: string;
|
|
572
|
-
traceId?: string;
|
|
573
|
-
routeTemplate?: string;
|
|
574
|
-
screen?: string;
|
|
575
|
-
funnel?: string;
|
|
576
|
-
step?: string;
|
|
577
|
-
metadata?: Metadata;
|
|
578
|
-
};
|
|
579
|
-
|
|
580
|
-
/** App-owned API milestone input for agent-readable network timelines. */
|
|
581
|
-
export type NetworkMilestoneInput = string | {
|
|
582
|
-
name?: string;
|
|
583
|
-
routeTemplate: string;
|
|
584
|
-
method?: string;
|
|
585
|
-
status?: ActionAttributes["status"];
|
|
586
|
-
statusCode?: number;
|
|
587
|
-
durationMs?: number;
|
|
588
|
-
sessionId?: string;
|
|
589
|
-
traceId?: string;
|
|
590
|
-
metadata?: Metadata;
|
|
591
|
-
};
|
|
592
|
-
|
|
593
|
-
/** Shared timeline helper options for primitive app metadata. */
|
|
594
|
-
export type TimelineAttributesOptions = {
|
|
595
|
-
metadata?: Metadata;
|
|
596
|
-
};
|
|
597
|
-
|
|
598
|
-
/** Planned backend support-ticket sources accepted by explicit draft helpers. */
|
|
599
|
-
export type SupportTicketSource = "cli" | "sdk" | "website" | "docs" | "mobile";
|
|
600
|
-
|
|
601
|
-
/** Planned backend support-ticket categories accepted by explicit draft helpers. */
|
|
602
|
-
export type SupportTicketCategory =
|
|
603
|
-
| "sdk_install_failure"
|
|
604
|
-
| "ingest_failure"
|
|
605
|
-
| "auth_failure"
|
|
606
|
-
| "project_setup"
|
|
607
|
-
| "dashboard_issue"
|
|
608
|
-
| "docs_confusion"
|
|
609
|
-
| "cli_issue"
|
|
610
|
-
| "mobile_issue"
|
|
611
|
-
| "billing_question"
|
|
612
|
-
| "other";
|
|
613
|
-
|
|
614
|
-
/** JSON-like diagnostics input sanitized before a support-ticket draft is returned. */
|
|
615
|
-
export type SupportDiagnosticsValue =
|
|
616
|
-
| string
|
|
617
|
-
| number
|
|
618
|
-
| boolean
|
|
619
|
-
| null
|
|
620
|
-
| SupportDiagnosticsValue[]
|
|
621
|
-
| { [key: string]: SupportDiagnosticsValue };
|
|
622
|
-
|
|
623
|
-
/** Explicit local-only support-ticket draft input. This does not open a ticket. */
|
|
624
|
-
export type SupportTicketDraftInput = {
|
|
625
|
-
source: SupportTicketSource;
|
|
626
|
-
category: SupportTicketCategory;
|
|
627
|
-
title: string;
|
|
628
|
-
description: string;
|
|
629
|
-
projectId?: string;
|
|
630
|
-
environment?: string;
|
|
631
|
-
runtime?: string;
|
|
632
|
-
framework?: string;
|
|
633
|
-
sdkPackage?: string;
|
|
634
|
-
sdkVersion?: string;
|
|
635
|
-
release?: string;
|
|
636
|
-
traceId?: string;
|
|
637
|
-
eventId?: string;
|
|
638
|
-
diagnostics?: Record<string, unknown>;
|
|
639
|
-
};
|
|
640
|
-
|
|
641
|
-
/** Planned backend create payload produced locally for explicit user or agent action. */
|
|
642
|
-
export type SupportTicketDraft = {
|
|
643
|
-
source: SupportTicketSource;
|
|
644
|
-
category: SupportTicketCategory;
|
|
645
|
-
title: string;
|
|
646
|
-
description: string;
|
|
647
|
-
project_id?: string;
|
|
648
|
-
environment?: string;
|
|
649
|
-
runtime?: string;
|
|
650
|
-
framework?: string;
|
|
651
|
-
sdk_package?: string;
|
|
652
|
-
sdk_version?: string;
|
|
653
|
-
release?: string;
|
|
654
|
-
trace_id?: string;
|
|
655
|
-
event_id?: string;
|
|
656
|
-
diagnostics?: Record<string, SupportDiagnosticsValue>;
|
|
657
|
-
};
|
|
658
|
-
|
|
659
|
-
/** Public metric event attributes. Use low-cardinality metadata only. */
|
|
660
|
-
export type MetricAttributes = {
|
|
661
|
-
name: string;
|
|
662
|
-
/** Optional stable, single-line meaning; 1 to 1,024 Unicode characters. */
|
|
663
|
-
description?: string;
|
|
664
|
-
kind: "counter" | "histogram";
|
|
665
|
-
value: number;
|
|
666
|
-
unit: string;
|
|
667
|
-
temporality: "delta" | "cumulative";
|
|
668
|
-
metadata?: Metadata;
|
|
669
|
-
context?: TelemetryContext;
|
|
670
|
-
} | {
|
|
671
|
-
name: string;
|
|
672
|
-
/** Optional stable, single-line meaning; 1 to 1,024 Unicode characters. */
|
|
673
|
-
description?: string;
|
|
674
|
-
kind: "gauge";
|
|
675
|
-
value: number;
|
|
676
|
-
unit: string;
|
|
677
|
-
temporality: "instant";
|
|
678
|
-
metadata?: Metadata;
|
|
679
|
-
};
|
|
680
|
-
|
|
681
|
-
/** Public event union used in preview and transport payloads. */
|
|
682
|
-
export type Event =
|
|
683
|
-
| { type: "release"; id: string; timestamp: string; attributes: ReleaseAttributes }
|
|
684
|
-
| { type: "environment"; id: string; timestamp: string; attributes: EnvironmentAttributes }
|
|
685
|
-
| { type: "issue"; id: string; timestamp: string; attributes: IssueAttributes }
|
|
686
|
-
| { type: "log"; id: string; timestamp: string; attributes: LogAttributes }
|
|
687
|
-
| { type: "span"; id: string; timestamp: string; attributes: SpanAttributes }
|
|
688
|
-
| { type: "action"; id: string; timestamp: string; attributes: ActionAttributes }
|
|
689
|
-
| { type: "metric"; id: string; timestamp: string; attributes: MetricAttributes };
|
|
690
|
-
|
|
691
|
-
/** Drop-only event filter called after validation and before an event is queued. */
|
|
692
|
-
export type EventFilter = (event: Event) => boolean | void;
|
|
693
|
-
|
|
694
|
-
/** Canonical compact event record exchanged with an app-owned synchronous persistence adapter. */
|
|
695
|
-
export type StoredEvent = {
|
|
696
|
-
event: Event;
|
|
697
|
-
serializedEvent: string;
|
|
698
|
-
eventBytes: number;
|
|
699
|
-
};
|
|
700
|
-
|
|
701
|
-
/** Explicit synchronous persistence seam used to recover and acknowledge queued events safely. */
|
|
702
|
-
export type EventStore = {
|
|
703
|
-
load(): StoredEvent[];
|
|
704
|
-
append(record: StoredEvent): void;
|
|
705
|
-
acknowledge(count: number): void;
|
|
706
|
-
purge(): void;
|
|
707
|
-
close(): void;
|
|
708
|
-
};
|
|
709
|
-
|
|
710
|
-
/** Queue drop notification emitted when a bounded in-memory queue is full. */
|
|
711
|
-
export type DroppedEvent = {
|
|
712
|
-
reason: "event_too_large" | "queue_bytes_overflow" | "queue_overflow";
|
|
713
|
-
eventType: Event["type"];
|
|
714
|
-
eventId: string;
|
|
715
|
-
droppedEvents: number;
|
|
716
|
-
};
|
|
717
|
-
|
|
718
|
-
/** Stable transport response returned from flush and shutdown operations. */
|
|
719
|
-
export type TransportResponse = {
|
|
720
|
-
/** Final HTTP-like status returned by the transport. */
|
|
721
|
-
statusCode: number;
|
|
722
|
-
/** Number of transport attempts used for the flush. */
|
|
723
|
-
attempts: number;
|
|
724
|
-
/** Number of distinct batches acknowledged; client flush/shutdown responses always include it. */
|
|
725
|
-
batches?: number;
|
|
726
|
-
/** Optional retry delay from a rate-limit response, in milliseconds. */
|
|
727
|
-
retryAfterMs?: number;
|
|
728
|
-
};
|
|
729
|
-
|
|
730
|
-
/** Minimal transport interface accepted by flush and shutdown operations. */
|
|
731
|
-
export type Transport = {
|
|
732
|
-
send(apiKey: string, body: string): TransportResponse | Promise<TransportResponse>;
|
|
733
|
-
};
|
|
734
|
-
|
|
735
|
-
/** Content-free bounded delivery state with no event or sensitive transport fields. */
|
|
736
|
-
export type DeliveryHealthSnapshot = Readonly<{
|
|
737
|
-
/** Stable schema discriminator for JSON consumers. */
|
|
738
|
-
schemaVersion: 1;
|
|
739
|
-
automaticDelivery: boolean;
|
|
740
|
-
lifecycle: "active" | "shutting_down" | "closed";
|
|
741
|
-
deliveryState: "idle" | "queued" | "scheduled" | "in_flight" | "retrying" | "paused" | "accepted" | "failed" | "dropped";
|
|
742
|
-
storage: "memory" | "persistent";
|
|
743
|
-
queueEvents: number;
|
|
744
|
-
queueBytes: number;
|
|
745
|
-
/** Events and compact bytes loaded from persistence when this client started. */
|
|
746
|
-
hydratedEvents: number;
|
|
747
|
-
hydratedBytes: number;
|
|
748
|
-
droppedEvents: number;
|
|
749
|
-
droppedByReason: Readonly<{
|
|
750
|
-
event_too_large: number;
|
|
751
|
-
queue_bytes_overflow: number;
|
|
752
|
-
queue_overflow: number;
|
|
753
|
-
}>;
|
|
754
|
-
lastDropReason: "none" | "event_too_large" | "queue_bytes_overflow" | "queue_overflow";
|
|
755
|
-
scheduled: boolean;
|
|
756
|
-
inFlight: boolean;
|
|
757
|
-
coalesced: boolean;
|
|
758
|
-
pendingOperations: number;
|
|
759
|
-
lastOutcome: "idle" | "empty" | "accepted" | "failed";
|
|
760
|
-
lastStatusClass: "none" | "success" | "client_error" | "server_error" | "network_error" | "transport_error" | "invalid_response" | "other_status";
|
|
761
|
-
pausedReason: "none" | "authentication" | "rate_limit" | "non_retryable";
|
|
762
|
-
consecutiveFailures: number;
|
|
763
|
-
/** Bounded transient retry delay; zero when no automatic retry is scheduled. */
|
|
764
|
-
retryDelayMs: number;
|
|
765
|
-
flushes: number;
|
|
766
|
-
failures: number;
|
|
767
|
-
attempts: number;
|
|
768
|
-
batches: number;
|
|
769
|
-
/** Events durably acknowledged since this client was created. */
|
|
770
|
-
acceptedEvents: number;
|
|
771
|
-
/** Bounded monotonic-within-client Unix milliseconds; zero until the transition occurs. */
|
|
772
|
-
lastAttemptAtUnixMs: number;
|
|
773
|
-
lastAcceptedAtUnixMs: number;
|
|
774
|
-
lastDroppedAtUnixMs: number;
|
|
775
|
-
}>;
|
|
776
|
-
|
|
777
|
-
/** Stable public SDK error with parseable code and message fields. */
|
|
778
|
-
export declare class SdkError extends Error {
|
|
779
|
-
code: string;
|
|
780
|
-
retryAfterMs?: number;
|
|
781
|
-
retryable?: boolean;
|
|
782
|
-
constructor(code: string, message: string, details?: { retryAfterMs?: number; retryable?: boolean });
|
|
783
|
-
}
|
|
784
|
-
|
|
785
|
-
/** Transport error that can optionally be marked retryable by the caller. */
|
|
786
|
-
export declare class TransportError extends Error {
|
|
787
|
-
code: string;
|
|
788
|
-
retryable: boolean;
|
|
789
|
-
constructor(code: string, message: string, retryable?: boolean);
|
|
790
|
-
/** Create a retryable network failure that preserves queued events. */
|
|
791
|
-
static network(message: string): TransportError;
|
|
792
|
-
}
|
|
793
|
-
|
|
794
|
-
/** Scripted transport for previewing, accepting, or failing queued event flushes. */
|
|
795
|
-
export declare class RecordingTransport {
|
|
796
|
-
constructor(scriptedResponses?: Array<{ statusCode: number; retryAfterMs?: number } | Error>);
|
|
797
|
-
/** Every request body sent through this transport instance. */
|
|
798
|
-
sentBodies: string[];
|
|
799
|
-
/** Create a transport that accepts queued flushes with a 202 response. */
|
|
800
|
-
static alwaysAccept(): RecordingTransport;
|
|
801
|
-
/** Return the most recent request body sent through this transport. */
|
|
802
|
-
lastBody(): string | null;
|
|
803
|
-
send(apiKey: string, body: string): Promise<TransportResponse>;
|
|
804
|
-
}
|
|
805
|
-
|
|
806
1
|
/** Buffered public client for validating, previewing, and flushing LogBrew events. */
|
|
807
|
-
export
|
|
808
|
-
/** Create a client from public SDK identity, retry, and API key settings. */
|
|
809
|
-
static create(config: {
|
|
810
|
-
apiKey: string;
|
|
811
|
-
sdkName: string;
|
|
812
|
-
sdkVersion: string;
|
|
813
|
-
/** Versioned context merged into every captured event; event context can override dynamic fields. */
|
|
814
|
-
context?: TelemetryContext;
|
|
815
|
-
/** Retry attempts after the first send. Must be a non-negative integer; defaults to 2. */
|
|
816
|
-
maxRetries?: number;
|
|
817
|
-
eventFilter?: EventFilter;
|
|
818
|
-
/** Maximum queued compact event bytes. Defaults to 4 MiB. */
|
|
819
|
-
maxQueueBytes?: number;
|
|
820
|
-
maxQueueSize?: number;
|
|
821
|
-
/** Maximum events per request body. Defaults to 100. */
|
|
822
|
-
maxBatchEvents?: number;
|
|
823
|
-
/** Maximum UTF-8 request body bytes. Defaults to 256 KiB. */
|
|
824
|
-
maxBatchBytes?: number;
|
|
825
|
-
onEventDropped?: (drop: DroppedEvent) => void;
|
|
826
|
-
/** Optional app-scoped persistence adapter. Methods must complete synchronously. */
|
|
827
|
-
eventStore?: EventStore;
|
|
828
|
-
/** Client-owned transport used by automatic delivery and by flush/shutdown when no argument is supplied. */
|
|
829
|
-
transport?: Transport;
|
|
830
|
-
/** Enable interval and queue-threshold delivery. Defaults to true when transport is supplied. */
|
|
831
|
-
automaticDelivery?: boolean;
|
|
832
|
-
/** One-shot delivery interval in milliseconds. Defaults to 5000 and must not exceed 60000. */
|
|
833
|
-
deliveryIntervalMs?: number;
|
|
834
|
-
/** Queue count that triggers delivery without waiting for the interval. Defaults to min(50, maxQueueSize). */
|
|
835
|
-
deliveryQueueThreshold?: number;
|
|
836
|
-
}): LogBrewClient;
|
|
837
|
-
/** Return the queued event count currently buffered in memory. */
|
|
838
|
-
pendingEvents(): number;
|
|
839
|
-
/** Return compact serialized event bytes currently buffered in memory. */
|
|
840
|
-
pendingBytes(): number;
|
|
841
|
-
/** Return the number of events dropped because the bounded in-memory queue was full. */
|
|
842
|
-
droppedEvents(): number;
|
|
843
|
-
/** Return a frozen, content-free snapshot of queue and delivery lifecycle health. */
|
|
844
|
-
deliveryHealth(): DeliveryHealthSnapshot;
|
|
845
|
-
/** Return the queued event batch as stable, pretty-printed JSON. */
|
|
846
|
-
previewJson(): string;
|
|
847
|
-
/** Purge queued events from memory and persistence while no delivery operation is active. */
|
|
848
|
-
purgePendingEvents(): number;
|
|
849
|
-
/** Add one explicit privacy-bounded breadcrumb to the client's 64-entry issue history. */
|
|
850
|
-
addBreadcrumb(breadcrumb: IssueBreadcrumbInput, timestamp?: string): void;
|
|
851
|
-
/** Clear the current issue breadcrumb history and return the number removed. */
|
|
852
|
-
clearBreadcrumbs(): number;
|
|
853
|
-
release(id: string, timestamp: string, attributes: ReleaseAttributes): void;
|
|
854
|
-
environment(id: string, timestamp: string, attributes: EnvironmentAttributes): void;
|
|
855
|
-
issue(id: string, timestamp: string, attributes: IssueAttributes): void;
|
|
856
|
-
log(id: string, timestamp: string, attributes: LogAttributes): void;
|
|
857
|
-
span(id: string, timestamp: string, attributes: SpanAttributes): void;
|
|
858
|
-
action(id: string, timestamp: string, attributes: ActionAttributes): void;
|
|
859
|
-
metric(id: string, timestamp: string, attributes: MetricAttributes): void;
|
|
860
|
-
/** Flush one queue snapshot in bounded batches while preserving concurrent captures and retry bodies. */
|
|
861
|
-
flush(transport?: Transport): Promise<TransportResponse>;
|
|
862
|
-
/** Reject new capture, flush queued events, then close; a failed flush reopens the intact remainder. */
|
|
863
|
-
shutdown(transport?: Transport): Promise<TransportResponse>;
|
|
864
|
-
}
|
|
865
|
-
|
|
866
|
-
/** Install explicit console capture while preserving the target console's normal output behavior. */
|
|
867
|
-
export declare function installLogBrewConsoleCapture(config: ConsoleCaptureConfig): ConsoleCaptureHandle;
|
|
868
|
-
|
|
869
|
-
/** Create safe action attributes for an app-owned product step without automatic UI capture. */
|
|
870
|
-
export declare function createProductActionAttributes(
|
|
871
|
-
action: ProductActionInput,
|
|
872
|
-
options?: TimelineAttributesOptions
|
|
873
|
-
): ActionAttributes;
|
|
874
|
-
|
|
875
|
-
/** Create safe action attributes for an app-owned network milestone without HTTP client patching. */
|
|
876
|
-
export declare function createNetworkMilestoneAttributes(
|
|
877
|
-
request: NetworkMilestoneInput,
|
|
878
|
-
options?: TimelineAttributesOptions
|
|
879
|
-
): ActionAttributes;
|
|
880
|
-
|
|
881
|
-
/** Build a local-only, token-free support-ticket create payload draft without calling backend routes. */
|
|
882
|
-
export declare function createSupportTicketDraft(input: SupportTicketDraftInput): SupportTicketDraft;
|
|
883
|
-
|
|
884
|
-
/**
|
|
885
|
-
* Convert a JavaScript Error-like value into safe issue attributes with optional source-map Debug ID metadata.
|
|
886
|
-
* Parent-first cause and AggregateError evidence is bounded to the public exception-chain contract.
|
|
887
|
-
*/
|
|
888
|
-
export declare function createIssueAttributesFromError(
|
|
889
|
-
error: unknown,
|
|
890
|
-
options?: JavaScriptErrorIssueOptions
|
|
891
|
-
): IssueAttributes;
|
|
892
|
-
|
|
893
|
-
/** Convert console arguments into safe LogBrew log attributes without installing capture. */
|
|
894
|
-
export declare function logAttributesFromConsoleArgs(
|
|
895
|
-
method: ConsoleMethodName,
|
|
896
|
-
args: readonly unknown[],
|
|
897
|
-
options?: {
|
|
898
|
-
logger?: string;
|
|
899
|
-
metadata?: Metadata;
|
|
900
|
-
includeErrorStack?: boolean;
|
|
901
|
-
}
|
|
902
|
-
): LogAttributes;
|
|
903
|
-
|
|
904
|
-
/** Map a console method name to the corresponding LogBrew log level. */
|
|
905
|
-
export declare function logbrewLevelFromConsoleMethod(method: ConsoleMethodName): LogAttributes["level"];
|
|
906
|
-
|
|
907
|
-
/** Parse a W3C traceparent value into normalized trace/span context. */
|
|
908
|
-
export declare function parseTraceparent(traceparent: string): TraceparentContext;
|
|
909
|
-
|
|
910
|
-
/** Create a W3C traceparent value from explicit trace/span ids. */
|
|
911
|
-
export declare function createTraceparent(input: TraceparentInput): string;
|
|
912
|
-
|
|
913
|
-
/** Create an explicit outbound header carrier containing only traceparent. */
|
|
914
|
-
export declare function createTraceparentHeaders(input: TraceparentInput): { traceparent: string };
|
|
915
|
-
|
|
916
|
-
/** Parse a W3C tracestate header into normalized entries. */
|
|
917
|
-
export declare function parseTracestate(tracestate: string): TracestateEntry[];
|
|
918
|
-
|
|
919
|
-
/** Create a normalized W3C tracestate header from explicit entries. */
|
|
920
|
-
export declare function createTracestate(entries: TracestateEntry[]): string;
|
|
921
|
-
|
|
922
|
-
/** Parse a W3C baggage header into decoded entries. */
|
|
923
|
-
export declare function parseBaggage(baggage: string): BaggageEntry[];
|
|
924
|
-
|
|
925
|
-
/** Create a W3C baggage header from explicit entries. */
|
|
926
|
-
export declare function createBaggage(entries: BaggageEntry[]): string;
|
|
927
|
-
|
|
928
|
-
/** Create an explicit outbound carrier for traceparent plus optional tracestate and baggage. */
|
|
929
|
-
export declare function createTraceContextHeaders(input: TraceContextInput): {
|
|
930
|
-
traceparent: string;
|
|
931
|
-
tracestate?: string;
|
|
932
|
-
baggage?: string;
|
|
933
|
-
};
|
|
934
|
-
|
|
935
|
-
/** Create a LogBrew child trace from a live OpenTelemetry SpanContext-like object. */
|
|
936
|
-
export declare function logbrewTraceContextFromOpenTelemetrySpanContext(
|
|
937
|
-
spanContext: OpenTelemetrySpanContextLike | null | undefined,
|
|
938
|
-
options?: OpenTelemetryTraceContextOptions
|
|
939
|
-
): LogCorrelationTraceContext | null;
|
|
940
|
-
|
|
941
|
-
/** Create a LogBrew child trace from a live OpenTelemetry Span-like object. */
|
|
942
|
-
export declare function logbrewTraceContextFromOpenTelemetrySpan(
|
|
943
|
-
span: OpenTelemetrySpanLike | null | undefined,
|
|
944
|
-
options?: OpenTelemetryTraceContextOptions
|
|
945
|
-
): LogCorrelationTraceContext | null;
|
|
946
|
-
|
|
947
|
-
/** Create a LogBrew child trace from OpenTelemetry's current active span, when available. */
|
|
948
|
-
export declare function logbrewTraceContextFromCurrentOpenTelemetrySpan(
|
|
949
|
-
options?: CurrentOpenTelemetryTraceContextOptions
|
|
950
|
-
): LogCorrelationTraceContext | null;
|
|
951
|
-
|
|
952
|
-
/** Convert an ended OpenTelemetry ReadableSpan-like object into safe LogBrew span attributes. */
|
|
953
|
-
export declare function spanAttributesFromOpenTelemetryReadableSpan(
|
|
954
|
-
span: OpenTelemetryReadableSpanLike | null | undefined,
|
|
955
|
-
options?: OpenTelemetryReadableSpanOptions
|
|
956
|
-
): SpanAttributes | null;
|
|
957
|
-
|
|
958
|
-
/** Create an opt-in SpanProcessor-compatible bridge for app-owned OpenTelemetry providers. */
|
|
959
|
-
export declare function createLogBrewOpenTelemetrySpanProcessor(
|
|
960
|
-
config: OpenTelemetrySpanProcessorConfig
|
|
961
|
-
): OpenTelemetrySpanProcessorHandle;
|
|
962
|
-
|
|
963
|
-
/** Create an opt-in SpanExporter-compatible bridge for app-owned OpenTelemetry processors. */
|
|
964
|
-
export declare function createLogBrewOpenTelemetrySpanExporter(
|
|
965
|
-
config: OpenTelemetrySpanExporterConfig
|
|
966
|
-
): OpenTelemetrySpanExporterHandle;
|
|
967
|
-
|
|
968
|
-
/** Build LogBrew span attributes that continue an incoming W3C traceparent value. */
|
|
969
|
-
export declare function spanAttributesFromTraceparent(
|
|
970
|
-
traceparent: string,
|
|
971
|
-
attributes: TraceparentSpanInput
|
|
972
|
-
): SpanAttributes;
|
|
973
|
-
|
|
974
|
-
/** Create a dependency-free Pino destination that turns JSON log lines into queued LogBrew log events. */
|
|
975
|
-
export declare function createLogBrewPinoDestination(config: PinoDestinationConfig): PinoDestinationHandle;
|
|
976
|
-
|
|
977
|
-
/** Convert a parsed Pino JSON log record into safe LogBrew log attributes without installing a destination. */
|
|
978
|
-
export declare function logAttributesFromPinoRecord(
|
|
979
|
-
record: PinoLogRecord,
|
|
980
|
-
options?: {
|
|
981
|
-
logger?: string;
|
|
982
|
-
metadata?: Metadata;
|
|
983
|
-
trace?: LogCorrelationTraceContext | null;
|
|
984
|
-
includeErrorStack?: boolean;
|
|
985
|
-
}
|
|
986
|
-
): LogAttributes;
|
|
987
|
-
|
|
988
|
-
/** Create a dependency-free Winston object-mode transport that queues LogBrew log events. */
|
|
989
|
-
export declare function createLogBrewWinstonTransport(config: WinstonTransportConfig): WinstonTransportHandle;
|
|
990
|
-
|
|
991
|
-
/** Convert a Winston info object into safe LogBrew log attributes without installing a transport. */
|
|
992
|
-
export declare function logAttributesFromWinstonInfo(
|
|
993
|
-
info: WinstonLogInfo,
|
|
994
|
-
options?: {
|
|
995
|
-
logger?: string;
|
|
996
|
-
metadata?: Metadata;
|
|
997
|
-
trace?: LogCorrelationTraceContext | null;
|
|
998
|
-
includeErrorStack?: boolean;
|
|
999
|
-
}
|
|
1000
|
-
): LogAttributes;
|
|
2
|
+
export * from "./index.js";
|
package/index.d.ts
CHANGED
|
@@ -357,6 +357,38 @@ export type IssueBreadcrumbInput = Omit<IssueBreadcrumb, "timestamp" | "level">
|
|
|
357
357
|
level?: IssueBreadcrumbLevelInput;
|
|
358
358
|
};
|
|
359
359
|
|
|
360
|
+
/** App-reported code location that narrows the smallest likely fix area. */
|
|
361
|
+
export type IssueLikelyFixArea = {
|
|
362
|
+
component?: string;
|
|
363
|
+
module?: string;
|
|
364
|
+
function?: string;
|
|
365
|
+
/** Safe repository-relative source path. */
|
|
366
|
+
file?: string;
|
|
367
|
+
line?: number;
|
|
368
|
+
column?: number;
|
|
369
|
+
inApp?: boolean;
|
|
370
|
+
};
|
|
371
|
+
|
|
372
|
+
/** App-reported user impact without user identities or raw request data. */
|
|
373
|
+
export type IssueImpactEvidence = {
|
|
374
|
+
affectedUserSegment?: string;
|
|
375
|
+
failedAction?: string;
|
|
376
|
+
userVisibleOutcome?: string;
|
|
377
|
+
};
|
|
378
|
+
|
|
379
|
+
/** Explicit diagnostic evidence for cause, fix area, impact, and capture limitations. */
|
|
380
|
+
export type IssueDiagnosticEvidence = {
|
|
381
|
+
/** App-owned hypothesis. LogBrew presents it as reported, never proven. */
|
|
382
|
+
likelyRootCause?: string;
|
|
383
|
+
likelyFixArea?: IssueLikelyFixArea;
|
|
384
|
+
impact?: IssueImpactEvidence;
|
|
385
|
+
/** Unique bounded field names whose values were captured. */
|
|
386
|
+
capturedFields?: string[];
|
|
387
|
+
missingFields?: string[];
|
|
388
|
+
redactedFields?: string[];
|
|
389
|
+
truncatedFields?: string[];
|
|
390
|
+
};
|
|
391
|
+
|
|
360
392
|
/** Public issue event attributes. */
|
|
361
393
|
export type IssueAttributes = {
|
|
362
394
|
title: string;
|
|
@@ -371,6 +403,8 @@ export type IssueAttributes = {
|
|
|
371
403
|
breadcrumbs?: IssueBreadcrumb[];
|
|
372
404
|
/** True when older or invalid history was omitted before capture. */
|
|
373
405
|
breadcrumbsTruncated?: boolean;
|
|
406
|
+
/** App-reported diagnostic evidence, validated and labeled separately from observed facts. */
|
|
407
|
+
evidence?: IssueDiagnosticEvidence;
|
|
374
408
|
metadata?: Metadata;
|
|
375
409
|
context?: TelemetryContext;
|
|
376
410
|
};
|
|
@@ -403,6 +437,8 @@ export type JavaScriptErrorIssueOptions = {
|
|
|
403
437
|
debugIdMap?: Record<string, string>;
|
|
404
438
|
/** Optional stable app-owned grouping fingerprint. Keep it safe and low-cardinality. */
|
|
405
439
|
fingerprint?: string;
|
|
440
|
+
/** App-reported cause, fix-area, impact, and explicit evidence-state receipt. */
|
|
441
|
+
evidence?: IssueDiagnosticEvidence;
|
|
406
442
|
/** Include raw stack text only when the app has explicitly approved it. Defaults to false. */
|
|
407
443
|
includeErrorStack?: boolean;
|
|
408
444
|
};
|
package/issue-diagnostics.cjs
CHANGED
|
@@ -10,8 +10,13 @@ const MAX_BREADCRUMB_NAME_LENGTH = 64;
|
|
|
10
10
|
const MAX_BREADCRUMB_MESSAGE_LENGTH = 512;
|
|
11
11
|
const MAX_BREADCRUMB_DATA_FIELDS = 8;
|
|
12
12
|
const MAX_BREADCRUMB_DATA_STRING_LENGTH = 256;
|
|
13
|
+
const MAX_DIAGNOSTIC_IDENTITY_LENGTH = 256;
|
|
14
|
+
const MAX_DIAGNOSTIC_CAUSE_LENGTH = 1024;
|
|
15
|
+
const MAX_DIAGNOSTIC_OUTCOME_LENGTH = 512;
|
|
16
|
+
const MAX_DIAGNOSTIC_FIELDS = 32;
|
|
13
17
|
const MACHINE_NAME_PATTERN = /^[A-Za-z][A-Za-z0-9_.:-]{0,63}$/u;
|
|
14
18
|
const DATA_KEY_PATTERN = /^[A-Za-z][A-Za-z0-9_.-]{0,63}$/u;
|
|
19
|
+
const EVIDENCE_FIELD_PATTERN = /^[A-Za-z0-9][A-Za-z0-9_.-]{0,63}$/u;
|
|
15
20
|
const BREADCRUMB_LEVEL_ALIASES = new Map([
|
|
16
21
|
["trace", "debug"],
|
|
17
22
|
["debug", "debug"],
|
|
@@ -257,6 +262,7 @@ function buildIssueDiagnosticsHelpers({ SdkError, requireTimestamp, validateIssu
|
|
|
257
262
|
attributes.stackFrames
|
|
258
263
|
);
|
|
259
264
|
const breadcrumbs = validateIssueBreadcrumbs(attributes.breadcrumbs);
|
|
265
|
+
const evidence = validateIssueEvidence(attributes.evidence);
|
|
260
266
|
if (
|
|
261
267
|
attributes.breadcrumbsTruncated !== undefined
|
|
262
268
|
&& typeof attributes.breadcrumbsTruncated !== "boolean"
|
|
@@ -267,7 +273,8 @@ function buildIssueDiagnosticsHelpers({ SdkError, requireTimestamp, validateIssu
|
|
|
267
273
|
...(exception === undefined ? {} : { exception }),
|
|
268
274
|
...(exceptionChain === undefined ? {} : { exceptionChain }),
|
|
269
275
|
...(breadcrumbs === undefined ? {} : { breadcrumbs }),
|
|
270
|
-
...(attributes.breadcrumbsTruncated === true ? { breadcrumbsTruncated: true } : {})
|
|
276
|
+
...(attributes.breadcrumbsTruncated === true ? { breadcrumbsTruncated: true } : {}),
|
|
277
|
+
...(evidence === undefined ? {} : { evidence })
|
|
271
278
|
};
|
|
272
279
|
}
|
|
273
280
|
|
|
@@ -304,9 +311,175 @@ function buildIssueDiagnosticsHelpers({ SdkError, requireTimestamp, validateIssu
|
|
|
304
311
|
if (attributes.breadcrumbsTruncated === true) {
|
|
305
312
|
diagnostics.breadcrumbsTruncated = true;
|
|
306
313
|
}
|
|
314
|
+
if (attributes.evidence !== undefined) {
|
|
315
|
+
diagnostics.evidence = cloneIssueEvidence(attributes.evidence);
|
|
316
|
+
}
|
|
307
317
|
return diagnostics;
|
|
308
318
|
}
|
|
309
319
|
|
|
320
|
+
function validateIssueEvidence(evidence) {
|
|
321
|
+
if (evidence === undefined) {
|
|
322
|
+
return undefined;
|
|
323
|
+
}
|
|
324
|
+
requireObject("issue evidence", evidence);
|
|
325
|
+
const fieldKeys = ["capturedFields", "missingFields", "redactedFields", "truncatedFields"];
|
|
326
|
+
rejectUnknownKeys(
|
|
327
|
+
"issue evidence",
|
|
328
|
+
evidence,
|
|
329
|
+
new Set(["likelyRootCause", "likelyFixArea", "impact", ...fieldKeys])
|
|
330
|
+
);
|
|
331
|
+
const likelyRootCause = evidence.likelyRootCause === undefined
|
|
332
|
+
? undefined
|
|
333
|
+
: boundedText(
|
|
334
|
+
"issue evidence likelyRootCause",
|
|
335
|
+
evidence.likelyRootCause,
|
|
336
|
+
MAX_DIAGNOSTIC_CAUSE_LENGTH
|
|
337
|
+
).trim();
|
|
338
|
+
const likelyFixArea = validateLikelyFixArea(evidence.likelyFixArea);
|
|
339
|
+
const impact = validateImpactEvidence(evidence.impact);
|
|
340
|
+
const fieldLists = Object.fromEntries(
|
|
341
|
+
fieldKeys.map((key) => [key, validateEvidenceFields(key, evidence[key])])
|
|
342
|
+
);
|
|
343
|
+
const present = new Set();
|
|
344
|
+
for (const key of fieldKeys) {
|
|
345
|
+
for (const field of fieldLists[key] ?? []) {
|
|
346
|
+
if (present.has(field)) {
|
|
347
|
+
throw validationError(`issue evidence field ${field} has conflicting states`);
|
|
348
|
+
}
|
|
349
|
+
present.add(field);
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
const validated = {
|
|
353
|
+
...(likelyRootCause === undefined ? {} : { likelyRootCause }),
|
|
354
|
+
...(likelyFixArea === undefined ? {} : { likelyFixArea }),
|
|
355
|
+
...(impact === undefined ? {} : { impact }),
|
|
356
|
+
...Object.fromEntries(fieldKeys.flatMap((key) => fieldLists[key] === undefined ? [] : [[key, fieldLists[key]]]))
|
|
357
|
+
};
|
|
358
|
+
if (Object.keys(validated).length === 0) {
|
|
359
|
+
throw validationError("issue evidence must contain at least one field");
|
|
360
|
+
}
|
|
361
|
+
return validated;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
function validateLikelyFixArea(area) {
|
|
365
|
+
if (area === undefined) {
|
|
366
|
+
return undefined;
|
|
367
|
+
}
|
|
368
|
+
requireObject("issue evidence likelyFixArea", area);
|
|
369
|
+
rejectUnknownKeys(
|
|
370
|
+
"issue evidence likelyFixArea",
|
|
371
|
+
area,
|
|
372
|
+
new Set(["component", "module", "function", "file", "line", "column", "inApp"])
|
|
373
|
+
);
|
|
374
|
+
const validated = {};
|
|
375
|
+
for (const key of ["component", "module", "function"]) {
|
|
376
|
+
if (area[key] !== undefined) {
|
|
377
|
+
validated[key] = boundedText(
|
|
378
|
+
`issue evidence likelyFixArea ${key}`,
|
|
379
|
+
area[key],
|
|
380
|
+
MAX_DIAGNOSTIC_IDENTITY_LENGTH,
|
|
381
|
+
{ rejectLocationText: true }
|
|
382
|
+
).trim();
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
if (area.file !== undefined) {
|
|
386
|
+
validated.file = safeRelativeSourcePath(area.file);
|
|
387
|
+
}
|
|
388
|
+
for (const key of ["line", "column"]) {
|
|
389
|
+
if (area[key] !== undefined) {
|
|
390
|
+
if (!Number.isInteger(area[key]) || area[key] < 1 || area[key] > 2147483647) {
|
|
391
|
+
throw validationError(`issue evidence likelyFixArea ${key} must be a positive integer`);
|
|
392
|
+
}
|
|
393
|
+
validated[key] = area[key];
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
if (area.inApp !== undefined) {
|
|
397
|
+
if (typeof area.inApp !== "boolean") {
|
|
398
|
+
throw validationError("issue evidence likelyFixArea inApp must be a boolean");
|
|
399
|
+
}
|
|
400
|
+
validated.inApp = area.inApp;
|
|
401
|
+
}
|
|
402
|
+
if (!Object.keys(validated).some((key) => key !== "inApp")) {
|
|
403
|
+
throw validationError("issue evidence likelyFixArea must identify a code location");
|
|
404
|
+
}
|
|
405
|
+
return validated;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
function validateImpactEvidence(impact) {
|
|
409
|
+
if (impact === undefined) {
|
|
410
|
+
return undefined;
|
|
411
|
+
}
|
|
412
|
+
requireObject("issue evidence impact", impact);
|
|
413
|
+
rejectUnknownKeys(
|
|
414
|
+
"issue evidence impact",
|
|
415
|
+
impact,
|
|
416
|
+
new Set(["affectedUserSegment", "failedAction", "userVisibleOutcome"])
|
|
417
|
+
);
|
|
418
|
+
const validated = {};
|
|
419
|
+
for (const key of ["affectedUserSegment", "failedAction"]) {
|
|
420
|
+
if (impact[key] !== undefined) {
|
|
421
|
+
validated[key] = boundedText(
|
|
422
|
+
`issue evidence impact ${key}`,
|
|
423
|
+
impact[key],
|
|
424
|
+
MAX_DIAGNOSTIC_IDENTITY_LENGTH,
|
|
425
|
+
{ rejectLocationText: true }
|
|
426
|
+
).trim();
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
if (impact.userVisibleOutcome !== undefined) {
|
|
430
|
+
validated.userVisibleOutcome = boundedText(
|
|
431
|
+
"issue evidence impact userVisibleOutcome",
|
|
432
|
+
impact.userVisibleOutcome,
|
|
433
|
+
MAX_DIAGNOSTIC_OUTCOME_LENGTH
|
|
434
|
+
).trim();
|
|
435
|
+
}
|
|
436
|
+
if (Object.keys(validated).length === 0) {
|
|
437
|
+
throw validationError("issue evidence impact must contain at least one field");
|
|
438
|
+
}
|
|
439
|
+
return validated;
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
function validateEvidenceFields(key, fields) {
|
|
443
|
+
if (fields === undefined) {
|
|
444
|
+
return undefined;
|
|
445
|
+
}
|
|
446
|
+
if (!Array.isArray(fields) || fields.length < 1 || fields.length > MAX_DIAGNOSTIC_FIELDS) {
|
|
447
|
+
throw validationError(`issue evidence ${key} must contain 1-${MAX_DIAGNOSTIC_FIELDS} fields`);
|
|
448
|
+
}
|
|
449
|
+
const unique = new Set(fields);
|
|
450
|
+
if (unique.size !== fields.length || fields.some((field) => typeof field !== "string" || !EVIDENCE_FIELD_PATTERN.test(field))) {
|
|
451
|
+
throw validationError(`issue evidence ${key} fields must be unique bounded identifiers`);
|
|
452
|
+
}
|
|
453
|
+
return [...fields];
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
function safeRelativeSourcePath(value) {
|
|
457
|
+
const path = boundedText(
|
|
458
|
+
"issue evidence likelyFixArea file",
|
|
459
|
+
value,
|
|
460
|
+
MAX_DIAGNOSTIC_IDENTITY_LENGTH,
|
|
461
|
+
{ rejectLocationText: true }
|
|
462
|
+
).trim().replaceAll("\\", "/");
|
|
463
|
+
const parts = path.split("/");
|
|
464
|
+
if (path.startsWith("/") || /^[A-Za-z]:\//u.test(path) || path.includes("://")
|
|
465
|
+
|| parts.some((part) => part === "" || part === "." || part === "..")) {
|
|
466
|
+
throw validationError("issue evidence likelyFixArea file must be a safe relative path");
|
|
467
|
+
}
|
|
468
|
+
return path;
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
function cloneIssueEvidence(evidence) {
|
|
472
|
+
return {
|
|
473
|
+
...evidence,
|
|
474
|
+
...(evidence.likelyFixArea === undefined ? {} : { likelyFixArea: { ...evidence.likelyFixArea } }),
|
|
475
|
+
...(evidence.impact === undefined ? {} : { impact: { ...evidence.impact } }),
|
|
476
|
+
...Object.fromEntries(
|
|
477
|
+
["capturedFields", "missingFields", "redactedFields", "truncatedFields"]
|
|
478
|
+
.flatMap((key) => evidence[key] === undefined ? [] : [[key, [...evidence[key]]]])
|
|
479
|
+
)
|
|
480
|
+
};
|
|
481
|
+
}
|
|
482
|
+
|
|
310
483
|
function validateBreadcrumbData(data) {
|
|
311
484
|
if (data === undefined) {
|
|
312
485
|
return undefined;
|
|
@@ -411,7 +584,8 @@ function buildIssueDiagnosticsHelpers({ SdkError, requireTimestamp, validateIssu
|
|
|
411
584
|
cloneIssueDiagnostics,
|
|
412
585
|
createIssueException,
|
|
413
586
|
validateIssueBreadcrumb,
|
|
414
|
-
validateIssueDiagnostics
|
|
587
|
+
validateIssueDiagnostics,
|
|
588
|
+
validateIssueEvidence
|
|
415
589
|
};
|
|
416
590
|
}
|
|
417
591
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@logbrew/sdk",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.14",
|
|
4
4
|
"description": "Public LogBrew JavaScript SDK for building, validating, and flushing event batches.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./index.cjs",
|
|
@@ -86,7 +86,7 @@
|
|
|
86
86
|
"url": "git+https://github.com/LogBrewCo/sdk.git"
|
|
87
87
|
},
|
|
88
88
|
"scripts": {
|
|
89
|
-
"test": "
|
|
90
|
-
"smoke": "
|
|
89
|
+
"test": "bun test",
|
|
90
|
+
"smoke": "bun ./smoke.js"
|
|
91
91
|
}
|
|
92
92
|
}
|