{"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../src/memory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEX,cAAc,EACd,WAAW,EACX,UAAU,EACV,gBAAgB,EAChB,aAAa,EACb,MAAM,YAAY,CAAC;AAGpB,MAAM,WAAW,sBAAsB;IACtC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,UAAU,EAAE,QAAQ,CAAC,cAAc,CAAC,CAAC;CAC9C;AAED,MAAM,WAAW,qBAAqB;IACrC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,UAAU,EAAE,QAAQ,CAAC,cAAc,CAAC,CAAC;IAC9C,QAAQ,CAAC,MAAM,EAAE,SAAS,sBAAsB,EAAE,CAAC;IACnD,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;IAC5B,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;CAC9B;AAmKD;;;GAGG;AACH,qBAAa,wBAAyB,YAAW,gBAAgB;IAChE,OAAO,CAAC,QAAQ,CAAC,KAAK,CAIpB;IAEF,SAAS,CAAC,CAAC,EAAE,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,CAAC,IAAI,EAAE,aAAa,KAAK,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAEhG;IAED,sDAAsD;IACtD,QAAQ,IAAI,SAAS,qBAAqB,EAAE,CAc3C;CACD","sourcesContent":["import type {\n\tAttributeValue,\n\tSpanAttributes,\n\tSpanOptions,\n\tSpanStatus,\n\tTelemetryContext,\n\tTelemetrySpan,\n} from \"./index.ts\";\nimport { NOOP_TELEMETRY_CONTEXT } from \"./noop.ts\";\n\nexport interface RecordedTelemetryEvent {\n\treadonly name: string;\n\treadonly attributes: Readonly<SpanAttributes>;\n}\n\nexport interface RecordedTelemetrySpan {\n\treadonly id: number;\n\treadonly parentId: number | null;\n\treadonly name: string;\n\treadonly attributes: Readonly<SpanAttributes>;\n\treadonly events: readonly RecordedTelemetryEvent[];\n\treadonly status: SpanStatus;\n\treadonly settled: boolean;\n\treadonly endSequence?: number;\n}\n\ninterface MutableRecordedTelemetryEvent {\n\tname: string;\n\tattributes: SpanAttributes;\n}\n\ninterface MutableRecordedTelemetrySpan {\n\tid: number;\n\tparentId: number | null;\n\tname: string;\n\tattributes: SpanAttributes;\n\tevents: MutableRecordedTelemetryEvent[];\n\tstatus: SpanStatus;\n\texplicitStatus: boolean;\n\tsettled: boolean;\n\tendSequence?: number;\n}\n\ninterface InMemoryTelemetryState {\n\tspans: MutableRecordedTelemetrySpan[];\n\tnextSpanId: number;\n\tnextEndSequence: number;\n}\n\nfunction copyAttributeValue(value: AttributeValue): AttributeValue {\n\treturn Array.isArray(value) ? ([...value] as AttributeValue) : value;\n}\n\nfunction copyAttributes(attributes?: SpanAttributes): SpanAttributes {\n\tconst copy: SpanAttributes = {};\n\tif (!attributes) return copy;\n\tfor (const [name, value] of Object.entries(attributes)) {\n\t\tif (value !== undefined) copy[name] = copyAttributeValue(value);\n\t}\n\treturn copy;\n}\n\nfunction mergeAttributes(current: SpanAttributes, attributes: SpanAttributes): SpanAttributes {\n\tconst merged = copyAttributes(current);\n\tfor (const [name, value] of Object.entries(attributes)) {\n\t\tif (value !== undefined) merged[name] = copyAttributeValue(value);\n\t}\n\treturn merged;\n}\n\nfunction copyStatus(status: SpanStatus): SpanStatus {\n\tif (status.status === \"ok\") return { status: \"ok\" };\n\treturn status.error\n\t\t? { status: \"error\", error: { name: status.error.name, message: status.error.message } }\n\t\t: { status: \"error\" };\n}\n\nfunction automaticErrorStatus(error: unknown): SpanStatus {\n\ttry {\n\t\tif (error instanceof Error) {\n\t\t\treturn { status: \"error\", error: { name: error.name, message: error.message } };\n\t\t}\n\t} catch {\n\t\t// Error inspection is passive. Fall through to an error status without details.\n\t}\n\treturn { status: \"error\" };\n}\n\nfunction settleSpan(\n\tstate: InMemoryTelemetryState,\n\tspan: MutableRecordedTelemetrySpan,\n\tfailed: boolean,\n\terror?: unknown,\n): void {\n\tif (span.settled) return;\n\tif (failed && !span.explicitStatus) span.status = automaticErrorStatus(error);\n\tspan.settled = true;\n\tspan.endSequence = state.nextEndSequence++;\n}\n\nfunction createSpan(\n\tstate: InMemoryTelemetryState,\n\tparent: MutableRecordedTelemetrySpan | undefined,\n\toptions: SpanOptions,\n): MutableRecordedTelemetrySpan {\n\tconst name = options.name;\n\tconst attributes = copyAttributes(options.attributes);\n\treturn {\n\t\tid: state.nextSpanId++,\n\t\tparentId: parent?.id ?? null,\n\t\tname,\n\t\tattributes,\n\t\tevents: [],\n\t\tstatus: { status: \"ok\" },\n\t\texplicitStatus: false,\n\t\tsettled: false,\n\t};\n}\n\nfunction startInMemorySpan<T>(\n\tstate: InMemoryTelemetryState,\n\tparent: MutableRecordedTelemetrySpan | undefined,\n\toptions: SpanOptions,\n\tcallback: (span: TelemetrySpan) => T | Promise<T>,\n): Promise<T> {\n\tif (parent?.settled) return NOOP_TELEMETRY_CONTEXT.startSpan(options, callback);\n\n\tlet recordedSpan: MutableRecordedTelemetrySpan;\n\ttry {\n\t\trecordedSpan = createSpan(state, parent, options);\n\t\tstate.spans.push(recordedSpan);\n\t} catch {\n\t\treturn NOOP_TELEMETRY_CONTEXT.startSpan(options, callback);\n\t}\n\n\tconst span: TelemetrySpan = {\n\t\tstartSpan: <Result>(\n\t\t\tchildOptions: SpanOptions,\n\t\t\tchildCallback: (child: TelemetrySpan) => Result | Promise<Result>,\n\t\t) => startInMemorySpan(state, recordedSpan, childOptions, childCallback),\n\t\taddEvent(name, attributes) {\n\t\t\tif (recordedSpan.settled) return;\n\t\t\ttry {\n\t\t\t\trecordedSpan.events.push({ name, attributes: copyAttributes(attributes) });\n\t\t\t} catch {\n\t\t\t\t// Recording is passive. Ignore malformed or unreadable telemetry payloads.\n\t\t\t}\n\t\t},\n\t\tsetAttributes(attributes) {\n\t\t\tif (recordedSpan.settled) return;\n\t\t\ttry {\n\t\t\t\trecordedSpan.attributes = mergeAttributes(recordedSpan.attributes, attributes);\n\t\t\t} catch {\n\t\t\t\t// Recording is passive. Ignore malformed or unreadable telemetry payloads.\n\t\t\t}\n\t\t},\n\t\tsetStatus(status) {\n\t\t\tif (recordedSpan.settled) return;\n\t\t\ttry {\n\t\t\t\trecordedSpan.status = copyStatus(status);\n\t\t\t\trecordedSpan.explicitStatus = true;\n\t\t\t} catch {\n\t\t\t\t// Recording is passive. Ignore malformed or unreadable telemetry payloads.\n\t\t\t}\n\t\t},\n\t};\n\n\tlet result: T | Promise<T>;\n\ttry {\n\t\tresult = callback(span);\n\t} catch (error) {\n\t\tsettleSpan(state, recordedSpan, true, error);\n\t\treturn Promise.reject(error);\n\t}\n\n\treturn Promise.resolve(result).then(\n\t\t(value) => {\n\t\t\tsettleSpan(state, recordedSpan, false);\n\t\t\treturn value;\n\t\t},\n\t\t(error: unknown) => {\n\t\t\tsettleSpan(state, recordedSpan, true, error);\n\t\t\tthrow error;\n\t\t},\n\t);\n}\n\n/**\n * Backend-neutral reference implementation that records spans in process memory.\n * Create a fresh instance to isolate tests or independent recording scopes.\n */\nexport class InMemoryTelemetryContext implements TelemetryContext {\n\tprivate readonly state: InMemoryTelemetryState = {\n\t\tspans: [],\n\t\tnextSpanId: 1,\n\t\tnextEndSequence: 1,\n\t};\n\n\tstartSpan<T>(options: SpanOptions, callback: (span: TelemetrySpan) => T | Promise<T>): Promise<T> {\n\t\treturn startInMemorySpan(this.state, undefined, options, callback);\n\t}\n\n\t/** Returns detached snapshots in span-start order. */\n\tgetSpans(): readonly RecordedTelemetrySpan[] {\n\t\treturn this.state.spans.map((span) => ({\n\t\t\tid: span.id,\n\t\t\tparentId: span.parentId,\n\t\t\tname: span.name,\n\t\t\tattributes: copyAttributes(span.attributes),\n\t\t\tevents: span.events.map((event) => ({\n\t\t\t\tname: event.name,\n\t\t\t\tattributes: copyAttributes(event.attributes),\n\t\t\t})),\n\t\t\tstatus: copyStatus(span.status),\n\t\t\tsettled: span.settled,\n\t\t\t...(span.endSequence === undefined ? {} : { endSequence: span.endSequence }),\n\t\t}));\n\t}\n}\n"]}