/** * decision-otlp.ts, map permission/policy decision-log records to OpenTelemetry * (OTLP) span and log semantics, and export them as OTLP/HTTP JSON. * * HONEST SCOPE: this is EXPORT-ONLY. It surfaces ahead-of-field data that * already exists, every allow/deny the DecisionLog already records, by * mapping each decision to the OTLP wire shape and POSTing it to a configured * collector. There is no ingestion path, no span/trace correlation with the * runtime tracer, and no new heavyweight dependency: the payload is plain * OTLP/HTTP JSON (which the protocol supports) emitted with the platform's * `instrumentedFetch`. Off by default; enabled only with an endpoint. * * Each decision maps to the same attribute set in both shapes: * decision.id , the log entry's monotonic sequence number * tool.name , the tool evaluated * command.class , the semantic classification (read/write/network/…) * permission.mode , the active permission mode, when the caller supplies it * decision.layer , the evaluation layer that produced the decision * decision.reason , the canonical reason code * decision.allowed, the boolean outcome */ import type { DecisionLogEntry } from './decision-log.js'; /** An OTLP AnyValue (the subset this mapping emits). */ export type OtlpAnyValue = { readonly stringValue: string; } | { readonly boolValue: boolean; } | { readonly intValue: string; }; /** An OTLP KeyValue attribute. */ export interface OtlpKeyValue { readonly key: string; readonly value: OtlpAnyValue; } /** An OTLP span (v1/traces), the fields this mapping populates. */ export interface OtlpSpan { readonly traceId: string; readonly spanId: string; readonly name: string; readonly kind: number; readonly startTimeUnixNano: string; readonly endTimeUnixNano: string; readonly attributes: readonly OtlpKeyValue[]; readonly status: { readonly code: number; }; } /** An OTLP log record (v1/logs), the fields this mapping populates. */ export interface OtlpLogRecord { readonly timeUnixNano: string; readonly observedTimeUnixNano: string; readonly severityNumber: number; readonly severityText: string; readonly body: { readonly stringValue: string; }; readonly attributes: readonly OtlpKeyValue[]; } /** The OTLP/HTTP JSON envelope for a batch of spans. */ export interface OtlpTracePayload { readonly resourceSpans: readonly { readonly resource: { readonly attributes: readonly OtlpKeyValue[]; }; readonly scopeSpans: readonly { readonly scope: { readonly name: string; }; readonly spans: readonly OtlpSpan[]; }[]; }[]; } /** The OTLP/HTTP JSON envelope for a batch of log records. */ export interface OtlpLogsPayload { readonly resourceLogs: readonly { readonly resource: { readonly attributes: readonly OtlpKeyValue[]; }; readonly scopeLogs: readonly { readonly scope: { readonly name: string; }; readonly logRecords: readonly OtlpLogRecord[]; }[]; }[]; } /** Export configuration; mirrors the `telemetry.decisionOtlp*` config keys. */ export interface DecisionOtlpConfig { /** Master switch, off by default. */ readonly enabled: boolean; /** OTLP/HTTP JSON endpoint base (spans → `/v1/traces`, logs → `/v1/logs`). */ readonly endpoint: string; /** Which record shape(s) to emit per decision. */ readonly signal: 'span' | 'log' | 'both'; /** `service.name` resource attribute (default: goodvibes-sdk). */ readonly serviceName?: string | undefined; /** Per-request timeout (default 8000ms). */ readonly timeoutMs?: number | undefined; /** Extra headers (e.g. an auth token). */ readonly headers?: Record | undefined; } /** Optional per-decision context the log entry does not carry itself. */ export interface DecisionOtlpContext { /** The active permission mode, mapped to the `permission.mode` attribute. */ readonly mode?: string | undefined; } /** Map a decision-log entry to the shared OTLP attribute set. */ export declare function decisionAttributes(entry: DecisionLogEntry, ctx?: DecisionOtlpContext): OtlpKeyValue[]; /** Map a decision-log entry to an OTLP span. */ export declare function decisionToSpan(entry: DecisionLogEntry, ctx?: DecisionOtlpContext): OtlpSpan; /** Map a decision-log entry to an OTLP log record. */ export declare function decisionToLogRecord(entry: DecisionLogEntry, ctx?: DecisionOtlpContext): OtlpLogRecord; /** Build the OTLP/HTTP JSON trace payload for a batch of decisions. */ export declare function buildTracePayload(entries: readonly DecisionLogEntry[], serviceName?: string, ctx?: DecisionOtlpContext): OtlpTracePayload; /** Build the OTLP/HTTP JSON logs payload for a batch of decisions. */ export declare function buildLogsPayload(entries: readonly DecisionLogEntry[], serviceName?: string, ctx?: DecisionOtlpContext): OtlpLogsPayload; /** Outcome of an export attempt. Never thrown, export never blocks the runtime. */ export interface DecisionExportResult { readonly exported: boolean; /** Why nothing was exported, when `exported` is false. */ readonly reason?: string | undefined; /** The OTLP signals that were POSTed. */ readonly signals: readonly ('span' | 'log')[]; } /** * Export a batch of decision-log entries as OTLP/HTTP JSON. Off by default: when * `enabled` is false or no endpoint is configured, this is a no-op that reports * why. Never throws, an unreachable collector never blocks a permission * decision. */ export declare function exportDecisions(entries: readonly DecisionLogEntry[], config: DecisionOtlpConfig, ctx?: DecisionOtlpContext): Promise; //# sourceMappingURL=decision-otlp.d.ts.map