@reliantlabs/forge-web-runtime 0.13.1 → 0.13.3
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/mock-transport.d.ts +41 -5
- package/dist/mock-transport.js +125 -7
- package/dist/mock-transport.js.map +1 -1
- package/dist/telemetry.js +156 -0
- package/dist/telemetry.js.map +1 -1
- package/package.json +1 -1
package/dist/mock-transport.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { type DescMessage } from "@bufbuild/protobuf";
|
|
2
|
-
import { type Transport } from "@connectrpc/connect";
|
|
1
|
+
import { type DescMessage, type DescMethod } from "@bufbuild/protobuf";
|
|
2
|
+
import { ConnectError, type Transport } from "@connectrpc/connect";
|
|
3
3
|
/**
|
|
4
4
|
* The shape the generated scenario files satisfy. Structural on purpose: the
|
|
5
5
|
* project's own `Scenario` type (src/mocks/scenario-types.ts) carries a
|
|
@@ -10,8 +10,12 @@ export interface MockScenario {
|
|
|
10
10
|
name: string;
|
|
11
11
|
/** Per-RPC overrides keyed by `${serviceTypeName}/${methodName}`. */
|
|
12
12
|
handlers: Record<string, ((req: never) => unknown) | undefined>;
|
|
13
|
-
/**
|
|
14
|
-
|
|
13
|
+
/**
|
|
14
|
+
* `true`: forward RPCs no handler matches to the real backend (hybrid mode
|
|
15
|
+
* only). `"first"`: forward EVERY RPC, and answer from the handlers and
|
|
16
|
+
* fixtures only when the backend fails — see the dispatch notes above.
|
|
17
|
+
*/
|
|
18
|
+
passthrough?: boolean | "first";
|
|
15
19
|
/** Non-RPC side effects, run once before the first RPC fires. */
|
|
16
20
|
setup?: () => void;
|
|
17
21
|
}
|
|
@@ -91,6 +95,38 @@ export interface CreateMockTransportOptions {
|
|
|
91
95
|
* forwarded here instead of falling through to the fixtures.
|
|
92
96
|
*/
|
|
93
97
|
fallback?: Transport;
|
|
98
|
+
/**
|
|
99
|
+
* Refuse every RPC that is not a read, with PermissionDenied, before any
|
|
100
|
+
* handler, fixture or backend sees it. `true` classifies by the proto's
|
|
101
|
+
* `idempotency_level = NO_SIDE_EFFECTS`; a function classifies itself (a
|
|
102
|
+
* contract that does not annotate idempotency, e.g. by method name).
|
|
103
|
+
*/
|
|
104
|
+
readOnly?: boolean | ((method: DescMethod) => boolean);
|
|
105
|
+
/** The message a refused write carries. Default names the RPC. */
|
|
106
|
+
readOnlyMessage?: string;
|
|
107
|
+
/**
|
|
108
|
+
* With `passthrough: "first"`: the forwarded call's deadline in ms, after
|
|
109
|
+
* which the scenario answers instead. Default: the caller's own timeout.
|
|
110
|
+
* Enforced by the mock transport itself, so a fallback transport that
|
|
111
|
+
* ignores its timeout cannot hold the call open; a server stream must END
|
|
112
|
+
* within it to count as the backend's answer.
|
|
113
|
+
*/
|
|
114
|
+
passthroughTimeoutMs?: number;
|
|
115
|
+
/**
|
|
116
|
+
* With `passthrough: "first"`: called each time the backend failed (or
|
|
117
|
+
* timed out) and the mock answered instead. A caller's own abort is never
|
|
118
|
+
* a fallback: it rejects as it would against the backend.
|
|
119
|
+
*/
|
|
120
|
+
onPassthroughFallback?: (key: string, error: ConnectError) => void;
|
|
121
|
+
}
|
|
122
|
+
/** Options for {@link resolveActiveScenario}. */
|
|
123
|
+
export interface ResolveScenarioOptions {
|
|
124
|
+
/**
|
|
125
|
+
* The scenario to run, chosen by the app (its host, its runtime config)
|
|
126
|
+
* instead of the URL. When the key is present — even as null or "" — the
|
|
127
|
+
* `?scenario=` parameter is NOT read; null/""/unknown select the default.
|
|
128
|
+
*/
|
|
129
|
+
name?: string | null;
|
|
94
130
|
}
|
|
95
131
|
/**
|
|
96
132
|
* Resolve the scenario the app should run under, and run its `setup()` once.
|
|
@@ -103,7 +139,7 @@ export interface CreateMockTransportOptions {
|
|
|
103
139
|
* `setup()` is for non-RPC state (localStorage flags, sessionStorage). It is
|
|
104
140
|
* synchronous and makes no network calls.
|
|
105
141
|
*/
|
|
106
|
-
export declare function resolveActiveScenario(registry: MockScenarioRegistry): MockScenario;
|
|
142
|
+
export declare function resolveActiveScenario(registry: MockScenarioRegistry, options?: ResolveScenarioOptions): MockScenario;
|
|
107
143
|
/**
|
|
108
144
|
* Normalize whatever a streaming scenario handler returns into an
|
|
109
145
|
* AsyncIterable<unknown>. Accepts arrays, iterables, async iterables, and
|
package/dist/mock-transport.js
CHANGED
|
@@ -16,6 +16,17 @@
|
|
|
16
16
|
// NEXT_PUBLIC_MOCK_API=hybrid), unmatched RPCs are forwarded to the
|
|
17
17
|
// real backend. This lets one scenario stub a single endpoint while
|
|
18
18
|
// everything else exercises the live server.
|
|
19
|
+
//
|
|
20
|
+
// `passthrough: "first"` turns that around: EVERY RPC goes to the
|
|
21
|
+
// backend first, and the scenario (then the fixtures) answer only when
|
|
22
|
+
// it fails or exceeds `passthroughTimeoutMs`. That is a demo or a
|
|
23
|
+
// preview on live data that degrades to sample data instead of to an
|
|
24
|
+
// error page — and `onPassthroughFallback` lets the UI say so.
|
|
25
|
+
//
|
|
26
|
+
// 0. Before any of it, `readOnly` refuses every RPC that is not a read
|
|
27
|
+
// (by default: not marked `idempotency_level = NO_SIDE_EFFECTS`) with
|
|
28
|
+
// PermissionDenied, so neither a handler, a fixture nor the backend
|
|
29
|
+
// ever sees a write — a public demo's guarantee.
|
|
19
30
|
// 3. Otherwise RPCs not overridden fall through to the deterministic
|
|
20
31
|
// per-entity fixtures described by the entity descriptors.
|
|
21
32
|
// 4. Anything else rejects with Code.Unimplemented so callers see a
|
|
@@ -32,7 +43,8 @@
|
|
|
32
43
|
// and this engine out entirely, which is why the generated `connect.ts`
|
|
33
44
|
// reaches its own shim through a dynamic `require()` gated on the mock-mode
|
|
34
45
|
// env var.
|
|
35
|
-
import { create, ScalarType, } from "@bufbuild/protobuf";
|
|
46
|
+
import { create, isMessage, ScalarType, } from "@bufbuild/protobuf";
|
|
47
|
+
import { MethodOptions_IdempotencyLevel } from "@bufbuild/protobuf/wkt";
|
|
36
48
|
import { Code, ConnectError, } from "@connectrpc/connect";
|
|
37
49
|
/**
|
|
38
50
|
* Mutable session stores, keyed by descriptor identity.
|
|
@@ -70,10 +82,12 @@ const initialized = new WeakSet();
|
|
|
70
82
|
* `setup()` is for non-RPC state (localStorage flags, sessionStorage). It is
|
|
71
83
|
* synchronous and makes no network calls.
|
|
72
84
|
*/
|
|
73
|
-
export function resolveActiveScenario(registry) {
|
|
74
|
-
const requested =
|
|
75
|
-
?
|
|
76
|
-
:
|
|
85
|
+
export function resolveActiveScenario(registry, options = {}) {
|
|
86
|
+
const requested = "name" in options
|
|
87
|
+
? (options.name ?? null)
|
|
88
|
+
: typeof globalThis !== "undefined" && globalThis.location
|
|
89
|
+
? new URLSearchParams(globalThis.location.search).get("scenario")
|
|
90
|
+
: null;
|
|
77
91
|
// A ternary, not `&&`: with `??` alone the empty-string falsy branch leaks
|
|
78
92
|
// '' into the inferred union, and '' survives `??` (which only replaces
|
|
79
93
|
// null/undefined), so downstream access on .setup / .handlers would fail
|
|
@@ -119,10 +133,29 @@ function makeUnaryResponse(method, message) {
|
|
|
119
133
|
method: method,
|
|
120
134
|
stream: false,
|
|
121
135
|
header: new Headers(),
|
|
122
|
-
message: message,
|
|
136
|
+
message: asResponseMessage(method.output, message),
|
|
123
137
|
trailer: new Headers(),
|
|
124
138
|
};
|
|
125
139
|
}
|
|
140
|
+
/**
|
|
141
|
+
* A handler may return the response as a plain init object
|
|
142
|
+
* (`{ items: [...] }`) instead of `create(Schema, {...})`. A real client
|
|
143
|
+
* always receives a full message — every repeated field an array, every
|
|
144
|
+
* scalar its zero value — so a plain object is completed against the
|
|
145
|
+
* method's output schema here; without that, `res.items.map` on a field the
|
|
146
|
+
* handler left out throws in the UI and nowhere near the scenario.
|
|
147
|
+
*/
|
|
148
|
+
function asResponseMessage(output, value) {
|
|
149
|
+
if (!output || value == null || typeof value !== "object")
|
|
150
|
+
return value;
|
|
151
|
+
if (isMessage(value))
|
|
152
|
+
return value;
|
|
153
|
+
return create(output, value);
|
|
154
|
+
}
|
|
155
|
+
/** The default read-only classification: the proto says the method has no side effects. */
|
|
156
|
+
function isRead(method) {
|
|
157
|
+
return method.idempotency === MethodOptions_IdempotencyLevel.NO_SIDE_EFFECTS;
|
|
158
|
+
}
|
|
126
159
|
// ── List semantics ─────────────────────────────────────────────────────
|
|
127
160
|
//
|
|
128
161
|
// What the backend's generated List does, and therefore what the fixture
|
|
@@ -418,9 +451,62 @@ function buildFixtureTable(entities) {
|
|
|
418
451
|
* real transport when running in hybrid mode.
|
|
419
452
|
*/
|
|
420
453
|
export function createMockTransport(options) {
|
|
421
|
-
const { scenario, entities = [], fallback } = options;
|
|
454
|
+
const { scenario, entities = [], fallback, readOnly, passthroughTimeoutMs, onPassthroughFallback, } = options;
|
|
422
455
|
const passthrough = scenario.passthrough === true && fallback != null;
|
|
456
|
+
const first = scenario.passthrough === "first" && fallback != null;
|
|
423
457
|
const fixtures = buildFixtureTable(entities);
|
|
458
|
+
const readsOnly = typeof readOnly === "function" ? readOnly : isRead;
|
|
459
|
+
// 0) The read-only guard: before any dispatch, so a write never reaches a
|
|
460
|
+
// handler, a fixture store or the backend.
|
|
461
|
+
const guard = (method, key) => {
|
|
462
|
+
if (readOnly && !readsOnly(method)) {
|
|
463
|
+
throw new ConnectError(options.readOnlyMessage ?? `mock-transport: ${key} is not a read`, Code.PermissionDenied);
|
|
464
|
+
}
|
|
465
|
+
};
|
|
466
|
+
// "first": the backend's answer, or undefined when the mock should answer.
|
|
467
|
+
//
|
|
468
|
+
// The deadline is enforced HERE, not left to the fallback transport: the
|
|
469
|
+
// attempt gets its own signal (aborted by the caller's signal or by the
|
|
470
|
+
// timer) and is raced against that signal, so a transport that ignores
|
|
471
|
+
// both its timeout and its signal still cannot hold the call open. A
|
|
472
|
+
// caller's own abort is rethrown; only the deadline or a failure falls back.
|
|
473
|
+
const tryBackend = async (key, signal, timeoutMs, call) => {
|
|
474
|
+
const attempt = new AbortController();
|
|
475
|
+
const abortAttempt = () => attempt.abort(signal?.reason);
|
|
476
|
+
if (signal?.aborted)
|
|
477
|
+
abortAttempt();
|
|
478
|
+
signal?.addEventListener("abort", abortAttempt, { once: true });
|
|
479
|
+
const timer = timeoutMs != null && timeoutMs > 0
|
|
480
|
+
? setTimeout(() => attempt.abort(new ConnectError(`mock-transport: ${key} exceeded ${timeoutMs}ms`, Code.DeadlineExceeded)), timeoutMs)
|
|
481
|
+
: undefined;
|
|
482
|
+
const abandoned = new Promise((_, reject) => {
|
|
483
|
+
const fail = () => reject(attempt.signal.reason);
|
|
484
|
+
if (attempt.signal.aborted)
|
|
485
|
+
fail();
|
|
486
|
+
else
|
|
487
|
+
attempt.signal.addEventListener("abort", fail, { once: true });
|
|
488
|
+
});
|
|
489
|
+
// The race observes it; this keeps the release below from surfacing as
|
|
490
|
+
// an unhandled rejection after the race has settled.
|
|
491
|
+
abandoned.catch(() => undefined);
|
|
492
|
+
try {
|
|
493
|
+
return await Promise.race([call(attempt.signal), abandoned]);
|
|
494
|
+
}
|
|
495
|
+
catch (err) {
|
|
496
|
+
if (signal?.aborted)
|
|
497
|
+
throw err;
|
|
498
|
+
onPassthroughFallback?.(key, ConnectError.from(err));
|
|
499
|
+
return undefined;
|
|
500
|
+
}
|
|
501
|
+
finally {
|
|
502
|
+
if (timer !== undefined)
|
|
503
|
+
clearTimeout(timer);
|
|
504
|
+
signal?.removeEventListener("abort", abortAttempt);
|
|
505
|
+
// Release whatever the backend attempt still holds (a pending fetch,
|
|
506
|
+
// an unread stream) once it has been answered or abandoned.
|
|
507
|
+
attempt.abort();
|
|
508
|
+
}
|
|
509
|
+
};
|
|
424
510
|
// Bind the object literal to a Transport-typed variable rather than
|
|
425
511
|
// casting at the return site. A trailing assertion cast does not propagate
|
|
426
512
|
// Connect's Transport signature backwards into the literal's method
|
|
@@ -434,6 +520,14 @@ export function createMockTransport(options) {
|
|
|
434
520
|
// fixture keys are matched against.
|
|
435
521
|
async unary(method, signal, timeoutMs, header, input, contextValues) {
|
|
436
522
|
const key = `${method.parent.typeName}/${method.name}`;
|
|
523
|
+
guard(method, key);
|
|
524
|
+
// 0b) "first": the backend answers unless it fails.
|
|
525
|
+
if (first) {
|
|
526
|
+
const deadline = passthroughTimeoutMs ?? timeoutMs;
|
|
527
|
+
const live = await tryBackend(key, signal, deadline, (attempt) => fallback.unary(method, attempt, deadline, header, input, contextValues));
|
|
528
|
+
if (live)
|
|
529
|
+
return live;
|
|
530
|
+
}
|
|
437
531
|
// 1) Scenario overlay.
|
|
438
532
|
const handler = scenario.handlers[key];
|
|
439
533
|
if (handler) {
|
|
@@ -473,6 +567,30 @@ export function createMockTransport(options) {
|
|
|
473
567
|
// ill-typed (TS2322) because fallback.stream returns StreamResponse<I,O>.
|
|
474
568
|
async stream(method, signal, timeoutMs, header, input, contextValues) {
|
|
475
569
|
const key = `${method.parent.typeName}/${method.name}`;
|
|
570
|
+
guard(method, key);
|
|
571
|
+
// "first" forwards server streams only: a client-streaming request is
|
|
572
|
+
// consumed by the attempt and could not be replayed to the handler.
|
|
573
|
+
//
|
|
574
|
+
// The backend's stream is read to its END, within the deadline, before
|
|
575
|
+
// it counts as an answer, then replayed: a stream that fails or stalls
|
|
576
|
+
// after its headers arrived still falls back to the mock, as a unary
|
|
577
|
+
// call does. So "first" suits finite server streams; a stream that
|
|
578
|
+
// never ends always answers from the mock once the deadline passes.
|
|
579
|
+
if (first && method.methodKind === "server_streaming") {
|
|
580
|
+
const deadline = passthroughTimeoutMs ?? timeoutMs;
|
|
581
|
+
const live = await tryBackend(key, signal, deadline, async (attempt) => {
|
|
582
|
+
const res = await fallback.stream(method, attempt, deadline, header, input, contextValues);
|
|
583
|
+
const messages = [];
|
|
584
|
+
for await (const m of res.message)
|
|
585
|
+
messages.push(m);
|
|
586
|
+
return {
|
|
587
|
+
...res,
|
|
588
|
+
message: toAsyncIterable(messages),
|
|
589
|
+
};
|
|
590
|
+
});
|
|
591
|
+
if (live)
|
|
592
|
+
return live;
|
|
593
|
+
}
|
|
476
594
|
const handler = scenario.handlers[key];
|
|
477
595
|
if (!handler) {
|
|
478
596
|
// Passthrough mirrors the unary path: in hybrid mode, unmatched
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mock-transport.js","sourceRoot":"","sources":["../src/mock-transport.ts"],"names":[],"mappings":"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","sourcesContent":["// Part of @reliantlabs/forge-web-runtime — the web twin of forge/pkg.\n//\n// The mock transport ENGINE. A generated frontend used to carry this entire\n// pipeline as ~300 lines of Tier-1 scaffold; what varies per project is only\n// the table of entities to dispatch on, so the engine lives here and the\n// project keeps a declarative descriptor list.\n//\n// Dispatch order (unchanged from the scaffolded original):\n//\n// 1. A scenario selected via `?scenario=<name>` (or the auto-generated\n// `default` scenario) gets first crack at every unary RPC. Handlers\n// keyed by `${serviceTypeName}/${methodName}` return typed proto\n// messages and short-circuit the rest of the pipeline.\n// 2. If the active scenario has `passthrough: true` AND a fallback\n// transport was supplied (hybrid mode — VITE_MOCK_API=hybrid /\n// NEXT_PUBLIC_MOCK_API=hybrid), unmatched RPCs are forwarded to the\n// real backend. This lets one scenario stub a single endpoint while\n// everything else exercises the live server.\n// 3. Otherwise RPCs not overridden fall through to the deterministic\n// per-entity fixtures described by the entity descriptors.\n// 4. Anything else rejects with Code.Unimplemented so callers see a\n// clear error instead of a silent empty response.\n//\n// A fixture List answers the way the backend's generated CRUD List does\n// (pkg/crud HandleList), so a filtered table, a paged table and a \"how many\"\n// tile read the same against fixtures as against a server — see\n// `serveList` for the exact contract. Custom (non-CRUD) RPCs are not\n// interpreted at all; they stay hand-written scenario handlers.\n//\n// Imported through the \"@reliantlabs/forge-web-runtime/mock-transport\" subpath,\n// never the barrel: a production bundle must be able to shake the fixtures\n// and this engine out entirely, which is why the generated `connect.ts`\n// reaches its own shim through a dynamic `require()` gated on the mock-mode\n// env var.\nimport {\n create,\n ScalarType,\n type DescField,\n type DescMessage,\n type MessageInitShape,\n} from \"@bufbuild/protobuf\";\nimport {\n Code,\n ConnectError,\n type Transport,\n type UnaryResponse,\n} from \"@connectrpc/connect\";\n\n/**\n * The shape the generated scenario files satisfy. Structural on purpose: the\n * project's own `Scenario` type (src/mocks/scenario-types.ts) carries a\n * richer, per-RPC-typed `handlers` map, and this is the subset the engine\n * dispatches through.\n */\nexport interface MockScenario {\n name: string;\n /** Per-RPC overrides keyed by `${serviceTypeName}/${methodName}`. */\n handlers: Record<string, ((req: never) => unknown) | undefined>;\n /** Forward unmatched RPCs to the real backend (hybrid mode only). */\n passthrough?: boolean;\n /** Non-RPC side effects, run once before the first RPC fires. */\n setup?: () => void;\n}\n\n/** The generated `src/mocks/scenarios` barrel, as the engine consumes it. */\nexport interface MockScenarioRegistry {\n byName(name: string): MockScenario | undefined;\n defaultScenario: MockScenario;\n}\n\n/**\n * One CRUD arm of an entity's dispatch table.\n *\n * The List arm needs nothing beyond these three fields to honour filters,\n * paging and total_count: the REQUEST schema arrives on every call as the\n * Connect method's `input`, and the entity schema is the element type of\n * `itemsField` on `responseSchema`.\n */\nexport interface MockListRpc {\n rpc: string;\n responseSchema: DescMessage;\n /**\n * The camelCase name of the list response's repeated field — the ACTUAL\n * proto field (e.g. `keys`), not the camelCased entity plural.\n */\n itemsField: string;\n}\n\nexport interface MockGetRpc {\n rpc: string;\n responseSchema: DescMessage;\n /** The camelCase field wrapping the entity on the response message. */\n entityField: string;\n}\n\nexport interface MockWriteRpc extends MockGetRpc {\n /**\n * The camelCase field wrapping the entity on the REQUEST message. AIP-134\n * requests nest the entity ({ item: {...}, updateMask }); the generated\n * forms submit it flattened. Both are accepted.\n */\n requestField: string;\n}\n\nexport interface MockDeleteRpc {\n rpc: string;\n}\n\n/**\n * Everything the engine needs to serve one entity's CRUD quintet from\n * fixtures. Generated into `src/lib/mock-transport.ts` from the project's\n * proto descriptors.\n */\nexport interface MockEntityDescriptor {\n /** Fully-qualified proto service name, e.g. \"demo.v1.ClinicService\". */\n service: string;\n /** Lowercase entity name, used verbatim in the NotFound message. */\n label: string;\n /**\n * The camelCase PRIMARY-KEY field. The session store keys records by this\n * field; hardcoding \"id\" breaks every surrogate-PK entity (a\n * `usage_event_id` PK projects to a message with no `id` field).\n */\n pkField: string;\n /** Deterministic seed rows — the same values the dev database is seeded with. */\n fixtures: readonly unknown[];\n /** The entity message schema. Required by the create/update write paths. */\n entitySchema?: DescMessage;\n list?: MockListRpc;\n get?: MockGetRpc;\n create?: MockWriteRpc;\n update?: MockWriteRpc;\n delete?: MockDeleteRpc;\n}\n\nexport interface CreateMockTransportOptions {\n /** The resolved scenario — see {@link resolveActiveScenario}. */\n scenario: MockScenario;\n /** Per-entity fixture dispatch. Omit for a scenario-only project. */\n entities?: readonly MockEntityDescriptor[];\n /**\n * Optional real Connect transport. When the active scenario declares\n * `passthrough: true`, any RPC not matched by a scenario handler is\n * forwarded here instead of falling through to the fixtures.\n */\n fallback?: Transport;\n}\n\n/**\n * Mutable session stores, keyed by descriptor identity.\n *\n * Create/Update/Delete round-trip within one browser session (a created row\n * appears in the next List; a deleted one disappears) and reset to the\n * deterministic fixtures on reload. The scaffolded original got that from\n * module-scope `const store = new Map(...)`; keying off the descriptor\n * object preserves it — a module-level descriptor array hands back the same\n * store on every call, so building the transport twice (hybrid mode, a test\n * swapping transports) does not silently fork the data.\n */\nconst stores = new WeakMap<MockEntityDescriptor, Map<string, unknown>>();\n\nfunction storeFor(entity: MockEntityDescriptor): Map<string, unknown> {\n let store = stores.get(entity);\n if (!store) {\n store = new Map(\n entity.fixtures.map((row) => [\n String((row as Record<string, unknown>)[entity.pkField]),\n row,\n ]),\n );\n stores.set(entity, store);\n }\n return store;\n}\n\n/** Scenarios whose `setup()` has already run. */\nconst initialized = new WeakSet<MockScenario>();\n\n/**\n * Resolve the scenario the app should run under, and run its `setup()` once.\n *\n * Call this at MODULE SCOPE (the generated `src/lib/mock-transport.ts` does).\n * Reading the URL once — rather than on every RPC — means navigating away\n * from `?scenario=` keeps the scenario active until a full reload, matching\n * the agent-driven flow where the URL is the single source of truth.\n *\n * `setup()` is for non-RPC state (localStorage flags, sessionStorage). It is\n * synchronous and makes no network calls.\n */\nexport function resolveActiveScenario(\n registry: MockScenarioRegistry,\n): MockScenario {\n const requested =\n typeof globalThis !== \"undefined\" && globalThis.location\n ? new URLSearchParams(globalThis.location.search).get(\"scenario\")\n : null;\n // A ternary, not `&&`: with `??` alone the empty-string falsy branch leaks\n // '' into the inferred union, and '' survives `??` (which only replaces\n // null/undefined), so downstream access on .setup / .handlers would fail\n // under strict tsc.\n const active =\n (requested ? registry.byName(requested) : undefined) ??\n registry.defaultScenario;\n\n if (!initialized.has(active)) {\n initialized.add(active);\n active.setup?.();\n }\n return active;\n}\n\n/**\n * Normalize whatever a streaming scenario handler returns into an\n * AsyncIterable<unknown>. Accepts arrays, iterables, async iterables, and\n * promises that resolve to any of the above. Single (non-iterable) values\n * are wrapped as a one-element stream — handy for handlers that conceptually\n * yield once.\n */\nexport async function* toAsyncIterable(value: unknown): AsyncIterable<unknown> {\n const resolved = await Promise.resolve(value);\n if (resolved == null) return;\n // AsyncIterable\n if (\n typeof (resolved as { [Symbol.asyncIterator]?: unknown })[\n Symbol.asyncIterator\n ] === \"function\"\n ) {\n for await (const m of resolved as AsyncIterable<unknown>) yield m;\n return;\n }\n // Iterable (including arrays)\n if (\n typeof (resolved as { [Symbol.iterator]?: unknown })[Symbol.iterator] ===\n \"function\"\n ) {\n for (const m of resolved as Iterable<unknown>) yield m;\n return;\n }\n // Single value\n yield resolved;\n}\n\nfunction makeUnaryResponse<T>(\n method: { name: string; parent: { typeName: string } },\n message: T,\n): UnaryResponse<never, never> {\n return {\n service: method.parent as never,\n method: method as never,\n stream: false,\n header: new Headers(),\n message: message as never,\n trailer: new Headers(),\n };\n}\n\n/**\n * A fixture-backed handler for one RPC key. `requestSchema` is the Connect\n * method's input descriptor — absent only when a caller hand-builds a method\n * object without one, in which case List serves paging alone.\n */\ntype FixtureHandler = (\n input: unknown,\n requestSchema: DescMessage | undefined,\n) => unknown;\n\n// ── List semantics ─────────────────────────────────────────────────────\n//\n// What the backend's generated List does, and therefore what the fixture\n// List does (pkg/crud HandleList + the generated Filters closure):\n//\n// - Every `optional` request field that is SET filters by equality on the\n// entity field of the same name. Enums compare by value. A field with\n// IMPLICIT presence (no `optional`) is never a filter — the backend\n// generates none for it, so the mock must not invent one.\n// - `search` matches case-insensitively against the entity's string\n// fields and enum value names (enum columns are stored as names).\n// - `order_by` (snake_case column, comma-separated, optional ASC/DESC per\n// column) plus `descending` sorts; an unknown column is InvalidArgument.\n// - `page_size` defaults to 50 and is clamped to 100. `total_count` is the\n// filtered count BEFORE paging. `next_page_token` is minted only for the\n// default (primary-key) order — an ordered list is single-page on the\n// backend, and a mock that paged it would hide that.\n//\n// Paging, ordering and search arrive through these request fields, by the\n// names forge's CRUD List requests declare. They are never equality filters.\nconst LIST_CONTROL_FIELDS = new Set([\n \"pageSize\",\n \"pageToken\",\n \"orderBy\",\n \"descending\",\n \"search\",\n]);\n\n/** pkg/crud ListOp's defaults: 0 means 50, and no page exceeds 100. */\nconst DEFAULT_PAGE_SIZE = 50;\nconst MAX_PAGE_SIZE = 100;\n\n/** FeatureSet_FieldPresence.EXPLICIT — proto3 `optional`, oneofs, messages. */\nconst EXPLICIT_PRESENCE = 1;\n\ntype Row = Record<string, unknown>;\n\n/** The entity message a List response repeats, read off its descriptor. */\nfunction listItemSchema(list: MockListRpc): DescMessage | undefined {\n const items = list.responseSchema.field[list.itemsField];\n return items?.fieldKind === \"list\" && items.listKind === \"message\"\n ? items.message\n : undefined;\n}\n\n/** Scalars and enums compare by value; messages, bytes, lists and maps do not. */\nfunction isComparable(field: DescField): boolean {\n if (field.fieldKind === \"enum\") return true;\n return field.fieldKind === \"scalar\" && field.scalar !== ScalarType.BYTES;\n}\n\nfunction sameValue(a: unknown, b: unknown): boolean {\n if (a === b) return true;\n // A 64-bit field is a bigint — or a string under jstype=JS_STRING — and\n // the two sides are not guaranteed to agree on which.\n if (a == null || b == null) return false;\n return (\n (typeof a === \"bigint\" || typeof b === \"bigint\") && String(a) === String(b)\n );\n}\n\nfunction enumName(field: DescField, value: unknown): string | undefined {\n return field.fieldKind === \"enum\"\n ? field.enum.values.find((v) => v.number === value)?.name\n : undefined;\n}\n\n/** The value a column sorts by, as Postgres would order the stored column. */\nfunction sortKey(field: DescField, value: unknown): unknown {\n if (value == null) return undefined;\n // Enum columns hold the value NAME, so they sort alphabetically by name.\n if (field.fieldKind === \"enum\") return enumName(field, value) ?? \"\";\n if (field.fieldKind === \"scalar\") return value;\n if (\n field.fieldKind === \"message\" &&\n field.message.typeName === \"google.protobuf.Timestamp\"\n ) {\n const ts = value as { seconds: bigint; nanos: number };\n return BigInt(ts.seconds) * 1_000_000_000n + BigInt(ts.nanos);\n }\n return undefined;\n}\n\n/** Postgres's default: NULL sorts after every value ascending. */\nfunction compareKeys(a: unknown, b: unknown): number {\n if (a === undefined || b === undefined) {\n return a === b ? 0 : a === undefined ? 1 : -1;\n }\n const x = a as string | number | bigint | boolean;\n const y = b as string | number | bigint | boolean;\n return x < y ? -1 : x > y ? 1 : 0;\n}\n\nfunction invalidArgument(message: string): ConnectError {\n return new ConnectError(`mock-transport: ${message}`, Code.InvalidArgument);\n}\n\n/** Parse `order_by` the way orm.ValidateOrderBy reads it. */\nfunction parseOrderBy(\n clause: string,\n descending: boolean,\n itemSchema: DescMessage,\n): { field: DescField; desc: boolean }[] {\n return clause.split(\",\").map((part) => {\n const [column = \"\", direction] = part.trim().split(/\\s+/);\n const field = itemSchema.fields.find(\n (f) => f.name === column || f.localName === column,\n );\n if (!field) {\n throw invalidArgument(`unknown order-by column \"${column}\"`);\n }\n const dir = direction?.toUpperCase();\n if (dir !== undefined && dir !== \"ASC\" && dir !== \"DESC\") {\n throw invalidArgument(`invalid order-by direction \"${direction}\"`);\n }\n return { field, desc: dir === undefined ? descending : dir === \"DESC\" };\n });\n}\n\n/** A count in whatever JS type the response's total_count field takes. */\nfunction countValue(field: DescField, n: number): unknown {\n if (field.fieldKind !== \"scalar\") return n;\n switch (field.scalar) {\n case ScalarType.INT64:\n case ScalarType.UINT64:\n case ScalarType.SINT64:\n case ScalarType.FIXED64:\n case ScalarType.SFIXED64:\n return field.longAsString ? String(n) : BigInt(n);\n default:\n return n;\n }\n}\n\n/**\n * Answer one List call from the entity's rows. See the List semantics note\n * above for the contract; the engine's tests pin each clause.\n */\nfunction serveList(\n rows: readonly unknown[],\n list: MockListRpc,\n input: unknown,\n requestSchema: DescMessage | undefined,\n): unknown {\n const req = (input ?? {}) as Row;\n const itemSchema = listItemSchema(list);\n let matched = rows as readonly Row[];\n\n if (itemSchema && requestSchema) {\n for (const filter of requestSchema.fields) {\n if (LIST_CONTROL_FIELDS.has(filter.localName)) continue;\n if (filter.presence !== EXPLICIT_PRESENCE || !isComparable(filter)) {\n continue;\n }\n const want = req[filter.localName];\n if (want == null) continue; // unset: no filter\n const target = itemSchema.field[filter.localName];\n if (!target || !isComparable(target)) continue;\n matched = matched.filter((row) => sameValue(row[filter.localName], want));\n }\n }\n\n const search =\n typeof req.search === \"string\" ? req.search.trim().toLowerCase() : \"\";\n if (itemSchema && search) {\n const searchable = itemSchema.fields.filter(\n (f) =>\n f.fieldKind === \"enum\" ||\n (f.fieldKind === \"scalar\" && f.scalar === ScalarType.STRING),\n );\n matched = matched.filter((row) =>\n searchable.some((f) => {\n const value = row[f.localName];\n const text = f.fieldKind === \"enum\" ? enumName(f, value) : value;\n return typeof text === \"string\" && text.toLowerCase().includes(search);\n }),\n );\n }\n\n const orderBy = typeof req.orderBy === \"string\" ? req.orderBy.trim() : \"\";\n if (itemSchema && orderBy) {\n const keys = parseOrderBy(orderBy, req.descending === true, itemSchema);\n matched = [...matched].sort((a, b) => {\n for (const { field, desc } of keys) {\n const c = compareKeys(\n sortKey(field, a[field.localName]),\n sortKey(field, b[field.localName]),\n );\n if (c !== 0) return desc ? -c : c;\n }\n return 0;\n });\n }\n\n const total = matched.length;\n\n let offset = 0;\n const token = typeof req.pageToken === \"string\" ? req.pageToken : \"\";\n if (token) {\n // The mock's own cursor: an offset into the filtered rows. Opaque to the\n // client, exactly like the backend's keyset cursor.\n if (!/^\\d+$/.test(token)) throw invalidArgument(\"invalid page token\");\n offset = Number(token);\n }\n const requested = Number(req.pageSize ?? 0);\n const pageSize =\n requested > 0 ? Math.min(requested, MAX_PAGE_SIZE) : DEFAULT_PAGE_SIZE;\n const end = offset + pageSize;\n\n const init: Row = { [list.itemsField]: matched.slice(offset, end) };\n const totalField = list.responseSchema.field.totalCount;\n if (totalField) init.totalCount = countValue(totalField, total);\n if (list.responseSchema.field.nextPageToken && !orderBy && end < total) {\n init.nextPageToken = String(end);\n }\n return create(list.responseSchema, init as MessageInitShape<DescMessage>);\n}\n\n/**\n * Compile the entity descriptors into a flat `${service}/${rpc}` → handler\n * map. Building it once per transport keeps per-RPC dispatch to a single\n * lookup, exactly like the generated `switch` it replaces.\n */\nfunction buildFixtureTable(\n entities: readonly MockEntityDescriptor[],\n): Map<string, FixtureHandler> {\n const table = new Map<string, FixtureHandler>();\n\n for (const entity of entities) {\n const pk = entity.pkField;\n const key = (rpc: string) => `${entity.service}/${rpc}`;\n\n if (entity.list) {\n const list = entity.list;\n table.set(key(list.rpc), (input, requestSchema) =>\n serveList(\n Array.from(storeFor(entity).values()),\n list,\n input,\n requestSchema,\n ),\n );\n }\n\n if (entity.get) {\n const { rpc, responseSchema, entityField } = entity.get;\n table.set(key(rpc), (input) => {\n // Read the key off the SAME field the store is keyed by, not a\n // hardcoded `id` — a surrogate-PK entity would otherwise look up\n // String(undefined) and miss every record.\n const req = input as Record<string, unknown> | undefined;\n const found = storeFor(entity).get(String(req?.[pk]));\n if (!found) {\n // A miss is NotFound — exactly what the real backend returns.\n // (Falling back to the first fixture made every detail page\n // \"work\" against the wrong record and hid bad-id bugs.)\n throw new ConnectError(\n `${entity.label} ${String(req?.[pk])} not found`,\n Code.NotFound,\n );\n }\n return create(responseSchema, {\n [entityField]: found,\n } as MessageInitShape<DescMessage>);\n });\n }\n\n if (entity.create && entity.entitySchema) {\n const { rpc, responseSchema, entityField, requestField } = entity.create;\n const entitySchema = entity.entitySchema;\n table.set(key(rpc), (input) => {\n // Create requests carry the entity fields flattened (that's how the\n // generated form submits); a nested { <entity>: {...} } payload is\n // accepted too.\n const req = (input ?? {}) as Record<string, unknown>;\n const init = {\n ...((req[requestField] ?? req) as Record<string, unknown>),\n };\n delete init.$typeName;\n // Mint the primary key on the PK field the store is keyed by — for a\n // surrogate-PK entity this is NOT `id`, and writing a generated `id`\n // would leave the store key undefined so the row never round-trips.\n const id =\n typeof init[pk] === \"string\" && init[pk]\n ? (init[pk] as string)\n : crypto.randomUUID();\n const created = create(entitySchema, {\n ...init,\n [pk]: id,\n } as MessageInitShape<DescMessage>);\n storeFor(entity).set(String(id), created);\n return create(responseSchema, {\n [entityField]: created,\n } as MessageInitShape<DescMessage>);\n });\n }\n\n if (entity.update && entity.entitySchema) {\n const { rpc, responseSchema, entityField, requestField } = entity.update;\n const entitySchema = entity.entitySchema;\n table.set(key(rpc), (input) => {\n const req = (input ?? {}) as Record<string, unknown>;\n // AIP-134 requests wrap the entity ({ <entity>: {...}, updateMask })\n // — the id lives inside the wrapper; flat requests carry it at the\n // top level.\n const patch = {\n ...((req[requestField] ?? req) as Record<string, unknown>),\n };\n delete patch.$typeName;\n const id = String(patch[pk] ?? req[pk] ?? \"\");\n const store = storeFor(entity);\n const existing = store.get(id);\n if (!existing) {\n throw new ConnectError(\n `${entity.label} ${id} not found`,\n Code.NotFound,\n );\n }\n const updated = create(entitySchema, {\n ...(existing as Record<string, unknown>),\n ...patch,\n [pk]: id,\n } as MessageInitShape<DescMessage>);\n store.set(id, updated);\n return create(responseSchema, {\n [entityField]: updated,\n } as MessageInitShape<DescMessage>);\n });\n }\n\n if (entity.delete) {\n table.set(key(entity.delete.rpc), (input) => {\n // Delete by the SAME field the store is keyed by.\n const req = input as Record<string, unknown> | undefined;\n storeFor(entity).delete(String(req?.[pk]));\n // Delete returns an empty response — the standard CRUD shape.\n return {};\n });\n }\n }\n\n return table;\n}\n\n/**\n * Create the mock transport.\n *\n * The generated `src/lib/mock-transport.ts` supplies the resolved scenario\n * and the project's entity descriptors; `connect.ts` supplies the optional\n * real transport when running in hybrid mode.\n */\nexport function createMockTransport(\n options: CreateMockTransportOptions,\n): Transport {\n const { scenario, entities = [], fallback } = options;\n const passthrough = scenario.passthrough === true && fallback != null;\n const fixtures = buildFixtureTable(entities);\n\n // Bind the object literal to a Transport-typed variable rather than\n // casting at the return site. A trailing assertion cast does not propagate\n // Connect's Transport signature backwards into the literal's method\n // bodies, so under `strict` tsc every callback parameter on unary/stream\n // errors with TS7006 (\"implicitly has an 'any' type\").\n const transport: Transport = {\n // Connect v2's Transport.unary signature is\n // (method, signal, timeoutMs, header, input, contextValues)\n // — method first, no separate service arg. `method.parent.typeName` is\n // the fully-qualified service name; that is what handler keys and\n // fixture keys are matched against.\n async unary(method, signal, timeoutMs, header, input, contextValues) {\n const key = `${method.parent.typeName}/${method.name}`;\n\n // 1) Scenario overlay.\n const handler = scenario.handlers[key];\n if (handler) {\n const result = await handler(input as never);\n return makeUnaryResponse(method, result);\n }\n\n // 2) Passthrough: route to the real backend instead of fixtures.\n // Skips fixtures entirely — in hybrid mode the whole point is\n // \"use real data for anything not explicitly stubbed\".\n if (passthrough) {\n return fallback!.unary(\n method,\n signal,\n timeoutMs,\n header,\n input,\n contextValues,\n );\n }\n\n // 3) Base fixture dispatch, backed by the mutable per-entity stores so\n // writes round-trip within the session. Misses are REAL errors\n // (Code.NotFound), never a silent wrong-record fallback.\n const fixture = fixtures.get(key);\n if (fixture) {\n // `method.input` is typed as always present, but a hand-built method\n // object (a test, a custom harness) may omit it.\n const requestSchema = (method as { input?: DescMessage }).input;\n return makeUnaryResponse(method, fixture(input, requestSchema));\n }\n\n // 4) Nothing matched. Surface a clear error instead of hanging.\n return Promise.reject(\n new ConnectError(\n `mock-transport: no scenario handler or entity fixture for ${key}`,\n Code.Unimplemented,\n ),\n );\n },\n\n // Streaming: a scenario handler can return an array, iterable, async\n // iterable, or a Promise resolving to any of those. The transport adapts\n // it into the AsyncIterable<Response> shape Connect expects. If no\n // handler matches, reject with Unimplemented — base-fixture streaming is\n // intentionally not served (there is no canonical \"list of N messages\"\n // shape for an arbitrary streaming RPC).\n //\n // No explicit return-type annotation: the outer `const transport:\n // Transport` binding lets tsc infer the per-callback signature from\n // Connect's generic Transport.stream<I, O>. Annotating this as\n // Promise<StreamResponse<never, never>> makes the passthrough branch\n // ill-typed (TS2322) because fallback.stream returns StreamResponse<I,O>.\n async stream(method, signal, timeoutMs, header, input, contextValues) {\n const key = `${method.parent.typeName}/${method.name}`;\n const handler = scenario.handlers[key];\n if (!handler) {\n // Passthrough mirrors the unary path: in hybrid mode, unmatched\n // streaming RPCs go to the real backend.\n if (passthrough) {\n return fallback!.stream(\n method,\n signal,\n timeoutMs,\n header,\n input,\n contextValues,\n );\n }\n return Promise.reject(\n new ConnectError(\n `mock-transport: no scenario handler for streaming RPC ${key}`,\n Code.Unimplemented,\n ),\n );\n }\n // Read the request stream eagerly into an array so the scenario handler\n // sees the full client-streaming payload. For server-stream and\n // unary-into-stream-out RPCs this is a single message.\n const requestMessages: unknown[] = [];\n try {\n for await (const m of input as AsyncIterable<unknown>) {\n requestMessages.push(m);\n }\n } catch {\n // Synthetic clients sometimes pass a single value rather than an\n // iterable; treat that as an empty request payload.\n }\n const handlerInput =\n requestMessages.length <= 1 ? requestMessages[0] : requestMessages;\n const result = handler(handlerInput as never);\n return {\n service: method.parent as never,\n method: method as never,\n stream: true,\n header: new Headers(),\n message: toAsyncIterable(result) as AsyncIterable<never>,\n trailer: new Headers(),\n };\n },\n };\n return transport;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"mock-transport.js","sourceRoot":"","sources":["../src/mock-transport.ts"],"names":[],"mappings":"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","sourcesContent":["// Part of @reliantlabs/forge-web-runtime — the web twin of forge/pkg.\n//\n// The mock transport ENGINE. A generated frontend used to carry this entire\n// pipeline as ~300 lines of Tier-1 scaffold; what varies per project is only\n// the table of entities to dispatch on, so the engine lives here and the\n// project keeps a declarative descriptor list.\n//\n// Dispatch order (unchanged from the scaffolded original):\n//\n// 1. A scenario selected via `?scenario=<name>` (or the auto-generated\n// `default` scenario) gets first crack at every unary RPC. Handlers\n// keyed by `${serviceTypeName}/${methodName}` return typed proto\n// messages and short-circuit the rest of the pipeline.\n// 2. If the active scenario has `passthrough: true` AND a fallback\n// transport was supplied (hybrid mode — VITE_MOCK_API=hybrid /\n// NEXT_PUBLIC_MOCK_API=hybrid), unmatched RPCs are forwarded to the\n// real backend. This lets one scenario stub a single endpoint while\n// everything else exercises the live server.\n//\n// `passthrough: \"first\"` turns that around: EVERY RPC goes to the\n// backend first, and the scenario (then the fixtures) answer only when\n// it fails or exceeds `passthroughTimeoutMs`. That is a demo or a\n// preview on live data that degrades to sample data instead of to an\n// error page — and `onPassthroughFallback` lets the UI say so.\n//\n// 0. Before any of it, `readOnly` refuses every RPC that is not a read\n// (by default: not marked `idempotency_level = NO_SIDE_EFFECTS`) with\n// PermissionDenied, so neither a handler, a fixture nor the backend\n// ever sees a write — a public demo's guarantee.\n// 3. Otherwise RPCs not overridden fall through to the deterministic\n// per-entity fixtures described by the entity descriptors.\n// 4. Anything else rejects with Code.Unimplemented so callers see a\n// clear error instead of a silent empty response.\n//\n// A fixture List answers the way the backend's generated CRUD List does\n// (pkg/crud HandleList), so a filtered table, a paged table and a \"how many\"\n// tile read the same against fixtures as against a server — see\n// `serveList` for the exact contract. Custom (non-CRUD) RPCs are not\n// interpreted at all; they stay hand-written scenario handlers.\n//\n// Imported through the \"@reliantlabs/forge-web-runtime/mock-transport\" subpath,\n// never the barrel: a production bundle must be able to shake the fixtures\n// and this engine out entirely, which is why the generated `connect.ts`\n// reaches its own shim through a dynamic `require()` gated on the mock-mode\n// env var.\nimport {\n create,\n isMessage,\n ScalarType,\n type DescField,\n type DescMessage,\n type DescMethod,\n type MessageInitShape,\n} from \"@bufbuild/protobuf\";\nimport { MethodOptions_IdempotencyLevel } from \"@bufbuild/protobuf/wkt\";\nimport {\n Code,\n ConnectError,\n type Transport,\n type UnaryResponse,\n} from \"@connectrpc/connect\";\n\n/**\n * The shape the generated scenario files satisfy. Structural on purpose: the\n * project's own `Scenario` type (src/mocks/scenario-types.ts) carries a\n * richer, per-RPC-typed `handlers` map, and this is the subset the engine\n * dispatches through.\n */\nexport interface MockScenario {\n name: string;\n /** Per-RPC overrides keyed by `${serviceTypeName}/${methodName}`. */\n handlers: Record<string, ((req: never) => unknown) | undefined>;\n /**\n * `true`: forward RPCs no handler matches to the real backend (hybrid mode\n * only). `\"first\"`: forward EVERY RPC, and answer from the handlers and\n * fixtures only when the backend fails — see the dispatch notes above.\n */\n passthrough?: boolean | \"first\";\n /** Non-RPC side effects, run once before the first RPC fires. */\n setup?: () => void;\n}\n\n/** The generated `src/mocks/scenarios` barrel, as the engine consumes it. */\nexport interface MockScenarioRegistry {\n byName(name: string): MockScenario | undefined;\n defaultScenario: MockScenario;\n}\n\n/**\n * One CRUD arm of an entity's dispatch table.\n *\n * The List arm needs nothing beyond these three fields to honour filters,\n * paging and total_count: the REQUEST schema arrives on every call as the\n * Connect method's `input`, and the entity schema is the element type of\n * `itemsField` on `responseSchema`.\n */\nexport interface MockListRpc {\n rpc: string;\n responseSchema: DescMessage;\n /**\n * The camelCase name of the list response's repeated field — the ACTUAL\n * proto field (e.g. `keys`), not the camelCased entity plural.\n */\n itemsField: string;\n}\n\nexport interface MockGetRpc {\n rpc: string;\n responseSchema: DescMessage;\n /** The camelCase field wrapping the entity on the response message. */\n entityField: string;\n}\n\nexport interface MockWriteRpc extends MockGetRpc {\n /**\n * The camelCase field wrapping the entity on the REQUEST message. AIP-134\n * requests nest the entity ({ item: {...}, updateMask }); the generated\n * forms submit it flattened. Both are accepted.\n */\n requestField: string;\n}\n\nexport interface MockDeleteRpc {\n rpc: string;\n}\n\n/**\n * Everything the engine needs to serve one entity's CRUD quintet from\n * fixtures. Generated into `src/lib/mock-transport.ts` from the project's\n * proto descriptors.\n */\nexport interface MockEntityDescriptor {\n /** Fully-qualified proto service name, e.g. \"demo.v1.ClinicService\". */\n service: string;\n /** Lowercase entity name, used verbatim in the NotFound message. */\n label: string;\n /**\n * The camelCase PRIMARY-KEY field. The session store keys records by this\n * field; hardcoding \"id\" breaks every surrogate-PK entity (a\n * `usage_event_id` PK projects to a message with no `id` field).\n */\n pkField: string;\n /** Deterministic seed rows — the same values the dev database is seeded with. */\n fixtures: readonly unknown[];\n /** The entity message schema. Required by the create/update write paths. */\n entitySchema?: DescMessage;\n list?: MockListRpc;\n get?: MockGetRpc;\n create?: MockWriteRpc;\n update?: MockWriteRpc;\n delete?: MockDeleteRpc;\n}\n\nexport interface CreateMockTransportOptions {\n /** The resolved scenario — see {@link resolveActiveScenario}. */\n scenario: MockScenario;\n /** Per-entity fixture dispatch. Omit for a scenario-only project. */\n entities?: readonly MockEntityDescriptor[];\n /**\n * Optional real Connect transport. When the active scenario declares\n * `passthrough: true`, any RPC not matched by a scenario handler is\n * forwarded here instead of falling through to the fixtures.\n */\n fallback?: Transport;\n /**\n * Refuse every RPC that is not a read, with PermissionDenied, before any\n * handler, fixture or backend sees it. `true` classifies by the proto's\n * `idempotency_level = NO_SIDE_EFFECTS`; a function classifies itself (a\n * contract that does not annotate idempotency, e.g. by method name).\n */\n readOnly?: boolean | ((method: DescMethod) => boolean);\n /** The message a refused write carries. Default names the RPC. */\n readOnlyMessage?: string;\n /**\n * With `passthrough: \"first\"`: the forwarded call's deadline in ms, after\n * which the scenario answers instead. Default: the caller's own timeout.\n * Enforced by the mock transport itself, so a fallback transport that\n * ignores its timeout cannot hold the call open; a server stream must END\n * within it to count as the backend's answer.\n */\n passthroughTimeoutMs?: number;\n /**\n * With `passthrough: \"first\"`: called each time the backend failed (or\n * timed out) and the mock answered instead. A caller's own abort is never\n * a fallback: it rejects as it would against the backend.\n */\n onPassthroughFallback?: (key: string, error: ConnectError) => void;\n}\n\n/** Options for {@link resolveActiveScenario}. */\nexport interface ResolveScenarioOptions {\n /**\n * The scenario to run, chosen by the app (its host, its runtime config)\n * instead of the URL. When the key is present — even as null or \"\" — the\n * `?scenario=` parameter is NOT read; null/\"\"/unknown select the default.\n */\n name?: string | null;\n}\n\n/**\n * Mutable session stores, keyed by descriptor identity.\n *\n * Create/Update/Delete round-trip within one browser session (a created row\n * appears in the next List; a deleted one disappears) and reset to the\n * deterministic fixtures on reload. The scaffolded original got that from\n * module-scope `const store = new Map(...)`; keying off the descriptor\n * object preserves it — a module-level descriptor array hands back the same\n * store on every call, so building the transport twice (hybrid mode, a test\n * swapping transports) does not silently fork the data.\n */\nconst stores = new WeakMap<MockEntityDescriptor, Map<string, unknown>>();\n\nfunction storeFor(entity: MockEntityDescriptor): Map<string, unknown> {\n let store = stores.get(entity);\n if (!store) {\n store = new Map(\n entity.fixtures.map((row) => [\n String((row as Record<string, unknown>)[entity.pkField]),\n row,\n ]),\n );\n stores.set(entity, store);\n }\n return store;\n}\n\n/** Scenarios whose `setup()` has already run. */\nconst initialized = new WeakSet<MockScenario>();\n\n/**\n * Resolve the scenario the app should run under, and run its `setup()` once.\n *\n * Call this at MODULE SCOPE (the generated `src/lib/mock-transport.ts` does).\n * Reading the URL once — rather than on every RPC — means navigating away\n * from `?scenario=` keeps the scenario active until a full reload, matching\n * the agent-driven flow where the URL is the single source of truth.\n *\n * `setup()` is for non-RPC state (localStorage flags, sessionStorage). It is\n * synchronous and makes no network calls.\n */\nexport function resolveActiveScenario(\n registry: MockScenarioRegistry,\n options: ResolveScenarioOptions = {},\n): MockScenario {\n const requested =\n \"name\" in options\n ? (options.name ?? null)\n : typeof globalThis !== \"undefined\" && globalThis.location\n ? new URLSearchParams(globalThis.location.search).get(\"scenario\")\n : null;\n // A ternary, not `&&`: with `??` alone the empty-string falsy branch leaks\n // '' into the inferred union, and '' survives `??` (which only replaces\n // null/undefined), so downstream access on .setup / .handlers would fail\n // under strict tsc.\n const active =\n (requested ? registry.byName(requested) : undefined) ??\n registry.defaultScenario;\n\n if (!initialized.has(active)) {\n initialized.add(active);\n active.setup?.();\n }\n return active;\n}\n\n/**\n * Normalize whatever a streaming scenario handler returns into an\n * AsyncIterable<unknown>. Accepts arrays, iterables, async iterables, and\n * promises that resolve to any of the above. Single (non-iterable) values\n * are wrapped as a one-element stream — handy for handlers that conceptually\n * yield once.\n */\nexport async function* toAsyncIterable(value: unknown): AsyncIterable<unknown> {\n const resolved = await Promise.resolve(value);\n if (resolved == null) return;\n // AsyncIterable\n if (\n typeof (resolved as { [Symbol.asyncIterator]?: unknown })[\n Symbol.asyncIterator\n ] === \"function\"\n ) {\n for await (const m of resolved as AsyncIterable<unknown>) yield m;\n return;\n }\n // Iterable (including arrays)\n if (\n typeof (resolved as { [Symbol.iterator]?: unknown })[Symbol.iterator] ===\n \"function\"\n ) {\n for (const m of resolved as Iterable<unknown>) yield m;\n return;\n }\n // Single value\n yield resolved;\n}\n\nfunction makeUnaryResponse<T>(\n method: { name: string; parent: { typeName: string }; output?: DescMessage },\n message: T,\n): UnaryResponse<never, never> {\n return {\n service: method.parent as never,\n method: method as never,\n stream: false,\n header: new Headers(),\n message: asResponseMessage(method.output, message) as never,\n trailer: new Headers(),\n };\n}\n\n/**\n * A handler may return the response as a plain init object\n * (`{ items: [...] }`) instead of `create(Schema, {...})`. A real client\n * always receives a full message — every repeated field an array, every\n * scalar its zero value — so a plain object is completed against the\n * method's output schema here; without that, `res.items.map` on a field the\n * handler left out throws in the UI and nowhere near the scenario.\n */\nfunction asResponseMessage(\n output: DescMessage | undefined,\n value: unknown,\n): unknown {\n if (!output || value == null || typeof value !== \"object\") return value;\n if (isMessage(value)) return value;\n return create(output, value as MessageInitShape<DescMessage>);\n}\n\n/** The default read-only classification: the proto says the method has no side effects. */\nfunction isRead(method: DescMethod): boolean {\n return method.idempotency === MethodOptions_IdempotencyLevel.NO_SIDE_EFFECTS;\n}\n\n/**\n * A fixture-backed handler for one RPC key. `requestSchema` is the Connect\n * method's input descriptor — absent only when a caller hand-builds a method\n * object without one, in which case List serves paging alone.\n */\ntype FixtureHandler = (\n input: unknown,\n requestSchema: DescMessage | undefined,\n) => unknown;\n\n// ── List semantics ─────────────────────────────────────────────────────\n//\n// What the backend's generated List does, and therefore what the fixture\n// List does (pkg/crud HandleList + the generated Filters closure):\n//\n// - Every `optional` request field that is SET filters by equality on the\n// entity field of the same name. Enums compare by value. A field with\n// IMPLICIT presence (no `optional`) is never a filter — the backend\n// generates none for it, so the mock must not invent one.\n// - `search` matches case-insensitively against the entity's string\n// fields and enum value names (enum columns are stored as names).\n// - `order_by` (snake_case column, comma-separated, optional ASC/DESC per\n// column) plus `descending` sorts; an unknown column is InvalidArgument.\n// - `page_size` defaults to 50 and is clamped to 100. `total_count` is the\n// filtered count BEFORE paging. `next_page_token` is minted only for the\n// default (primary-key) order — an ordered list is single-page on the\n// backend, and a mock that paged it would hide that.\n//\n// Paging, ordering and search arrive through these request fields, by the\n// names forge's CRUD List requests declare. They are never equality filters.\nconst LIST_CONTROL_FIELDS = new Set([\n \"pageSize\",\n \"pageToken\",\n \"orderBy\",\n \"descending\",\n \"search\",\n]);\n\n/** pkg/crud ListOp's defaults: 0 means 50, and no page exceeds 100. */\nconst DEFAULT_PAGE_SIZE = 50;\nconst MAX_PAGE_SIZE = 100;\n\n/** FeatureSet_FieldPresence.EXPLICIT — proto3 `optional`, oneofs, messages. */\nconst EXPLICIT_PRESENCE = 1;\n\ntype Row = Record<string, unknown>;\n\n/** The entity message a List response repeats, read off its descriptor. */\nfunction listItemSchema(list: MockListRpc): DescMessage | undefined {\n const items = list.responseSchema.field[list.itemsField];\n return items?.fieldKind === \"list\" && items.listKind === \"message\"\n ? items.message\n : undefined;\n}\n\n/** Scalars and enums compare by value; messages, bytes, lists and maps do not. */\nfunction isComparable(field: DescField): boolean {\n if (field.fieldKind === \"enum\") return true;\n return field.fieldKind === \"scalar\" && field.scalar !== ScalarType.BYTES;\n}\n\nfunction sameValue(a: unknown, b: unknown): boolean {\n if (a === b) return true;\n // A 64-bit field is a bigint — or a string under jstype=JS_STRING — and\n // the two sides are not guaranteed to agree on which.\n if (a == null || b == null) return false;\n return (\n (typeof a === \"bigint\" || typeof b === \"bigint\") && String(a) === String(b)\n );\n}\n\nfunction enumName(field: DescField, value: unknown): string | undefined {\n return field.fieldKind === \"enum\"\n ? field.enum.values.find((v) => v.number === value)?.name\n : undefined;\n}\n\n/** The value a column sorts by, as Postgres would order the stored column. */\nfunction sortKey(field: DescField, value: unknown): unknown {\n if (value == null) return undefined;\n // Enum columns hold the value NAME, so they sort alphabetically by name.\n if (field.fieldKind === \"enum\") return enumName(field, value) ?? \"\";\n if (field.fieldKind === \"scalar\") return value;\n if (\n field.fieldKind === \"message\" &&\n field.message.typeName === \"google.protobuf.Timestamp\"\n ) {\n const ts = value as { seconds: bigint; nanos: number };\n return BigInt(ts.seconds) * 1_000_000_000n + BigInt(ts.nanos);\n }\n return undefined;\n}\n\n/** Postgres's default: NULL sorts after every value ascending. */\nfunction compareKeys(a: unknown, b: unknown): number {\n if (a === undefined || b === undefined) {\n return a === b ? 0 : a === undefined ? 1 : -1;\n }\n const x = a as string | number | bigint | boolean;\n const y = b as string | number | bigint | boolean;\n return x < y ? -1 : x > y ? 1 : 0;\n}\n\nfunction invalidArgument(message: string): ConnectError {\n return new ConnectError(`mock-transport: ${message}`, Code.InvalidArgument);\n}\n\n/** Parse `order_by` the way orm.ValidateOrderBy reads it. */\nfunction parseOrderBy(\n clause: string,\n descending: boolean,\n itemSchema: DescMessage,\n): { field: DescField; desc: boolean }[] {\n return clause.split(\",\").map((part) => {\n const [column = \"\", direction] = part.trim().split(/\\s+/);\n const field = itemSchema.fields.find(\n (f) => f.name === column || f.localName === column,\n );\n if (!field) {\n throw invalidArgument(`unknown order-by column \"${column}\"`);\n }\n const dir = direction?.toUpperCase();\n if (dir !== undefined && dir !== \"ASC\" && dir !== \"DESC\") {\n throw invalidArgument(`invalid order-by direction \"${direction}\"`);\n }\n return { field, desc: dir === undefined ? descending : dir === \"DESC\" };\n });\n}\n\n/** A count in whatever JS type the response's total_count field takes. */\nfunction countValue(field: DescField, n: number): unknown {\n if (field.fieldKind !== \"scalar\") return n;\n switch (field.scalar) {\n case ScalarType.INT64:\n case ScalarType.UINT64:\n case ScalarType.SINT64:\n case ScalarType.FIXED64:\n case ScalarType.SFIXED64:\n return field.longAsString ? String(n) : BigInt(n);\n default:\n return n;\n }\n}\n\n/**\n * Answer one List call from the entity's rows. See the List semantics note\n * above for the contract; the engine's tests pin each clause.\n */\nfunction serveList(\n rows: readonly unknown[],\n list: MockListRpc,\n input: unknown,\n requestSchema: DescMessage | undefined,\n): unknown {\n const req = (input ?? {}) as Row;\n const itemSchema = listItemSchema(list);\n let matched = rows as readonly Row[];\n\n if (itemSchema && requestSchema) {\n for (const filter of requestSchema.fields) {\n if (LIST_CONTROL_FIELDS.has(filter.localName)) continue;\n if (filter.presence !== EXPLICIT_PRESENCE || !isComparable(filter)) {\n continue;\n }\n const want = req[filter.localName];\n if (want == null) continue; // unset: no filter\n const target = itemSchema.field[filter.localName];\n if (!target || !isComparable(target)) continue;\n matched = matched.filter((row) => sameValue(row[filter.localName], want));\n }\n }\n\n const search =\n typeof req.search === \"string\" ? req.search.trim().toLowerCase() : \"\";\n if (itemSchema && search) {\n const searchable = itemSchema.fields.filter(\n (f) =>\n f.fieldKind === \"enum\" ||\n (f.fieldKind === \"scalar\" && f.scalar === ScalarType.STRING),\n );\n matched = matched.filter((row) =>\n searchable.some((f) => {\n const value = row[f.localName];\n const text = f.fieldKind === \"enum\" ? enumName(f, value) : value;\n return typeof text === \"string\" && text.toLowerCase().includes(search);\n }),\n );\n }\n\n const orderBy = typeof req.orderBy === \"string\" ? req.orderBy.trim() : \"\";\n if (itemSchema && orderBy) {\n const keys = parseOrderBy(orderBy, req.descending === true, itemSchema);\n matched = [...matched].sort((a, b) => {\n for (const { field, desc } of keys) {\n const c = compareKeys(\n sortKey(field, a[field.localName]),\n sortKey(field, b[field.localName]),\n );\n if (c !== 0) return desc ? -c : c;\n }\n return 0;\n });\n }\n\n const total = matched.length;\n\n let offset = 0;\n const token = typeof req.pageToken === \"string\" ? req.pageToken : \"\";\n if (token) {\n // The mock's own cursor: an offset into the filtered rows. Opaque to the\n // client, exactly like the backend's keyset cursor.\n if (!/^\\d+$/.test(token)) throw invalidArgument(\"invalid page token\");\n offset = Number(token);\n }\n const requested = Number(req.pageSize ?? 0);\n const pageSize =\n requested > 0 ? Math.min(requested, MAX_PAGE_SIZE) : DEFAULT_PAGE_SIZE;\n const end = offset + pageSize;\n\n const init: Row = { [list.itemsField]: matched.slice(offset, end) };\n const totalField = list.responseSchema.field.totalCount;\n if (totalField) init.totalCount = countValue(totalField, total);\n if (list.responseSchema.field.nextPageToken && !orderBy && end < total) {\n init.nextPageToken = String(end);\n }\n return create(list.responseSchema, init as MessageInitShape<DescMessage>);\n}\n\n/**\n * Compile the entity descriptors into a flat `${service}/${rpc}` → handler\n * map. Building it once per transport keeps per-RPC dispatch to a single\n * lookup, exactly like the generated `switch` it replaces.\n */\nfunction buildFixtureTable(\n entities: readonly MockEntityDescriptor[],\n): Map<string, FixtureHandler> {\n const table = new Map<string, FixtureHandler>();\n\n for (const entity of entities) {\n const pk = entity.pkField;\n const key = (rpc: string) => `${entity.service}/${rpc}`;\n\n if (entity.list) {\n const list = entity.list;\n table.set(key(list.rpc), (input, requestSchema) =>\n serveList(\n Array.from(storeFor(entity).values()),\n list,\n input,\n requestSchema,\n ),\n );\n }\n\n if (entity.get) {\n const { rpc, responseSchema, entityField } = entity.get;\n table.set(key(rpc), (input) => {\n // Read the key off the SAME field the store is keyed by, not a\n // hardcoded `id` — a surrogate-PK entity would otherwise look up\n // String(undefined) and miss every record.\n const req = input as Record<string, unknown> | undefined;\n const found = storeFor(entity).get(String(req?.[pk]));\n if (!found) {\n // A miss is NotFound — exactly what the real backend returns.\n // (Falling back to the first fixture made every detail page\n // \"work\" against the wrong record and hid bad-id bugs.)\n throw new ConnectError(\n `${entity.label} ${String(req?.[pk])} not found`,\n Code.NotFound,\n );\n }\n return create(responseSchema, {\n [entityField]: found,\n } as MessageInitShape<DescMessage>);\n });\n }\n\n if (entity.create && entity.entitySchema) {\n const { rpc, responseSchema, entityField, requestField } = entity.create;\n const entitySchema = entity.entitySchema;\n table.set(key(rpc), (input) => {\n // Create requests carry the entity fields flattened (that's how the\n // generated form submits); a nested { <entity>: {...} } payload is\n // accepted too.\n const req = (input ?? {}) as Record<string, unknown>;\n const init = {\n ...((req[requestField] ?? req) as Record<string, unknown>),\n };\n delete init.$typeName;\n // Mint the primary key on the PK field the store is keyed by — for a\n // surrogate-PK entity this is NOT `id`, and writing a generated `id`\n // would leave the store key undefined so the row never round-trips.\n const id =\n typeof init[pk] === \"string\" && init[pk]\n ? (init[pk] as string)\n : crypto.randomUUID();\n const created = create(entitySchema, {\n ...init,\n [pk]: id,\n } as MessageInitShape<DescMessage>);\n storeFor(entity).set(String(id), created);\n return create(responseSchema, {\n [entityField]: created,\n } as MessageInitShape<DescMessage>);\n });\n }\n\n if (entity.update && entity.entitySchema) {\n const { rpc, responseSchema, entityField, requestField } = entity.update;\n const entitySchema = entity.entitySchema;\n table.set(key(rpc), (input) => {\n const req = (input ?? {}) as Record<string, unknown>;\n // AIP-134 requests wrap the entity ({ <entity>: {...}, updateMask })\n // — the id lives inside the wrapper; flat requests carry it at the\n // top level.\n const patch = {\n ...((req[requestField] ?? req) as Record<string, unknown>),\n };\n delete patch.$typeName;\n const id = String(patch[pk] ?? req[pk] ?? \"\");\n const store = storeFor(entity);\n const existing = store.get(id);\n if (!existing) {\n throw new ConnectError(\n `${entity.label} ${id} not found`,\n Code.NotFound,\n );\n }\n const updated = create(entitySchema, {\n ...(existing as Record<string, unknown>),\n ...patch,\n [pk]: id,\n } as MessageInitShape<DescMessage>);\n store.set(id, updated);\n return create(responseSchema, {\n [entityField]: updated,\n } as MessageInitShape<DescMessage>);\n });\n }\n\n if (entity.delete) {\n table.set(key(entity.delete.rpc), (input) => {\n // Delete by the SAME field the store is keyed by.\n const req = input as Record<string, unknown> | undefined;\n storeFor(entity).delete(String(req?.[pk]));\n // Delete returns an empty response — the standard CRUD shape.\n return {};\n });\n }\n }\n\n return table;\n}\n\n/**\n * Create the mock transport.\n *\n * The generated `src/lib/mock-transport.ts` supplies the resolved scenario\n * and the project's entity descriptors; `connect.ts` supplies the optional\n * real transport when running in hybrid mode.\n */\nexport function createMockTransport(\n options: CreateMockTransportOptions,\n): Transport {\n const {\n scenario,\n entities = [],\n fallback,\n readOnly,\n passthroughTimeoutMs,\n onPassthroughFallback,\n } = options;\n const passthrough = scenario.passthrough === true && fallback != null;\n const first = scenario.passthrough === \"first\" && fallback != null;\n const fixtures = buildFixtureTable(entities);\n const readsOnly = typeof readOnly === \"function\" ? readOnly : isRead;\n\n // 0) The read-only guard: before any dispatch, so a write never reaches a\n // handler, a fixture store or the backend.\n const guard = (method: DescMethod, key: string) => {\n if (readOnly && !readsOnly(method)) {\n throw new ConnectError(\n options.readOnlyMessage ?? `mock-transport: ${key} is not a read`,\n Code.PermissionDenied,\n );\n }\n };\n // \"first\": the backend's answer, or undefined when the mock should answer.\n //\n // The deadline is enforced HERE, not left to the fallback transport: the\n // attempt gets its own signal (aborted by the caller's signal or by the\n // timer) and is raced against that signal, so a transport that ignores\n // both its timeout and its signal still cannot hold the call open. A\n // caller's own abort is rethrown; only the deadline or a failure falls back.\n const tryBackend = async <R>(\n key: string,\n signal: AbortSignal | undefined,\n timeoutMs: number | undefined,\n call: (signal: AbortSignal) => Promise<R>,\n ): Promise<R | undefined> => {\n const attempt = new AbortController();\n const abortAttempt = () => attempt.abort(signal?.reason);\n if (signal?.aborted) abortAttempt();\n signal?.addEventListener(\"abort\", abortAttempt, { once: true });\n const timer =\n timeoutMs != null && timeoutMs > 0\n ? setTimeout(\n () =>\n attempt.abort(\n new ConnectError(\n `mock-transport: ${key} exceeded ${timeoutMs}ms`,\n Code.DeadlineExceeded,\n ),\n ),\n timeoutMs,\n )\n : undefined;\n const abandoned = new Promise<never>((_, reject) => {\n const fail = () => reject(attempt.signal.reason);\n if (attempt.signal.aborted) fail();\n else attempt.signal.addEventListener(\"abort\", fail, { once: true });\n });\n // The race observes it; this keeps the release below from surfacing as\n // an unhandled rejection after the race has settled.\n abandoned.catch(() => undefined);\n try {\n return await Promise.race([call(attempt.signal), abandoned]);\n } catch (err) {\n if (signal?.aborted) throw err;\n onPassthroughFallback?.(key, ConnectError.from(err));\n return undefined;\n } finally {\n if (timer !== undefined) clearTimeout(timer);\n signal?.removeEventListener(\"abort\", abortAttempt);\n // Release whatever the backend attempt still holds (a pending fetch,\n // an unread stream) once it has been answered or abandoned.\n attempt.abort();\n }\n };\n\n // Bind the object literal to a Transport-typed variable rather than\n // casting at the return site. A trailing assertion cast does not propagate\n // Connect's Transport signature backwards into the literal's method\n // bodies, so under `strict` tsc every callback parameter on unary/stream\n // errors with TS7006 (\"implicitly has an 'any' type\").\n const transport: Transport = {\n // Connect v2's Transport.unary signature is\n // (method, signal, timeoutMs, header, input, contextValues)\n // — method first, no separate service arg. `method.parent.typeName` is\n // the fully-qualified service name; that is what handler keys and\n // fixture keys are matched against.\n async unary(method, signal, timeoutMs, header, input, contextValues) {\n const key = `${method.parent.typeName}/${method.name}`;\n guard(method, key);\n\n // 0b) \"first\": the backend answers unless it fails.\n if (first) {\n const deadline = passthroughTimeoutMs ?? timeoutMs;\n const live = await tryBackend(key, signal, deadline, (attempt) =>\n fallback!.unary(\n method,\n attempt,\n deadline,\n header,\n input,\n contextValues,\n ),\n );\n if (live) return live;\n }\n\n // 1) Scenario overlay.\n const handler = scenario.handlers[key];\n if (handler) {\n const result = await handler(input as never);\n return makeUnaryResponse(method, result);\n }\n\n // 2) Passthrough: route to the real backend instead of fixtures.\n // Skips fixtures entirely — in hybrid mode the whole point is\n // \"use real data for anything not explicitly stubbed\".\n if (passthrough) {\n return fallback!.unary(\n method,\n signal,\n timeoutMs,\n header,\n input,\n contextValues,\n );\n }\n\n // 3) Base fixture dispatch, backed by the mutable per-entity stores so\n // writes round-trip within the session. Misses are REAL errors\n // (Code.NotFound), never a silent wrong-record fallback.\n const fixture = fixtures.get(key);\n if (fixture) {\n // `method.input` is typed as always present, but a hand-built method\n // object (a test, a custom harness) may omit it.\n const requestSchema = (method as { input?: DescMessage }).input;\n return makeUnaryResponse(method, fixture(input, requestSchema));\n }\n\n // 4) Nothing matched. Surface a clear error instead of hanging.\n return Promise.reject(\n new ConnectError(\n `mock-transport: no scenario handler or entity fixture for ${key}`,\n Code.Unimplemented,\n ),\n );\n },\n\n // Streaming: a scenario handler can return an array, iterable, async\n // iterable, or a Promise resolving to any of those. The transport adapts\n // it into the AsyncIterable<Response> shape Connect expects. If no\n // handler matches, reject with Unimplemented — base-fixture streaming is\n // intentionally not served (there is no canonical \"list of N messages\"\n // shape for an arbitrary streaming RPC).\n //\n // No explicit return-type annotation: the outer `const transport:\n // Transport` binding lets tsc infer the per-callback signature from\n // Connect's generic Transport.stream<I, O>. Annotating this as\n // Promise<StreamResponse<never, never>> makes the passthrough branch\n // ill-typed (TS2322) because fallback.stream returns StreamResponse<I,O>.\n async stream(method, signal, timeoutMs, header, input, contextValues) {\n const key = `${method.parent.typeName}/${method.name}`;\n guard(method, key);\n // \"first\" forwards server streams only: a client-streaming request is\n // consumed by the attempt and could not be replayed to the handler.\n //\n // The backend's stream is read to its END, within the deadline, before\n // it counts as an answer, then replayed: a stream that fails or stalls\n // after its headers arrived still falls back to the mock, as a unary\n // call does. So \"first\" suits finite server streams; a stream that\n // never ends always answers from the mock once the deadline passes.\n if (first && method.methodKind === \"server_streaming\") {\n const deadline = passthroughTimeoutMs ?? timeoutMs;\n const live = await tryBackend(\n key,\n signal,\n deadline,\n async (attempt) => {\n const res = await fallback!.stream(\n method,\n attempt,\n deadline,\n header,\n input,\n contextValues,\n );\n const messages: unknown[] = [];\n for await (const m of res.message) messages.push(m);\n return {\n ...res,\n message: toAsyncIterable(messages) as typeof res.message,\n };\n },\n );\n if (live) return live;\n }\n const handler = scenario.handlers[key];\n if (!handler) {\n // Passthrough mirrors the unary path: in hybrid mode, unmatched\n // streaming RPCs go to the real backend.\n if (passthrough) {\n return fallback!.stream(\n method,\n signal,\n timeoutMs,\n header,\n input,\n contextValues,\n );\n }\n return Promise.reject(\n new ConnectError(\n `mock-transport: no scenario handler for streaming RPC ${key}`,\n Code.Unimplemented,\n ),\n );\n }\n // Read the request stream eagerly into an array so the scenario handler\n // sees the full client-streaming payload. For server-stream and\n // unary-into-stream-out RPCs this is a single message.\n const requestMessages: unknown[] = [];\n try {\n for await (const m of input as AsyncIterable<unknown>) {\n requestMessages.push(m);\n }\n } catch {\n // Synthetic clients sometimes pass a single value rather than an\n // iterable; treat that as an empty request payload.\n }\n const handlerInput =\n requestMessages.length <= 1 ? requestMessages[0] : requestMessages;\n const result = handler(handlerInput as never);\n return {\n service: method.parent as never,\n method: method as never,\n stream: true,\n header: new Headers(),\n message: toAsyncIterable(result) as AsyncIterable<never>,\n trailer: new Headers(),\n };\n },\n };\n return transport;\n}\n"]}
|
package/dist/telemetry.js
CHANGED
|
@@ -73,6 +73,21 @@
|
|
|
73
73
|
// as they are while the SDK loads. A page that never becomes visible sends
|
|
74
74
|
// nothing.
|
|
75
75
|
//
|
|
76
|
+
// ── Paint vitals are dropped for a page first shown late ─────────────────
|
|
77
|
+
//
|
|
78
|
+
// web-vitals reports no FCP or LCP painted after the page was first hidden,
|
|
79
|
+
// but it learns of hiding only from the moment it registers, and it registers
|
|
80
|
+
// inside the SDK, which starts only once the page is visible. So a page loaded
|
|
81
|
+
// in the background would report, as its FCP and LCP, the time from navigation
|
|
82
|
+
// until it was first SHOWN: a tab opened behind another for a minute reported
|
|
83
|
+
// a 60 s LCP. The runtime records when the page was first hidden (the browser's
|
|
84
|
+
// `visibility-state` entries where it has them, else from startup on) and
|
|
85
|
+
// drops an FCP or LCP painted at or after that moment. The paint time is the
|
|
86
|
+
// metric's value (web-vitals times it from navigation, less a prerendered
|
|
87
|
+
// page's activationStart); a back/forward-cache restore, timed from the
|
|
88
|
+
// restore, is kept. TTFB, CLS and INP are kept: being hidden does not change
|
|
89
|
+
// them.
|
|
90
|
+
//
|
|
76
91
|
// ── Network URLs carry no query string ───────────────────────────────────
|
|
77
92
|
//
|
|
78
93
|
// fetch/XHR spans record the request URL, and a query string is where tokens,
|
|
@@ -198,10 +213,14 @@ export function initBrowserTelemetry(config) {
|
|
|
198
213
|
return started;
|
|
199
214
|
}
|
|
200
215
|
async function start(config, ingest) {
|
|
216
|
+
// Before the first await: until web-vitals registers in hdx.init, only this
|
|
217
|
+
// watch sees the page hidden (see "Paint vitals" in the header).
|
|
218
|
+
const hidden = watchFirstHidden();
|
|
201
219
|
try {
|
|
202
220
|
await firstVisible();
|
|
203
221
|
const hdx = resolveClient(await import("@hyperdx/browser"));
|
|
204
222
|
if (!hdx || isTelemetryDisabled()) {
|
|
223
|
+
hidden.stop();
|
|
205
224
|
setTelemetrySink(null);
|
|
206
225
|
return false;
|
|
207
226
|
}
|
|
@@ -209,6 +228,9 @@ async function start(config, ingest) {
|
|
|
209
228
|
// Before init: the SDK reads its session cookie as it starts.
|
|
210
229
|
keepSessionWithoutCookies();
|
|
211
230
|
hdx.init(buildSdkOptions({ ...config, replay }, ingest, window.location.origin, pageClientResourceAttributes()));
|
|
231
|
+
// From here web-vitals watches visibility itself.
|
|
232
|
+
hidden.stop();
|
|
233
|
+
dropBackgroundPaintVitals(hidden.at());
|
|
212
234
|
// After init: both hook what the SDK RECORDS, never what the app sees.
|
|
213
235
|
const benign = benignFilter(config, hdx);
|
|
214
236
|
filterSdkErrorSpans(benign);
|
|
@@ -271,6 +293,7 @@ async function start(config, ingest) {
|
|
|
271
293
|
catch (err) {
|
|
272
294
|
// Blocked chunk, ad-blocker, SDK throw: telemetry must never break the app.
|
|
273
295
|
// A startup that failed after the hooks went in takes them out again.
|
|
296
|
+
hidden.stop();
|
|
274
297
|
removeBenignFilter();
|
|
275
298
|
console.debug("[telemetry] disabled:", err);
|
|
276
299
|
setTelemetrySink(null);
|
|
@@ -298,6 +321,139 @@ function firstVisible() {
|
|
|
298
321
|
document.addEventListener("visibilitychange", onChange);
|
|
299
322
|
});
|
|
300
323
|
}
|
|
324
|
+
/**
|
|
325
|
+
* Watches for the page's first hidden moment from now until stop(). The
|
|
326
|
+
* browser's `visibility-state` entries (Chromium) go back to navigation; where
|
|
327
|
+
* there are none, a page hidden now counts as hidden from now on, and a later
|
|
328
|
+
* visibilitychange to hidden from then. See "Paint vitals" in the header.
|
|
329
|
+
*/
|
|
330
|
+
function watchFirstHidden() {
|
|
331
|
+
let at = Number.POSITIVE_INFINITY;
|
|
332
|
+
const now = () => typeof performance !== "undefined" && typeof performance.now === "function"
|
|
333
|
+
? performance.now()
|
|
334
|
+
: 0;
|
|
335
|
+
try {
|
|
336
|
+
const entries = typeof performance !== "undefined" &&
|
|
337
|
+
typeof performance.getEntriesByType === "function"
|
|
338
|
+
? performance.getEntriesByType("visibility-state")
|
|
339
|
+
: [];
|
|
340
|
+
// A prerendered page is hidden until it is activated, as web-vitals
|
|
341
|
+
// also ignores: only hiding after activation counts.
|
|
342
|
+
const activated = activationStart();
|
|
343
|
+
for (const e of entries) {
|
|
344
|
+
if (e.name === "hidden" && e.startTime >= activated) {
|
|
345
|
+
at = Math.min(at, e.startTime);
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
catch {
|
|
350
|
+
// No such entry type here: the document's state below decides.
|
|
351
|
+
}
|
|
352
|
+
if (typeof document === "undefined") {
|
|
353
|
+
return { at: () => at, stop: () => { } };
|
|
354
|
+
}
|
|
355
|
+
const hiddenNow = () => document.visibilityState === "hidden" &&
|
|
356
|
+
!document.prerendering;
|
|
357
|
+
if (hiddenNow()) {
|
|
358
|
+
at = Math.min(at, now());
|
|
359
|
+
}
|
|
360
|
+
if (typeof document.addEventListener !== "function") {
|
|
361
|
+
return { at: () => at, stop: () => { } };
|
|
362
|
+
}
|
|
363
|
+
const onChange = () => {
|
|
364
|
+
if (hiddenNow()) {
|
|
365
|
+
at = Math.min(at, now());
|
|
366
|
+
}
|
|
367
|
+
};
|
|
368
|
+
document.addEventListener("visibilitychange", onChange);
|
|
369
|
+
return {
|
|
370
|
+
at: () => at,
|
|
371
|
+
stop: () => document.removeEventListener?.("visibilitychange", onChange),
|
|
372
|
+
};
|
|
373
|
+
}
|
|
374
|
+
/** The tracer (name) the SDK's web-vitals instrumentation records under. */
|
|
375
|
+
const SDK_WEBVITALS_SCOPE = "webvitals";
|
|
376
|
+
/** The web vitals timed from navigation to a paint: wrong for a hidden page. */
|
|
377
|
+
const PAINT_VITALS = ["fcp", "lcp"];
|
|
378
|
+
/** The span attribute the SDK copies web-vitals' metric.navigationType into. */
|
|
379
|
+
const SDK_WEBVITALS_NAV_TYPE = "webvitals.navigation_type";
|
|
380
|
+
/**
|
|
381
|
+
* When an FCP or LCP span's paint happened, in ms since the time origin (the
|
|
382
|
+
* coordinates of hiddenAt), or undefined when its value is not timed from
|
|
383
|
+
* navigation. The SDK (@hyperdx/otel-web webvitals.js) sets the attribute to
|
|
384
|
+
* web-vitals' metric.value, which web-vitals 3 computes as the paint entry's
|
|
385
|
+
* startTime minus activationStart (0 except for a prerendered page); so the
|
|
386
|
+
* paint time is the value plus activationStart. A page restored from the
|
|
387
|
+
* back/forward cache instead reports the time since the restore, which says
|
|
388
|
+
* nothing about when the first load was hidden.
|
|
389
|
+
*/
|
|
390
|
+
function paintTime(value, attributes) {
|
|
391
|
+
const navigationType = attributes[SDK_WEBVITALS_NAV_TYPE];
|
|
392
|
+
if (navigationType === "back-forward-cache") {
|
|
393
|
+
return undefined;
|
|
394
|
+
}
|
|
395
|
+
return navigationType === "prerender" ? value + activationStart() : value;
|
|
396
|
+
}
|
|
397
|
+
/** The navigation's activationStart (a prerendered page), else 0. */
|
|
398
|
+
function activationStart() {
|
|
399
|
+
try {
|
|
400
|
+
const [nav] = typeof performance !== "undefined" &&
|
|
401
|
+
typeof performance.getEntriesByType === "function"
|
|
402
|
+
? performance.getEntriesByType("navigation")
|
|
403
|
+
: [];
|
|
404
|
+
const at = nav?.activationStart;
|
|
405
|
+
return typeof at === "number" && Number.isFinite(at) ? at : 0;
|
|
406
|
+
}
|
|
407
|
+
catch {
|
|
408
|
+
return 0;
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
/**
|
|
412
|
+
* Drops an FCP or LCP span whose paint came at or after hiddenAt (ms since the
|
|
413
|
+
* time origin): it measured how long the page waited to be shown. A no-op for
|
|
414
|
+
* a page that was never hidden.
|
|
415
|
+
*/
|
|
416
|
+
function dropBackgroundPaintVitals(hiddenAt) {
|
|
417
|
+
if (!Number.isFinite(hiddenAt)) {
|
|
418
|
+
return;
|
|
419
|
+
}
|
|
420
|
+
const proxy = trace.getTracerProvider();
|
|
421
|
+
const provider = (proxy.getDelegate?.() ?? proxy);
|
|
422
|
+
const tracer = provider.getTracer?.(SDK_WEBVITALS_SCOPE);
|
|
423
|
+
if (!tracer || typeof tracer.startSpan !== "function") {
|
|
424
|
+
return;
|
|
425
|
+
}
|
|
426
|
+
const original = tracer.startSpan;
|
|
427
|
+
const startSpan = function (name, ...rest) {
|
|
428
|
+
const span = original.call(this, name, ...rest);
|
|
429
|
+
if (typeof span?.end !== "function") {
|
|
430
|
+
return span;
|
|
431
|
+
}
|
|
432
|
+
const end = span.end;
|
|
433
|
+
span.end = function (...args) {
|
|
434
|
+
const attributes = span.attributes ?? {};
|
|
435
|
+
for (const vital of PAINT_VITALS) {
|
|
436
|
+
const value = attributes[vital];
|
|
437
|
+
if (typeof value !== "number") {
|
|
438
|
+
continue;
|
|
439
|
+
}
|
|
440
|
+
const paintedAt = paintTime(value, attributes);
|
|
441
|
+
if (paintedAt !== undefined && paintedAt >= hiddenAt) {
|
|
442
|
+
// Never ended, so never exported.
|
|
443
|
+
return undefined;
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
return end.apply(this, args);
|
|
447
|
+
};
|
|
448
|
+
return span;
|
|
449
|
+
};
|
|
450
|
+
tracer.startSpan = startSpan;
|
|
451
|
+
benignTeardown.push(() => {
|
|
452
|
+
if (tracer.startSpan === startSpan) {
|
|
453
|
+
tracer.startSpan = original;
|
|
454
|
+
}
|
|
455
|
+
});
|
|
456
|
+
}
|
|
301
457
|
// ── One failure, one record ──────────────────────────────────────────────
|
|
302
458
|
//
|
|
303
459
|
// The SDK records an Error that reaches window "error", window
|
package/dist/telemetry.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"telemetry.js","sourceRoot":"","sources":["../src/telemetry.ts"],"names":[],"mappings":"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","sourcesContent":["// Part of @reliantlabs/forge-web-runtime — the web twin of forge/pkg.\n//\n// Browser telemetry: the HyperDX browser SDK, initialised the forge way.\n//\n// Captures errors (uncaught, unhandled rejections, boundary-caught), console\n// output, fetch/XHR spans, document load, long tasks and web vitals, and\n// ships them to ClickStack through a SAME-ORIGIN `/_otel` route.\n//\n// ── Why HyperDX REPLACES the old OTel web wiring, not joins it ───────────\n//\n// @hyperdx/browser wraps @hyperdx/otel-web, which builds its own\n// WebTracerProvider and calls provider.register() — the global tracer\n// provider, context manager and propagator. A second registration (the old\n// `./otel` subpath did exactly that) is rejected by @opentelemetry/api with a\n// \"duplicate registration\" diagnostic and silently loses: whichever ran\n// second would simply never see a span. Two tracer providers cannot coexist\n// in one page, so there is one, and it is HyperDX's. `./otel` and its eight\n// @opentelemetry/* SDK peer dependencies are gone.\n//\n// traceparent on RPCs is unaffected. traceInterceptor (trace.ts) injects the\n// active span's context into every Connect call, or synthesises a valid\n// traceparent when none is active — with no SDK at all. With the SDK running,\n// the fetch span HyperDX opens for the call carries the same trace id, and\n// `apiOrigins` below makes that hold for a cross-origin API too (which is\n// every dev loop: the API binds its own port).\n//\n// ── The browser holds no secret ──────────────────────────────────────────\n//\n// `url` is `${location.origin}/_otel`. The browser talks only to its own\n// origin; a dev-server proxy (next.config.ts rewrites / Vite server.proxy) or\n// the deployment's ingress forwards `/_otel/v1/{traces,logs}` to the OTLP/HTTP\n// port of a collector, and that hop — never the bundle — owns credentials.\n//\n// The SDK nevertheless wants an `apiKey` and sends it as an `authorization`\n// header. We pass PLACEHOLDER_API_KEY, a constant that grants nothing and is\n// public by construction. A collector that enforces ingestion auth (ClickStack\n// `collectorAuthenticationEnforced`) rejects it with 401, so the proxy in\n// front of such a collector must strip the header or replace it with the real\n// key. The local ClickStack collector does not enforce, and ignores it.\n//\n// ── Replay: shipped, off, masked, media blocked ─────────────────────────\n//\n// The SDK bundles an rrweb recorder. It is DISABLED unless `replay: true`.\n// Privacy is forced, not offered: every input and all text is masked, canvas is\n// never recorded, and images, video, audio, iframes and embeds are BLOCKED\n// (replaced by a same-size placeholder; their pixels never leave the browser).\n// Images are not inlined and web fonts are not collected. There is deliberately\n// no option to turn any of that off while replay is on; an app that needs\n// unmasked replay passes its own SDK options.\n//\n// `replaySampleRate` (0..1, default 1) records only that share of SESSIONS. The\n// SDK has no session sampler, so the decision is made here, once, and held in\n// sessionStorage for the tab's session.\n//\n// ── One session per visit, even where cookies are dropped ────────────────\n//\n// The SDK keeps its session id only in the `__rum_sid` cookie and mints a new\n// one whenever it cannot read that cookie back, which it checks every minute.\n// An origin that drops cookies (an Electron renderer on a custom scheme such\n// as `app://`) therefore got a new session every minute. Before init, the\n// runtime probes whether cookies persist and, when they do not, keeps that one\n// cookie in localStorage with the same 15-minute inactivity and 4-hour limits\n// (session-cookie-fallback.ts). Origins whose cookies work are untouched.\n//\n// ── No session until the page has been seen ──────────────────────────────\n//\n// A page loaded in the background (a desktop window opened hidden, a tab\n// restored behind another) starts no session at all: the SDK is not loaded\n// until the document is first visible. Started hidden, it would mint a session\n// made only of background fetch spans, with nothing on screen to record, and\n// the recorder would hold no replay for it. Until then reportException returns\n// false (the caller logs to the console) and track() calls are held, bounded,\n// as they are while the SDK loads. A page that never becomes visible sends\n// nothing.\n//\n// ── Network URLs carry no query string ───────────────────────────────────\n//\n// fetch/XHR spans record the request URL, and a query string is where tokens,\n// OAuth codes and search terms live. The runtime rewrites `http.url` and\n// `url.full` on every fetch/XHR span to the URL without query or fragment.\n// The SDK's own `location.href` attribute (the page URL, stamped on every span)\n// has no client-side hook; the ingest side scrubs it.\n//\n// ── Network spans are named by what they called ──────────────────────────\n//\n// HyperDX names every fetch/XHR span `HTTP <METHOD>`, so a trace a browser\n// starts is titled \"HTTP POST\" whatever it did. The same hook renames it to\n// the procedure when it is a Connect/gRPC call (`POST /pkg.v1.Service/Method`,\n// the server span's name with the method in front; spanRouteName). Any other\n// URL keeps `HTTP <METHOD>`: a free-form path can carry ids and tokens, and\n// the span name is exported unscrubbed.\n//\n// ── Client context ───────────────────────────────────────────────────────\n//\n// The page reports what only it can know about its client — client hints\n// (browser.brands/platform/mobile), its viewport and screen (app.viewport.*,\n// app.screen.*) and, inside a desktop app, the app's versions from the\n// `window.forgeDesktop` preload bridge (app.desktop.*) — sanitized\n// (client-context.ts). Browser, OS and device type are NOT page claims: the\n// ingest side derives them from the request's User-Agent and Sec-CH-UA\n// headers and overwrites any the page sent.\n//\n// ── Loading ──────────────────────────────────────────────────────────────\n//\n// The SDK is ~600 KB minified (rrweb and the OTel web stack are bundled in\n// it), so it is imported lazily: bundlers split it into its own chunk that\n// loads after the app is interactive and costs the first paint nothing.\n// initBrowserTelemetry is therefore async and idempotent — every caller gets\n// the same promise, which is what survives React StrictMode's double mount and\n// Fast Refresh. It is a no-op without a DOM (SSR, prerender) and without an\n// endpoint, and it never throws.\nimport { trace } from \"@opentelemetry/api\";\n\nimport {\n captureAttribution,\n type AttributionTouch,\n detectAppClient,\n takeIdentifyProps,\n} from \"./attribution.js\";\nimport {\n type BenignErrorClassifier,\n type BenignErrorSource,\n classifyBenignError,\n FilteredErrorCounter,\n} from \"./benign-errors.js\";\nimport {\n pageClientResourceAttributes,\n watchViewport,\n} from \"./client-context.js\";\nimport { setExceptionReporter } from \"./error-reporter.js\";\nimport { installSessionCookieFallback } from \"./session-cookie-fallback.js\";\nimport {\n registerRumSession,\n registerTelemetryStartup,\n rumSessionId,\n} from \"./telemetry-gate.js\";\nimport {\n isTelemetryDisabled,\n setTelemetrySink,\n type TrackValue,\n} from \"./track.js\";\n\nexport {\n clientResourceAttributes,\n type ForgeDesktopInfo,\n viewportAttributes,\n} from \"./client-context.js\";\n\nexport {\n cookiesPersist,\n installSessionCookieFallback,\n RUM_SESSION_COOKIE,\n RUM_SESSION_STORAGE_KEY,\n} from \"./session-cookie-fallback.js\";\n\nexport {\n type BenignErrorClassifier,\n type BenignErrorKind,\n classifyBenignError,\n FILTERED_ERRORS_ACTION,\n} from \"./benign-errors.js\";\n\n/** Where the browser ships telemetry: this origin's `/_otel`. */\nexport const DEFAULT_INGEST_PATH = \"/_otel\";\n\n/**\n * The apiKey handed to the SDK. Public by construction: it identifies\n * nothing and authorises nothing. See the header — the proxy or collector\n * owns the real credential.\n */\nexport const PLACEHOLDER_API_KEY = \"forge-browser-public\";\n\nexport interface BrowserTelemetryConfig {\n /** `service.name` on everything this page emits. */\n serviceName: string;\n /** `service.version`. Omit for none. */\n serviceVersion?: string;\n /**\n * The forge environment name. Emitted as BOTH `deployment.environment.name`\n * (current semconv) and `deployment.environment` (the legacy key HyperDX's\n * default sources still key on).\n */\n environment?: string;\n /** `service.namespace`, conventionally the project name. */\n serviceNamespace?: string;\n /**\n * The forge frontend's name, emitted as the `forge.frontend` resource\n * attribute. Unlike `serviceName` (which an app may override to anything) it\n * is the stable key that joins this page's telemetry to the frontend and its\n * source maps. Omit for none.\n */\n frontend?: string;\n /**\n * Ingest base: a path on this origin (`/_otel`) or, as an escape hatch, an\n * absolute URL. Unset, empty, or `off` disables telemetry — the app runs\n * untraced rather than throwing, which is what makes it safe to call\n * unconditionally from the app shell.\n */\n endpoint?: string;\n /**\n * Origins (or URLs — only the origin is used) of the app's own backend.\n * Requests to them always get a `traceparent` from the SDK's fetch/XHR\n * spans. This page's own origin is always included.\n */\n apiOrigins?: Array<string | undefined>;\n /**\n * Mirror console.log/info/warn/debug into telemetry spans. Default true;\n * pass false when console output can hold user content. It does NOT stop\n * `console.error(err)` from being recorded as an error: the SDK's error\n * instrumentation is separate and always on.\n */\n consoleCapture?: boolean;\n /**\n * Capture full request/response headers AND BODIES on fetch/XHR spans.\n * Default false, and it should stay false: bodies are user data.\n */\n advancedNetworkCapture?: boolean;\n /**\n * Session replay (rrweb). Default false. When true, all text and inputs are\n * masked, media is blocked and canvas is not recorded (see the header).\n */\n replay?: boolean;\n /**\n * The share of sessions to record when `replay` is true, 0..1. Default 1\n * (every session). Decided once per session and held in sessionStorage. A\n * value that is not a number records nothing. An app with its own policy\n * (every session of a new user, a fraction of the rest) computes the rate\n * it wants for this session and passes it here.\n */\n replaySampleRate?: number;\n /** Verbose SDK diagnostics to the console. Default false. */\n debug?: boolean;\n /**\n * The `app.client` stamped on every event: `web`, `electron` or `landing`\n * (any short string is accepted). Unset, it is `electron` inside Electron\n * and `web` elsewhere.\n */\n appClient?: string;\n /**\n * localStorage key holding this browser's anonymous visitor id (stamped as\n * `visitor.id`). Set it to adopt an id a site already keeps, e.g. a landing\n * page's `reliant.visitor_id`. Default `forge.visitor_id`. A `rid` in the\n * landing URL wins over it.\n */\n visitorIdStorageKey?: string;\n /**\n * Start visitor attribution with the SDK. Default true. Pass false when the\n * visitor id needs a consent the page does not have yet (error telemetry for\n * everyone, a visitor id only with analytics consent): no visitor id is\n * created, read or stamped, nothing is captured from the URL, withAttribution\n * returns URLs untouched and `user_identified` never fires, until the app\n * calls enableAttribution().\n */\n attribution?: boolean;\n /**\n * `last` (default): a visit carrying `rid`/`utm_*` replaces the stored\n * record. `first`: the first stored record is kept for good — a marketing\n * site attributing acquisition to the campaign that first brought a visitor.\n */\n attributionTouch?: AttributionTouch;\n /**\n * Decides which errors are benign browser noise: kept out of the error\n * pipeline and counted as `forge.errors_filtered` actions instead\n * (benign-errors.ts). Default classifyBenignError: an AbortError, and the\n * browser's generic \"Failed to fetch\" TypeError; never a ConnectError. It\n * applies to what the SDK records from unhandled rejections, uncaught\n * errors, console.error and reportException; the app's own handlers see\n * every event unchanged. For an unhandled rejection or uncaught error it is\n * handed `{ name, message }` as the SDK recorded them, not the original\n * value. Pass `() => null` to record everything.\n */\n classifyBenignError?: BenignErrorClassifier;\n}\n\n/** The slice of the SDK this module calls. Typed here, not imported, so the module loads without it. */\ninterface HyperDXClient {\n init(config: Record<string, unknown>): void;\n recordException(error: unknown, attributes?: Record<string, unknown>): void;\n addAction?(name: string, attributes?: Record<string, TrackValue>): void;\n setGlobalAttributes?(attributes: Record<string, string>): void;\n stopSessionRecorder?(): void;\n getSessionId?(): string | undefined;\n}\n\nlet started: Promise<boolean> | null = null;\n\n// Attribution state shared by start() and enableAttribution(): whichever runs\n// second does the stamping, so the call order does not matter.\nlet attributionWanted = false;\nlet attributionOptions: { search?: string } = {};\nlet runningConfig: BrowserTelemetryConfig | null = null;\nlet runningClient: HyperDXClient | null = null;\n\nfunction captureVisitor(config: BrowserTelemetryConfig): string {\n return captureAttribution({\n search: attributionOptions.search,\n visitorIdStorageKey: config.visitorIdStorageKey,\n touch: config.attributionTouch,\n });\n}\n\n/**\n * Turn on visitor attribution for a page that started telemetry with\n * `attribution: false`, once the consent it needs is granted: from here on\n * every event carries `visitor.id`, withAttribution stamps links and the first\n * sign-in emits `user_identified`. Pass `search` (the landing URL's query\n * string, kept from page load) when a client-side navigation may have dropped\n * it since. Safe to call before init resolves, more than once, and on the\n * server; a no-op after disableTelemetry().\n */\nexport function enableAttribution(options?: { search?: string }): void {\n if (typeof window === \"undefined\" || isTelemetryDisabled()) {\n return;\n }\n if (options?.search !== undefined) {\n attributionOptions = { search: options.search };\n }\n if (attributionWanted) {\n return;\n }\n attributionWanted = true;\n if (runningClient && runningConfig) {\n try {\n runningClient.setGlobalAttributes?.({\n \"visitor.id\": captureVisitor(runningConfig),\n });\n } catch {\n // Telemetry must never break the app.\n }\n }\n}\n\n/**\n * initBrowserTelemetry starts the HyperDX browser SDK once per page load and\n * resolves to whether it is running. See the module header for the contract.\n */\nexport function initBrowserTelemetry(\n config: BrowserTelemetryConfig,\n): Promise<boolean> {\n if (typeof window === \"undefined\") {\n return Promise.resolve(false);\n }\n if (started) {\n return started;\n }\n if (isTelemetryDisabled()) {\n return Promise.resolve(false);\n }\n const ingest = resolveIngestUrl(config.endpoint, window.location.origin);\n if (!ingest) {\n // Nothing will ever drain track() calls held for the SDK; let them go.\n setTelemetrySink(null);\n return Promise.resolve(false);\n }\n started = start(config, ingest);\n registerTelemetryStartup(started);\n return started;\n}\n\nasync function start(\n config: BrowserTelemetryConfig,\n ingest: string,\n): Promise<boolean> {\n try {\n await firstVisible();\n const hdx = resolveClient(await import(\"@hyperdx/browser\"));\n if (!hdx || isTelemetryDisabled()) {\n setTelemetrySink(null);\n return false;\n }\n const replay = decideReplay(config, sessionStorageOrNull(), Math.random);\n // Before init: the SDK reads its session cookie as it starts.\n keepSessionWithoutCookies();\n hdx.init(\n buildSdkOptions(\n { ...config, replay },\n ingest,\n window.location.origin,\n pageClientResourceAttributes(),\n ),\n );\n // After init: both hook what the SDK RECORDS, never what the app sees.\n const benign = benignFilter(config, hdx);\n filterSdkErrorSpans(benign);\n tapSdkInputs(benign);\n // Every span carries where it came from and which visitor made it; the\n // product-event view reads these as app.client and visitor.id.\n // With attribution deferred (attribution: false), visitor.id joins them\n // when enableAttribution() runs.\n if (config.attribution !== false) {\n attributionWanted = true;\n }\n const globals: Record<string, string> = {\n \"app.client\": detectAppClient(config.appClient),\n };\n if (attributionWanted) {\n globals[\"visitor.id\"] = captureVisitor(config);\n }\n hdx.setGlobalAttributes?.(globals);\n // The viewport and screen ride on every span, refreshed on resize\n // (client-context.ts): the SDK's global attributes are a span processor\n // that stamps the current set on each span as it starts, so a span carries\n // the size of the moment it began (proved against the real SDK in\n // scripts/browser-telemetry-smoke.mjs). Device, OS and browser are\n // derived at ingest.\n const stopViewport = watchViewport((attrs) =>\n hdx.setGlobalAttributes?.(attrs),\n );\n runningClient = hdx;\n runningConfig = config;\n // The session id rides on every Connect call as baggage (trace.ts) and on\n // every fetch/XHR span (sessionAttribute), joining backend traces to the\n // session that caused them.\n registerRumSession(() => hdx.getSessionId?.());\n setExceptionReporter((error, attributes) => {\n if (alreadyRecorded(error) || benign.filtered(error, \"reportException\")) {\n return;\n }\n hdx.recordException(error, attributes);\n });\n setTelemetrySink({\n track: (name, attributes) => hdx.addAction?.(name, attributes),\n setUser: (id) => {\n hdx.setGlobalAttributes?.({ userId: id });\n // The first sign-in of a user in this browser links the visitor to\n // them: one event, never repeated for the same user.\n const identify = takeIdentifyProps(id);\n if (identify) {\n hdx.addAction?.(\"user_identified\", identify);\n }\n },\n disable: () => {\n // Back to \"no SDK\": reportException returns false, so a caller falls\n // back to console.error and the error does not vanish.\n setExceptionReporter(null);\n registerRumSession(null);\n stopViewport();\n hdx.stopSessionRecorder?.();\n },\n });\n return true;\n } catch (err) {\n // Blocked chunk, ad-blocker, SDK throw: telemetry must never break the app.\n // A startup that failed after the hooks went in takes them out again.\n removeBenignFilter();\n console.debug(\"[telemetry] disabled:\", err);\n setTelemetrySink(null);\n return false;\n }\n}\n\n/**\n * Resolves once the document is visible: at once for a visible page or one\n * with no Page Visibility API, otherwise at its first visibilitychange to\n * visible. See \"No session until the page has been seen\" in the header.\n */\nfunction firstVisible(): Promise<void> {\n if (\n typeof document === \"undefined\" ||\n document.visibilityState !== \"hidden\" ||\n typeof document.addEventListener !== \"function\"\n ) {\n return Promise.resolve();\n }\n return new Promise((resolve) => {\n const onChange = () => {\n if (document.visibilityState !== \"hidden\") {\n document.removeEventListener(\"visibilitychange\", onChange);\n resolve();\n }\n };\n document.addEventListener(\"visibilitychange\", onChange);\n });\n}\n\n// ── One failure, one record ──────────────────────────────────────────────\n//\n// The SDK records an Error that reaches window \"error\", window\n// \"unhandledrejection\", or console.error. React (18 and 19) console.errors an\n// error a boundary catches BEFORE it calls componentDidCatch, and Next\n// dispatches an uncaught render error to window \"error\" — so by the time\n// reportException runs, the SDK has usually recorded that very error already.\n// Recording it again would count one failure twice, and the issue layer\n// (which groups by fingerprint) would report two.\n//\n// So the taps below remember which Error OBJECTS the SDK was shown, and the\n// installed recorder skips those. Whatever the SDK did not see — a custom\n// onCaughtError that silences React's logging, an error rethrown as a new\n// object — is still recorded. The console tap is installed after the SDK's own\n// wrapper, so it sits outermost and only observes; every call is forwarded\n// untouched.\n//\n// The cost is the React component stack: the SDK's record of a boundary-caught\n// error comes from console.error(error), which carries the error and its\n// stack but not React's componentStack, and attributes passed to a skipped\n// reportException are dropped with it.\nconst seenBySdk = new WeakSet<object>();\nlet tapped = false;\n\nfunction noteSeen(value: unknown): void {\n if (typeof value === \"object\" && value !== null) {\n seenBySdk.add(value);\n }\n}\n\nfunction tapSdkInputs(benign: BenignFilter): void {\n if (tapped) {\n return;\n }\n tapped = true;\n const wrapped = console.error;\n const tap = function (this: unknown, ...args: unknown[]) {\n for (const arg of args) {\n try {\n if (arg instanceof Error) {\n noteSeen(arg);\n }\n } catch {\n // A revoked Proxy: not ours to inspect; forward it untouched.\n }\n }\n // The call always goes on to the SDK and the console, exactly as without\n // this tap. Only the verdict on the SDK's RECORD of it is decided here,\n // where the real arguments are: the SDK opens its console.error span\n // synchronously inside wrapped(), and filterSdkErrorSpans reads it.\n const previous = consoleVerdict;\n consoleVerdict = benignKindsOf(benign, args);\n try {\n return wrapped.apply(this, args);\n } finally {\n consoleVerdict = previous;\n }\n };\n console.error = tap;\n const onError = (e: ErrorEvent) => noteSeen(e.error);\n const onRejection = (e: PromiseRejectionEvent) => noteSeen(e.reason);\n window.addEventListener(\"error\", onError, true);\n window.addEventListener(\"unhandledrejection\", onRejection, true);\n benignTeardown.push(() => {\n if (console.error === tap) {\n console.error = wrapped;\n }\n window.removeEventListener?.(\"error\", onError, true);\n window.removeEventListener?.(\"unhandledrejection\", onRejection, true);\n tapped = false;\n });\n}\n\n/**\n * The kind of every exception in a console.error call when ALL of them are\n * benign, or null to record the call: no exception, one real one, or an\n * argument that cannot even be inspected (a throwing Symbol.toStringTag\n * getter, a revoked Proxy).\n */\nfunction benignKindsOf(benign: BenignFilter, args: unknown[]): string[] | null {\n const kinds: string[] = [];\n for (const arg of args) {\n let exception: boolean;\n try {\n exception = isExceptionLike(arg);\n } catch {\n return null;\n }\n if (!exception) {\n continue;\n }\n const kind = benign.classify(arg);\n if (kind === null) {\n return null;\n }\n kinds.push(kind);\n }\n return kinds.length > 0 ? kinds : null;\n}\n\n// ── Benign browser errors (benign-errors.ts) ────────────────────────────\n//\n// Filtered at the SDK's RECORDING boundary, never at the app's: every window\n// \"error\" / \"unhandledrejection\" event and every console.error call reaches\n// every app handler (window.onerror, onunhandledrejection, listeners of any\n// phase, registered before telemetry started or after) and the console\n// exactly as it would with no telemetry at all.\n//\n// The SDK's error capture opens one span per failure on its `errors` tracer —\n// named onerror, unhandledrejection or console.error — and ends it once the\n// exception is attached; only an ENDED span is ever exported. The SDK has no\n// drop hook (its exporter options are not reachable through @hyperdx/browser,\n// and an OTel 2.x provider takes no span processor after construction), so the\n// runtime wraps that tracer's startSpan: a benign failure's span is counted\n// and simply never ended, so it is never exported. Everything else ends as\n// the SDK meant.\n//\n// - window events: the span describes one value, so it is classified from\n// what the SDK recorded on it (error.object = the error's name,\n// error.message). A String (a non-Error throw) is never benign.\n// - console.error: one call can carry several values, and the span names\n// only the first exception, so the verdict comes from the console tap,\n// which classifies every argument (consoleVerdict).\ninterface BenignFilter {\n /** The kind of a benign error, or null. Counts nothing. */\n classify(error: unknown): string | null;\n /** Count one filtered error of `kind`. */\n note(kind: string, source: BenignErrorSource): void;\n /** Count and report true when `error` is benign; false to record it. */\n filtered(error: unknown, source: BenignErrorSource): boolean;\n}\n\nfunction benignFilter(\n config: BrowserTelemetryConfig,\n hdx: HyperDXClient,\n): BenignFilter {\n const classify = config.classifyBenignError ?? classifyBenignError;\n const counter = new FilteredErrorCounter((name, attributes) => {\n if (!isTelemetryDisabled()) {\n hdx.addAction?.(name, attributes);\n }\n });\n const onPageHide = () => counter.flush();\n const onVisibility = () => {\n if (document.visibilityState === \"hidden\") {\n counter.flush();\n }\n };\n if (typeof window.addEventListener === \"function\") {\n window.addEventListener(\"pagehide\", onPageHide);\n }\n if (typeof document !== \"undefined\") {\n document.addEventListener(\"visibilitychange\", onVisibility);\n }\n benignTeardown.push(() => {\n window.removeEventListener?.(\"pagehide\", onPageHide);\n if (typeof document !== \"undefined\") {\n document.removeEventListener(\"visibilitychange\", onVisibility);\n }\n });\n const kindOf = (error: unknown): string | null => {\n try {\n return classify(error) || null;\n } catch {\n // A classifier that throws keeps the error.\n return null;\n }\n };\n return {\n classify: kindOf,\n note: (kind, source) => counter.note(kind, source),\n filtered(error, source) {\n const kind = kindOf(error);\n if (!kind) {\n return false;\n }\n counter.note(kind, source);\n return true;\n },\n };\n}\n\n/** The scope (name, version) the SDK's error capture records under. */\nconst SDK_ERRORS_SCOPE = { name: \"errors\", version: \"1\" } as const;\n\n/** The spans that scope opens, one per captured failure, and their source. */\nconst SDK_ERROR_SPANS: Record<string, BenignErrorSource> = {\n onerror: \"error\",\n unhandledrejection: \"unhandledrejection\",\n \"console.error\": \"console.error\",\n};\n\n// The console tap's verdict on the call now inside the SDK's wrapper: the\n// benign kinds, null to record it, undefined when no tapped call is running.\nlet consoleVerdict: string[] | null | undefined;\n\ninterface RecordingSpan {\n end(...args: unknown[]): unknown;\n attributes?: Record<string, unknown>;\n}\n\ninterface StartSpanTracer {\n startSpan(name: string, ...rest: unknown[]): unknown;\n}\n\nfunction filterSdkErrorSpans(benign: BenignFilter): void {\n const proxy = trace.getTracerProvider() as { getDelegate?: () => unknown };\n const provider = (proxy.getDelegate?.() ?? proxy) as {\n getTracer?: (name: string, version?: string) => unknown;\n };\n const tracer = provider.getTracer?.(\n SDK_ERRORS_SCOPE.name,\n SDK_ERRORS_SCOPE.version,\n ) as StartSpanTracer | undefined;\n if (!tracer || typeof tracer.startSpan !== \"function\") {\n // No seam: record everything, as without the filter.\n return;\n }\n const original = tracer.startSpan;\n const startSpan = function (\n this: unknown,\n name: string,\n ...rest: unknown[]\n ): unknown {\n const span = original.call(this, name, ...rest) as RecordingSpan;\n const source = SDK_ERROR_SPANS[name];\n if (!source || typeof span?.end !== \"function\") {\n return span;\n }\n const verdict = name === \"console.error\" ? consoleVerdict : undefined;\n const end = span.end;\n span.end = function (this: unknown, ...args: unknown[]) {\n const kinds =\n name === \"console.error\"\n ? (verdict ?? null)\n : recordedKind(benign, span);\n if (kinds) {\n for (const kind of kinds) {\n benign.note(kind, source);\n }\n // Never ended, so never exported.\n return undefined;\n }\n return end.apply(this, args);\n };\n return span;\n };\n tracer.startSpan = startSpan;\n benignTeardown.push(() => {\n if (tracer.startSpan === startSpan) {\n tracer.startSpan = original;\n }\n });\n}\n\n/** The benign kind of the one failure a window-event span recorded, or null. */\nfunction recordedKind(\n benign: BenignFilter,\n span: RecordingSpan,\n): string[] | null {\n try {\n const name = span.attributes?.[\"error.object\"];\n const message = span.attributes?.[\"error.message\"];\n if (typeof name !== \"string\" || name === \"String\") {\n return null;\n }\n const kind = benign.classify({\n name,\n message: typeof message === \"string\" ? message : \"\",\n });\n return kind ? [kind] : null;\n } catch {\n return null;\n }\n}\n\n// What undoes the benign filter's hooks (the tracer wrap, the console tap, the\n// flush listeners), run when startup fails at any point after they went in.\nlet benignTeardown: Array<() => void> = [];\n\nfunction removeBenignFilter(): void {\n const undo = benignTeardown;\n benignTeardown = [];\n for (const fn of undo.reverse()) {\n try {\n fn();\n } catch {\n // Telemetry must never break the app.\n }\n }\n}\n\n// An exception value as console.error receives it: an Error, a DOMException\n// (not an Error in every browser), or either from another realm (an iframe),\n// which fails instanceof but keeps its [object Error] / [object DOMException]\n// tag.\nfunction isExceptionLike(value: unknown): boolean {\n if (typeof value !== \"object\" || value === null) {\n return false;\n }\n if (value instanceof Error) {\n return true;\n }\n if (typeof DOMException !== \"undefined\" && value instanceof DOMException) {\n return true;\n }\n const tag = Object.prototype.toString.call(value);\n return tag === \"[object Error]\" || tag === \"[object DOMException]\";\n}\n\nfunction alreadyRecorded(error: unknown): boolean {\n return typeof error === \"object\" && error !== null && seenBySdk.has(error);\n}\n\n/**\n * The options passed to HyperDX.init. Exported for tests and for apps that\n * want to see exactly what is configured — it is pure. `clientAttributes`\n * are the page's own client resource attributes (client-context.ts:\n * browser.* client hints, app.desktop.*); the config's keys win over them.\n */\nexport function buildSdkOptions(\n config: BrowserTelemetryConfig,\n ingestUrl: string,\n pageOrigin: string,\n clientAttributes: Record<string, string> = {},\n): Record<string, unknown> {\n // `config.replay` is the FINAL decision here. initBrowserTelemetry resolves\n // replaySampleRate into it (decideReplay) before calling this.\n const replay = config.replay === true;\n const resourceAttributes: Record<string, string> = { ...clientAttributes };\n if (config.serviceVersion) {\n resourceAttributes[\"service.version\"] = config.serviceVersion;\n }\n if (config.serviceNamespace) {\n resourceAttributes[\"service.namespace\"] = config.serviceNamespace;\n }\n if (config.frontend) {\n resourceAttributes[\"forge.frontend\"] = config.frontend;\n }\n if (config.environment) {\n resourceAttributes[\"deployment.environment.name\"] = config.environment;\n resourceAttributes[\"deployment.environment\"] = config.environment;\n }\n\n const targets = propagationTargets(pageOrigin, config.apiOrigins);\n const advancedNetworkCapture = config.advancedNetworkCapture ?? false;\n const options: Record<string, unknown> = {\n apiKey: PLACEHOLDER_API_KEY,\n service: config.serviceName,\n url: ingestUrl,\n tracePropagationTargets: targets,\n // The SDK would otherwise trace its own exports, and it must never\n // observe the route it ships through.\n ignoreUrls: [new RegExp(`^${escapeRegExp(ingestUrl)}`)],\n consoleCapture: config.consoleCapture ?? true,\n advancedNetworkCapture,\n // The SDK spreads this over ITS fetch/xhr config as whole keys, so\n // everything it would have set (propagation targets, the capture switch)\n // must be restated here or it is lost.\n instrumentations: {\n // Raw DOM events belong to replay, not distributed traces. HyperDX's\n // default traces every mousedown/up listener (including replay's own),\n // creating empty roots. Meaningful actions can still use manual spans;\n // fetch/xhr and document-load instrumentation keep their real parents.\n interactions: false,\n fetch: {\n propagateTraceHeaderCorsUrls: targets,\n advancedNetworkCapture: () => advancedNetworkCapture,\n applyCustomAttributesOnSpan: finishNetworkSpan,\n },\n xhr: {\n propagateTraceHeaderCorsUrls: targets,\n advancedNetworkCapture: () => advancedNetworkCapture,\n applyCustomAttributesOnSpan: finishNetworkSpan,\n },\n },\n // Polls for window.Intercom on a timer; nothing here uses Intercom.\n disableIntercom: true,\n disableReplay: !replay,\n otelResourceAttributes: resourceAttributes,\n debug: config.debug ?? false,\n // Privacy is forced and unconditional: no path through this function\n // yields an unmasked or media-recording replay. The SDK's own default\n // masks inputs but NOT text, and text is where chat content and records\n // live.\n maskAllInputs: true,\n maskAllText: true,\n recordCanvas: false,\n blockSelector: REPLAY_BLOCK_SELECTOR,\n replay: { inlineImages: false, collectFonts: false },\n };\n return options;\n}\n\n/** Elements a replay never records: their pixels stay in the browser. */\nexport const REPLAY_BLOCK_SELECTOR =\n \"img, picture, video, audio, iframe, object, embed\";\n\n/** Where a replay sampling decision is held for the tab's session. */\nexport const REPLAY_SAMPLE_KEY = \"forge.replay.sampled\";\n\n/** The slice of Storage the sampling decision needs. */\ninterface DecisionStore {\n getItem(key: string): string | null;\n setItem(key: string, value: string): void;\n}\n\n/**\n * Whether this session records a replay: config.replay, then the sample rate,\n * drawn once and remembered in `store` so a reload (or a route change that\n * re-runs init) never re-rolls into a session that only half-recorded. With no\n * usable store the draw is made each load. Pure given its inputs; exported for\n * tests.\n */\nexport function decideReplay(\n config: Pick<BrowserTelemetryConfig, \"replay\" | \"replaySampleRate\">,\n store: DecisionStore | null,\n random: () => number,\n): boolean {\n if (config.replay !== true) {\n return false;\n }\n const rate = clampRate(config.replaySampleRate);\n if (rate >= 1) {\n return true;\n }\n if (rate <= 0) {\n return false;\n }\n try {\n const held = store?.getItem(REPLAY_SAMPLE_KEY);\n if (held === \"1\" || held === \"0\") {\n return held === \"1\";\n }\n } catch {\n // Storage blocked: fall through to a fresh draw.\n }\n const sampled = random() < rate;\n try {\n store?.setItem(REPLAY_SAMPLE_KEY, sampled ? \"1\" : \"0\");\n } catch {\n // Not persisted: the next load draws again.\n }\n return sampled;\n}\n\n// Unset is \"every session\"; anything that is not a number is a bug, and a bug\n// must not start recording people.\nfunction clampRate(rate: number | undefined): number {\n if (rate === undefined) {\n return 1;\n }\n if (typeof rate !== \"number\" || Number.isNaN(rate)) {\n return 0;\n }\n return Math.min(1, Math.max(0, rate));\n}\n\n/** See \"One session per visit\" in the header. Never throws. */\nfunction keepSessionWithoutCookies(): void {\n try {\n if (typeof document === \"undefined\") {\n return;\n }\n installSessionCookieFallback(document, window.localStorage ?? null);\n } catch {\n // localStorage access can throw (blocked storage): keep the SDK default.\n }\n}\n\nfunction sessionStorageOrNull(): DecisionStore | null {\n try {\n return window.sessionStorage;\n } catch {\n return null;\n }\n}\n\n/** The span attributes that hold a request URL. */\nconst URL_ATTRIBUTES = [\"http.url\", \"url.full\"] as const;\n\n/** `url` without its query string and fragment. */\nexport function stripUrlQuery(url: string): string {\n const cut = url.search(/[?#]/);\n return cut === -1 ? url : url.slice(0, cut);\n}\n\ninterface UrlSpan {\n attributes?: Record<string, unknown>;\n setAttribute(key: string, value: string): unknown;\n updateName?(name: string): unknown;\n}\n\n// applyCustomAttributesOnSpan for both instrumentations: it runs before the\n// span ends, and after HyperDX's own `HTTP <METHOD>` rename, so the values\n// set here are the ones exported. The span carries the RUM session as\n// `session.id` (the resource's rum.sessionId says the same for the browser;\n// the attribute is what the backend's own spans carry too, so a trace is found\n// by session from either side).\nfunction finishNetworkSpan(span: UrlSpan): void {\n stripNetworkQuery(span);\n const url = span.attributes?.[\"url.full\"] ?? span.attributes?.[\"http.url\"];\n const method =\n span.attributes?.[\"http.request.method\"] ??\n span.attributes?.[\"http.method\"];\n if (typeof url === \"string\" && typeof span.updateName === \"function\") {\n const name = spanRouteName(typeof method === \"string\" ? method : \"\", url);\n if (name) {\n span.updateName(name);\n }\n }\n const session = rumSessionId();\n if (session) {\n span.setAttribute(\"session.id\", session);\n }\n}\n\nfunction stripNetworkQuery(span: UrlSpan): void {\n for (const key of URL_ATTRIBUTES) {\n const value = span.attributes?.[key];\n if (typeof value === \"string\") {\n const stripped = stripUrlQuery(value);\n if (stripped !== value) {\n span.setAttribute(key, stripped);\n }\n }\n }\n}\n\n// A Connect/gRPC procedure: `/<package>.<Service>/<Method>`, the service and\n// method PascalCase as protobuf declares them. The whole path is the route,\n// fixed by the proto, so it carries no request values.\nconst RPC_PATH = /^\\/[A-Za-z_]\\w*(?:\\.[A-Za-z_]\\w*)*\\.[A-Z]\\w*\\/[A-Z]\\w*$/;\n\n/**\n * The name a fetch/XHR span gets: `<METHOD> /<package>.<Service>/<Method>`,\n * the server span's name with the method in front, when the URL is a\n * Connect/gRPC procedure. Empty for any other URL, which keeps the SDK's\n * `HTTP <METHOD>`: an arbitrary path can hold values (ids, tokens, emails) no\n * pattern recognises reliably, and a span name must be neither sensitive nor\n * unbounded. Empty too when `url` cannot be parsed. Exported for tests.\n */\nexport function spanRouteName(method: string, url: string): string {\n let path: string;\n try {\n path = new URL(url, \"http://base.invalid\").pathname;\n } catch {\n return \"\";\n }\n if (!RPC_PATH.test(path)) {\n return \"\";\n }\n return `${method.trim().toUpperCase() || \"POST\"} ${path}`;\n}\n\n/**\n * resolveIngestUrl turns the configured endpoint into the absolute URL the SDK\n * is given, or null when telemetry is off. A path resolves against the page\n * origin, so the default is same-origin by construction.\n */\nexport function resolveIngestUrl(\n endpoint: string | undefined,\n pageOrigin: string,\n): string | null {\n const value = (endpoint ?? \"\").trim();\n if (value === \"\" || value.toLowerCase() === \"off\") {\n return null;\n }\n try {\n return new URL(value, pageOrigin).toString().replace(/\\/+$/, \"\");\n } catch {\n return null;\n }\n}\n\nfunction propagationTargets(\n pageOrigin: string,\n apiOrigins: Array<string | undefined> = [],\n): RegExp[] {\n const origins = new Set<string>([pageOrigin]);\n for (const raw of apiOrigins) {\n if (!raw) {\n continue;\n }\n try {\n origins.add(new URL(raw, pageOrigin).origin);\n } catch {\n // An unparsable origin is not a target.\n }\n }\n return [...origins].map((o) => new RegExp(`^${escapeRegExp(o)}(?:[/?#]|$)`));\n}\n\nfunction escapeRegExp(s: string): string {\n return s.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n\n// @hyperdx/browser is a UMD/CJS bundle whose module.exports IS the client, and\n// its methods use `this`. A bundler hands back a module NAMESPACE that exposes\n// both the client's members at the top level (as read-only getters) and the\n// client itself as `default`. Calling init on the namespace binds `this` to that\n// frozen object and the SDK throws on its first property write, which disabled\n// telemetry silently. So descend to the deepest `default` that is still a\n// client, the real instance, and never settle for the namespace in front of it.\nfunction resolveClient(mod: unknown): HyperDXClient | null {\n let cur: unknown = mod;\n for (let depth = 0; depth < 4; depth++) {\n const next = peek(cur, \"default\");\n if (!isClient(next)) {\n break;\n }\n cur = next;\n }\n return isClient(cur) ? cur : null;\n}\n\nfunction isClient(v: unknown): v is HyperDXClient {\n return (\n typeof peek(v, \"init\") === \"function\" &&\n typeof peek(v, \"recordException\") === \"function\"\n );\n}\n\n// A module namespace object may throw on an absent key (strict ESM\n// interop shims and test doubles do), and \"absent\" is an answer here.\nfunction peek(obj: unknown, key: string): unknown {\n try {\n return (obj as Record<string, unknown>)[key];\n } catch {\n return undefined;\n }\n}\n\n/** The tracer to open manual spans on. Resolves HyperDX's provider once it is running. */\nexport function getTracer(name = \"default\") {\n return trace.getTracer(name);\n}\n\nexport { context, propagation, trace } from \"@opentelemetry/api\";\n"]}
|
|
1
|
+
{"version":3,"file":"telemetry.js","sourceRoot":"","sources":["../src/telemetry.ts"],"names":[],"mappings":"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","sourcesContent":["// Part of @reliantlabs/forge-web-runtime — the web twin of forge/pkg.\n//\n// Browser telemetry: the HyperDX browser SDK, initialised the forge way.\n//\n// Captures errors (uncaught, unhandled rejections, boundary-caught), console\n// output, fetch/XHR spans, document load, long tasks and web vitals, and\n// ships them to ClickStack through a SAME-ORIGIN `/_otel` route.\n//\n// ── Why HyperDX REPLACES the old OTel web wiring, not joins it ───────────\n//\n// @hyperdx/browser wraps @hyperdx/otel-web, which builds its own\n// WebTracerProvider and calls provider.register() — the global tracer\n// provider, context manager and propagator. A second registration (the old\n// `./otel` subpath did exactly that) is rejected by @opentelemetry/api with a\n// \"duplicate registration\" diagnostic and silently loses: whichever ran\n// second would simply never see a span. Two tracer providers cannot coexist\n// in one page, so there is one, and it is HyperDX's. `./otel` and its eight\n// @opentelemetry/* SDK peer dependencies are gone.\n//\n// traceparent on RPCs is unaffected. traceInterceptor (trace.ts) injects the\n// active span's context into every Connect call, or synthesises a valid\n// traceparent when none is active — with no SDK at all. With the SDK running,\n// the fetch span HyperDX opens for the call carries the same trace id, and\n// `apiOrigins` below makes that hold for a cross-origin API too (which is\n// every dev loop: the API binds its own port).\n//\n// ── The browser holds no secret ──────────────────────────────────────────\n//\n// `url` is `${location.origin}/_otel`. The browser talks only to its own\n// origin; a dev-server proxy (next.config.ts rewrites / Vite server.proxy) or\n// the deployment's ingress forwards `/_otel/v1/{traces,logs}` to the OTLP/HTTP\n// port of a collector, and that hop — never the bundle — owns credentials.\n//\n// The SDK nevertheless wants an `apiKey` and sends it as an `authorization`\n// header. We pass PLACEHOLDER_API_KEY, a constant that grants nothing and is\n// public by construction. A collector that enforces ingestion auth (ClickStack\n// `collectorAuthenticationEnforced`) rejects it with 401, so the proxy in\n// front of such a collector must strip the header or replace it with the real\n// key. The local ClickStack collector does not enforce, and ignores it.\n//\n// ── Replay: shipped, off, masked, media blocked ─────────────────────────\n//\n// The SDK bundles an rrweb recorder. It is DISABLED unless `replay: true`.\n// Privacy is forced, not offered: every input and all text is masked, canvas is\n// never recorded, and images, video, audio, iframes and embeds are BLOCKED\n// (replaced by a same-size placeholder; their pixels never leave the browser).\n// Images are not inlined and web fonts are not collected. There is deliberately\n// no option to turn any of that off while replay is on; an app that needs\n// unmasked replay passes its own SDK options.\n//\n// `replaySampleRate` (0..1, default 1) records only that share of SESSIONS. The\n// SDK has no session sampler, so the decision is made here, once, and held in\n// sessionStorage for the tab's session.\n//\n// ── One session per visit, even where cookies are dropped ────────────────\n//\n// The SDK keeps its session id only in the `__rum_sid` cookie and mints a new\n// one whenever it cannot read that cookie back, which it checks every minute.\n// An origin that drops cookies (an Electron renderer on a custom scheme such\n// as `app://`) therefore got a new session every minute. Before init, the\n// runtime probes whether cookies persist and, when they do not, keeps that one\n// cookie in localStorage with the same 15-minute inactivity and 4-hour limits\n// (session-cookie-fallback.ts). Origins whose cookies work are untouched.\n//\n// ── No session until the page has been seen ──────────────────────────────\n//\n// A page loaded in the background (a desktop window opened hidden, a tab\n// restored behind another) starts no session at all: the SDK is not loaded\n// until the document is first visible. Started hidden, it would mint a session\n// made only of background fetch spans, with nothing on screen to record, and\n// the recorder would hold no replay for it. Until then reportException returns\n// false (the caller logs to the console) and track() calls are held, bounded,\n// as they are while the SDK loads. A page that never becomes visible sends\n// nothing.\n//\n// ── Paint vitals are dropped for a page first shown late ─────────────────\n//\n// web-vitals reports no FCP or LCP painted after the page was first hidden,\n// but it learns of hiding only from the moment it registers, and it registers\n// inside the SDK, which starts only once the page is visible. So a page loaded\n// in the background would report, as its FCP and LCP, the time from navigation\n// until it was first SHOWN: a tab opened behind another for a minute reported\n// a 60 s LCP. The runtime records when the page was first hidden (the browser's\n// `visibility-state` entries where it has them, else from startup on) and\n// drops an FCP or LCP painted at or after that moment. The paint time is the\n// metric's value (web-vitals times it from navigation, less a prerendered\n// page's activationStart); a back/forward-cache restore, timed from the\n// restore, is kept. TTFB, CLS and INP are kept: being hidden does not change\n// them.\n//\n// ── Network URLs carry no query string ───────────────────────────────────\n//\n// fetch/XHR spans record the request URL, and a query string is where tokens,\n// OAuth codes and search terms live. The runtime rewrites `http.url` and\n// `url.full` on every fetch/XHR span to the URL without query or fragment.\n// The SDK's own `location.href` attribute (the page URL, stamped on every span)\n// has no client-side hook; the ingest side scrubs it.\n//\n// ── Network spans are named by what they called ──────────────────────────\n//\n// HyperDX names every fetch/XHR span `HTTP <METHOD>`, so a trace a browser\n// starts is titled \"HTTP POST\" whatever it did. The same hook renames it to\n// the procedure when it is a Connect/gRPC call (`POST /pkg.v1.Service/Method`,\n// the server span's name with the method in front; spanRouteName). Any other\n// URL keeps `HTTP <METHOD>`: a free-form path can carry ids and tokens, and\n// the span name is exported unscrubbed.\n//\n// ── Client context ───────────────────────────────────────────────────────\n//\n// The page reports what only it can know about its client — client hints\n// (browser.brands/platform/mobile), its viewport and screen (app.viewport.*,\n// app.screen.*) and, inside a desktop app, the app's versions from the\n// `window.forgeDesktop` preload bridge (app.desktop.*) — sanitized\n// (client-context.ts). Browser, OS and device type are NOT page claims: the\n// ingest side derives them from the request's User-Agent and Sec-CH-UA\n// headers and overwrites any the page sent.\n//\n// ── Loading ──────────────────────────────────────────────────────────────\n//\n// The SDK is ~600 KB minified (rrweb and the OTel web stack are bundled in\n// it), so it is imported lazily: bundlers split it into its own chunk that\n// loads after the app is interactive and costs the first paint nothing.\n// initBrowserTelemetry is therefore async and idempotent — every caller gets\n// the same promise, which is what survives React StrictMode's double mount and\n// Fast Refresh. It is a no-op without a DOM (SSR, prerender) and without an\n// endpoint, and it never throws.\nimport { trace } from \"@opentelemetry/api\";\n\nimport {\n captureAttribution,\n type AttributionTouch,\n detectAppClient,\n takeIdentifyProps,\n} from \"./attribution.js\";\nimport {\n type BenignErrorClassifier,\n type BenignErrorSource,\n classifyBenignError,\n FilteredErrorCounter,\n} from \"./benign-errors.js\";\nimport {\n pageClientResourceAttributes,\n watchViewport,\n} from \"./client-context.js\";\nimport { setExceptionReporter } from \"./error-reporter.js\";\nimport { installSessionCookieFallback } from \"./session-cookie-fallback.js\";\nimport {\n registerRumSession,\n registerTelemetryStartup,\n rumSessionId,\n} from \"./telemetry-gate.js\";\nimport {\n isTelemetryDisabled,\n setTelemetrySink,\n type TrackValue,\n} from \"./track.js\";\n\nexport {\n clientResourceAttributes,\n type ForgeDesktopInfo,\n viewportAttributes,\n} from \"./client-context.js\";\n\nexport {\n cookiesPersist,\n installSessionCookieFallback,\n RUM_SESSION_COOKIE,\n RUM_SESSION_STORAGE_KEY,\n} from \"./session-cookie-fallback.js\";\n\nexport {\n type BenignErrorClassifier,\n type BenignErrorKind,\n classifyBenignError,\n FILTERED_ERRORS_ACTION,\n} from \"./benign-errors.js\";\n\n/** Where the browser ships telemetry: this origin's `/_otel`. */\nexport const DEFAULT_INGEST_PATH = \"/_otel\";\n\n/**\n * The apiKey handed to the SDK. Public by construction: it identifies\n * nothing and authorises nothing. See the header — the proxy or collector\n * owns the real credential.\n */\nexport const PLACEHOLDER_API_KEY = \"forge-browser-public\";\n\nexport interface BrowserTelemetryConfig {\n /** `service.name` on everything this page emits. */\n serviceName: string;\n /** `service.version`. Omit for none. */\n serviceVersion?: string;\n /**\n * The forge environment name. Emitted as BOTH `deployment.environment.name`\n * (current semconv) and `deployment.environment` (the legacy key HyperDX's\n * default sources still key on).\n */\n environment?: string;\n /** `service.namespace`, conventionally the project name. */\n serviceNamespace?: string;\n /**\n * The forge frontend's name, emitted as the `forge.frontend` resource\n * attribute. Unlike `serviceName` (which an app may override to anything) it\n * is the stable key that joins this page's telemetry to the frontend and its\n * source maps. Omit for none.\n */\n frontend?: string;\n /**\n * Ingest base: a path on this origin (`/_otel`) or, as an escape hatch, an\n * absolute URL. Unset, empty, or `off` disables telemetry — the app runs\n * untraced rather than throwing, which is what makes it safe to call\n * unconditionally from the app shell.\n */\n endpoint?: string;\n /**\n * Origins (or URLs — only the origin is used) of the app's own backend.\n * Requests to them always get a `traceparent` from the SDK's fetch/XHR\n * spans. This page's own origin is always included.\n */\n apiOrigins?: Array<string | undefined>;\n /**\n * Mirror console.log/info/warn/debug into telemetry spans. Default true;\n * pass false when console output can hold user content. It does NOT stop\n * `console.error(err)` from being recorded as an error: the SDK's error\n * instrumentation is separate and always on.\n */\n consoleCapture?: boolean;\n /**\n * Capture full request/response headers AND BODIES on fetch/XHR spans.\n * Default false, and it should stay false: bodies are user data.\n */\n advancedNetworkCapture?: boolean;\n /**\n * Session replay (rrweb). Default false. When true, all text and inputs are\n * masked, media is blocked and canvas is not recorded (see the header).\n */\n replay?: boolean;\n /**\n * The share of sessions to record when `replay` is true, 0..1. Default 1\n * (every session). Decided once per session and held in sessionStorage. A\n * value that is not a number records nothing. An app with its own policy\n * (every session of a new user, a fraction of the rest) computes the rate\n * it wants for this session and passes it here.\n */\n replaySampleRate?: number;\n /** Verbose SDK diagnostics to the console. Default false. */\n debug?: boolean;\n /**\n * The `app.client` stamped on every event: `web`, `electron` or `landing`\n * (any short string is accepted). Unset, it is `electron` inside Electron\n * and `web` elsewhere.\n */\n appClient?: string;\n /**\n * localStorage key holding this browser's anonymous visitor id (stamped as\n * `visitor.id`). Set it to adopt an id a site already keeps, e.g. a landing\n * page's `reliant.visitor_id`. Default `forge.visitor_id`. A `rid` in the\n * landing URL wins over it.\n */\n visitorIdStorageKey?: string;\n /**\n * Start visitor attribution with the SDK. Default true. Pass false when the\n * visitor id needs a consent the page does not have yet (error telemetry for\n * everyone, a visitor id only with analytics consent): no visitor id is\n * created, read or stamped, nothing is captured from the URL, withAttribution\n * returns URLs untouched and `user_identified` never fires, until the app\n * calls enableAttribution().\n */\n attribution?: boolean;\n /**\n * `last` (default): a visit carrying `rid`/`utm_*` replaces the stored\n * record. `first`: the first stored record is kept for good — a marketing\n * site attributing acquisition to the campaign that first brought a visitor.\n */\n attributionTouch?: AttributionTouch;\n /**\n * Decides which errors are benign browser noise: kept out of the error\n * pipeline and counted as `forge.errors_filtered` actions instead\n * (benign-errors.ts). Default classifyBenignError: an AbortError, and the\n * browser's generic \"Failed to fetch\" TypeError; never a ConnectError. It\n * applies to what the SDK records from unhandled rejections, uncaught\n * errors, console.error and reportException; the app's own handlers see\n * every event unchanged. For an unhandled rejection or uncaught error it is\n * handed `{ name, message }` as the SDK recorded them, not the original\n * value. Pass `() => null` to record everything.\n */\n classifyBenignError?: BenignErrorClassifier;\n}\n\n/** The slice of the SDK this module calls. Typed here, not imported, so the module loads without it. */\ninterface HyperDXClient {\n init(config: Record<string, unknown>): void;\n recordException(error: unknown, attributes?: Record<string, unknown>): void;\n addAction?(name: string, attributes?: Record<string, TrackValue>): void;\n setGlobalAttributes?(attributes: Record<string, string>): void;\n stopSessionRecorder?(): void;\n getSessionId?(): string | undefined;\n}\n\nlet started: Promise<boolean> | null = null;\n\n// Attribution state shared by start() and enableAttribution(): whichever runs\n// second does the stamping, so the call order does not matter.\nlet attributionWanted = false;\nlet attributionOptions: { search?: string } = {};\nlet runningConfig: BrowserTelemetryConfig | null = null;\nlet runningClient: HyperDXClient | null = null;\n\nfunction captureVisitor(config: BrowserTelemetryConfig): string {\n return captureAttribution({\n search: attributionOptions.search,\n visitorIdStorageKey: config.visitorIdStorageKey,\n touch: config.attributionTouch,\n });\n}\n\n/**\n * Turn on visitor attribution for a page that started telemetry with\n * `attribution: false`, once the consent it needs is granted: from here on\n * every event carries `visitor.id`, withAttribution stamps links and the first\n * sign-in emits `user_identified`. Pass `search` (the landing URL's query\n * string, kept from page load) when a client-side navigation may have dropped\n * it since. Safe to call before init resolves, more than once, and on the\n * server; a no-op after disableTelemetry().\n */\nexport function enableAttribution(options?: { search?: string }): void {\n if (typeof window === \"undefined\" || isTelemetryDisabled()) {\n return;\n }\n if (options?.search !== undefined) {\n attributionOptions = { search: options.search };\n }\n if (attributionWanted) {\n return;\n }\n attributionWanted = true;\n if (runningClient && runningConfig) {\n try {\n runningClient.setGlobalAttributes?.({\n \"visitor.id\": captureVisitor(runningConfig),\n });\n } catch {\n // Telemetry must never break the app.\n }\n }\n}\n\n/**\n * initBrowserTelemetry starts the HyperDX browser SDK once per page load and\n * resolves to whether it is running. See the module header for the contract.\n */\nexport function initBrowserTelemetry(\n config: BrowserTelemetryConfig,\n): Promise<boolean> {\n if (typeof window === \"undefined\") {\n return Promise.resolve(false);\n }\n if (started) {\n return started;\n }\n if (isTelemetryDisabled()) {\n return Promise.resolve(false);\n }\n const ingest = resolveIngestUrl(config.endpoint, window.location.origin);\n if (!ingest) {\n // Nothing will ever drain track() calls held for the SDK; let them go.\n setTelemetrySink(null);\n return Promise.resolve(false);\n }\n started = start(config, ingest);\n registerTelemetryStartup(started);\n return started;\n}\n\nasync function start(\n config: BrowserTelemetryConfig,\n ingest: string,\n): Promise<boolean> {\n // Before the first await: until web-vitals registers in hdx.init, only this\n // watch sees the page hidden (see \"Paint vitals\" in the header).\n const hidden = watchFirstHidden();\n try {\n await firstVisible();\n const hdx = resolveClient(await import(\"@hyperdx/browser\"));\n if (!hdx || isTelemetryDisabled()) {\n hidden.stop();\n setTelemetrySink(null);\n return false;\n }\n const replay = decideReplay(config, sessionStorageOrNull(), Math.random);\n // Before init: the SDK reads its session cookie as it starts.\n keepSessionWithoutCookies();\n hdx.init(\n buildSdkOptions(\n { ...config, replay },\n ingest,\n window.location.origin,\n pageClientResourceAttributes(),\n ),\n );\n // From here web-vitals watches visibility itself.\n hidden.stop();\n dropBackgroundPaintVitals(hidden.at());\n // After init: both hook what the SDK RECORDS, never what the app sees.\n const benign = benignFilter(config, hdx);\n filterSdkErrorSpans(benign);\n tapSdkInputs(benign);\n // Every span carries where it came from and which visitor made it; the\n // product-event view reads these as app.client and visitor.id.\n // With attribution deferred (attribution: false), visitor.id joins them\n // when enableAttribution() runs.\n if (config.attribution !== false) {\n attributionWanted = true;\n }\n const globals: Record<string, string> = {\n \"app.client\": detectAppClient(config.appClient),\n };\n if (attributionWanted) {\n globals[\"visitor.id\"] = captureVisitor(config);\n }\n hdx.setGlobalAttributes?.(globals);\n // The viewport and screen ride on every span, refreshed on resize\n // (client-context.ts): the SDK's global attributes are a span processor\n // that stamps the current set on each span as it starts, so a span carries\n // the size of the moment it began (proved against the real SDK in\n // scripts/browser-telemetry-smoke.mjs). Device, OS and browser are\n // derived at ingest.\n const stopViewport = watchViewport((attrs) =>\n hdx.setGlobalAttributes?.(attrs),\n );\n runningClient = hdx;\n runningConfig = config;\n // The session id rides on every Connect call as baggage (trace.ts) and on\n // every fetch/XHR span (sessionAttribute), joining backend traces to the\n // session that caused them.\n registerRumSession(() => hdx.getSessionId?.());\n setExceptionReporter((error, attributes) => {\n if (alreadyRecorded(error) || benign.filtered(error, \"reportException\")) {\n return;\n }\n hdx.recordException(error, attributes);\n });\n setTelemetrySink({\n track: (name, attributes) => hdx.addAction?.(name, attributes),\n setUser: (id) => {\n hdx.setGlobalAttributes?.({ userId: id });\n // The first sign-in of a user in this browser links the visitor to\n // them: one event, never repeated for the same user.\n const identify = takeIdentifyProps(id);\n if (identify) {\n hdx.addAction?.(\"user_identified\", identify);\n }\n },\n disable: () => {\n // Back to \"no SDK\": reportException returns false, so a caller falls\n // back to console.error and the error does not vanish.\n setExceptionReporter(null);\n registerRumSession(null);\n stopViewport();\n hdx.stopSessionRecorder?.();\n },\n });\n return true;\n } catch (err) {\n // Blocked chunk, ad-blocker, SDK throw: telemetry must never break the app.\n // A startup that failed after the hooks went in takes them out again.\n hidden.stop();\n removeBenignFilter();\n console.debug(\"[telemetry] disabled:\", err);\n setTelemetrySink(null);\n return false;\n }\n}\n\n/**\n * Resolves once the document is visible: at once for a visible page or one\n * with no Page Visibility API, otherwise at its first visibilitychange to\n * visible. See \"No session until the page has been seen\" in the header.\n */\nfunction firstVisible(): Promise<void> {\n if (\n typeof document === \"undefined\" ||\n document.visibilityState !== \"hidden\" ||\n typeof document.addEventListener !== \"function\"\n ) {\n return Promise.resolve();\n }\n return new Promise((resolve) => {\n const onChange = () => {\n if (document.visibilityState !== \"hidden\") {\n document.removeEventListener(\"visibilitychange\", onChange);\n resolve();\n }\n };\n document.addEventListener(\"visibilitychange\", onChange);\n });\n}\n\n/** When the page was first hidden, as watchFirstHidden saw it. */\ninterface HiddenWatch {\n /** ms since the time origin, or Infinity while the page has not been hidden. */\n at(): number;\n stop(): void;\n}\n\n/**\n * Watches for the page's first hidden moment from now until stop(). The\n * browser's `visibility-state` entries (Chromium) go back to navigation; where\n * there are none, a page hidden now counts as hidden from now on, and a later\n * visibilitychange to hidden from then. See \"Paint vitals\" in the header.\n */\nfunction watchFirstHidden(): HiddenWatch {\n let at = Number.POSITIVE_INFINITY;\n const now = () =>\n typeof performance !== \"undefined\" && typeof performance.now === \"function\"\n ? performance.now()\n : 0;\n try {\n const entries =\n typeof performance !== \"undefined\" &&\n typeof performance.getEntriesByType === \"function\"\n ? performance.getEntriesByType(\"visibility-state\")\n : [];\n // A prerendered page is hidden until it is activated, as web-vitals\n // also ignores: only hiding after activation counts.\n const activated = activationStart();\n for (const e of entries) {\n if (e.name === \"hidden\" && e.startTime >= activated) {\n at = Math.min(at, e.startTime);\n }\n }\n } catch {\n // No such entry type here: the document's state below decides.\n }\n if (typeof document === \"undefined\") {\n return { at: () => at, stop: () => {} };\n }\n const hiddenNow = () =>\n document.visibilityState === \"hidden\" &&\n !(document as { prerendering?: boolean }).prerendering;\n if (hiddenNow()) {\n at = Math.min(at, now());\n }\n if (typeof document.addEventListener !== \"function\") {\n return { at: () => at, stop: () => {} };\n }\n const onChange = () => {\n if (hiddenNow()) {\n at = Math.min(at, now());\n }\n };\n document.addEventListener(\"visibilitychange\", onChange);\n return {\n at: () => at,\n stop: () => document.removeEventListener?.(\"visibilitychange\", onChange),\n };\n}\n\n/** The tracer (name) the SDK's web-vitals instrumentation records under. */\nconst SDK_WEBVITALS_SCOPE = \"webvitals\";\n\n/** The web vitals timed from navigation to a paint: wrong for a hidden page. */\nconst PAINT_VITALS = [\"fcp\", \"lcp\"] as const;\n\n/** The span attribute the SDK copies web-vitals' metric.navigationType into. */\nconst SDK_WEBVITALS_NAV_TYPE = \"webvitals.navigation_type\";\n\n/**\n * When an FCP or LCP span's paint happened, in ms since the time origin (the\n * coordinates of hiddenAt), or undefined when its value is not timed from\n * navigation. The SDK (@hyperdx/otel-web webvitals.js) sets the attribute to\n * web-vitals' metric.value, which web-vitals 3 computes as the paint entry's\n * startTime minus activationStart (0 except for a prerendered page); so the\n * paint time is the value plus activationStart. A page restored from the\n * back/forward cache instead reports the time since the restore, which says\n * nothing about when the first load was hidden.\n */\nfunction paintTime(\n value: number,\n attributes: Record<string, unknown>,\n): number | undefined {\n const navigationType = attributes[SDK_WEBVITALS_NAV_TYPE];\n if (navigationType === \"back-forward-cache\") {\n return undefined;\n }\n return navigationType === \"prerender\" ? value + activationStart() : value;\n}\n\n/** The navigation's activationStart (a prerendered page), else 0. */\nfunction activationStart(): number {\n try {\n const [nav] =\n typeof performance !== \"undefined\" &&\n typeof performance.getEntriesByType === \"function\"\n ? (performance.getEntriesByType(\"navigation\") as Array<{\n activationStart?: unknown;\n }>)\n : [];\n const at = nav?.activationStart;\n return typeof at === \"number\" && Number.isFinite(at) ? at : 0;\n } catch {\n return 0;\n }\n}\n\n/**\n * Drops an FCP or LCP span whose paint came at or after hiddenAt (ms since the\n * time origin): it measured how long the page waited to be shown. A no-op for\n * a page that was never hidden.\n */\nfunction dropBackgroundPaintVitals(hiddenAt: number): void {\n if (!Number.isFinite(hiddenAt)) {\n return;\n }\n const proxy = trace.getTracerProvider() as { getDelegate?: () => unknown };\n const provider = (proxy.getDelegate?.() ?? proxy) as {\n getTracer?: (name: string, version?: string) => unknown;\n };\n const tracer = provider.getTracer?.(SDK_WEBVITALS_SCOPE) as\n | StartSpanTracer\n | undefined;\n if (!tracer || typeof tracer.startSpan !== \"function\") {\n return;\n }\n const original = tracer.startSpan;\n const startSpan = function (\n this: unknown,\n name: string,\n ...rest: unknown[]\n ): unknown {\n const span = original.call(this, name, ...rest) as RecordingSpan;\n if (typeof span?.end !== \"function\") {\n return span;\n }\n const end = span.end;\n span.end = function (this: unknown, ...args: unknown[]) {\n const attributes = span.attributes ?? {};\n for (const vital of PAINT_VITALS) {\n const value = attributes[vital];\n if (typeof value !== \"number\") {\n continue;\n }\n const paintedAt = paintTime(value, attributes);\n if (paintedAt !== undefined && paintedAt >= hiddenAt) {\n // Never ended, so never exported.\n return undefined;\n }\n }\n return end.apply(this, args);\n };\n return span;\n };\n tracer.startSpan = startSpan;\n benignTeardown.push(() => {\n if (tracer.startSpan === startSpan) {\n tracer.startSpan = original;\n }\n });\n}\n\n// ── One failure, one record ──────────────────────────────────────────────\n//\n// The SDK records an Error that reaches window \"error\", window\n// \"unhandledrejection\", or console.error. React (18 and 19) console.errors an\n// error a boundary catches BEFORE it calls componentDidCatch, and Next\n// dispatches an uncaught render error to window \"error\" — so by the time\n// reportException runs, the SDK has usually recorded that very error already.\n// Recording it again would count one failure twice, and the issue layer\n// (which groups by fingerprint) would report two.\n//\n// So the taps below remember which Error OBJECTS the SDK was shown, and the\n// installed recorder skips those. Whatever the SDK did not see — a custom\n// onCaughtError that silences React's logging, an error rethrown as a new\n// object — is still recorded. The console tap is installed after the SDK's own\n// wrapper, so it sits outermost and only observes; every call is forwarded\n// untouched.\n//\n// The cost is the React component stack: the SDK's record of a boundary-caught\n// error comes from console.error(error), which carries the error and its\n// stack but not React's componentStack, and attributes passed to a skipped\n// reportException are dropped with it.\nconst seenBySdk = new WeakSet<object>();\nlet tapped = false;\n\nfunction noteSeen(value: unknown): void {\n if (typeof value === \"object\" && value !== null) {\n seenBySdk.add(value);\n }\n}\n\nfunction tapSdkInputs(benign: BenignFilter): void {\n if (tapped) {\n return;\n }\n tapped = true;\n const wrapped = console.error;\n const tap = function (this: unknown, ...args: unknown[]) {\n for (const arg of args) {\n try {\n if (arg instanceof Error) {\n noteSeen(arg);\n }\n } catch {\n // A revoked Proxy: not ours to inspect; forward it untouched.\n }\n }\n // The call always goes on to the SDK and the console, exactly as without\n // this tap. Only the verdict on the SDK's RECORD of it is decided here,\n // where the real arguments are: the SDK opens its console.error span\n // synchronously inside wrapped(), and filterSdkErrorSpans reads it.\n const previous = consoleVerdict;\n consoleVerdict = benignKindsOf(benign, args);\n try {\n return wrapped.apply(this, args);\n } finally {\n consoleVerdict = previous;\n }\n };\n console.error = tap;\n const onError = (e: ErrorEvent) => noteSeen(e.error);\n const onRejection = (e: PromiseRejectionEvent) => noteSeen(e.reason);\n window.addEventListener(\"error\", onError, true);\n window.addEventListener(\"unhandledrejection\", onRejection, true);\n benignTeardown.push(() => {\n if (console.error === tap) {\n console.error = wrapped;\n }\n window.removeEventListener?.(\"error\", onError, true);\n window.removeEventListener?.(\"unhandledrejection\", onRejection, true);\n tapped = false;\n });\n}\n\n/**\n * The kind of every exception in a console.error call when ALL of them are\n * benign, or null to record the call: no exception, one real one, or an\n * argument that cannot even be inspected (a throwing Symbol.toStringTag\n * getter, a revoked Proxy).\n */\nfunction benignKindsOf(benign: BenignFilter, args: unknown[]): string[] | null {\n const kinds: string[] = [];\n for (const arg of args) {\n let exception: boolean;\n try {\n exception = isExceptionLike(arg);\n } catch {\n return null;\n }\n if (!exception) {\n continue;\n }\n const kind = benign.classify(arg);\n if (kind === null) {\n return null;\n }\n kinds.push(kind);\n }\n return kinds.length > 0 ? kinds : null;\n}\n\n// ── Benign browser errors (benign-errors.ts) ────────────────────────────\n//\n// Filtered at the SDK's RECORDING boundary, never at the app's: every window\n// \"error\" / \"unhandledrejection\" event and every console.error call reaches\n// every app handler (window.onerror, onunhandledrejection, listeners of any\n// phase, registered before telemetry started or after) and the console\n// exactly as it would with no telemetry at all.\n//\n// The SDK's error capture opens one span per failure on its `errors` tracer —\n// named onerror, unhandledrejection or console.error — and ends it once the\n// exception is attached; only an ENDED span is ever exported. The SDK has no\n// drop hook (its exporter options are not reachable through @hyperdx/browser,\n// and an OTel 2.x provider takes no span processor after construction), so the\n// runtime wraps that tracer's startSpan: a benign failure's span is counted\n// and simply never ended, so it is never exported. Everything else ends as\n// the SDK meant.\n//\n// - window events: the span describes one value, so it is classified from\n// what the SDK recorded on it (error.object = the error's name,\n// error.message). A String (a non-Error throw) is never benign.\n// - console.error: one call can carry several values, and the span names\n// only the first exception, so the verdict comes from the console tap,\n// which classifies every argument (consoleVerdict).\ninterface BenignFilter {\n /** The kind of a benign error, or null. Counts nothing. */\n classify(error: unknown): string | null;\n /** Count one filtered error of `kind`. */\n note(kind: string, source: BenignErrorSource): void;\n /** Count and report true when `error` is benign; false to record it. */\n filtered(error: unknown, source: BenignErrorSource): boolean;\n}\n\nfunction benignFilter(\n config: BrowserTelemetryConfig,\n hdx: HyperDXClient,\n): BenignFilter {\n const classify = config.classifyBenignError ?? classifyBenignError;\n const counter = new FilteredErrorCounter((name, attributes) => {\n if (!isTelemetryDisabled()) {\n hdx.addAction?.(name, attributes);\n }\n });\n const onPageHide = () => counter.flush();\n const onVisibility = () => {\n if (document.visibilityState === \"hidden\") {\n counter.flush();\n }\n };\n if (typeof window.addEventListener === \"function\") {\n window.addEventListener(\"pagehide\", onPageHide);\n }\n if (typeof document !== \"undefined\") {\n document.addEventListener(\"visibilitychange\", onVisibility);\n }\n benignTeardown.push(() => {\n window.removeEventListener?.(\"pagehide\", onPageHide);\n if (typeof document !== \"undefined\") {\n document.removeEventListener(\"visibilitychange\", onVisibility);\n }\n });\n const kindOf = (error: unknown): string | null => {\n try {\n return classify(error) || null;\n } catch {\n // A classifier that throws keeps the error.\n return null;\n }\n };\n return {\n classify: kindOf,\n note: (kind, source) => counter.note(kind, source),\n filtered(error, source) {\n const kind = kindOf(error);\n if (!kind) {\n return false;\n }\n counter.note(kind, source);\n return true;\n },\n };\n}\n\n/** The scope (name, version) the SDK's error capture records under. */\nconst SDK_ERRORS_SCOPE = { name: \"errors\", version: \"1\" } as const;\n\n/** The spans that scope opens, one per captured failure, and their source. */\nconst SDK_ERROR_SPANS: Record<string, BenignErrorSource> = {\n onerror: \"error\",\n unhandledrejection: \"unhandledrejection\",\n \"console.error\": \"console.error\",\n};\n\n// The console tap's verdict on the call now inside the SDK's wrapper: the\n// benign kinds, null to record it, undefined when no tapped call is running.\nlet consoleVerdict: string[] | null | undefined;\n\ninterface RecordingSpan {\n end(...args: unknown[]): unknown;\n attributes?: Record<string, unknown>;\n}\n\ninterface StartSpanTracer {\n startSpan(name: string, ...rest: unknown[]): unknown;\n}\n\nfunction filterSdkErrorSpans(benign: BenignFilter): void {\n const proxy = trace.getTracerProvider() as { getDelegate?: () => unknown };\n const provider = (proxy.getDelegate?.() ?? proxy) as {\n getTracer?: (name: string, version?: string) => unknown;\n };\n const tracer = provider.getTracer?.(\n SDK_ERRORS_SCOPE.name,\n SDK_ERRORS_SCOPE.version,\n ) as StartSpanTracer | undefined;\n if (!tracer || typeof tracer.startSpan !== \"function\") {\n // No seam: record everything, as without the filter.\n return;\n }\n const original = tracer.startSpan;\n const startSpan = function (\n this: unknown,\n name: string,\n ...rest: unknown[]\n ): unknown {\n const span = original.call(this, name, ...rest) as RecordingSpan;\n const source = SDK_ERROR_SPANS[name];\n if (!source || typeof span?.end !== \"function\") {\n return span;\n }\n const verdict = name === \"console.error\" ? consoleVerdict : undefined;\n const end = span.end;\n span.end = function (this: unknown, ...args: unknown[]) {\n const kinds =\n name === \"console.error\"\n ? (verdict ?? null)\n : recordedKind(benign, span);\n if (kinds) {\n for (const kind of kinds) {\n benign.note(kind, source);\n }\n // Never ended, so never exported.\n return undefined;\n }\n return end.apply(this, args);\n };\n return span;\n };\n tracer.startSpan = startSpan;\n benignTeardown.push(() => {\n if (tracer.startSpan === startSpan) {\n tracer.startSpan = original;\n }\n });\n}\n\n/** The benign kind of the one failure a window-event span recorded, or null. */\nfunction recordedKind(\n benign: BenignFilter,\n span: RecordingSpan,\n): string[] | null {\n try {\n const name = span.attributes?.[\"error.object\"];\n const message = span.attributes?.[\"error.message\"];\n if (typeof name !== \"string\" || name === \"String\") {\n return null;\n }\n const kind = benign.classify({\n name,\n message: typeof message === \"string\" ? message : \"\",\n });\n return kind ? [kind] : null;\n } catch {\n return null;\n }\n}\n\n// What undoes the benign filter's hooks (the tracer wrap, the console tap, the\n// flush listeners), run when startup fails at any point after they went in.\nlet benignTeardown: Array<() => void> = [];\n\nfunction removeBenignFilter(): void {\n const undo = benignTeardown;\n benignTeardown = [];\n for (const fn of undo.reverse()) {\n try {\n fn();\n } catch {\n // Telemetry must never break the app.\n }\n }\n}\n\n// An exception value as console.error receives it: an Error, a DOMException\n// (not an Error in every browser), or either from another realm (an iframe),\n// which fails instanceof but keeps its [object Error] / [object DOMException]\n// tag.\nfunction isExceptionLike(value: unknown): boolean {\n if (typeof value !== \"object\" || value === null) {\n return false;\n }\n if (value instanceof Error) {\n return true;\n }\n if (typeof DOMException !== \"undefined\" && value instanceof DOMException) {\n return true;\n }\n const tag = Object.prototype.toString.call(value);\n return tag === \"[object Error]\" || tag === \"[object DOMException]\";\n}\n\nfunction alreadyRecorded(error: unknown): boolean {\n return typeof error === \"object\" && error !== null && seenBySdk.has(error);\n}\n\n/**\n * The options passed to HyperDX.init. Exported for tests and for apps that\n * want to see exactly what is configured — it is pure. `clientAttributes`\n * are the page's own client resource attributes (client-context.ts:\n * browser.* client hints, app.desktop.*); the config's keys win over them.\n */\nexport function buildSdkOptions(\n config: BrowserTelemetryConfig,\n ingestUrl: string,\n pageOrigin: string,\n clientAttributes: Record<string, string> = {},\n): Record<string, unknown> {\n // `config.replay` is the FINAL decision here. initBrowserTelemetry resolves\n // replaySampleRate into it (decideReplay) before calling this.\n const replay = config.replay === true;\n const resourceAttributes: Record<string, string> = { ...clientAttributes };\n if (config.serviceVersion) {\n resourceAttributes[\"service.version\"] = config.serviceVersion;\n }\n if (config.serviceNamespace) {\n resourceAttributes[\"service.namespace\"] = config.serviceNamespace;\n }\n if (config.frontend) {\n resourceAttributes[\"forge.frontend\"] = config.frontend;\n }\n if (config.environment) {\n resourceAttributes[\"deployment.environment.name\"] = config.environment;\n resourceAttributes[\"deployment.environment\"] = config.environment;\n }\n\n const targets = propagationTargets(pageOrigin, config.apiOrigins);\n const advancedNetworkCapture = config.advancedNetworkCapture ?? false;\n const options: Record<string, unknown> = {\n apiKey: PLACEHOLDER_API_KEY,\n service: config.serviceName,\n url: ingestUrl,\n tracePropagationTargets: targets,\n // The SDK would otherwise trace its own exports, and it must never\n // observe the route it ships through.\n ignoreUrls: [new RegExp(`^${escapeRegExp(ingestUrl)}`)],\n consoleCapture: config.consoleCapture ?? true,\n advancedNetworkCapture,\n // The SDK spreads this over ITS fetch/xhr config as whole keys, so\n // everything it would have set (propagation targets, the capture switch)\n // must be restated here or it is lost.\n instrumentations: {\n // Raw DOM events belong to replay, not distributed traces. HyperDX's\n // default traces every mousedown/up listener (including replay's own),\n // creating empty roots. Meaningful actions can still use manual spans;\n // fetch/xhr and document-load instrumentation keep their real parents.\n interactions: false,\n fetch: {\n propagateTraceHeaderCorsUrls: targets,\n advancedNetworkCapture: () => advancedNetworkCapture,\n applyCustomAttributesOnSpan: finishNetworkSpan,\n },\n xhr: {\n propagateTraceHeaderCorsUrls: targets,\n advancedNetworkCapture: () => advancedNetworkCapture,\n applyCustomAttributesOnSpan: finishNetworkSpan,\n },\n },\n // Polls for window.Intercom on a timer; nothing here uses Intercom.\n disableIntercom: true,\n disableReplay: !replay,\n otelResourceAttributes: resourceAttributes,\n debug: config.debug ?? false,\n // Privacy is forced and unconditional: no path through this function\n // yields an unmasked or media-recording replay. The SDK's own default\n // masks inputs but NOT text, and text is where chat content and records\n // live.\n maskAllInputs: true,\n maskAllText: true,\n recordCanvas: false,\n blockSelector: REPLAY_BLOCK_SELECTOR,\n replay: { inlineImages: false, collectFonts: false },\n };\n return options;\n}\n\n/** Elements a replay never records: their pixels stay in the browser. */\nexport const REPLAY_BLOCK_SELECTOR =\n \"img, picture, video, audio, iframe, object, embed\";\n\n/** Where a replay sampling decision is held for the tab's session. */\nexport const REPLAY_SAMPLE_KEY = \"forge.replay.sampled\";\n\n/** The slice of Storage the sampling decision needs. */\ninterface DecisionStore {\n getItem(key: string): string | null;\n setItem(key: string, value: string): void;\n}\n\n/**\n * Whether this session records a replay: config.replay, then the sample rate,\n * drawn once and remembered in `store` so a reload (or a route change that\n * re-runs init) never re-rolls into a session that only half-recorded. With no\n * usable store the draw is made each load. Pure given its inputs; exported for\n * tests.\n */\nexport function decideReplay(\n config: Pick<BrowserTelemetryConfig, \"replay\" | \"replaySampleRate\">,\n store: DecisionStore | null,\n random: () => number,\n): boolean {\n if (config.replay !== true) {\n return false;\n }\n const rate = clampRate(config.replaySampleRate);\n if (rate >= 1) {\n return true;\n }\n if (rate <= 0) {\n return false;\n }\n try {\n const held = store?.getItem(REPLAY_SAMPLE_KEY);\n if (held === \"1\" || held === \"0\") {\n return held === \"1\";\n }\n } catch {\n // Storage blocked: fall through to a fresh draw.\n }\n const sampled = random() < rate;\n try {\n store?.setItem(REPLAY_SAMPLE_KEY, sampled ? \"1\" : \"0\");\n } catch {\n // Not persisted: the next load draws again.\n }\n return sampled;\n}\n\n// Unset is \"every session\"; anything that is not a number is a bug, and a bug\n// must not start recording people.\nfunction clampRate(rate: number | undefined): number {\n if (rate === undefined) {\n return 1;\n }\n if (typeof rate !== \"number\" || Number.isNaN(rate)) {\n return 0;\n }\n return Math.min(1, Math.max(0, rate));\n}\n\n/** See \"One session per visit\" in the header. Never throws. */\nfunction keepSessionWithoutCookies(): void {\n try {\n if (typeof document === \"undefined\") {\n return;\n }\n installSessionCookieFallback(document, window.localStorage ?? null);\n } catch {\n // localStorage access can throw (blocked storage): keep the SDK default.\n }\n}\n\nfunction sessionStorageOrNull(): DecisionStore | null {\n try {\n return window.sessionStorage;\n } catch {\n return null;\n }\n}\n\n/** The span attributes that hold a request URL. */\nconst URL_ATTRIBUTES = [\"http.url\", \"url.full\"] as const;\n\n/** `url` without its query string and fragment. */\nexport function stripUrlQuery(url: string): string {\n const cut = url.search(/[?#]/);\n return cut === -1 ? url : url.slice(0, cut);\n}\n\ninterface UrlSpan {\n attributes?: Record<string, unknown>;\n setAttribute(key: string, value: string): unknown;\n updateName?(name: string): unknown;\n}\n\n// applyCustomAttributesOnSpan for both instrumentations: it runs before the\n// span ends, and after HyperDX's own `HTTP <METHOD>` rename, so the values\n// set here are the ones exported. The span carries the RUM session as\n// `session.id` (the resource's rum.sessionId says the same for the browser;\n// the attribute is what the backend's own spans carry too, so a trace is found\n// by session from either side).\nfunction finishNetworkSpan(span: UrlSpan): void {\n stripNetworkQuery(span);\n const url = span.attributes?.[\"url.full\"] ?? span.attributes?.[\"http.url\"];\n const method =\n span.attributes?.[\"http.request.method\"] ??\n span.attributes?.[\"http.method\"];\n if (typeof url === \"string\" && typeof span.updateName === \"function\") {\n const name = spanRouteName(typeof method === \"string\" ? method : \"\", url);\n if (name) {\n span.updateName(name);\n }\n }\n const session = rumSessionId();\n if (session) {\n span.setAttribute(\"session.id\", session);\n }\n}\n\nfunction stripNetworkQuery(span: UrlSpan): void {\n for (const key of URL_ATTRIBUTES) {\n const value = span.attributes?.[key];\n if (typeof value === \"string\") {\n const stripped = stripUrlQuery(value);\n if (stripped !== value) {\n span.setAttribute(key, stripped);\n }\n }\n }\n}\n\n// A Connect/gRPC procedure: `/<package>.<Service>/<Method>`, the service and\n// method PascalCase as protobuf declares them. The whole path is the route,\n// fixed by the proto, so it carries no request values.\nconst RPC_PATH = /^\\/[A-Za-z_]\\w*(?:\\.[A-Za-z_]\\w*)*\\.[A-Z]\\w*\\/[A-Z]\\w*$/;\n\n/**\n * The name a fetch/XHR span gets: `<METHOD> /<package>.<Service>/<Method>`,\n * the server span's name with the method in front, when the URL is a\n * Connect/gRPC procedure. Empty for any other URL, which keeps the SDK's\n * `HTTP <METHOD>`: an arbitrary path can hold values (ids, tokens, emails) no\n * pattern recognises reliably, and a span name must be neither sensitive nor\n * unbounded. Empty too when `url` cannot be parsed. Exported for tests.\n */\nexport function spanRouteName(method: string, url: string): string {\n let path: string;\n try {\n path = new URL(url, \"http://base.invalid\").pathname;\n } catch {\n return \"\";\n }\n if (!RPC_PATH.test(path)) {\n return \"\";\n }\n return `${method.trim().toUpperCase() || \"POST\"} ${path}`;\n}\n\n/**\n * resolveIngestUrl turns the configured endpoint into the absolute URL the SDK\n * is given, or null when telemetry is off. A path resolves against the page\n * origin, so the default is same-origin by construction.\n */\nexport function resolveIngestUrl(\n endpoint: string | undefined,\n pageOrigin: string,\n): string | null {\n const value = (endpoint ?? \"\").trim();\n if (value === \"\" || value.toLowerCase() === \"off\") {\n return null;\n }\n try {\n return new URL(value, pageOrigin).toString().replace(/\\/+$/, \"\");\n } catch {\n return null;\n }\n}\n\nfunction propagationTargets(\n pageOrigin: string,\n apiOrigins: Array<string | undefined> = [],\n): RegExp[] {\n const origins = new Set<string>([pageOrigin]);\n for (const raw of apiOrigins) {\n if (!raw) {\n continue;\n }\n try {\n origins.add(new URL(raw, pageOrigin).origin);\n } catch {\n // An unparsable origin is not a target.\n }\n }\n return [...origins].map((o) => new RegExp(`^${escapeRegExp(o)}(?:[/?#]|$)`));\n}\n\nfunction escapeRegExp(s: string): string {\n return s.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n\n// @hyperdx/browser is a UMD/CJS bundle whose module.exports IS the client, and\n// its methods use `this`. A bundler hands back a module NAMESPACE that exposes\n// both the client's members at the top level (as read-only getters) and the\n// client itself as `default`. Calling init on the namespace binds `this` to that\n// frozen object and the SDK throws on its first property write, which disabled\n// telemetry silently. So descend to the deepest `default` that is still a\n// client, the real instance, and never settle for the namespace in front of it.\nfunction resolveClient(mod: unknown): HyperDXClient | null {\n let cur: unknown = mod;\n for (let depth = 0; depth < 4; depth++) {\n const next = peek(cur, \"default\");\n if (!isClient(next)) {\n break;\n }\n cur = next;\n }\n return isClient(cur) ? cur : null;\n}\n\nfunction isClient(v: unknown): v is HyperDXClient {\n return (\n typeof peek(v, \"init\") === \"function\" &&\n typeof peek(v, \"recordException\") === \"function\"\n );\n}\n\n// A module namespace object may throw on an absent key (strict ESM\n// interop shims and test doubles do), and \"absent\" is an answer here.\nfunction peek(obj: unknown, key: string): unknown {\n try {\n return (obj as Record<string, unknown>)[key];\n } catch {\n return undefined;\n }\n}\n\n/** The tracer to open manual spans on. Resolves HyperDX's provider once it is running. */\nexport function getTracer(name = \"default\") {\n return trace.getTracer(name);\n}\n\nexport { context, propagation, trace } from \"@opentelemetry/api\";\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@reliantlabs/forge-web-runtime",
|
|
3
|
-
"version": "0.13.
|
|
3
|
+
"version": "0.13.3",
|
|
4
4
|
"description": "The forge frontend runtime: Connect interceptor stack, session, error boundary, toast queue, <Resource> container, W3C trace propagation and the HyperDX browser SDK wiring (errors, console, network, traces; replay off by default). The web twin of forge/pkg.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"//repository note": "REQUIRED for `npm publish --provenance`, not decoration. npm cross-checks this against the repository in the signed provenance statement and rejects the publish with a 422 if they disagree — an absent field reads as \"\" and fails that comparison. `directory` names the subdirectory this package lives in, so the provenance points at the real source. Omitting this is what made the first 0.3.1 publish fail AFTER the tarball had been signed and written to the sigstore transparency log.",
|