@safaricom-mxl/effect-sdk 0.0.23 → 0.0.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +34 -13
- package/dist/browser/index.d.ts +50 -89
- package/dist/browser/index.d.ts.map +1 -1
- package/dist/browser/index.js +4 -512
- package/dist/browser/index.js.map +1 -1
- package/dist/cloudflare/index.d.ts +1 -2
- package/dist/cloudflare/index.d.ts.map +1 -1
- package/dist/cloudflare/index.js +75 -27
- package/dist/cloudflare/index.js.map +1 -1
- package/dist/flushable-CXe-q-GF.js +1068 -0
- package/dist/flushable-CXe-q-GF.js.map +1 -0
- package/dist/flushable-SCVrRJX3.d.ts +143 -0
- package/dist/flushable-SCVrRJX3.d.ts.map +1 -0
- package/dist/foldkit/index.d.ts +65 -0
- package/dist/foldkit/index.d.ts.map +1 -0
- package/dist/foldkit/index.js +495 -0
- package/dist/foldkit/index.js.map +1 -0
- package/dist/{index-CPZhMHLl.d.mts → index-BUoRJxHg.d.mts} +262 -196
- package/dist/index-BUoRJxHg.d.mts.map +1 -0
- package/dist/index.server.d.mts +2 -2
- package/dist/index.server.mjs +1 -2
- package/dist/{rolldown-runtime-D7D4PA-g.js → rolldown-runtime-D8jQpDG7.js} +1 -2
- package/dist/{rolldown-runtime-D7D4PA-g.mjs → rolldown-runtime-D8jQpDG7.mjs} +1 -2
- package/dist/server/index.d.mts +2 -2
- package/dist/server/index.mjs +1 -2
- package/dist/{server-25vCyy-w.mjs → server-BMDPjez-.mjs} +645 -573
- package/dist/server-BMDPjez-.mjs.map +1 -0
- package/package.json +61 -53
- package/dist/index-CPZhMHLl.d.mts.map +0 -1
- package/dist/server-25vCyy-w.mjs.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flushable-CXe-q-GF.js","names":["identify","clearIdentity","track","identifySync","clearIdentitySync","trackSync","layer","browserLayer"],"sources":["../src/shared/url-privacy.ts","../src/shared/identity.ts","../src/shared/product-event.ts","../src/version.ts","../src/browser/analytics.ts","../src/shared/try-sync.ts","../src/browser/browser-globals.ts","../src/server/otlp.ts","../src/shared/flush-core.ts","../src/shared/span-options.ts","../src/shared/flushable-tracer.ts","../src/browser/replay.ts","../src/browser/layer.ts","../src/browser/flushable.ts"],"sourcesContent":["/**\n * URL redaction for everything that leaves the page carrying a URL: session\n * entry/exit URLs, event rows, network events, rrweb meta events and span\n * attributes.\n *\n * Magic links, password resets and OAuth implicit flows put credentials in the\n * query string or fragment, and a page view is captured on exactly those\n * pages. Values of credential-shaped parameters are therefore replaced by\n * default; the host app can add its own `sanitizeUrl` on top.\n */\n\nexport type UrlSanitizer = (url: string) => string;\n\nconst REDACTED = 'REDACTED';\n\nconst SENSITIVE_PARAM =\n /^(access_token|id_token|refresh_token|token|token_hash|auth|authorization|code|oobcode|state|password|passwd|pwd|pass|secret|client_secret|api_key|apikey|key|signature|sig|otp|jwt|session|sessionid|session_id|ticket|__clerk_ticket|reset_token|magic|nonce|x-amz-signature|x-amz-credential|x-amz-security-token|x-goog-signature|x-goog-credential)$/i;\n\n/** Sanitizers live on `globalThis`, like consent: one page, one policy, however many SDK copies. */\nconst SANITIZERS_KEY = '__MXL_URL_SANITIZERS__';\n\nfunction sanitizers(): Set<UrlSanitizer> {\n const owner = globalThis as Record<string, unknown>;\n const existing = owner[SANITIZERS_KEY];\n if (existing instanceof Set) return existing as Set<UrlSanitizer>;\n const fresh = new Set<UrlSanitizer>();\n owner[SANITIZERS_KEY] = fresh;\n return fresh;\n}\n\n/**\n * Register a host-app sanitizer. Additive, like the consent gates: an SDK\n * initialized without one must not remove the one another SDK was given.\n */\nexport function addUrlSanitizer(sanitizer: UrlSanitizer): void {\n sanitizers().add(sanitizer);\n}\n\n/** Test seam. */\nexport function resetUrlSanitizersForTests(): void {\n sanitizers().clear();\n}\n\nfunction redactParams(params: URLSearchParams): boolean {\n let changed = false;\n for (const name of new Set(params.keys())) {\n if (!SENSITIVE_PARAM.test(name)) continue;\n params.set(name, REDACTED);\n changed = true;\n }\n return changed;\n}\n\n/**\n * Implicit-flow tokens ride the fragment as `#access_token=…&…`; a hash-routed\n * app carries them in the route's own query, `#/reset?token=…`. The route path\n * is kept either way.\n */\nfunction redactFragment(fragment: string): string {\n if (fragment.startsWith('/') || fragment.startsWith('!/')) {\n const queryAt = fragment.indexOf('?');\n if (queryAt === -1) return fragment;\n const params = new URLSearchParams(fragment.slice(queryAt + 1));\n return redactParams(params)\n ? `${fragment.slice(0, queryAt)}?${params.toString()}`\n : fragment;\n }\n if (!fragment.includes('=')) return fragment;\n const params = new URLSearchParams(fragment);\n return redactParams(params) ? params.toString() : fragment;\n}\n\nconst ABSOLUTE = /^[a-z][a-z0-9+.-]*:/i;\nconst RELATIVE_BASE = 'http://relative.invalid';\n\n/** Redact credential-shaped query and fragment parameters, keeping the URL's form. */\nexport function redactUrl(url: string): string {\n if (!url || (!url.includes('?') && !url.includes('#'))) return url;\n const absolute = ABSOLUTE.test(url);\n let parsed: URL;\n try {\n parsed = new URL(url, absolute ? undefined : RELATIVE_BASE);\n } catch {\n return url;\n }\n let changed = redactParams(parsed.searchParams);\n const fragment = parsed.hash.slice(1);\n const redactedFragment = redactFragment(fragment);\n if (redactedFragment !== fragment) {\n parsed.hash = redactedFragment;\n changed = true;\n }\n if (!changed) return url;\n if (absolute) return parsed.href;\n // Protocol-relative (`//cdn.example.com/a`): keep the host, drop the base's scheme.\n if (url.startsWith('//')) return parsed.href.slice(parsed.protocol.length);\n const tail = `${parsed.pathname}${parsed.search}${parsed.hash}`;\n return url.startsWith('/') ? tail : tail.replace(/^\\//, '');\n}\n\n/**\n * The URL as it may leave the page: default redaction, then every registered\n * host sanitizer. A sanitizer that throws or returns a non-string yields the\n * default-redacted URL rather than the raw one.\n */\nexport function scrubUrl(url: string): string {\n let out = redactUrl(url);\n for (const sanitizer of sanitizers()) {\n try {\n const next = sanitizer(out);\n if (typeof next === 'string') out = next;\n } catch {\n // A broken host sanitizer must not throw into capture.\n }\n }\n return out;\n}\n","export interface MapleIdentity {\n readonly email?: string | undefined;\n readonly groupId?: string | undefined;\n readonly groupName?: string | undefined;\n readonly id: string;\n readonly traits?: Record<string, unknown> | undefined;\n}\n\nexport type IdentifyInput = string | MapleIdentity | null | undefined;\n\nexport const normalizeIdentity = (\n input: IdentifyInput,\n): MapleIdentity | undefined => {\n if (input === null || input === undefined) {\n return undefined;\n }\n if (typeof input === 'string') {\n const id = input.trim();\n return id.length > 0 ? { id } : undefined;\n }\n const id = input.id.trim();\n if (id.length === 0) {\n return undefined;\n }\n return {\n email: input.email,\n groupId: input.groupId,\n groupName: input.groupName,\n id,\n traits: input.traits,\n };\n};\n","export type ProductEventSource = 'server' | 'browser';\n\nexport const MAX_EVENT_NAME_LENGTH = 80;\nexport const RESERVED_EVENT_NAMES = ['session_start', 'session_end'] as const;\n\nexport interface ProductEventLine {\n readonly attributes: Record<string, string>;\n readonly group_id: string;\n readonly name: string;\n readonly page_path: string;\n readonly service_name: string;\n readonly session_id: string;\n readonly source: ProductEventSource;\n readonly timestamp: string;\n readonly traceparent?: string | undefined;\n readonly url: string;\n readonly user_id: string;\n readonly visitor_id: string;\n}\n\nexport interface TrackProps {\n readonly [key: string]: unknown;\n}\n\nexport interface TrackOptions {\n readonly attributes?: TrackProps | undefined;\n readonly groupId?: string | undefined;\n readonly pagePath?: string | undefined;\n readonly sessionId?: string | undefined;\n readonly timestamp?: Date | number | undefined;\n readonly traceparent?: string | undefined;\n readonly url?: string | undefined;\n readonly userId?: string | undefined;\n readonly visitorId?: string | undefined;\n}\n\nconst isReservedEventName = (name: string): boolean =>\n RESERVED_EVENT_NAMES.some((reserved) => reserved === name);\n\nexport const coerceTrackProps = (\n props: TrackProps | undefined,\n): Record<string, string> => {\n if (props === undefined) {\n return {};\n }\n const attributes: Record<string, string> = {};\n for (const [key, value] of Object.entries(props)) {\n if (value === undefined) {\n continue;\n }\n attributes[key] = typeof value === 'string' ? value : String(value);\n }\n return attributes;\n};\n\nexport const toEventTimestamp = (value: Date | number | undefined): string =>\n (value instanceof Date ? value : new Date(value ?? Date.now())).toISOString();\n\nexport const encodeProductEventLine = (input: {\n readonly name: string;\n readonly options?: TrackOptions | undefined;\n readonly serviceName: string;\n readonly source: ProductEventSource;\n}): ProductEventLine | undefined => {\n const trimmed = typeof input.name === 'string' ? input.name.trim() : '';\n if (trimmed.length === 0 || isReservedEventName(trimmed)) {\n return undefined;\n }\n const options = input.options ?? {};\n return {\n attributes: coerceTrackProps(options.attributes),\n group_id: options.groupId ?? '',\n name: trimmed.slice(0, MAX_EVENT_NAME_LENGTH),\n page_path: options.pagePath ?? '',\n service_name: input.serviceName,\n session_id: options.sessionId ?? '',\n source: input.source,\n timestamp: toEventTimestamp(options.timestamp),\n traceparent: options.traceparent,\n url: options.url ?? '',\n user_id: options.userId ?? '',\n visitor_id: options.visitorId ?? '',\n };\n};\n\nexport const encodeNdjson = (lines: ReadonlyArray<ProductEventLine>): string =>\n `${lines.map((line) => JSON.stringify(line)).join('\\n')}\\n`;\n","export const SDK_NAME = 'mxl-effect-sdk';\nexport const SDK_VERSION = '0.0.24';\n","import type { IdentifyInput, MapleIdentity } from '../shared/identity.js';\nimport { normalizeIdentity } from '../shared/identity.js';\nimport type { TrackProps } from '../shared/product-event.js';\nimport {\n encodeNdjson,\n encodeProductEventLine,\n} from '../shared/product-event.js';\nimport { SDK_NAME, SDK_VERSION } from '../version.js';\n\nexport type { IdentifyInput, MapleIdentity, TrackProps };\n\nexport interface PrivacyOptions {\n readonly requireConsent?: boolean | undefined;\n}\n\nexport interface BrowserAnalyticsConfig {\n readonly apiKey?: string | undefined;\n readonly clientId?: string | undefined;\n readonly ingestUrl?: string | undefined;\n readonly privacy?: PrivacyOptions | undefined;\n readonly serviceName?: string | undefined;\n}\n\ninterface QueuedCustomEvent {\n readonly name: string;\n readonly props?: TrackProps | undefined;\n}\n\nconst DEFAULT_INGEST_URL = 'http://127.0.0.1:8000';\nconst MAX_QUEUE = 100;\n\nlet config: BrowserAnalyticsConfig | undefined;\nlet identity: MapleIdentity | undefined;\nlet consentGranted = true;\nlet sessionId = '';\nlet queue: QueuedCustomEvent[] = [];\nlet started = false;\n\nconst randomId = (): string => {\n if (globalThis.crypto?.randomUUID) {\n return globalThis.crypto.randomUUID();\n }\n return `mxl_${Math.random().toString(36).slice(2)}_${Date.now()}`;\n};\n\nconst storageGet = (key: string): string | undefined => {\n try {\n const value = globalThis.sessionStorage?.getItem(key);\n return value && value.length > 0 ? value : undefined;\n } catch {\n return undefined;\n }\n};\n\nconst storageSet = (key: string, value: string): void => {\n try {\n globalThis.sessionStorage?.setItem(key, value);\n } catch {\n // Private mode or missing storage.\n }\n};\n\nconst resolveSessionId = (): string => {\n if (sessionId.length > 0) {\n return sessionId;\n }\n sessionId = storageGet('mxl.session.id') ?? randomId();\n storageSet('mxl.session.id', sessionId);\n return sessionId;\n};\n\nconst ingestOrigin = (): string =>\n (config?.ingestUrl ?? DEFAULT_INGEST_URL).replace(/\\/$/, '');\n\nconst headers = (): Record<string, string> => {\n const next: Record<string, string> = {\n 'content-type': 'application/json',\n 'mxl-client-id': config?.clientId ?? '',\n 'mxl-sdk-name': SDK_NAME,\n 'mxl-sdk-version': SDK_VERSION,\n };\n if (config?.apiKey) {\n next['mxl-api-key'] = config.apiKey;\n }\n return next;\n};\n\nconst post = (\n path: string,\n body: string,\n contentType: string,\n keepalive = false,\n): void => {\n if (!config?.clientId) {\n return;\n }\n try {\n void fetch(`${ingestOrigin()}${path}`, {\n body,\n headers: { ...headers(), 'content-type': contentType },\n keepalive,\n method: 'POST',\n });\n } catch {\n // Never throw into the host app.\n }\n};\n\nconst captureAllowed = (): boolean =>\n Boolean(config?.clientId) && consentGranted && started;\n\nexport const getCurrentIdentity = (): MapleIdentity | undefined => identity;\n\nexport const getCurrentUserId = (): string | undefined => identity?.id;\n\nexport const getCurrentSessionId = (): string => resolveSessionId();\n\nexport const configureBrowserAnalytics = (\n next: BrowserAnalyticsConfig,\n): void => {\n config = next;\n consentGranted = next.privacy?.requireConsent !== true;\n started = true;\n resolveSessionId();\n drainQueue();\n};\n\nexport const resetBrowserAnalytics = (): void => {\n config = undefined;\n identity = undefined;\n consentGranted = true;\n sessionId = '';\n queue = [];\n started = false;\n};\n\nexport const setConsent = (granted: boolean): void => {\n consentGranted = granted;\n if (granted) {\n drainQueue();\n }\n};\n\nexport const identify = (input?: IdentifyInput): void => {\n identity = normalizeIdentity(input);\n if (!captureAllowed() || identity === undefined) {\n return;\n }\n post(\n '/track',\n JSON.stringify({\n payload: {\n email: identity.email,\n firstName:\n typeof identity.traits?.['firstName'] === 'string'\n ? identity.traits['firstName']\n : undefined,\n lastName:\n typeof identity.traits?.['lastName'] === 'string'\n ? identity.traits['lastName']\n : undefined,\n profileId: identity.id,\n properties: {\n ...identity.traits,\n groupId: identity.groupId,\n groupName: identity.groupName,\n },\n },\n type: 'identify',\n }),\n 'application/json',\n );\n};\n\nexport const clearIdentity = (): void => {\n identity = undefined;\n};\n\nconst postProductAndSession = (\n name: string,\n props?: TrackProps,\n keepalive = false,\n): void => {\n const line = encodeProductEventLine({\n name,\n options: {\n attributes: props,\n groupId: identity?.groupId,\n sessionId: resolveSessionId(),\n userId: identity?.id,\n },\n serviceName: config?.serviceName ?? 'unknown',\n source: 'browser',\n });\n if (line === undefined) {\n return;\n }\n post('/events', encodeNdjson([line]), 'application/x-ndjson', keepalive);\n post(\n '/sessionEvents',\n `${JSON.stringify({\n attributes: line.attributes,\n message: line.name,\n session_id: line.session_id,\n timestamp: line.timestamp,\n type: 'custom',\n })}\\n`,\n 'application/x-ndjson',\n keepalive,\n );\n};\n\nconst drainQueue = (keepalive = false): void => {\n if (!captureAllowed()) {\n return;\n }\n const pending = queue;\n queue = [];\n for (const event of pending) {\n postProductAndSession(event.name, event.props, keepalive);\n }\n};\n\nexport const track = (name: string, props?: TrackProps): void => {\n if (!started || !consentGranted || !config?.clientId) {\n if (queue.length >= MAX_QUEUE) {\n queue.shift();\n }\n queue.push({ name, props });\n return;\n }\n postProductAndSession(name, props);\n};\n\nconst postProfileDelta = (\n type: 'increment' | 'decrement',\n property: string,\n value?: number,\n): void => {\n if (!captureAllowed() || identity === undefined) {\n return;\n }\n post(\n '/track',\n JSON.stringify({\n payload: {\n profileId: identity.id,\n property,\n value: value ?? 1,\n },\n type,\n }),\n 'application/json',\n );\n};\n\nexport const increment = (property: string, value?: number): void => {\n postProfileDelta('increment', property, value);\n};\n\nexport const decrement = (property: string, value?: number): void => {\n postProfileDelta('decrement', property, value);\n};\n\nexport const flushAnalytics = (keepalive = false): void => {\n drainQueue(keepalive);\n};\n","// A throwing host call, as a value.\n//\n// The SDK runs inside someone else's app, so it touches host APIs that throw\n// rather than return a failure: `Intl` in a locale-stripped build, `BigInt` on a\n// wire value that isn't numeric, `decodeURIComponent` on a literal `%`, a\n// `node:fs` read the sandbox refuses. Every one of those is best-effort — the\n// SDK degrades an attribute rather than breaking the host — and `Effect.try` is\n// what makes that an `Option` the caller has to answer for instead of a `catch`\n// block that quietly covers the next three statements too.\nimport { Effect, Option } from 'effect';\n\n/** Run a throwing synchronous call, `None` if it threw. */\nexport const trySync = <A>(thunk: () => A): Option.Option<A> =>\n Effect.runSync(Effect.option(Effect.try(thunk)));\n\n/** Run a throwing synchronous call, `undefined` if it threw. */\nexport const trySyncOrUndefined = <A>(thunk: () => A): A | undefined =>\n Option.getOrUndefined(trySync(thunk));\n","/**\n * Narrow optional globals for the DOM-free SDK build, which also runs in\n * Workers and Node.\n */\nimport { trySyncOrUndefined } from '../shared/try-sync.js';\nimport { SDK_VERSION } from '../version.js';\n\ninterface BrowserNavigator {\n readonly userAgent?: string;\n readonly language?: string;\n readonly onLine?: boolean;\n}\n\ninterface BrowserDocument {\n readonly visibilityState?: string;\n}\n\nexport const browserNavigator = (): BrowserNavigator | undefined =>\n (globalThis as { navigator?: BrowserNavigator }).navigator;\n\nexport const browserDocument = (): BrowserDocument | undefined =>\n (globalThis as { document?: BrowserDocument }).document;\n\n/** Resource attributes every browser preset sends: the SDK, the user agent, language and time zone. */\nexport const browserResourceAttributes = () => {\n const nav = browserNavigator();\n // A locale-stripped build throws from `DateTimeFormat` rather than reporting an unknown zone.\n const timezone =\n typeof Intl === 'undefined'\n ? undefined\n : trySyncOrUndefined(\n () => Intl.DateTimeFormat().resolvedOptions().timeZone,\n );\n return {\n // Semconv requires these of an SDK; one that is not OpenTelemetry's names its own package.\n 'telemetry.sdk.name': '@safaricom-mxl/effect-sdk',\n 'telemetry.sdk.language': 'webjs',\n 'telemetry.sdk.version': SDK_VERSION,\n // `user_agent.original` is the semconv key; `browser.user_agent` was deprecated in favour of it.\n ...(nav?.userAgent ? { 'user_agent.original': nav.userAgent } : undefined),\n ...(nav?.language ? { 'browser.language': nav.language } : undefined),\n // Not a semconv key, so it lives under `mxl.*` rather than semconv's `browser.*`.\n ...(timezone ? { 'mxl.browser.timezone': timezone } : undefined),\n };\n};\n","export function normalizeOtlpBaseUrl(url: string): string {\n const trimmed = url.replace(/\\/$/, '');\n if (trimmed.endsWith('/v1/traces') || trimmed.endsWith('/v1/logs')) {\n return trimmed.replace(/\\/v1\\/(traces|logs|metrics)$/, '');\n }\n return trimmed;\n}\n","export interface SignalState {\n disabledUntil: number;\n}\n\nexport const COOLDOWN_MS = 60_000;\n\nexport const makeSerializedFlush = <Args extends unknown[]>(\n flush: (...args: Args) => Promise<void>,\n): ((...args: Args) => Promise<void>) => {\n let pending: Promise<void> = Promise.resolve();\n return (...args: Args) => {\n pending = pending.then(\n () => flush(...args),\n () => flush(...args),\n );\n return pending;\n };\n};\n\nexport const guardFlush = <Args extends unknown[]>(\n prefix: string,\n flush: (...args: Args) => Promise<void>,\n state?: SignalState,\n): ((...args: Args) => Promise<void>) => {\n return async (...args: Args) => {\n if (state && Date.now() < state.disabledUntil) {\n return;\n }\n try {\n await flush(...args);\n } catch (error) {\n if (state) {\n state.disabledUntil = Date.now() + COOLDOWN_MS;\n }\n console.error(`${prefix} flush failed; cooling down 60s`, error);\n }\n };\n};\n\nexport const fetchTransport = async (input: {\n readonly body: string | Uint8Array;\n readonly headers: Record<string, string>;\n readonly keepalive?: boolean | undefined;\n readonly url: string;\n}): Promise<void> => {\n const body: BodyInit =\n typeof input.body === 'string' ? input.body : new Uint8Array(input.body);\n const response = await fetch(input.url, {\n body,\n headers: input.headers,\n keepalive: input.keepalive,\n method: 'POST',\n });\n if (!response.ok) {\n throw new Error(`POST ${input.url} → ${response.status}`);\n }\n};\n","// Span filtering + error classification options, shared by every preset\n// (`Mxl.layer`, `MxlFlush.make`, and the Cloudflare `make`) so they accept\n// the same options and classify a given span the same way.\n//\n// BOUNDARY: a span's failure can be any value, so error predicates take `unknown`\n// and `failureIdentifier` narrows it.\n\nimport type { Exit, Tracer } from 'effect';\nimport { Predicate } from 'effect';\n\n/** A finished span, as handed to the `dropSpan` predicate. */\nexport interface FinishedSpan {\n readonly name: string;\n readonly kind: Tracer.SpanKind;\n readonly attributes: ReadonlyMap<string, unknown>;\n readonly exit: Exit.Exit<unknown, unknown>;\n}\n\nexport interface MxlSpanOptions {\n /**\n * Span name prefixes to drop before OTLP export. Only the matching span is\n * dropped: its children still export (with a parent that never arrives). Use\n * `dropSpanSubtrees` to drop the children too.\n */\n readonly dropSpanNames?: ReadonlyArray<string> | undefined;\n /**\n * Span name prefixes whose span AND every descendant are dropped. The span is\n * started unsampled, so children inherit that and nothing under it exports,\n * whatever its name (DB queries, HTTP client calls, ...).\n *\n * Two side effects worth knowing before reaching for it: outgoing HTTP calls\n * under a dropped span send `traceparent` with the sampled flag off, so\n * downstream services that honour it drop their part of the trace too; and\n * errors inside the subtree never reach error tracking. Keep real work (e.g.\n * processing a job a poll found) out of the dropped span.\n */\n readonly dropSpanSubtrees?: ReadonlyArray<string> | undefined;\n /**\n * Called on each finished span; returning `true` drops it (children are not\n * affected). Use when a name prefix isn't enough, e.g. dropping only polls\n * that found nothing: `(span) => span.attributes.get(\"queue.empty\") === true`.\n */\n readonly dropSpan?: ((span: FinishedSpan) => boolean) | undefined;\n /**\n * Stable `_tag` / `Error.name` identifiers of expected failures (validation,\n * not-found, duplicate, ...). A span failing entirely with these exports as\n * status `Ok` with no `exception` event: still visible, never an error. A\n * failure wrapped in an `{ error: … }` envelope is matched on the body's\n * `_tag`. A server span that answered 5xx stays `Error` regardless.\n */\n readonly anticipatedErrorIdentifiers?: ReadonlyArray<string> | undefined;\n /** @deprecated Use `anticipatedErrorIdentifiers`. */\n readonly anticipatedErrorTags?: ReadonlyArray<string> | undefined;\n /**\n * Predicate form of `anticipatedErrorIdentifiers`, for failures a tag can't\n * single out (e.g. a driver error that is only expected for a duplicate key).\n * Either matching makes the failure anticipated.\n */\n readonly isAnticipatedError?: ((error: unknown) => boolean) | undefined;\n}\n\nexport type MapleSpanOptions = MxlSpanOptions;\n\n/** Internal input: sets are accepted wherever the public options take arrays. */\nexport interface SpanFilterInput {\n readonly dropSpanNames?: Iterable<string> | undefined;\n readonly dropSpanSubtrees?: Iterable<string> | undefined;\n readonly dropSpan?: ((span: FinishedSpan) => boolean) | undefined;\n readonly anticipatedErrorIdentifiers?: Iterable<string> | undefined;\n readonly anticipatedErrorTags?: Iterable<string> | undefined;\n readonly isAnticipatedError?: ((error: unknown) => boolean) | undefined;\n /**\n * Append each error's `[cause]` chain to `exception.stacktrace`, as Effect's\n * stock `OtlpTracer` does. Fingerprints hash the top stack frames, so a\n * preset keeps whatever it shipped with to avoid re-splitting error groups.\n */\n readonly includeCauseInStack?: boolean | undefined;\n}\n\nexport interface SpanFilter {\n readonly dropSubtree: ((name: string) => boolean) | undefined;\n readonly drop: ((span: FinishedSpan) => boolean) | undefined;\n readonly isAnticipated: ((error: unknown) => boolean) | undefined;\n readonly includeCauseInStack: boolean;\n}\n\nconst prefixMatcher = (\n prefixes: Iterable<string> | undefined,\n): ((name: string) => boolean) | undefined => {\n const list = prefixes === undefined ? [] : [...prefixes];\n return list.length > 0\n ? (name) => list.some((prefix) => name.startsWith(prefix))\n : undefined;\n};\n\n// A failure's stable identifier: its `_tag`, else its `Error.name`. An error\n// that crossed an HTTP boundary arrives as a decoded *body*, so an API that\n// wraps bodies in `{ error: … }` hands over a plain object with no identifier of\n// its own; unwrap one level, and only for the body's own tag.\nexport const failureIdentifier = (error: unknown): string | undefined => {\n if (Predicate.hasProperty(error, '_tag') && typeof error._tag === 'string')\n return error._tag;\n if (Predicate.hasProperty(error, 'name') && typeof error.name === 'string')\n return error.name;\n const body = Predicate.hasProperty(error, 'error') ? error.error : undefined;\n if (Predicate.hasProperty(body, '_tag') && typeof body._tag === 'string')\n return body._tag;\n return undefined;\n};\n\nexport const resolveSpanFilter = (input: SpanFilterInput = {}): SpanFilter => {\n const dropName = prefixMatcher(input.dropSpanNames);\n const dropPredicate = input.dropSpan;\n const drop =\n dropName !== undefined && dropPredicate !== undefined\n ? (span: FinishedSpan) => dropName(span.name) || dropPredicate(span)\n : dropName !== undefined\n ? (span: FinishedSpan) => dropName(span.name)\n : dropPredicate;\n\n const identifiers = new Set([\n ...(input.anticipatedErrorIdentifiers ?? []),\n ...(input.anticipatedErrorTags ?? []),\n ]);\n const byIdentifier =\n identifiers.size > 0\n ? (error: unknown) => {\n const identifier = failureIdentifier(error);\n return identifier !== undefined && identifiers.has(identifier);\n }\n : undefined;\n const byPredicate = input.isAnticipatedError;\n const isAnticipated =\n byIdentifier !== undefined && byPredicate !== undefined\n ? (error: unknown) => byIdentifier(error) || byPredicate(error)\n : (byIdentifier ?? byPredicate);\n\n return {\n dropSubtree: prefixMatcher(input.dropSpanSubtrees),\n drop,\n isAnticipated,\n includeCauseInStack: input.includeCauseInStack ?? false,\n };\n};\n","// Buffer-backed OTLP tracer (platform-agnostic)\n//\n// Pure Tracer that pushes OTLP-shaped spans into a caller-owned buffer. URL,\n// resource, and headers are NOT baked in here — the caller (the Cloudflare,\n// server, or client flushable preset) resolves them and POSTs the drained\n// buffer on `flush`, so the layer itself can be constructed without I/O.\nimport { Cause, Context, Exit, Layer, Option, Predicate, Tracer } from 'effect';\nimport * as ErrorReporter from 'effect/ErrorReporter';\nimport * as OtlpResource from 'effect/observability/OtlpResource';\nimport type { ExtractTag } from 'effect/Types';\nimport type { SpanFilter, SpanFilterInput } from './span-options.js';\nimport { resolveSpanFilter } from './span-options.js';\n\nexport interface CaptureExceptionOptions {\n /** Span name. Default `\"exception\"`. */\n readonly name?: string | undefined;\n /** Extra span attributes (e.g. the URL the error happened on). */\n readonly attributes?: Record<string, unknown> | undefined;\n}\n\nexport interface SpanBuffer {\n readonly tracerLayer: Layer.Layer<never>;\n /**\n * Record a thrown value that never passed through an Effect span.\n *\n * Everything else in this buffer arrives because an Effect *span* failed —\n * which means an error thrown outside Effect had no path here at all. In a\n * browser that is most of them: a React render crash caught by an error\n * boundary, a throw in an event handler, a rejected promise nobody awaited.\n *\n * The error is recorded as a one-off span carrying a `Die` cause, so it takes\n * the same road as every other failure: `makeOtlpSpan` gives it status\n * `Error` and an `exception` event with type/message/stacktrace, which is\n * exactly the shape `error_events_mv` fingerprints on. A `Die` (not a `Fail`)\n * because an uncaught throw is by definition not an anticipated failure —\n * that also keeps it clear of the `anticipatedErrorIdentifiers` filter, which\n * would otherwise let a caller silence real crashes by tag.\n *\n * BOUNDARY: a thrown value is unparsed by definition — JavaScript can throw\n * anything. `Cause.prettyErrors` narrows it on the way into the event.\n */\n readonly captureException: (\n error: unknown,\n options?: CaptureExceptionOptions,\n ) => void;\n readonly drain: () => Array<OtlpSpan>;\n readonly restore: (items: ReadonlyArray<OtlpSpan>) => void;\n readonly setDisabled: (value: boolean) => void;\n readonly size: () => number;\n}\n\nconst MAX_BUFFER = 10_000;\n\nexport interface SpanBufferOptions extends SpanFilterInput {\n /**\n * Called as each span starts. The returned check, run as it ends, says why the\n * host lost its connection in between (or `undefined` if it did not). A span that\n * failed with an HTTP transport error meanwhile (the client span and any caller that\n * passed the error up) exports as `Unset` with the reason in `mxl.connection_lost`:\n * a hidden, unloading or offline page cancelled the request, so nothing in the app failed.\n */\n readonly watchConnection?: (() => () => string | undefined) | undefined;\n}\n\n// Errors carrying Effect's `[ErrorReporter.ignore]` flag are benign by design —\n// Effect's own \"don't report this failure\" signal. The canonical case is\n// `HttpServerError { reason: RouteNotFound }` (unmatched routes → 404), which\n// would otherwise surface as an Error-status span. We key off the annotation\n// rather than concrete error tags so the check stays robust and HTTP-agnostic.\n// An anticipated identifier wins over the flag: Effect also flags\n// `HttpApiSchemaError` (request-decode 400s), which should export as `Ok`, not vanish.\nconst isIgnoredFailure = (\n error: unknown,\n anticipated: SpanFilter['isAnticipated'],\n): boolean =>\n Predicate.hasProperty(error, ErrorReporter.ignore) &&\n error[ErrorReporter.ignore] === true &&\n !(anticipated !== undefined && anticipated(error));\n\nconst isIgnoredExit = (\n exit: Exit.Exit<unknown, unknown>,\n anticipated: SpanFilter['isAnticipated'],\n): boolean => {\n if (exit._tag !== 'Failure') return false;\n if (exit.cause.reasons.some(Cause.isDieReason)) return false;\n const failures = exit.cause.reasons.filter(Cause.isFailReason);\n return (\n failures.length > 0 &&\n failures.every((reason) => isIgnoredFailure(reason.error, anticipated))\n );\n};\n\n/**\n * Turns a finished span into its OTLP shape, or `undefined` when it must not be\n * exported (unsampled, dropped, or an ignored failure).\n */\nexport const makeSpanEncoder = (filter: SpanFilter) => {\n const drop = filter.drop;\n return (\n span: SpanImpl,\n connectionLost?: () => string | undefined,\n ): OtlpSpan | undefined => {\n if (!span.sampled) return undefined;\n const status = span.status as ExtractTag<Tracer.SpanStatus, 'Ended'>;\n if (\n drop !== undefined &&\n drop({\n name: span.name,\n kind: span.kind,\n attributes: span.attributes,\n exit: status.exit,\n })\n )\n return undefined;\n if (isIgnoredExit(status.exit, filter.isAnticipated)) return undefined;\n return makeOtlpSpan(span, filter, connectionLost);\n };\n};\n\n/**\n * A Tracer whose finished spans go to `exportFn`. A span matching\n * `dropSpanSubtrees` starts unsampled, which its descendants inherit (Effect\n * only samples a child of a sampled parent), so the whole subtree is skipped.\n * Only ever forced to `false`: trace levels and incoming `00` headers win.\n */\nexport const makeMapleTracer = (\n filter: SpanFilter,\n exportFn: (span: SpanImpl, connectionLost?: () => string | undefined) => void,\n watchConnection?: SpanBufferOptions['watchConnection'],\n): Tracer.Tracer => {\n const dropSubtree = filter.dropSubtree;\n return Tracer.make({\n span(spanOptions) {\n const connectionLost = watchConnection?.();\n return makeSpan({\n ...spanOptions,\n sampled:\n spanOptions.sampled &&\n (dropSubtree === undefined || !dropSubtree(spanOptions.name)),\n status: { _tag: 'Started', startTime: spanOptions.startTime },\n attributes: new Map(),\n export: (span) => exportFn(span, connectionLost),\n });\n },\n });\n};\n\nexport const makeSpanBuffer = (options: SpanBufferOptions = {}): SpanBuffer => {\n let buffer: Array<OtlpSpan> = [];\n let disabled = false;\n const filter = resolveSpanFilter(options);\n const encode = makeSpanEncoder(filter);\n\n const push = (span: SpanImpl, connectionLost?: () => string | undefined) => {\n if (disabled) return;\n if (buffer.length >= MAX_BUFFER) return;\n const otlp = encode(span, connectionLost);\n if (otlp !== undefined) buffer.push(otlp);\n };\n\n // A browser can reject a request between two `pagehide` listeners, before the one noting\n // the unload has run. Such a transport failure is encoded a task later, or at the next\n // drain, so the loss is known by then.\n let unsettled: Array<readonly [SpanImpl, () => string | undefined]> = [];\n const settle = () => {\n const items = unsettled;\n unsettled = [];\n for (const [span, connectionLost] of items) push(span, connectionLost);\n };\n const exportFn = (\n span: SpanImpl,\n connectionLost?: () => string | undefined,\n ) => {\n if (disabled) return;\n if (\n connectionLost !== undefined &&\n connectionLost() === undefined &&\n isTransportFailure(span)\n ) {\n if (buffer.length + unsettled.length >= MAX_BUFFER) return;\n unsettled.push([span, connectionLost]);\n if (unsettled.length === 1) setTimeout(settle, 0);\n return;\n }\n push(span, connectionLost);\n };\n\n const tracer = makeMapleTracer(filter, exportFn, options.watchConnection);\n\n const captureException = (\n error: unknown,\n captureOptions: CaptureExceptionOptions = {},\n ): void => {\n if (disabled) return;\n const now = BigInt(Date.now()) * 1_000_000n;\n const span = makeSpan({\n name: captureOptions.name ?? 'exception',\n parent: Option.none(),\n annotations: Context.empty(),\n status: { _tag: 'Started', startTime: now },\n attributes: new Map(Object.entries(captureOptions.attributes ?? {})),\n links: [],\n sampled: true,\n kind: 'internal',\n export: exportFn,\n });\n span.end(now, Exit.failCause(Cause.die(error)));\n };\n\n return {\n tracerLayer: Layer.succeed(Tracer.Tracer, tracer),\n captureException,\n drain: () => {\n settle();\n const items = buffer;\n buffer = [];\n return items;\n },\n restore: (items) => {\n if (disabled || items.length === 0) return;\n buffer = [...items, ...buffer].slice(0, MAX_BUFFER);\n },\n setDisabled: (value) => {\n disabled = value;\n if (value) {\n buffer = [];\n unsettled = [];\n }\n },\n size: () => buffer.length + unsettled.length,\n };\n};\n\n// OTLP span construction (adapted from `effect/observability/OtlpTracer`)\n\nconst ATTR_EXCEPTION_TYPE = 'exception.type';\nconst ATTR_EXCEPTION_MESSAGE = 'exception.message';\nconst ATTR_EXCEPTION_STACKTRACE = 'exception.stacktrace';\n\nexport interface SpanImpl extends Tracer.Span {\n readonly export: (span: SpanImpl) => void;\n readonly attributes: Map<string, unknown>;\n readonly links: Array<Tracer.SpanLink>;\n readonly events: Array<\n [\n name: string,\n startTime: bigint,\n attributes: Record<string, unknown> | undefined,\n ]\n >;\n status: Tracer.SpanStatus;\n}\n\nconst SpanProto = {\n _tag: 'Span' as const,\n end(this: SpanImpl, endTime: bigint, exit: Exit.Exit<unknown, unknown>) {\n this.status = {\n _tag: 'Ended',\n startTime: this.status.startTime,\n endTime,\n exit,\n };\n this.export(this);\n },\n attribute(this: SpanImpl, key: string, value: unknown) {\n this.attributes.set(key, value);\n },\n event(\n this: SpanImpl,\n name: string,\n startTime: bigint,\n attributes?: Record<string, unknown>,\n ) {\n this.events.push([name, startTime, attributes]);\n },\n addLinks(this: SpanImpl, links: ReadonlyArray<Tracer.SpanLink>) {\n this.links.push(...links);\n },\n};\n\nconst makeSpan = (options: {\n readonly name: string;\n readonly parent: Option.Option<Tracer.AnySpan>;\n readonly annotations: Context.Context<never>;\n readonly status: Tracer.SpanStatus;\n readonly attributes: ReadonlyMap<string, unknown>;\n readonly links: ReadonlyArray<Tracer.SpanLink>;\n readonly sampled: boolean;\n readonly kind: Tracer.SpanKind;\n readonly export: (span: SpanImpl) => void;\n}): SpanImpl => {\n const self = Object.assign(Object.create(SpanProto), options) as SpanImpl;\n (self as { traceId: string }).traceId =\n self.parent._tag === 'Some' ? self.parent.value.traceId : generateId(32);\n (self as { spanId: string }).spanId = generateId(16);\n (self as { events: unknown[] }).events = [];\n return self;\n};\n\nconst generateId = (len: number): string => {\n const chars = '0123456789abcdef';\n let result = '';\n for (let i = 0; i < len; i++)\n result += chars[Math.floor(Math.random() * chars.length)];\n return result;\n};\n\n// A span whose failure is caused *entirely* by anticipated errors (no\n// defects/Die) records OTLP status `Ok` and emits no `exception` event.\nconst isFullyAnticipated = (\n cause: Cause.Cause<unknown>,\n isAnticipated: ((error: unknown) => boolean) | undefined,\n): boolean => {\n if (isAnticipated === undefined) return false;\n if (cause.reasons.some(Cause.isDieReason)) return false;\n const failErrors = cause.reasons\n .filter(Cause.isFailReason)\n .map((reason) => reason.error);\n return failErrors.length > 0 && failErrors.every(isAnticipated);\n};\n\n// OTEL HTTP semconv for SERVER spans: a 5xx response is an error even when the\n// handler rendered it as a plain response — exactly what the HTTP boundaries\n// (`HttpRouter.toWebHandler`, alchemy's Worker bridge) do with a defect, so the\n// span would otherwise reach the warehouse as `Ok` and the crash never reach\n// error tracking. A 4xx is a rejection the service handled and stays `Ok`.\nconst renderedServerError = (self: SpanImpl): number | undefined => {\n if (self.kind !== 'server') return undefined;\n const raw = self.attributes.get('http.response.status_code');\n const code =\n typeof raw === 'number'\n ? raw\n : typeof raw === 'string'\n ? Number(raw)\n : Number.NaN;\n return Number.isInteger(code) && code >= 500 ? code : undefined;\n};\n\n// Effect 4.0.2+ fails a 5xx server span itself, with an `HttpServerError` whose reason is\n// `ResponseError`. That names nothing the rendered 5xx did not, so it takes the same road. One\n// carrying a cause or description is a failed response write, a real error of its own.\nconst isStatusOnlyResponseError = (error: unknown): boolean =>\n Predicate.isTagged(error, 'ResponseError') &&\n (!Predicate.hasProperty(error, 'cause') || error.cause === undefined) &&\n (!Predicate.hasProperty(error, 'description') ||\n error.description === undefined);\n\nconst isResponseFailure = (exit: Exit.Exit<unknown, unknown>): boolean => {\n if (exit._tag === 'Success') return true;\n const [reason, ...rest] = exit.cause.reasons;\n return (\n rest.length === 0 &&\n reason !== undefined &&\n Cause.isFailReason(reason) &&\n Predicate.isTagged(reason.error, 'HttpServerError') &&\n Predicate.hasProperty(reason.error, 'reason') &&\n isStatusOnlyResponseError(reason.error.reason)\n );\n};\n\n// The single failure of a raw HTTP client span, when it is an Effect `HttpClientError`\n// with this reason. Anything carrying a defect or a second failure is a real error.\nconst httpClientFailureReason = (\n exit: Exit.Exit<unknown, unknown>,\n reasonTag: string,\n): unknown => {\n if (exit._tag === 'Success') return undefined;\n const [reason, ...rest] = exit.cause.reasons;\n if (rest.length > 0 || reason === undefined || !Cause.isFailReason(reason))\n return undefined;\n const error = reason.error;\n if (\n !Predicate.isTagged(error, 'HttpClientError') ||\n !Predicate.hasProperty(error, 'reason')\n )\n return undefined;\n return Predicate.isTagged(error.reason, reasonTag) ? error.reason : undefined;\n};\n\nconst isTransportFailure = (span: SpanImpl): boolean =>\n span.status._tag === 'Ended' &&\n httpClientFailureReason(span.status.exit, 'TransportError') !== undefined;\n\n// Effect ends every 4xx client span itself, failed with a synthetic `StatusCodeError`, before\n// the caller has seen the response. Whether the 4xx is a fault is the caller's to say: an\n// unhandled one fails the caller's span too, which carries its own exception.\nconst isClientStatus4xx = (\n self: SpanImpl,\n exit: Exit.Exit<unknown, unknown>,\n): boolean => {\n if (self.kind !== 'client') return false;\n const reason = httpClientFailureReason(exit, 'StatusCodeError');\n if (\n !Predicate.hasProperty(reason, 'response') ||\n !Predicate.hasProperty(reason.response, 'status')\n ) {\n return false;\n }\n const code = reason.response.status;\n return typeof code === 'number' && code >= 400 && code < 500;\n};\n\n// Semconv `error.type` for a failed span that has none: the HTTP status code when the response\n// was the failure, else the HttpClientError reason (`TransportError`) or the error's own name.\nconst errorTypeOf = (\n self: SpanImpl,\n exit: Exit.Exit<unknown, unknown>,\n): string => {\n const code = self.attributes.get('http.response.status_code');\n if (typeof code === 'number' && code >= 400) return String(code);\n if (exit._tag === 'Success') return '_OTHER';\n const [reason] = exit.cause.reasons;\n if (reason !== undefined && Cause.isFailReason(reason)) {\n const error = reason.error;\n if (\n Predicate.isTagged(error, 'HttpClientError') &&\n Predicate.hasProperty(error, 'reason')\n ) {\n const tag = Predicate.hasProperty(error.reason, '_tag')\n ? error.reason._tag\n : undefined;\n if (typeof tag === 'string') return tag;\n }\n }\n return Cause.prettyErrors(exit.cause)[0]?.name || '_OTHER';\n};\n\nconst makeOtlpSpan = (\n self: SpanImpl,\n filter: SpanFilter,\n connectionLost?: () => string | undefined,\n): OtlpSpan => {\n const status = self.status as ExtractTag<Tracer.SpanStatus, 'Ended'>;\n const attributes = OtlpResource.entriesToAttributes(\n self.attributes.entries(),\n );\n const events = self.events.map(([name, startTime, attrs]) => ({\n name,\n timeUnixNano: String(startTime),\n attributes: attrs\n ? OtlpResource.entriesToAttributes(Object.entries(attrs))\n : [],\n droppedAttributesCount: 0,\n }));\n\n let otelStatus: Status;\n const lostReason =\n connectionLost !== undefined &&\n httpClientFailureReason(status.exit, 'TransportError') !== undefined\n ? connectionLost()\n : undefined;\n const serverError = isResponseFailure(status.exit)\n ? renderedServerError(self)\n : undefined;\n if (serverError !== undefined) {\n const method = self.attributes.get('http.request.method');\n const path = self.attributes.get('url.path');\n const message =\n typeof method === 'string' && typeof path === 'string'\n ? `HTTP ${serverError} (${method} ${path})`\n : `HTTP ${serverError}`;\n otelStatus = { code: StatusCode.Error, message };\n // Only when nothing named the failure itself — relabelling a recorded exception would\n // collapse every such 5xx into one anonymous bucket in error tracking.\n if (!events.some((event) => event.name === 'exception')) {\n events.push({\n name: 'exception',\n timeUnixNano: String(status.endTime),\n droppedAttributesCount: 0,\n attributes: [\n {\n key: ATTR_EXCEPTION_TYPE,\n value: { stringValue: 'HttpServerErrorResponse' },\n },\n { key: ATTR_EXCEPTION_MESSAGE, value: { stringValue: message } },\n ],\n });\n }\n } else if (status.exit._tag === 'Success') {\n otelStatus = constOtelStatusSuccess;\n } else if (Cause.hasInterruptsOnly(status.exit.cause)) {\n // Cancelled, not failed. A status description is reserved for `Error`, so the attribute says it.\n otelStatus = constOtelStatusSuccess;\n attributes.push({ key: 'mxl.interrupted', value: { boolValue: true } });\n } else if (\n renderedServerError(self) === undefined &&\n isFullyAnticipated(status.exit.cause, filter.isAnticipated)\n ) {\n // Expected business outcome (4xx). Keep the span (latency / status code\n // stay visible) but don't flag it as an error or fingerprint it. A server\n // span that still answered 5xx is a real error, anticipated or not.\n otelStatus = constOtelStatusSuccess;\n } else if (isClientStatus4xx(self, status.exit)) {\n // Semconv keeps a 4xx client span `Error`, but without an `exception` event: error\n // tracking skips a 4xx span that carries none, so the issue is the caller's to open.\n otelStatus = {\n code: StatusCode.Error,\n message: Cause.prettyErrors(status.exit.cause)[0]?.message ?? '',\n };\n } else if (lostReason !== undefined) {\n otelStatus = { code: StatusCode.Unset };\n attributes.push({\n key: 'mxl.connection_lost',\n value: { stringValue: lostReason },\n });\n } else {\n const errors = Cause.prettyErrors(status.exit.cause, {\n includeCauseInStack: filter.includeCauseInStack,\n });\n otelStatus = { code: StatusCode.Error };\n const firstError = errors[0];\n if (firstError) {\n otelStatus.message = firstError.message;\n for (const error of errors) {\n events.push({\n name: 'exception',\n timeUnixNano: String(status.endTime),\n droppedAttributesCount: 0,\n attributes: [\n { key: ATTR_EXCEPTION_TYPE, value: { stringValue: error.name } },\n {\n key: ATTR_EXCEPTION_MESSAGE,\n value: { stringValue: error.message },\n },\n {\n key: ATTR_EXCEPTION_STACKTRACE,\n value: { stringValue: error.stack ?? 'No stack trace available' },\n },\n ],\n });\n }\n }\n }\n\n if (\n otelStatus.code === StatusCode.Error &&\n !self.attributes.has('error.type')\n ) {\n attributes.push({\n key: 'error.type',\n value: { stringValue: errorTypeOf(self, status.exit) },\n });\n }\n\n return {\n traceId: self.traceId,\n spanId: self.spanId,\n parentSpanId:\n self.parent._tag === 'Some' ? self.parent.value.spanId : undefined,\n name: self.name,\n kind: SpanKind[self.kind],\n startTimeUnixNano: String(status.startTime),\n endTimeUnixNano: String(status.endTime),\n attributes,\n droppedAttributesCount: 0,\n events,\n droppedEventsCount: 0,\n status: otelStatus,\n links: self.links.map((link) => ({\n traceId: link.span.traceId,\n spanId: link.span.spanId,\n attributes: OtlpResource.entriesToAttributes(\n Object.entries(link.attributes),\n ),\n droppedAttributesCount: 0,\n })),\n droppedLinksCount: 0,\n };\n};\n\n// OTLP wire types\n\nexport interface OtlpSpan {\n readonly traceId: string;\n readonly spanId: string;\n readonly parentSpanId: string | undefined;\n readonly name: string;\n readonly kind: number;\n readonly startTimeUnixNano: string;\n readonly endTimeUnixNano: string;\n readonly attributes: Array<OtlpResource.KeyValue>;\n readonly droppedAttributesCount: number;\n readonly events: Array<Event>;\n readonly droppedEventsCount: number;\n readonly status: Status;\n readonly links: Array<Link>;\n readonly droppedLinksCount: number;\n}\ninterface Event {\n readonly attributes: Array<OtlpResource.KeyValue>;\n readonly name: string;\n readonly timeUnixNano: string;\n readonly droppedAttributesCount: number;\n}\ninterface Link {\n readonly attributes: Array<OtlpResource.KeyValue>;\n readonly spanId: string;\n readonly traceId: string;\n readonly droppedAttributesCount: number;\n}\ninterface Status {\n readonly code: StatusCode;\n message?: string;\n}\n\nconst StatusCode = {\n Unset: 0,\n Ok: 1,\n Error: 2,\n} as const;\ntype StatusCode = (typeof StatusCode)[keyof typeof StatusCode];\n\nconst SpanKind = {\n unspecified: 0,\n internal: 1,\n server: 2,\n client: 3,\n producer: 4,\n consumer: 5,\n} as const;\n\nconst constOtelStatusSuccess: Status = { code: StatusCode.Ok };\n","import { SDK_NAME, SDK_VERSION } from '../version.js';\nimport { getCurrentIdentity, getCurrentSessionId } from './analytics.js';\n\nexport interface ClientReplayConfig {\n readonly canvasFps?: number | undefined;\n readonly enabled?: boolean | undefined;\n readonly maskAllInputs?: boolean | undefined;\n readonly maskAllText?: boolean | undefined;\n readonly sampleRate?: number | undefined;\n}\n\nexport interface ReplayRecordOptions {\n readonly maskAllInputs?: boolean;\n readonly maskTextSelector?: string;\n readonly recordCanvas?: boolean;\n readonly sampling?: { readonly canvas: number };\n}\n\nexport const replayRecordOptions = (\n replay: ClientReplayConfig | undefined,\n): ReplayRecordOptions => ({\n maskAllInputs: replay?.maskAllInputs ?? true,\n maskTextSelector: replay?.maskAllText === true ? '*' : undefined,\n ...(replay?.canvasFps && replay.canvasFps > 0 && replay.maskAllText !== true\n ? { recordCanvas: true, sampling: { canvas: replay.canvasFps } }\n : {}),\n});\n\nexport interface ReplayChunkMeta {\n readonly chunkSeq: number;\n readonly durationMs: number;\n readonly eventCount: number;\n readonly isCheckpoint: boolean;\n readonly sessionId: string;\n}\n\ntype StopReplay = () => void;\n\nlet stopRecorder: StopReplay | undefined;\nlet chunkSeq = 0;\n\nconst ingestHeaders = (\n clientId: string,\n apiKey: string | undefined,\n contentType: string,\n): Record<string, string> => {\n const headers: Record<string, string> = {\n 'content-type': contentType,\n 'mxl-client-id': clientId,\n 'mxl-sdk-name': SDK_NAME,\n 'mxl-sdk-version': SDK_VERSION,\n };\n if (apiKey) {\n headers['mxl-api-key'] = apiKey;\n }\n return headers;\n};\n\nexport const isWebSdkPresent = (): boolean => {\n const global = globalThis as {\n MxlWebSdk?: unknown;\n __MXL_REPLAY_SESSION__?: unknown;\n __MXL_WEB_SDK__?: unknown;\n };\n return Boolean(\n global.__MXL_WEB_SDK__ || global.MxlWebSdk || global.__MXL_REPLAY_SESSION__,\n );\n};\n\nexport const shouldRecordReplay = (\n replay: ClientReplayConfig | undefined,\n): boolean => {\n if (isWebSdkPresent()) {\n return false;\n }\n if (replay?.enabled === false) {\n return false;\n }\n const sampleRate = replay?.sampleRate ?? 1;\n return sampleRate >= 1 || Math.random() < sampleRate;\n};\n\nexport const sessionMetaRow = (serviceName: string) => {\n const identity = getCurrentIdentity();\n const started = new Date();\n return {\n service_name: serviceName,\n session_id: getCurrentSessionId(),\n start_time: started.toISOString().replace('T', ' ').replace('Z', ''),\n status: 'active',\n url_initial:\n typeof globalThis.location?.href === 'string'\n ? globalThis.location.href\n : '',\n user_agent:\n typeof globalThis.navigator?.userAgent === 'string'\n ? globalThis.navigator.userAgent\n : '',\n user_id: identity?.id ?? '',\n version: 1,\n };\n};\n\nexport const postSessionReplayMeta = (\n ingestUrl: string,\n clientId: string,\n serviceName: string,\n apiKey?: string,\n): void => {\n try {\n void fetch(`${ingestUrl.replace(/\\/$/, '')}/sessionReplays/meta`, {\n body: `${JSON.stringify(sessionMetaRow(serviceName))}\\n`,\n headers: ingestHeaders(clientId, apiKey, 'application/x-ndjson'),\n keepalive: true,\n method: 'POST',\n });\n } catch {\n // Replay must never throw into the host app.\n }\n};\n\nexport const postSessionReplayBlob = (\n ingestUrl: string,\n clientId: string,\n meta: ReplayChunkMeta,\n body: Uint8Array,\n apiKey?: string,\n): void => {\n try {\n void fetch(`${ingestUrl.replace(/\\/$/, '')}/sessionReplays/blob`, {\n body: body as unknown as Blob,\n headers: {\n ...ingestHeaders(clientId, apiKey, 'application/octet-stream'),\n 'x-mxl-chunk-seq': String(meta.chunkSeq),\n 'x-mxl-duration-ms': String(meta.durationMs),\n 'x-mxl-event-count': String(meta.eventCount),\n 'x-mxl-is-checkpoint': meta.isCheckpoint ? '1' : '0',\n 'x-mxl-session-id': meta.sessionId,\n },\n keepalive: true,\n method: 'POST',\n });\n } catch {\n // Replay must never throw into the host app.\n }\n};\n\nconst gzipJson = async (value: unknown): Promise<Uint8Array | undefined> => {\n if (typeof CompressionStream === 'undefined') {\n return undefined;\n }\n const encoded = new TextEncoder().encode(JSON.stringify(value));\n const stream = new Blob([encoded])\n .stream()\n .pipeThrough(new CompressionStream('gzip'));\n return new Uint8Array(await new Response(stream).arrayBuffer());\n};\n\nexport const stopReplay = (): void => {\n stopRecorder?.();\n stopRecorder = undefined;\n};\n\nexport const startReplay = async (config: {\n readonly apiKey?: string | undefined;\n readonly clientId: string;\n readonly ingestUrl: string;\n readonly replay?: ClientReplayConfig | undefined;\n readonly serviceName: string;\n}): Promise<void> => {\n if (!shouldRecordReplay(config.replay)) {\n return;\n }\n stopReplay();\n chunkSeq = 0;\n postSessionReplayMeta(\n config.ingestUrl,\n config.clientId,\n config.serviceName,\n config.apiKey,\n );\n try {\n const specifier = 'rrweb';\n const rrweb = (await import(/* @vite-ignore */ specifier)) as {\n record?: (\n options: ReplayRecordOptions & { emit: (event: unknown) => void },\n ) => (() => void) | undefined;\n };\n if (typeof rrweb.record !== 'function') {\n return;\n }\n const events: unknown[] = [];\n const startedAt = Date.now();\n const stop = rrweb.record({\n emit: (event) => {\n events.push(event);\n },\n ...replayRecordOptions(config.replay),\n });\n stopRecorder = () => {\n stop?.();\n if (events.length === 0) {\n return;\n }\n void gzipJson(events).then((gzipped) => {\n if (!gzipped) {\n return;\n }\n postSessionReplayBlob(\n config.ingestUrl,\n config.clientId,\n {\n chunkSeq: chunkSeq++,\n durationMs: Date.now() - startedAt,\n eventCount: events.length,\n isCheckpoint: true,\n sessionId: getCurrentSessionId(),\n },\n gzipped,\n config.apiKey,\n );\n });\n };\n } catch {\n // rrweb is optional; metadata rows still make the session visible.\n }\n};\n","import * as WebSdk from '@effect/opentelemetry/WebSdk';\nimport type { Context } from '@opentelemetry/api';\nimport { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http';\nimport type {\n ReadableSpan,\n SpanProcessor,\n} from '@opentelemetry/sdk-trace-base';\nimport { BatchSpanProcessor } from '@opentelemetry/sdk-trace-base';\nimport { Effect, Layer } from 'effect';\nimport { normalizeOtlpBaseUrl } from '../server/otlp.js';\nimport type { IdentifyInput, PrivacyOptions, TrackProps } from './analytics.js';\nimport {\n clearIdentity as clearIdentitySync,\n configureBrowserAnalytics,\n getCurrentUserId,\n identify as identifySync,\n track as trackSync,\n} from './analytics.js';\nimport { browserResourceAttributes } from './browser-globals.js';\nimport type { ClientReplayConfig } from './replay.js';\nimport { startReplay } from './replay.js';\n\nexport interface MxlBrowserConfig {\n readonly apiKey?: string | undefined;\n readonly attributes?: Record<string, string> | undefined;\n readonly clientId?: string | undefined;\n readonly disabled?: boolean | undefined;\n readonly endpoint?: string | undefined;\n readonly environment?: string | undefined;\n readonly headers?: Record<string, string> | undefined;\n readonly ingestUrl?: string | undefined;\n readonly privacy?: PrivacyOptions | undefined;\n readonly replay?: ClientReplayConfig | undefined;\n readonly serviceName?: string | undefined;\n readonly serviceNamespace?: string | undefined;\n readonly serviceVersion?: string | undefined;\n}\n\nexport const stampUserIdOnSpan = (span: {\n setAttribute: (key: string, value: string) => unknown;\n}): void => {\n const userId = getCurrentUserId();\n if (userId) {\n span.setAttribute('user.id', userId);\n }\n};\n\nclass UserIdSpanProcessor implements SpanProcessor {\n constructor(private readonly inner: SpanProcessor) {}\n\n forceFlush(): Promise<void> {\n return this.inner.forceFlush();\n }\n\n onEnd(span: ReadableSpan): void {\n this.inner.onEnd(span);\n }\n\n onStart(\n span: Parameters<SpanProcessor['onStart']>[0],\n parentContext: Context,\n ): void {\n stampUserIdOnSpan(span);\n this.inner.onStart(span, parentContext);\n }\n\n shutdown(): Promise<void> {\n return this.inner.shutdown();\n }\n}\n\nfunction resolveBrowserEndpoint(config: MxlBrowserConfig): string | undefined {\n if (config.disabled) {\n return undefined;\n }\n if (config.endpoint && config.endpoint.length > 0) {\n return normalizeOtlpBaseUrl(config.endpoint);\n }\n return undefined;\n}\n\n/**\n * Browser Effect observability layer backed by OpenTelemetry WebSdk.\n *\n * Returns a no-op layer when `disabled` is true or no OTLP endpoint is configured.\n */\nexport const layer = (config: MxlBrowserConfig = {}) => {\n if (config.clientId) {\n configureBrowserAnalytics({\n apiKey: config.apiKey,\n clientId: config.clientId,\n ingestUrl: config.ingestUrl,\n privacy: config.privacy,\n serviceName: config.serviceName,\n });\n void startReplay({\n apiKey: config.apiKey,\n clientId: config.clientId,\n ingestUrl: config.ingestUrl ?? 'http://127.0.0.1:8000',\n replay: config.replay,\n serviceName: config.serviceName ?? 'unknown',\n });\n }\n const endpoint = resolveBrowserEndpoint(config);\n if (!endpoint) {\n return Layer.empty;\n }\n\n const attributes: Record<string, string> = {\n ...browserResourceAttributes(),\n 'mxl.sdk.type': 'browser',\n ...(config.environment\n ? {\n 'deployment.environment': config.environment,\n 'deployment.environment.name': config.environment,\n }\n : {}),\n ...(config.serviceNamespace\n ? { 'service.namespace': config.serviceNamespace }\n : {}),\n ...config.attributes,\n };\n\n // WebSdk.layer installs OtelTracer.make, which already binds Otel.context.\n return WebSdk.layer(() => ({\n resource: {\n attributes,\n serviceName: config.serviceName ?? 'unknown',\n serviceVersion: config.serviceVersion,\n },\n spanProcessor: new UserIdSpanProcessor(\n new BatchSpanProcessor(\n new OTLPTraceExporter({\n headers: config.headers,\n url: `${endpoint}/v1/traces`,\n }),\n ),\n ),\n }));\n};\n\nexport const identify = (input?: IdentifyInput) =>\n Effect.sync(() => identifySync(input));\n\nexport const clearIdentity = Effect.sync(() => clearIdentitySync());\n\nexport const track = (name: string, props?: TrackProps) =>\n Effect.sync(() => trackSync(name, props));\n","import type { BatchSpanProcessor } from '@opentelemetry/sdk-trace-base';\nimport type { Layer } from 'effect';\nimport { normalizeOtlpBaseUrl } from '../server/otlp.js';\nimport {\n fetchTransport,\n guardFlush,\n makeSerializedFlush,\n} from '../shared/flush-core.js';\nimport type {\n CaptureExceptionOptions,\n OtlpSpan,\n SpanBuffer,\n} from '../shared/flushable-tracer.js';\nimport { makeSpanBuffer } from '../shared/flushable-tracer.js';\nimport type { MxlSpanOptions } from '../shared/span-options.js';\nimport { flushAnalytics, track } from './analytics.js';\nimport { browserResourceAttributes } from './browser-globals.js';\nimport type { MxlBrowserConfig } from './layer.js';\nimport { layer as browserLayer } from './layer.js';\nimport { stopReplay } from './replay.js';\n\nexport interface MxlBrowserFlushableConfig\n extends MxlBrowserConfig, MxlSpanOptions {\n readonly autoFlushInterval?: number | false | undefined;\n readonly captureGlobalErrors?: boolean | undefined;\n readonly flushOnUnload?: boolean | undefined;\n}\n\nexport interface FlushableTelemetry {\n readonly captureException: (\n error: unknown,\n options?: CaptureExceptionOptions,\n ) => void;\n readonly dispose: () => Promise<void>;\n readonly flush: () => Promise<void>;\n readonly layer: Layer.Layer<never>;\n}\n\nconst processors = new WeakMap<FlushableTelemetry, BatchSpanProcessor>();\nconst DEFAULT_AUTO_FLUSH_MS = 5_000;\n\nexport const attachProcessor = (\n telemetry: FlushableTelemetry,\n processor: BatchSpanProcessor,\n): void => {\n processors.set(telemetry, processor);\n};\n\nconst otlpAnyValue = (value: unknown): unknown => {\n if (Array.isArray(value)) {\n return { arrayValue: { values: value.map(otlpAnyValue) } };\n }\n switch (typeof value) {\n case 'string':\n return { stringValue: value };\n case 'boolean':\n return { boolValue: value };\n case 'number':\n return Number.isInteger(value)\n ? { intValue: value }\n : { doubleValue: value };\n case 'bigint':\n return { intValue: Number(value) };\n default:\n return { stringValue: String(value) };\n }\n};\n\nconst makeTracesBody = (input: {\n readonly attributes: Record<string, unknown>;\n readonly serviceName: string;\n readonly serviceVersion: string | undefined;\n readonly spans: ReadonlyArray<OtlpSpan>;\n}) => {\n const attributes = Object.entries(input.attributes).map(([key, value]) => ({\n key,\n value: otlpAnyValue(value),\n }));\n attributes.push({\n key: 'service.name',\n value: { stringValue: input.serviceName },\n });\n if (input.serviceVersion) {\n attributes.push({\n key: 'service.version',\n value: { stringValue: input.serviceVersion },\n });\n }\n return {\n resourceSpans: [\n {\n resource: { attributes, droppedAttributesCount: 0 },\n scopeSpans: [\n {\n scope: { name: input.serviceName },\n spans: input.spans,\n },\n ],\n },\n ],\n };\n};\n\nconst resolveFlushableEndpoint = (\n config: MxlBrowserFlushableConfig,\n): string | undefined => {\n if (config.disabled) return undefined;\n if (config.endpoint && config.endpoint.length > 0) {\n return normalizeOtlpBaseUrl(config.endpoint);\n }\n return undefined;\n};\n\nexport const make = (\n config: MxlBrowserFlushableConfig = {},\n): FlushableTelemetry => {\n const endpoint = resolveFlushableEndpoint(config);\n const spanBuffer: SpanBuffer | undefined = endpoint\n ? makeSpanBuffer(config)\n : undefined;\n // Span-buffer path owns the tracer. Still run analytics/replay side effects.\n const layer = spanBuffer ? spanBuffer.tracerLayer : browserLayer(config);\n if (spanBuffer && config.clientId) {\n browserLayer({ ...config, endpoint: undefined });\n }\n\n const resourceAttributes: Record<string, unknown> = {\n ...browserResourceAttributes(),\n 'mxl.sdk.type': 'browser',\n ...(config.environment\n ? {\n 'deployment.environment': config.environment,\n 'deployment.environment.name': config.environment,\n }\n : {}),\n ...(config.serviceNamespace\n ? { 'service.namespace': config.serviceNamespace }\n : {}),\n ...config.attributes,\n };\n\n const state = { disabledUntil: 0 };\n const listeners: Array<() => void> = [];\n\n const telemetry: FlushableTelemetry = {\n captureException: (error, options) => {\n if (spanBuffer) {\n spanBuffer.captureException(error, options);\n }\n if (config.clientId) {\n track(options?.name ?? 'uncaught_error', {\n ...options?.attributes,\n message: error instanceof Error ? error.message : String(error),\n });\n }\n },\n dispose: async () => {\n for (const stop of listeners) {\n stop();\n }\n listeners.length = 0;\n stopReplay();\n await telemetry.flush();\n },\n flush: makeSerializedFlush(\n guardFlush(\n '[MxlFlush]',\n async () => {\n flushAnalytics(true);\n await processors.get(telemetry)?.forceFlush();\n if (spanBuffer && endpoint) {\n const spans = spanBuffer.drain();\n if (spans.length > 0) {\n await fetchTransport({\n body: JSON.stringify(\n makeTracesBody({\n attributes: resourceAttributes,\n serviceName: config.serviceName ?? 'unknown',\n serviceVersion: config.serviceVersion,\n spans,\n }),\n ),\n headers: {\n 'content-type': 'application/json',\n ...config.headers,\n },\n keepalive: true,\n url: `${endpoint}/v1/traces`,\n });\n }\n }\n },\n state,\n ),\n ),\n layer,\n };\n\n const intervalMs =\n config.autoFlushInterval === undefined\n ? DEFAULT_AUTO_FLUSH_MS\n : config.autoFlushInterval === false\n ? 0\n : config.autoFlushInterval;\n if (intervalMs > 0) {\n const timer = setInterval(() => {\n void telemetry.flush();\n }, intervalMs);\n timer.unref?.();\n listeners.push(() => {\n clearInterval(timer);\n });\n }\n\n const documentRef = (\n globalThis as {\n document?: {\n addEventListener: (type: string, listener: () => void) => void;\n removeEventListener: (type: string, listener: () => void) => void;\n visibilityState?: string;\n };\n }\n ).document;\n\n if (config.flushOnUnload !== false) {\n const onHidden = () => {\n void telemetry.flush();\n };\n if (documentRef) {\n const onVisibilityChange = () => {\n if (documentRef.visibilityState === 'hidden') {\n onHidden();\n }\n };\n documentRef.addEventListener('visibilitychange', onVisibilityChange);\n listeners.push(() => {\n documentRef.removeEventListener('visibilitychange', onVisibilityChange);\n });\n }\n if (typeof globalThis.addEventListener === 'function') {\n globalThis.addEventListener('pagehide', onHidden);\n listeners.push(() => {\n globalThis.removeEventListener('pagehide', onHidden);\n });\n }\n }\n\n if (\n config.captureGlobalErrors !== false &&\n typeof globalThis.addEventListener === 'function'\n ) {\n const onError = (event: Event) => {\n const record = event as { error?: unknown; reason?: unknown };\n telemetry.captureException(record.error ?? record.reason ?? event);\n void telemetry.flush();\n };\n globalThis.addEventListener('error', onError);\n globalThis.addEventListener('unhandledrejection', onError);\n listeners.push(() => {\n globalThis.removeEventListener('error', onError);\n globalThis.removeEventListener('unhandledrejection', onError);\n });\n }\n\n return telemetry;\n};\n"],"mappings":"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"}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { Effect, Exit, Layer, Tracer } from "effect";
|
|
2
|
+
import "effect/observability/OtlpResource";
|
|
3
|
+
import { BatchSpanProcessor } from "@opentelemetry/sdk-trace-base";
|
|
4
|
+
/** A finished span, as handed to the `dropSpan` predicate. */
|
|
5
|
+
interface FinishedSpan {
|
|
6
|
+
readonly name: string;
|
|
7
|
+
readonly kind: Tracer.SpanKind;
|
|
8
|
+
readonly attributes: ReadonlyMap<string, unknown>;
|
|
9
|
+
readonly exit: Exit.Exit<unknown, unknown>;
|
|
10
|
+
}
|
|
11
|
+
interface MxlSpanOptions {
|
|
12
|
+
/**
|
|
13
|
+
* Span name prefixes to drop before OTLP export. Only the matching span is
|
|
14
|
+
* dropped: its children still export (with a parent that never arrives). Use
|
|
15
|
+
* `dropSpanSubtrees` to drop the children too.
|
|
16
|
+
*/
|
|
17
|
+
readonly dropSpanNames?: ReadonlyArray<string> | undefined;
|
|
18
|
+
/**
|
|
19
|
+
* Span name prefixes whose span AND every descendant are dropped. The span is
|
|
20
|
+
* started unsampled, so children inherit that and nothing under it exports,
|
|
21
|
+
* whatever its name (DB queries, HTTP client calls, ...).
|
|
22
|
+
*
|
|
23
|
+
* Two side effects worth knowing before reaching for it: outgoing HTTP calls
|
|
24
|
+
* under a dropped span send `traceparent` with the sampled flag off, so
|
|
25
|
+
* downstream services that honour it drop their part of the trace too; and
|
|
26
|
+
* errors inside the subtree never reach error tracking. Keep real work (e.g.
|
|
27
|
+
* processing a job a poll found) out of the dropped span.
|
|
28
|
+
*/
|
|
29
|
+
readonly dropSpanSubtrees?: ReadonlyArray<string> | undefined;
|
|
30
|
+
/**
|
|
31
|
+
* Called on each finished span; returning `true` drops it (children are not
|
|
32
|
+
* affected). Use when a name prefix isn't enough, e.g. dropping only polls
|
|
33
|
+
* that found nothing: `(span) => span.attributes.get("queue.empty") === true`.
|
|
34
|
+
*/
|
|
35
|
+
readonly dropSpan?: ((span: FinishedSpan) => boolean) | undefined;
|
|
36
|
+
/**
|
|
37
|
+
* Stable `_tag` / `Error.name` identifiers of expected failures (validation,
|
|
38
|
+
* not-found, duplicate, ...). A span failing entirely with these exports as
|
|
39
|
+
* status `Ok` with no `exception` event: still visible, never an error. A
|
|
40
|
+
* failure wrapped in an `{ error: … }` envelope is matched on the body's
|
|
41
|
+
* `_tag`. A server span that answered 5xx stays `Error` regardless.
|
|
42
|
+
*/
|
|
43
|
+
readonly anticipatedErrorIdentifiers?: ReadonlyArray<string> | undefined;
|
|
44
|
+
/** @deprecated Use `anticipatedErrorIdentifiers`. */
|
|
45
|
+
readonly anticipatedErrorTags?: ReadonlyArray<string> | undefined;
|
|
46
|
+
/**
|
|
47
|
+
* Predicate form of `anticipatedErrorIdentifiers`, for failures a tag can't
|
|
48
|
+
* single out (e.g. a driver error that is only expected for a duplicate key).
|
|
49
|
+
* Either matching makes the failure anticipated.
|
|
50
|
+
*/
|
|
51
|
+
readonly isAnticipatedError?: ((error: unknown) => boolean) | undefined;
|
|
52
|
+
}
|
|
53
|
+
type MapleSpanOptions = MxlSpanOptions;
|
|
54
|
+
interface MapleIdentity {
|
|
55
|
+
readonly email?: string | undefined;
|
|
56
|
+
readonly groupId?: string | undefined;
|
|
57
|
+
readonly groupName?: string | undefined;
|
|
58
|
+
readonly id: string;
|
|
59
|
+
readonly traits?: Record<string, unknown> | undefined;
|
|
60
|
+
}
|
|
61
|
+
type IdentifyInput = string | MapleIdentity | null | undefined;
|
|
62
|
+
interface TrackProps {
|
|
63
|
+
readonly [key: string]: unknown;
|
|
64
|
+
}
|
|
65
|
+
interface PrivacyOptions {
|
|
66
|
+
readonly requireConsent?: boolean | undefined;
|
|
67
|
+
}
|
|
68
|
+
declare const setConsent: (granted: boolean) => void;
|
|
69
|
+
declare const identify$1: (input?: IdentifyInput) => void;
|
|
70
|
+
declare const clearIdentity$1: () => void;
|
|
71
|
+
declare const track$1: (name: string, props?: TrackProps) => void;
|
|
72
|
+
declare const increment: (property: string, value?: number) => void;
|
|
73
|
+
declare const decrement: (property: string, value?: number) => void;
|
|
74
|
+
interface CaptureExceptionOptions {
|
|
75
|
+
/** Span name. Default `"exception"`. */
|
|
76
|
+
readonly name?: string | undefined;
|
|
77
|
+
/** Extra span attributes (e.g. the URL the error happened on). */
|
|
78
|
+
readonly attributes?: Record<string, unknown> | undefined;
|
|
79
|
+
}
|
|
80
|
+
interface ClientReplayConfig {
|
|
81
|
+
readonly canvasFps?: number | undefined;
|
|
82
|
+
readonly enabled?: boolean | undefined;
|
|
83
|
+
readonly maskAllInputs?: boolean | undefined;
|
|
84
|
+
readonly maskAllText?: boolean | undefined;
|
|
85
|
+
readonly sampleRate?: number | undefined;
|
|
86
|
+
}
|
|
87
|
+
interface ReplayRecordOptions {
|
|
88
|
+
readonly maskAllInputs?: boolean;
|
|
89
|
+
readonly maskTextSelector?: string;
|
|
90
|
+
readonly recordCanvas?: boolean;
|
|
91
|
+
readonly sampling?: {
|
|
92
|
+
readonly canvas: number;
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
declare const replayRecordOptions: (replay: ClientReplayConfig | undefined) => ReplayRecordOptions;
|
|
96
|
+
declare namespace layer_d_exports {
|
|
97
|
+
export { MxlBrowserConfig, clearIdentity, identify, layer, stampUserIdOnSpan, track };
|
|
98
|
+
}
|
|
99
|
+
interface MxlBrowserConfig {
|
|
100
|
+
readonly apiKey?: string | undefined;
|
|
101
|
+
readonly attributes?: Record<string, string> | undefined;
|
|
102
|
+
readonly clientId?: string | undefined;
|
|
103
|
+
readonly disabled?: boolean | undefined;
|
|
104
|
+
readonly endpoint?: string | undefined;
|
|
105
|
+
readonly environment?: string | undefined;
|
|
106
|
+
readonly headers?: Record<string, string> | undefined;
|
|
107
|
+
readonly ingestUrl?: string | undefined;
|
|
108
|
+
readonly privacy?: PrivacyOptions | undefined;
|
|
109
|
+
readonly replay?: ClientReplayConfig | undefined;
|
|
110
|
+
readonly serviceName?: string | undefined;
|
|
111
|
+
readonly serviceNamespace?: string | undefined;
|
|
112
|
+
readonly serviceVersion?: string | undefined;
|
|
113
|
+
}
|
|
114
|
+
declare const stampUserIdOnSpan: (span: {
|
|
115
|
+
setAttribute: (key: string, value: string) => unknown;
|
|
116
|
+
}) => void;
|
|
117
|
+
/**
|
|
118
|
+
* Browser Effect observability layer backed by OpenTelemetry WebSdk.
|
|
119
|
+
*
|
|
120
|
+
* Returns a no-op layer when `disabled` is true or no OTLP endpoint is configured.
|
|
121
|
+
*/
|
|
122
|
+
declare const layer: (config?: MxlBrowserConfig) => Layer.Layer<never, never, never>;
|
|
123
|
+
declare const identify: (input?: IdentifyInput) => Effect.Effect<void, never, never>;
|
|
124
|
+
declare const clearIdentity: Effect.Effect<void, never, never>;
|
|
125
|
+
declare const track: (name: string, props?: TrackProps) => Effect.Effect<void, never, never>;
|
|
126
|
+
declare namespace flushable_d_exports {
|
|
127
|
+
export { FlushableTelemetry, MxlBrowserFlushableConfig, attachProcessor, make };
|
|
128
|
+
}
|
|
129
|
+
interface MxlBrowserFlushableConfig extends MxlBrowserConfig, MxlSpanOptions {
|
|
130
|
+
readonly autoFlushInterval?: number | false | undefined;
|
|
131
|
+
readonly captureGlobalErrors?: boolean | undefined;
|
|
132
|
+
readonly flushOnUnload?: boolean | undefined;
|
|
133
|
+
}
|
|
134
|
+
interface FlushableTelemetry {
|
|
135
|
+
readonly captureException: (error: unknown, options?: CaptureExceptionOptions) => void;
|
|
136
|
+
readonly dispose: () => Promise<void>;
|
|
137
|
+
readonly flush: () => Promise<void>;
|
|
138
|
+
readonly layer: Layer.Layer<never>;
|
|
139
|
+
}
|
|
140
|
+
declare const attachProcessor: (telemetry: FlushableTelemetry, processor: BatchSpanProcessor) => void;
|
|
141
|
+
declare const make: (config?: MxlBrowserFlushableConfig) => FlushableTelemetry;
|
|
142
|
+
export { IdentifyInput as _, layer_d_exports as a, MapleSpanOptions as b, replayRecordOptions as c, decrement as d, identify$1 as f, TrackProps as g, track$1 as h, MxlBrowserConfig as i, PrivacyOptions as l, setConsent as m, MxlBrowserFlushableConfig as n, ClientReplayConfig as o, increment as p, flushable_d_exports as r, ReplayRecordOptions as s, FlushableTelemetry as t, clearIdentity$1 as u, MapleIdentity as v, MxlSpanOptions as x, FinishedSpan as y };
|
|
143
|
+
//# sourceMappingURL=flushable-SCVrRJX3.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flushable-SCVrRJX3.d.ts","names":["identify","clearIdentity","track"],"sources":["../src/shared/span-options.ts","../src/shared/identity.ts","../src/shared/product-event.ts","../src/browser/analytics.ts","../src/shared/flushable-tracer.ts","../src/browser/replay.ts","../src/browser/layer.ts","../src/browser/flushable.ts"],"mappings":";;;;UAWiB;WACN;WACA,MAAM,OAAO;WACb,YAAY;WACZ,MAAM,KAAK;;UAGL;;;;;;WAMN,gBAAgB;;;;;;;;;;;;WAYhB,mBAAmB;;;;;;WAMnB,aAAa,MAAM;;;;;;;;WAQnB,8BAA8B;;WAE9B,uBAAuB;;;;;;WAMvB,uBAAuB;;KAGtB,mBAAmB;UC7Dd;WACN;WACA;WACA;WACA;WACA,SAAS;;KAGR,yBAAyB;UCYpB;YACL;;UCVK;WACN;;cA4HE,aAAU;cAOVA,aAAQ,QAAY;cA+BpBC;cAiDAC,UAAK,cAAgB,QAAU;cAiC/B,YAAS,kBAAoB;cAI7B,YAAS,kBAAoB;UCvPzB;;WAEN;;WAEA,aAAa;;UCdP;WACN;WACA;WACA;WACA;WACA;;UAGM;WACN;WACA;WACA;WACA;aAAsB;;;cAGpB,sBAAmB,QACtB,mCACP;;;;UCEc;WACN;WACA,aAAa;WACb;WACA;WACA;WACA;WACA,UAAU;WACV;WACA,UAAU;WACV,SAAS;WACT;WACA;WACA;;cAGE,oBAAiB;EAC5B,eAAe,aAAa;;;;;;;cA+CjB,QAAK,SAAY,qBAAgB,MAAA;cAuDjC,WAAQ,QAAY,kBAAa,OAAA;cAGjC,eAAa,OAAA;cAEb,QAAK,cAAgB,QAAU,eAAU,OAAA;;;;UC7HrC,kCACP,kBAAkB;WACjB;WACA;WACA;;UAGM;WACN,mBACP,gBACA,UAAU;WAEH,eAAe;WACf,aAAa;WACb,OAAO,MAAM;;cAMX,kBAAe,WACf,oBAAkB,WAClB;cAsEA,OAAI,SACP,8BACP"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { n as MxlBrowserFlushableConfig, t as FlushableTelemetry } from "../flushable-SCVrRJX3.js";
|
|
2
|
+
/** How Command args reach span attributes. */
|
|
3
|
+
type CommandArgsPolicy = 'ids' | 'all' | 'none' | {
|
|
4
|
+
/** Arg keys exported as-is, on top of ids and flags. */
|
|
5
|
+
readonly allow?: ReadonlyArray<string> | undefined;
|
|
6
|
+
};
|
|
7
|
+
declare namespace make_d_exports {
|
|
8
|
+
export { MapleFoldkit, MapleFoldkitConfig, MxlFoldkit, MxlFoldkitConfig, make };
|
|
9
|
+
}
|
|
10
|
+
interface MxlFoldkitConfig extends MxlBrowserFlushableConfig {
|
|
11
|
+
/**
|
|
12
|
+
* Which Command args become span attributes, as `mxl.foldkit.arg.<key>`. Default
|
|
13
|
+
* `"ids"`: args whose key ends in `Id`/`Ids`, booleans and nulls export, every
|
|
14
|
+
* other value exports as `[redacted]`. `{ allow: ["channelId", "provider"] }` adds keys by name.
|
|
15
|
+
*/
|
|
16
|
+
readonly commandArgs?: CommandArgsPolicy | undefined;
|
|
17
|
+
/**
|
|
18
|
+
* Commands exported even when they finish without starting a child span.
|
|
19
|
+
* By default such a Command is UI work (focus, scroll, a hover delay) and is
|
|
20
|
+
* dropped, so only Commands that called an API, RPC or traced Effect export.
|
|
21
|
+
* Failed Commands always export.
|
|
22
|
+
*/
|
|
23
|
+
readonly keepCommands?: ReadonlyArray<string> | undefined;
|
|
24
|
+
/** Sample rates for chatty Commands outside a navigation, e.g. `{ SendTypingHeartbeat: 0.01 }`. */
|
|
25
|
+
readonly sampleCommands?: Readonly<Record<string, number>> | undefined;
|
|
26
|
+
/** Share of navigations traced. Every Command under a navigation follows its decision. Default 1. */
|
|
27
|
+
readonly navigationSampleRate?: number | undefined;
|
|
28
|
+
/**
|
|
29
|
+
* Span name suffix for a navigation, from the URL path: a route template like
|
|
30
|
+
* `/chat/:channelId` or a route name. Default: the path itself.
|
|
31
|
+
*/
|
|
32
|
+
readonly routeName?: ((pathname: string) => string) | undefined;
|
|
33
|
+
/**
|
|
34
|
+
* Report slow `update`, `view` and DOM patch phases as spans. Default
|
|
35
|
+
* thresholds: update 16ms, view 50ms, patch 50ms. `false` turns it off.
|
|
36
|
+
*/
|
|
37
|
+
readonly slowPhases?: false | Partial<Record<'Update' | 'View' | 'Patch', number>> | undefined;
|
|
38
|
+
}
|
|
39
|
+
interface MxlFoldkit extends FlushableTelemetry {
|
|
40
|
+
/**
|
|
41
|
+
* Wrap a `Runtime.makeApplication` (or `makeElement`) config: merges the
|
|
42
|
+
* telemetry into `resources`, and instruments `init`, `update`, `routing`,
|
|
43
|
+
* `crash` and `slow`. Everything else passes through.
|
|
44
|
+
*/
|
|
45
|
+
readonly instrument: <Config extends object>(config: Config) => Config;
|
|
46
|
+
}
|
|
47
|
+
type MapleFoldkit = MxlFoldkit;
|
|
48
|
+
type MapleFoldkitConfig = MxlFoldkitConfig;
|
|
49
|
+
/**
|
|
50
|
+
* MXL telemetry for a Foldkit app: Command spans with navigation parents,
|
|
51
|
+
* scrubbed args, crash reports and slow-phase spans, on top of the buffered
|
|
52
|
+
* browser tracer (`MxlFlush.make`) with session replay.
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* ```ts
|
|
56
|
+
* import { MxlFoldkit } from "@safaricom-mxl/effect-sdk/foldkit"
|
|
57
|
+
*
|
|
58
|
+
* const telemetry = MxlFoldkit.make({ serviceName: "acme-web", endpoint: "http://127.0.0.1:4318" })
|
|
59
|
+
*
|
|
60
|
+
* Runtime.run(Runtime.makeApplication(telemetry.instrument({ Model, init, update, view, resources, routing })))
|
|
61
|
+
* ```
|
|
62
|
+
*/
|
|
63
|
+
declare const make: (config: MxlFoldkitConfig) => MxlFoldkit;
|
|
64
|
+
export { type CommandArgsPolicy, make_d_exports as MapleFoldkit, make_d_exports as MxlFoldkit, type MapleFoldkitConfig, type MapleFoldkit as MapleFoldkitTelemetry, type MxlFoldkitConfig, type MxlFoldkit as MxlFoldkitTelemetry };
|
|
65
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../../src/foldkit/args.ts","../../src/foldkit/make.ts"],"mappings":";;KAKY;;WAMG,QAAQ;;;;;UCmGN,yBAAyB;;;;;;WAM/B,cAAc;;;;;;;WAOd,eAAe;;WAEf,iBAAiB,SAAS;;WAE1B;;;;;WAKA,cAAc;;;;;WAKd,qBAEL,QAAQ;;UAIG,mBAAmB;;;;;;WAMzB,aAAa,uBAAuB,QAAQ,WAAW;;KAGtD,eAAe;KACf,qBAAqB;;;;;;;;;;;;;;;cAwCpB,OAAI,QAAY,qBAAmB"}
|