@drawbridge/drawbridge-utils 0.0.29 → 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 +76 -74
- 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 +50 -98
- package/dist/transactions.d.cts +92 -133
- package/dist/transactions.d.ts +92 -133
- package/dist/transactions.js +1 -3
- package/package.json +1 -1
- package/dist/chunk-H735KDYS.js +0 -162
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,105 +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
94
|
stripeEventId,
|
|
92
|
-
session
|
|
95
|
+
session,
|
|
96
|
+
...rest
|
|
93
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;
|
|
94
101
|
await db.create({
|
|
95
|
-
authenticated,
|
|
102
|
+
authenticated: user,
|
|
96
103
|
collection: "transaction",
|
|
97
104
|
data: {
|
|
105
|
+
..._id && { _id },
|
|
98
106
|
userId,
|
|
99
|
-
|
|
100
|
-
item: "ai"
|
|
101
|
-
},
|
|
107
|
+
type,
|
|
102
108
|
category,
|
|
103
|
-
|
|
109
|
+
source,
|
|
104
110
|
amount,
|
|
105
|
-
balance,
|
|
106
|
-
...
|
|
111
|
+
...balance && { balance },
|
|
112
|
+
...rest,
|
|
107
113
|
...stripeInvoiceId && { stripeInvoiceId },
|
|
108
114
|
...stripeEventId && { stripeEventId }
|
|
109
115
|
},
|
|
110
116
|
...session && { options: { session } }
|
|
111
117
|
});
|
|
112
118
|
};
|
|
113
|
-
var InsufficientCreditsError = class extends Error {
|
|
114
|
-
constructor(message = "Insufficient AI credits") {
|
|
115
|
-
super(message);
|
|
116
|
-
this.name = "InsufficientCreditsError";
|
|
117
|
-
this.status = 402;
|
|
118
|
-
}
|
|
119
|
-
};
|
|
120
119
|
var debit = async ({
|
|
121
120
|
db,
|
|
122
|
-
|
|
121
|
+
user,
|
|
123
122
|
userId,
|
|
124
123
|
amount,
|
|
124
|
+
type,
|
|
125
125
|
category,
|
|
126
|
-
|
|
127
|
-
provider,
|
|
126
|
+
source,
|
|
128
127
|
stripeInvoiceId,
|
|
129
128
|
stripeEventId,
|
|
130
|
-
session
|
|
129
|
+
session,
|
|
130
|
+
...rest
|
|
131
131
|
}) => {
|
|
132
|
-
var _a, _b, _c;
|
|
133
132
|
if (!Number.isInteger(amount) || amount <= 0) {
|
|
134
133
|
throw new Error(`debit() requires a positive integer amount, got ${amount}`);
|
|
135
134
|
}
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
collection: "user",
|
|
139
|
-
query: {
|
|
140
|
-
id: userId,
|
|
141
|
-
"balance.ai": {
|
|
142
|
-
$gte: amount
|
|
143
|
-
}
|
|
144
|
-
},
|
|
145
|
-
data: {
|
|
146
|
-
$inc: {
|
|
147
|
-
"balance.ai": -amount
|
|
148
|
-
}
|
|
149
|
-
},
|
|
150
|
-
...session && { options: { session } }
|
|
151
|
-
});
|
|
152
|
-
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);
|
|
153
|
-
if (typeof after !== "number") {
|
|
154
|
-
throw new InsufficientCreditsError();
|
|
135
|
+
if (!type) {
|
|
136
|
+
throw new Error('debit() requires a type (e.g., "ai")');
|
|
155
137
|
}
|
|
156
|
-
|
|
157
|
-
|
|
138
|
+
if (!source) {
|
|
139
|
+
throw new Error('debit() requires a source ("system" | "admin" | "user")');
|
|
140
|
+
}
|
|
141
|
+
await insertTransaction({
|
|
158
142
|
db,
|
|
159
|
-
|
|
143
|
+
user,
|
|
160
144
|
userId,
|
|
145
|
+
type,
|
|
161
146
|
category,
|
|
162
|
-
|
|
147
|
+
source,
|
|
163
148
|
amount: -amount,
|
|
164
|
-
balance: {
|
|
165
|
-
before,
|
|
166
|
-
after
|
|
167
|
-
},
|
|
168
|
-
provider,
|
|
169
149
|
stripeInvoiceId,
|
|
170
150
|
stripeEventId,
|
|
171
|
-
session
|
|
151
|
+
session,
|
|
152
|
+
...rest
|
|
172
153
|
});
|
|
173
|
-
return {
|
|
174
|
-
amount: -amount,
|
|
175
|
-
balance: {
|
|
176
|
-
before,
|
|
177
|
-
after
|
|
178
|
-
}
|
|
179
|
-
};
|
|
180
154
|
};
|
|
181
155
|
|
|
182
156
|
// ai.js
|
|
@@ -192,7 +166,7 @@ var models = {
|
|
|
192
166
|
image: "gemini-2.5-flash-image",
|
|
193
167
|
text: "gemini-2.5-flash"
|
|
194
168
|
};
|
|
195
|
-
var
|
|
169
|
+
var cost = {
|
|
196
170
|
"gemini-2.5-flash": {
|
|
197
171
|
cached: 3,
|
|
198
172
|
input: 30,
|
|
@@ -204,18 +178,33 @@ var pricing = {
|
|
|
204
178
|
output: 250
|
|
205
179
|
}
|
|
206
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
|
+
);
|
|
207
195
|
var priceForRequest = (model, usage) => {
|
|
208
196
|
const rates = pricing[model];
|
|
209
197
|
if (!rates) {
|
|
210
198
|
throw new Error(`Unknown model for pricing: ${model}`);
|
|
211
199
|
}
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
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);
|
|
219
208
|
};
|
|
220
209
|
var tokensFromMetadata = (metadata) => ({
|
|
221
210
|
cached: Number(metadata == null ? void 0 : metadata.cachedContentTokenCount) || 0,
|
|
@@ -229,19 +218,29 @@ var billRequest = async ({
|
|
|
229
218
|
model,
|
|
230
219
|
usage
|
|
231
220
|
}) => {
|
|
232
|
-
const
|
|
221
|
+
const gross = priceForRequest(model, usage);
|
|
222
|
+
const cogs = costForRequest(model, usage);
|
|
233
223
|
await debit({
|
|
234
224
|
db,
|
|
235
225
|
authenticated,
|
|
236
226
|
userId,
|
|
237
|
-
amount,
|
|
227
|
+
amount: gross,
|
|
228
|
+
type: "ai",
|
|
238
229
|
category: "usage",
|
|
239
|
-
|
|
240
|
-
|
|
230
|
+
source: "user",
|
|
231
|
+
ai: {
|
|
241
232
|
name: "google",
|
|
242
233
|
model,
|
|
243
234
|
tokens: usage,
|
|
244
|
-
|
|
235
|
+
rates: {
|
|
236
|
+
wholesale: cost[model],
|
|
237
|
+
retail: pricing[model]
|
|
238
|
+
},
|
|
239
|
+
totals: {
|
|
240
|
+
cost: cogs,
|
|
241
|
+
net: gross - cogs,
|
|
242
|
+
gross
|
|
243
|
+
}
|
|
245
244
|
}
|
|
246
245
|
});
|
|
247
246
|
};
|
|
@@ -327,6 +326,9 @@ var google = {
|
|
|
327
326
|
};
|
|
328
327
|
// Annotate the CommonJS export names for ESM import in node:
|
|
329
328
|
0 && (module.exports = {
|
|
329
|
+
MARKUP,
|
|
330
|
+
cost,
|
|
331
|
+
costForRequest,
|
|
330
332
|
google,
|
|
331
333
|
priceForRequest,
|
|
332
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
|