tokenmeter 0.9.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 +21 -0
- package/README.md +346 -0
- package/dist/__tests__/context.test.d.ts +2 -0
- package/dist/__tests__/context.test.d.ts.map +1 -0
- package/dist/__tests__/context.test.js +94 -0
- package/dist/__tests__/context.test.js.map +1 -0
- package/dist/__tests__/elevenlabs.test.d.ts +2 -0
- package/dist/__tests__/elevenlabs.test.d.ts.map +1 -0
- package/dist/__tests__/elevenlabs.test.js +108 -0
- package/dist/__tests__/elevenlabs.test.js.map +1 -0
- package/dist/__tests__/fal.test.d.ts +2 -0
- package/dist/__tests__/fal.test.d.ts.map +1 -0
- package/dist/__tests__/fal.test.js +153 -0
- package/dist/__tests__/fal.test.js.map +1 -0
- package/dist/__tests__/pricing.test.d.ts +2 -0
- package/dist/__tests__/pricing.test.d.ts.map +1 -0
- package/dist/__tests__/pricing.test.js +76 -0
- package/dist/__tests__/pricing.test.js.map +1 -0
- package/dist/__tests__/recorder.test.d.ts +2 -0
- package/dist/__tests__/recorder.test.d.ts.map +1 -0
- package/dist/__tests__/recorder.test.js +133 -0
- package/dist/__tests__/recorder.test.js.map +1 -0
- package/dist/__tests__/storage.test.d.ts +2 -0
- package/dist/__tests__/storage.test.d.ts.map +1 -0
- package/dist/__tests__/storage.test.js +106 -0
- package/dist/__tests__/storage.test.js.map +1 -0
- package/dist/client/index.d.ts +8 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +7 -0
- package/dist/client/index.js.map +1 -0
- package/dist/config.d.ts +92 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +166 -0
- package/dist/config.js.map +1 -0
- package/dist/context.d.ts +80 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +131 -0
- package/dist/context.js.map +1 -0
- package/dist/exporter/PostgresExporter.d.ts +82 -0
- package/dist/exporter/PostgresExporter.d.ts.map +1 -0
- package/dist/exporter/PostgresExporter.js +237 -0
- package/dist/exporter/PostgresExporter.js.map +1 -0
- package/dist/exporter/index.d.ts +8 -0
- package/dist/exporter/index.d.ts.map +1 -0
- package/dist/exporter/index.js +7 -0
- package/dist/exporter/index.js.map +1 -0
- package/dist/index.d.ts +31 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +37 -0
- package/dist/index.js.map +1 -0
- package/dist/instrumentation/proxy.d.ts +26 -0
- package/dist/instrumentation/proxy.d.ts.map +1 -0
- package/dist/instrumentation/proxy.js +337 -0
- package/dist/instrumentation/proxy.js.map +1 -0
- package/dist/instrumentation/strategies/index.d.ts +55 -0
- package/dist/instrumentation/strategies/index.d.ts.map +1 -0
- package/dist/instrumentation/strategies/index.js +429 -0
- package/dist/instrumentation/strategies/index.js.map +1 -0
- package/dist/integrations/express/index.d.ts +137 -0
- package/dist/integrations/express/index.d.ts.map +1 -0
- package/dist/integrations/express/index.js +186 -0
- package/dist/integrations/express/index.js.map +1 -0
- package/dist/integrations/inngest/index.d.ts +222 -0
- package/dist/integrations/inngest/index.d.ts.map +1 -0
- package/dist/integrations/inngest/index.js +223 -0
- package/dist/integrations/inngest/index.js.map +1 -0
- package/dist/integrations/langfuse/index.d.ts +170 -0
- package/dist/integrations/langfuse/index.d.ts.map +1 -0
- package/dist/integrations/langfuse/index.js +225 -0
- package/dist/integrations/langfuse/index.js.map +1 -0
- package/dist/integrations/next/index.d.ts +138 -0
- package/dist/integrations/next/index.d.ts.map +1 -0
- package/dist/integrations/next/index.js +170 -0
- package/dist/integrations/next/index.js.map +1 -0
- package/dist/integrations/nextjs/index.d.ts +198 -0
- package/dist/integrations/nextjs/index.d.ts.map +1 -0
- package/dist/integrations/nextjs/index.js +181 -0
- package/dist/integrations/nextjs/index.js.map +1 -0
- package/dist/integrations/vercel-ai/index.d.ts +288 -0
- package/dist/integrations/vercel-ai/index.d.ts.map +1 -0
- package/dist/integrations/vercel-ai/index.js +260 -0
- package/dist/integrations/vercel-ai/index.js.map +1 -0
- package/dist/logger.d.ts +58 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +89 -0
- package/dist/logger.js.map +1 -0
- package/dist/pricing/catalog.d.ts +10 -0
- package/dist/pricing/catalog.d.ts.map +1 -0
- package/dist/pricing/catalog.js +297 -0
- package/dist/pricing/catalog.js.map +1 -0
- package/dist/pricing/index.d.ts +77 -0
- package/dist/pricing/index.d.ts.map +1 -0
- package/dist/pricing/index.js +251 -0
- package/dist/pricing/index.js.map +1 -0
- package/dist/pricing/manifest.d.ts +156 -0
- package/dist/pricing/manifest.d.ts.map +1 -0
- package/dist/pricing/manifest.js +381 -0
- package/dist/pricing/manifest.js.map +1 -0
- package/dist/pricing/manifest.json +12786 -0
- package/dist/pricing/providers/anthropic.json +253 -0
- package/dist/pricing/providers/bedrock.json +341 -0
- package/dist/pricing/providers/bfl.json +220 -0
- package/dist/pricing/providers/elevenlabs.json +142 -0
- package/dist/pricing/providers/fal.json +15866 -0
- package/dist/pricing/providers/google.json +346 -0
- package/dist/pricing/providers/openai.json +1035 -0
- package/dist/pricing/schema.d.ts +102 -0
- package/dist/pricing/schema.d.ts.map +1 -0
- package/dist/pricing/schema.js +56 -0
- package/dist/pricing/schema.js.map +1 -0
- package/dist/processor/TokenMeterProcessor.d.ts +55 -0
- package/dist/processor/TokenMeterProcessor.d.ts.map +1 -0
- package/dist/processor/TokenMeterProcessor.js +132 -0
- package/dist/processor/TokenMeterProcessor.js.map +1 -0
- package/dist/query/client.d.ts +61 -0
- package/dist/query/client.d.ts.map +1 -0
- package/dist/query/client.js +206 -0
- package/dist/query/client.js.map +1 -0
- package/dist/query/index.d.ts +8 -0
- package/dist/query/index.d.ts.map +1 -0
- package/dist/query/index.js +7 -0
- package/dist/query/index.js.map +1 -0
- package/dist/recorder.d.ts +74 -0
- package/dist/recorder.d.ts.map +1 -0
- package/dist/recorder.js +227 -0
- package/dist/recorder.js.map +1 -0
- package/dist/sdks/anthropic.d.ts +21 -0
- package/dist/sdks/anthropic.d.ts.map +1 -0
- package/dist/sdks/anthropic.js +258 -0
- package/dist/sdks/anthropic.js.map +1 -0
- package/dist/sdks/elevenlabs.d.ts +59 -0
- package/dist/sdks/elevenlabs.d.ts.map +1 -0
- package/dist/sdks/elevenlabs.js +192 -0
- package/dist/sdks/elevenlabs.js.map +1 -0
- package/dist/sdks/fal.d.ts +102 -0
- package/dist/sdks/fal.d.ts.map +1 -0
- package/dist/sdks/fal.js +306 -0
- package/dist/sdks/fal.js.map +1 -0
- package/dist/sdks/openai.d.ts +17 -0
- package/dist/sdks/openai.d.ts.map +1 -0
- package/dist/sdks/openai.js +191 -0
- package/dist/sdks/openai.js.map +1 -0
- package/dist/storage/interface.d.ts +15 -0
- package/dist/storage/interface.d.ts.map +1 -0
- package/dist/storage/interface.js +53 -0
- package/dist/storage/interface.js.map +1 -0
- package/dist/storage/prisma.d.ts +15 -0
- package/dist/storage/prisma.d.ts.map +1 -0
- package/dist/storage/prisma.js +135 -0
- package/dist/storage/prisma.js.map +1 -0
- package/dist/types.d.ts +206 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +45 -0
- package/dist/types.js.map +1 -0
- package/dist/vercel-ai/index.d.ts +89 -0
- package/dist/vercel-ai/index.d.ts.map +1 -0
- package/dist/vercel-ai/index.js +298 -0
- package/dist/vercel-ai/index.js.map +1 -0
- package/package.json +119 -0
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import { withCostTrace } from "../../context.js";
|
|
2
|
+
import { isInitialized } from "../../config.js";
|
|
3
|
+
/**
|
|
4
|
+
* Create an Express middleware that automatically sets up cost tracking context.
|
|
5
|
+
*
|
|
6
|
+
* This middleware wraps incoming requests with `withCostTrace()`, allowing
|
|
7
|
+
* any AI calls made during request handling to be automatically tracked.
|
|
8
|
+
*
|
|
9
|
+
* @param config - Configuration for extracting identifiers and metadata
|
|
10
|
+
* @returns An Express middleware function
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```typescript
|
|
14
|
+
* import express from 'express';
|
|
15
|
+
* import { init } from 'tokenmeter';
|
|
16
|
+
* import { tokenmeterMiddleware } from 'tokenmeter/express';
|
|
17
|
+
*
|
|
18
|
+
* init({ databaseUrl: process.env.DATABASE_URL });
|
|
19
|
+
*
|
|
20
|
+
* const app = express();
|
|
21
|
+
*
|
|
22
|
+
* app.use(tokenmeterMiddleware({
|
|
23
|
+
* getIdentifier: (req) => req.user?.id || req.headers['x-user-id'] as string,
|
|
24
|
+
* shouldTrack: (req) => req.path.startsWith('/api/'),
|
|
25
|
+
* }));
|
|
26
|
+
*
|
|
27
|
+
* app.post('/api/chat', async (req, res) => {
|
|
28
|
+
* // AI calls here are automatically tracked
|
|
29
|
+
* const result = await openai.chat.completions.create({ ... });
|
|
30
|
+
* res.json({ result });
|
|
31
|
+
* });
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
export function tokenmeterMiddleware(config) {
|
|
35
|
+
return (req, res, next) => {
|
|
36
|
+
// Check if tokenmeter is initialized
|
|
37
|
+
if (!isInitialized()) {
|
|
38
|
+
console.warn("[tokenmeter] Not initialized. Call init() before using middleware.");
|
|
39
|
+
next();
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
// Check if we should track this request
|
|
43
|
+
if (config.shouldTrack && !config.shouldTrack(req)) {
|
|
44
|
+
next();
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
// Get identifier
|
|
48
|
+
const identifier = config.getIdentifier(req);
|
|
49
|
+
if (!identifier) {
|
|
50
|
+
// No identifier - skip tracking but continue request
|
|
51
|
+
next();
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
// Build trace options
|
|
55
|
+
const traceOptions = {
|
|
56
|
+
identifier,
|
|
57
|
+
secondaryIdentifier: config.getSecondaryIdentifier?.(req) ?? undefined,
|
|
58
|
+
workflowId: config.getWorkflowId?.(req) ??
|
|
59
|
+
req.headers["x-request-id"] ??
|
|
60
|
+
crypto.randomUUID(),
|
|
61
|
+
workflowType: config.getWorkflowType?.(req) ?? undefined,
|
|
62
|
+
requestId: req.headers["x-request-id"] ?? undefined,
|
|
63
|
+
metadata: {
|
|
64
|
+
...config.getMetadata?.(req),
|
|
65
|
+
path: req.path,
|
|
66
|
+
method: req.method,
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
// Wrap the request handling in a cost trace context
|
|
70
|
+
// We need to handle this differently since Express uses callbacks
|
|
71
|
+
void withCostTrace(traceOptions, async () => {
|
|
72
|
+
return new Promise((resolve, reject) => {
|
|
73
|
+
// Override next to resolve our promise when called
|
|
74
|
+
const wrappedNext = (err) => {
|
|
75
|
+
if (err) {
|
|
76
|
+
reject(err);
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
resolve();
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
// Call next to continue the middleware chain
|
|
83
|
+
// The actual next() should not be called until the response is sent
|
|
84
|
+
// So we need to hook into res.end or similar
|
|
85
|
+
// Store original end
|
|
86
|
+
const originalEnd = res.end.bind(res);
|
|
87
|
+
let ended = false;
|
|
88
|
+
// Override end to resolve our promise
|
|
89
|
+
res.end = function (...args) {
|
|
90
|
+
if (!ended) {
|
|
91
|
+
ended = true;
|
|
92
|
+
resolve();
|
|
93
|
+
}
|
|
94
|
+
return originalEnd(...args);
|
|
95
|
+
};
|
|
96
|
+
// Call next to continue
|
|
97
|
+
next();
|
|
98
|
+
});
|
|
99
|
+
}).catch((err) => {
|
|
100
|
+
// If there's an error, pass it to Express error handling
|
|
101
|
+
next(err);
|
|
102
|
+
});
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Wrap an async Express route handler with cost tracking.
|
|
107
|
+
*
|
|
108
|
+
* Use this for individual route handlers when you need more control than middleware.
|
|
109
|
+
*
|
|
110
|
+
* @param handler - The async route handler function
|
|
111
|
+
* @param getOptions - Function to extract trace options from the request
|
|
112
|
+
* @returns A wrapped route handler
|
|
113
|
+
*
|
|
114
|
+
* @example
|
|
115
|
+
* ```typescript
|
|
116
|
+
* import { withTokenmeter } from 'tokenmeter/express';
|
|
117
|
+
*
|
|
118
|
+
* const chatHandler = withTokenmeter(
|
|
119
|
+
* async (req, res) => {
|
|
120
|
+
* const result = await openai.chat.completions.create({ ... });
|
|
121
|
+
* res.json({ result });
|
|
122
|
+
* },
|
|
123
|
+
* (req) => ({
|
|
124
|
+
* identifier: req.user?.id || 'anonymous',
|
|
125
|
+
* workflowType: 'chat',
|
|
126
|
+
* })
|
|
127
|
+
* );
|
|
128
|
+
*
|
|
129
|
+
* app.post('/api/chat', chatHandler);
|
|
130
|
+
* ```
|
|
131
|
+
*/
|
|
132
|
+
export function withTokenmeter(handler, getOptions) {
|
|
133
|
+
return async (req, res, next) => {
|
|
134
|
+
if (!isInitialized()) {
|
|
135
|
+
console.warn("[tokenmeter] Not initialized. Call init() before using withTokenmeter.");
|
|
136
|
+
return handler(req, res, next);
|
|
137
|
+
}
|
|
138
|
+
try {
|
|
139
|
+
const options = await getOptions(req);
|
|
140
|
+
if (!options.identifier) {
|
|
141
|
+
return handler(req, res, next);
|
|
142
|
+
}
|
|
143
|
+
await withCostTrace(options, async () => {
|
|
144
|
+
await handler(req, res, next);
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
catch (err) {
|
|
148
|
+
next(err);
|
|
149
|
+
}
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Helper to extract common identifiers from Express request headers.
|
|
154
|
+
*/
|
|
155
|
+
export const headerExtractors = {
|
|
156
|
+
/**
|
|
157
|
+
* Get identifier from x-user-id header
|
|
158
|
+
*/
|
|
159
|
+
userId: (req) => req.headers["x-user-id"],
|
|
160
|
+
/**
|
|
161
|
+
* Get identifier from x-org-id header
|
|
162
|
+
*/
|
|
163
|
+
orgId: (req) => req.headers["x-org-id"],
|
|
164
|
+
/**
|
|
165
|
+
* Get identifier from x-api-key header
|
|
166
|
+
*/
|
|
167
|
+
apiKey: (req) => req.headers["x-api-key"],
|
|
168
|
+
/**
|
|
169
|
+
* Get identifier from Authorization header (Bearer token)
|
|
170
|
+
*/
|
|
171
|
+
bearerToken: (req) => {
|
|
172
|
+
const auth = req.headers.authorization;
|
|
173
|
+
if (auth?.startsWith("Bearer ")) {
|
|
174
|
+
return auth.slice(7);
|
|
175
|
+
}
|
|
176
|
+
return undefined;
|
|
177
|
+
},
|
|
178
|
+
/**
|
|
179
|
+
* Get request ID from common headers
|
|
180
|
+
*/
|
|
181
|
+
requestId: (req) => req.headers["x-request-id"] ||
|
|
182
|
+
req.headers["x-correlation-id"] ||
|
|
183
|
+
req.headers["x-trace-id"],
|
|
184
|
+
};
|
|
185
|
+
export default tokenmeterMiddleware;
|
|
186
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/integrations/express/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Inngest Integration
|
|
3
|
+
*
|
|
4
|
+
* Provides helpers for propagating trace context to and from Inngest functions.
|
|
5
|
+
*/
|
|
6
|
+
import type { TokenMeterAttributes } from "../../types.js";
|
|
7
|
+
/**
|
|
8
|
+
* Trace headers that can be passed in Inngest event metadata
|
|
9
|
+
*/
|
|
10
|
+
export interface TraceHeaders {
|
|
11
|
+
traceparent?: string;
|
|
12
|
+
tracestate?: string;
|
|
13
|
+
baggage?: string;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Inngest event with optional trace metadata
|
|
17
|
+
*/
|
|
18
|
+
export interface InngestEventWithTrace<T = unknown> {
|
|
19
|
+
name: string;
|
|
20
|
+
data: T;
|
|
21
|
+
/** Trace headers for context propagation */
|
|
22
|
+
trace?: TraceHeaders;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Options for creating traced Inngest events
|
|
26
|
+
*/
|
|
27
|
+
export interface CreateTracedEventOptions {
|
|
28
|
+
/** Additional attributes to include in the trace */
|
|
29
|
+
attributes?: TokenMeterAttributes;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Extract trace headers to include when sending an Inngest event.
|
|
33
|
+
*
|
|
34
|
+
* Call this in your API route before sending an Inngest event to propagate
|
|
35
|
+
* the trace context to the Inngest function.
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* ```typescript
|
|
39
|
+
* import { inngest } from './inngest';
|
|
40
|
+
* import { getInngestTraceHeaders } from 'tokenmeter/inngest';
|
|
41
|
+
*
|
|
42
|
+
* // In your API route
|
|
43
|
+
* export async function POST(req: Request) {
|
|
44
|
+
* const trace = getInngestTraceHeaders();
|
|
45
|
+
*
|
|
46
|
+
* await inngest.send({
|
|
47
|
+
* name: 'document/process',
|
|
48
|
+
* data: { documentId: '123' },
|
|
49
|
+
* trace, // Pass trace headers
|
|
50
|
+
* });
|
|
51
|
+
*
|
|
52
|
+
* return Response.json({ ok: true });
|
|
53
|
+
* }
|
|
54
|
+
* ```
|
|
55
|
+
*/
|
|
56
|
+
export declare function getInngestTraceHeaders(): TraceHeaders;
|
|
57
|
+
/**
|
|
58
|
+
* Create a traced Inngest event with trace headers included.
|
|
59
|
+
*
|
|
60
|
+
* This is a convenience wrapper that combines your event data with trace headers.
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* ```typescript
|
|
64
|
+
* import { inngest } from './inngest';
|
|
65
|
+
* import { createTracedEvent } from 'tokenmeter/inngest';
|
|
66
|
+
*
|
|
67
|
+
* await inngest.send(createTracedEvent({
|
|
68
|
+
* name: 'document/process',
|
|
69
|
+
* data: { documentId: '123' },
|
|
70
|
+
* }));
|
|
71
|
+
* ```
|
|
72
|
+
*/
|
|
73
|
+
export declare function createTracedEvent<T>(event: {
|
|
74
|
+
name: string;
|
|
75
|
+
data: T;
|
|
76
|
+
}, options?: CreateTracedEventOptions): InngestEventWithTrace<T>;
|
|
77
|
+
/**
|
|
78
|
+
* Run a function within the trace context from an Inngest event.
|
|
79
|
+
*
|
|
80
|
+
* Use this at the start of your Inngest function to resume the trace
|
|
81
|
+
* from the parent request.
|
|
82
|
+
*
|
|
83
|
+
* @example
|
|
84
|
+
* ```typescript
|
|
85
|
+
* import { inngest } from './inngest';
|
|
86
|
+
* import { withInngestTrace } from 'tokenmeter/inngest';
|
|
87
|
+
* import { monitor } from 'tokenmeter';
|
|
88
|
+
* import OpenAI from 'openai';
|
|
89
|
+
*
|
|
90
|
+
* const openai = monitor(new OpenAI());
|
|
91
|
+
*
|
|
92
|
+
* export const processDocument = inngest.createFunction(
|
|
93
|
+
* { id: 'process-document' },
|
|
94
|
+
* { event: 'document/process' },
|
|
95
|
+
* async ({ event }) => {
|
|
96
|
+
* return withInngestTrace(event, async () => {
|
|
97
|
+
* // All AI calls here are traced back to the original request
|
|
98
|
+
* const result = await openai.chat.completions.create({
|
|
99
|
+
* model: 'gpt-4o',
|
|
100
|
+
* messages: [{ role: 'user', content: 'Summarize this document' }],
|
|
101
|
+
* });
|
|
102
|
+
*
|
|
103
|
+
* return { summary: result.choices[0].message.content };
|
|
104
|
+
* });
|
|
105
|
+
* }
|
|
106
|
+
* );
|
|
107
|
+
* ```
|
|
108
|
+
*/
|
|
109
|
+
export declare function withInngestTrace<T>(event: {
|
|
110
|
+
trace?: TraceHeaders;
|
|
111
|
+
}, fn: () => Promise<T>): Promise<T>;
|
|
112
|
+
/**
|
|
113
|
+
* Run a function within trace context and with additional attributes.
|
|
114
|
+
*
|
|
115
|
+
* Combines trace context restoration with attribute setting for Inngest functions.
|
|
116
|
+
*
|
|
117
|
+
* @example
|
|
118
|
+
* ```typescript
|
|
119
|
+
* export const processDocument = inngest.createFunction(
|
|
120
|
+
* { id: 'process-document' },
|
|
121
|
+
* { event: 'document/process' },
|
|
122
|
+
* async ({ event }) => {
|
|
123
|
+
* return withInngestTraceAndAttributes(
|
|
124
|
+
* event,
|
|
125
|
+
* { 'workflow.type': 'document-processing' },
|
|
126
|
+
* async () => {
|
|
127
|
+
* // AI calls have both parent trace and custom attributes
|
|
128
|
+
* const result = await openai.chat.completions.create({...});
|
|
129
|
+
* return { result };
|
|
130
|
+
* }
|
|
131
|
+
* );
|
|
132
|
+
* }
|
|
133
|
+
* );
|
|
134
|
+
* ```
|
|
135
|
+
*/
|
|
136
|
+
export declare function withInngestTraceAndAttributes<T>(event: {
|
|
137
|
+
trace?: TraceHeaders;
|
|
138
|
+
}, attributes: TokenMeterAttributes, fn: () => Promise<T>): Promise<T>;
|
|
139
|
+
/**
|
|
140
|
+
* Inngest handler context type
|
|
141
|
+
*/
|
|
142
|
+
export interface InngestHandlerContext<TEvent = unknown> {
|
|
143
|
+
event: TEvent & {
|
|
144
|
+
trace?: TraceHeaders;
|
|
145
|
+
};
|
|
146
|
+
step: unknown;
|
|
147
|
+
[key: string]: unknown;
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Inngest handler function type
|
|
151
|
+
*/
|
|
152
|
+
export type InngestHandler<TEvent, TResult> = (ctx: InngestHandlerContext<TEvent>) => Promise<TResult>;
|
|
153
|
+
/**
|
|
154
|
+
* Wrap an Inngest function handler to automatically restore trace context.
|
|
155
|
+
*
|
|
156
|
+
* This is the recommended way to integrate TokenMeter with Inngest. It extracts
|
|
157
|
+
* trace headers from the event and runs your handler within that context.
|
|
158
|
+
*
|
|
159
|
+
* @example
|
|
160
|
+
* ```typescript
|
|
161
|
+
* import { inngest } from './inngest';
|
|
162
|
+
* import { withInngest } from 'tokenmeter/inngest';
|
|
163
|
+
* import { monitor } from 'tokenmeter';
|
|
164
|
+
* import OpenAI from 'openai';
|
|
165
|
+
*
|
|
166
|
+
* const openai = monitor(new OpenAI());
|
|
167
|
+
*
|
|
168
|
+
* export const processDocument = inngest.createFunction(
|
|
169
|
+
* { id: 'process-document' },
|
|
170
|
+
* { event: 'document/process' },
|
|
171
|
+
* withInngest(async ({ event, step }) => {
|
|
172
|
+
* // All AI calls here are traced back to the original request
|
|
173
|
+
* const result = await openai.chat.completions.create({
|
|
174
|
+
* model: 'gpt-4o',
|
|
175
|
+
* messages: [{ role: 'user', content: 'Summarize this document' }],
|
|
176
|
+
* });
|
|
177
|
+
*
|
|
178
|
+
* return { summary: result.choices[0].message.content };
|
|
179
|
+
* })
|
|
180
|
+
* );
|
|
181
|
+
* ```
|
|
182
|
+
*/
|
|
183
|
+
export declare function withInngest<TEvent, TResult>(handler: InngestHandler<TEvent, TResult>): InngestHandler<TEvent, TResult>;
|
|
184
|
+
/**
|
|
185
|
+
* Create Inngest middleware that automatically handles trace context.
|
|
186
|
+
*
|
|
187
|
+
* This middleware extracts trace headers from incoming events and sets up
|
|
188
|
+
* the context for all AI calls within the function.
|
|
189
|
+
*
|
|
190
|
+
* @example
|
|
191
|
+
* ```typescript
|
|
192
|
+
* import { Inngest } from 'inngest';
|
|
193
|
+
* import { createInngestMiddleware } from 'tokenmeter/inngest';
|
|
194
|
+
*
|
|
195
|
+
* export const inngest = new Inngest({
|
|
196
|
+
* id: 'my-app',
|
|
197
|
+
* middleware: [createInngestMiddleware()],
|
|
198
|
+
* });
|
|
199
|
+
* ```
|
|
200
|
+
*/
|
|
201
|
+
export declare function createInngestMiddleware(): {
|
|
202
|
+
name: string;
|
|
203
|
+
init(): {
|
|
204
|
+
onFunctionRun({ fn, ctx, }: {
|
|
205
|
+
fn: unknown;
|
|
206
|
+
ctx: {
|
|
207
|
+
event: {
|
|
208
|
+
trace?: TraceHeaders;
|
|
209
|
+
};
|
|
210
|
+
};
|
|
211
|
+
}): {
|
|
212
|
+
transformInput({ ctx: inputCtx, steps, }: {
|
|
213
|
+
ctx: unknown;
|
|
214
|
+
steps: unknown;
|
|
215
|
+
}): {
|
|
216
|
+
ctx: unknown;
|
|
217
|
+
steps: unknown;
|
|
218
|
+
};
|
|
219
|
+
};
|
|
220
|
+
};
|
|
221
|
+
};
|
|
222
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/integrations/inngest/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAOH,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAE3D;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,qBAAqB,CAAC,CAAC,GAAG,OAAO;IAChD,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,CAAC,CAAC;IACR,4CAA4C;IAC5C,KAAK,CAAC,EAAE,YAAY,CAAC;CACtB;AAED;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACvC,oDAAoD;IACpD,UAAU,CAAC,EAAE,oBAAoB,CAAC;CACnC;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,sBAAsB,IAAI,YAAY,CAErD;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,EACjC,KAAK,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,CAAC,CAAA;CAAE,EAChC,OAAO,CAAC,EAAE,wBAAwB,GACjC,qBAAqB,CAAC,CAAC,CAAC,CAK1B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAsB,gBAAgB,CAAC,CAAC,EACtC,KAAK,EAAE;IAAE,KAAK,CAAC,EAAE,YAAY,CAAA;CAAE,EAC/B,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GACnB,OAAO,CAAC,CAAC,CAAC,CAcZ;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAsB,6BAA6B,CAAC,CAAC,EACnD,KAAK,EAAE;IAAE,KAAK,CAAC,EAAE,YAAY,CAAA;CAAE,EAC/B,UAAU,EAAE,oBAAoB,EAChC,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GACnB,OAAO,CAAC,CAAC,CAAC,CAEZ;AAED;;GAEG;AACH,MAAM,WAAW,qBAAqB,CAAC,MAAM,GAAG,OAAO;IACrD,KAAK,EAAE,MAAM,GAAG;QAAE,KAAK,CAAC,EAAE,YAAY,CAAA;KAAE,CAAC;IACzC,IAAI,EAAE,OAAO,CAAC;IACd,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED;;GAEG;AACH,MAAM,MAAM,cAAc,CAAC,MAAM,EAAE,OAAO,IAAI,CAC5C,GAAG,EAAE,qBAAqB,CAAC,MAAM,CAAC,KAC/B,OAAO,CAAC,OAAO,CAAC,CAAC;AAEtB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,OAAO,EACzC,OAAO,EAAE,cAAc,CAAC,MAAM,EAAE,OAAO,CAAC,GACvC,cAAc,CAAC,MAAM,EAAE,OAAO,CAAC,CAgBjC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,uBAAuB;;;oCAQ5B;YACD,EAAE,EAAE,OAAO,CAAC;YACZ,GAAG,EAAE;gBAAE,KAAK,EAAE;oBAAE,KAAK,CAAC,EAAE,YAAY,CAAA;iBAAE,CAAA;aAAE,CAAC;SAC1C;sDAKM;gBACD,GAAG,EAAE,OAAO,CAAC;gBACb,KAAK,EAAE,OAAO,CAAC;aAChB;;;;;;EA2BZ"}
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Inngest Integration
|
|
3
|
+
*
|
|
4
|
+
* Provides helpers for propagating trace context to and from Inngest functions.
|
|
5
|
+
*/
|
|
6
|
+
import { extractTraceHeaders, withExtractedContext, withAttributes, } from "../../context.js";
|
|
7
|
+
/**
|
|
8
|
+
* Extract trace headers to include when sending an Inngest event.
|
|
9
|
+
*
|
|
10
|
+
* Call this in your API route before sending an Inngest event to propagate
|
|
11
|
+
* the trace context to the Inngest function.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```typescript
|
|
15
|
+
* import { inngest } from './inngest';
|
|
16
|
+
* import { getInngestTraceHeaders } from 'tokenmeter/inngest';
|
|
17
|
+
*
|
|
18
|
+
* // In your API route
|
|
19
|
+
* export async function POST(req: Request) {
|
|
20
|
+
* const trace = getInngestTraceHeaders();
|
|
21
|
+
*
|
|
22
|
+
* await inngest.send({
|
|
23
|
+
* name: 'document/process',
|
|
24
|
+
* data: { documentId: '123' },
|
|
25
|
+
* trace, // Pass trace headers
|
|
26
|
+
* });
|
|
27
|
+
*
|
|
28
|
+
* return Response.json({ ok: true });
|
|
29
|
+
* }
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
export function getInngestTraceHeaders() {
|
|
33
|
+
return extractTraceHeaders();
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Create a traced Inngest event with trace headers included.
|
|
37
|
+
*
|
|
38
|
+
* This is a convenience wrapper that combines your event data with trace headers.
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* ```typescript
|
|
42
|
+
* import { inngest } from './inngest';
|
|
43
|
+
* import { createTracedEvent } from 'tokenmeter/inngest';
|
|
44
|
+
*
|
|
45
|
+
* await inngest.send(createTracedEvent({
|
|
46
|
+
* name: 'document/process',
|
|
47
|
+
* data: { documentId: '123' },
|
|
48
|
+
* }));
|
|
49
|
+
* ```
|
|
50
|
+
*/
|
|
51
|
+
export function createTracedEvent(event, options) {
|
|
52
|
+
return {
|
|
53
|
+
...event,
|
|
54
|
+
trace: getInngestTraceHeaders(),
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Run a function within the trace context from an Inngest event.
|
|
59
|
+
*
|
|
60
|
+
* Use this at the start of your Inngest function to resume the trace
|
|
61
|
+
* from the parent request.
|
|
62
|
+
*
|
|
63
|
+
* @example
|
|
64
|
+
* ```typescript
|
|
65
|
+
* import { inngest } from './inngest';
|
|
66
|
+
* import { withInngestTrace } from 'tokenmeter/inngest';
|
|
67
|
+
* import { monitor } from 'tokenmeter';
|
|
68
|
+
* import OpenAI from 'openai';
|
|
69
|
+
*
|
|
70
|
+
* const openai = monitor(new OpenAI());
|
|
71
|
+
*
|
|
72
|
+
* export const processDocument = inngest.createFunction(
|
|
73
|
+
* { id: 'process-document' },
|
|
74
|
+
* { event: 'document/process' },
|
|
75
|
+
* async ({ event }) => {
|
|
76
|
+
* return withInngestTrace(event, async () => {
|
|
77
|
+
* // All AI calls here are traced back to the original request
|
|
78
|
+
* const result = await openai.chat.completions.create({
|
|
79
|
+
* model: 'gpt-4o',
|
|
80
|
+
* messages: [{ role: 'user', content: 'Summarize this document' }],
|
|
81
|
+
* });
|
|
82
|
+
*
|
|
83
|
+
* return { summary: result.choices[0].message.content };
|
|
84
|
+
* });
|
|
85
|
+
* }
|
|
86
|
+
* );
|
|
87
|
+
* ```
|
|
88
|
+
*/
|
|
89
|
+
export async function withInngestTrace(event, fn) {
|
|
90
|
+
const headers = {};
|
|
91
|
+
if (event.trace?.traceparent) {
|
|
92
|
+
headers.traceparent = event.trace.traceparent;
|
|
93
|
+
}
|
|
94
|
+
if (event.trace?.tracestate) {
|
|
95
|
+
headers.tracestate = event.trace.tracestate;
|
|
96
|
+
}
|
|
97
|
+
if (event.trace?.baggage) {
|
|
98
|
+
headers.baggage = event.trace.baggage;
|
|
99
|
+
}
|
|
100
|
+
return withExtractedContext(headers, fn);
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Run a function within trace context and with additional attributes.
|
|
104
|
+
*
|
|
105
|
+
* Combines trace context restoration with attribute setting for Inngest functions.
|
|
106
|
+
*
|
|
107
|
+
* @example
|
|
108
|
+
* ```typescript
|
|
109
|
+
* export const processDocument = inngest.createFunction(
|
|
110
|
+
* { id: 'process-document' },
|
|
111
|
+
* { event: 'document/process' },
|
|
112
|
+
* async ({ event }) => {
|
|
113
|
+
* return withInngestTraceAndAttributes(
|
|
114
|
+
* event,
|
|
115
|
+
* { 'workflow.type': 'document-processing' },
|
|
116
|
+
* async () => {
|
|
117
|
+
* // AI calls have both parent trace and custom attributes
|
|
118
|
+
* const result = await openai.chat.completions.create({...});
|
|
119
|
+
* return { result };
|
|
120
|
+
* }
|
|
121
|
+
* );
|
|
122
|
+
* }
|
|
123
|
+
* );
|
|
124
|
+
* ```
|
|
125
|
+
*/
|
|
126
|
+
export async function withInngestTraceAndAttributes(event, attributes, fn) {
|
|
127
|
+
return withInngestTrace(event, () => withAttributes(attributes, fn));
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Wrap an Inngest function handler to automatically restore trace context.
|
|
131
|
+
*
|
|
132
|
+
* This is the recommended way to integrate TokenMeter with Inngest. It extracts
|
|
133
|
+
* trace headers from the event and runs your handler within that context.
|
|
134
|
+
*
|
|
135
|
+
* @example
|
|
136
|
+
* ```typescript
|
|
137
|
+
* import { inngest } from './inngest';
|
|
138
|
+
* import { withInngest } from 'tokenmeter/inngest';
|
|
139
|
+
* import { monitor } from 'tokenmeter';
|
|
140
|
+
* import OpenAI from 'openai';
|
|
141
|
+
*
|
|
142
|
+
* const openai = monitor(new OpenAI());
|
|
143
|
+
*
|
|
144
|
+
* export const processDocument = inngest.createFunction(
|
|
145
|
+
* { id: 'process-document' },
|
|
146
|
+
* { event: 'document/process' },
|
|
147
|
+
* withInngest(async ({ event, step }) => {
|
|
148
|
+
* // All AI calls here are traced back to the original request
|
|
149
|
+
* const result = await openai.chat.completions.create({
|
|
150
|
+
* model: 'gpt-4o',
|
|
151
|
+
* messages: [{ role: 'user', content: 'Summarize this document' }],
|
|
152
|
+
* });
|
|
153
|
+
*
|
|
154
|
+
* return { summary: result.choices[0].message.content };
|
|
155
|
+
* })
|
|
156
|
+
* );
|
|
157
|
+
* ```
|
|
158
|
+
*/
|
|
159
|
+
export function withInngest(handler) {
|
|
160
|
+
return async (ctx) => {
|
|
161
|
+
const headers = {};
|
|
162
|
+
if (ctx.event?.trace?.traceparent) {
|
|
163
|
+
headers.traceparent = ctx.event.trace.traceparent;
|
|
164
|
+
}
|
|
165
|
+
if (ctx.event?.trace?.tracestate) {
|
|
166
|
+
headers.tracestate = ctx.event.trace.tracestate;
|
|
167
|
+
}
|
|
168
|
+
if (ctx.event?.trace?.baggage) {
|
|
169
|
+
headers.baggage = ctx.event.trace.baggage;
|
|
170
|
+
}
|
|
171
|
+
return withExtractedContext(headers, () => handler(ctx));
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Create Inngest middleware that automatically handles trace context.
|
|
176
|
+
*
|
|
177
|
+
* This middleware extracts trace headers from incoming events and sets up
|
|
178
|
+
* the context for all AI calls within the function.
|
|
179
|
+
*
|
|
180
|
+
* @example
|
|
181
|
+
* ```typescript
|
|
182
|
+
* import { Inngest } from 'inngest';
|
|
183
|
+
* import { createInngestMiddleware } from 'tokenmeter/inngest';
|
|
184
|
+
*
|
|
185
|
+
* export const inngest = new Inngest({
|
|
186
|
+
* id: 'my-app',
|
|
187
|
+
* middleware: [createInngestMiddleware()],
|
|
188
|
+
* });
|
|
189
|
+
* ```
|
|
190
|
+
*/
|
|
191
|
+
export function createInngestMiddleware() {
|
|
192
|
+
return {
|
|
193
|
+
name: "tokenmeter",
|
|
194
|
+
init() {
|
|
195
|
+
return {
|
|
196
|
+
onFunctionRun({ fn, ctx, }) {
|
|
197
|
+
return {
|
|
198
|
+
transformInput({ ctx: inputCtx, steps, }) {
|
|
199
|
+
// Extract trace headers from event
|
|
200
|
+
const event = inputCtx
|
|
201
|
+
?.event;
|
|
202
|
+
const headers = {};
|
|
203
|
+
if (event?.trace?.traceparent) {
|
|
204
|
+
headers.traceparent = event.trace.traceparent;
|
|
205
|
+
}
|
|
206
|
+
if (event?.trace?.tracestate) {
|
|
207
|
+
headers.tracestate = event.trace.tracestate;
|
|
208
|
+
}
|
|
209
|
+
if (event?.trace?.baggage) {
|
|
210
|
+
headers.baggage = event.trace.baggage;
|
|
211
|
+
}
|
|
212
|
+
// Note: Middleware can't wrap async execution directly
|
|
213
|
+
// Users should still use withInngest() in their function
|
|
214
|
+
// This middleware is for future compatibility
|
|
215
|
+
return { ctx: inputCtx, steps };
|
|
216
|
+
},
|
|
217
|
+
};
|
|
218
|
+
},
|
|
219
|
+
};
|
|
220
|
+
},
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/integrations/inngest/index.ts"],"names":[],"mappings":"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"}
|