wiretap-llm 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.
package/README.md ADDED
@@ -0,0 +1,112 @@
1
+ # wiretap-llm
2
+
3
+ Telemetry client for sending LLM logs to your Wiretap instance.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install wiretap-llm
9
+ # or
10
+ bun add wiretap-llm
11
+ ```
12
+
13
+ ## Quick Start
14
+
15
+ ```ts
16
+ import { TelemetryClient, createId, toIso } from "wiretap-llm";
17
+
18
+ // Create client
19
+ const client = new TelemetryClient({
20
+ baseUrl: process.env.WIRETAP_BASE_URL!,
21
+ apiKey: process.env.WIRETAP_API_KEY!,
22
+ });
23
+
24
+ // Send a log
25
+ client.report({
26
+ id: createId(),
27
+ timestamp: toIso(new Date()),
28
+ project: "", // Inferred from API key
29
+ source: "openrouter",
30
+ method: "POST",
31
+ url: "https://openrouter.ai/api/v1/chat/completions",
32
+ path: "/v1/chat/completions",
33
+ model: "anthropic/claude-sonnet-4",
34
+ streamed: true,
35
+ timing: {
36
+ started_at: toIso(startTime),
37
+ ended_at: toIso(endTime),
38
+ duration_ms: endTime.getTime() - startTime.getTime(),
39
+ },
40
+ request: {
41
+ body_json: requestBody,
42
+ },
43
+ stream: {
44
+ output_text: "Hello!",
45
+ finish_reason: "stop",
46
+ usage: { prompt_tokens: 10, completion_tokens: 5 },
47
+ },
48
+ });
49
+
50
+ // On app shutdown
51
+ await client.shutdown();
52
+ ```
53
+
54
+ ## Configuration
55
+
56
+ ### TelemetryClient Options
57
+
58
+ | Option | Type | Required | Default | Description |
59
+ |--------|------|----------|---------|-------------|
60
+ | `baseUrl` | string | Yes | - | Your Wiretap instance URL |
61
+ | `apiKey` | string | Yes | - | Your Wiretap API key |
62
+ | `project` | string | No | - | Project slug (usually inferred from API key) |
63
+ | `environment` | string | No | - | Environment name (e.g., "production") |
64
+ | `defaultMetadata` | object | No | - | Metadata added to all logs |
65
+ | `timeoutMs` | number | No | 5000 | Request timeout |
66
+ | `maxBatchSize` | number | No | 25 | Max logs per batch |
67
+ | `flushIntervalMs` | number | No | 2000 | Auto-flush interval |
68
+ | `maxLogBytes` | number | No | 1000000 | Max log size before truncation |
69
+ | `onError` | function | No | - | Error handler |
70
+
71
+ ## API
72
+
73
+ ### `client.report(log: TelemetryLog)`
74
+
75
+ Queue a log for sending. Logs are batched and sent automatically.
76
+
77
+ ### `client.flush()`
78
+
79
+ Manually flush pending logs.
80
+
81
+ ### `client.shutdown()`
82
+
83
+ Flush remaining logs and stop the client. Call on app shutdown.
84
+
85
+ ## Helper Utilities
86
+
87
+ ```ts
88
+ import { createId, toIso, sanitizeHeaders, safeJsonParse } from "wiretap-llm";
89
+
90
+ // Generate unique ID
91
+ const id = createId(); // "abc123..."
92
+
93
+ // ISO timestamp
94
+ const ts = toIso(new Date()); // "2024-01-20T..."
95
+
96
+ // Remove sensitive headers
97
+ const headers = sanitizeHeaders(req.headers); // Strips auth headers
98
+
99
+ // Safe JSON parse
100
+ const { ok, value } = safeJsonParse(jsonString);
101
+ ```
102
+
103
+ ## Environment Variables
104
+
105
+ ```bash
106
+ WIRETAP_BASE_URL=https://your-wiretap-instance.com
107
+ WIRETAP_API_KEY=wt_your_api_key
108
+ ```
109
+
110
+ ## License
111
+
112
+ MIT
@@ -0,0 +1,35 @@
1
+ import type { JsonValue } from "./json";
2
+ import type { TelemetryLog } from "./types/telemetry";
3
+ export type TelemetryClientOptions = {
4
+ baseUrl: string;
5
+ apiKey: string;
6
+ /** Optional - project is automatically inferred from API key on server */
7
+ project?: string;
8
+ environment?: string;
9
+ defaultMetadata?: Record<string, JsonValue>;
10
+ timeoutMs?: number;
11
+ maxBatchSize?: number;
12
+ flushIntervalMs?: number;
13
+ maxLogBytes?: number;
14
+ onError?: (err: unknown) => void;
15
+ };
16
+ export declare class TelemetryClient {
17
+ readonly baseUrl: string;
18
+ readonly apiKey: string;
19
+ readonly project?: string;
20
+ readonly environment?: string;
21
+ readonly defaultMetadata?: Record<string, JsonValue>;
22
+ private timeoutMs;
23
+ private maxBatchSize;
24
+ private flushIntervalMs;
25
+ private maxLogBytes;
26
+ private queue;
27
+ private flushing;
28
+ private timer;
29
+ private onError?;
30
+ constructor(opts: TelemetryClientOptions);
31
+ report(log: TelemetryLog): void;
32
+ flush(): Promise<void>;
33
+ shutdown(): Promise<void>;
34
+ }
35
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AAExC,OAAO,KAAK,EAAyB,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAE7E,MAAM,MAAM,sBAAsB,GAAG;IACnC,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,0EAA0E;IAC1E,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IAC5C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,IAAI,CAAC;CAClC,CAAC;AAEF,qBAAa,eAAe;IAC1B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IAErD,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,eAAe,CAAS;IAChC,OAAO,CAAC,WAAW,CAAS;IAE5B,OAAO,CAAC,KAAK,CAAsB;IACnC,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,KAAK,CAA+C;IAE5D,OAAO,CAAC,OAAO,CAAC,CAAyB;gBAE7B,IAAI,EAAE,sBAAsB;IAuBxC,MAAM,CAAC,GAAG,EAAE,YAAY,GAAG,IAAI;IAmCzB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IA0EtB,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;CAQhC"}
@@ -0,0 +1,6 @@
1
+ export { TelemetryClient } from "./client";
2
+ export type { TelemetryClientOptions } from "./client";
3
+ export type { TelemetryBatchPayload, TelemetryLog, TelemetryTrace, } from "./types/telemetry";
4
+ export { createId, safeJsonParse, sanitizeHeaders, toIso, truncateUtf8 } from "./json";
5
+ export type { JsonPrimitive, JsonValue } from "./json";
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAC3C,YAAY,EAAE,sBAAsB,EAAE,MAAM,UAAU,CAAC;AAGvD,YAAY,EACV,qBAAqB,EACrB,YAAY,EACZ,cAAc,GACf,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,eAAe,EAAE,KAAK,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AACvF,YAAY,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,192 @@
1
+ // src/json.ts
2
+ function toIso(d) {
3
+ return d.toISOString();
4
+ }
5
+ function createId() {
6
+ const c = globalThis.crypto;
7
+ if (c?.randomUUID)
8
+ return c.randomUUID();
9
+ return `id_${Date.now().toString(36)}_${Math.random().toString(36).slice(2)}`;
10
+ }
11
+ function safeJsonParse(text) {
12
+ try {
13
+ const v = JSON.parse(text);
14
+ return { ok: true, value: v };
15
+ } catch (e) {
16
+ return { ok: false, error: e instanceof Error ? e.message : "Invalid JSON" };
17
+ }
18
+ }
19
+ var SENSITIVE_HEADERS = new Set([
20
+ "authorization",
21
+ "cookie",
22
+ "set-cookie",
23
+ "x-api-key",
24
+ "api-key"
25
+ ]);
26
+ function sanitizeHeaders(headers) {
27
+ const out = {};
28
+ if (!headers)
29
+ return out;
30
+ const set = (k, v) => {
31
+ const key = k.toLowerCase();
32
+ if (SENSITIVE_HEADERS.has(key))
33
+ return;
34
+ out[key] = v;
35
+ };
36
+ if (headers instanceof Headers) {
37
+ headers.forEach((v, k) => set(k, v));
38
+ } else if (Array.isArray(headers)) {
39
+ for (const [k, v] of headers)
40
+ set(k, v);
41
+ } else {
42
+ for (const [k, v] of Object.entries(headers))
43
+ set(k, String(v));
44
+ }
45
+ return out;
46
+ }
47
+ function truncateUtf8(input, maxBytes) {
48
+ const enc = new TextEncoder;
49
+ const bytes = enc.encode(input);
50
+ if (bytes.length <= maxBytes)
51
+ return { text: input, truncated: false };
52
+ const sliced = bytes.slice(0, maxBytes);
53
+ const dec = new TextDecoder("utf-8", { fatal: false });
54
+ return { text: dec.decode(sliced), truncated: true };
55
+ }
56
+
57
+ // src/client.ts
58
+ class TelemetryClient {
59
+ baseUrl;
60
+ apiKey;
61
+ project;
62
+ environment;
63
+ defaultMetadata;
64
+ timeoutMs;
65
+ maxBatchSize;
66
+ flushIntervalMs;
67
+ maxLogBytes;
68
+ queue = [];
69
+ flushing = false;
70
+ timer = null;
71
+ onError;
72
+ constructor(opts) {
73
+ this.baseUrl = opts.baseUrl.replace(/\/+$/, "");
74
+ this.apiKey = opts.apiKey;
75
+ this.project = opts.project;
76
+ this.environment = opts.environment;
77
+ this.defaultMetadata = opts.defaultMetadata;
78
+ this.timeoutMs = opts.timeoutMs ?? 5000;
79
+ this.maxBatchSize = opts.maxBatchSize ?? 25;
80
+ this.flushIntervalMs = opts.flushIntervalMs ?? 2000;
81
+ this.maxLogBytes = opts.maxLogBytes ?? 1e6;
82
+ this.onError = opts.onError;
83
+ if (this.flushIntervalMs > 0) {
84
+ this.timer = setInterval(() => void this.flush(), this.flushIntervalMs);
85
+ if (typeof this.timer === "object" && "unref" in this.timer) {
86
+ this.timer.unref();
87
+ }
88
+ }
89
+ }
90
+ report(log) {
91
+ if (this.project) {
92
+ log.project = log.project || this.project;
93
+ }
94
+ log.environment = log.environment ?? this.environment;
95
+ if (this.defaultMetadata) {
96
+ log.metadata = { ...this.defaultMetadata, ...log.metadata ?? {} };
97
+ }
98
+ const raw = JSON.stringify(log);
99
+ const truncated = truncateUtf8(raw, this.maxLogBytes);
100
+ if (!truncated.truncated) {
101
+ this.queue.push(log);
102
+ } else {
103
+ this.queue.push({
104
+ ...log,
105
+ request: {
106
+ ...log.request,
107
+ body_text: "[truncated - log exceeded maxLogBytes]",
108
+ body_truncated: true
109
+ },
110
+ error: log.error ?? { message: "Log truncated to maxLogBytes" }
111
+ });
112
+ }
113
+ if (this.queue.length >= this.maxBatchSize) {
114
+ this.flush();
115
+ }
116
+ }
117
+ async flush() {
118
+ if (this.flushing)
119
+ return;
120
+ if (this.queue.length === 0)
121
+ return;
122
+ this.flushing = true;
123
+ const batch = this.queue.splice(0, this.maxBatchSize);
124
+ try {
125
+ const payload = { logs: batch };
126
+ const ctrl = new AbortController;
127
+ const t = setTimeout(() => ctrl.abort(), this.timeoutMs);
128
+ const res = await fetch(`${this.baseUrl}/v1/logs/batch`, {
129
+ method: "POST",
130
+ headers: {
131
+ "content-type": "application/json",
132
+ authorization: `Bearer ${this.apiKey}`
133
+ },
134
+ body: JSON.stringify(payload),
135
+ signal: ctrl.signal
136
+ });
137
+ clearTimeout(t);
138
+ if (res.status === 207) {
139
+ const body = await res.json().catch(() => null);
140
+ const failedIds = new Set;
141
+ if (body && typeof body === "object") {
142
+ const failed = body.failed;
143
+ if (Array.isArray(failed)) {
144
+ for (const item of failed) {
145
+ if (item && typeof item === "object") {
146
+ const id = item.id;
147
+ if (typeof id === "string") {
148
+ failedIds.add(id);
149
+ }
150
+ }
151
+ }
152
+ }
153
+ }
154
+ if (failedIds.size > 0) {
155
+ const retry = batch.filter((log) => failedIds.has(log.id));
156
+ if (retry.length > 0) {
157
+ this.queue.unshift(...retry);
158
+ }
159
+ }
160
+ const partialMessage = body && typeof body === "object" ? body.partial_success?.error_message : undefined;
161
+ const message = typeof partialMessage === "string" ? partialMessage : "Telemetry partial success";
162
+ this.onError?.(new Error(message));
163
+ return;
164
+ }
165
+ if (!res.ok) {
166
+ this.queue.unshift(...batch);
167
+ const errorText = await res.text().catch(() => "");
168
+ throw new Error(`Telemetry ingest failed: ${res.status} ${res.statusText} - ${errorText}`);
169
+ }
170
+ } catch (err) {
171
+ this.queue.unshift(...batch);
172
+ this.onError?.(err);
173
+ } finally {
174
+ this.flushing = false;
175
+ }
176
+ }
177
+ async shutdown() {
178
+ if (this.timer) {
179
+ clearInterval(this.timer);
180
+ this.timer = null;
181
+ }
182
+ await this.flush();
183
+ }
184
+ }
185
+ export {
186
+ truncateUtf8,
187
+ toIso,
188
+ sanitizeHeaders,
189
+ safeJsonParse,
190
+ createId,
191
+ TelemetryClient
192
+ };
package/dist/json.d.ts ADDED
@@ -0,0 +1,19 @@
1
+ export type JsonPrimitive = string | number | boolean | null;
2
+ export type JsonValue = JsonPrimitive | JsonValue[] | {
3
+ [key: string]: JsonValue;
4
+ };
5
+ export declare function toIso(d: Date): string;
6
+ export declare function createId(): string;
7
+ export declare function safeJsonParse(text: string): {
8
+ ok: true;
9
+ value: JsonValue;
10
+ } | {
11
+ ok: false;
12
+ error: string;
13
+ };
14
+ export declare function sanitizeHeaders(headers: HeadersInit | undefined): Record<string, string>;
15
+ export declare function truncateUtf8(input: string, maxBytes: number): {
16
+ text: string;
17
+ truncated: boolean;
18
+ };
19
+ //# sourceMappingURL=json.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json.d.ts","sourceRoot":"","sources":["../src/json.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC;AAC7D,MAAM,MAAM,SAAS,GAAG,aAAa,GAAG,SAAS,EAAE,GAAG;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,CAAC;AAEnF,wBAAgB,KAAK,CAAC,CAAC,EAAE,IAAI,GAAG,MAAM,CAErC;AAED,wBAAgB,QAAQ,IAAI,MAAM,CAIjC;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,SAAS,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAOzG;AAUD,wBAAgB,eAAe,CAAC,OAAO,EAAE,WAAW,GAAG,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAmBxF;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,OAAO,CAAA;CAAE,CAQlG"}
@@ -0,0 +1,56 @@
1
+ import type { JsonValue } from "../json";
2
+ export type TelemetryTrace = {
3
+ trace_id?: string;
4
+ span_id?: string;
5
+ parent_span_id?: string;
6
+ };
7
+ export type TelemetryLog = {
8
+ id: string;
9
+ timestamp: string;
10
+ project: string;
11
+ environment?: string;
12
+ source: string;
13
+ method: string;
14
+ url: string;
15
+ path: string;
16
+ model?: string;
17
+ generation_id?: string;
18
+ streamed: boolean;
19
+ timing: {
20
+ started_at: string;
21
+ ended_at?: string;
22
+ duration_ms?: number;
23
+ };
24
+ metadata?: Record<string, JsonValue>;
25
+ trace?: TelemetryTrace;
26
+ request: {
27
+ headers?: Record<string, string>;
28
+ body_json?: JsonValue;
29
+ body_text?: string;
30
+ body_truncated?: boolean;
31
+ };
32
+ response?: {
33
+ status: number;
34
+ headers?: Record<string, string>;
35
+ body_json?: JsonValue;
36
+ body_text?: string;
37
+ body_truncated?: boolean;
38
+ };
39
+ stream?: {
40
+ sse_events?: JsonValue[];
41
+ sse_events_truncated?: boolean;
42
+ output_text?: string;
43
+ tool_calls?: JsonValue;
44
+ finish_reason?: string | null;
45
+ usage?: JsonValue;
46
+ };
47
+ usage?: JsonValue;
48
+ error?: {
49
+ message: string;
50
+ stack?: string;
51
+ };
52
+ };
53
+ export type TelemetryBatchPayload = {
54
+ logs: TelemetryLog[];
55
+ };
56
+ //# sourceMappingURL=telemetry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"telemetry.d.ts","sourceRoot":"","sources":["../../src/types/telemetry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAEzC,MAAM,MAAM,cAAc,GAAG;IAC3B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAElB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IAEb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,EAAE,OAAO,CAAC;IAElB,MAAM,EAAE;QACN,UAAU,EAAE,MAAM,CAAC;QACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,WAAW,CAAC,EAAE,MAAM,CAAC;KACtB,CAAC;IAEF,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IACrC,KAAK,CAAC,EAAE,cAAc,CAAC;IAEvB,OAAO,EAAE;QACP,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACjC,SAAS,CAAC,EAAE,SAAS,CAAC;QACtB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,cAAc,CAAC,EAAE,OAAO,CAAC;KAC1B,CAAC;IAEF,QAAQ,CAAC,EAAE;QACT,MAAM,EAAE,MAAM,CAAC;QACf,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACjC,SAAS,CAAC,EAAE,SAAS,CAAC;QACtB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,cAAc,CAAC,EAAE,OAAO,CAAC;KAC1B,CAAC;IAEF,MAAM,CAAC,EAAE;QACP,UAAU,CAAC,EAAE,SAAS,EAAE,CAAC;QACzB,oBAAoB,CAAC,EAAE,OAAO,CAAC;QAC/B,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,UAAU,CAAC,EAAE,SAAS,CAAC;QACvB,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAC9B,KAAK,CAAC,EAAE,SAAS,CAAC;KACnB,CAAC;IAEF,KAAK,CAAC,EAAE,SAAS,CAAC;IAElB,KAAK,CAAC,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAC7C,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG;IAClC,IAAI,EAAE,YAAY,EAAE,CAAC;CACtB,CAAC"}
package/package.json ADDED
@@ -0,0 +1,52 @@
1
+ {
2
+ "name": "wiretap-llm",
3
+ "version": "0.1.0",
4
+ "description": "Telemetry client for sending LLM logs to Wiretap",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "import": "./dist/index.js",
12
+ "types": "./dist/index.d.ts"
13
+ }
14
+ },
15
+ "files": [
16
+ "dist",
17
+ "README.md"
18
+ ],
19
+ "scripts": {
20
+ "build": "bun build ./src/index.ts --outdir ./dist --target node && tsc --emitDeclarationOnly",
21
+ "dev": "bun build ./src/index.ts --outdir ./dist --target node --watch",
22
+ "typecheck": "tsc --noEmit",
23
+ "prepublishOnly": "bun run build"
24
+ },
25
+ "keywords": [
26
+ "llm",
27
+ "telemetry",
28
+ "openrouter",
29
+ "openai",
30
+ "observability",
31
+ "monitoring",
32
+ "ai",
33
+ "wiretap"
34
+ ],
35
+ "author": "Saint",
36
+ "license": "MIT",
37
+ "repository": {
38
+ "type": "git",
39
+ "url": "git+https://github.com/kingbootoshi/wiretap.git",
40
+ "directory": "packages/sdk"
41
+ },
42
+ "bugs": {
43
+ "url": "https://github.com/kingbootoshi/wiretap/issues"
44
+ },
45
+ "homepage": "https://github.com/kingbootoshi/wiretap/tree/main/packages/sdk#readme",
46
+ "engines": {
47
+ "node": ">=18"
48
+ },
49
+ "devDependencies": {
50
+ "typescript": "^5.7.2"
51
+ }
52
+ }