/** * Host-side telemetry: Segment-shaped analytics event router. * * Provides a vendor-neutral analytics interface that accepts events from * sandboxed product iframes and routes them to per-product backends. * * The event shape follows the Segment spec (`track`, `identify`, `page`) * which is the de facto standard accepted by PostHog, Amplitude, Mixpanel, * RudderStack, and Jitsu without custom adapters. * * @example * ```ts * import { createAnalyticsRouter, type AnalyticsAdapter } from "@polkadot-apps/host-sdk"; * * const posthogAdapter: AnalyticsAdapter = { * track: (event) => posthog.capture(event.event!, event.properties), * identify: (event) => posthog.identify(event.userId!, event.traits), * flush: () => Promise.resolve(), * }; * * const router = createAnalyticsRouter(); * router.register("com.example.app", posthogAdapter); * * // Events from products are automatically routed to the registered adapter. * ``` */ /** * W3C-compatible trace context injected into product iframes. * * The host sets `sampled: false` to disable all telemetry collection for a * session. Products MUST NOT send timing or analytics events when * `sampled` is false. */ export interface TraceContext { /** 32-char hex string (16 bytes), W3C trace-id format. */ readonly traceId: string; /** 16-char hex string (8 bytes), W3C span-id format. */ readonly parentSpanId: string; /** Whether this trace is being sampled. Products must respect this flag. */ readonly sampled: boolean; /** Product identifier injected by the host; takes precedence over document.title. */ readonly productId?: string; } /** * Common fields on every analytics event. * * Follows the Segment spec: https://segment.com/docs/connections/spec/ */ interface AnalyticsEventBase { /** ISO 8601 timestamp. */ readonly timestamp: string; /** Trace correlation (ties analytics events to OTel distributed traces). */ readonly context: AnalyticsContext; } /** Contextual metadata attached to every event. */ export interface AnalyticsContext { /** Product that emitted the event. */ readonly app: { readonly productId: string; readonly version?: string; }; /** OTel trace correlation (present when the host injects a TraceContext). */ readonly trace?: { readonly traceId: string; readonly spanId: string; }; } /** * Segment `track` call — records a user action. * * @example * ```ts * { type: "track", event: "tx_submitted", properties: { chain: "polkadot" } } * ``` */ export interface TrackEvent extends AnalyticsEventBase { readonly type: "track"; /** Action name (e.g. "wallet_connected", "tx_submitted"). */ readonly event: string; /** Arbitrary properties describing the action. */ readonly properties?: Readonly>; } /** * Segment `identify` call — associates a user identity. * * Products should only call this with the user's public address or an * anonymous ID — never with PII like email or name. */ export interface IdentifyEvent extends AnalyticsEventBase { readonly type: "identify"; /** User identifier (wallet address or anonymous ID). */ readonly userId: string; /** Traits describing the user (e.g. { chain_count: 3 }). */ readonly traits?: Readonly>; } /** * Segment `page` / `screen` call — records a page view. */ export interface PageEvent extends AnalyticsEventBase { readonly type: "page"; /** Page or screen name. */ readonly name: string; /** Additional page properties. */ readonly properties?: Readonly>; } /** * Performance timing event posted by products through the postMessage bridge. * * This is NOT part of the Segment spec — it bridges product-side * `performance.measure()` calls into the host's OTel trace tree. */ export interface TimingEvent extends AnalyticsEventBase { readonly type: "timing"; /** Span name (e.g. "product.wallet_connect", "product.rpc_call"). */ readonly name: string; /** Span start time (epoch ms, derived from performance.now + Date.now). */ readonly startMs: number; /** Span duration in milliseconds. */ readonly durationMs: number; /** Span ID generated by the product (16-char hex). */ readonly spanId: string; /** Parent span ID from the trace context. */ readonly parentSpanId: string; /** Arbitrary attributes. */ readonly attributes?: Readonly>; } /** Union of all analytics event types. */ export type AnalyticsEvent = TrackEvent | IdentifyEvent | PageEvent | TimingEvent; /** Shape of the postMessage data sent by the product iframe. */ export interface ProductAnalyticsMessage { readonly type: "host-analytics"; readonly event: AnalyticsEvent; } /** * Type guard for analytics messages from product iframes. * * @internal Exported for testing — not part of the public API contract. */ export declare function isProductAnalyticsMessage(data: unknown): data is ProductAnalyticsMessage; /** * Backend adapter interface. Each analytics provider (PostHog, Amplitude, * RudderStack, custom webhook, etc.) implements this to receive events. * * All methods are optional — implement only what the backend supports. */ export interface AnalyticsAdapter { /** Handle a `track` event. */ track?(event: TrackEvent): void; /** Handle an `identify` event. */ identify?(event: IdentifyEvent): void; /** Handle a `page` event. */ page?(event: PageEvent): void; /** Handle a `timing` event (for OTel/APM backends). */ timing?(event: TimingEvent): void; /** Flush any buffered events (called on product destroy). */ flush?(): Promise; } /** Configuration for the analytics router. */ export interface AnalyticsRouterOptions { /** * Maximum events per product per window. Default: 100. * Prevents a malicious product from flooding the analytics pipeline. */ maxEventsPerWindow?: number; /** Rate limit window duration in milliseconds. Default: 60_000 (1 minute). */ windowMs?: number; /** Called when a product exceeds its rate limit. */ onRateLimited?: (productId: string, event: AnalyticsEvent) => void; } /** Routes analytics events from products to per-product backend adapters. */ export interface AnalyticsRouter { /** * Register a backend adapter for a product. * Events from this product will be forwarded to the adapter. * Replaces any previously registered adapter for the same product. */ register(productId: string, adapter: AnalyticsAdapter): void; /** Unregister the adapter for a product. Events will be silently dropped. */ unregister(productId: string): void; /** * Route an analytics event to the appropriate backend. * Applies rate limiting and validation before forwarding. * * @returns `true` if the event was forwarded, `false` if dropped. */ dispatch(productId: string, event: AnalyticsEvent): boolean; /** Flush all registered adapters. */ flushAll(): Promise; /** Remove all adapters and reset state. */ destroy(): void; } /** * Create a new analytics router that dispatches product events to * per-product backend adapters. * * @example * ```ts * const router = createAnalyticsRouter({ maxEventsPerWindow: 200 }); * router.register("com.example.app", myPostHogAdapter); * // In mountProductView's onMessage handler: * router.dispatch(productId, event); * ``` */ export declare function createAnalyticsRouter(options?: AnalyticsRouterOptions): AnalyticsRouter; /** Generate a random 32-char hex trace ID. */ export declare function generateTraceId(): string; /** Generate a random 16-char hex span ID. */ export declare function generateSpanId(): string; /** Create a TraceContext for injection into a product iframe. */ export declare function createTraceContext(sampled?: boolean, productId?: string): TraceContext; /** * Format a TraceContext as a W3C traceparent header value. * * @see https://www.w3.org/TR/trace-context/#traceparent-header-field-values */ export declare function formatTraceparent(ctx: TraceContext): string; export {}; //# sourceMappingURL=telemetry.d.ts.map