@fluxgate/sdk 0.0.2-dev.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/LICENSE ADDED
@@ -0,0 +1,7 @@
1
+ Copyright (c) 2026 [Your Name or Organization]
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4
+
5
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6
+
7
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,341 @@
1
+ # @fluxgate/sdk
2
+
3
+ ![Status: In Development](https://img.shields.io/badge/status-in%20development-orange)
4
+
5
+ Core tracking functionality for FluxGate. This package provides the base `FluxGate` class that sends usage data to the FluxGate API.
6
+
7
+ ## 📦 Installation
8
+
9
+ ```bash
10
+ npm install @fluxgate/sdk
11
+ ```
12
+
13
+ ## 🚀 Quick Start
14
+
15
+ ```typescript
16
+ import { FluxGate } from "@fluxgate/sdk";
17
+
18
+ const fluxgate = new FluxGate({
19
+ apiKey: process.env.FLUXGATE_API_KEY,
20
+ endpoint: "https://fluxgate.app/api/events", // optional
21
+ timeout: 5000, // optional, default: 5000ms
22
+ debug: false, // optional, default: false
23
+ });
24
+
25
+ // Record a usage event
26
+ const response = await fluxgate.recordEvent({
27
+ usage: {
28
+ inputTokens: 100,
29
+ outputTokens: 50,
30
+ cachedTokens: 20,
31
+ model: "gpt-4",
32
+ provider: "openai",
33
+ latencyInMs: 1500,
34
+ isStreamed: false,
35
+ },
36
+ status: "SUCCESS",
37
+ metadata: {
38
+ feature: "chatbot",
39
+ user: "user-123",
40
+ sessionId: "session-456",
41
+ },
42
+ });
43
+
44
+ console.log(response);
45
+ // { id: "event-123", createdAt: "2026-05-05T...", cost: 0.001 }
46
+ ```
47
+
48
+ ## 📖 API Reference
49
+
50
+ ### `FluxGate`
51
+
52
+ The main class for tracking LLM usage events.
53
+
54
+ #### Constructor
55
+
56
+ ```typescript
57
+ new FluxGate(config: FluxGateConfig)
58
+ ```
59
+
60
+ **Configuration Options:**
61
+
62
+ | Option | Type | Required | Default | Description |
63
+ | ---------- | --------- | -------- | --------------------------------- | ------------------------------- |
64
+ | `apiKey` | `string` | ✅ | - | Your FluxGate API key |
65
+ | `endpoint` | `string` | ❌ | `https://fluxgate.app/api/events` | API endpoint URL |
66
+ | `timeout` | `number` | ❌ | `5000` | Request timeout in milliseconds |
67
+ | `debug` | `boolean` | ❌ | `false` | Enable debug logging |
68
+
69
+ #### Methods
70
+
71
+ ##### `recordEvent(event: LLMEvent)`
72
+
73
+ Records a usage event to FluxGate.
74
+
75
+ **Parameters:**
76
+
77
+ ```typescript
78
+ interface LLMEvent {
79
+ usage: AiEventUsage;
80
+ status?: AiEventStatus | { status: AiEventStatus; errorMessage?: string };
81
+ metadata?: AiEventMetadata;
82
+ }
83
+ ```
84
+
85
+ **Usage Object:**
86
+
87
+ ```typescript
88
+ interface AiEventUsage {
89
+ inputTokens: number;
90
+ outputTokens: number;
91
+ cachedTokens?: number;
92
+ model?: string;
93
+ provider?: string;
94
+ latencyInMs?: number;
95
+ isStreamed?: boolean;
96
+ streamingDurationInMs?: number;
97
+ }
98
+ ```
99
+
100
+ **Status Types:**
101
+
102
+ ```typescript
103
+ type AiEventStatus =
104
+ | "SUCCESS"
105
+ | "ERROR"
106
+ | "BLOCKED"
107
+ | "MAX_TOKENS"
108
+ | "CONTENT_FILTER"
109
+ | "RECITATION"
110
+ | "MALFORMED_REQUEST";
111
+ ```
112
+
113
+ **Metadata Object:**
114
+
115
+ ```typescript
116
+ interface AiEventMetadata {
117
+ feature?: string;
118
+ step?: string;
119
+ user?: string | TrackedUser;
120
+ sessionId?: string;
121
+ conversationId?: string;
122
+ [key: string]: unknown; // Custom fields allowed
123
+ }
124
+
125
+ interface TrackedUser {
126
+ id: string;
127
+ name?: string;
128
+ email?: string;
129
+ image?: string;
130
+ monthlyRevenue?: number;
131
+ }
132
+ ```
133
+
134
+ **Returns:**
135
+
136
+ ```typescript
137
+ Promise<CreateAiEventResponse | null>;
138
+
139
+ interface CreateAiEventResponse {
140
+ id: string;
141
+ createdAt: string;
142
+ cost: number | null;
143
+ }
144
+ ```
145
+
146
+ ## 💡 Usage Examples
147
+
148
+ ### Basic Usage
149
+
150
+ ```typescript
151
+ const fluxgate = new FluxGate({
152
+ apiKey: "your-api-key",
153
+ });
154
+
155
+ await fluxgate.recordEvent({
156
+ usage: {
157
+ inputTokens: 100,
158
+ outputTokens: 50,
159
+ },
160
+ status: "SUCCESS",
161
+ });
162
+ ```
163
+
164
+ ### With Full Metadata
165
+
166
+ ```typescript
167
+ await fluxgate.recordEvent({
168
+ usage: {
169
+ inputTokens: 200,
170
+ outputTokens: 150,
171
+ cachedTokens: 50,
172
+ model: "gpt-4-turbo",
173
+ provider: "openai",
174
+ latencyInMs: 2500,
175
+ isStreamed: true,
176
+ streamingDurationInMs: 3000,
177
+ },
178
+ status: "SUCCESS",
179
+ metadata: {
180
+ feature: "code-generation",
181
+ step: "implementation",
182
+ user: {
183
+ id: "user-123",
184
+ name: "John Doe",
185
+ email: "john@example.com",
186
+ monthlyRevenue: 99.99,
187
+ },
188
+ sessionId: "session-abc",
189
+ conversationId: "conv-xyz",
190
+ customField: "any custom data",
191
+ },
192
+ });
193
+ ```
194
+
195
+ ### Error Tracking
196
+
197
+ ```typescript
198
+ await fluxgate.recordEvent({
199
+ usage: {
200
+ inputTokens: 100,
201
+ outputTokens: 0,
202
+ },
203
+ status: {
204
+ status: "ERROR",
205
+ errorMessage: "API rate limit exceeded",
206
+ },
207
+ metadata: {
208
+ feature: "chatbot",
209
+ },
210
+ });
211
+ ```
212
+
213
+ ### With Debug Mode
214
+
215
+ ```typescript
216
+ const fluxgate = new FluxGate({
217
+ apiKey: "your-api-key",
218
+ debug: true, // Logs all events to console
219
+ });
220
+
221
+ await fluxgate.recordEvent({
222
+ usage: {
223
+ inputTokens: 100,
224
+ outputTokens: 50,
225
+ },
226
+ });
227
+ // [fluxgate] FluxGate initialized { endpoint: '...', timeout: 5000 }
228
+ // [fluxgate] Sending event to ...: { ... }
229
+ // [fluxgate] Event sent successfully. Status: 200. Response: { "id": "evt_...", ... }
230
+ ```
231
+
232
+ ### Custom Endpoint
233
+
234
+ ```typescript
235
+ const fluxgate = new FluxGate({
236
+ apiKey: "your-api-key",
237
+ endpoint: "https://your-custom-domain.com/api/track",
238
+ timeout: 10000,
239
+ });
240
+ ```
241
+
242
+ ## 🔧 Advanced Usage
243
+
244
+ ### Using with SDK Wrappers
245
+
246
+ This package is typically used through provider-specific wrappers:
247
+
248
+ - [`@fluxgate/openai`](../openai/README.md) - For OpenAI
249
+ - [`@fluxgate/gemini`](../gemini/README.md) - For Google Gemini
250
+ - [`@fluxgate/anthropic`](../anthropic/README.md) - For Anthropic
251
+
252
+ ### Direct Integration
253
+
254
+ If you're integrating a custom provider:
255
+
256
+ ```typescript
257
+ import { FluxGate, type LLMEvent } from "@fluxgate/sdk";
258
+
259
+ const fluxgate = new FluxGate({ apiKey: "your-api-key" });
260
+
261
+ async function trackMyCustomLLM(prompt: string) {
262
+ const start = performance.now();
263
+
264
+ try {
265
+ const response = await myCustomLLM.generate(prompt);
266
+
267
+ await fluxgate.recordEvent({
268
+ usage: {
269
+ inputTokens: response.inputTokens,
270
+ outputTokens: response.outputTokens,
271
+ model: "custom-model",
272
+ provider: "custom-provider",
273
+ latencyInMs: performance.now() - start,
274
+ },
275
+ status: "SUCCESS",
276
+ metadata: {
277
+ feature: "my-feature",
278
+ },
279
+ });
280
+
281
+ return response;
282
+ } catch (error) {
283
+ await fluxgate.recordEvent({
284
+ usage: {
285
+ inputTokens: 0,
286
+ outputTokens: 0,
287
+ },
288
+ status: {
289
+ status: "ERROR",
290
+ errorMessage: error.message,
291
+ },
292
+ });
293
+ throw error;
294
+ }
295
+ }
296
+ ```
297
+
298
+ ## 🛡️ Error Handling
299
+
300
+ The tracker is designed to never break your application:
301
+
302
+ - Network errors are caught and logged (in debug mode)
303
+ - Timeouts are handled gracefully
304
+ - Returns `null` if tracking fails
305
+ - Your main LLM calls continue regardless of tracking status
306
+
307
+ ```typescript
308
+ const result = await tracker.recordEvent(event);
309
+ if (result === null) {
310
+ // Tracking failed, but your app continues
311
+ console.log("Failed to track event");
312
+ }
313
+ ```
314
+
315
+ ## 📊 Type Exports
316
+
317
+ All types are exported for use in your application:
318
+
319
+ ```typescript
320
+ import type {
321
+ LLMEvent,
322
+ CreateAiEventResponse,
323
+ TrackedUser,
324
+ AiEventMetadata,
325
+ FluxGateCostTrackingResponse,
326
+ WithTracking,
327
+ AiEventStatus,
328
+ AiEventUsage,
329
+ ExtractedUsage,
330
+ FluxGateConfig,
331
+ } from "@fluxgate/sdk";
332
+ ```
333
+
334
+ ## 🔗 Related Packages
335
+
336
+ - [@fluxgate/openai](../openai) - OpenAI SDK wrapper
337
+ - [@fluxgate/gemini](../gemini) - Gemini SDK wrapper
338
+
339
+ ## 📝 License
340
+
341
+ MIT
@@ -0,0 +1,10 @@
1
+ import { CreateAiEventResponse, LLMEvent, FluxGateConfig } from "./types/types.js";
2
+ export declare class FluxGate {
3
+ private apiKey;
4
+ private endpoint;
5
+ private timeout;
6
+ private debug;
7
+ constructor(config: FluxGateConfig);
8
+ recordEvent(event: LLMEvent): Promise<CreateAiEventResponse | null>;
9
+ }
10
+ export type { LLMEvent, CreateAiEventResponse, TrackedUser, AiEventMetadata, FluxGateCostTrackingResponse, WithTracking, AiEventStatus, AiEventUsage, ExtractedUsage, FluxGateConfig, } from "./types/types.js";
package/dist/index.js ADDED
@@ -0,0 +1,72 @@
1
+ export class FluxGate {
2
+ constructor(config) {
3
+ if (!config.apiKey) {
4
+ throw new Error("FluxGate requires an apiKey in config");
5
+ }
6
+ this.apiKey = config.apiKey;
7
+ this.endpoint = config.endpoint || "https://fluxgate.app/api/events";
8
+ this.timeout = config.timeout || 5000;
9
+ this.debug = config.debug || false;
10
+ if (this.debug) {
11
+ console.log("[fluxgate] FluxGate initialized", {
12
+ endpoint: this.endpoint,
13
+ timeout: this.timeout,
14
+ });
15
+ }
16
+ }
17
+ async recordEvent(event) {
18
+ const controller = new AbortController();
19
+ if (this.debug) {
20
+ console.log(`[fluxgate] Sending event to ${this.endpoint}:`, JSON.stringify(event, null, 2));
21
+ }
22
+ if (!event.status) {
23
+ event.status = "SUCCESS";
24
+ }
25
+ const fetchPromise = fetch(this.endpoint, {
26
+ method: "POST",
27
+ headers: {
28
+ "Content-Type": "application/json",
29
+ Authorization: `Bearer ${this.apiKey}`,
30
+ "User-Agent": "@fluxgate/sdk/0.0.2-dev.0",
31
+ },
32
+ body: JSON.stringify(event),
33
+ signal: controller.signal,
34
+ });
35
+ const timeoutPromise = new Promise((_, reject) => {
36
+ setTimeout(() => {
37
+ controller.abort();
38
+ reject(new Error(`Request timeout after ${this.timeout}ms`));
39
+ }, this.timeout);
40
+ });
41
+ let response;
42
+ try {
43
+ response = await Promise.race([fetchPromise, timeoutPromise]);
44
+ }
45
+ catch (err) {
46
+ if (this.debug) {
47
+ console.error("[fluxgate] Network error sending event:", err);
48
+ }
49
+ return {
50
+ cost: 0,
51
+ createdAt: new Date().toISOString(),
52
+ id: "error-" + Math.random().toString(36).substring(2, 15),
53
+ status: "ERROR",
54
+ };
55
+ // throw err;
56
+ }
57
+ let trackingData = null;
58
+ try {
59
+ const text = await response.text();
60
+ trackingData = JSON.parse(text);
61
+ }
62
+ catch (error) {
63
+ if (this.debug) {
64
+ console.error("[fluxgate] Failed to parse response:", error);
65
+ }
66
+ }
67
+ if (this.debug) {
68
+ console.log(`[fluxgate] Event sent successfully. Status: ${response.status}. Response: ${JSON.stringify(trackingData)}`);
69
+ }
70
+ return trackingData;
71
+ }
72
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,257 @@
1
+ import { describe, it, expect, beforeEach, vi, afterEach } from "vitest";
2
+ import { FluxGate } from "./index.js";
3
+ describe("FluxGate", () => {
4
+ let instance;
5
+ const mockApiKey = "test-api-key";
6
+ const mockEndpoint = "https://test.example.com/api/events";
7
+ // Mock fetch globally
8
+ const originalFetch = global.fetch;
9
+ beforeEach(() => {
10
+ instance = new FluxGate({
11
+ apiKey: mockApiKey,
12
+ endpoint: mockEndpoint,
13
+ timeout: 5000,
14
+ debug: false,
15
+ });
16
+ // Mock fetch
17
+ global.fetch = vi.fn();
18
+ });
19
+ afterEach(() => {
20
+ global.fetch = originalFetch;
21
+ vi.restoreAllMocks();
22
+ });
23
+ describe("constructor", () => {
24
+ it("should throw error if apiKey is not provided", () => {
25
+ expect(() => new FluxGate({
26
+ apiKey: "",
27
+ })).toThrow("FluxGate requires an apiKey in config");
28
+ });
29
+ it("should use default endpoint if not provided", () => {
30
+ const defaultTracker = new FluxGate({ apiKey: "test" });
31
+ expect(defaultTracker).toBeDefined();
32
+ });
33
+ it("should use custom endpoint if provided", () => {
34
+ const customTracker = new FluxGate({
35
+ apiKey: "test",
36
+ endpoint: "https://custom.example.com",
37
+ });
38
+ expect(customTracker).toBeDefined();
39
+ });
40
+ it("should use default timeout if not provided", () => {
41
+ const defaultTracker = new FluxGate({ apiKey: "test" });
42
+ expect(defaultTracker).toBeDefined();
43
+ });
44
+ });
45
+ describe("recordEvent", () => {
46
+ it("should send event to the correct endpoint", async () => {
47
+ const mockResponse = {
48
+ id: "event-123",
49
+ createdAt: "2026-05-05T00:00:00Z",
50
+ cost: 0.001,
51
+ };
52
+ vi.mocked(fetch).mockResolvedValue({
53
+ status: 200,
54
+ statusText: "OK",
55
+ text: async () => JSON.stringify(mockResponse),
56
+ });
57
+ const event = {
58
+ usage: {
59
+ inputTokens: 100,
60
+ outputTokens: 50,
61
+ model: "gpt-4",
62
+ provider: "openai",
63
+ latencyInMs: 1000,
64
+ },
65
+ status: "SUCCESS",
66
+ metadata: {
67
+ feature: "chat",
68
+ user: "user-123",
69
+ },
70
+ };
71
+ const result = await instance.recordEvent(event);
72
+ expect(fetch).toHaveBeenCalledWith(mockEndpoint, expect.objectContaining({
73
+ method: "POST",
74
+ headers: expect.objectContaining({
75
+ "Content-Type": "application/json",
76
+ Authorization: `Bearer ${mockApiKey}`,
77
+ "User-Agent": "@fluxgate/sdk/0.0.2-dev.0",
78
+ }),
79
+ body: JSON.stringify(event),
80
+ }));
81
+ expect(result).toEqual(mockResponse);
82
+ });
83
+ it("should default status to SUCCESS if not provided", async () => {
84
+ vi.mocked(fetch).mockResolvedValue({
85
+ status: 200,
86
+ statusText: "OK",
87
+ text: async () => JSON.stringify({
88
+ id: "123",
89
+ createdAt: "2026-05-05T00:00:00Z",
90
+ cost: 0.001,
91
+ }),
92
+ });
93
+ const event = {
94
+ usage: {
95
+ inputTokens: 100,
96
+ outputTokens: 50,
97
+ },
98
+ };
99
+ await instance.recordEvent(event);
100
+ const callArgs = vi.mocked(fetch).mock.calls[0];
101
+ const body = JSON.parse(callArgs[1]?.body);
102
+ expect(body.status).toBe("SUCCESS");
103
+ });
104
+ it("should handle fetch errors gracefully", async () => {
105
+ const mockResponse = {
106
+ id: "event-123",
107
+ createdAt: "2026-05-05T00:00:00Z",
108
+ cost: 0.001,
109
+ };
110
+ vi.mocked(fetch).mockResolvedValue({
111
+ status: 500,
112
+ statusText: "Internal Server Error",
113
+ text: async () => JSON.stringify(mockResponse),
114
+ });
115
+ const event = {
116
+ usage: {
117
+ inputTokens: 100,
118
+ outputTokens: 50,
119
+ },
120
+ };
121
+ const result = await instance.recordEvent(event);
122
+ expect(result).toEqual(mockResponse);
123
+ });
124
+ it("should handle invalid JSON response", async () => {
125
+ vi.mocked(fetch).mockResolvedValue({
126
+ status: 200,
127
+ statusText: "OK",
128
+ text: async () => "invalid json",
129
+ });
130
+ const event = {
131
+ usage: {
132
+ inputTokens: 100,
133
+ outputTokens: 50,
134
+ },
135
+ };
136
+ const result = await instance.recordEvent(event);
137
+ expect(result).toBeNull();
138
+ });
139
+ it("should respect timeout setting", async () => {
140
+ const shortTimeoutTracker = new FluxGate({
141
+ apiKey: mockApiKey,
142
+ endpoint: mockEndpoint,
143
+ timeout: 100,
144
+ });
145
+ vi.mocked(fetch).mockImplementation(() => new Promise((resolve) => {
146
+ setTimeout(() => resolve({
147
+ status: 200,
148
+ statusText: "OK",
149
+ text: async () => JSON.stringify({}),
150
+ }), 1000);
151
+ }));
152
+ const event = {
153
+ usage: {
154
+ inputTokens: 100,
155
+ outputTokens: 50,
156
+ },
157
+ };
158
+ await expect(shortTimeoutTracker.recordEvent(event)).resolves.toHaveProperty("status", "ERROR");
159
+ });
160
+ it("should include complex metadata in the event", async () => {
161
+ vi.mocked(fetch).mockResolvedValue({
162
+ status: 200,
163
+ statusText: "OK",
164
+ text: async () => JSON.stringify({
165
+ id: "123",
166
+ createdAt: "2026-05-05T00:00:00Z",
167
+ cost: 0.001,
168
+ }),
169
+ });
170
+ const event = {
171
+ usage: {
172
+ inputTokens: 100,
173
+ outputTokens: 50,
174
+ cachedTokens: 20,
175
+ model: "gpt-4",
176
+ provider: "openai",
177
+ latencyInMs: 1500,
178
+ isStreamed: true,
179
+ streamingDurationInMs: 2000,
180
+ },
181
+ status: "SUCCESS",
182
+ metadata: {
183
+ feature: "chat",
184
+ step: "generation",
185
+ user: {
186
+ id: "user-123",
187
+ name: "Test User",
188
+ email: "test@example.com",
189
+ monthlyRevenue: 99.99,
190
+ },
191
+ sessionId: "session-456",
192
+ conversationId: "conv-789",
193
+ customField: "custom value",
194
+ },
195
+ };
196
+ await instance.recordEvent(event);
197
+ const callArgs = vi.mocked(fetch).mock.calls[0];
198
+ const body = JSON.parse(callArgs[1]?.body);
199
+ expect(body.usage).toEqual(event.usage);
200
+ expect(body.metadata).toEqual(event.metadata);
201
+ });
202
+ it("should handle status with error message", async () => {
203
+ vi.mocked(fetch).mockResolvedValue({
204
+ status: 200,
205
+ statusText: "OK",
206
+ text: async () => JSON.stringify({
207
+ id: "123",
208
+ createdAt: "2026-05-05T00:00:00Z",
209
+ cost: null,
210
+ }),
211
+ });
212
+ const event = {
213
+ usage: {
214
+ inputTokens: 100,
215
+ outputTokens: 0,
216
+ },
217
+ status: {
218
+ status: "ERROR",
219
+ errorMessage: "API call failed",
220
+ },
221
+ };
222
+ await instance.recordEvent(event);
223
+ const callArgs = vi.mocked(fetch).mock.calls[0];
224
+ const body = JSON.parse(callArgs[1]?.body);
225
+ expect(body.status).toEqual(event.status);
226
+ });
227
+ });
228
+ describe("debug mode", () => {
229
+ it("should log debug information when debug is enabled", async () => {
230
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
231
+ const debugTracker = new FluxGate({
232
+ apiKey: mockApiKey,
233
+ endpoint: mockEndpoint,
234
+ debug: true,
235
+ });
236
+ expect(consoleSpy).toHaveBeenCalledWith("[fluxgate] FluxGate initialized", expect.any(Object));
237
+ vi.mocked(fetch).mockResolvedValue({
238
+ status: 200,
239
+ statusText: "OK",
240
+ text: async () => JSON.stringify({
241
+ id: "123",
242
+ createdAt: "2026-05-05T00:00:00Z",
243
+ cost: 0.001,
244
+ }),
245
+ });
246
+ const event = {
247
+ usage: {
248
+ inputTokens: 100,
249
+ outputTokens: 50,
250
+ },
251
+ };
252
+ await debugTracker.recordEvent(event);
253
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("[fluxgate] Sending event"), expect.any(String));
254
+ consoleSpy.mockRestore();
255
+ });
256
+ });
257
+ });
@@ -0,0 +1,63 @@
1
+ export type AiEventStatus = "SUCCESS" | "ERROR" | "BLOCKED" | "MAX_TOKENS" | "CONTENT_FILTER" | "RECITATION" | "MALFORMED_REQUEST";
2
+ export type TrackedUser = {
3
+ id: string;
4
+ name?: string;
5
+ email?: string;
6
+ image?: string;
7
+ monthlyRevenue?: number;
8
+ };
9
+ export type AiEventUsage = {
10
+ inputTokens: number;
11
+ outputTokens: number;
12
+ cachedTokens?: number;
13
+ model?: string;
14
+ provider?: string;
15
+ latencyInMs?: number;
16
+ isStreamed?: boolean;
17
+ streamingDurationInMs?: number;
18
+ };
19
+ export type AiEventMetadata = {
20
+ feature?: string;
21
+ step?: string;
22
+ user?: string | TrackedUser;
23
+ sessionId?: string;
24
+ conversationId?: string;
25
+ timestamp?: Date;
26
+ [key: string]: unknown;
27
+ };
28
+ export type LLMEvent = {
29
+ usage: AiEventUsage;
30
+ status?: AiEventStatus | {
31
+ status: AiEventStatus;
32
+ errorMessage?: string;
33
+ };
34
+ metadata?: AiEventMetadata;
35
+ };
36
+ export type CreateAiEventResponse = {
37
+ id: string;
38
+ createdAt: string;
39
+ cost: number | null;
40
+ status: "SUCCESS" | "ERROR";
41
+ };
42
+ export interface FluxGateConfig {
43
+ apiKey: string;
44
+ endpoint?: string;
45
+ debug?: boolean;
46
+ timeout?: number;
47
+ }
48
+ export type FluxGateCostTrackingResponse = {
49
+ status: AiEventStatus;
50
+ cost: number | null;
51
+ trackingId: string | null;
52
+ createdAt: string | null;
53
+ errorMessage?: string;
54
+ };
55
+ export type WithTracking<T> = T & {
56
+ fluxGateCostTrackingResponse: FluxGateCostTrackingResponse;
57
+ };
58
+ export type ExtractedUsage = {
59
+ inputTokens: number;
60
+ outputTokens: number;
61
+ cachedTokens: number;
62
+ totalTokens: number;
63
+ };
@@ -0,0 +1 @@
1
+ export {};
package/package.json ADDED
@@ -0,0 +1,60 @@
1
+ {
2
+ "name": "@fluxgate/sdk",
3
+ "version": "0.0.2-dev.0",
4
+ "description": "Core tracking SDK for FluxGate token usage, latency, and cost monitoring.",
5
+ "main": "./dist/index.js",
6
+ "types": "./dist/index.d.ts",
7
+ "exports": {
8
+ ".": {
9
+ "import": "./dist/index.js",
10
+ "types": "./dist/index.d.ts"
11
+ },
12
+ "./types": {
13
+ "types": "./dist/types/types.d.ts"
14
+ }
15
+ },
16
+ "files": [
17
+ "dist"
18
+ ],
19
+ "sideEffects": false,
20
+ "scripts": {
21
+ "build": "tsc",
22
+ "dev": "tsc --watch",
23
+ "prepublishOnly": "npm run build",
24
+ "typecheck": "tsc --noEmit",
25
+ "test": "vitest run --root ../../",
26
+ "test:watch": "vitest --root ../../"
27
+ },
28
+ "keywords": [
29
+ "llm",
30
+ "tokens",
31
+ "tracker",
32
+ "openai",
33
+ "claude",
34
+ "gemini",
35
+ "monitoring",
36
+ "costs"
37
+ ],
38
+ "author": "FluxGate Team",
39
+ "license": "MIT",
40
+ "repository": {
41
+ "type": "git",
42
+ "url": "https://github.com/yehova73/fluxgate-npm.git",
43
+ "directory": "packages/sdk"
44
+ },
45
+ "bugs": {
46
+ "url": "https://github.com/yehova73/fluxgate-npm/issues"
47
+ },
48
+ "homepage": "https://fluxgate.app",
49
+ "publishConfig": {
50
+ "access": "public"
51
+ },
52
+ "devDependencies": {
53
+ "@types/node": "^20.11.0",
54
+ "typescript": "^5.3.3"
55
+ },
56
+ "type": "module",
57
+ "engines": {
58
+ "node": ">=18.0.0"
59
+ }
60
+ }