{"_id":"@accordkit/tracer","_rev":"2-914d282f119f139cd2c81fa01f609b76","name":"@accordkit/tracer","dist-tags":{"latest":"0.2.1"},"versions":{"0.2.0":{"name":"@accordkit/tracer","version":"0.2.0","_id":"@accordkit/tracer@0.2.0","maintainers":[{"name":"faranjit","email":"trkmen.blent@gmail.com"}],"dist":{"shasum":"3c0fdf6d61dd7bc0eba88c50951b9f610d4c1518","tarball":"https://registry.npmjs.org/@accordkit/tracer/-/tracer-0.2.0.tgz","fileCount":9,"integrity":"sha512-mjBV78mAjzvcWOOnNdbIzg1HrEa7Xf8oitKjV86IcPhMnoJuGnY6MA1ir6+CObMYSU24KIx9T7YhQIyJwnKkEw==","signatures":[{"sig":"MEQCIEGS5UwJGoGgLGCwsP2J8G8XP0lb1lNCHHysDJ2eiQmDAiByOOyihm36N8XEhwN+hIJ9HgT6yjKJCiUmFxatPSlHFQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":276664},"main":"dist/index.cjs","type":"module","types":"dist/index.d.ts","module":"dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"3b0576cc875fde77f9703fa784a596522e004bbc","scripts":{"dev":"tsup --watch --clean=false","docs":"typedoc --options typedoc.json","lint":"eslint .","test":"vitest run --reporter=dot","build":"tsup src/index.ts --format esm,cjs --dts","clean":"rimraf dist","format":"prettier --write .","lint:fix":"eslint . --fix","typecheck":"tsc -p tsconfig.json --noEmit","test:watch":"vitest"},"_npmUser":{"name":"faranjit","email":"trkmen.blent@gmail.com"},"_npmVersion":"11.6.0","description":"<p align=\"center\">   <img src=\"https://docs.accordkit.dev/img/logo.png\" height=\"80\"> </p>","directories":{},"sideEffects":false,"_nodeVersion":"24.9.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.1.0","eslint":"^9.38.0","rimraf":"^6.0.0","vitest":"^3.2.0","globals":"^16.4.0","typedoc":"^0.28.14","prettier":"^3.6.2","typescript":"^5.9.3","@types/node":"^24.8.0","fake-indexeddb":"^6.2.4","eslint-plugin-import":"^2.32.0","@vitest/eslint-plugin":"^1.3.23","eslint-config-prettier":"^10.1.8","typedoc-plugin-markdown":"^4.9.0","@typescript-eslint/parser":"^8.46.0","eslint-plugin-unused-imports":"^4.2.0","@typescript-eslint/eslint-plugin":"^8.46.0"},"_npmOperationalInternal":{"tmp":"tmp/tracer_0.2.0_1762116495607_0.17071318032594185","host":"s3://npm-registry-packages-npm-production"}},"0.2.1":{"name":"@accordkit/tracer","version":"0.2.1","description":"Lightweight, vendor-agnostic tracing core for AccordKit; designed for SDKs, AI agents, and self-hosted analytics. Provides a unified Tracer interface with message, usage, and span events that can be streamed or batched to any sink.","repository":{"type":"git","url":"git+https://github.com/accordkit/tracer.git","directory":"packages/tracer"},"bugs":{"url":"https://github.com/accordkit/tracer/issues"},"homepage":"https://github.com/accordkit/tracer/tree/main?tab=readme-ov-file","license":"MIT","type":"module","main":"dist/index.cjs","module":"dist/index.js","types":"dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"publishConfig":{"access":"public"},"sideEffects":false,"scripts":{"build":"tsup src/index.ts --format esm,cjs --dts","dev":"tsup --watch --clean=false","clean":"rimraf dist","typecheck":"tsc -p tsconfig.json --noEmit","test":"vitest run --coverage","test:watch":"vitest","docs":"typedoc --options typedoc.json","lint":"eslint . --max-warnings=0","lint:fix":"eslint . --fix","format":"prettier --write ."},"devDependencies":{"@types/node":"^24.8.0","@typescript-eslint/eslint-plugin":"^8.46.0","@typescript-eslint/parser":"^8.46.0","@vitest/coverage-v8":"3.2.4","@vitest/eslint-plugin":"^1.3.23","eslint":"^9.38.0","eslint-config-prettier":"^10.1.8","eslint-plugin-import":"^2.32.0","eslint-plugin-unused-imports":"^4.2.0","fake-indexeddb":"^6.2.4","globals":"^16.4.0","prettier":"^3.6.2","rimraf":"^6.0.0","tsup":"^8.1.0","typedoc":"^0.28.14","typedoc-plugin-markdown":"^4.9.0","typescript":"^5.9.3","vitest":"^3.2.0"},"_id":"@accordkit/tracer@0.2.1","gitHead":"975c4f7aa5b1ebc9ecf0f1bfb3fb89f7cbb381d5","_nodeVersion":"24.9.0","_npmVersion":"11.6.0","dist":{"integrity":"sha512-u1XAn3pF4e60bQpTzssigIsmqsCwFz9pApyRtW9mGtbNtnq1aq5PdExsZeA+0QVXwyyEBAFOMNh6ks5nqdA+GA==","shasum":"d768cc269223eeeaf8c0d82f2c42706fc70b11e4","tarball":"https://registry.npmjs.org/@accordkit/tracer/-/tracer-0.2.1.tgz","fileCount":9,"unpackedSize":277278,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQCTT9eCzciODLijnp6UEA0lA6oarB2IIqE98ZUXjb2nOAIgIIkL9xrARmzL8KjaZHV3y1SFSeDvmvPjH2g4pymep28="}]},"_npmUser":{"name":"faranjit","email":"trkmen.blent@gmail.com"},"directories":{},"maintainers":[{"name":"faranjit","email":"trkmen.blent@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/tracer_0.2.1_1762984876711_0.08125886797579307"},"_hasShrinkwrap":false}},"time":{"created":"2025-11-02T20:48:15.513Z","modified":"2025-11-12T22:01:17.078Z","0.2.0":"2025-11-02T20:48:15.832Z","0.2.1":"2025-11-12T22:01:16.888Z"},"description":"Lightweight, vendor-agnostic tracing core for AccordKit; designed for SDKs, AI agents, and self-hosted analytics. Provides a unified Tracer interface with message, usage, and span events that can be streamed or batched to any sink.","maintainers":[{"name":"faranjit","email":"trkmen.blent@gmail.com"}],"readme":"<p align=\"center\">\n  <img src=\"https://docs.accordkit.dev/img/logo.png\" height=\"80\">\n</p>\n\n<h1 align=\"center\">AccordKit - Tracer</h1>\n\n<p align=\"center\">\n  Tracing and observability core for AI & LLM applications.\n  <br />\n  <a href=\"https://docs.accordkit.dev\"><strong>📘 Read the docs</strong></a>\n</p>\n\n---\n\n[![Part of AccordKit](https://img.shields.io/badge/AccordKit-ecosystem-00cc88?style=flat-square)](https://github.com/accordkit)\n\n> **Part of the [AccordKit](https://github.com/accordkit) ecosystem**  \n> an open, AI-agnostic tracing SDK for LLM-powered and ChatGPT-interoperable applications.  \n> AccordKit gives developers local-first observability: **no vendor lock-in, no opaque dashboards**, just clean event streams and tools that work anywhere.\n\nLightweight, vendor-agnostic tracing core for AccordKit; designed for SDKs, AI agents, and self-hosted analytics.  \nProvides a unified `Tracer` interface with message, usage, and span events that can be streamed or batched to any sink.\n\n---\n\n### 🧭 Overview\nAccordKit Tracer provides a minimal, structured way to log, emit, and visualize events from your AI apps.\n\n- 📄 Local file and HTTP sinks  \n- 🔍 Compatible with any SDK  \n- ⚙️ Built-in OpenAI adapter via `@accordkit/provider-openai`\n\n## ✨ Features\n\n- **Unified tracing model** for messages, tool calls, spans, and usage.\n- **Parent–child span propagation** with accurate `durationMs`.\n- **Middleware pipeline** for sampling, transformation, or enrichment.\n- **Buffered and immediate sinks** with `flush()` / `close()` for graceful shutdowns.\n- **No vendor lock-in**; integrate with your own backend, file sink, or AccordKit Cloud.\n\n---\n\n## 📦 Installation\n\n```bash\npnpm add @accordkit/tracer\n# or\nnpm install @accordkit/tracer\n```\n\n## 🚀 QuickStart\n\n```ts\nimport { Tracer } from '@accordkit/tracer';\n\n// simplest usage\nconst tracer = new Tracer({\n  sink: { write: (_session, e) => console.log('trace event', e) },\n  service: 'demo-service',\n  env: 'dev',\n});\n\n// emit a message\nawait tracer.message({ role: 'user', content: 'hello, Trabzon!' });\n\n// start a span\nconst span = tracer.spanStart({ operation: 'db.query' });\n// ... perform some work ...\nawait tracer.spanEnd(span, { status: 'ok', attrs: { rows: 61 } });\n```\n\n## 🧩 Span Lifecycle\n\n```ts\nconst parent = tracer.spanStart({ operation: 'request' });\nconst child = tracer.spanStart({ operation: 'fetch.users', parent });\nawait tracer.spanEnd(child, { attrs: { count: 3 } });\nawait tracer.spanEnd(parent);\n```\n\nWhen a parent is provided, the new span inherits the parent’s traceId and sets its parentSpanId to the parent’s spanId.\n\nEach span produces a SpanEvent with:\n\n```ts\n{\n  type: 'span',\n  operation: string,\n  durationMs: number,\n  status: 'ok' | 'error',\n  ctx: { traceId, spanId, parentSpanId? },\n  service?: string,\n  env?: string,\n  region?: string,\n}\n```\n\n- ### 🧠 Types\n\n```ts\ninterface SpanToken {\n  ctx: { traceId: string; spanId: string; parentSpanId?: string };\n  operation: string;\n  service?: string;\n  env?: string;\n  region?: string;\n  attrs?: Record<string, unknown>;\n  t0: number;\n}\n\ninterface SpanStartOptions {\n  operation: string;\n  service?: string;\n  env?: string;\n  region?: string;\n  attrs?: Record<string, unknown>;\n  parent?:\n    | SpanToken\n    | { traceId: string; spanId: string }\n    | { ctx: { traceId: string; spanId: string } };\n}\n```\n\n## ⚙️ Middleware\n\nMiddleware functions can transform, enrich, or drop events before they reach the sink.\n\n```ts\nimport type { TraceMiddleware } from '@accordkit/tracer';\n\nconst redact: TraceMiddleware = (e) => {\n  if (e.type === 'message' && typeof e.content === 'string') {\n    e.content = e.content.replace(/secret/gi, '[REDACTED]');\n  }\n  return e;\n};\n\nconst tracer = new Tracer({ sink, middlewares: [redact] });\n```\n\n## 🧺 Choosing a Sink\n\nAll sinks implement `Sink` from `@accordkit/tracer`, exposing a single `write(sessionId, event)` method. Some sinks also implement `BufferedSink`, adding `flush()` and optional `close()` for controlled delivery.\n\n- **FileSink (Node.js)** – JSONL per session, optional buffered mode via `delivery: 'buffered'`.\n- **BrowserSink (Web)** – Persists to `localStorage` under `accordkit:{sessionId}`.\n- **HttpSink (Node.js / Web)** – Batches events to an HTTP endpoint; falls back to best effort delivery.\n\n`Tracer` only depends on the interface, so you can bring your own sink or test with an in-memory implementation.\n\n### Buffered vs Immediate Delivery\n\nBuffered sinks accumulate events before writing them out. Tracer forwards `flush()` and `close()` so your app can do:\n\n```ts\nawait tracer.flush(); // ensure buffered events are persisted\nawait tracer.close(); // close transport (if supported)\n```\n\nIf the sink lacks `close()`, the tracer falls back to `flush()`. For immediate sinks, both methods are no-ops.\n\n## Lifecycle Options\n\nregion is optional and propagated to all emitted events (useful for multi-region ingestion).\n\n```ts\nconst tracer = new Tracer({\n  sink: new HttpSink({ url: 'https://trace.ingest' }),\n  middlewares: [sample(0.1), maskPII()],\n  defaultLevel: 'warn',\n  sessionId: 'session-123', // optional override\n  service: 'support-bot',\n  env: 'prod',\n  region: 'us-east-1',\n});\n```\n\n- `defaultLevel` sets the log level for emitted events (`info` by default).\n- `sessionId` can be provided for deterministic sessions (otherwise generated).\n- `service`, `env`, and `region` tags propagate on every event.\n- `middlewares` run sequentially. Return `null` from a middleware to drop the event.\n\n## Emitting Events\n\n```ts\nawait tracer.message({ role: 'user', content: 'Hi there!' } as any);\nawait tracer.toolCall({ tool: 'weather', input: { city: 'AMS' } } as any);\nawait tracer.toolResult({ tool: 'weather', output: { temp: 12 }, ok: true } as any);\nawait tracer.usage({ inputTokens: 100, outputTokens: 18, cost: 0.02 } as any);\n```\n\nEach helper injects timestamps, session id, level, and (if needed) a fresh trace context.\n\n## Spans\n\n```ts\nconst parent = tracer.spanStart({ operation: 'db.query' });\nconst child = tracer.spanStart({ operation: 'cache.lookup', parent });\n\n/* ... */\n\nawait tracer.spanEnd(child, { status: 'ok' });\nawait tracer.spanEnd(parent, { status: 'error', attrs: { reason: 'timeout' } });\n```\n\n- `spanStart` returns `{ ctx, operation, t0, attrs }`. Reuse `ctx` on related events.\n- `spanEnd` computes `durationMs`, merges attributes provided at start and end, and defaults `status` to `ok`.\n\n## 🧪 Testing\n\nThis package ships with comprehensive Vitest coverage under tests/, validating:\n\n- span lifecycle and duration\n- parent propagation\n- middleware execution\n- sink buffering and idempotency\n- attribute merge and tag propagation\n\nRun:\n\n```bash\npnpm vitest\n```\n\nFor unit tests, supply a simple `Sink` double:\n\n```ts\nclass MemorySink {\n  events = [];\n  write(_sessionId, event) {\n    this.events.push(event);\n  }\n}\n\nconst tracer = new Tracer({ sink: new MemorySink() });\n```\n\nIf you need to assert `flush()`/`close()` calls, implement the `BufferedSink` interface in your test double.\n\n## Further Reading\n\n- Core event schema and sink details: `@accordkit/tracer` docs (`docs/CORE.md`).\n- Middleware helpers: `sample(rate)`, `maskPII()`, or roll your own by returning either a transformed event or `null`.\n- Full TypeScript signatures are documented via TSDoc; run `pnpm run docs` in the repo to generate API documentation.\n\n---\n\n### 🧱 Repository structure\n\nThis package is part of the [AccordKit](https://github.com/accordkit) organization:\n\n- [`@accordkit/provider-openai`](https://github.com/accordkit/provider-openai) — OpenAI API adapter with automatic trace streaming\n- [`@accordkit/viewer`](https://github.com/accordkit/viewer) — local-first viewer for traces\n- [`@accordkit/docs`](https://github.com/accordkit/docs) — developer documentation site\n- [`@accordkit/examples`](https://github.com/accordkit/examples) — sample integrations\n\n---\n\n## 🪪 License\n\nMIT © AccordKit Contributors\n\n## 🤝 Contributing\n\nIssues and PRs welcome!  \nPlease follow the [AccordKit Contribution Guide](https://github.com/accordkit/tracer/blob/main/CONTRIBUTING.md).\n","readmeFilename":"README.md","homepage":"https://github.com/accordkit/tracer/tree/main?tab=readme-ov-file","repository":{"type":"git","url":"git+https://github.com/accordkit/tracer.git","directory":"packages/tracer"},"bugs":{"url":"https://github.com/accordkit/tracer/issues"},"license":"MIT"}