@openmeter/sdk 1.0.0-beta.3 → 1.0.0-beta.31
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 +117 -26
- package/dist/clients/client.d.ts +3 -3
- package/dist/clients/client.js +11 -8
- package/dist/clients/event.d.ts +15 -0
- package/dist/clients/event.js +18 -3
- package/dist/clients/meter.d.ts +26 -7
- package/dist/clients/meter.js +16 -4
- package/dist/clients/portal.d.ts +23 -0
- package/dist/clients/portal.js +37 -0
- package/dist/index.d.ts +5 -2
- package/dist/index.js +4 -0
- package/dist/next.d.ts +15 -0
- package/dist/next.js +46 -0
- package/dist/schemas/openapi.d.ts +220 -123
- package/dist/test/agent.js +109 -32
- package/dist/test/mocks.d.ts +2 -1
- package/dist/test/mocks.js +19 -8
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/index.ts +13 -8
- package/next.ts +76 -0
- package/package.json +55 -52
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
## Install
|
|
4
4
|
|
|
5
5
|
```sh
|
|
6
|
-
npm install --save @openmeter/sdk
|
|
6
|
+
npm install --save @openmeter/sdk
|
|
7
7
|
```
|
|
8
8
|
|
|
9
9
|
## Example
|
|
@@ -15,15 +15,15 @@ const openmeter = new OpenMeter({ baseUrl: 'http://localhost:8888' })
|
|
|
15
15
|
|
|
16
16
|
// Ingesting an event
|
|
17
17
|
const event: Event = {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
18
|
+
specversion: '1.0',
|
|
19
|
+
id: 'id-1',
|
|
20
|
+
source: 'my-app',
|
|
21
|
+
type: 'my-type',
|
|
22
|
+
subject: 'my-awesome-user-id',
|
|
23
|
+
time: new Date(),
|
|
24
|
+
data: {
|
|
25
|
+
api_calls: 1,
|
|
26
|
+
},
|
|
27
27
|
}
|
|
28
28
|
await openmeter.events.ingest(event)
|
|
29
29
|
|
|
@@ -41,19 +41,27 @@ const meter = await openmeter.meters.get('m1')
|
|
|
41
41
|
import { type Event } from '@openmeter/sdk'
|
|
42
42
|
|
|
43
43
|
const event: Event = {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
44
|
+
specversion: '1.0',
|
|
45
|
+
id: 'id-1',
|
|
46
|
+
source: 'my-app',
|
|
47
|
+
type: 'my-type',
|
|
48
|
+
subject: 'my-awesome-user-id',
|
|
49
|
+
time: new Date(),
|
|
50
|
+
data: {
|
|
51
|
+
api_calls: 1,
|
|
52
|
+
},
|
|
53
53
|
}
|
|
54
54
|
await openmeter.events.ingest(event)
|
|
55
55
|
```
|
|
56
56
|
|
|
57
|
+
#### list
|
|
58
|
+
|
|
59
|
+
Retrieve latest raw events. Useful for debugging.
|
|
60
|
+
|
|
61
|
+
```ts
|
|
62
|
+
const events = await openmeter.events.list()
|
|
63
|
+
```
|
|
64
|
+
|
|
57
65
|
### Meters
|
|
58
66
|
|
|
59
67
|
#### list
|
|
@@ -72,17 +80,100 @@ Get one meter by slug.
|
|
|
72
80
|
const meter = await openmeter.meters.get('m1')
|
|
73
81
|
```
|
|
74
82
|
|
|
75
|
-
####
|
|
83
|
+
#### query
|
|
76
84
|
|
|
77
|
-
|
|
85
|
+
Query meter values.
|
|
78
86
|
|
|
79
87
|
```ts
|
|
80
88
|
import { WindowSize } from '@openmeter/sdk'
|
|
81
89
|
|
|
82
|
-
const values = await openmeter.meters.
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
90
|
+
const values = await openmeter.meters.query('my-meter-slug', {
|
|
91
|
+
subject: ['user-1'],
|
|
92
|
+
groupBy: ['method', 'path'],
|
|
93
|
+
from: new Date('2021-01-01'),
|
|
94
|
+
to: new Date('2021-01-02'),
|
|
95
|
+
windowSize: WindowSize.HOUR,
|
|
87
96
|
})
|
|
88
97
|
```
|
|
98
|
+
|
|
99
|
+
#### subjects
|
|
100
|
+
|
|
101
|
+
List meter subjects.
|
|
102
|
+
|
|
103
|
+
```ts
|
|
104
|
+
const subjects = await openmeter.meters.subjects('my-meter-slug')
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### Portal
|
|
108
|
+
|
|
109
|
+
#### createToken
|
|
110
|
+
|
|
111
|
+
Create subject specific tokens.
|
|
112
|
+
Useful to build consumer dashboards.
|
|
113
|
+
|
|
114
|
+
```ts
|
|
115
|
+
const token = await openmeter.portal.createToken({ subject: 'customer-1' })
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
#### invalidateTokens
|
|
119
|
+
|
|
120
|
+
Invalidate portal tokens for all or specific subjects.
|
|
121
|
+
|
|
122
|
+
```ts
|
|
123
|
+
await openmeter.portal.invalidateTokens()
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## Helpers
|
|
127
|
+
|
|
128
|
+
### Vercel AI SDK / Next.js
|
|
129
|
+
|
|
130
|
+
The OpenAI streaming API used by the Vercel AI SDK doesn't return token usage metadata by default.
|
|
131
|
+
The OpenMeter `createOpenAIStreamCallback` helper function decorates the callback with a `onUsage`
|
|
132
|
+
callback which you can use to report usage to OpenMeter.
|
|
133
|
+
|
|
134
|
+
```ts
|
|
135
|
+
import OpenAI from 'openai'
|
|
136
|
+
import { OpenAIStream, StreamingTextResponse } from 'ai'
|
|
137
|
+
import { createOpenAIStreamCallback } from '@openmeter/sdk'
|
|
138
|
+
|
|
139
|
+
export async function POST(req: Request) {
|
|
140
|
+
const { messages } = await req.json()
|
|
141
|
+
const model = 'gpt-3.5-turbo'
|
|
142
|
+
|
|
143
|
+
const response = await openai.chat.completions.create({
|
|
144
|
+
model,
|
|
145
|
+
messages,
|
|
146
|
+
stream: true,
|
|
147
|
+
})
|
|
148
|
+
|
|
149
|
+
const streamCallbacks = await createOpenAIStreamCallback(
|
|
150
|
+
{
|
|
151
|
+
model,
|
|
152
|
+
prompts: messages.map(({ content }) => content),
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
// onToken() => {...}
|
|
156
|
+
// onFinal() => {...}
|
|
157
|
+
async onUsage(usage) {
|
|
158
|
+
try {
|
|
159
|
+
await openmeter.events.ingest({
|
|
160
|
+
source: 'my-app',
|
|
161
|
+
type: 'my-event-type',
|
|
162
|
+
subject: 'my-customer-id',
|
|
163
|
+
data: {
|
|
164
|
+
// Usage is { total_tokens, prompt_tokens, completion_tokens }
|
|
165
|
+
...usage,
|
|
166
|
+
model,
|
|
167
|
+
},
|
|
168
|
+
})
|
|
169
|
+
} catch (err) {
|
|
170
|
+
console.error('failed to ingest usage', err)
|
|
171
|
+
}
|
|
172
|
+
},
|
|
173
|
+
}
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
const stream = OpenAIStream(response, streamCallbacks)
|
|
177
|
+
return new StreamingTextResponse(stream)
|
|
178
|
+
}
|
|
179
|
+
```
|
package/dist/clients/client.d.ts
CHANGED
|
@@ -18,7 +18,7 @@ export type Problem = components['schemas']['Problem'];
|
|
|
18
18
|
export declare class BaseClient {
|
|
19
19
|
protected config: OpenMeterConfig;
|
|
20
20
|
constructor(config: OpenMeterConfig);
|
|
21
|
-
protected request<T>({ path, method, searchParams, headers, body, options }: {
|
|
21
|
+
protected request<T>({ path, method, searchParams, headers, body, options, }: {
|
|
22
22
|
path: string;
|
|
23
23
|
method: Dispatcher.HttpMethod;
|
|
24
24
|
searchParams?: URLSearchParams;
|
|
@@ -28,12 +28,12 @@ export declare class BaseClient {
|
|
|
28
28
|
}): Promise<T>;
|
|
29
29
|
protected getUrl(path: string, searchParams?: URLSearchParams): import("url").URL;
|
|
30
30
|
protected getAuthHeaders(): IncomingHttpHeaders;
|
|
31
|
-
protected static toURLSearchParams(params: Record<string, string | number | Date | string[]>): URLSearchParams;
|
|
31
|
+
protected static toURLSearchParams(params: Record<string, string | number | Date | string[] | undefined>): URLSearchParams;
|
|
32
32
|
}
|
|
33
33
|
export declare class HttpError extends Error {
|
|
34
34
|
statusCode: number;
|
|
35
35
|
problem?: Problem;
|
|
36
|
-
constructor({ statusCode, problem }: {
|
|
36
|
+
constructor({ statusCode, problem, }: {
|
|
37
37
|
statusCode: number;
|
|
38
38
|
problem?: Problem;
|
|
39
39
|
});
|
package/dist/clients/client.js
CHANGED
|
@@ -4,7 +4,7 @@ export class BaseClient {
|
|
|
4
4
|
constructor(config) {
|
|
5
5
|
this.config = config;
|
|
6
6
|
}
|
|
7
|
-
async request({ path, method, searchParams, headers, body, options }) {
|
|
7
|
+
async request({ path, method, searchParams, headers, body, options, }) {
|
|
8
8
|
// Building URL
|
|
9
9
|
const url = this.getUrl(path, searchParams);
|
|
10
10
|
// Request options
|
|
@@ -17,7 +17,7 @@ export class BaseClient {
|
|
|
17
17
|
};
|
|
18
18
|
const reqOpts = {
|
|
19
19
|
method,
|
|
20
|
-
headers: reqHeaders
|
|
20
|
+
headers: reqHeaders,
|
|
21
21
|
};
|
|
22
22
|
// Optional body
|
|
23
23
|
if (body) {
|
|
@@ -30,7 +30,7 @@ export class BaseClient {
|
|
|
30
30
|
// Error handling
|
|
31
31
|
if (resp.statusCode > 399) {
|
|
32
32
|
if (resp.headers['content-type'] === 'application/problem+json') {
|
|
33
|
-
const problem = await resp.body.json();
|
|
33
|
+
const problem = (await resp.body.json());
|
|
34
34
|
throw new HttpError({
|
|
35
35
|
statusCode: resp.statusCode,
|
|
36
36
|
problem,
|
|
@@ -46,7 +46,7 @@ export class BaseClient {
|
|
|
46
46
|
return undefined;
|
|
47
47
|
}
|
|
48
48
|
if (resp.headers['content-type'] === 'application/json') {
|
|
49
|
-
return await resp.body.json();
|
|
49
|
+
return (await resp.body.json());
|
|
50
50
|
}
|
|
51
51
|
if (!resp.headers['content-type']) {
|
|
52
52
|
throw new Error('Missing content type');
|
|
@@ -62,13 +62,13 @@ export class BaseClient {
|
|
|
62
62
|
getAuthHeaders() {
|
|
63
63
|
if (this.config.token) {
|
|
64
64
|
return {
|
|
65
|
-
authorization: `Bearer ${this.config.token}
|
|
65
|
+
authorization: `Bearer ${this.config.token}`,
|
|
66
66
|
};
|
|
67
67
|
}
|
|
68
68
|
if (this.config.username && this.config.password) {
|
|
69
|
-
const encoded = Buffer.from(`${this.config.username}:${this.config.password}
|
|
69
|
+
const encoded = Buffer.from(`${this.config.username}:${this.config.password}`).toString('base64');
|
|
70
70
|
return {
|
|
71
|
-
authorization: `Basic ${encoded}
|
|
71
|
+
authorization: `Basic ${encoded}`,
|
|
72
72
|
};
|
|
73
73
|
}
|
|
74
74
|
return {};
|
|
@@ -76,6 +76,9 @@ export class BaseClient {
|
|
|
76
76
|
static toURLSearchParams(params) {
|
|
77
77
|
const searchParams = new URLSearchParams();
|
|
78
78
|
for (const [key, value] of Object.entries(params)) {
|
|
79
|
+
if (value === undefined) {
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
79
82
|
if (Array.isArray(value)) {
|
|
80
83
|
searchParams.append(key, value.join(','));
|
|
81
84
|
}
|
|
@@ -92,7 +95,7 @@ export class BaseClient {
|
|
|
92
95
|
export class HttpError extends Error {
|
|
93
96
|
statusCode;
|
|
94
97
|
problem;
|
|
95
|
-
constructor({ statusCode, problem }) {
|
|
98
|
+
constructor({ statusCode, problem, }) {
|
|
96
99
|
super(problem?.type || 'unexpected status code');
|
|
97
100
|
this.name = 'HttpError';
|
|
98
101
|
this.statusCode = statusCode;
|
package/dist/clients/event.d.ts
CHANGED
|
@@ -1,4 +1,14 @@
|
|
|
1
|
+
import { components } from '../schemas/openapi.js';
|
|
1
2
|
import { RequestOptions, BaseClient, OpenMeterConfig } from './client.js';
|
|
3
|
+
type CloudEvents = components['schemas']['Event'];
|
|
4
|
+
export type IngestedEvent = components['schemas']['IngestedEvent'];
|
|
5
|
+
export type EventsQueryParams = {
|
|
6
|
+
/**
|
|
7
|
+
* @description Limit number of results. Max: 100
|
|
8
|
+
* @example 25
|
|
9
|
+
*/
|
|
10
|
+
limit?: number;
|
|
11
|
+
};
|
|
2
12
|
/**
|
|
3
13
|
* Usage Event
|
|
4
14
|
*/
|
|
@@ -62,4 +72,9 @@ export declare class EventsClient extends BaseClient {
|
|
|
62
72
|
* @see https://cloudevents.io
|
|
63
73
|
*/
|
|
64
74
|
ingest(usageEvent: Event, options?: RequestOptions): Promise<void>;
|
|
75
|
+
/**
|
|
76
|
+
* List raw events
|
|
77
|
+
*/
|
|
78
|
+
list(params?: EventsQueryParams, options?: RequestOptions): Promise<CloudEvents[]>;
|
|
65
79
|
}
|
|
80
|
+
export {};
|
package/dist/clients/event.js
CHANGED
|
@@ -9,7 +9,8 @@ export class EventsClient extends BaseClient {
|
|
|
9
9
|
* @see https://cloudevents.io
|
|
10
10
|
*/
|
|
11
11
|
async ingest(usageEvent, options) {
|
|
12
|
-
if (usageEvent.datacontenttype &&
|
|
12
|
+
if (usageEvent.datacontenttype &&
|
|
13
|
+
usageEvent.datacontenttype !== 'application/json') {
|
|
13
14
|
throw new TypeError(`Unsupported datacontenttype: ${usageEvent.datacontenttype}`);
|
|
14
15
|
}
|
|
15
16
|
// We default where we can to lower the barrier to use CloudEvents
|
|
@@ -22,7 +23,7 @@ export class EventsClient extends BaseClient {
|
|
|
22
23
|
time: usageEvent.time?.toISOString(),
|
|
23
24
|
datacontenttype: usageEvent.datacontenttype,
|
|
24
25
|
dataschema: usageEvent.dataschema,
|
|
25
|
-
data: usageEvent.data
|
|
26
|
+
data: usageEvent.data,
|
|
26
27
|
};
|
|
27
28
|
// Making Request
|
|
28
29
|
return await this.request({
|
|
@@ -32,7 +33,21 @@ export class EventsClient extends BaseClient {
|
|
|
32
33
|
headers: {
|
|
33
34
|
'Content-Type': 'application/cloudevents+json',
|
|
34
35
|
},
|
|
35
|
-
options
|
|
36
|
+
options,
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* List raw events
|
|
41
|
+
*/
|
|
42
|
+
async list(params, options) {
|
|
43
|
+
const searchParams = params
|
|
44
|
+
? BaseClient.toURLSearchParams(params)
|
|
45
|
+
: undefined;
|
|
46
|
+
return this.request({
|
|
47
|
+
method: 'GET',
|
|
48
|
+
path: `/api/v1/events`,
|
|
49
|
+
searchParams,
|
|
50
|
+
options,
|
|
36
51
|
});
|
|
37
52
|
}
|
|
38
53
|
}
|
package/dist/clients/meter.d.ts
CHANGED
|
@@ -13,7 +13,11 @@ export declare enum MeterAggregation {
|
|
|
13
13
|
MAX = "MAX"
|
|
14
14
|
}
|
|
15
15
|
export type MeterQueryParams = {
|
|
16
|
-
|
|
16
|
+
/**
|
|
17
|
+
* @description Subject(s) to filter by.
|
|
18
|
+
* @example ["customer-1", "customer-2"]
|
|
19
|
+
*/
|
|
20
|
+
subject?: string[];
|
|
17
21
|
/**
|
|
18
22
|
* @description Start date.
|
|
19
23
|
* Must be aligned with the window size.
|
|
@@ -26,13 +30,24 @@ export type MeterQueryParams = {
|
|
|
26
30
|
* Inclusive.
|
|
27
31
|
*/
|
|
28
32
|
to?: Date;
|
|
29
|
-
/**
|
|
33
|
+
/**
|
|
34
|
+
* @description Window Size
|
|
35
|
+
* If not specified, a single usage aggregate will be returned for the entirety of
|
|
36
|
+
* the specified period for each subject and group.
|
|
37
|
+
*/
|
|
30
38
|
windowSize?: WindowSizeType;
|
|
31
|
-
/**
|
|
39
|
+
/**
|
|
40
|
+
* @description The value is the name of the time zone as defined in the IANA Time Zone Database (http://www.iana.org/time-zones).
|
|
41
|
+
* If not specified, the UTC timezone will be used.
|
|
42
|
+
*/
|
|
43
|
+
windowTimeZone?: string;
|
|
44
|
+
/**
|
|
45
|
+
* @description Group By
|
|
46
|
+
* If not specified a single aggregate will be returned for each subject and time window.
|
|
47
|
+
*/
|
|
32
48
|
groupBy?: string[];
|
|
33
49
|
};
|
|
34
|
-
export type MeterQueryResponse = paths['/api/v1/meters/{meterIdOrSlug}/
|
|
35
|
-
export type MeterValue = components['schemas']['MeterValue'];
|
|
50
|
+
export type MeterQueryResponse = paths['/api/v1/meters/{meterIdOrSlug}/query']['get']['responses']['200']['content']['application/json'];
|
|
36
51
|
export type Meter = components['schemas']['Meter'];
|
|
37
52
|
export type WindowSizeType = components['schemas']['WindowSize'];
|
|
38
53
|
export declare class MetersClient extends BaseClient {
|
|
@@ -46,7 +61,11 @@ export declare class MetersClient extends BaseClient {
|
|
|
46
61
|
*/
|
|
47
62
|
list(options?: RequestOptions): Promise<Meter[]>;
|
|
48
63
|
/**
|
|
49
|
-
*
|
|
64
|
+
* Query a meter
|
|
65
|
+
*/
|
|
66
|
+
query(slug: string, params?: MeterQueryParams, options?: RequestOptions): Promise<MeterQueryResponse>;
|
|
67
|
+
/**
|
|
68
|
+
* List subjects of a meter
|
|
50
69
|
*/
|
|
51
|
-
|
|
70
|
+
subjects(slug: string, options?: RequestOptions): Promise<string[]>;
|
|
52
71
|
}
|
package/dist/clients/meter.js
CHANGED
|
@@ -38,15 +38,27 @@ export class MetersClient extends BaseClient {
|
|
|
38
38
|
});
|
|
39
39
|
}
|
|
40
40
|
/**
|
|
41
|
-
*
|
|
41
|
+
* Query a meter
|
|
42
42
|
*/
|
|
43
|
-
async
|
|
44
|
-
const searchParams = params
|
|
43
|
+
async query(slug, params, options) {
|
|
44
|
+
const searchParams = params
|
|
45
|
+
? BaseClient.toURLSearchParams(params)
|
|
46
|
+
: undefined;
|
|
45
47
|
return this.request({
|
|
46
48
|
method: 'GET',
|
|
47
|
-
path: `/api/v1/meters/${slug}/
|
|
49
|
+
path: `/api/v1/meters/${slug}/query`,
|
|
48
50
|
searchParams,
|
|
49
51
|
options,
|
|
50
52
|
});
|
|
51
53
|
}
|
|
54
|
+
/**
|
|
55
|
+
* List subjects of a meter
|
|
56
|
+
*/
|
|
57
|
+
async subjects(slug, options) {
|
|
58
|
+
return this.request({
|
|
59
|
+
method: 'GET',
|
|
60
|
+
path: `/api/v1/meters/${slug}/subjects`,
|
|
61
|
+
options,
|
|
62
|
+
});
|
|
63
|
+
}
|
|
52
64
|
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { components } from '../schemas/openapi.js';
|
|
2
|
+
import { RequestOptions, BaseClient, OpenMeterConfig } from './client.js';
|
|
3
|
+
export type PortalToken = components['schemas']['PortalToken'];
|
|
4
|
+
export declare class PortalClient extends BaseClient {
|
|
5
|
+
constructor(config: OpenMeterConfig);
|
|
6
|
+
/**
|
|
7
|
+
* Create portal token
|
|
8
|
+
* Useful for creating a token sharable with your customer to query their own usage
|
|
9
|
+
* @note OpenMeter Cloud only feature
|
|
10
|
+
*/
|
|
11
|
+
createToken(token: {
|
|
12
|
+
subject: string;
|
|
13
|
+
expiresAt?: Date;
|
|
14
|
+
allowedMeterSlugs?: string[];
|
|
15
|
+
}, options?: RequestOptions): Promise<PortalToken>;
|
|
16
|
+
/**
|
|
17
|
+
* Invalidate portal token
|
|
18
|
+
* @note OpenMeter Cloud only feature
|
|
19
|
+
*/
|
|
20
|
+
invalidateTokens(invalidate?: {
|
|
21
|
+
subject?: string;
|
|
22
|
+
}, options?: RequestOptions): Promise<void>;
|
|
23
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { BaseClient } from './client.js';
|
|
2
|
+
export class PortalClient extends BaseClient {
|
|
3
|
+
constructor(config) {
|
|
4
|
+
super(config);
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Create portal token
|
|
8
|
+
* Useful for creating a token sharable with your customer to query their own usage
|
|
9
|
+
* @note OpenMeter Cloud only feature
|
|
10
|
+
*/
|
|
11
|
+
async createToken(token, options) {
|
|
12
|
+
return await this.request({
|
|
13
|
+
path: '/api/v1/portal/tokens',
|
|
14
|
+
method: 'POST',
|
|
15
|
+
headers: {
|
|
16
|
+
'Content-Type': 'application/json',
|
|
17
|
+
},
|
|
18
|
+
body: JSON.stringify(token),
|
|
19
|
+
options,
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Invalidate portal token
|
|
24
|
+
* @note OpenMeter Cloud only feature
|
|
25
|
+
*/
|
|
26
|
+
async invalidateTokens(invalidate = {}, options) {
|
|
27
|
+
return await this.request({
|
|
28
|
+
path: '/api/v1/portal/tokens/invalidate',
|
|
29
|
+
method: 'POST',
|
|
30
|
+
headers: {
|
|
31
|
+
'Content-Type': 'application/json',
|
|
32
|
+
},
|
|
33
|
+
body: JSON.stringify(invalidate),
|
|
34
|
+
options,
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import { OpenMeterConfig } from './clients/client.js';
|
|
2
2
|
import { EventsClient } from './clients/event.js';
|
|
3
3
|
import { MetersClient } from './clients/meter.js';
|
|
4
|
+
import { PortalClient } from './clients/portal.js';
|
|
4
5
|
export { OpenMeterConfig, RequestOptions } from './clients/client.js';
|
|
5
|
-
export { Event } from './clients/event.js';
|
|
6
|
-
export { Meter,
|
|
6
|
+
export { Event, IngestedEvent } from './clients/event.js';
|
|
7
|
+
export { Meter, MeterAggregation, WindowSize } from './clients/meter.js';
|
|
8
|
+
export { createOpenAIStreamCallback } from './next.js';
|
|
7
9
|
export declare class OpenMeter {
|
|
8
10
|
events: EventsClient;
|
|
9
11
|
meters: MetersClient;
|
|
12
|
+
portal: PortalClient;
|
|
10
13
|
constructor(config: OpenMeterConfig);
|
|
11
14
|
}
|
package/dist/index.js
CHANGED
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
import { EventsClient } from './clients/event.js';
|
|
2
2
|
import { MetersClient } from './clients/meter.js';
|
|
3
|
+
import { PortalClient } from './clients/portal.js';
|
|
3
4
|
export { MeterAggregation, WindowSize } from './clients/meter.js';
|
|
5
|
+
export { createOpenAIStreamCallback } from './next.js';
|
|
4
6
|
export class OpenMeter {
|
|
5
7
|
events;
|
|
6
8
|
meters;
|
|
9
|
+
portal;
|
|
7
10
|
constructor(config) {
|
|
8
11
|
this.events = new EventsClient(config);
|
|
9
12
|
this.meters = new MetersClient(config);
|
|
13
|
+
this.portal = new PortalClient(config);
|
|
10
14
|
}
|
|
11
15
|
}
|
package/dist/next.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { OpenAIStreamCallbacks } from 'ai';
|
|
2
|
+
import type { TiktokenModel } from 'js-tiktoken';
|
|
3
|
+
type OpenAIUsage = {
|
|
4
|
+
total_tokens: number;
|
|
5
|
+
prompt_tokens: number;
|
|
6
|
+
completion_tokens: number;
|
|
7
|
+
};
|
|
8
|
+
type OpenAIStreamCallbacksWithUsage = OpenAIStreamCallbacks & {
|
|
9
|
+
onUsage?: (usage: OpenAIUsage) => Promise<void> | void;
|
|
10
|
+
};
|
|
11
|
+
export declare function createOpenAIStreamCallback({ model, prompts, }: {
|
|
12
|
+
model: TiktokenModel;
|
|
13
|
+
prompts: string[];
|
|
14
|
+
}, openAIStreamCallbacks: OpenAIStreamCallbacksWithUsage): Promise<OpenAIStreamCallbacks>;
|
|
15
|
+
export {};
|
package/dist/next.js
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
let encodingForModel;
|
|
2
|
+
export async function createOpenAIStreamCallback({ model, prompts, }, openAIStreamCallbacks) {
|
|
3
|
+
// Tiktoken is an optional dependency, so we import it conditionally
|
|
4
|
+
if (!encodingForModel) {
|
|
5
|
+
const { encodingForModel: encodingForModel_ } = await import('js-tiktoken');
|
|
6
|
+
encodingForModel = encodingForModel_;
|
|
7
|
+
}
|
|
8
|
+
const enc = encodingForModel(model);
|
|
9
|
+
let promptTokens = 0;
|
|
10
|
+
let completionTokens = 0;
|
|
11
|
+
const streamCallbacks = {
|
|
12
|
+
...openAIStreamCallbacks,
|
|
13
|
+
async onStart() {
|
|
14
|
+
for (const content of prompts) {
|
|
15
|
+
const tokens = enc.encode(content);
|
|
16
|
+
promptTokens += tokens.length;
|
|
17
|
+
}
|
|
18
|
+
if (typeof openAIStreamCallbacks?.onStart === 'function') {
|
|
19
|
+
return openAIStreamCallbacks.onStart();
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
async onToken(content) {
|
|
23
|
+
// To test tokenizaton see: https://platform.openai.com/tokenizer
|
|
24
|
+
const tokens = enc.encode(content);
|
|
25
|
+
completionTokens += tokens.length;
|
|
26
|
+
if (typeof openAIStreamCallbacks?.onToken === 'function') {
|
|
27
|
+
return openAIStreamCallbacks.onToken(content);
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
async onFinal(completion) {
|
|
31
|
+
// Mimicking OpenAI usage metadata API
|
|
32
|
+
const usage = {
|
|
33
|
+
total_tokens: promptTokens + completionTokens,
|
|
34
|
+
prompt_tokens: promptTokens,
|
|
35
|
+
completion_tokens: completionTokens,
|
|
36
|
+
};
|
|
37
|
+
if (typeof openAIStreamCallbacks?.onUsage === 'function') {
|
|
38
|
+
await openAIStreamCallbacks.onUsage(usage);
|
|
39
|
+
}
|
|
40
|
+
if (typeof openAIStreamCallbacks?.onFinal === 'function') {
|
|
41
|
+
return openAIStreamCallbacks.onFinal(completion);
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
return streamCallbacks;
|
|
46
|
+
}
|