export type TelemetryScalar = string | number | boolean | null | undefined; export type TelemetryFields = Readonly>; type TelemetryContext = { orgId?: string | null; playName?: string | null; requestId?: string | null; runId?: string | null; }; export type TelemetryEvent = { telemetrySchemaVersion: 1; timestamp: string; service: string; component: string | null; event: string; tag: string; telemetryKind: 'log'; telemetryLevel: 'info' | 'warn' | 'error'; errorType?: string; errorMessage?: string; } & TelemetryContext & Record; type TelemetryAdapter = { emit(event: TelemetryEvent): void | Promise }; type TelemetryOptions = { tag?: string }; type WorkerTelemetryInput = { service: string; component?: string; context?: TelemetryContext; adapter?: TelemetryAdapter; }; type WorkerTelemetry = { child(input: { component?: string; context?: TelemetryContext; }): WorkerTelemetry; info( event: string, fields?: TelemetryFields, options?: TelemetryOptions, ): Promise; warn( event: string, fields?: TelemetryFields, options?: TelemetryOptions, ): Promise; error( event: string, error?: unknown, fields?: TelemetryFields, options?: TelemetryOptions, ): Promise; }; /** * Small, Worker-safe implementation of the canonical telemetry envelope. * It intentionally omits server-only recursive normalization and adapters so * it can remain in the size-capped dynamic play bundle. */ export function createWorkerTelemetry( input: WorkerTelemetryInput, ): WorkerTelemetry { const service = input.service.trim(); const component = input.component?.trim() || null; const context = input.context ?? {}; const adapter = input.adapter ?? { emit: (event: TelemetryEvent) => console[event.telemetryLevel](JSON.stringify(event)), }; async function emit( level: TelemetryEvent['telemetryLevel'], event: string, fields?: TelemetryFields, options?: TelemetryOptions, error?: unknown, ): Promise { try { await adapter.emit({ telemetrySchemaVersion: 1, timestamp: new Date().toISOString(), service, component, event, tag: options?.tag?.trim() || `[${event}]`, ...context, ...(fields as Record), telemetryKind: 'log', telemetryLevel: level, ...(error == null ? {} : { errorType: error instanceof Error ? error.name : 'Error', errorMessage: error instanceof Error ? error.message : String(error), }), }); } catch { // Never make workflow execution depend on telemetry delivery. } } return { child(child) { return createWorkerTelemetry({ service, component: child.component ?? component ?? undefined, context: { ...context, ...child.context }, adapter, }); }, info: (event, fields, options) => emit('info', event, fields, options), warn: (event, fields, options) => emit('warn', event, fields, options), error: (event, error, fields, options) => emit('error', event, fields, options, error), }; }