@alvin0/ai-agent-sdk-observability-node 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,"file":"journal-export-HAdAQxLv.mjs","names":[],"sources":["../src/journal/config.ts","../src/journal/errors.ts","../src/journal/frame.ts","../src/journal.ts","../src/journal/runtime-options.ts","../src/journal/runtime-frame.ts","../src/journal/runtime-store.ts","../src/journal/runtime-exporter.ts","../src/lifecycle.ts"],"sourcesContent":["export const JOURNAL_DEFAULTS = Object.freeze({\n maxSegmentBytes: 64 * 1024 * 1024,\n maxRetainedBytes: 1024 * 1024 * 1024,\n acknowledgedRetentionMs: 7 * 24 * 60 * 60 * 1000,\n syncIntervalMs: 100,\n syncRecordCount: 256,\n})\n\nexport const JOURNAL_LIMITS = Object.freeze({\n recoverySegmentBytes: 65 * 1024 * 1024,\n cursorBytes: 64 * 1024 * 1024,\n identifierCharacters: 64,\n})\n\nexport const JOURNAL_FILES = Object.freeze({\n advancedCursor: 'cursor.json',\n runtimeDirectory: 'runtime-delivery',\n runtimeCursor: 'cursor.json',\n})\n\nexport function positiveSafeInteger(value: number, field: string): number {\n if (!Number.isSafeInteger(value) || value < 1) {\n throw new RangeError(`${field} must be a positive safe integer`)\n }\n return value\n}\n\nexport function safeSegmentId(value: string): string {\n const normalized = value.replace(/[^A-Za-z0-9_-]/g, '')\n if (normalized.length < 8 || normalized.length > JOURNAL_LIMITS.identifierCharacters) {\n throw new TypeError('journal segmentId must yield 8-64 safe characters')\n }\n return normalized\n}\n","import { NODE_OBSERVATION_ERROR_CODES, NodeObservationError } from '../common/errors.ts'\n\nexport function journalFailure(\n code: 'corrupt' | 'io',\n message: string,\n cause?: unknown,\n): NodeObservationError {\n return new NodeObservationError(\n NODE_OBSERVATION_ERROR_CODES[code],\n message,\n cause === undefined ? undefined : { cause },\n )\n}\n","import { createHash } from 'node:crypto'\nimport {\n isSpanId,\n isTraceId,\n type ObservationEvent,\n type ObservationEventName,\n} from '@alvin0/ai-agent-sdk-core'\n\nconst EVENT_NAMES = new Set<ObservationEventName>([\n 'sdk.agent.run', 'sdk.agent.turn', 'sdk.model.call', 'sdk.provider.attempt',\n 'sdk.provider.retry.scheduled', 'sdk.tool.call', 'sdk.compaction', 'sdk.hook.call',\n 'sdk.user.input.wait', 'sdk.skill.operation', 'sdk.memory.operation',\n 'sdk.credential.operation', 'sdk.integration.request', 'sdk.observer.failure',\n 'sdk.exporter.state', 'sdk.log',\n])\n\nexport function journalChecksum(payloadJson: string): string {\n return createHash('sha256').update(payloadJson, 'utf8').digest('hex')\n}\n\nexport function validObservationEvent(value: unknown, eventId: string): value is ObservationEvent {\n if (typeof value !== 'object' || value === null) return false\n try {\n const sequence = Reflect.get(value, 'sequence')\n const monotonicMs = Reflect.get(value, 'monotonicMs')\n const occurredAt = Reflect.get(value, 'occurredAt')\n const resource = Reflect.get(value, 'resource') as unknown\n const correlation = Reflect.get(value, 'correlation') as unknown\n const name = Reflect.get(value, 'name') as ObservationEventName\n const optionalCorrelation = [\n 'conversationId', 'turnId', 'modelCallId', 'attemptId', 'toolCallId',\n 'providerRequestId', 'sessionId',\n ].every(key => {\n const field = Reflect.get(correlation as object, key)\n return field === undefined || (typeof field === 'string' && field.length > 0)\n })\n return Reflect.get(value, 'schemaVersion') === 1\n && Reflect.get(value, 'eventId') === eventId && /^[0-9a-f]{32}$/.test(eventId) && !/^0+$/.test(eventId)\n && Number.isSafeInteger(sequence) && sequence > 0\n && EVENT_NAMES.has(name)\n && ['start', 'end', 'point'].includes(Reflect.get(value, 'phase'))\n && ['critical', 'normal', 'verbose'].includes(Reflect.get(value, 'priority'))\n && typeof occurredAt === 'string' && !Number.isNaN(Date.parse(occurredAt))\n && new Date(occurredAt).toISOString() === occurredAt\n && typeof monotonicMs === 'number' && Number.isFinite(monotonicMs) && monotonicMs >= 0\n && typeof resource === 'object' && resource !== null\n && Reflect.get(resource, 'sdkName') === 'ai-agent-sdk'\n && typeof Reflect.get(resource, 'sdkVersion') === 'string'\n && Reflect.get(resource, 'sdkVersion').length > 0\n && ['browser', 'edge', 'node', 'unknown'].includes(Reflect.get(resource, 'runtime'))\n && typeof correlation === 'object' && correlation !== null\n && isTraceId(Reflect.get(correlation, 'traceId')) && isSpanId(Reflect.get(correlation, 'spanId'))\n && (Reflect.get(correlation, 'parentSpanId') === null || isSpanId(Reflect.get(correlation, 'parentSpanId')))\n && typeof Reflect.get(correlation, 'runId') === 'string' && Reflect.get(correlation, 'runId').length > 0\n && optionalCorrelation\n && typeof Reflect.get(value, 'data') === 'object' && Reflect.get(value, 'data') !== null\n && !Array.isArray(Reflect.get(value, 'data'))\n } catch { return false }\n}\n","import { randomBytes } from 'node:crypto'\nimport {\n chmod,\n lstat,\n readFile,\n readdir,\n rename,\n stat,\n truncate,\n unlink,\n type FileHandle,\n} from 'node:fs/promises'\nimport { join } from 'node:path'\nimport {\n deepFreeze,\n type ObservationBoundary,\n type ObservationEvent,\n} from '@alvin0/ai-agent-sdk-core'\nimport type { ExportAck, ObservationBatch, ObservationExporter } from '@alvin0/ai-agent-sdk-core/observability'\nimport {\n JOURNAL_DEFAULTS,\n JOURNAL_FILES,\n JOURNAL_LIMITS,\n positiveSafeInteger,\n safeSegmentId,\n} from './journal/config.ts'\nimport { journalFailure } from './journal/errors.ts'\nimport { journalChecksum, validObservationEvent } from './journal/frame.ts'\nimport { atomicWriteJson, ensureSafeRoot, openExclusiveFile } from './common/safe-filesystem.ts'\nimport type { JsonlObservationJournalOptions } from './journal/types.ts'\n\nexport type { JournalDurabilityMode, JsonlObservationJournalOptions } from './journal/types.ts'\n\nexport interface JournalRecoveryRecord {\n readonly segment: string\n readonly line: number\n readonly event: ObservationEvent\n readonly payloadJson: string\n}\n\nexport interface JournalRecoveryResult {\n readonly records: readonly JournalRecoveryRecord[]\n readonly quarantinedSegments: readonly string[]\n readonly truncatedSegments: readonly string[]\n}\n\nexport interface JournalStats {\n readonly segmentCount: number\n readonly retainedBytes: number\n readonly unacknowledgedEvents: number\n readonly currentSegment?: string\n}\n\ninterface CursorFile {\n readonly schemaVersion: 1\n readonly acknowledgedEventIds: readonly string[]\n}\n\ninterface SegmentState {\n readonly name: string\n readonly day: string\n readonly handle: FileHandle\n bytes: number\n readonly eventIds: string[]\n}\n\ninterface PendingStage {\n readonly payloadJson: string\n readonly promise: Promise<void>\n}\n\nfunction journalLine(event: ObservationEvent, payloadJson: string): string {\n return `${JSON.stringify({ schemaVersion: 1, eventId: event.eventId, payloadJson, sha256: journalChecksum(payloadJson) })}\\n`\n}\n\nfunction dateDay(value: Date): string {\n return value.toISOString().slice(0, 10)\n}\n\n/** Append-only Node journal whose local durability is measured with fdatasync. */\nexport class JsonlObservationJournalExporter implements ObservationExporter {\n readonly id: string\n readonly supportedBoundaries: readonly ObservationBoundary[]\n private readonly options: Required<Omit<JsonlObservationJournalOptions, 'id' | 'rootDir' | 'mode'>>\n & Pick<JsonlObservationJournalOptions, 'mode'>\n private readonly rootPromise: Promise<string>\n private current: SegmentState | undefined\n private writeTail: Promise<void> = Promise.resolve()\n private readonly pendingStages = new Map<string, PendingStage>()\n private readonly batchEvents = new Map<string, readonly string[]>()\n private readonly acknowledged = new Set<string>()\n private syncTimer: ReturnType<typeof setTimeout> | undefined\n private unsyncedRecords = 0\n private unsyncedCritical = 0\n private closing = false\n\n constructor(options: JsonlObservationJournalOptions) {\n if (typeof options !== 'object' || options === null) throw new TypeError('journal options are required')\n if (!['operational', 'reliable', 'audit'].includes(options.mode)) throw new TypeError('journal mode is invalid')\n this.id = options.id ?? 'journal'\n if (!/^[A-Za-z0-9](?:[A-Za-z0-9._-]{0,63})$/.test(this.id)) throw new TypeError('journal id is invalid')\n this.supportedBoundaries = Object.freeze(options.mode === 'operational' ? ['none'] : ['local-durable'])\n this.options = {\n mode: options.mode,\n maxSegmentBytes: positiveSafeInteger(options.maxSegmentBytes ?? JOURNAL_DEFAULTS.maxSegmentBytes, 'maxSegmentBytes'),\n maxRetainedBytes: positiveSafeInteger(options.maxRetainedBytes ?? JOURNAL_DEFAULTS.maxRetainedBytes, 'maxRetainedBytes'),\n acknowledgedRetentionMs: positiveSafeInteger(\n options.acknowledgedRetentionMs ?? JOURNAL_DEFAULTS.acknowledgedRetentionMs, 'acknowledgedRetentionMs',\n ),\n syncIntervalMs: positiveSafeInteger(options.syncIntervalMs ?? JOURNAL_DEFAULTS.syncIntervalMs, 'syncIntervalMs'),\n syncRecordCount: positiveSafeInteger(options.syncRecordCount ?? JOURNAL_DEFAULTS.syncRecordCount, 'syncRecordCount'),\n now: options.now ?? (() => new Date()),\n segmentId: options.segmentId ?? (() => randomBytes(12).toString('hex')),\n }\n this.rootPromise = this.initialize(options.rootDir)\n void this.rootPromise.catch(() => undefined)\n }\n\n async ready(): Promise<void> {\n await this.rootPromise\n }\n\n stage(event: ObservationEvent): Promise<void> {\n if (this.closing) throw journalFailure('io', 'observation journal is closed')\n const payloadJson = JSON.stringify(event)\n const existing = this.pendingStages.get(event.eventId)\n if (existing !== undefined) {\n if (existing.payloadJson !== payloadJson) throw journalFailure('corrupt', 'duplicate journal eventId has different data')\n return existing.promise\n }\n const promise = this.enqueueWrite(async () => {\n const root = await this.rootPromise\n const line = journalLine(event, payloadJson)\n const lineBytes = Buffer.byteLength(line)\n if (lineBytes > JOURNAL_LIMITS.recoverySegmentBytes) throw journalFailure(\n 'io', 'journal record exceeds the recovery bound',\n )\n await this.ensureCapacity(root, lineBytes, event.priority)\n await this.rotateIfNeeded(root, lineBytes)\n const segment = this.current\n if (segment === undefined) throw journalFailure('io', 'journal segment was not opened')\n await segment.handle.writeFile(line, 'utf8')\n segment.bytes += lineBytes\n segment.eventIds.push(event.eventId)\n this.unsyncedRecords++\n if (event.priority === 'critical') this.unsyncedCritical++\n if (this.options.mode === 'audit') await this.syncCurrent()\n else if (this.options.mode === 'reliable') this.scheduleReliableSync()\n })\n this.pendingStages.set(event.eventId, { payloadJson, promise })\n void promise.catch(() => undefined)\n return promise\n }\n\n async export(batch: ObservationBatch, signal: AbortSignal): Promise<ExportAck> {\n if (signal.aborted) throw signal.reason ?? new Error('journal export aborted')\n const existingBatch = this.batchEvents.get(batch.batchId)\n if (existingBatch !== undefined) {\n const eventIds = batch.events.map(event => event.eventId)\n if (eventIds.length !== existingBatch.length\n || eventIds.some((eventId, index) => eventId !== existingBatch[index])) {\n throw journalFailure('corrupt', 'duplicate journal batchId has different events')\n }\n return deepFreeze({ batchId: batch.batchId, accepted: true, retryable: false })\n }\n await Promise.all(batch.events.map(event => this.stage(event)))\n if (signal.aborted) throw signal.reason ?? new Error('journal export aborted')\n if (this.options.mode !== 'operational') await this.enqueueWrite(async () => { await this.syncCurrent() })\n this.batchEvents.set(batch.batchId, Object.freeze(batch.events.map(event => event.eventId)))\n for (const event of batch.events) this.pendingStages.delete(event.eventId)\n return deepFreeze({ batchId: batch.batchId, accepted: true, retryable: false })\n }\n\n async acknowledgeBatch(batchId: string): Promise<number> {\n const eventIds = this.batchEvents.get(batchId)\n if (eventIds === undefined) return 0\n await this.acknowledgeEvents(eventIds)\n this.batchEvents.delete(batchId)\n return eventIds.length\n }\n\n async acknowledgeEvents(eventIds: readonly string[]): Promise<void> {\n if (!Array.isArray(eventIds) || eventIds.some(\n eventId => typeof eventId !== 'string' || !/^[0-9a-f]{32}$/.test(eventId) || /^0+$/.test(eventId),\n )) throw new TypeError('journal acknowledgments require valid event IDs')\n await this.enqueueWrite(async () => {\n const root = await this.rootPromise\n const previous = new Set(this.acknowledged)\n for (const eventId of eventIds) this.acknowledged.add(eventId)\n try { await this.persistCursor(root) }\n catch (error) {\n this.acknowledged.clear()\n for (const eventId of previous) this.acknowledged.add(eventId)\n throw error\n }\n await this.cleanupNow(root)\n })\n }\n\n async recover(): Promise<JournalRecoveryResult> {\n let result: JournalRecoveryResult | undefined\n await this.enqueueWrite(async () => {\n result = await recoverJournal(await this.rootPromise)\n })\n if (result === undefined) throw journalFailure('io', 'journal recovery did not complete')\n return result\n }\n\n async cleanup(): Promise<void> {\n await this.enqueueWrite(async () => {\n await this.cleanupNow(await this.rootPromise)\n })\n }\n\n private async cleanupNow(root: string): Promise<void> {\n const recovered = await recoverJournal(root)\n const bySegment = new Map<string, JournalRecoveryRecord[]>()\n for (const record of recovered.records) {\n const records = bySegment.get(record.segment) ?? []\n records.push(record)\n bySegment.set(record.segment, records)\n }\n const now = this.options.now().getTime()\n const candidates: Array<{ name: string; bytes: number; mtimeMs: number; acknowledged: boolean }> = []\n for (const [name, records] of bySegment) {\n if (name === this.current?.name) continue\n const info = await stat(join(root, name))\n candidates.push({\n name, bytes: info.size, mtimeMs: info.mtimeMs,\n acknowledged: records.every(record => this.acknowledged.has(record.event.eventId)),\n })\n }\n let retained = candidates.reduce((sum, item) => sum + item.bytes, this.current?.bytes ?? 0)\n const deletedAcknowledged = new Set<string>()\n for (const candidate of candidates.sort((left, right) => left.mtimeMs - right.mtimeMs)) {\n if (!candidate.acknowledged) continue\n if (now - candidate.mtimeMs < this.options.acknowledgedRetentionMs\n && retained <= this.options.maxRetainedBytes) continue\n await unlink(join(root, candidate.name))\n retained -= candidate.bytes\n for (const record of bySegment.get(candidate.name) ?? []) deletedAcknowledged.add(record.event.eventId)\n }\n if (deletedAcknowledged.size > 0) {\n for (const eventId of deletedAcknowledged) this.acknowledged.delete(eventId)\n await this.persistCursor(root)\n }\n if (retained > this.options.maxRetainedBytes) throw journalFailure(\n 'io', 'journal retention cap contains unacknowledged records',\n )\n }\n\n async stats(): Promise<JournalStats> {\n let result: JournalStats | undefined\n await this.enqueueWrite(async () => {\n const root = await this.rootPromise\n const files = (await readdir(root)).filter(name => name.endsWith('.jsonl'))\n let retainedBytes = 0\n for (const name of files) retainedBytes += (await stat(join(root, name))).size\n const recovered = await recoverJournal(root)\n result = deepFreeze({\n segmentCount: files.length,\n retainedBytes,\n unacknowledgedEvents: recovered.records.filter(record => !this.acknowledged.has(record.event.eventId)).length,\n ...this.current === undefined ? {} : { currentSegment: this.current.name },\n })\n })\n if (result === undefined) throw journalFailure('io', 'journal stats did not complete')\n return result\n }\n\n async shutdown(_signal: AbortSignal): Promise<void> {\n if (this.closing) return\n this.closing = true\n if (this.syncTimer !== undefined) clearTimeout(this.syncTimer)\n await Promise.allSettled([...this.pendingStages.values()].map(stage => stage.promise))\n await this.enqueueWrite(async () => {\n await this.syncCurrent()\n await this.current?.handle.close()\n this.current = undefined\n })\n }\n\n private async initialize(rootInput: string): Promise<string> {\n const root = await ensureSafeRoot(rootInput)\n await this.loadCursor(root)\n await recoverJournal(root)\n await this.openSegment(root)\n return root\n }\n\n private enqueueWrite(operation: () => Promise<void>): Promise<void> {\n const result = this.writeTail.then(operation)\n this.writeTail = result.catch(() => undefined)\n return result\n }\n\n private async openSegment(root: string): Promise<void> {\n const now = this.options.now()\n const day = dateDay(now)\n const id = safeSegmentId(this.options.segmentId())\n const name = `${day}-${process.pid}-${id}.jsonl`\n const handle = await openExclusiveFile(root, name)\n this.current = { name, day, handle, bytes: 0, eventIds: [] }\n }\n\n private async rotateIfNeeded(root: string, incomingBytes: number): Promise<void> {\n const current = this.current\n if (current === undefined) {\n await this.openSegment(root)\n return\n }\n const day = dateDay(this.options.now())\n if (current.day === day && (current.bytes === 0 || current.bytes + incomingBytes <= this.options.maxSegmentBytes)) return\n await this.syncCurrent()\n await current.handle.close()\n this.current = undefined\n await this.openSegment(root)\n }\n\n private scheduleReliableSync(): void {\n if (this.unsyncedCritical >= this.options.syncRecordCount) {\n if (this.syncTimer !== undefined) clearTimeout(this.syncTimer)\n this.syncTimer = undefined\n void this.enqueueWrite(async () => { await this.syncCurrent() }).catch(() => undefined)\n return\n }\n if (this.syncTimer !== undefined) return\n this.syncTimer = setTimeout(() => {\n this.syncTimer = undefined\n void this.enqueueWrite(async () => { await this.syncCurrent() }).catch(() => undefined)\n }, this.options.syncIntervalMs)\n this.syncTimer.unref?.()\n }\n\n private async syncCurrent(): Promise<void> {\n if (this.current === undefined || this.unsyncedRecords === 0) return\n await this.current.handle.datasync()\n this.unsyncedRecords = 0\n this.unsyncedCritical = 0\n }\n\n private async ensureCapacity(root: string, incomingBytes: number, priority: ObservationEvent['priority']): Promise<void> {\n const files = (await readdir(root)).filter(name => name.endsWith('.jsonl'))\n let total = 0\n for (const name of files) total += (await stat(join(root, name))).size\n if (total + incomingBytes <= this.options.maxRetainedBytes) return\n await this.cleanupNow(root)\n total = 0\n for (const name of files) {\n const path = join(root, name)\n total += await stat(path).then(value => value.size, () => 0)\n }\n if (total + incomingBytes > this.options.maxRetainedBytes) throw journalFailure(\n 'io', priority === 'critical'\n ? 'journal capacity contains unacknowledged critical records'\n : 'journal capacity is exhausted',\n )\n }\n\n private async loadCursor(root: string): Promise<void> {\n let raw: string\n try {\n const path = join(root, JOURNAL_FILES.advancedCursor)\n const info = await lstat(path)\n if (!info.isFile() || info.isSymbolicLink() || info.size > JOURNAL_LIMITS.cursorBytes) throw new Error('unsafe cursor')\n raw = await readFile(path, 'utf8')\n }\n catch (error) {\n if (typeof error === 'object' && error !== null && Reflect.get(error, 'code') === 'ENOENT') return\n throw journalFailure('io', 'journal cursor read failed', error)\n }\n try {\n const value = JSON.parse(raw) as CursorFile\n if (value.schemaVersion !== 1 || !Array.isArray(value.acknowledgedEventIds)\n || value.acknowledgedEventIds.some(id => typeof id !== 'string' || !/^[0-9a-f]{32}$/.test(id))) {\n throw new Error('invalid cursor')\n }\n for (const id of value.acknowledgedEventIds) this.acknowledged.add(id)\n } catch (error) {\n throw journalFailure('corrupt', 'journal cursor is corrupt', error)\n }\n }\n\n private async persistCursor(root: string): Promise<void> {\n const value = {\n schemaVersion: 1,\n acknowledgedEventIds: [...this.acknowledged].sort(),\n } satisfies CursorFile\n if (Buffer.byteLength(JSON.stringify(value)) > JOURNAL_LIMITS.cursorBytes) throw journalFailure(\n 'io', 'journal cursor exceeds its persistence bound',\n )\n await atomicWriteJson(root, JOURNAL_FILES.advancedCursor, value)\n }\n}\n\nexport async function recoverJournal(rootInput: string): Promise<JournalRecoveryResult> {\n const root = await ensureSafeRoot(rootInput)\n const names = (await readdir(root)).filter(name => name.endsWith('.jsonl')).sort()\n const records: JournalRecoveryRecord[] = []\n const quarantinedSegments: string[] = []\n const truncatedSegments: string[] = []\n const eventIds = new Set<string>()\n for (const name of names) {\n const path = join(root, name)\n const info = await lstat(path)\n if (!info.isFile() || info.isSymbolicLink()) throw journalFailure('io', 'journal segment is not a regular file')\n if (info.size > JOURNAL_LIMITS.recoverySegmentBytes) throw journalFailure('corrupt', 'journal segment exceeds recovery bound')\n await chmod(path, 0o600)\n let text = await readFile(path, 'utf8')\n if (text.length > 0 && !text.endsWith('\\n')) {\n const boundary = text.lastIndexOf('\\n') + 1\n await truncate(path, Buffer.byteLength(text.slice(0, boundary)))\n text = text.slice(0, boundary)\n truncatedSegments.push(name)\n }\n const lines = text.length === 0 ? [] : text.slice(0, -1).split('\\n')\n const segmentEventIds: string[] = []\n for (let index = 0; index < lines.length; index++) {\n const line = lines[index] ?? ''\n try {\n const envelope = JSON.parse(line) as Record<string, unknown>\n if (envelope.schemaVersion !== 1 || typeof envelope.eventId !== 'string'\n || typeof envelope.payloadJson !== 'string' || typeof envelope.sha256 !== 'string'\n || envelope.sha256 !== journalChecksum(envelope.payloadJson)) throw new Error('invalid frame')\n const event = JSON.parse(envelope.payloadJson) as unknown\n if (!validObservationEvent(event, envelope.eventId) || eventIds.has(envelope.eventId)) throw new Error('invalid event')\n eventIds.add(envelope.eventId)\n segmentEventIds.push(envelope.eventId)\n records.push(deepFreeze({ segment: name, line: index + 1, event, payloadJson: envelope.payloadJson }))\n } catch (error) {\n if (index === lines.length - 1) {\n const quarantine = `${name}.corrupt-${Date.now()}`\n await rename(path, join(root, quarantine))\n quarantinedSegments.push(quarantine)\n for (let recordIndex = records.length - 1; recordIndex >= 0; recordIndex--) {\n if (records[recordIndex]?.segment === name) records.splice(recordIndex, 1)\n }\n for (const eventId of segmentEventIds) eventIds.delete(eventId)\n break\n }\n throw journalFailure('corrupt', `journal segment ${name} has mid-file corruption`, error)\n }\n }\n }\n return deepFreeze({ records, quarantinedSegments, truncatedSegments })\n}\n","import { randomBytes } from 'node:crypto'\nimport type { ObservationBoundary } from '@alvin0/ai-agent-sdk-core'\nimport type { JsonlObservationJournalOptions } from './types.ts'\nimport { JOURNAL_DEFAULTS, positiveSafeInteger } from './config.ts'\n\nexport interface RuntimeJournalOptions {\n readonly id: string\n readonly rootDir: string\n readonly mode: JsonlObservationJournalOptions['mode']\n readonly maxSegmentBytes: number\n readonly maxRetainedBytes: number\n readonly acknowledgedRetentionMs: number\n readonly syncIntervalMs: number\n readonly syncRecordCount: number\n readonly now: () => Date\n readonly segmentId: () => string\n readonly supportedBoundaries: readonly ObservationBoundary[]\n}\n\nexport function captureRuntimeJournalOptions(options: JsonlObservationJournalOptions): RuntimeJournalOptions {\n if (typeof options !== 'object' || options === null) throw new TypeError('journal options are required')\n if (!['operational', 'reliable', 'audit'].includes(options.mode)) throw new TypeError('journal mode is invalid')\n const id = options.id ?? 'journal'\n if (!/^[A-Za-z0-9](?:[A-Za-z0-9._-]{0,63})$/.test(id)) throw new TypeError('journal id is invalid')\n if (typeof options.rootDir !== 'string' || options.rootDir.trim().length === 0) {\n throw new TypeError('observation journal rootDir must be explicit and non-empty')\n }\n if (options.now !== undefined && typeof options.now !== 'function') throw new TypeError('journal now must be a function')\n if (options.segmentId !== undefined && typeof options.segmentId !== 'function') {\n throw new TypeError('journal segmentId must be a function')\n }\n const supportedBoundaries: readonly ObservationBoundary[] = Object.freeze(\n options.mode === 'operational' ? ['none'] : ['local-durable'],\n )\n return Object.freeze({\n id,\n rootDir: options.rootDir,\n mode: options.mode,\n maxSegmentBytes: positiveSafeInteger(options.maxSegmentBytes ?? JOURNAL_DEFAULTS.maxSegmentBytes, 'maxSegmentBytes'),\n maxRetainedBytes: positiveSafeInteger(options.maxRetainedBytes ?? JOURNAL_DEFAULTS.maxRetainedBytes, 'maxRetainedBytes'),\n acknowledgedRetentionMs: positiveSafeInteger(\n options.acknowledgedRetentionMs ?? JOURNAL_DEFAULTS.acknowledgedRetentionMs, 'acknowledgedRetentionMs',\n ),\n syncIntervalMs: positiveSafeInteger(options.syncIntervalMs ?? JOURNAL_DEFAULTS.syncIntervalMs, 'syncIntervalMs'),\n syncRecordCount: positiveSafeInteger(options.syncRecordCount ?? JOURNAL_DEFAULTS.syncRecordCount, 'syncRecordCount'),\n now: options.now ?? (() => new Date()),\n segmentId: options.segmentId ?? (() => randomBytes(12).toString('hex')),\n supportedBoundaries,\n })\n}\n","import { isTraceId, type ObservationEvent, type RunTerminalRecord } from '@alvin0/ai-agent-sdk-core'\nimport type { ObservationExportItem } from '@alvin0/ai-agent-sdk-core/observability'\nimport { journalChecksum, validObservationEvent } from './frame.ts'\n\nexport type RuntimeFrameKind = 'event' | 'run-terminal-record'\n\nexport interface RuntimeJournalRecord {\n readonly segment: string\n readonly line: number\n readonly kind: RuntimeFrameKind\n readonly id: string\n readonly key: string\n readonly item: ObservationExportItem\n readonly payloadJson: string\n}\n\nexport function runtimeItemIdentity(item: ObservationExportItem): {\n readonly kind: RuntimeFrameKind\n readonly id: string\n readonly key: string\n} {\n const kind = 'kind' in item && item.kind === 'run-terminal-record' ? 'run-terminal-record' : 'event'\n const id = kind === 'event' ? (item as ObservationEvent).eventId : (item as RunTerminalRecord).runId\n return { kind, id, key: `${kind}:${id}` }\n}\n\nexport function runtimeJournalLine(item: ObservationExportItem, payloadJson: string): string {\n const identity = runtimeItemIdentity(item)\n return `${JSON.stringify({\n schemaVersion: 1,\n itemKind: identity.kind,\n itemId: identity.id,\n payloadJson,\n sha256: journalChecksum(payloadJson),\n })}\\n`\n}\n\nexport function parseRuntimeJournalLine(line: string, segment: string, lineNumber: number): RuntimeJournalRecord {\n const envelope = JSON.parse(line) as Record<string, unknown>\n if (envelope.schemaVersion !== 1\n || (envelope.itemKind !== 'event' && envelope.itemKind !== 'run-terminal-record')\n || typeof envelope.itemId !== 'string'\n || typeof envelope.payloadJson !== 'string'\n || typeof envelope.sha256 !== 'string'\n || envelope.sha256 !== journalChecksum(envelope.payloadJson)) throw new Error('invalid frame')\n const parsed = JSON.parse(envelope.payloadJson) as unknown\n let item: ObservationExportItem\n if (envelope.itemKind === 'event') {\n if (!validObservationEvent(parsed, envelope.itemId)) throw new Error('invalid journal item')\n item = parsed\n } else {\n if (!validTerminalRecord(parsed, envelope.itemId)) throw new Error('invalid journal item')\n item = parsed\n }\n return {\n segment,\n line: lineNumber,\n kind: envelope.itemKind,\n id: envelope.itemId,\n key: `${envelope.itemKind}:${envelope.itemId}`,\n item,\n payloadJson: envelope.payloadJson,\n }\n}\n\nfunction validTerminalRecord(value: unknown, runId: string): value is RunTerminalRecord {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) return false\n try {\n const startedAt = Reflect.get(value, 'startedAt')\n const endedAt = Reflect.get(value, 'endedAt')\n const durationMs = Reflect.get(value, 'durationMs')\n return Reflect.get(value, 'kind') === 'run-terminal-record'\n && Reflect.get(value, 'runId') === runId && runId.length > 0 && runId.length <= 128\n && isTraceId(Reflect.get(value, 'traceId'))\n && validIsoDate(startedAt) && validIsoDate(endedAt)\n && typeof durationMs === 'number' && Number.isFinite(durationMs) && durationMs >= 0\n && ['success', 'error', 'aborted', 'rejected', 'unknown'].includes(Reflect.get(value, 'status'))\n && objectRecord(Reflect.get(value, 'usage'))\n && Array.isArray(Reflect.get(value, 'modelCalls'))\n && Array.isArray(Reflect.get(value, 'toolSourceSnapshots'))\n && objectRecord(Reflect.get(value, 'operationCounts'))\n && Array.isArray(Reflect.get(value, 'errors'))\n && !Object.prototype.hasOwnProperty.call(value, 'delivery')\n } catch { return false }\n}\n\nfunction validIsoDate(value: unknown): value is string {\n return typeof value === 'string' && !Number.isNaN(Date.parse(value)) && new Date(value).toISOString() === value\n}\n\nfunction objectRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n","import { randomBytes } from 'node:crypto'\nimport {\n chmod,\n lstat,\n readFile,\n readdir,\n rename,\n stat,\n truncate,\n unlink,\n type FileHandle,\n} from 'node:fs/promises'\nimport { join } from 'node:path'\nimport { deepFreeze, type ObservationEvent } from '@alvin0/ai-agent-sdk-core'\nimport type {\n ObservationDeliveryAck,\n ObservationDeliveryBatch,\n ObservationExportItem,\n} from '@alvin0/ai-agent-sdk-core/observability'\nimport { atomicWriteJson, ensureSafeRoot, openExclusiveFile } from '../common/safe-filesystem.ts'\nimport { JOURNAL_FILES, JOURNAL_LIMITS, safeSegmentId } from './config.ts'\nimport { journalFailure } from './errors.ts'\nimport {\n parseRuntimeJournalLine,\n runtimeItemIdentity,\n runtimeJournalLine,\n type RuntimeJournalRecord,\n} from './runtime-frame.ts'\nimport type { RuntimeJournalOptions } from './runtime-options.ts'\n\ninterface RuntimeCursor {\n readonly schemaVersion: 1\n readonly acceptedItemKeys: readonly string[]\n}\n\ninterface RuntimeSegment {\n readonly name: string\n readonly day: string\n readonly handle: FileHandle\n bytes: number\n}\n\ninterface PendingItem {\n readonly payloadJson: string\n readonly promise: Promise<void>\n}\n\nexport interface RuntimeJournalRecoveryResult {\n readonly records: readonly RuntimeJournalRecord[]\n readonly truncatedSegments: readonly string[]\n readonly quarantinedSegments: readonly string[]\n}\n\nexport class RuntimeJsonlJournal {\n private root: string | undefined\n private current: RuntimeSegment | undefined\n private writeTail: Promise<void> = Promise.resolve()\n private readonly payloads = new Map<string, string>()\n private readonly pending = new Map<string, PendingItem>()\n private readonly batches = new Map<string, readonly string[]>()\n private readonly accepted = new Set<string>()\n private syncTimer: ReturnType<typeof setTimeout> | undefined\n private unsyncedRecords = 0\n private unsyncedCritical = 0\n private failed: unknown\n private closing = false\n\n constructor(private readonly options: RuntimeJournalOptions) {}\n\n async ready(signal: AbortSignal): Promise<void> {\n abortIfRequested(signal)\n if (this.root !== undefined) return\n const parent = await ensureSafeRoot(this.options.rootDir)\n abortIfRequested(signal)\n const root = await ensureSafeRoot(join(parent, JOURNAL_FILES.runtimeDirectory))\n abortIfRequested(signal)\n await this.loadCursor(root)\n const recovered = await recoverRuntimeJournal(root)\n for (const record of recovered.records) {\n const previous = this.payloads.get(record.key)\n if (previous !== undefined && previous !== record.payloadJson) {\n throw journalFailure('corrupt', 'duplicate runtime journal item has different data')\n }\n this.payloads.set(record.key, record.payloadJson)\n }\n for (const key of [...this.accepted]) if (!this.payloads.has(key)) this.accepted.delete(key)\n abortIfRequested(signal)\n await this.openSegment(root)\n if (signal.aborted) {\n await this.current?.handle.close().catch(() => undefined)\n this.current = undefined\n abortIfRequested(signal)\n }\n this.root = root\n }\n\n stage(item: ObservationExportItem): Promise<void> {\n this.ensureAvailable()\n const identity = runtimeItemIdentity(item)\n const payloadJson = JSON.stringify(item)\n const persisted = this.payloads.get(identity.key)\n if (persisted !== undefined) {\n if (persisted !== payloadJson) throw journalFailure('corrupt', 'duplicate runtime journal item has different data')\n return Promise.resolve()\n }\n const existing = this.pending.get(identity.key)\n if (existing !== undefined) {\n if (existing.payloadJson !== payloadJson) throw journalFailure('corrupt', 'duplicate runtime journal item has different data')\n return existing.promise\n }\n const promise = this.enqueue(async () => {\n const root = this.requiredRoot()\n const line = runtimeJournalLine(item, payloadJson)\n const lineBytes = Buffer.byteLength(line)\n if (lineBytes > JOURNAL_LIMITS.recoverySegmentBytes) {\n throw journalFailure('io', 'runtime journal record exceeds the recovery bound')\n }\n const priority = identity.kind === 'run-terminal-record' ? 'critical' : (item as ObservationEvent).priority\n await this.ensureCapacity(root, lineBytes, priority)\n await this.rotateIfNeeded(root, lineBytes)\n if (this.current === undefined) throw journalFailure('io', 'runtime journal segment was not opened')\n await this.current.handle.writeFile(line, 'utf8')\n this.current.bytes += lineBytes\n this.payloads.set(identity.key, payloadJson)\n this.unsyncedRecords++\n if (priority === 'critical') this.unsyncedCritical++\n if (this.options.mode === 'audit') await this.syncCurrent()\n else if (this.options.mode === 'reliable') this.scheduleReliableSync()\n })\n this.pending.set(identity.key, { payloadJson, promise })\n void promise.then(\n () => { this.pending.delete(identity.key) },\n error => { this.failed = error },\n )\n return promise\n }\n\n async export(batch: ObservationDeliveryBatch, signal: AbortSignal): Promise<ObservationDeliveryAck> {\n this.ensureAvailable()\n abortIfRequested(signal)\n const items: readonly ObservationExportItem[] = [...batch.events, ...batch.runRecords]\n const keys = items.map(item => runtimeItemIdentity(item).key)\n const previous = this.batches.get(batch.id)\n if (previous !== undefined) {\n if (!sameList(previous, keys)) throw journalFailure('corrupt', 'duplicate runtime journal batch has different items')\n return deliveryAck(batch)\n }\n await Promise.all(items.map(item => this.stage(item)))\n abortIfRequested(signal)\n await this.enqueue(async () => {\n await this.syncCurrent()\n const before = new Set(this.accepted)\n for (const key of keys) this.accepted.add(key)\n try {\n await this.persistCursor(this.requiredRoot())\n await this.cleanupNow(this.requiredRoot())\n } catch (error) {\n this.accepted.clear()\n for (const key of before) this.accepted.add(key)\n throw error\n }\n })\n abortIfRequested(signal)\n this.batches.set(batch.id, Object.freeze(keys))\n return deliveryAck(batch)\n }\n\n async shutdown(signal: AbortSignal): Promise<void> {\n if (this.closing) return\n this.closing = true\n if (this.syncTimer !== undefined) clearTimeout(this.syncTimer)\n await Promise.allSettled([...this.pending.values()].map(value => value.promise))\n abortIfRequested(signal)\n await this.enqueue(async () => {\n await this.syncCurrent()\n await this.current?.handle.close()\n this.current = undefined\n })\n }\n\n private ensureAvailable(): void {\n if (this.root === undefined) throw journalFailure('io', 'runtime observation journal is not ready')\n if (this.closing) throw journalFailure('io', 'runtime observation journal is closed')\n if (this.failed !== undefined) throw journalFailure('io', 'runtime observation journal has failed', this.failed)\n }\n\n private requiredRoot(): string {\n if (this.root === undefined) throw journalFailure('io', 'runtime observation journal is not ready')\n return this.root\n }\n\n private enqueue(operation: () => Promise<void>): Promise<void> {\n const result = this.writeTail.then(operation)\n this.writeTail = result.catch(() => undefined)\n return result\n }\n\n private async openSegment(root: string): Promise<void> {\n const now = validNow(this.options.now())\n const day = now.toISOString().slice(0, 10)\n const id = safeSegmentId(this.options.segmentId())\n const name = `${day}-${process.pid}-${id}-${randomBytes(4).toString('hex')}.jsonl`\n this.current = { name, day, handle: await openExclusiveFile(root, name), bytes: 0 }\n }\n\n private async rotateIfNeeded(root: string, incomingBytes: number): Promise<void> {\n const current = this.current\n if (current === undefined) return this.openSegment(root)\n const day = validNow(this.options.now()).toISOString().slice(0, 10)\n if (current.day === day && (current.bytes === 0 || current.bytes + incomingBytes <= this.options.maxSegmentBytes)) return\n await this.syncCurrent()\n await current.handle.close()\n this.current = undefined\n await this.openSegment(root)\n }\n\n private scheduleReliableSync(): void {\n if (this.unsyncedCritical >= this.options.syncRecordCount) {\n if (this.syncTimer !== undefined) clearTimeout(this.syncTimer)\n this.syncTimer = undefined\n void this.enqueue(() => this.syncCurrent()).catch(error => { this.failed = error })\n return\n }\n if (this.syncTimer !== undefined) return\n this.syncTimer = setTimeout(() => {\n this.syncTimer = undefined\n void this.enqueue(() => this.syncCurrent()).catch(error => { this.failed = error })\n }, this.options.syncIntervalMs)\n this.syncTimer.unref?.()\n }\n\n private async syncCurrent(): Promise<void> {\n if (this.current === undefined || this.unsyncedRecords === 0) return\n await this.current.handle.datasync()\n this.unsyncedRecords = 0\n this.unsyncedCritical = 0\n }\n\n private async ensureCapacity(root: string, incomingBytes: number, priority: string): Promise<void> {\n let total = await retainedBytes(root)\n if (total + incomingBytes <= this.options.maxRetainedBytes) return\n await this.cleanupNow(root)\n total = await retainedBytes(root)\n if (total + incomingBytes > this.options.maxRetainedBytes) throw journalFailure(\n 'io',\n priority === 'critical'\n ? 'runtime journal capacity contains unacknowledged critical records'\n : 'runtime journal capacity is exhausted',\n )\n }\n\n private async cleanupNow(root: string): Promise<void> {\n const recovered = await recoverRuntimeJournal(root)\n const bySegment = new Map<string, RuntimeJournalRecord[]>()\n for (const record of recovered.records) {\n const records = bySegment.get(record.segment) ?? []\n records.push(record)\n bySegment.set(record.segment, records)\n }\n const candidates: Array<{ name: string; bytes: number; mtimeMs: number; accepted: boolean }> = []\n for (const [name, records] of bySegment) {\n if (name === this.current?.name) continue\n const info = await stat(join(root, name))\n candidates.push({ name, bytes: info.size, mtimeMs: info.mtimeMs,\n accepted: records.every(record => this.accepted.has(record.key)) })\n }\n let retained = candidates.reduce((sum, value) => sum + value.bytes, this.current?.bytes ?? 0)\n let cursorChanged = false\n const now = validNow(this.options.now()).getTime()\n for (const candidate of candidates.sort((left, right) => left.mtimeMs - right.mtimeMs)) {\n if (!candidate.accepted) continue\n if (now - candidate.mtimeMs < this.options.acknowledgedRetentionMs\n && retained <= this.options.maxRetainedBytes) continue\n await unlink(join(root, candidate.name))\n retained -= candidate.bytes\n for (const record of bySegment.get(candidate.name) ?? []) {\n this.payloads.delete(record.key)\n if (this.accepted.delete(record.key)) cursorChanged = true\n }\n }\n if (cursorChanged) await this.persistCursor(root)\n if (retained > this.options.maxRetainedBytes) {\n throw journalFailure('io', 'runtime journal retention cap contains unacknowledged records')\n }\n }\n\n private async loadCursor(root: string): Promise<void> {\n try {\n const path = join(root, JOURNAL_FILES.runtimeCursor)\n const info = await lstat(path)\n if (!info.isFile() || info.isSymbolicLink() || info.size > JOURNAL_LIMITS.cursorBytes) throw new Error('unsafe cursor')\n const parsed = JSON.parse(await readFile(path, 'utf8')) as RuntimeCursor\n if (parsed.schemaVersion !== 1 || !Array.isArray(parsed.acceptedItemKeys)\n || parsed.acceptedItemKeys.some(key => typeof key !== 'string' || key.length === 0 || key.length > 256)) {\n throw new Error('invalid cursor')\n }\n for (const key of parsed.acceptedItemKeys) this.accepted.add(key)\n } catch (error) {\n if (typeof error === 'object' && error !== null && Reflect.get(error, 'code') === 'ENOENT') return\n throw journalFailure('corrupt', 'runtime journal cursor is corrupt', error)\n }\n }\n\n private async persistCursor(root: string): Promise<void> {\n const value = { schemaVersion: 1, acceptedItemKeys: [...this.accepted].sort() } satisfies RuntimeCursor\n if (Buffer.byteLength(JSON.stringify(value)) > JOURNAL_LIMITS.cursorBytes) {\n throw journalFailure('io', 'runtime journal cursor exceeds its persistence bound')\n }\n await atomicWriteJson(root, JOURNAL_FILES.runtimeCursor, value)\n }\n}\n\nexport async function recoverRuntimeJournal(root: string): Promise<RuntimeJournalRecoveryResult> {\n const names = (await readdir(root)).filter(name => name.endsWith('.jsonl')).sort()\n const records: RuntimeJournalRecord[] = []\n const payloads = new Map<string, string>()\n const truncatedSegments: string[] = []\n const quarantinedSegments: string[] = []\n for (const name of names) {\n const path = join(root, name)\n const info = await lstat(path)\n if (!info.isFile() || info.isSymbolicLink()) throw journalFailure('io', 'runtime journal segment is not a regular file')\n if (info.size > JOURNAL_LIMITS.recoverySegmentBytes) {\n throw journalFailure('corrupt', 'runtime journal segment exceeds recovery bound')\n }\n await chmod(path, 0o600)\n let text = await readFile(path, 'utf8')\n if (text.length > 0 && !text.endsWith('\\n')) {\n const boundary = text.lastIndexOf('\\n') + 1\n await truncate(path, Buffer.byteLength(text.slice(0, boundary)))\n text = text.slice(0, boundary)\n truncatedSegments.push(name)\n }\n const lines = text.length === 0 ? [] : text.slice(0, -1).split('\\n')\n const segmentRecords: RuntimeJournalRecord[] = []\n for (let index = 0; index < lines.length; index++) {\n try {\n const record = parseRuntimeJournalLine(lines[index] ?? '', name, index + 1)\n const previous = payloads.get(record.key)\n if (previous !== undefined && previous !== record.payloadJson) throw new Error('conflicting duplicate item')\n segmentRecords.push(record)\n } catch (error) {\n if (index !== lines.length - 1) {\n throw journalFailure('corrupt', `runtime journal segment ${name} has mid-file corruption`, error)\n }\n const quarantine = `${name}.corrupt-${Date.now()}`\n await rename(path, join(root, quarantine))\n quarantinedSegments.push(quarantine)\n segmentRecords.length = 0\n break\n }\n }\n for (const record of segmentRecords) {\n payloads.set(record.key, record.payloadJson)\n records.push(record)\n }\n }\n return deepFreeze({ records, truncatedSegments, quarantinedSegments })\n}\n\nfunction deliveryAck(batch: ObservationDeliveryBatch): ObservationDeliveryAck {\n return deepFreeze({\n batchId: batch.id,\n acceptedEventIds: batch.events.map(event => event.eventId),\n acceptedRunIds: batch.runRecords.map(record => record.runId),\n })\n}\n\nfunction abortIfRequested(signal: AbortSignal): void {\n if (signal.aborted) throw signal.reason ?? new Error('runtime observation journal aborted')\n}\n\nfunction sameList(left: readonly string[], right: readonly string[]): boolean {\n return left.length === right.length && left.every((value, index) => value === right[index])\n}\n\nfunction validNow(value: Date): Date {\n if (!(value instanceof Date) || Number.isNaN(value.getTime())) throw new TypeError('journal now must return a valid Date')\n return value\n}\n\nasync function retainedBytes(root: string): Promise<number> {\n const names = (await readdir(root)).filter(name => name.endsWith('.jsonl'))\n let total = 0\n for (const name of names) total += await stat(join(root, name)).then(value => value.size, () => 0)\n return total\n}\n","import {\n defineObservationExporter,\n type ObservationExporterPlugin,\n type ObservationExportItem,\n type ObservationDeliveryBatch,\n} from '@alvin0/ai-agent-sdk-core/observability'\nimport type { JsonlObservationJournalOptions } from './types.ts'\nimport { join } from 'node:path'\nimport { ensureSafeRoot } from '../common/safe-filesystem.ts'\nimport { JOURNAL_FILES } from './config.ts'\nimport { journalFailure } from './errors.ts'\nimport { captureRuntimeJournalOptions } from './runtime-options.ts'\nimport {\n RuntimeJsonlJournal,\n recoverRuntimeJournal,\n type RuntimeJournalRecoveryResult,\n} from './runtime-store.ts'\n\nexport type { RuntimeJournalRecoveryResult } from './runtime-store.ts'\nexport type { RuntimeJournalRecord as RuntimeJournalRecoveryRecord } from './runtime-frame.ts'\n\n/** Recommended runtime adapter. The advanced marker-free journal remains independent. */\nexport function jsonlObservationExporter(\n options: JsonlObservationJournalOptions,\n): ObservationExporterPlugin {\n const captured = captureRuntimeJournalOptions(options)\n let journal: RuntimeJsonlJournal | undefined\n let readiness: Promise<void> | undefined\n\n const ready = (signal: AbortSignal): Promise<void> => {\n if (readiness !== undefined) return readiness\n const created = new RuntimeJsonlJournal(captured)\n journal = created\n readiness = created.ready(signal)\n void readiness.catch(() => undefined)\n return readiness\n }\n\n const requiredJournal = (): RuntimeJsonlJournal => {\n if (journal === undefined) throw journalFailure('io', 'runtime observation exporter is not ready')\n return journal\n }\n\n return defineObservationExporter({\n id: captured.id,\n supportedBoundaries: captured.supportedBoundaries,\n ready,\n stage(item: ObservationExportItem) { return requiredJournal().stage(item) },\n export(batch: ObservationDeliveryBatch, signal: AbortSignal) {\n return requiredJournal().export(batch, signal)\n },\n async shutdown(signal: AbortSignal) {\n if (journal === undefined) return\n await readiness?.catch(() => undefined)\n await journal.shutdown(signal)\n },\n })\n}\n\n/** Verify and recover records written by the recommended runtime exporter. */\nexport async function recoverRuntimeObservationJournal(\n rootDir: string,\n): Promise<RuntimeJournalRecoveryResult> {\n const parent = await ensureSafeRoot(rootDir)\n const root = await ensureSafeRoot(join(parent, JOURNAL_FILES.runtimeDirectory))\n return recoverRuntimeJournal(root)\n}\n","import type { Observability } from '@alvin0/ai-agent-sdk-core/observability'\n\nexport interface NodeLifecycleTarget {\n on(event: 'beforeExit' | 'SIGINT' | 'SIGTERM', listener: () => void): unknown\n off(event: 'beforeExit' | 'SIGINT' | 'SIGTERM', listener: () => void): unknown\n}\n\nexport interface NodeLifecycleOptions {\n readonly target?: NodeLifecycleTarget\n readonly signals?: readonly ('SIGINT' | 'SIGTERM')[]\n readonly onFailure?: (error: unknown) => void\n}\n\n/** Install opt-in Node shutdown triggers and return an idempotent disposer. */\nexport function installNodeObservabilityLifecycle(\n observation: Pick<Observability, 'shutdown'>,\n options: NodeLifecycleOptions = {},\n): () => void {\n if (typeof observation?.shutdown !== 'function') throw new TypeError('Node lifecycle requires observability.shutdown')\n const target = options.target ?? process\n const events = Object.freeze(['beforeExit', ...(options.signals ?? [])] as const)\n let disposed = false\n let pending: Promise<unknown> | undefined\n const shutdown = () => {\n if (disposed || pending !== undefined) return\n try {\n pending = observation.shutdown()\n void pending.catch(error => {\n try { options.onFailure?.(error) } catch { /* user callback is contained */ }\n })\n } catch (error) {\n try { options.onFailure?.(error) } catch { /* user callback is contained */ }\n }\n }\n for (const event of events) target.on(event, shutdown)\n return () => {\n if (disposed) return\n disposed = true\n for (const event of events) target.off(event, shutdown)\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import { _ as JsonlObservationJournalOptions, a as NodeLifecycleTarget, c as recoverRuntimeObservationJournal, d as JournalRecoveryRecord, f as JournalRecoveryResult, g as JournalDurabilityMode, h as recoverJournal, i as NodeLifecycleOptions, l as RuntimeJournalRecoveryResult, m as JsonlObservationJournalExporter, n as NodeObservationError, o as installNodeObservabilityLifecycle, p as JournalStats, r as NodeObservationErrorCode, s as jsonlObservationExporter, t as NODE_OBSERVATION_ERROR_CODES, u as RuntimeJournalRecord } from "./journal-export-BMfSC4Z6.mjs";
2
+ export { type JournalDurabilityMode, type JournalRecoveryRecord, type JournalRecoveryResult, type JournalStats, JsonlObservationJournalExporter, type JsonlObservationJournalOptions, NODE_OBSERVATION_ERROR_CODES, type NodeLifecycleOptions, type NodeLifecycleTarget, NodeObservationError, type NodeObservationErrorCode, type RuntimeJournalRecord as RuntimeJournalRecoveryRecord, type RuntimeJournalRecoveryResult, installNodeObservabilityLifecycle, jsonlObservationExporter, recoverJournal, recoverRuntimeObservationJournal };
@@ -0,0 +1,4 @@
1
+ import { a as recoverJournal, i as JsonlObservationJournalExporter, n as jsonlObservationExporter, r as recoverRuntimeObservationJournal, t as installNodeObservabilityLifecycle } from "./journal-export-HAdAQxLv.mjs";
2
+ import { a as NodeObservationError, i as NODE_OBSERVATION_ERROR_CODES } from "./safe-filesystem-CbOPNSoN.mjs";
3
+
4
+ export { JsonlObservationJournalExporter, NODE_OBSERVATION_ERROR_CODES, NodeObservationError, installNodeObservabilityLifecycle, jsonlObservationExporter, recoverJournal, recoverRuntimeObservationJournal };
@@ -0,0 +1,100 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { chmod, lstat, mkdir, open, realpath, rename, unlink } from "node:fs/promises";
3
+ import { basename, dirname, join, resolve } from "node:path";
4
+ import { constants } from "node:fs";
5
+
6
+ //#region src/common/errors.ts
7
+ const NODE_OBSERVATION_ERROR_CODES = Object.freeze({
8
+ corrupt: "OBSERVABILITY_JOURNAL_CORRUPT",
9
+ io: "OBSERVABILITY_JOURNAL_IO"
10
+ });
11
+ var NodeObservationError = class extends Error {
12
+ name = "NodeObservationError";
13
+ code;
14
+ constructor(code, message, options) {
15
+ super(message, options);
16
+ this.code = code;
17
+ }
18
+ };
19
+
20
+ //#endregion
21
+ //#region src/common/safe-filesystem.ts
22
+ function ioError(message, error) {
23
+ if (error instanceof NodeObservationError) return error;
24
+ return new NodeObservationError(NODE_OBSERVATION_ERROR_CODES.io, message, { cause: error });
25
+ }
26
+ async function ensureSafeRoot(input) {
27
+ if (typeof input !== "string" || input.trim().length === 0) throw new TypeError("observation journal rootDir must be explicit and non-empty");
28
+ const requestedRoot = resolve(input);
29
+ try {
30
+ await mkdir(requestedRoot, {
31
+ recursive: true,
32
+ mode: 448
33
+ });
34
+ const requestedInfo = await lstat(requestedRoot);
35
+ if (!requestedInfo.isDirectory() || requestedInfo.isSymbolicLink()) throw new NodeObservationError(NODE_OBSERVATION_ERROR_CODES.io, "observation journal root must be a real directory");
36
+ const root = await realpath(requestedRoot);
37
+ const canonicalInfo = await lstat(root);
38
+ if (!canonicalInfo.isDirectory() || canonicalInfo.isSymbolicLink()) throw new NodeObservationError(NODE_OBSERVATION_ERROR_CODES.io, "observation journal root must resolve to a real directory");
39
+ await chmod(root, 448);
40
+ return root;
41
+ } catch (error) {
42
+ throw ioError("observation journal root validation failed", error);
43
+ }
44
+ }
45
+ async function openExclusiveFile(root, name) {
46
+ if (basename(name) !== name || !/^[A-Za-z0-9._-]+$/.test(name)) throw new TypeError("observation journal segment name is unsafe");
47
+ const path = join(root, name);
48
+ const noFollow = "O_NOFOLLOW" in constants ? constants.O_NOFOLLOW : 0;
49
+ try {
50
+ const handle = await open(path, constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL | constants.O_APPEND | noFollow, 384);
51
+ try {
52
+ const [opened, linked] = await Promise.all([handle.stat(), lstat(path)]);
53
+ if (!opened.isFile() || linked.isSymbolicLink() || opened.dev !== linked.dev || opened.ino !== linked.ino) throw new NodeObservationError(NODE_OBSERVATION_ERROR_CODES.io, "observation journal segment identity changed during open");
54
+ await chmod(path, 384);
55
+ return handle;
56
+ } catch (error) {
57
+ await handle.close().catch(() => void 0);
58
+ await unlink(path).catch(() => void 0);
59
+ throw error;
60
+ }
61
+ } catch (error) {
62
+ throw ioError("observation journal segment open failed", error);
63
+ }
64
+ }
65
+ async function atomicWriteJson(root, targetName, value) {
66
+ if (basename(targetName) !== targetName) throw new TypeError("atomic target name is unsafe");
67
+ const temporary = `${targetName}.tmp-${randomUUID()}`;
68
+ const target = join(root, targetName);
69
+ const handle = await openExclusiveFile(root, temporary);
70
+ try {
71
+ await handle.writeFile(JSON.stringify(value), "utf8");
72
+ await handle.sync();
73
+ } finally {
74
+ await handle.close();
75
+ }
76
+ try {
77
+ await rename(join(root, temporary), target);
78
+ await syncDirectory(dirname(target));
79
+ } catch (error) {
80
+ await unlink(join(root, temporary)).catch(() => void 0);
81
+ throw ioError("observation journal cursor commit failed", error);
82
+ }
83
+ }
84
+ async function syncDirectory(directory) {
85
+ let handle;
86
+ try {
87
+ handle = await open(directory, constants.O_RDONLY);
88
+ await handle.sync();
89
+ } catch (error) {
90
+ const code = typeof error === "object" && error !== null ? Reflect.get(error, "code") : void 0;
91
+ if (process.platform === "win32" && (code === "EISDIR" || code === "EPERM" || code === "EINVAL")) return;
92
+ throw error;
93
+ } finally {
94
+ await handle?.close().catch(() => void 0);
95
+ }
96
+ }
97
+
98
+ //#endregion
99
+ export { NodeObservationError as a, NODE_OBSERVATION_ERROR_CODES as i, ensureSafeRoot as n, openExclusiveFile as r, atomicWriteJson as t };
100
+ //# sourceMappingURL=safe-filesystem-CbOPNSoN.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"safe-filesystem-CbOPNSoN.mjs","names":[],"sources":["../src/common/errors.ts","../src/common/safe-filesystem.ts"],"sourcesContent":["export const NODE_OBSERVATION_ERROR_CODES = Object.freeze({\n corrupt: 'OBSERVABILITY_JOURNAL_CORRUPT',\n io: 'OBSERVABILITY_JOURNAL_IO',\n} as const)\n\nexport type NodeObservationErrorCode = typeof NODE_OBSERVATION_ERROR_CODES[keyof typeof NODE_OBSERVATION_ERROR_CODES]\n\nexport class NodeObservationError extends Error {\n override readonly name = 'NodeObservationError'\n readonly code: NodeObservationErrorCode\n\n constructor(code: NodeObservationErrorCode, message: string, options?: ErrorOptions) {\n super(message, options)\n this.code = code\n }\n}\n","import { randomUUID } from 'node:crypto'\nimport { constants } from 'node:fs'\nimport {\n chmod,\n lstat,\n mkdir,\n open,\n realpath,\n rename,\n unlink,\n type FileHandle,\n} from 'node:fs/promises'\nimport { basename, dirname, join, resolve } from 'node:path'\nimport { NODE_OBSERVATION_ERROR_CODES, NodeObservationError } from './errors.ts'\n\nfunction ioError(message: string, error: unknown): NodeObservationError {\n if (error instanceof NodeObservationError) return error\n return new NodeObservationError(NODE_OBSERVATION_ERROR_CODES.io, message, { cause: error })\n}\n\nexport async function ensureSafeRoot(input: string): Promise<string> {\n if (typeof input !== 'string' || input.trim().length === 0) {\n throw new TypeError('observation journal rootDir must be explicit and non-empty')\n }\n const requestedRoot = resolve(input)\n try {\n await mkdir(requestedRoot, { recursive: true, mode: 0o700 })\n const requestedInfo = await lstat(requestedRoot)\n if (!requestedInfo.isDirectory() || requestedInfo.isSymbolicLink()) throw new NodeObservationError(\n NODE_OBSERVATION_ERROR_CODES.io, 'observation journal root must be a real directory',\n )\n // Host-configured roots may include an operating-system alias such as\n // macOS /var -> /private/var. Canonicalize that trusted boundary once,\n // while continuing to reject a symlink as the final root component.\n const root = await realpath(requestedRoot)\n const canonicalInfo = await lstat(root)\n if (!canonicalInfo.isDirectory() || canonicalInfo.isSymbolicLink()) throw new NodeObservationError(\n NODE_OBSERVATION_ERROR_CODES.io, 'observation journal root must resolve to a real directory',\n )\n await chmod(root, 0o700)\n return root\n } catch (error) {\n throw ioError('observation journal root validation failed', error)\n }\n}\n\nexport async function openExclusiveFile(root: string, name: string): Promise<FileHandle> {\n if (basename(name) !== name || !/^[A-Za-z0-9._-]+$/.test(name)) {\n throw new TypeError('observation journal segment name is unsafe')\n }\n const path = join(root, name)\n const noFollow = 'O_NOFOLLOW' in constants ? constants.O_NOFOLLOW : 0\n try {\n const handle = await open(path, constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL\n | constants.O_APPEND | noFollow, 0o600)\n try {\n const [opened, linked] = await Promise.all([handle.stat(), lstat(path)])\n if (!opened.isFile() || linked.isSymbolicLink() || opened.dev !== linked.dev || opened.ino !== linked.ino) {\n throw new NodeObservationError(\n NODE_OBSERVATION_ERROR_CODES.io, 'observation journal segment identity changed during open',\n )\n }\n await chmod(path, 0o600)\n return handle\n } catch (error) {\n await handle.close().catch(() => undefined)\n await unlink(path).catch(() => undefined)\n throw error\n }\n } catch (error) {\n throw ioError('observation journal segment open failed', error)\n }\n}\n\nexport async function atomicWriteJson(root: string, targetName: string, value: unknown): Promise<void> {\n if (basename(targetName) !== targetName) throw new TypeError('atomic target name is unsafe')\n const temporary = `${targetName}.tmp-${randomUUID()}`\n const target = join(root, targetName)\n const handle = await openExclusiveFile(root, temporary)\n try {\n await handle.writeFile(JSON.stringify(value), 'utf8')\n await handle.sync()\n } finally {\n await handle.close()\n }\n try {\n await rename(join(root, temporary), target)\n await syncDirectory(dirname(target))\n } catch (error) {\n await unlink(join(root, temporary)).catch(() => undefined)\n throw ioError('observation journal cursor commit failed', error)\n }\n}\n\nasync function syncDirectory(directory: string): Promise<void> {\n let handle: FileHandle | undefined\n try {\n handle = await open(directory, constants.O_RDONLY)\n await handle.sync()\n } catch (error) {\n const code = typeof error === 'object' && error !== null ? Reflect.get(error, 'code') : undefined\n if (process.platform === 'win32' && (code === 'EISDIR' || code === 'EPERM' || code === 'EINVAL')) return\n throw error\n } finally {\n await handle?.close().catch(() => undefined)\n }\n}\n"],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,83 @@
1
+ {
2
+ "name": "@alvin0/ai-agent-sdk-observability-node",
3
+ "author": {
4
+ "name": "alvin0 - chaulamdinhai",
5
+ "email": "chaulamdinhai@gmail.com"
6
+ },
7
+ "version": "0.1.0",
8
+ "description": "Durable Node JSONL observation journal, recovery, lifecycle, and opt-in wire diagnostics",
9
+ "license": "MIT",
10
+ "repository": {
11
+ "type": "git",
12
+ "url": "git+https://github.com/alvin0/ai-agent-sdk.git",
13
+ "directory": "packages/observability-node"
14
+ },
15
+ "homepage": "https://github.com/alvin0/ai-agent-sdk/tree/main/packages/observability-node#readme",
16
+ "bugs": {
17
+ "url": "https://github.com/alvin0/ai-agent-sdk/issues"
18
+ },
19
+ "type": "module",
20
+ "sideEffects": false,
21
+ "files": [
22
+ "dist",
23
+ "README.md",
24
+ "LICENSE"
25
+ ],
26
+ "main": "./dist/index.mjs",
27
+ "types": "./dist/index.d.mts",
28
+ "exports": {
29
+ ".": {
30
+ "types": "./dist/index.d.mts",
31
+ "import": "./dist/index.mjs",
32
+ "default": "./dist/index.mjs"
33
+ },
34
+ "./journal": {
35
+ "types": "./dist/journal.d.mts",
36
+ "import": "./dist/journal.mjs",
37
+ "default": "./dist/journal.mjs"
38
+ },
39
+ "./diagnostic": {
40
+ "types": "./dist/diagnostic.d.mts",
41
+ "import": "./dist/diagnostic.mjs",
42
+ "default": "./dist/diagnostic.mjs"
43
+ },
44
+ "./package.json": "./package.json"
45
+ },
46
+ "publishConfig": {
47
+ "access": "public",
48
+ "provenance": true
49
+ },
50
+ "peerDependencies": {
51
+ "@alvin0/ai-agent-sdk-core": "^0.1.0"
52
+ },
53
+ "devDependencies": {
54
+ "@alvin0/ai-agent-sdk-core": "^0.1.0",
55
+ "@arethetypeswrong/cli": "0.18.5",
56
+ "@types/node": "26.4.0",
57
+ "publint": "0.3.24",
58
+ "tsdown": "0.22.14",
59
+ "typescript": "7.0.2",
60
+ "vitest": "4.1.11"
61
+ },
62
+ "engines": {
63
+ "node": ">=22.12"
64
+ },
65
+ "aiAgentSdk": {
66
+ "runtime": "node",
67
+ "coreApi": 1,
68
+ "roles": [
69
+ "observation-exporter",
70
+ "diagnostics"
71
+ ]
72
+ },
73
+ "scripts": {
74
+ "build": "tsdown",
75
+ "clean": "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true});require('node:fs').rmSync('artifacts',{recursive:true,force:true})\"",
76
+ "typecheck": "tsc --noEmit",
77
+ "test": "vitest run --config vitest.config.ts",
78
+ "pack": "pnpm pack --pack-destination artifacts",
79
+ "test:pack": "node scripts/test-packed.mts",
80
+ "check:publint": "publint",
81
+ "check:types": "attw --profile esm-only --pack ."
82
+ }
83
+ }