@intentproof/sdk 0.1.0

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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/client.ts","../src/exporters/memory.ts","../src/runtime.ts","../src/snapshot.ts","../src/exporters/http.ts","../src/exporters/queue.ts"],"sourcesContent":["/**\n * @packageDocumentation\n * Structured `ExecutionEvent` emission for verification / ingest pipelines.\n */\n\nimport { IntentProofClient, getIntentProofClient } from \"./client.js\";\nimport type { IntentProofConfig } from \"./types.js\";\n\n/** Injected at build (`tsup`) and test (`vitest`) time from `package.json` — single source of truth. */\ndeclare const __INTENTPROOF_SDK_VERSION__: string;\n\nexport const VERSION = __INTENTPROOF_SDK_VERSION__;\n\nexport type {\n ExecutionErrorSnapshot,\n ExecutionEvent,\n ExecutionStatus,\n Exporter,\n SerializeOptions,\n IntentProofConfig,\n WrapOptions,\n} from \"./types.js\";\n\nexport { snapshot } from \"./snapshot.js\";\n\nexport { MemoryExporter } from \"./exporters/memory.js\";\nexport type { MemoryExporterOptions } from \"./exporters/memory.js\";\n\nexport { HttpExporter } from \"./exporters/http.js\";\nexport type { HttpExporterOptions } from \"./exporters/http.js\";\n\nexport { BoundedQueueExporter } from \"./exporters/queue.js\";\nexport type {\n BoundedQueueExporterOptions,\n QueueOverflowStrategy,\n} from \"./exporters/queue.js\";\n\nexport {\n IntentProofClient,\n assertCorrelationId,\n assertWrapOptionsShape,\n getCorrelationId,\n getIntentProofClient,\n runWithCorrelationId,\n} from \"./client.js\";\n\n/** Default singleton — same instance as `getIntentProofClient()`. */\nexport const client = getIntentProofClient();\n\n/** Isolated client instance (tests, workers, per-tenant configuration). */\nexport function createIntentProofClient(config?: IntentProofConfig): IntentProofClient {\n return new IntentProofClient(config);\n}\n","import { AsyncLocalStorage } from \"async_hooks\";\nimport { randomUUID } from \"crypto\";\nimport { MemoryExporter } from \"./exporters/memory.js\";\nimport { describeValueType, isPromiseLike } from \"./runtime.js\";\nimport { snapshot } from \"./snapshot.js\";\nimport type {\n ExecutionErrorSnapshot,\n ExecutionEvent,\n ExecutionStatus,\n Exporter,\n SerializeOptions,\n IntentProofConfig,\n WrapOptions,\n} from \"./types.js\";\n\nconst correlationStore = new AsyncLocalStorage<string>();\n\n/**\n * Validates a correlation id: non-empty string after trim (same as `WrapOptions.correlationId` /\n * {@link assertWrapOptionsShape}). Used by {@link runWithCorrelationId}.\n */\nexport function assertCorrelationId(id: unknown): asserts id is string {\n if (typeof id !== \"string\") {\n throw new TypeError(\n `IntentProofClient: \"correlationId\" must be a string, got ${describeValueType(id)}`,\n );\n }\n if (id.trim().length === 0) {\n throw new TypeError(\n `IntentProofClient: \"correlationId\" must be a non-empty string (trimmed length is 0)`,\n );\n }\n}\n\n/** Active correlation id from async context, if any. */\nexport function getCorrelationId(): string | undefined {\n return correlationStore.getStore();\n}\n\n/**\n * Run `fn` with an explicit `correlationId` in async context. The id must be a non-empty string\n * after trim ({@link assertCorrelationId}) — the parameter name implies a caller-supplied id.\n */\nexport function runWithCorrelationId<T>(correlationId: string, fn: () => T): T {\n if (typeof fn !== \"function\") {\n throw new TypeError(\n \"IntentProofClient: expected runWithCorrelationId(correlationId, fn)\",\n );\n }\n assertCorrelationId(correlationId);\n return correlationStore.run(correlationId, fn);\n}\n\nfunction defaultOnExporterError(error: unknown, _event: ExecutionEvent): void {\n console.error(\"[intentproof] exporter error\", error);\n}\n\nfunction toErrorSnapshot(e: unknown, includeStack: boolean): ExecutionErrorSnapshot {\n if (e instanceof Error) {\n return includeStack\n ? { name: e.name, message: e.message, stack: e.stack }\n : { name: e.name, message: e.message };\n }\n return { name: \"Error\", message: String(e) };\n}\n\nfunction assertExporterAtIndex(ex: unknown, index: number): void {\n if (\n ex == null ||\n typeof ex !== \"object\" ||\n typeof (ex as Exporter).export !== \"function\"\n ) {\n throw new TypeError(\n `IntentProofClient: exporters[${index}] must be an object with an export() method`,\n );\n }\n}\n\nfunction assertAttributesRecord(label: string, value: unknown): void {\n if (value === null || typeof value !== \"object\" || Array.isArray(value)) {\n throw new TypeError(\n `IntentProofClient: ${label} must be a plain object, got ${describeValueType(value)}`,\n );\n }\n const o = value as Record<string, unknown>;\n for (const key of Object.keys(o)) {\n const v = o[key];\n const t = typeof v;\n if (t !== \"string\" && t !== \"number\" && t !== \"boolean\") {\n throw new TypeError(\n `IntentProofClient: ${label}[${JSON.stringify(key)}] must be a string, number, or boolean, got ${describeValueType(v)}`,\n );\n }\n }\n}\n\n/** Runtime validation for {@link IntentProofClient.wrap} options. */\nexport function assertWrapOptionsShape(options: WrapOptions): void {\n if (typeof options.intent !== \"string\") {\n throw new TypeError(\n `IntentProofClient: \"intent\" must be a string, got ${describeValueType(options.intent)}`,\n );\n }\n if (options.intent.trim().length === 0) {\n throw new TypeError(\n `IntentProofClient: \"intent\" must be a non-empty string (trimmed length is 0)`,\n );\n }\n if (typeof options.action !== \"string\") {\n throw new TypeError(\n `IntentProofClient: \"action\" must be a string, got ${describeValueType(options.action)}`,\n );\n }\n if (options.action.trim().length === 0) {\n throw new TypeError(\n `IntentProofClient: \"action\" must be a non-empty string (trimmed length is 0)`,\n );\n }\n if (\n options.correlationId !== undefined &&\n typeof options.correlationId !== \"string\"\n ) {\n throw new TypeError(\n `IntentProofClient: \"correlationId\" must be a string when provided, got ${describeValueType(options.correlationId)}`,\n );\n }\n if (\n options.correlationId !== undefined &&\n options.correlationId.trim().length === 0\n ) {\n throw new TypeError(\n `IntentProofClient: \"correlationId\" must be a non-empty string when provided (trimmed length is 0)`,\n );\n }\n if (options.attributes !== undefined) {\n assertAttributesRecord(\"WrapOptions.attributes\", options.attributes);\n }\n if (options.includeErrorStack !== undefined) {\n if (typeof options.includeErrorStack !== \"boolean\") {\n throw new TypeError(\n `IntentProofClient: \"includeErrorStack\" must be a boolean when provided, got ${describeValueType(options.includeErrorStack)}`,\n );\n }\n }\n}\n\nexport class IntentProofClient {\n private exporters: Exporter[] = [new MemoryExporter()];\n private onExporterError: (error: unknown, event: ExecutionEvent) => void =\n defaultOnExporterError;\n private defaultAttributes: Readonly<Record<string, string | number | boolean>> = {};\n private includeErrorStack = true;\n\n constructor(config: IntentProofConfig = {}) {\n this.configure(config);\n }\n\n configure(config: IntentProofConfig): void {\n if (config.exporters !== undefined) {\n for (let i = 0; i < config.exporters.length; i++) {\n assertExporterAtIndex(config.exporters[i], i);\n }\n this.exporters = [...config.exporters];\n }\n if (config.onExporterError !== undefined) {\n if (typeof config.onExporterError !== \"function\") {\n throw new TypeError(\n `IntentProofClient: onExporterError must be a function, got ${describeValueType(config.onExporterError)}`,\n );\n }\n this.onExporterError = config.onExporterError;\n }\n if (config.defaultAttributes !== undefined) {\n assertAttributesRecord(\"defaultAttributes\", config.defaultAttributes);\n this.defaultAttributes = config.defaultAttributes;\n }\n if (config.includeErrorStack !== undefined) {\n if (typeof config.includeErrorStack !== \"boolean\") {\n throw new TypeError(\n `IntentProofClient: includeErrorStack must be a boolean when provided, got ${describeValueType(config.includeErrorStack)}`,\n );\n }\n this.includeErrorStack = config.includeErrorStack;\n }\n }\n\n /**\n * Await optional {@link Exporter.flush} on each exporter (parallel).\n * Used for graceful shutdown or tests.\n */\n flush(): Promise<void> {\n return Promise.all(\n this.exporters.map((ex) =>\n typeof ex.flush === \"function\"\n ? Promise.resolve(ex.flush())\n : Promise.resolve(),\n ),\n ).then(() => {});\n }\n\n /**\n * {@link Exporter.shutdown} when present, otherwise {@link Exporter.flush}.\n */\n shutdown(): Promise<void> {\n return Promise.all(\n this.exporters.map((ex) => {\n if (typeof ex.shutdown === \"function\") {\n return Promise.resolve(ex.shutdown());\n }\n if (typeof ex.flush === \"function\") {\n return Promise.resolve(ex.flush());\n }\n return Promise.resolve();\n }),\n ).then(() => {});\n }\n\n /** Read active correlation id (AsyncLocalStorage). */\n getCorrelationId(): string | undefined {\n return getCorrelationId();\n }\n\n /**\n * Run `fn` with a generated correlation id for nested `wrap` calls (callers do not supply an id).\n */\n withCorrelation<T>(fn: () => T): T;\n /**\n * Run `fn` under an optional inbound `correlationId`. Non-empty after trim uses that id;\n * empty or whitespace-only values generate a UUID instead (e.g. missing request header).\n * To require a validated, non-blank id, use {@link runWithCorrelationId}.\n */\n withCorrelation<T>(correlationId: string, fn: () => T): T;\n withCorrelation<T>(correlationIdOrFn: string | (() => T), maybeFn?: () => T): T {\n if (typeof correlationIdOrFn === \"function\") {\n return runWithCorrelationId(randomUUID(), correlationIdOrFn);\n }\n if (typeof correlationIdOrFn !== \"string\") {\n throw new TypeError(\n \"IntentProofClient: withCorrelation: correlation id must be a string\",\n );\n }\n if (typeof maybeFn !== \"function\") {\n throw new TypeError(\n \"IntentProofClient: expected withCorrelation(fn) or withCorrelation(correlationId, fn)\",\n );\n }\n const fn = maybeFn;\n const id = correlationIdOrFn;\n if (id.trim().length === 0) {\n return runWithCorrelationId(randomUUID(), fn);\n }\n return runWithCorrelationId(id, fn);\n }\n\n /**\n * Wrap a function to emit one `ExecutionEvent` per invocation (sync or async).\n */\n wrap<A extends unknown[], R>(\n options: WrapOptions,\n fn: (...args: A) => R,\n ): (...args: A) => R {\n assertWrapOptionsShape(options);\n if (typeof fn !== \"function\") {\n throw new TypeError(\n `IntentProofClient: wrap() second argument must be a function, got ${describeValueType(fn)}`,\n );\n }\n // eslint-disable-next-line @typescript-eslint/no-this-alias -- `function` wrapper uses `fn.apply(this, …)`\n const self = this;\n const wrapped = function (this: unknown, ...args: A): R {\n const correlationId = options.correlationId ?? getCorrelationId() ?? undefined;\n const startedAt = new Date();\n const serOpts: SerializeOptions = {\n maxDepth: options.maxDepth,\n maxKeys: options.maxKeys,\n redactKeys: options.redactKeys,\n maxStringLength: options.maxStringLength,\n };\n let inputs: unknown;\n if (options.captureInput) {\n try {\n inputs = options.captureInput(args as unknown[]);\n } catch {\n inputs = snapshot(args as unknown[], serOpts);\n }\n } else {\n inputs = snapshot(args as unknown[], serOpts);\n }\n\n const base = {\n id: randomUUID(),\n correlationId,\n intent: options.intent,\n action: options.action,\n inputs,\n startedAt: startedAt.toISOString(),\n attributes: mergeAttrs(self.defaultAttributes, options.attributes),\n };\n\n try {\n const out = fn.apply(this, args as unknown as A);\n if (isPromiseLike(out)) {\n return self.handleAsync(out, base, options, serOpts, startedAt) as R;\n }\n self.emitComplete(\n base,\n \"ok\",\n out,\n undefined,\n options,\n serOpts,\n startedAt,\n self.includeErrorStack,\n );\n return out;\n } catch (e) {\n self.emitComplete(\n base,\n \"error\",\n undefined,\n e,\n options,\n serOpts,\n startedAt,\n self.includeErrorStack,\n );\n throw e;\n }\n };\n Object.defineProperty(wrapped, \"name\", {\n value: `intentproof(${fn.name || \"anonymous\"})`,\n configurable: true,\n });\n return wrapped as (...args: A) => R;\n }\n\n private handleAsync(\n p: PromiseLike<unknown>,\n base: Omit<\n ExecutionEvent,\n \"status\" | \"completedAt\" | \"durationMs\" | \"output\" | \"error\"\n >,\n options: WrapOptions,\n serOpts: SerializeOptions,\n startedAt: Date,\n ): Promise<unknown> {\n const includeStack = this.includeErrorStack;\n return Promise.resolve(p).then(\n (value) => {\n this.emitComplete(\n base,\n \"ok\",\n value,\n undefined,\n options,\n serOpts,\n startedAt,\n includeStack,\n );\n return value;\n },\n (err) => {\n this.emitComplete(\n base,\n \"error\",\n undefined,\n err,\n options,\n serOpts,\n startedAt,\n includeStack,\n );\n throw err;\n },\n );\n }\n\n private emitComplete(\n base: Omit<\n ExecutionEvent,\n \"status\" | \"completedAt\" | \"durationMs\" | \"output\" | \"error\"\n >,\n status: ExecutionStatus,\n result: unknown,\n error: unknown | undefined,\n options: WrapOptions,\n serOpts: SerializeOptions,\n startedAt: Date,\n defaultIncludeErrorStack: boolean,\n ): void {\n const completedAt = new Date();\n const durationMs = completedAt.getTime() - startedAt.getTime();\n let output: unknown | undefined;\n let errSnap: ExecutionErrorSnapshot | undefined;\n const includeStack = options.includeErrorStack ?? defaultIncludeErrorStack;\n\n if (status === \"ok\") {\n try {\n output = options.captureOutput\n ? options.captureOutput(result)\n : snapshot(result, serOpts);\n } catch {\n output = snapshot(result, serOpts);\n }\n } else {\n errSnap = toErrorSnapshot(error, includeStack);\n if (options.captureError) {\n try {\n output = options.captureError(error);\n } catch {\n output = undefined;\n }\n }\n }\n\n const event: ExecutionEvent =\n status === \"ok\"\n ? {\n ...base,\n status,\n completedAt: completedAt.toISOString(),\n durationMs,\n output,\n }\n : {\n ...base,\n status,\n completedAt: completedAt.toISOString(),\n durationMs,\n error: errSnap,\n ...(output !== undefined ? { output } : {}),\n };\n\n this.dispatch(event);\n }\n\n private dispatch(event: ExecutionEvent): void {\n for (const ex of this.exporters) {\n try {\n const r = ex.export(event);\n if (isPromiseLike(r)) {\n void r.catch((e) => this.onExporterError(e, event));\n }\n } catch (e) {\n this.onExporterError(e, event);\n }\n }\n }\n}\n\nfunction mergeAttrs(\n a: Readonly<Record<string, string | number | boolean>>,\n b: Readonly<Record<string, string | number | boolean>> | undefined,\n): Readonly<Record<string, string | number | boolean>> | undefined {\n if (!b || Object.keys(b).length === 0) {\n return Object.keys(a).length ? { ...a } : undefined;\n }\n return { ...a, ...b };\n}\n\nlet defaultClient: IntentProofClient | null = null;\n\nexport function getIntentProofClient(): IntentProofClient {\n if (!defaultClient) defaultClient = new IntentProofClient();\n return defaultClient;\n}\n","import type { ExecutionEvent, Exporter } from \"../types.js\";\n\nexport interface MemoryExporterOptions {\n /** Keep at most this many recent events (default 1000). Must be a finite number >= 1. */\n maxEvents?: number;\n}\n\n/**\n * Default exporter: ring buffer in memory for debugging and tests.\n */\nexport class MemoryExporter implements Exporter {\n private readonly maxEvents: number;\n private readonly events: ExecutionEvent[] = [];\n\n constructor(options: MemoryExporterOptions = {}) {\n const cap = options.maxEvents ?? 1000;\n if (!Number.isFinite(cap) || cap < 1) {\n throw new TypeError('MemoryExporter: \"maxEvents\" must be a finite number >= 1');\n }\n this.maxEvents = Math.trunc(cap);\n }\n\n export(event: ExecutionEvent): void {\n this.events.push(event);\n const overflow = this.events.length - this.maxEvents;\n if (overflow > 0) this.events.splice(0, overflow);\n }\n\n /** Mutable snapshot for inspection — newest last. */\n getEvents(): readonly ExecutionEvent[] {\n return this.events;\n }\n\n clear(): void {\n this.events.length = 0;\n }\n\n flush(): Promise<void> {\n return Promise.resolve();\n }\n}\n","export function describeValueType(value: unknown): string {\n if (value === null) return \"null\";\n if (Array.isArray(value)) return \"array\";\n return typeof value;\n}\n\nexport function isPromiseLike(x: unknown): x is PromiseLike<unknown> {\n return (\n x !== null &&\n typeof x === \"object\" &&\n typeof (x as PromiseLike<unknown>).then === \"function\"\n );\n}\n","import type { SerializeOptions } from \"./types.js\";\n\nconst DEFAULT_MAX_DEPTH = 6;\nconst DEFAULT_MAX_KEYS = 50;\n\nfunction snapshotLimit(n: number | undefined, fallback: number): number {\n if (n === undefined) return fallback;\n if (!Number.isFinite(n)) return fallback;\n const i = Math.trunc(n);\n return i < 0 ? fallback : i;\n}\n\nfunction snapshotStringLimit(n: number | undefined): number | undefined {\n if (n === undefined) return undefined;\n if (!Number.isFinite(n)) return undefined;\n const i = Math.trunc(n);\n return i < 0 ? undefined : i;\n}\n\nfunction normalizeRedactSet(redactKeys: string[] | undefined): Set<string> | undefined {\n if (!redactKeys?.length) return undefined;\n const set = new Set(\n redactKeys\n .filter((k): k is string => typeof k === \"string\" && k.length > 0)\n .map((k) => k.toLowerCase()),\n );\n return set.size > 0 ? set : undefined;\n}\n\nfunction shouldRedactKey(key: string, redact: Set<string> | undefined): boolean {\n if (!redact) return false;\n return redact.has(key.toLowerCase());\n}\n\nfunction truncateString(s: string, maxLen: number | undefined): string {\n if (maxLen === undefined || s.length <= maxLen) return s;\n return `${s.slice(0, maxLen)}…[truncated ${s.length - maxLen} chars]`;\n}\n\n/** JSON-safe value for `ExecutionEvent` inputs/output (depth/key limits, optional redaction). */\nexport function snapshot(value: unknown, options: SerializeOptions = {}): unknown {\n const maxDepth = snapshotLimit(options.maxDepth, DEFAULT_MAX_DEPTH);\n const maxKeys = snapshotLimit(options.maxKeys, DEFAULT_MAX_KEYS);\n const maxStringLength = snapshotStringLimit(options.maxStringLength);\n const redact = normalizeRedactSet(options.redactKeys);\n const seen = new WeakSet<object>();\n\n function walk(v: unknown, depth: number): unknown {\n if (v === null || v === undefined) return v;\n const t = typeof v;\n if (t === \"string\" || t === \"number\" || t === \"boolean\") {\n if (t === \"string\") return truncateString(v as string, maxStringLength);\n return v;\n }\n if (t === \"bigint\") return (v as bigint).toString();\n if (t === \"symbol\") return (v as symbol).toString();\n if (t === \"function\") {\n const fn = v as { name?: string };\n return `[Function ${fn.name || \"anonymous\"}]`;\n }\n if (v instanceof Date) return v.toISOString();\n if (Array.isArray(v)) {\n if (depth >= maxDepth) return \"[Array]\";\n return v.slice(0, maxKeys).map((item) => walk(item, depth + 1));\n }\n if (t === \"object\") {\n const o = v as object;\n if (seen.has(o)) return \"[Circular]\";\n seen.add(o);\n if (depth >= maxDepth) return \"[Object]\";\n const out: Record<string, unknown> = {};\n const keys = Object.keys(o);\n let n = 0;\n for (const k of keys) {\n if (n >= maxKeys) {\n out[\"…\"] = `${keys.length - maxKeys} more keys`;\n break;\n }\n try {\n if (shouldRedactKey(k, redact)) {\n out[k] = \"[REDACTED]\";\n } else {\n out[k] = walk((o as Record<string, unknown>)[k], depth + 1);\n }\n } catch {\n out[k] = \"[Unserializable]\";\n }\n n += 1;\n }\n return out;\n }\n }\n\n try {\n return walk(value, 0);\n } catch {\n return \"[SnapshotError]\";\n }\n}\n","import type { ExecutionEvent, Exporter } from \"../types.js\";\nimport { describeValueType } from \"../runtime.js\";\n\n/** Last-resort wire body when custom `body` and `safeJsonEnvelope` both fail. */\nconst HTTP_EXPORTER_FALLBACK_BODY =\n '{\"intentproof\":\"1\",\"eventSerializeFailed\":true}' as const;\n\n/** JSON body for the default wire shape; never throws (last resort is a static envelope). */\nfunction safeJsonEnvelope(event: ExecutionEvent): string {\n try {\n return JSON.stringify({ intentproof: \"1\", event });\n } catch {\n try {\n return JSON.stringify({\n intentproof: \"1\",\n eventPartial: {\n id: event.id,\n action: event.action,\n intent: event.intent,\n status: event.status,\n correlationId: event.correlationId,\n startedAt: event.startedAt,\n completedAt: event.completedAt,\n durationMs: event.durationMs,\n },\n note: \"full event not JSON-serializable\",\n });\n } catch {\n return HTTP_EXPORTER_FALLBACK_BODY;\n }\n }\n}\n\nexport interface HttpExporterOptions {\n url: string;\n method?: string;\n headers?: Record<string, string>;\n /** Serialize event for wire format (default JSON body). */\n body?: (event: ExecutionEvent) => string;\n /**\n * When true, await each request (blocks until HTTP completes). Default false.\n */\n awaitEach?: boolean;\n /** Abort the request after this many milliseconds (global `AbortSignal.timeout`). */\n timeoutMs?: number;\n onError?: (error: unknown, event: ExecutionEvent) => void;\n}\n\n/**\n * POST execution events as JSON. Uses global `fetch` (Node 18+).\n * Fire-and-forget by default to avoid slowing callers.\n */\nexport class HttpExporter implements Exporter {\n private readonly url: string;\n private readonly method: string;\n private readonly headers: Record<string, string>;\n private readonly body: (event: ExecutionEvent) => string;\n private readonly awaitEach: boolean;\n private readonly timeoutMs?: number;\n private readonly onError?: (error: unknown, event: ExecutionEvent) => void;\n private readonly inFlight = new Set<Promise<void>>();\n private closed = false;\n\n constructor(options: HttpExporterOptions) {\n if (typeof options.url !== \"string\") {\n throw new TypeError(\n `HttpExporter: \"url\" must be a non-empty string, got ${describeValueType(options.url)}`,\n );\n }\n if (options.url.trim().length === 0) {\n throw new TypeError(\n 'HttpExporter: \"url\" must be a non-empty string (trimmed length is 0)',\n );\n }\n this.url = options.url;\n this.method = (options.method ?? \"POST\").trim() || \"POST\";\n const rawHeaders = options.headers;\n const extraHeaders =\n rawHeaders !== undefined &&\n rawHeaders !== null &&\n typeof rawHeaders === \"object\" &&\n !Array.isArray(rawHeaders)\n ? (rawHeaders as Record<string, string>)\n : {};\n this.headers = {\n \"content-type\": \"application/json\",\n ...extraHeaders,\n };\n this.body = options.body ?? ((event: ExecutionEvent) => safeJsonEnvelope(event));\n this.awaitEach = options.awaitEach ?? false;\n if (options.timeoutMs !== undefined) {\n const t = options.timeoutMs;\n if (!Number.isFinite(t) || t <= 0) {\n throw new TypeError(\n 'HttpExporter: \"timeoutMs\" must be a finite number > 0 when set',\n );\n }\n this.timeoutMs = Math.trunc(t);\n } else {\n this.timeoutMs = undefined;\n }\n this.onError = options.onError;\n }\n\n private track(p: Promise<void>): void {\n this.inFlight.add(p);\n void p.finally(() => this.inFlight.delete(p));\n }\n\n export(event: ExecutionEvent): void | Promise<void> {\n if (this.closed) {\n this.onError?.(new Error(\"HttpExporter has been shut down\"), event);\n return;\n }\n\n let payload: string;\n try {\n payload = this.body(event);\n } catch (e) {\n this.onError?.(e, event);\n payload = safeJsonEnvelope(event);\n }\n\n const run = async (): Promise<void> => {\n try {\n const res = await fetch(this.url, {\n method: this.method,\n headers: this.headers,\n body: payload,\n credentials: \"omit\",\n signal:\n this.timeoutMs !== undefined\n ? AbortSignal.timeout(this.timeoutMs)\n : undefined,\n });\n if (!res.ok) {\n const err = new Error(`HTTP ${res.status}: ${res.statusText}`);\n this.onError?.(err, event);\n }\n } catch (e) {\n this.onError?.(e, event);\n }\n };\n\n const p = run();\n this.track(p);\n if (this.awaitEach) return p;\n void p;\n }\n\n /** Waits until every started request has settled (success or failure). */\n flush(): Promise<void> {\n if (this.inFlight.size === 0) return Promise.resolve();\n return Promise.all([...this.inFlight]).then(() => {});\n }\n\n /** Stops accepting new events and waits for in-flight requests to finish. */\n async shutdown(): Promise<void> {\n this.closed = true;\n await this.flush();\n }\n}\n","import type { ExecutionEvent, Exporter } from \"../types.js\";\nimport { isPromiseLike } from \"../runtime.js\";\n\nexport type QueueOverflowStrategy = \"drop-newest\" | \"drop-oldest\";\n\nexport interface BoundedQueueExporterOptions {\n /** Downstream exporter (often {@link import(\"./http.js\").HttpExporter}). */\n exporter: Exporter;\n /** Maximum concurrent async exports to the inner exporter (default `4`). */\n maxConcurrent?: number;\n /**\n * Maximum **queued** events waiting for a worker slot (default `1000`).\n * Use `0` for unlimited backlog (not recommended under sustained overload).\n */\n maxQueue?: number;\n /** How to handle overflow when the queue is full (default `drop-newest`). */\n strategy?: QueueOverflowStrategy;\n onDrop?: (event: ExecutionEvent, reason: string) => void;\n onInnerError?: (error: unknown, event: ExecutionEvent) => void;\n}\n\n/**\n * Bounded concurrency + backlog for async-heavy exporters.\n * Sync inner exporters run on the microtask queue and still respect {@link maxConcurrent}.\n */\nexport class BoundedQueueExporter implements Exporter {\n private readonly inner: Exporter;\n private readonly maxConcurrent: number;\n private readonly maxQueue: number;\n private readonly strategy: QueueOverflowStrategy;\n private readonly onDrop?: (event: ExecutionEvent, reason: string) => void;\n private readonly onInnerError?: (error: unknown, event: ExecutionEvent) => void;\n\n private readonly queue: ExecutionEvent[] = [];\n private active = 0;\n /** When false, {@link export} drops events with reason `shutdown`; queued work still drains. */\n private accepting = true;\n private idleResolvers: Array<() => void> = [];\n\n constructor(options: BoundedQueueExporterOptions) {\n const inner = options.exporter;\n if (\n inner == null ||\n typeof inner !== \"object\" ||\n typeof inner.export !== \"function\"\n ) {\n throw new TypeError(\n 'BoundedQueueExporter: \"exporter\" must be an object with an export() method',\n );\n }\n this.inner = inner;\n const rawMc = options.maxConcurrent ?? 4;\n this.maxConcurrent = !Number.isFinite(rawMc) ? 4 : Math.max(1, Math.trunc(rawMc));\n const rawQ = options.maxQueue ?? 1000;\n if (!Number.isFinite(rawQ)) {\n this.maxQueue = 1000;\n } else {\n const q = Math.trunc(rawQ);\n if (q === 0) {\n this.maxQueue = 0;\n } else if (q < 0) {\n this.maxQueue = 1000;\n } else {\n this.maxQueue = q;\n }\n }\n const strategy = options.strategy ?? \"drop-newest\";\n if (strategy !== \"drop-newest\" && strategy !== \"drop-oldest\") {\n throw new TypeError(\n 'BoundedQueueExporter: \"strategy\" must be \"drop-newest\" or \"drop-oldest\"',\n );\n }\n this.strategy = strategy;\n this.onDrop = options.onDrop;\n this.onInnerError = options.onInnerError;\n }\n\n export(event: ExecutionEvent): void {\n if (!this.accepting) {\n this.onDrop?.(event, \"shutdown\");\n return;\n }\n\n const cap = this.maxQueue <= 0 ? Number.POSITIVE_INFINITY : this.maxQueue;\n\n if (this.queue.length >= cap) {\n if (this.strategy === \"drop-oldest\") {\n const dropped = this.queue.shift();\n if (dropped) this.onDrop?.(dropped, \"queue-overflow-drop-oldest\");\n this.queue.push(event);\n } else {\n this.onDrop?.(event, \"queue-overflow-drop-newest\");\n }\n this.pump();\n return;\n }\n\n this.queue.push(event);\n this.pump();\n }\n\n private pump(): void {\n while (this.active < this.maxConcurrent && this.queue.length > 0) {\n const next = this.queue.shift()!;\n this.active++;\n void this.runInner(next).finally(() => {\n this.active--;\n this.pump();\n this.resolveIdleWaitersIfNeeded();\n });\n }\n }\n\n private async runInner(event: ExecutionEvent): Promise<void> {\n try {\n const r = this.inner.export(event);\n if (isPromiseLike(r)) await r;\n } catch (e) {\n this.onInnerError?.(e, event);\n }\n }\n\n private resolveIdleWaitersIfNeeded(): void {\n if (this.queue.length === 0 && this.active === 0) {\n const waiters = this.idleResolvers;\n this.idleResolvers = [];\n for (const r of waiters) r();\n }\n }\n\n /** Resolves when the queue is empty and no inner export is in flight. */\n flush(): Promise<void> {\n if (this.queue.length === 0 && this.active === 0) {\n return Promise.resolve();\n }\n return new Promise((resolve) => {\n this.idleResolvers.push(resolve);\n });\n }\n\n /**\n * Stops accepting new events; does **not** drop items already in the queue—\n * {@link flush} waits until queued and in-flight work finishes.\n */\n async shutdown(): Promise<void> {\n this.accepting = false;\n await this.flush();\n }\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,243 @@
1
+ /** Wire shape for emitted execution records (verification / ingest). */
2
+ type ExecutionStatus = "ok" | "error";
3
+ interface ExecutionErrorSnapshot {
4
+ readonly name: string;
5
+ readonly message: string;
6
+ readonly stack?: string;
7
+ }
8
+ /** One record per wrapped invocation — stable fields for a verifier to consume. */
9
+ interface ExecutionEvent {
10
+ readonly id: string;
11
+ readonly correlationId?: string;
12
+ readonly intent: string;
13
+ readonly action: string;
14
+ readonly inputs: unknown;
15
+ readonly output?: unknown;
16
+ readonly error?: ExecutionErrorSnapshot;
17
+ readonly status: ExecutionStatus;
18
+ readonly startedAt: string;
19
+ readonly completedAt: string;
20
+ readonly durationMs: number;
21
+ readonly attributes?: Readonly<Record<string, string | number | boolean>>;
22
+ }
23
+ interface Exporter {
24
+ /** Must not throw synchronously; async exporters may return a Promise. */
25
+ export(event: ExecutionEvent): void | Promise<void>;
26
+ /** Wait until async side-effects are idle (optional). */
27
+ flush?(): void | Promise<void>;
28
+ /** Stop accepting work and drain (optional). */
29
+ shutdown?(): void | Promise<void>;
30
+ }
31
+ interface SerializeOptions {
32
+ /** Max object nesting when snapshotting (default 6). */
33
+ maxDepth?: number;
34
+ /** Max enumerable own keys per object (default 50). */
35
+ maxKeys?: number;
36
+ /**
37
+ * Own-property keys to replace with `[REDACTED]` (case-insensitive exact match).
38
+ * Nested objects are walked recursively.
39
+ */
40
+ redactKeys?: string[];
41
+ /** Truncate string primitives longer than this (default unlimited). */
42
+ maxStringLength?: number;
43
+ }
44
+ interface WrapOptions extends SerializeOptions {
45
+ /** Non-empty after trim; enforced at runtime in {@link import("./client.js").assertWrapOptionsShape}. */
46
+ intent: string;
47
+ /** Non-empty after trim; enforced at runtime in {@link import("./client.js").assertWrapOptionsShape}. */
48
+ action: string;
49
+ /** Non-empty after trim when set; enforced at runtime. Otherwise uses active context. */
50
+ correlationId?: string;
51
+ /** Extra dimensions on the emitted event. */
52
+ attributes?: Readonly<Record<string, string | number | boolean>>;
53
+ captureInput?: (args: unknown[]) => unknown;
54
+ captureOutput?: (result: unknown) => unknown;
55
+ captureError?: (error: unknown) => unknown;
56
+ /**
57
+ * When false, omit `error.stack` from recorded failures (reduces path/log leakage).
58
+ * Overrides {@link IntentProofConfig.includeErrorStack} for this wrap only.
59
+ */
60
+ includeErrorStack?: boolean;
61
+ }
62
+ interface IntentProofConfig {
63
+ exporters?: Exporter[];
64
+ /** Invoked if an exporter throws synchronously or rejects. Defaults to `console.error` when unset. */
65
+ onExporterError?: (error: unknown, event: ExecutionEvent) => void;
66
+ /** Default attributes merged into every event (e.g. service, env). */
67
+ defaultAttributes?: Readonly<Record<string, string | number | boolean>>;
68
+ /**
69
+ * When false, omit error stack traces from export payloads (default true).
70
+ * Prefer false in production unless you operate a locked-down ingest pipeline.
71
+ */
72
+ includeErrorStack?: boolean;
73
+ }
74
+
75
+ /**
76
+ * Validates a correlation id: non-empty string after trim (same as `WrapOptions.correlationId` /
77
+ * {@link assertWrapOptionsShape}). Used by {@link runWithCorrelationId}.
78
+ */
79
+ declare function assertCorrelationId(id: unknown): asserts id is string;
80
+ /** Active correlation id from async context, if any. */
81
+ declare function getCorrelationId(): string | undefined;
82
+ /**
83
+ * Run `fn` with an explicit `correlationId` in async context. The id must be a non-empty string
84
+ * after trim ({@link assertCorrelationId}) — the parameter name implies a caller-supplied id.
85
+ */
86
+ declare function runWithCorrelationId<T>(correlationId: string, fn: () => T): T;
87
+ /** Runtime validation for {@link IntentProofClient.wrap} options. */
88
+ declare function assertWrapOptionsShape(options: WrapOptions): void;
89
+ declare class IntentProofClient {
90
+ private exporters;
91
+ private onExporterError;
92
+ private defaultAttributes;
93
+ private includeErrorStack;
94
+ constructor(config?: IntentProofConfig);
95
+ configure(config: IntentProofConfig): void;
96
+ /**
97
+ * Await optional {@link Exporter.flush} on each exporter (parallel).
98
+ * Used for graceful shutdown or tests.
99
+ */
100
+ flush(): Promise<void>;
101
+ /**
102
+ * {@link Exporter.shutdown} when present, otherwise {@link Exporter.flush}.
103
+ */
104
+ shutdown(): Promise<void>;
105
+ /** Read active correlation id (AsyncLocalStorage). */
106
+ getCorrelationId(): string | undefined;
107
+ /**
108
+ * Run `fn` with a generated correlation id for nested `wrap` calls (callers do not supply an id).
109
+ */
110
+ withCorrelation<T>(fn: () => T): T;
111
+ /**
112
+ * Run `fn` under an optional inbound `correlationId`. Non-empty after trim uses that id;
113
+ * empty or whitespace-only values generate a UUID instead (e.g. missing request header).
114
+ * To require a validated, non-blank id, use {@link runWithCorrelationId}.
115
+ */
116
+ withCorrelation<T>(correlationId: string, fn: () => T): T;
117
+ /**
118
+ * Wrap a function to emit one `ExecutionEvent` per invocation (sync or async).
119
+ */
120
+ wrap<A extends unknown[], R>(options: WrapOptions, fn: (...args: A) => R): (...args: A) => R;
121
+ private handleAsync;
122
+ private emitComplete;
123
+ private dispatch;
124
+ }
125
+ declare function getIntentProofClient(): IntentProofClient;
126
+
127
+ /** JSON-safe value for `ExecutionEvent` inputs/output (depth/key limits, optional redaction). */
128
+ declare function snapshot(value: unknown, options?: SerializeOptions): unknown;
129
+
130
+ interface MemoryExporterOptions {
131
+ /** Keep at most this many recent events (default 1000). Must be a finite number >= 1. */
132
+ maxEvents?: number;
133
+ }
134
+ /**
135
+ * Default exporter: ring buffer in memory for debugging and tests.
136
+ */
137
+ declare class MemoryExporter implements Exporter {
138
+ private readonly maxEvents;
139
+ private readonly events;
140
+ constructor(options?: MemoryExporterOptions);
141
+ export(event: ExecutionEvent): void;
142
+ /** Mutable snapshot for inspection — newest last. */
143
+ getEvents(): readonly ExecutionEvent[];
144
+ clear(): void;
145
+ flush(): Promise<void>;
146
+ }
147
+
148
+ interface HttpExporterOptions {
149
+ url: string;
150
+ method?: string;
151
+ headers?: Record<string, string>;
152
+ /** Serialize event for wire format (default JSON body). */
153
+ body?: (event: ExecutionEvent) => string;
154
+ /**
155
+ * When true, await each request (blocks until HTTP completes). Default false.
156
+ */
157
+ awaitEach?: boolean;
158
+ /** Abort the request after this many milliseconds (global `AbortSignal.timeout`). */
159
+ timeoutMs?: number;
160
+ onError?: (error: unknown, event: ExecutionEvent) => void;
161
+ }
162
+ /**
163
+ * POST execution events as JSON. Uses global `fetch` (Node 18+).
164
+ * Fire-and-forget by default to avoid slowing callers.
165
+ */
166
+ declare class HttpExporter implements Exporter {
167
+ private readonly url;
168
+ private readonly method;
169
+ private readonly headers;
170
+ private readonly body;
171
+ private readonly awaitEach;
172
+ private readonly timeoutMs?;
173
+ private readonly onError?;
174
+ private readonly inFlight;
175
+ private closed;
176
+ constructor(options: HttpExporterOptions);
177
+ private track;
178
+ export(event: ExecutionEvent): void | Promise<void>;
179
+ /** Waits until every started request has settled (success or failure). */
180
+ flush(): Promise<void>;
181
+ /** Stops accepting new events and waits for in-flight requests to finish. */
182
+ shutdown(): Promise<void>;
183
+ }
184
+
185
+ type QueueOverflowStrategy = "drop-newest" | "drop-oldest";
186
+ interface BoundedQueueExporterOptions {
187
+ /** Downstream exporter (often {@link import("./http.js").HttpExporter}). */
188
+ exporter: Exporter;
189
+ /** Maximum concurrent async exports to the inner exporter (default `4`). */
190
+ maxConcurrent?: number;
191
+ /**
192
+ * Maximum **queued** events waiting for a worker slot (default `1000`).
193
+ * Use `0` for unlimited backlog (not recommended under sustained overload).
194
+ */
195
+ maxQueue?: number;
196
+ /** How to handle overflow when the queue is full (default `drop-newest`). */
197
+ strategy?: QueueOverflowStrategy;
198
+ onDrop?: (event: ExecutionEvent, reason: string) => void;
199
+ onInnerError?: (error: unknown, event: ExecutionEvent) => void;
200
+ }
201
+ /**
202
+ * Bounded concurrency + backlog for async-heavy exporters.
203
+ * Sync inner exporters run on the microtask queue and still respect {@link maxConcurrent}.
204
+ */
205
+ declare class BoundedQueueExporter implements Exporter {
206
+ private readonly inner;
207
+ private readonly maxConcurrent;
208
+ private readonly maxQueue;
209
+ private readonly strategy;
210
+ private readonly onDrop?;
211
+ private readonly onInnerError?;
212
+ private readonly queue;
213
+ private active;
214
+ /** When false, {@link export} drops events with reason `shutdown`; queued work still drains. */
215
+ private accepting;
216
+ private idleResolvers;
217
+ constructor(options: BoundedQueueExporterOptions);
218
+ export(event: ExecutionEvent): void;
219
+ private pump;
220
+ private runInner;
221
+ private resolveIdleWaitersIfNeeded;
222
+ /** Resolves when the queue is empty and no inner export is in flight. */
223
+ flush(): Promise<void>;
224
+ /**
225
+ * Stops accepting new events; does **not** drop items already in the queue—
226
+ * {@link flush} waits until queued and in-flight work finishes.
227
+ */
228
+ shutdown(): Promise<void>;
229
+ }
230
+
231
+ /**
232
+ * @packageDocumentation
233
+ * Structured `ExecutionEvent` emission for verification / ingest pipelines.
234
+ */
235
+
236
+ declare const VERSION: string;
237
+
238
+ /** Default singleton — same instance as `getIntentProofClient()`. */
239
+ declare const client: IntentProofClient;
240
+ /** Isolated client instance (tests, workers, per-tenant configuration). */
241
+ declare function createIntentProofClient(config?: IntentProofConfig): IntentProofClient;
242
+
243
+ export { BoundedQueueExporter, type BoundedQueueExporterOptions, type ExecutionErrorSnapshot, type ExecutionEvent, type ExecutionStatus, type Exporter, HttpExporter, type HttpExporterOptions, IntentProofClient, type IntentProofConfig, MemoryExporter, type MemoryExporterOptions, type QueueOverflowStrategy, type SerializeOptions, VERSION, type WrapOptions, assertCorrelationId, assertWrapOptionsShape, client, createIntentProofClient, getCorrelationId, getIntentProofClient, runWithCorrelationId, snapshot };
@@ -0,0 +1,243 @@
1
+ /** Wire shape for emitted execution records (verification / ingest). */
2
+ type ExecutionStatus = "ok" | "error";
3
+ interface ExecutionErrorSnapshot {
4
+ readonly name: string;
5
+ readonly message: string;
6
+ readonly stack?: string;
7
+ }
8
+ /** One record per wrapped invocation — stable fields for a verifier to consume. */
9
+ interface ExecutionEvent {
10
+ readonly id: string;
11
+ readonly correlationId?: string;
12
+ readonly intent: string;
13
+ readonly action: string;
14
+ readonly inputs: unknown;
15
+ readonly output?: unknown;
16
+ readonly error?: ExecutionErrorSnapshot;
17
+ readonly status: ExecutionStatus;
18
+ readonly startedAt: string;
19
+ readonly completedAt: string;
20
+ readonly durationMs: number;
21
+ readonly attributes?: Readonly<Record<string, string | number | boolean>>;
22
+ }
23
+ interface Exporter {
24
+ /** Must not throw synchronously; async exporters may return a Promise. */
25
+ export(event: ExecutionEvent): void | Promise<void>;
26
+ /** Wait until async side-effects are idle (optional). */
27
+ flush?(): void | Promise<void>;
28
+ /** Stop accepting work and drain (optional). */
29
+ shutdown?(): void | Promise<void>;
30
+ }
31
+ interface SerializeOptions {
32
+ /** Max object nesting when snapshotting (default 6). */
33
+ maxDepth?: number;
34
+ /** Max enumerable own keys per object (default 50). */
35
+ maxKeys?: number;
36
+ /**
37
+ * Own-property keys to replace with `[REDACTED]` (case-insensitive exact match).
38
+ * Nested objects are walked recursively.
39
+ */
40
+ redactKeys?: string[];
41
+ /** Truncate string primitives longer than this (default unlimited). */
42
+ maxStringLength?: number;
43
+ }
44
+ interface WrapOptions extends SerializeOptions {
45
+ /** Non-empty after trim; enforced at runtime in {@link import("./client.js").assertWrapOptionsShape}. */
46
+ intent: string;
47
+ /** Non-empty after trim; enforced at runtime in {@link import("./client.js").assertWrapOptionsShape}. */
48
+ action: string;
49
+ /** Non-empty after trim when set; enforced at runtime. Otherwise uses active context. */
50
+ correlationId?: string;
51
+ /** Extra dimensions on the emitted event. */
52
+ attributes?: Readonly<Record<string, string | number | boolean>>;
53
+ captureInput?: (args: unknown[]) => unknown;
54
+ captureOutput?: (result: unknown) => unknown;
55
+ captureError?: (error: unknown) => unknown;
56
+ /**
57
+ * When false, omit `error.stack` from recorded failures (reduces path/log leakage).
58
+ * Overrides {@link IntentProofConfig.includeErrorStack} for this wrap only.
59
+ */
60
+ includeErrorStack?: boolean;
61
+ }
62
+ interface IntentProofConfig {
63
+ exporters?: Exporter[];
64
+ /** Invoked if an exporter throws synchronously or rejects. Defaults to `console.error` when unset. */
65
+ onExporterError?: (error: unknown, event: ExecutionEvent) => void;
66
+ /** Default attributes merged into every event (e.g. service, env). */
67
+ defaultAttributes?: Readonly<Record<string, string | number | boolean>>;
68
+ /**
69
+ * When false, omit error stack traces from export payloads (default true).
70
+ * Prefer false in production unless you operate a locked-down ingest pipeline.
71
+ */
72
+ includeErrorStack?: boolean;
73
+ }
74
+
75
+ /**
76
+ * Validates a correlation id: non-empty string after trim (same as `WrapOptions.correlationId` /
77
+ * {@link assertWrapOptionsShape}). Used by {@link runWithCorrelationId}.
78
+ */
79
+ declare function assertCorrelationId(id: unknown): asserts id is string;
80
+ /** Active correlation id from async context, if any. */
81
+ declare function getCorrelationId(): string | undefined;
82
+ /**
83
+ * Run `fn` with an explicit `correlationId` in async context. The id must be a non-empty string
84
+ * after trim ({@link assertCorrelationId}) — the parameter name implies a caller-supplied id.
85
+ */
86
+ declare function runWithCorrelationId<T>(correlationId: string, fn: () => T): T;
87
+ /** Runtime validation for {@link IntentProofClient.wrap} options. */
88
+ declare function assertWrapOptionsShape(options: WrapOptions): void;
89
+ declare class IntentProofClient {
90
+ private exporters;
91
+ private onExporterError;
92
+ private defaultAttributes;
93
+ private includeErrorStack;
94
+ constructor(config?: IntentProofConfig);
95
+ configure(config: IntentProofConfig): void;
96
+ /**
97
+ * Await optional {@link Exporter.flush} on each exporter (parallel).
98
+ * Used for graceful shutdown or tests.
99
+ */
100
+ flush(): Promise<void>;
101
+ /**
102
+ * {@link Exporter.shutdown} when present, otherwise {@link Exporter.flush}.
103
+ */
104
+ shutdown(): Promise<void>;
105
+ /** Read active correlation id (AsyncLocalStorage). */
106
+ getCorrelationId(): string | undefined;
107
+ /**
108
+ * Run `fn` with a generated correlation id for nested `wrap` calls (callers do not supply an id).
109
+ */
110
+ withCorrelation<T>(fn: () => T): T;
111
+ /**
112
+ * Run `fn` under an optional inbound `correlationId`. Non-empty after trim uses that id;
113
+ * empty or whitespace-only values generate a UUID instead (e.g. missing request header).
114
+ * To require a validated, non-blank id, use {@link runWithCorrelationId}.
115
+ */
116
+ withCorrelation<T>(correlationId: string, fn: () => T): T;
117
+ /**
118
+ * Wrap a function to emit one `ExecutionEvent` per invocation (sync or async).
119
+ */
120
+ wrap<A extends unknown[], R>(options: WrapOptions, fn: (...args: A) => R): (...args: A) => R;
121
+ private handleAsync;
122
+ private emitComplete;
123
+ private dispatch;
124
+ }
125
+ declare function getIntentProofClient(): IntentProofClient;
126
+
127
+ /** JSON-safe value for `ExecutionEvent` inputs/output (depth/key limits, optional redaction). */
128
+ declare function snapshot(value: unknown, options?: SerializeOptions): unknown;
129
+
130
+ interface MemoryExporterOptions {
131
+ /** Keep at most this many recent events (default 1000). Must be a finite number >= 1. */
132
+ maxEvents?: number;
133
+ }
134
+ /**
135
+ * Default exporter: ring buffer in memory for debugging and tests.
136
+ */
137
+ declare class MemoryExporter implements Exporter {
138
+ private readonly maxEvents;
139
+ private readonly events;
140
+ constructor(options?: MemoryExporterOptions);
141
+ export(event: ExecutionEvent): void;
142
+ /** Mutable snapshot for inspection — newest last. */
143
+ getEvents(): readonly ExecutionEvent[];
144
+ clear(): void;
145
+ flush(): Promise<void>;
146
+ }
147
+
148
+ interface HttpExporterOptions {
149
+ url: string;
150
+ method?: string;
151
+ headers?: Record<string, string>;
152
+ /** Serialize event for wire format (default JSON body). */
153
+ body?: (event: ExecutionEvent) => string;
154
+ /**
155
+ * When true, await each request (blocks until HTTP completes). Default false.
156
+ */
157
+ awaitEach?: boolean;
158
+ /** Abort the request after this many milliseconds (global `AbortSignal.timeout`). */
159
+ timeoutMs?: number;
160
+ onError?: (error: unknown, event: ExecutionEvent) => void;
161
+ }
162
+ /**
163
+ * POST execution events as JSON. Uses global `fetch` (Node 18+).
164
+ * Fire-and-forget by default to avoid slowing callers.
165
+ */
166
+ declare class HttpExporter implements Exporter {
167
+ private readonly url;
168
+ private readonly method;
169
+ private readonly headers;
170
+ private readonly body;
171
+ private readonly awaitEach;
172
+ private readonly timeoutMs?;
173
+ private readonly onError?;
174
+ private readonly inFlight;
175
+ private closed;
176
+ constructor(options: HttpExporterOptions);
177
+ private track;
178
+ export(event: ExecutionEvent): void | Promise<void>;
179
+ /** Waits until every started request has settled (success or failure). */
180
+ flush(): Promise<void>;
181
+ /** Stops accepting new events and waits for in-flight requests to finish. */
182
+ shutdown(): Promise<void>;
183
+ }
184
+
185
+ type QueueOverflowStrategy = "drop-newest" | "drop-oldest";
186
+ interface BoundedQueueExporterOptions {
187
+ /** Downstream exporter (often {@link import("./http.js").HttpExporter}). */
188
+ exporter: Exporter;
189
+ /** Maximum concurrent async exports to the inner exporter (default `4`). */
190
+ maxConcurrent?: number;
191
+ /**
192
+ * Maximum **queued** events waiting for a worker slot (default `1000`).
193
+ * Use `0` for unlimited backlog (not recommended under sustained overload).
194
+ */
195
+ maxQueue?: number;
196
+ /** How to handle overflow when the queue is full (default `drop-newest`). */
197
+ strategy?: QueueOverflowStrategy;
198
+ onDrop?: (event: ExecutionEvent, reason: string) => void;
199
+ onInnerError?: (error: unknown, event: ExecutionEvent) => void;
200
+ }
201
+ /**
202
+ * Bounded concurrency + backlog for async-heavy exporters.
203
+ * Sync inner exporters run on the microtask queue and still respect {@link maxConcurrent}.
204
+ */
205
+ declare class BoundedQueueExporter implements Exporter {
206
+ private readonly inner;
207
+ private readonly maxConcurrent;
208
+ private readonly maxQueue;
209
+ private readonly strategy;
210
+ private readonly onDrop?;
211
+ private readonly onInnerError?;
212
+ private readonly queue;
213
+ private active;
214
+ /** When false, {@link export} drops events with reason `shutdown`; queued work still drains. */
215
+ private accepting;
216
+ private idleResolvers;
217
+ constructor(options: BoundedQueueExporterOptions);
218
+ export(event: ExecutionEvent): void;
219
+ private pump;
220
+ private runInner;
221
+ private resolveIdleWaitersIfNeeded;
222
+ /** Resolves when the queue is empty and no inner export is in flight. */
223
+ flush(): Promise<void>;
224
+ /**
225
+ * Stops accepting new events; does **not** drop items already in the queue—
226
+ * {@link flush} waits until queued and in-flight work finishes.
227
+ */
228
+ shutdown(): Promise<void>;
229
+ }
230
+
231
+ /**
232
+ * @packageDocumentation
233
+ * Structured `ExecutionEvent` emission for verification / ingest pipelines.
234
+ */
235
+
236
+ declare const VERSION: string;
237
+
238
+ /** Default singleton — same instance as `getIntentProofClient()`. */
239
+ declare const client: IntentProofClient;
240
+ /** Isolated client instance (tests, workers, per-tenant configuration). */
241
+ declare function createIntentProofClient(config?: IntentProofConfig): IntentProofClient;
242
+
243
+ export { BoundedQueueExporter, type BoundedQueueExporterOptions, type ExecutionErrorSnapshot, type ExecutionEvent, type ExecutionStatus, type Exporter, HttpExporter, type HttpExporterOptions, IntentProofClient, type IntentProofConfig, MemoryExporter, type MemoryExporterOptions, type QueueOverflowStrategy, type SerializeOptions, VERSION, type WrapOptions, assertCorrelationId, assertWrapOptionsShape, client, createIntentProofClient, getCorrelationId, getIntentProofClient, runWithCorrelationId, snapshot };