@drawbridge/drawbridge-utils 0.0.28 → 0.0.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/dist/ai.cjs +82 -75
- package/dist/ai.d.cts +72 -29
- package/dist/ai.d.ts +72 -29
- package/dist/ai.js +42 -14
- package/dist/chunk-6S43OFA7.js +115 -0
- package/dist/transactions.cjs +58 -98
- package/dist/transactions.d.cts +101 -127
- package/dist/transactions.d.ts +101 -127
- package/dist/transactions.js +1 -3
- package/package.json +1 -1
- package/dist/chunk-RC5E56UB.js +0 -154
package/dist/ai.cjs
CHANGED
|
@@ -19,6 +19,9 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
19
19
|
// ai.js
|
|
20
20
|
var ai_exports = {};
|
|
21
21
|
__export(ai_exports, {
|
|
22
|
+
MARKUP: () => MARKUP,
|
|
23
|
+
cost: () => cost,
|
|
24
|
+
costForRequest: () => costForRequest,
|
|
22
25
|
google: () => google,
|
|
23
26
|
priceForRequest: () => priceForRequest,
|
|
24
27
|
pricing: () => pricing
|
|
@@ -78,100 +81,76 @@ var circuit = ({
|
|
|
78
81
|
};
|
|
79
82
|
|
|
80
83
|
// transactions.js
|
|
81
|
-
var
|
|
84
|
+
var insertTransaction = async ({
|
|
82
85
|
db,
|
|
83
|
-
|
|
86
|
+
user,
|
|
84
87
|
userId,
|
|
88
|
+
type,
|
|
85
89
|
category,
|
|
86
|
-
|
|
90
|
+
source,
|
|
87
91
|
amount,
|
|
88
|
-
|
|
89
|
-
provider,
|
|
92
|
+
_id,
|
|
90
93
|
stripeInvoiceId,
|
|
91
|
-
stripeEventId
|
|
94
|
+
stripeEventId,
|
|
95
|
+
session,
|
|
96
|
+
...rest
|
|
92
97
|
}) => {
|
|
98
|
+
var _a;
|
|
99
|
+
const beforeRaw = (_a = user == null ? void 0 : user.balance) == null ? void 0 : _a[type];
|
|
100
|
+
const balance = typeof beforeRaw === "number" ? { before: beforeRaw, after: beforeRaw + amount } : void 0;
|
|
93
101
|
await db.create({
|
|
94
|
-
authenticated,
|
|
95
|
-
collection: "
|
|
102
|
+
authenticated: user,
|
|
103
|
+
collection: "transaction",
|
|
96
104
|
data: {
|
|
105
|
+
..._id && { _id },
|
|
97
106
|
userId,
|
|
98
|
-
|
|
99
|
-
item: "ai"
|
|
100
|
-
},
|
|
107
|
+
type,
|
|
101
108
|
category,
|
|
102
|
-
|
|
109
|
+
source,
|
|
103
110
|
amount,
|
|
104
|
-
balance,
|
|
105
|
-
...
|
|
111
|
+
...balance && { balance },
|
|
112
|
+
...rest,
|
|
106
113
|
...stripeInvoiceId && { stripeInvoiceId },
|
|
107
114
|
...stripeEventId && { stripeEventId }
|
|
108
|
-
}
|
|
115
|
+
},
|
|
116
|
+
...session && { options: { session } }
|
|
109
117
|
});
|
|
110
118
|
};
|
|
111
|
-
var InsufficientCreditsError = class extends Error {
|
|
112
|
-
constructor(message = "Insufficient AI credits") {
|
|
113
|
-
super(message);
|
|
114
|
-
this.name = "InsufficientCreditsError";
|
|
115
|
-
this.status = 402;
|
|
116
|
-
}
|
|
117
|
-
};
|
|
118
119
|
var debit = async ({
|
|
119
120
|
db,
|
|
120
|
-
|
|
121
|
+
user,
|
|
121
122
|
userId,
|
|
122
123
|
amount,
|
|
124
|
+
type,
|
|
123
125
|
category,
|
|
124
|
-
|
|
125
|
-
provider,
|
|
126
|
+
source,
|
|
126
127
|
stripeInvoiceId,
|
|
127
|
-
stripeEventId
|
|
128
|
+
stripeEventId,
|
|
129
|
+
session,
|
|
130
|
+
...rest
|
|
128
131
|
}) => {
|
|
129
|
-
var _a, _b, _c;
|
|
130
132
|
if (!Number.isInteger(amount) || amount <= 0) {
|
|
131
133
|
throw new Error(`debit() requires a positive integer amount, got ${amount}`);
|
|
132
134
|
}
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
"balance.ai": {
|
|
139
|
-
$gte: amount
|
|
140
|
-
}
|
|
141
|
-
},
|
|
142
|
-
data: {
|
|
143
|
-
$inc: {
|
|
144
|
-
"balance.ai": -amount
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
});
|
|
148
|
-
const after = ((_b = (_a = result == null ? void 0 : result.value) == null ? void 0 : _a.balance) == null ? void 0 : _b.ai) ?? ((_c = result == null ? void 0 : result.balance) == null ? void 0 : _c.ai);
|
|
149
|
-
if (typeof after !== "number") {
|
|
150
|
-
throw new InsufficientCreditsError();
|
|
135
|
+
if (!type) {
|
|
136
|
+
throw new Error('debit() requires a type (e.g., "ai")');
|
|
137
|
+
}
|
|
138
|
+
if (!source) {
|
|
139
|
+
throw new Error('debit() requires a source ("system" | "admin" | "user")');
|
|
151
140
|
}
|
|
152
|
-
|
|
153
|
-
await recordTransaction({
|
|
141
|
+
await insertTransaction({
|
|
154
142
|
db,
|
|
155
|
-
|
|
143
|
+
user,
|
|
156
144
|
userId,
|
|
145
|
+
type,
|
|
157
146
|
category,
|
|
158
|
-
|
|
147
|
+
source,
|
|
159
148
|
amount: -amount,
|
|
160
|
-
balance: {
|
|
161
|
-
before,
|
|
162
|
-
after
|
|
163
|
-
},
|
|
164
|
-
provider,
|
|
165
149
|
stripeInvoiceId,
|
|
166
|
-
stripeEventId
|
|
150
|
+
stripeEventId,
|
|
151
|
+
session,
|
|
152
|
+
...rest
|
|
167
153
|
});
|
|
168
|
-
return {
|
|
169
|
-
amount: -amount,
|
|
170
|
-
balance: {
|
|
171
|
-
before,
|
|
172
|
-
after
|
|
173
|
-
}
|
|
174
|
-
};
|
|
175
154
|
};
|
|
176
155
|
|
|
177
156
|
// ai.js
|
|
@@ -187,7 +166,7 @@ var models = {
|
|
|
187
166
|
image: "gemini-2.5-flash-image",
|
|
188
167
|
text: "gemini-2.5-flash"
|
|
189
168
|
};
|
|
190
|
-
var
|
|
169
|
+
var cost = {
|
|
191
170
|
"gemini-2.5-flash": {
|
|
192
171
|
cached: 3,
|
|
193
172
|
input: 30,
|
|
@@ -199,18 +178,33 @@ var pricing = {
|
|
|
199
178
|
output: 250
|
|
200
179
|
}
|
|
201
180
|
};
|
|
181
|
+
var MARKUP = 1.3;
|
|
182
|
+
var pricing = Object.fromEntries(
|
|
183
|
+
Object.entries(cost).map(([model, rates]) => [
|
|
184
|
+
model,
|
|
185
|
+
{
|
|
186
|
+
cached: Math.round(rates.cached * MARKUP),
|
|
187
|
+
input: Math.round(rates.input * MARKUP),
|
|
188
|
+
output: Math.round(rates.output * MARKUP)
|
|
189
|
+
}
|
|
190
|
+
])
|
|
191
|
+
);
|
|
192
|
+
var sumCents = (rates, tokens) => Math.ceil(
|
|
193
|
+
(Number((tokens == null ? void 0 : tokens.cached) || 0) * rates.cached + Number((tokens == null ? void 0 : tokens.input) || 0) * rates.input + Number((tokens == null ? void 0 : tokens.output) || 0) * rates.output) / 1e6
|
|
194
|
+
);
|
|
202
195
|
var priceForRequest = (model, usage) => {
|
|
203
196
|
const rates = pricing[model];
|
|
204
197
|
if (!rates) {
|
|
205
198
|
throw new Error(`Unknown model for pricing: ${model}`);
|
|
206
199
|
}
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
200
|
+
return sumCents(rates, usage);
|
|
201
|
+
};
|
|
202
|
+
var costForRequest = (model, usage) => {
|
|
203
|
+
const rates = cost[model];
|
|
204
|
+
if (!rates) {
|
|
205
|
+
throw new Error(`Unknown model for cost: ${model}`);
|
|
206
|
+
}
|
|
207
|
+
return sumCents(rates, usage);
|
|
214
208
|
};
|
|
215
209
|
var tokensFromMetadata = (metadata) => ({
|
|
216
210
|
cached: Number(metadata == null ? void 0 : metadata.cachedContentTokenCount) || 0,
|
|
@@ -224,19 +218,29 @@ var billRequest = async ({
|
|
|
224
218
|
model,
|
|
225
219
|
usage
|
|
226
220
|
}) => {
|
|
227
|
-
const
|
|
221
|
+
const gross = priceForRequest(model, usage);
|
|
222
|
+
const cogs = costForRequest(model, usage);
|
|
228
223
|
await debit({
|
|
229
224
|
db,
|
|
230
225
|
authenticated,
|
|
231
226
|
userId,
|
|
232
|
-
amount,
|
|
227
|
+
amount: gross,
|
|
228
|
+
type: "ai",
|
|
233
229
|
category: "usage",
|
|
234
|
-
|
|
235
|
-
|
|
230
|
+
source: "user",
|
|
231
|
+
ai: {
|
|
236
232
|
name: "google",
|
|
237
233
|
model,
|
|
238
234
|
tokens: usage,
|
|
239
|
-
|
|
235
|
+
rates: {
|
|
236
|
+
wholesale: cost[model],
|
|
237
|
+
retail: pricing[model]
|
|
238
|
+
},
|
|
239
|
+
totals: {
|
|
240
|
+
cost: cogs,
|
|
241
|
+
net: gross - cogs,
|
|
242
|
+
gross
|
|
243
|
+
}
|
|
240
244
|
}
|
|
241
245
|
});
|
|
242
246
|
};
|
|
@@ -322,6 +326,9 @@ var google = {
|
|
|
322
326
|
};
|
|
323
327
|
// Annotate the CommonJS export names for ESM import in node:
|
|
324
328
|
0 && (module.exports = {
|
|
329
|
+
MARKUP,
|
|
330
|
+
cost,
|
|
331
|
+
costForRequest,
|
|
325
332
|
google,
|
|
326
333
|
priceForRequest,
|
|
327
334
|
pricing
|
package/dist/ai.d.cts
CHANGED
|
@@ -36,14 +36,12 @@ const models = {
|
|
|
36
36
|
text : 'gemini-2.5-flash'
|
|
37
37
|
};
|
|
38
38
|
|
|
39
|
-
//
|
|
40
|
-
//
|
|
41
|
-
//
|
|
42
|
-
// Values mirror LiteLLM's published pricing at the time of writing. Model
|
|
43
|
-
// providers update pricing periodically — verify against
|
|
39
|
+
// Raw per-model provider rates in cents per 1,000,000 tokens. This is what
|
|
40
|
+
// Drawbridge pays the provider — the wholesale cost. Sync from LiteLLM:
|
|
44
41
|
// https://github.com/BerriAI/litellm/blob/main/litellm/model_prices_and_context_window_backup.json
|
|
45
|
-
//
|
|
46
|
-
|
|
42
|
+
// Never apply markup here; the MARKUP constant below derives the retail
|
|
43
|
+
// `pricing` table.
|
|
44
|
+
const cost = {
|
|
47
45
|
'gemini-2.5-flash' : {
|
|
48
46
|
cached : 3,
|
|
49
47
|
input : 30,
|
|
@@ -56,9 +54,37 @@ const pricing = {
|
|
|
56
54
|
}
|
|
57
55
|
};
|
|
58
56
|
|
|
59
|
-
//
|
|
60
|
-
//
|
|
61
|
-
//
|
|
57
|
+
// Markup multiplier applied to every model's cost to produce the retail
|
|
58
|
+
// price. 1.3 = 30% margin. Change one number, all pricing updates. Mirrors
|
|
59
|
+
// the per-customer markup Stripe rate cards used to provide; keeping it
|
|
60
|
+
// global (rather than per-model or per-plan) for simplicity — easy to
|
|
61
|
+
// refactor later if tier-based pricing becomes a real need.
|
|
62
|
+
const MARKUP = 1.3;
|
|
63
|
+
|
|
64
|
+
// Derived retail pricing in cents per 1,000,000 tokens — what users pay.
|
|
65
|
+
// Rounded so the per-1M rate is a whole-cent value; per-request rounding
|
|
66
|
+
// happens in priceForRequest via Math.ceil so we never under-bill.
|
|
67
|
+
const pricing = Object.fromEntries(
|
|
68
|
+
Object.entries( cost ).map( ( [ model, rates ] ) => [
|
|
69
|
+
model,
|
|
70
|
+
{
|
|
71
|
+
cached : Math.round( rates.cached * MARKUP ),
|
|
72
|
+
input : Math.round( rates.input * MARKUP ),
|
|
73
|
+
output : Math.round( rates.output * MARKUP )
|
|
74
|
+
}
|
|
75
|
+
] )
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
const sumCents = ( rates, tokens ) => Math.ceil(
|
|
79
|
+
(
|
|
80
|
+
Number( tokens?.cached || 0 ) * rates.cached +
|
|
81
|
+
Number( tokens?.input || 0 ) * rates.input +
|
|
82
|
+
Number( tokens?.output || 0 ) * rates.output
|
|
83
|
+
) / 1_000_000
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
// What we charge the user, rounded up so we never under-bill. Throws on an
|
|
87
|
+
// unknown model so a typo doesn't silently fall back to a wrong price.
|
|
62
88
|
const priceForRequest = ( model, usage ) => {
|
|
63
89
|
|
|
64
90
|
const rates = pricing[ model ];
|
|
@@ -69,19 +95,23 @@ const priceForRequest = ( model, usage ) => {
|
|
|
69
95
|
|
|
70
96
|
}
|
|
71
97
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
98
|
+
return sumCents( rates, usage );
|
|
99
|
+
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
// What we pay the provider. Recorded on each transaction row so margin is
|
|
103
|
+
// computable per request without backfilling from git history.
|
|
104
|
+
const costForRequest = ( model, usage ) => {
|
|
77
105
|
|
|
78
|
-
const
|
|
79
|
-
tokens.cached * rates.cached +
|
|
80
|
-
tokens.input * rates.input +
|
|
81
|
-
tokens.output * rates.output
|
|
82
|
-
);
|
|
106
|
+
const rates = cost[ model ];
|
|
83
107
|
|
|
84
|
-
|
|
108
|
+
if( !rates ){
|
|
109
|
+
|
|
110
|
+
throw new Error( `Unknown model for cost: ${ model }` );
|
|
111
|
+
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return sumCents( rates, usage );
|
|
85
115
|
|
|
86
116
|
};
|
|
87
117
|
|
|
@@ -92,8 +122,11 @@ const tokensFromMetadata = ( metadata ) => ({
|
|
|
92
122
|
output : Number( metadata?.candidatesTokenCount ) || 0
|
|
93
123
|
});
|
|
94
124
|
|
|
95
|
-
// Compute cost from response usage and atomically debit the user.
|
|
96
|
-
//
|
|
125
|
+
// Compute gross + cost from response usage and atomically debit the user.
|
|
126
|
+
// Records the full income-statement line on the transaction row's `ai`
|
|
127
|
+
// sub-doc: wholesale + retail per-1M rate snapshots, plus rolled-up cost,
|
|
128
|
+
// net, and gross totals. Margin per request is `ai.net`; margin per query
|
|
129
|
+
// is a single $sum: '$ai.net'.
|
|
97
130
|
const billRequest = async ({
|
|
98
131
|
db,
|
|
99
132
|
authenticated,
|
|
@@ -102,20 +135,30 @@ const billRequest = async ({
|
|
|
102
135
|
usage
|
|
103
136
|
}) => {
|
|
104
137
|
|
|
105
|
-
const
|
|
138
|
+
const gross = priceForRequest( model, usage );
|
|
139
|
+
const cogs = costForRequest( model, usage );
|
|
106
140
|
|
|
107
141
|
await debit({
|
|
108
142
|
db,
|
|
109
143
|
authenticated,
|
|
110
144
|
userId,
|
|
111
|
-
amount,
|
|
145
|
+
amount : gross,
|
|
146
|
+
type : 'ai',
|
|
112
147
|
category : 'usage',
|
|
113
|
-
|
|
114
|
-
|
|
148
|
+
source : 'user',
|
|
149
|
+
ai : {
|
|
115
150
|
name : 'google',
|
|
116
151
|
model,
|
|
117
152
|
tokens : usage,
|
|
118
|
-
|
|
153
|
+
rates : {
|
|
154
|
+
wholesale : cost[ model ],
|
|
155
|
+
retail : pricing[ model ]
|
|
156
|
+
},
|
|
157
|
+
totals : {
|
|
158
|
+
cost : cogs,
|
|
159
|
+
net : gross - cogs,
|
|
160
|
+
gross
|
|
161
|
+
}
|
|
119
162
|
}
|
|
120
163
|
});
|
|
121
164
|
|
|
@@ -241,4 +284,4 @@ const google = {
|
|
|
241
284
|
|
|
242
285
|
};
|
|
243
286
|
|
|
244
|
-
export { google, priceForRequest, pricing };
|
|
287
|
+
export { MARKUP, cost, costForRequest, google, priceForRequest, pricing };
|
package/dist/ai.d.ts
CHANGED
|
@@ -36,14 +36,12 @@ const models = {
|
|
|
36
36
|
text : 'gemini-2.5-flash'
|
|
37
37
|
};
|
|
38
38
|
|
|
39
|
-
//
|
|
40
|
-
//
|
|
41
|
-
//
|
|
42
|
-
// Values mirror LiteLLM's published pricing at the time of writing. Model
|
|
43
|
-
// providers update pricing periodically — verify against
|
|
39
|
+
// Raw per-model provider rates in cents per 1,000,000 tokens. This is what
|
|
40
|
+
// Drawbridge pays the provider — the wholesale cost. Sync from LiteLLM:
|
|
44
41
|
// https://github.com/BerriAI/litellm/blob/main/litellm/model_prices_and_context_window_backup.json
|
|
45
|
-
//
|
|
46
|
-
|
|
42
|
+
// Never apply markup here; the MARKUP constant below derives the retail
|
|
43
|
+
// `pricing` table.
|
|
44
|
+
const cost = {
|
|
47
45
|
'gemini-2.5-flash' : {
|
|
48
46
|
cached : 3,
|
|
49
47
|
input : 30,
|
|
@@ -56,9 +54,37 @@ const pricing = {
|
|
|
56
54
|
}
|
|
57
55
|
};
|
|
58
56
|
|
|
59
|
-
//
|
|
60
|
-
//
|
|
61
|
-
//
|
|
57
|
+
// Markup multiplier applied to every model's cost to produce the retail
|
|
58
|
+
// price. 1.3 = 30% margin. Change one number, all pricing updates. Mirrors
|
|
59
|
+
// the per-customer markup Stripe rate cards used to provide; keeping it
|
|
60
|
+
// global (rather than per-model or per-plan) for simplicity — easy to
|
|
61
|
+
// refactor later if tier-based pricing becomes a real need.
|
|
62
|
+
const MARKUP = 1.3;
|
|
63
|
+
|
|
64
|
+
// Derived retail pricing in cents per 1,000,000 tokens — what users pay.
|
|
65
|
+
// Rounded so the per-1M rate is a whole-cent value; per-request rounding
|
|
66
|
+
// happens in priceForRequest via Math.ceil so we never under-bill.
|
|
67
|
+
const pricing = Object.fromEntries(
|
|
68
|
+
Object.entries( cost ).map( ( [ model, rates ] ) => [
|
|
69
|
+
model,
|
|
70
|
+
{
|
|
71
|
+
cached : Math.round( rates.cached * MARKUP ),
|
|
72
|
+
input : Math.round( rates.input * MARKUP ),
|
|
73
|
+
output : Math.round( rates.output * MARKUP )
|
|
74
|
+
}
|
|
75
|
+
] )
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
const sumCents = ( rates, tokens ) => Math.ceil(
|
|
79
|
+
(
|
|
80
|
+
Number( tokens?.cached || 0 ) * rates.cached +
|
|
81
|
+
Number( tokens?.input || 0 ) * rates.input +
|
|
82
|
+
Number( tokens?.output || 0 ) * rates.output
|
|
83
|
+
) / 1_000_000
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
// What we charge the user, rounded up so we never under-bill. Throws on an
|
|
87
|
+
// unknown model so a typo doesn't silently fall back to a wrong price.
|
|
62
88
|
const priceForRequest = ( model, usage ) => {
|
|
63
89
|
|
|
64
90
|
const rates = pricing[ model ];
|
|
@@ -69,19 +95,23 @@ const priceForRequest = ( model, usage ) => {
|
|
|
69
95
|
|
|
70
96
|
}
|
|
71
97
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
98
|
+
return sumCents( rates, usage );
|
|
99
|
+
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
// What we pay the provider. Recorded on each transaction row so margin is
|
|
103
|
+
// computable per request without backfilling from git history.
|
|
104
|
+
const costForRequest = ( model, usage ) => {
|
|
77
105
|
|
|
78
|
-
const
|
|
79
|
-
tokens.cached * rates.cached +
|
|
80
|
-
tokens.input * rates.input +
|
|
81
|
-
tokens.output * rates.output
|
|
82
|
-
);
|
|
106
|
+
const rates = cost[ model ];
|
|
83
107
|
|
|
84
|
-
|
|
108
|
+
if( !rates ){
|
|
109
|
+
|
|
110
|
+
throw new Error( `Unknown model for cost: ${ model }` );
|
|
111
|
+
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return sumCents( rates, usage );
|
|
85
115
|
|
|
86
116
|
};
|
|
87
117
|
|
|
@@ -92,8 +122,11 @@ const tokensFromMetadata = ( metadata ) => ({
|
|
|
92
122
|
output : Number( metadata?.candidatesTokenCount ) || 0
|
|
93
123
|
});
|
|
94
124
|
|
|
95
|
-
// Compute cost from response usage and atomically debit the user.
|
|
96
|
-
//
|
|
125
|
+
// Compute gross + cost from response usage and atomically debit the user.
|
|
126
|
+
// Records the full income-statement line on the transaction row's `ai`
|
|
127
|
+
// sub-doc: wholesale + retail per-1M rate snapshots, plus rolled-up cost,
|
|
128
|
+
// net, and gross totals. Margin per request is `ai.net`; margin per query
|
|
129
|
+
// is a single $sum: '$ai.net'.
|
|
97
130
|
const billRequest = async ({
|
|
98
131
|
db,
|
|
99
132
|
authenticated,
|
|
@@ -102,20 +135,30 @@ const billRequest = async ({
|
|
|
102
135
|
usage
|
|
103
136
|
}) => {
|
|
104
137
|
|
|
105
|
-
const
|
|
138
|
+
const gross = priceForRequest( model, usage );
|
|
139
|
+
const cogs = costForRequest( model, usage );
|
|
106
140
|
|
|
107
141
|
await debit({
|
|
108
142
|
db,
|
|
109
143
|
authenticated,
|
|
110
144
|
userId,
|
|
111
|
-
amount,
|
|
145
|
+
amount : gross,
|
|
146
|
+
type : 'ai',
|
|
112
147
|
category : 'usage',
|
|
113
|
-
|
|
114
|
-
|
|
148
|
+
source : 'user',
|
|
149
|
+
ai : {
|
|
115
150
|
name : 'google',
|
|
116
151
|
model,
|
|
117
152
|
tokens : usage,
|
|
118
|
-
|
|
153
|
+
rates : {
|
|
154
|
+
wholesale : cost[ model ],
|
|
155
|
+
retail : pricing[ model ]
|
|
156
|
+
},
|
|
157
|
+
totals : {
|
|
158
|
+
cost : cogs,
|
|
159
|
+
net : gross - cogs,
|
|
160
|
+
gross
|
|
161
|
+
}
|
|
119
162
|
}
|
|
120
163
|
});
|
|
121
164
|
|
|
@@ -241,4 +284,4 @@ const google = {
|
|
|
241
284
|
|
|
242
285
|
};
|
|
243
286
|
|
|
244
|
-
export { google, priceForRequest, pricing };
|
|
287
|
+
export { MARKUP, cost, costForRequest, google, priceForRequest, pricing };
|
package/dist/ai.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
debit
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-6S43OFA7.js";
|
|
4
4
|
import {
|
|
5
5
|
circuit
|
|
6
6
|
} from "./chunk-6HH36OK6.js";
|
|
@@ -19,7 +19,7 @@ var models = {
|
|
|
19
19
|
image: "gemini-2.5-flash-image",
|
|
20
20
|
text: "gemini-2.5-flash"
|
|
21
21
|
};
|
|
22
|
-
var
|
|
22
|
+
var cost = {
|
|
23
23
|
"gemini-2.5-flash": {
|
|
24
24
|
cached: 3,
|
|
25
25
|
input: 30,
|
|
@@ -31,18 +31,33 @@ var pricing = {
|
|
|
31
31
|
output: 250
|
|
32
32
|
}
|
|
33
33
|
};
|
|
34
|
+
var MARKUP = 1.3;
|
|
35
|
+
var pricing = Object.fromEntries(
|
|
36
|
+
Object.entries(cost).map(([model, rates]) => [
|
|
37
|
+
model,
|
|
38
|
+
{
|
|
39
|
+
cached: Math.round(rates.cached * MARKUP),
|
|
40
|
+
input: Math.round(rates.input * MARKUP),
|
|
41
|
+
output: Math.round(rates.output * MARKUP)
|
|
42
|
+
}
|
|
43
|
+
])
|
|
44
|
+
);
|
|
45
|
+
var sumCents = (rates, tokens) => Math.ceil(
|
|
46
|
+
(Number((tokens == null ? void 0 : tokens.cached) || 0) * rates.cached + Number((tokens == null ? void 0 : tokens.input) || 0) * rates.input + Number((tokens == null ? void 0 : tokens.output) || 0) * rates.output) / 1e6
|
|
47
|
+
);
|
|
34
48
|
var priceForRequest = (model, usage) => {
|
|
35
49
|
const rates = pricing[model];
|
|
36
50
|
if (!rates) {
|
|
37
51
|
throw new Error(`Unknown model for pricing: ${model}`);
|
|
38
52
|
}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
53
|
+
return sumCents(rates, usage);
|
|
54
|
+
};
|
|
55
|
+
var costForRequest = (model, usage) => {
|
|
56
|
+
const rates = cost[model];
|
|
57
|
+
if (!rates) {
|
|
58
|
+
throw new Error(`Unknown model for cost: ${model}`);
|
|
59
|
+
}
|
|
60
|
+
return sumCents(rates, usage);
|
|
46
61
|
};
|
|
47
62
|
var tokensFromMetadata = (metadata) => ({
|
|
48
63
|
cached: Number(metadata == null ? void 0 : metadata.cachedContentTokenCount) || 0,
|
|
@@ -56,19 +71,29 @@ var billRequest = async ({
|
|
|
56
71
|
model,
|
|
57
72
|
usage
|
|
58
73
|
}) => {
|
|
59
|
-
const
|
|
74
|
+
const gross = priceForRequest(model, usage);
|
|
75
|
+
const cogs = costForRequest(model, usage);
|
|
60
76
|
await debit({
|
|
61
77
|
db,
|
|
62
78
|
authenticated,
|
|
63
79
|
userId,
|
|
64
|
-
amount,
|
|
80
|
+
amount: gross,
|
|
81
|
+
type: "ai",
|
|
65
82
|
category: "usage",
|
|
66
|
-
|
|
67
|
-
|
|
83
|
+
source: "user",
|
|
84
|
+
ai: {
|
|
68
85
|
name: "google",
|
|
69
86
|
model,
|
|
70
87
|
tokens: usage,
|
|
71
|
-
|
|
88
|
+
rates: {
|
|
89
|
+
wholesale: cost[model],
|
|
90
|
+
retail: pricing[model]
|
|
91
|
+
},
|
|
92
|
+
totals: {
|
|
93
|
+
cost: cogs,
|
|
94
|
+
net: gross - cogs,
|
|
95
|
+
gross
|
|
96
|
+
}
|
|
72
97
|
}
|
|
73
98
|
});
|
|
74
99
|
};
|
|
@@ -153,6 +178,9 @@ var google = {
|
|
|
153
178
|
}
|
|
154
179
|
};
|
|
155
180
|
export {
|
|
181
|
+
MARKUP,
|
|
182
|
+
cost,
|
|
183
|
+
costForRequest,
|
|
156
184
|
google,
|
|
157
185
|
priceForRequest,
|
|
158
186
|
pricing
|