@belvador/core 0.1.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/aborts.d.ts +12 -0
- package/dist/aborts.js +74 -0
- package/dist/constants.d.ts +15 -0
- package/dist/constants.js +18 -0
- package/dist/diagnostics.d.ts +60 -0
- package/dist/diagnostics.js +139 -0
- package/dist/facade.d.ts +3 -0
- package/dist/facade.js +9 -0
- package/dist/index.d.ts +9 -2
- package/dist/index.js +9 -2
- package/dist/monitor.d.ts +89 -0
- package/dist/monitor.js +330 -0
- package/dist/options.d.ts +26 -0
- package/dist/options.js +57 -8
- package/dist/privacy.d.ts +1 -1
- package/dist/privacy.js +25 -5
- package/dist/trace.d.ts +32 -0
- package/dist/trace.js +184 -0
- package/dist/transport.d.ts +9 -0
- package/dist/transport.js +106 -3
- package/dist/verification.d.ts +51 -0
- package/dist/verification.js +87 -0
- package/dist/verify.d.ts +47 -0
- package/dist/verify.js +180 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
package/dist/aborts.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/** Errors whose own name, or whose direct cause's name, is "AbortError". */
|
|
2
|
+
export declare function isAbortError(error: unknown): boolean;
|
|
3
|
+
/**
|
|
4
|
+
* Called by Belvador's server middleware and Worker wrapper when a request fails after its
|
|
5
|
+
* client went away (`request.signal.aborted`): whatever was thrown is then treated as an
|
|
6
|
+
* abort, even when it is not named AbortError (stream "terminated", "aborted", …).
|
|
7
|
+
*/
|
|
8
|
+
export declare function noteClientAbort(error: unknown, signal: AbortSignal | null | undefined): void;
|
|
9
|
+
/** True for an AbortError or an error thrown while its request's client had gone. */
|
|
10
|
+
export declare function isClientAbort(error: unknown): boolean;
|
|
11
|
+
/** A DOMException (AbortError/InvalidStateError) with a standard View Transition message. */
|
|
12
|
+
export declare function isViewTransitionSkip(error: unknown): boolean;
|
package/dist/aborts.js
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
// Client-cancelled work is expected, not a failure (integration-health 05-decisions,
|
|
2
|
+
// Supaclip finding): a user who closes the tab or navigates away aborts in-flight
|
|
3
|
+
// requests, and the server code serving them throws. These are dropped by default;
|
|
4
|
+
// `captureAborted: true` reports them again. Imports nothing (runs in every runtime).
|
|
5
|
+
/** Errors whose own name, or whose direct cause's name, is "AbortError". */
|
|
6
|
+
export function isAbortError(error) {
|
|
7
|
+
try {
|
|
8
|
+
if (nameOf(error) === "AbortError")
|
|
9
|
+
return true;
|
|
10
|
+
if (error !== null && typeof error === "object" && "cause" in error)
|
|
11
|
+
return nameOf(error.cause) === "AbortError";
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
/* a hostile getter: not an abort */
|
|
15
|
+
}
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
function nameOf(value) {
|
|
19
|
+
return value !== null && typeof value === "object" ? value.name : undefined;
|
|
20
|
+
}
|
|
21
|
+
const clientAborted = new WeakSet();
|
|
22
|
+
/**
|
|
23
|
+
* Called by Belvador's server middleware and Worker wrapper when a request fails after its
|
|
24
|
+
* client went away (`request.signal.aborted`): whatever was thrown is then treated as an
|
|
25
|
+
* abort, even when it is not named AbortError (stream "terminated", "aborted", …).
|
|
26
|
+
*/
|
|
27
|
+
export function noteClientAbort(error, signal) {
|
|
28
|
+
try {
|
|
29
|
+
if (signal?.aborted === true && error !== null && typeof error === "object")
|
|
30
|
+
clientAborted.add(error);
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
/* never throws into the app */
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
/** True for an AbortError or an error thrown while its request's client had gone. */
|
|
37
|
+
export function isClientAbort(error) {
|
|
38
|
+
if (isAbortError(error))
|
|
39
|
+
return true;
|
|
40
|
+
return error !== null && typeof error === "object" && clientAborted.has(error);
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Messages browsers give a View Transition that was skipped or aborted on purpose
|
|
44
|
+
* (observability-1.0 spec 03 §8): the page was hidden, another transition started, the
|
|
45
|
+
* viewport changed, or `skipTransition()` was called. Exact texts of Chromium, WebKit and
|
|
46
|
+
* Gecko, matched whole — never a broad pattern.
|
|
47
|
+
*/
|
|
48
|
+
const VIEW_TRANSITION_MESSAGES = [
|
|
49
|
+
/^Transition was skipped$/,
|
|
50
|
+
/^Transition was aborted because of invalid state$/,
|
|
51
|
+
/^Skipped ViewTransition due to (?:document being hidden|another transition starting|hidden document|viewport size change)\.?$/,
|
|
52
|
+
/^Skipping view transition because (?:document visibility state has become hidden|viewport size changed|the document is hidden|another transition started)\.?$/,
|
|
53
|
+
/^The (?:previous|old) transition was skipped(?: because a new transition started)?\.?$/,
|
|
54
|
+
/^View transition was skipped because document visibility state is hidden\.?$/,
|
|
55
|
+
];
|
|
56
|
+
/** A DOMException (AbortError/InvalidStateError) with a standard View Transition message. */
|
|
57
|
+
export function isViewTransitionSkip(error) {
|
|
58
|
+
try {
|
|
59
|
+
if (error === null || typeof error !== "object")
|
|
60
|
+
return false;
|
|
61
|
+
const name = error.name;
|
|
62
|
+
const message = error.message;
|
|
63
|
+
if (name !== "AbortError" && name !== "InvalidStateError")
|
|
64
|
+
return false;
|
|
65
|
+
if (typeof message !== "string")
|
|
66
|
+
return false;
|
|
67
|
+
if (typeof DOMException !== "undefined" && !(error instanceof DOMException))
|
|
68
|
+
return false;
|
|
69
|
+
return VIEW_TRANSITION_MESSAGES.some((re) => re.test(message.trim()));
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/** Reserved tag key; its value is the verification id. */
|
|
2
|
+
export declare const VERIFICATION_TAG = "belvador.verification";
|
|
3
|
+
/** Context the SDK adds to a verification event. */
|
|
4
|
+
export declare const VERIFICATION_CONTEXT = "belvador_verification";
|
|
5
|
+
/** Exception type a verification captures or throws. */
|
|
6
|
+
export declare const VERIFICATION_ERROR_TYPE = "BelvadorVerificationError";
|
|
7
|
+
/** `bv1_` + 32 lowercase hex. */
|
|
8
|
+
export declare const VERIFICATION_ID_RE: RegExp;
|
|
9
|
+
export declare const VERIFY_LIMITS: {
|
|
10
|
+
readonly timeoutDefaultMs: 20000;
|
|
11
|
+
readonly timeoutMaxMs: 30000;
|
|
12
|
+
readonly readbackMaxRequests: 10;
|
|
13
|
+
/** Waits between read-backs; the last value repeats. */
|
|
14
|
+
readonly readbackDelaysMs: readonly number[];
|
|
15
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// Integration-health wire constants (build integration-health-1.0 spec 01/02), a copy
|
|
2
|
+
// of `src/shared/contracts/integration-health.ts` that a root test keeps equal.
|
|
3
|
+
// Imports nothing.
|
|
4
|
+
/** Reserved tag key; its value is the verification id. */
|
|
5
|
+
export const VERIFICATION_TAG = "belvador.verification";
|
|
6
|
+
/** Context the SDK adds to a verification event. */
|
|
7
|
+
export const VERIFICATION_CONTEXT = "belvador_verification";
|
|
8
|
+
/** Exception type a verification captures or throws. */
|
|
9
|
+
export const VERIFICATION_ERROR_TYPE = "BelvadorVerificationError";
|
|
10
|
+
/** `bv1_` + 32 lowercase hex. */
|
|
11
|
+
export const VERIFICATION_ID_RE = /^bv1_[0-9a-f]{32}$/;
|
|
12
|
+
export const VERIFY_LIMITS = {
|
|
13
|
+
timeoutDefaultMs: 20000,
|
|
14
|
+
timeoutMaxMs: 30000,
|
|
15
|
+
readbackMaxRequests: 10,
|
|
16
|
+
/** Waits between read-backs; the last value repeats. */
|
|
17
|
+
readbackDelaysMs: [1000, 2000, 3000, 4000, 5000],
|
|
18
|
+
};
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
export declare const DIAGNOSTIC_CODES: readonly ["BLV_DSN_MISSING", "BLV_DSN_INVALID", "BLV_INIT_CONFLICT", "BLV_NOT_INITIALIZED", "BLV_SEND_UNAUTHORIZED", "BLV_SEND_RATE_LIMITED", "BLV_SEND_REJECTED", "BLV_SEND_NETWORK", "BLV_SEND_SERVER", "BLV_QUEUE_FULL", "BLV_EVENT_TOO_LARGE", "BLV_HOOK_MISSING", "BLV_DROPPED_BY_APP", "BLV_MONITOR_INVALID_SLUG", "BLV_MONITOR_INVALID_REASON", "BLV_MONITOR_CONFIG_INVALID", "BLV_CHECK_IN_DROPPED", "BLV_TRACE_TARGET_INVALID"];
|
|
2
|
+
export type DiagnosticCode = (typeof DIAGNOSTIC_CODES)[number];
|
|
3
|
+
/** Public page explaining every code and the verification (one anchor per code). */
|
|
4
|
+
export declare const VERIFY_DOCS_URL = "https://belvador.dev/en/docs/sdk/verify";
|
|
5
|
+
/** One callback/console line per code per interval; repeats add to `count`. */
|
|
6
|
+
export declare const DIAGNOSTIC_INTERVAL_MS = 60000;
|
|
7
|
+
export type Diagnostic = {
|
|
8
|
+
code: DiagnosticCode;
|
|
9
|
+
/** Epoch ms of this report. */
|
|
10
|
+
at: number;
|
|
11
|
+
/** Occurrences since the previous report of this code (≥ 1). */
|
|
12
|
+
count: number;
|
|
13
|
+
/** HTTP status of the send, when there was one. */
|
|
14
|
+
status?: number;
|
|
15
|
+
/** Seconds the edge asked to wait (429). */
|
|
16
|
+
retryAfterS?: number;
|
|
17
|
+
};
|
|
18
|
+
export type DiagnosticsSnapshot = {
|
|
19
|
+
active: boolean;
|
|
20
|
+
sdk: {
|
|
21
|
+
name: string;
|
|
22
|
+
version: string;
|
|
23
|
+
};
|
|
24
|
+
/** Host, project and the first 4 characters of the key — never the whole DSN. */
|
|
25
|
+
dsn: {
|
|
26
|
+
host: string;
|
|
27
|
+
project: number;
|
|
28
|
+
keyHint: string;
|
|
29
|
+
} | null;
|
|
30
|
+
lastSend: {
|
|
31
|
+
status: number | "network";
|
|
32
|
+
at: number;
|
|
33
|
+
} | null;
|
|
34
|
+
counts: Partial<Record<DiagnosticCode, number>>;
|
|
35
|
+
};
|
|
36
|
+
type Config = {
|
|
37
|
+
onDiagnostic: ((d: Diagnostic) => void) | undefined;
|
|
38
|
+
debug: boolean;
|
|
39
|
+
sdk: {
|
|
40
|
+
name: string;
|
|
41
|
+
version: string;
|
|
42
|
+
};
|
|
43
|
+
dsn: DiagnosticsSnapshot["dsn"];
|
|
44
|
+
};
|
|
45
|
+
/** Anchor on the verification page for one code. */
|
|
46
|
+
export declare function diagnosticDocsUrl(code: DiagnosticCode): string;
|
|
47
|
+
export declare function diagnosticMessage(code: DiagnosticCode): string;
|
|
48
|
+
/** Set by init (and by every Worker invocation). Never throws. */
|
|
49
|
+
export declare function configureDiagnostics(next: Partial<Config>): void;
|
|
50
|
+
/** Records one occurrence; reports at most once per code per minute (NOT_INITIALIZED once). */
|
|
51
|
+
export declare function reportDiagnostic(code: DiagnosticCode, extra?: {
|
|
52
|
+
status?: number;
|
|
53
|
+
retryAfterS?: number;
|
|
54
|
+
}, now?: number): void;
|
|
55
|
+
export declare function noteSend(status: number | "network", now?: number): void;
|
|
56
|
+
/** Fixed-size snapshot for support and AI agents; contains no event data. */
|
|
57
|
+
export declare function snapshotDiagnostics(active: boolean): DiagnosticsSnapshot;
|
|
58
|
+
/** Tests only: forget every count and setting. */
|
|
59
|
+
export declare function resetDiagnostics(): void;
|
|
60
|
+
export {};
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
// Local diagnostics (build integration-health-1.0 spec 02 §2): what went wrong in
|
|
2
|
+
// this app, said once per minute per code, never sent anywhere. The code list is a
|
|
3
|
+
// copy of `src/shared/contracts/integration-health.ts`; a root test keeps them equal.
|
|
4
|
+
// Imports nothing.
|
|
5
|
+
export const DIAGNOSTIC_CODES = [
|
|
6
|
+
"BLV_DSN_MISSING",
|
|
7
|
+
"BLV_DSN_INVALID",
|
|
8
|
+
"BLV_INIT_CONFLICT",
|
|
9
|
+
"BLV_NOT_INITIALIZED",
|
|
10
|
+
"BLV_SEND_UNAUTHORIZED",
|
|
11
|
+
"BLV_SEND_RATE_LIMITED",
|
|
12
|
+
"BLV_SEND_REJECTED",
|
|
13
|
+
"BLV_SEND_NETWORK",
|
|
14
|
+
"BLV_SEND_SERVER",
|
|
15
|
+
"BLV_QUEUE_FULL",
|
|
16
|
+
"BLV_EVENT_TOO_LARGE",
|
|
17
|
+
"BLV_HOOK_MISSING",
|
|
18
|
+
"BLV_DROPPED_BY_APP",
|
|
19
|
+
"BLV_MONITOR_INVALID_SLUG",
|
|
20
|
+
"BLV_MONITOR_INVALID_REASON",
|
|
21
|
+
"BLV_MONITOR_CONFIG_INVALID",
|
|
22
|
+
"BLV_CHECK_IN_DROPPED",
|
|
23
|
+
"BLV_TRACE_TARGET_INVALID",
|
|
24
|
+
];
|
|
25
|
+
/** Public page explaining every code and the verification (one anchor per code). */
|
|
26
|
+
export const VERIFY_DOCS_URL = "https://belvador.dev/en/docs/sdk/verify";
|
|
27
|
+
/** One callback/console line per code per interval; repeats add to `count`. */
|
|
28
|
+
export const DIAGNOSTIC_INTERVAL_MS = 60000;
|
|
29
|
+
const MESSAGES = {
|
|
30
|
+
BLV_DSN_MISSING: "no DSN — the SDK is off",
|
|
31
|
+
BLV_DSN_INVALID: "the DSN is not valid — the SDK is off",
|
|
32
|
+
BLV_INIT_CONFLICT: "another error-tracking client is already running — init skipped",
|
|
33
|
+
BLV_NOT_INITIALIZED: "capture called while the SDK is not running",
|
|
34
|
+
BLV_SEND_UNAUTHORIZED: "the DSN key was refused (revoked or wrong project) — sending stopped",
|
|
35
|
+
BLV_SEND_RATE_LIMITED: "rate limited by Belvador — events are dropped until the wait ends",
|
|
36
|
+
BLV_SEND_REJECTED: "an event was rejected (too large or not accepted)",
|
|
37
|
+
BLV_SEND_NETWORK: "Belvador could not be reached after retries (network, CSP or ad blocker)",
|
|
38
|
+
BLV_SEND_SERVER: "Belvador answered with a server error after retries",
|
|
39
|
+
BLV_QUEUE_FULL: "the send queue is full — an event was dropped",
|
|
40
|
+
BLV_EVENT_TOO_LARGE: "an event or attachment is over the size limit — dropped",
|
|
41
|
+
BLV_HOOK_MISSING: "this server code does not run inside Belvador's middleware or wrapper",
|
|
42
|
+
BLV_DROPPED_BY_APP: "the event was dropped before sending (beforeSend, ignoreErrors or sampleRate)",
|
|
43
|
+
BLV_MONITOR_INVALID_SLUG: "a monitor slug is not valid (lowercase letters, digits, - and _, at most 64) — no check-in was sent",
|
|
44
|
+
BLV_MONITOR_INVALID_REASON: "a run reason is not a short code (lowercase letters, digits, . - _, at most 64) — it was left out",
|
|
45
|
+
BLV_MONITOR_CONFIG_INVALID: "a monitor schedule or setting is not valid — the check-in was sent without it",
|
|
46
|
+
BLV_CHECK_IN_DROPPED: "a check-in was dropped (too many waiting, rate limited or not sent)",
|
|
47
|
+
BLV_TRACE_TARGET_INVALID: "a tracePropagation target is not a string or RegExp — it was ignored",
|
|
48
|
+
};
|
|
49
|
+
const config = {
|
|
50
|
+
onDiagnostic: undefined,
|
|
51
|
+
debug: false,
|
|
52
|
+
sdk: { name: "", version: "" },
|
|
53
|
+
dsn: null,
|
|
54
|
+
};
|
|
55
|
+
const perCode = new Map();
|
|
56
|
+
let lastSend = null;
|
|
57
|
+
/** Anchor on the verification page for one code. */
|
|
58
|
+
export function diagnosticDocsUrl(code) {
|
|
59
|
+
return `${VERIFY_DOCS_URL}#${code.toLowerCase().replace(/_/g, "-")}`;
|
|
60
|
+
}
|
|
61
|
+
export function diagnosticMessage(code) {
|
|
62
|
+
return MESSAGES[code];
|
|
63
|
+
}
|
|
64
|
+
/** Set by init (and by every Worker invocation). Never throws. */
|
|
65
|
+
export function configureDiagnostics(next) {
|
|
66
|
+
try {
|
|
67
|
+
Object.assign(config, next);
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
/* frozen input */
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
function emit(d) {
|
|
74
|
+
const cb = config.onDiagnostic;
|
|
75
|
+
if (cb) {
|
|
76
|
+
try {
|
|
77
|
+
cb({ ...d });
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
/* a failing callback never reaches the app or the SDK */
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
if (config.debug) {
|
|
84
|
+
try {
|
|
85
|
+
console.warn(`[belvador] ${d.code}: ${MESSAGES[d.code]} — ${diagnosticDocsUrl(d.code)}`);
|
|
86
|
+
}
|
|
87
|
+
catch {
|
|
88
|
+
/* no console */
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
/** Records one occurrence; reports at most once per code per minute (NOT_INITIALIZED once). */
|
|
93
|
+
export function reportDiagnostic(code, extra = {}, now = Date.now()) {
|
|
94
|
+
try {
|
|
95
|
+
const s = perCode.get(code) ?? { last: -Infinity, pending: 0, total: 0 };
|
|
96
|
+
s.total++;
|
|
97
|
+
s.pending++;
|
|
98
|
+
perCode.set(code, s);
|
|
99
|
+
const once = code === "BLV_NOT_INITIALIZED";
|
|
100
|
+
if (once ? s.total > 1 : now - s.last < DIAGNOSTIC_INTERVAL_MS)
|
|
101
|
+
return;
|
|
102
|
+
const d = { code, at: now, count: s.pending };
|
|
103
|
+
if (extra.status !== undefined)
|
|
104
|
+
d.status = extra.status;
|
|
105
|
+
if (extra.retryAfterS !== undefined)
|
|
106
|
+
d.retryAfterS = extra.retryAfterS;
|
|
107
|
+
s.last = now;
|
|
108
|
+
s.pending = 0;
|
|
109
|
+
emit(d);
|
|
110
|
+
}
|
|
111
|
+
catch {
|
|
112
|
+
/* never throws */
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
export function noteSend(status, now = Date.now()) {
|
|
116
|
+
lastSend = { status, at: now };
|
|
117
|
+
}
|
|
118
|
+
/** Fixed-size snapshot for support and AI agents; contains no event data. */
|
|
119
|
+
export function snapshotDiagnostics(active) {
|
|
120
|
+
const counts = {};
|
|
121
|
+
for (const [code, s] of perCode)
|
|
122
|
+
counts[code] = s.total;
|
|
123
|
+
return {
|
|
124
|
+
active,
|
|
125
|
+
sdk: { ...config.sdk },
|
|
126
|
+
dsn: config.dsn ? { ...config.dsn } : null,
|
|
127
|
+
lastSend: lastSend ? { ...lastSend } : null,
|
|
128
|
+
counts,
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
/** Tests only: forget every count and setting. */
|
|
132
|
+
export function resetDiagnostics() {
|
|
133
|
+
perCode.clear();
|
|
134
|
+
lastSend = null;
|
|
135
|
+
config.onDiagnostic = undefined;
|
|
136
|
+
config.debug = false;
|
|
137
|
+
config.sdk = { name: "", version: "" };
|
|
138
|
+
config.dsn = null;
|
|
139
|
+
}
|
package/dist/facade.d.ts
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import type { Breadcrumb, ExclusiveEventHintOrCaptureContext, Scope, SeverityLevel } from "@sentry/core";
|
|
2
|
+
import { type DiagnosticsSnapshot } from "./diagnostics.js";
|
|
2
3
|
export type { Scope, SeverityLevel };
|
|
3
4
|
/** True when the current scope's client was set up by a Belvador `init`. */
|
|
4
5
|
export declare function isActive(): boolean;
|
|
6
|
+
/** Local diagnostics snapshot (integration-health spec 02 §2.2); no event data. */
|
|
7
|
+
export declare function getDiagnostics(): DiagnosticsSnapshot;
|
|
5
8
|
/** Returns the event id (not a delivery receipt); "" when the SDK is off. */
|
|
6
9
|
export declare function captureException(error: unknown, context?: ExclusiveEventHintOrCaptureContext): string;
|
|
7
10
|
export declare function captureMessage(message: string, level?: SeverityLevel): string;
|
package/dist/facade.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
// function is a no-op returning a neutral value when no Belvador client is
|
|
3
3
|
// active, and never throws into the app.
|
|
4
4
|
import { addBreadcrumb as engineAddBreadcrumb, captureException as engineCaptureException, captureMessage as engineCaptureMessage, close as engineClose, flush as engineFlush, getClient, lastEventId as engineLastEventId, setContext as engineSetContext, setTag as engineSetTag, setTags as engineSetTags, setUser as engineSetUser, withScope as engineWithScope, } from "@sentry/core";
|
|
5
|
+
import { reportDiagnostic, snapshotDiagnostics } from "./diagnostics.js";
|
|
5
6
|
import { BELVADOR_MARKER } from "./options.js";
|
|
6
7
|
/** True when the current scope's client was set up by a Belvador `init`. */
|
|
7
8
|
export function isActive() {
|
|
@@ -13,6 +14,10 @@ export function isActive() {
|
|
|
13
14
|
return false;
|
|
14
15
|
}
|
|
15
16
|
}
|
|
17
|
+
/** Local diagnostics snapshot (integration-health spec 02 §2.2); no event data. */
|
|
18
|
+
export function getDiagnostics() {
|
|
19
|
+
return snapshotDiagnostics(isActive());
|
|
20
|
+
}
|
|
16
21
|
function guard(fallback, fn) {
|
|
17
22
|
if (!isActive())
|
|
18
23
|
return fallback;
|
|
@@ -25,9 +30,13 @@ function guard(fallback, fn) {
|
|
|
25
30
|
}
|
|
26
31
|
/** Returns the event id (not a delivery receipt); "" when the SDK is off. */
|
|
27
32
|
export function captureException(error, context) {
|
|
33
|
+
if (!isActive())
|
|
34
|
+
reportDiagnostic("BLV_NOT_INITIALIZED");
|
|
28
35
|
return guard("", () => engineCaptureException(error, context));
|
|
29
36
|
}
|
|
30
37
|
export function captureMessage(message, level) {
|
|
38
|
+
if (!isActive())
|
|
39
|
+
reportDiagnostic("BLV_NOT_INITIALIZED");
|
|
31
40
|
return guard("", () => engineCaptureMessage(String(message), level));
|
|
32
41
|
}
|
|
33
42
|
export function addBreadcrumb(crumb) {
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
export { SDK_VERSION, ENGINE_VERSION } from "./version.js";
|
|
2
2
|
export { checkDsn, type BelvadorDsn } from "./dsn.js";
|
|
3
|
+
export { isAbortError, isClientAbort, isViewTransitionSkip, noteClientAbort } from "./aborts.js";
|
|
4
|
+
export { INTERVAL_UNITS, MONITOR_CONFIG_LIMITS, MONITOR_CONTEXT, MONITOR_SLUG_RE, RUN_CONTEXT, RUN_REASON_RE, buildCheckIn, captureCheckIn, heartbeat, monitorConfigOf, runIdOf, withMonitor, type CheckInInput, type IntervalUnit, type MonitorConfigInput, type MonitorSchedule, type RunHandle, type WithMonitorOptions, } from "./monitor.js";
|
|
5
|
+
export { TRACE_OPTION, installTracePropagation, sentryTraceFromTraceparent, traceConfigOf, urlMatches, withIncomingTraceparent, type TraceConfig, type TracePropagationOptions, } from "./trace.js";
|
|
3
6
|
export { FILTERED, SENSITIVE_KEY_PARTS, isSensitiveKey, scrubBreadcrumb, scrubEvent, scrubParams, scrubText, scrubValue, } from "./privacy.js";
|
|
4
|
-
export { SEND_LIMITS, SENT_ITEM_TYPES, filterEnvelope, makeBelvadorTransport, sendWithRetry, type FetchLike, type SendPolicy, type SendState, } from "./transport.js";
|
|
7
|
+
export { MAX_QUEUED_CHECK_INS, SEND_LIMITS, SENT_ITEM_TYPES, filterEnvelope, makeBelvadorTransport, sendWithRetry, type FetchLike, type SendPolicy, type SendState, } from "./transport.js";
|
|
5
8
|
export { BELVADOR_MARKER, DEFAULT_MAX_BREADCRUMBS, MAX_BREADCRUMBS, MAX_VALUE_LENGTH, buildEngineOptions, warnOnce, type BelvadorBreadcrumb, type BelvadorEvent, type BelvadorEventHint, type BelvadorOptions, type EngineOptions, type RuntimeName, } from "./options.js";
|
|
6
|
-
export { addBreadcrumb, captureException, captureMessage, close, flush, isActive, lastEventId, setContext, setTag, setTags, setUser, withScope, type Scope, type SeverityLevel, } from "./facade.js";
|
|
9
|
+
export { addBreadcrumb, captureException, captureMessage, close, flush, getDiagnostics, isActive, lastEventId, setContext, setTag, setTags, setUser, withScope, type Scope, type SeverityLevel, } from "./facade.js";
|
|
10
|
+
export { DIAGNOSTIC_CODES, DIAGNOSTIC_INTERVAL_MS, VERIFY_DOCS_URL, configureDiagnostics, diagnosticDocsUrl, diagnosticMessage, reportDiagnostic, resetDiagnostics, type Diagnostic, type DiagnosticCode, type DiagnosticsSnapshot, } from "./diagnostics.js";
|
|
11
|
+
export { BelvadorVerificationError, VERIFICATION_CONTEXT, VERIFICATION_ERROR_TYPE, VERIFICATION_ID_RE, VERIFICATION_TAG, currentHooks, markHooked, newVerificationId, verificationOf, type HookKind, type VerificationContext, type VerificationSurface, } from "./verification.js";
|
|
12
|
+
export { VERIFY_LIMITS, runVerification, type CheckName, type CheckStatus, type VerificationResult, type VerifyOptions, type VerifyRuntime, } from "./verify.js";
|
|
13
|
+
export { diagnosticForStatus } from "./transport.js";
|
package/dist/index.js
CHANGED
|
@@ -3,7 +3,14 @@
|
|
|
3
3
|
// /tanstack-start instead. Importing this module has no side effects.
|
|
4
4
|
export { SDK_VERSION, ENGINE_VERSION } from "./version.js";
|
|
5
5
|
export { checkDsn } from "./dsn.js";
|
|
6
|
+
export { isAbortError, isClientAbort, isViewTransitionSkip, noteClientAbort } from "./aborts.js";
|
|
7
|
+
export { INTERVAL_UNITS, MONITOR_CONFIG_LIMITS, MONITOR_CONTEXT, MONITOR_SLUG_RE, RUN_CONTEXT, RUN_REASON_RE, buildCheckIn, captureCheckIn, heartbeat, monitorConfigOf, runIdOf, withMonitor, } from "./monitor.js";
|
|
8
|
+
export { TRACE_OPTION, installTracePropagation, sentryTraceFromTraceparent, traceConfigOf, urlMatches, withIncomingTraceparent, } from "./trace.js";
|
|
6
9
|
export { FILTERED, SENSITIVE_KEY_PARTS, isSensitiveKey, scrubBreadcrumb, scrubEvent, scrubParams, scrubText, scrubValue, } from "./privacy.js";
|
|
7
|
-
export { SEND_LIMITS, SENT_ITEM_TYPES, filterEnvelope, makeBelvadorTransport, sendWithRetry, } from "./transport.js";
|
|
10
|
+
export { MAX_QUEUED_CHECK_INS, SEND_LIMITS, SENT_ITEM_TYPES, filterEnvelope, makeBelvadorTransport, sendWithRetry, } from "./transport.js";
|
|
8
11
|
export { BELVADOR_MARKER, DEFAULT_MAX_BREADCRUMBS, MAX_BREADCRUMBS, MAX_VALUE_LENGTH, buildEngineOptions, warnOnce, } from "./options.js";
|
|
9
|
-
export { addBreadcrumb, captureException, captureMessage, close, flush, isActive, lastEventId, setContext, setTag, setTags, setUser, withScope, } from "./facade.js";
|
|
12
|
+
export { addBreadcrumb, captureException, captureMessage, close, flush, getDiagnostics, isActive, lastEventId, setContext, setTag, setTags, setUser, withScope, } from "./facade.js";
|
|
13
|
+
export { DIAGNOSTIC_CODES, DIAGNOSTIC_INTERVAL_MS, VERIFY_DOCS_URL, configureDiagnostics, diagnosticDocsUrl, diagnosticMessage, reportDiagnostic, resetDiagnostics, } from "./diagnostics.js";
|
|
14
|
+
export { BelvadorVerificationError, VERIFICATION_CONTEXT, VERIFICATION_ERROR_TYPE, VERIFICATION_ID_RE, VERIFICATION_TAG, currentHooks, markHooked, newVerificationId, verificationOf, } from "./verification.js";
|
|
15
|
+
export { VERIFY_LIMITS, runVerification, } from "./verify.js";
|
|
16
|
+
export { diagnosticForStatus } from "./transport.js";
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import type { Client, SerializedCheckIn } from "@sentry/core";
|
|
2
|
+
export declare const MONITOR_SLUG_RE: RegExp;
|
|
3
|
+
export declare const RUN_REASON_RE: RegExp;
|
|
4
|
+
export declare const RUN_CONTEXT = "belvador_run";
|
|
5
|
+
export declare const MONITOR_CONTEXT = "monitor";
|
|
6
|
+
export declare const MONITOR_CONFIG_LIMITS: {
|
|
7
|
+
readonly intervalValueMax: 1000;
|
|
8
|
+
readonly checkinMarginMax: 1440;
|
|
9
|
+
readonly maxRuntimeMax: 10080;
|
|
10
|
+
readonly thresholdMax: 720;
|
|
11
|
+
readonly environmentMax: 64;
|
|
12
|
+
readonly attemptMax: 1000;
|
|
13
|
+
};
|
|
14
|
+
export declare const INTERVAL_UNITS: readonly ["minute", "hour", "day", "week", "month", "year"];
|
|
15
|
+
export type IntervalUnit = (typeof INTERVAL_UNITS)[number];
|
|
16
|
+
export type MonitorSchedule = {
|
|
17
|
+
type: "crontab";
|
|
18
|
+
value: string;
|
|
19
|
+
} | {
|
|
20
|
+
type: "interval";
|
|
21
|
+
value: number;
|
|
22
|
+
unit: IntervalUnit;
|
|
23
|
+
};
|
|
24
|
+
/** Settings sent as `monitor_config` (creates or updates the monitor from code). */
|
|
25
|
+
export type MonitorConfigInput = {
|
|
26
|
+
schedule: MonitorSchedule;
|
|
27
|
+
/** IANA time zone of a crontab, default UTC. */
|
|
28
|
+
timezone?: string;
|
|
29
|
+
/** Minutes a check-in may be late before it counts as missed (default 5). */
|
|
30
|
+
checkinMargin?: number;
|
|
31
|
+
/** Minutes a run may take before it counts as timed out (default 30). */
|
|
32
|
+
maxRuntime?: number;
|
|
33
|
+
/** Failing runs in a row before an incident opens (default 1). */
|
|
34
|
+
failureIssueThreshold?: number;
|
|
35
|
+
/** Healthy runs in a row before it closes (default 1). */
|
|
36
|
+
recoveryThreshold?: number;
|
|
37
|
+
};
|
|
38
|
+
export type WithMonitorOptions = Partial<MonitorConfigInput> & {
|
|
39
|
+
environment?: string;
|
|
40
|
+
/** Your id of the logical run (e.g. a queue message id); retries with the same id form one run. */
|
|
41
|
+
runId?: string;
|
|
42
|
+
/** 1 for the first try. */
|
|
43
|
+
attempt?: number;
|
|
44
|
+
/** True (or a function of the error) when your queue will try again after this error. */
|
|
45
|
+
willRetry?: boolean | ((error: unknown) => boolean);
|
|
46
|
+
};
|
|
47
|
+
export type RunHandle = {
|
|
48
|
+
readonly checkInId: string;
|
|
49
|
+
readonly runId: string;
|
|
50
|
+
/** The run did nothing on purpose (healthy). `reason` is a short code. */
|
|
51
|
+
skip(reason: string): void;
|
|
52
|
+
/** The run ended but its effect is unknown (e.g. a provider timed out after a side effect). */
|
|
53
|
+
unknown(reason: string): void;
|
|
54
|
+
};
|
|
55
|
+
export type CheckInInput = {
|
|
56
|
+
monitorSlug: string;
|
|
57
|
+
status: "in_progress" | "ok" | "error";
|
|
58
|
+
/** The id of the start check-in this one finishes; omitted = a new attempt. */
|
|
59
|
+
checkInId?: string;
|
|
60
|
+
/** Seconds. */
|
|
61
|
+
duration?: number;
|
|
62
|
+
environment?: string;
|
|
63
|
+
runId?: string;
|
|
64
|
+
attempt?: number;
|
|
65
|
+
willRetry?: boolean;
|
|
66
|
+
outcome?: "skipped" | "unknown";
|
|
67
|
+
reason?: string;
|
|
68
|
+
};
|
|
69
|
+
/** A UUID as 32 lowercase hex; any other id maps to a stable UUID-shaped hash (grouping only). */
|
|
70
|
+
export declare function runIdOf(value: string): string;
|
|
71
|
+
/** Wire `monitor_config`, or null (with a diagnostic) when anything is invalid. */
|
|
72
|
+
export declare function monitorConfigOf(input: Partial<MonitorConfigInput> | undefined): Record<string, unknown> | null;
|
|
73
|
+
/** The check-in item exactly as sent (exported for the golden test). */
|
|
74
|
+
export declare function buildCheckIn(input: CheckInInput, client: Pick<Client, "getOptions">, config: Record<string, unknown> | null, trace: {
|
|
75
|
+
trace_id: string;
|
|
76
|
+
span_id: string;
|
|
77
|
+
} | null): SerializedCheckIn & Record<string, unknown>;
|
|
78
|
+
/** Sends one check-in; returns its id ("" when the SDK is off or the slug is invalid). Never throws. */
|
|
79
|
+
export declare function captureCheckIn(checkIn: CheckInInput, monitorConfig?: MonitorConfigInput): string;
|
|
80
|
+
/** A healthy check-in for an interval monitor ("still alive"). */
|
|
81
|
+
export declare function heartbeat(slug: string, options?: {
|
|
82
|
+
environment?: string;
|
|
83
|
+
}): void;
|
|
84
|
+
/**
|
|
85
|
+
* Runs `fn` as one monitored attempt: `in_progress` first, then `ok` (or skipped/unknown
|
|
86
|
+
* via the handle) when it returns, or the error captured as a normal issue and `error`
|
|
87
|
+
* when it throws — the same value or error goes back to the caller, unchanged.
|
|
88
|
+
*/
|
|
89
|
+
export declare function withMonitor<T>(slug: string, fn: (run: RunHandle) => T, options?: WithMonitorOptions): T;
|