@routstr/sdk 0.3.10 → 0.3.11

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.
Files changed (63) hide show
  1. package/dist/browser.d.mts +2 -2
  2. package/dist/browser.d.ts +2 -2
  3. package/dist/browser.js +201 -66
  4. package/dist/browser.js.map +1 -1
  5. package/dist/browser.mjs +198 -67
  6. package/dist/browser.mjs.map +1 -1
  7. package/dist/bun.d.mts +5 -5
  8. package/dist/bun.d.ts +5 -5
  9. package/dist/bun.js +271 -66
  10. package/dist/bun.js.map +1 -1
  11. package/dist/bun.mjs +268 -67
  12. package/dist/bun.mjs.map +1 -1
  13. package/dist/{bunSqlite-BMTseLIz.d.ts → bunSqlite-BmXWNc25.d.ts} +1 -1
  14. package/dist/{bunSqlite-D6AreVE2.d.mts → bunSqlite-Bro9efsl.d.mts} +1 -1
  15. package/dist/client/index.d.mts +31 -10
  16. package/dist/client/index.d.ts +31 -10
  17. package/dist/client/index.js +185 -36
  18. package/dist/client/index.js.map +1 -1
  19. package/dist/client/index.mjs +182 -37
  20. package/dist/client/index.mjs.map +1 -1
  21. package/dist/discovery/index.d.mts +3 -3
  22. package/dist/discovery/index.d.ts +3 -3
  23. package/dist/discovery/index.js +12 -20
  24. package/dist/discovery/index.js.map +1 -1
  25. package/dist/discovery/index.mjs +12 -20
  26. package/dist/discovery/index.mjs.map +1 -1
  27. package/dist/index.d.mts +8 -6
  28. package/dist/index.d.ts +8 -6
  29. package/dist/index.js +201 -66
  30. package/dist/index.js.map +1 -1
  31. package/dist/index.mjs +198 -67
  32. package/dist/index.mjs.map +1 -1
  33. package/dist/node.d.mts +2 -2
  34. package/dist/node.d.ts +2 -2
  35. package/dist/node.js +272 -66
  36. package/dist/node.js.map +1 -1
  37. package/dist/node.mjs +269 -67
  38. package/dist/node.mjs.map +1 -1
  39. package/dist/storage/bun.d.mts +4 -4
  40. package/dist/storage/bun.d.ts +4 -4
  41. package/dist/storage/bun.js +169 -0
  42. package/dist/storage/bun.js.map +1 -1
  43. package/dist/storage/bun.mjs +169 -0
  44. package/dist/storage/bun.mjs.map +1 -1
  45. package/dist/storage/index.d.mts +2 -2
  46. package/dist/storage/index.d.ts +2 -2
  47. package/dist/storage/index.js +99 -0
  48. package/dist/storage/index.js.map +1 -1
  49. package/dist/storage/index.mjs +99 -0
  50. package/dist/storage/index.mjs.map +1 -1
  51. package/dist/storage/node.d.mts +2 -2
  52. package/dist/storage/node.d.ts +2 -2
  53. package/dist/storage/node.js +170 -0
  54. package/dist/storage/node.js.map +1 -1
  55. package/dist/storage/node.mjs +170 -0
  56. package/dist/storage/node.mjs.map +1 -1
  57. package/dist/{store-C8MZlfuz.d.ts → store-CAQLSbEj.d.ts} +38 -1
  58. package/dist/{store-BiuM2V9N.d.mts → store-CuXwe5Rg.d.mts} +38 -1
  59. package/dist/wallet/index.js +38 -24
  60. package/dist/wallet/index.js.map +1 -1
  61. package/dist/wallet/index.mjs +38 -24
  62. package/dist/wallet/index.mjs.map +1 -1
  63. package/package.json +1 -1
package/dist/bun.mjs CHANGED
@@ -137,6 +137,11 @@ var MintDiscoveryError = class extends Error {
137
137
  }
138
138
  baseUrl;
139
139
  };
140
+ var DEFAULT_NOSTR_RELAYS = [
141
+ "wss://relay.damus.io",
142
+ "wss://nos.lol",
143
+ "wss://relay.routstr.com"
144
+ ];
140
145
  var ModelManager = class _ModelManager {
141
146
  constructor(adapter, config = {}) {
142
147
  this.adapter = adapter;
@@ -330,11 +335,11 @@ var ModelManager = class _ModelManager {
330
335
  return this.bootstrapFromHttp(torMode, forceRefresh);
331
336
  }
332
337
  /**
333
- * Resolve Nostr relay URLs for a given use case.
334
- * Returns user-configured relays if set, otherwise the provided defaults.
338
+ * Resolve Nostr relay URLs.
339
+ * Returns user-configured relays if set, otherwise the shared defaults.
335
340
  */
336
- getNostrRelays(defaults) {
337
- return this.nostrRelays && this.nostrRelays.length > 0 ? this.nostrRelays : defaults;
341
+ getNostrRelays() {
342
+ return this.nostrRelays && this.nostrRelays.length > 0 ? this.nostrRelays : DEFAULT_NOSTR_RELAYS;
338
343
  }
339
344
  /**
340
345
  * Bootstrap providers from Nostr network (kind 38421)
@@ -343,11 +348,7 @@ var ModelManager = class _ModelManager {
343
348
  * @returns Array of provider base URLs
344
349
  */
345
350
  async bootstrapFromNostr(kind, torMode, forceRefresh = false) {
346
- const relays = this.getNostrRelays([
347
- "wss://relay.primal.net",
348
- "wss://nos.lol",
349
- "wss://relay.damus.io"
350
- ]);
351
+ const relays = this.getNostrRelays();
351
352
  const cached = await this.getCachedNostrEvents(
352
353
  { kinds: [kind] },
353
354
  this.cacheTTL,
@@ -530,12 +531,7 @@ var ModelManager = class _ModelManager {
530
531
  );
531
532
  let sessionEvents = cached;
532
533
  if (cached.length === 0) {
533
- const lgtmRelays = this.getNostrRelays([
534
- "wss://relay.primal.net",
535
- "wss://nos.lol",
536
- "wss://relay.damus.io",
537
- "wss://relay.routstr.com"
538
- ]);
534
+ const lgtmRelays = this.getNostrRelays();
539
535
  const pool = new RelayPool();
540
536
  const timeoutMs = 5e3;
541
537
  await new Promise((resolve) => {
@@ -781,11 +777,7 @@ var ModelManager = class _ModelManager {
781
777
  return cachedModels;
782
778
  }
783
779
  }
784
- const relays = this.getNostrRelays([
785
- "wss://relay.damus.io",
786
- "wss://nos.lol",
787
- "wss://relay.routstr.com"
788
- ]);
780
+ const relays = this.getNostrRelays();
789
781
  const cached = await this.getCachedNostrEvents(
790
782
  { kinds: [38423], "#d": ["routstr-21-models"], authors: [this.routstrPubkey] },
791
783
  this.cacheTTL,
@@ -1997,8 +1989,8 @@ var BalanceManager = class _BalanceManager {
1997
1989
  const refundableProviderBalance = Object.entries(
1998
1990
  balanceState.providerBalances
1999
1991
  ).filter(([providerBaseUrl]) => providerBaseUrl !== baseUrl).reduce((sum, [, value]) => sum + value, 0);
2000
- if (totalMintBalance + targetProviderBalance < adjustedAmount && totalMintBalance + targetProviderBalance + refundableProviderBalance >= adjustedAmount && retryCount < 2) {
2001
- await this._refundOtherProvidersForTopUp(baseUrl, mintUrl, retryCount);
1992
+ if (totalMintBalance + targetProviderBalance < adjustedAmount && totalMintBalance + targetProviderBalance + refundableProviderBalance >= adjustedAmount && retryCount < 3) {
1993
+ await this._refundOtherProvidersForTopUp(baseUrl, mintUrl, retryCount, adjustedAmount);
2002
1994
  return this.createProviderToken({
2003
1995
  ...options,
2004
1996
  retryCount: retryCount + 1
@@ -2137,33 +2129,47 @@ var BalanceManager = class _BalanceManager {
2137
2129
  }
2138
2130
  return candidates;
2139
2131
  }
2140
- async _refundOtherProvidersForTopUp(baseUrl, mintUrl, retryCount) {
2132
+ async _refundOtherProvidersForTopUp(baseUrl, mintUrl, retryCount, requiredAmount) {
2141
2133
  const apiKeyDistribution = this.storageAdapter.getApiKeyDistribution();
2142
2134
  const forceRefund = retryCount >= 2;
2143
- const apiKeysToRefund = apiKeyDistribution.filter(
2144
- (apiKey) => apiKey.baseUrl !== baseUrl && apiKey.amount > 0
2145
- );
2146
- const apiKeyRefundResults = await Promise.allSettled(
2147
- apiKeysToRefund.map(async (apiKeyEntry) => {
2148
- const fullApiKeyEntry = this.storageAdapter.getApiKey(
2149
- apiKeyEntry.baseUrl
2150
- );
2151
- if (!fullApiKeyEntry) {
2152
- return { baseUrl: apiKeyEntry.baseUrl, success: false };
2153
- }
2154
- const result = await this.refundApiKey({
2135
+ const candidates = apiKeyDistribution.filter((apiKey) => apiKey.baseUrl !== baseUrl && apiKey.amount > 0).map((apiKey) => {
2136
+ const full = this.storageAdapter.getApiKey(apiKey.baseUrl);
2137
+ return {
2138
+ baseUrl: apiKey.baseUrl,
2139
+ amount: apiKey.amount,
2140
+ lastUsed: full?.lastUsed ?? 0,
2141
+ key: full?.key
2142
+ };
2143
+ }).filter((c) => c.key != null).sort((a, b) => a.lastUsed - b.lastUsed);
2144
+ if (candidates.length === 0) return;
2145
+ if (forceRefund) {
2146
+ for (const candidate of candidates) {
2147
+ await this.refundApiKey({
2155
2148
  mintUrl,
2156
- baseUrl: apiKeyEntry.baseUrl,
2157
- apiKey: fullApiKeyEntry.key,
2158
- forceRefund
2149
+ baseUrl: candidate.baseUrl,
2150
+ apiKey: candidate.key,
2151
+ forceRefund: true
2159
2152
  });
2160
- return { baseUrl: apiKeyEntry.baseUrl, success: result.success };
2161
- })
2162
- );
2163
- for (const result of apiKeyRefundResults) {
2164
- if (result.status === "fulfilled" && result.value.success) {
2165
- this.storageAdapter.updateApiKeyBalance(result.value.baseUrl, 0);
2153
+ const newState = await this.getBalanceState();
2154
+ const newAvailable = (newState.mintBalances[mintUrl] || 0) + (newState.providerBalances[baseUrl] || 0);
2155
+ if (newAvailable >= requiredAmount) {
2156
+ this.logger.log(
2157
+ `_refundOtherProvidersForTopUp: freed enough balance (${newAvailable} >= ${requiredAmount}), stopping early`
2158
+ );
2159
+ return;
2160
+ }
2166
2161
  }
2162
+ } else {
2163
+ await Promise.allSettled(
2164
+ candidates.map(
2165
+ (candidate) => this.refundApiKey({
2166
+ mintUrl,
2167
+ baseUrl: candidate.baseUrl,
2168
+ apiKey: candidate.key,
2169
+ forceRefund: false
2170
+ })
2171
+ )
2172
+ );
2167
2173
  }
2168
2174
  }
2169
2175
  /**
@@ -3160,6 +3166,149 @@ var SDK_STORAGE_KEYS = {
3160
3166
  PROVIDERS_ON_COOLDOWN: "providers_on_cooldown"
3161
3167
  };
3162
3168
 
3169
+ // storage/usageTracking/aggregate.ts
3170
+ var pad2 = (n) => String(n).padStart(2, "0");
3171
+ var aggregateColumns = "COUNT(*) AS requests, COALESCE(SUM(prompt_tokens), 0) AS promptTokens, COALESCE(SUM(completion_tokens), 0) AS completionTokens, COALESCE(SUM(total_tokens), 0) AS totalTokens, COALESCE(SUM(cost), 0) AS cost, COALESCE(SUM(sats_cost), 0) AS satsCost, COALESCE(SUM(base_msats), 0) AS baseMsats, COALESCE(SUM(input_msats), 0) AS inputMsats, COALESCE(SUM(output_msats), 0) AS outputMsats, COALESCE(SUM(total_msats), 0) AS totalMsats, COALESCE(SUM(total_usd), 0) AS totalUsd, COALESCE(SUM(cache_read_input_tokens), 0) AS cacheReadInputTokens, COALESCE(SUM(cache_creation_input_tokens), 0) AS cacheCreationInputTokens, COALESCE(SUM(cache_read_msats), 0) AS cacheReadMsats, COALESCE(SUM(cache_creation_msats), 0) AS cacheCreationMsats";
3172
+ var sqlGroupExpr = (groupBy) => {
3173
+ switch (groupBy) {
3174
+ case "modelId":
3175
+ return { expr: "model_id", usesTz: false };
3176
+ case "baseUrl":
3177
+ return { expr: "base_url", usesTz: false };
3178
+ case "client":
3179
+ return { expr: "client", usesTz: false };
3180
+ case "sessionId":
3181
+ return { expr: "session_id", usesTz: false };
3182
+ case "provider":
3183
+ return { expr: "provider", usesTz: false };
3184
+ case "day":
3185
+ return {
3186
+ expr: "strftime('%Y-%m-%d', (timestamp - ? * 60000) / 1000, 'unixepoch')",
3187
+ usesTz: true
3188
+ };
3189
+ case "hour":
3190
+ return {
3191
+ expr: "strftime('%H', (timestamp - ? * 60000) / 1000, 'unixepoch')",
3192
+ usesTz: true
3193
+ };
3194
+ }
3195
+ };
3196
+ var buildAggregateSql = (tableName, where, options = {}) => {
3197
+ if (!options.groupBy) {
3198
+ return {
3199
+ sql: `SELECT NULL AS grp, ${aggregateColumns} FROM ${tableName} ${where.sql}`,
3200
+ params: where.params
3201
+ };
3202
+ }
3203
+ const { expr, usesTz } = sqlGroupExpr(options.groupBy);
3204
+ const tzParams = usesTz ? [options.tzOffsetMinutes ?? 0] : [];
3205
+ const orderBy = options.groupBy === "day" || options.groupBy === "hour" ? "ORDER BY grp ASC" : "ORDER BY satsCost DESC";
3206
+ return {
3207
+ sql: `SELECT ${expr} AS grp, ${aggregateColumns} FROM ${tableName} ${where.sql} GROUP BY grp ${orderBy}`,
3208
+ params: [...tzParams, ...where.params]
3209
+ };
3210
+ };
3211
+ var mapAggregateRow = (row) => ({
3212
+ group: row.grp == null ? null : String(row.grp),
3213
+ requests: Number(row.requests ?? 0),
3214
+ promptTokens: Number(row.promptTokens ?? 0),
3215
+ completionTokens: Number(row.completionTokens ?? 0),
3216
+ totalTokens: Number(row.totalTokens ?? 0),
3217
+ cost: Number(row.cost ?? 0),
3218
+ satsCost: Number(row.satsCost ?? 0),
3219
+ baseMsats: Number(row.baseMsats ?? 0),
3220
+ inputMsats: Number(row.inputMsats ?? 0),
3221
+ outputMsats: Number(row.outputMsats ?? 0),
3222
+ totalMsats: Number(row.totalMsats ?? 0),
3223
+ totalUsd: Number(row.totalUsd ?? 0),
3224
+ cacheReadInputTokens: Number(row.cacheReadInputTokens ?? 0),
3225
+ cacheCreationInputTokens: Number(row.cacheCreationInputTokens ?? 0),
3226
+ cacheReadMsats: Number(row.cacheReadMsats ?? 0),
3227
+ cacheCreationMsats: Number(row.cacheCreationMsats ?? 0)
3228
+ });
3229
+ var jsGroupKey = (entry, groupBy, tzOffsetMinutes) => {
3230
+ switch (groupBy) {
3231
+ case "modelId":
3232
+ return entry.modelId ?? null;
3233
+ case "baseUrl":
3234
+ return entry.baseUrl ?? null;
3235
+ case "client":
3236
+ return entry.client ?? null;
3237
+ case "sessionId":
3238
+ return entry.sessionId ?? null;
3239
+ case "provider":
3240
+ return entry.provider ?? null;
3241
+ case "day": {
3242
+ const d = new Date(entry.timestamp - tzOffsetMinutes * 6e4);
3243
+ return `${d.getUTCFullYear()}-${pad2(d.getUTCMonth() + 1)}-${pad2(d.getUTCDate())}`;
3244
+ }
3245
+ case "hour": {
3246
+ const d = new Date(entry.timestamp - tzOffsetMinutes * 6e4);
3247
+ return pad2(d.getUTCHours());
3248
+ }
3249
+ }
3250
+ };
3251
+ var reduceAggregate = (entries, options = {}) => {
3252
+ const emptyRow = (group) => ({
3253
+ group,
3254
+ requests: 0,
3255
+ promptTokens: 0,
3256
+ completionTokens: 0,
3257
+ totalTokens: 0,
3258
+ cost: 0,
3259
+ satsCost: 0,
3260
+ baseMsats: 0,
3261
+ inputMsats: 0,
3262
+ outputMsats: 0,
3263
+ totalMsats: 0,
3264
+ totalUsd: 0,
3265
+ cacheReadInputTokens: 0,
3266
+ cacheCreationInputTokens: 0,
3267
+ cacheReadMsats: 0,
3268
+ cacheCreationMsats: 0
3269
+ });
3270
+ const accumulate = (row, entry) => {
3271
+ row.requests += 1;
3272
+ row.promptTokens += entry.promptTokens;
3273
+ row.completionTokens += entry.completionTokens;
3274
+ row.totalTokens += entry.totalTokens;
3275
+ row.cost += entry.cost;
3276
+ row.satsCost += entry.satsCost;
3277
+ row.baseMsats += entry.baseMsats ?? 0;
3278
+ row.inputMsats += entry.inputMsats ?? 0;
3279
+ row.outputMsats += entry.outputMsats ?? 0;
3280
+ row.totalMsats += entry.totalMsats ?? 0;
3281
+ row.totalUsd += entry.totalUsd ?? 0;
3282
+ row.cacheReadInputTokens += entry.cacheReadInputTokens ?? 0;
3283
+ row.cacheCreationInputTokens += entry.cacheCreationInputTokens ?? 0;
3284
+ row.cacheReadMsats += entry.cacheReadMsats ?? 0;
3285
+ row.cacheCreationMsats += entry.cacheCreationMsats ?? 0;
3286
+ };
3287
+ if (!options.groupBy) {
3288
+ const total = emptyRow(null);
3289
+ for (const entry of entries) accumulate(total, entry);
3290
+ return [total];
3291
+ }
3292
+ const tz = options.tzOffsetMinutes ?? 0;
3293
+ const groups = /* @__PURE__ */ new Map();
3294
+ for (const entry of entries) {
3295
+ const key = jsGroupKey(entry, options.groupBy, tz);
3296
+ let row = groups.get(key);
3297
+ if (!row) {
3298
+ row = emptyRow(key);
3299
+ groups.set(key, row);
3300
+ }
3301
+ accumulate(row, entry);
3302
+ }
3303
+ const rows = [...groups.values()];
3304
+ if (options.groupBy === "day" || options.groupBy === "hour") {
3305
+ rows.sort((a, b) => (a.group ?? "").localeCompare(b.group ?? ""));
3306
+ } else {
3307
+ rows.sort((a, b) => b.satsCost - a.satsCost);
3308
+ }
3309
+ return rows;
3310
+ };
3311
+
3163
3312
  // storage/usageTracking/indexedDB.ts
3164
3313
  var DEFAULT_DB_NAME = "routstr-sdk";
3165
3314
  var DEFAULT_STORE_NAME = "usage_tracking";
@@ -3222,6 +3371,9 @@ var matchesFilters = (entry, options = {}) => {
3222
3371
  if (options.client && entry.client !== options.client) {
3223
3372
  return false;
3224
3373
  }
3374
+ if (options.clients && options.clients.length > 0 && (entry.client == null || !options.clients.includes(entry.client))) {
3375
+ return false;
3376
+ }
3225
3377
  if (options.provider && entry.provider !== options.provider) {
3226
3378
  return false;
3227
3379
  }
@@ -3320,6 +3472,10 @@ var createIndexedDBUsageTrackingDriver = (options = {}) => {
3320
3472
  const results = await this.list(options2);
3321
3473
  return results.length;
3322
3474
  },
3475
+ async aggregate(options2 = {}) {
3476
+ const entries = await this.list(options2);
3477
+ return reduceAggregate(entries, options2);
3478
+ },
3323
3479
  async deleteOlderThan(timestamp) {
3324
3480
  await ensureMigrated();
3325
3481
  const db = await getDb();
@@ -3377,6 +3533,9 @@ var matchesFilters2 = (entry, options = {}) => {
3377
3533
  if (options.client && entry.client !== options.client) {
3378
3534
  return false;
3379
3535
  }
3536
+ if (options.clients && options.clients.length > 0 && (entry.client == null || !options.clients.includes(entry.client))) {
3537
+ return false;
3538
+ }
3380
3539
  if (options.provider && entry.provider !== options.provider) {
3381
3540
  return false;
3382
3541
  }
@@ -3409,6 +3568,10 @@ var createMemoryUsageTrackingDriver = (seed = []) => {
3409
3568
  async count(options = {}) {
3410
3569
  return (await this.list(options)).length;
3411
3570
  },
3571
+ async aggregate(options = {}) {
3572
+ const entries = [...store.values()].filter((entry) => matchesFilters2(entry, options));
3573
+ return reduceAggregate(entries, options);
3574
+ },
3412
3575
  async deleteOlderThan(timestamp) {
3413
3576
  let deleted = 0;
3414
3577
  for (const [id, entry] of store.entries()) {
@@ -4560,13 +4723,14 @@ function hasUsageChanged(previous, next) {
4560
4723
  function isInspectionComplete(responseIdCaptured, usage) {
4561
4724
  return responseIdCaptured && !!usage && usage.totalTokens > 0 && typeof usage.totalMsats === "number" && !!usage.provider;
4562
4725
  }
4563
- async function inspectSSEWebStream(stream, onUsage, onResponseId) {
4726
+ async function inspectSSEWebStream(stream, onUsage, onResponseId, options) {
4564
4727
  const reader = stream.getReader();
4565
4728
  const decoder = new TextDecoder("utf-8");
4566
4729
  let buffer = "";
4567
4730
  let capturedUsage = null;
4568
4731
  let capturedResponseId;
4569
4732
  let responseIdCaptured = false;
4733
+ let rawChunkSequence = 0;
4570
4734
  const inspectDataPayload = (jsonText) => {
4571
4735
  const trimmed = jsonText.trim();
4572
4736
  if (!trimmed || trimmed === "[DONE]") {
@@ -4637,7 +4801,9 @@ async function inspectSSEWebStream(stream, onUsage, onResponseId) {
4637
4801
  const { value, done } = await reader.read();
4638
4802
  if (done) break;
4639
4803
  if (value && value.byteLength > 0) {
4640
- buffer += decoder.decode(value, { stream: true });
4804
+ const text = decoder.decode(value, { stream: true });
4805
+ void options?.onRawChunk?.(value, rawChunkSequence++, text);
4806
+ buffer += text;
4641
4807
  drainBufferedEvents();
4642
4808
  }
4643
4809
  }
@@ -4782,6 +4948,7 @@ var RoutstrClient = class {
4782
4948
  this.mode = mode;
4783
4949
  this.usageTrackingDriver = options.usageTrackingDriver;
4784
4950
  this.sdkStore = options.sdkStore;
4951
+ this.requestResponseLogSink = options.requestResponseLogSink;
4785
4952
  this.providerManager = options.providerManager ?? new ProviderManager(providerRegistry, this.sdkStore, this.logger);
4786
4953
  }
4787
4954
  walletAdapter;
@@ -4796,6 +4963,7 @@ var RoutstrClient = class {
4796
4963
  usageTrackingDriver;
4797
4964
  sdkStore;
4798
4965
  logger;
4966
+ requestResponseLogSink;
4799
4967
  /**
4800
4968
  * Get the current client mode
4801
4969
  */
@@ -4986,6 +5154,7 @@ var RoutstrClient = class {
4986
5154
  let usagePromise = Promise.resolve({});
4987
5155
  if (contentType.includes("text/event-stream") && response.body) {
4988
5156
  const [clientStream, inspectStream] = response.body.tee();
5157
+ const requestResponseLogId = response.requestResponseLogId;
4989
5158
  processedResponse = new Response(clientStream, {
4990
5159
  status: response.status,
4991
5160
  statusText: response.statusText,
@@ -4993,6 +5162,7 @@ var RoutstrClient = class {
4993
5162
  });
4994
5163
  processedResponse.baseUrl = response.baseUrl;
4995
5164
  processedResponse.token = response.token;
5165
+ processedResponse.requestResponseLogId = requestResponseLogId;
4996
5166
  usagePromise = inspectSSEWebStream(
4997
5167
  inspectStream,
4998
5168
  (usage) => {
@@ -5002,8 +5172,23 @@ var RoutstrClient = class {
5002
5172
  (responseId) => {
5003
5173
  capturedResponseId = responseId;
5004
5174
  processedResponse.requestId = responseId;
5175
+ },
5176
+ {
5177
+ onRawChunk: (_chunk, sequence, text) => {
5178
+ void this.requestResponseLogSink?.logResponseChunk?.(
5179
+ requestResponseLogId,
5180
+ sequence,
5181
+ text
5182
+ );
5183
+ }
5005
5184
  }
5006
- );
5185
+ ).then(async (result) => {
5186
+ await this.requestResponseLogSink?.logResponseEnd?.(requestResponseLogId);
5187
+ return result;
5188
+ }).catch(async (error) => {
5189
+ await this.requestResponseLogSink?.logResponseError?.(requestResponseLogId, error);
5190
+ throw error;
5191
+ });
5007
5192
  processedResponse.usagePromise = usagePromise;
5008
5193
  }
5009
5194
  return {
@@ -5037,16 +5222,30 @@ var RoutstrClient = class {
5037
5222
  const { path, method, body, baseUrl, token, headers } = params;
5038
5223
  try {
5039
5224
  const url = `${baseUrl.replace(/\/$/, "")}${path}`;
5225
+ const requestBodyText = body === void 0 || method === "GET" ? void 0 : JSON.stringify(body);
5226
+ const requestLogId = await this.requestResponseLogSink?.logRequest?.({
5227
+ method,
5228
+ url,
5229
+ path,
5230
+ baseUrl,
5231
+ headers,
5232
+ body,
5233
+ rawBody: requestBodyText
5234
+ });
5040
5235
  if (this.mode === "xcashu") this._log("DEBUG", "HEADERS,", headers);
5041
5236
  const response = await fetch(url, {
5042
5237
  method,
5043
5238
  headers,
5044
- body: body === void 0 || method === "GET" ? void 0 : JSON.stringify(body)
5239
+ body: requestBodyText
5045
5240
  });
5046
5241
  if (this.mode === "xcashu") this._log("DEBUG", "response,", response);
5047
5242
  response.baseUrl = baseUrl;
5048
5243
  response.token = token;
5244
+ response.requestResponseLogId = requestLogId;
5245
+ await this.requestResponseLogSink?.logResponseStart?.(requestLogId, response);
5246
+ const contentType = response.headers.get("content-type") || "";
5049
5247
  if (!response.ok) {
5248
+ void this.requestResponseLogSink?.logResponseBody?.(requestLogId, response.clone());
5050
5249
  const requestId = response.headers.get("x-routstr-request-id") || void 0;
5051
5250
  let bodyText;
5052
5251
  try {
@@ -5064,6 +5263,9 @@ var RoutstrClient = class {
5064
5263
  params.retryCount ?? 0
5065
5264
  );
5066
5265
  }
5266
+ if (!contentType.includes("text/event-stream")) {
5267
+ void this.requestResponseLogSink?.logResponseBody?.(requestLogId, response.clone());
5268
+ }
5067
5269
  return response;
5068
5270
  } catch (error) {
5069
5271
  if (isNetworkErrorMessage(error?.message || "")) {
@@ -5953,15 +6155,8 @@ async function fetchAIResponse(options, callbacks, deps) {
5953
6155
  const apiMessages = await convertMessages(messageHistory);
5954
6156
  callbacks.onPaymentProcessing?.(true);
5955
6157
  callbacks.onTokenCreated?.(deps.getPendingCashuTokenAmount?.() ?? 0);
5956
- const providerInfo = await deps.providerRegistry.getProviderInfo(baseUrl);
5957
- const providerVersion = providerInfo?.version ?? "";
5958
- let modelIdForRequest = selectedModel.id;
5959
- if (/^0\.1\./.test(providerVersion)) {
5960
- const newModel = await deps.client.getProviderManager().getModelForProvider(baseUrl, selectedModel.id);
5961
- modelIdForRequest = newModel?.id ?? selectedModel.id;
5962
- }
5963
6158
  const body = {
5964
- model: modelIdForRequest,
6159
+ model: selectedModel.id,
5965
6160
  messages: apiMessages,
5966
6161
  stream: true
5967
6162
  };
@@ -6096,7 +6291,8 @@ async function resolveRouteRequestContext(options) {
6096
6291
  usageTrackingDriver,
6097
6292
  sdkStore,
6098
6293
  providerManager: providedProviderManager,
6099
- logger
6294
+ logger,
6295
+ requestResponseLogSink
6100
6296
  } = options;
6101
6297
  let modelManager;
6102
6298
  let providers;
@@ -6145,15 +6341,8 @@ async function resolveRouteRequestContext(options) {
6145
6341
  baseUrl = cheapest.baseUrl;
6146
6342
  selectedModel = cheapest.model;
6147
6343
  }
6148
- const balances = await walletAdapter.getBalances();
6149
- const totalBalance = Object.values(balances).reduce((sum, v) => sum + v, 0);
6150
- if (totalBalance <= 0) {
6151
- throw new Error(
6152
- "Wallet balance is empty. Add a mint and fund it before making requests."
6153
- );
6154
- }
6155
6344
  const providerMints = providerRegistry.getProviderMints(baseUrl);
6156
- const mintUrl = walletAdapter.getActiveMintUrl() || providerMints[0] || Object.keys(balances)[0];
6345
+ const mintUrl = walletAdapter.getActiveMintUrl() || providerMints[0] || Object.keys(await walletAdapter.getBalances())[0];
6157
6346
  if (!mintUrl) {
6158
6347
  throw new Error("No mint configured in wallet");
6159
6348
  }
@@ -6163,7 +6352,7 @@ async function resolveRouteRequestContext(options) {
6163
6352
  providerRegistry,
6164
6353
  "min",
6165
6354
  mode,
6166
- { usageTrackingDriver, sdkStore, providerManager, logger }
6355
+ { usageTrackingDriver, sdkStore, providerManager, logger, requestResponseLogSink }
6167
6356
  );
6168
6357
  const maxTokens = extractMaxTokens(requestBody);
6169
6358
  const stream = extractStream(requestBody);
@@ -6316,6 +6505,11 @@ var buildWhereClause = (options = {}) => {
6316
6505
  clauses.push("client = ?");
6317
6506
  params.push(options.client);
6318
6507
  }
6508
+ if (options.clients && options.clients.length > 0) {
6509
+ const placeholders = options.clients.map(() => "?").join(", ");
6510
+ clauses.push(`client IN (${placeholders})`);
6511
+ params.push(...options.clients);
6512
+ }
6319
6513
  if (options.provider) {
6320
6514
  clauses.push("provider = ?");
6321
6515
  params.push(options.provider);
@@ -6489,6 +6683,13 @@ var createBunSqliteUsageTrackingDriver = (options = {}) => {
6489
6683
  const row = db.query(query).get(...params);
6490
6684
  return Number(row?.count ?? 0);
6491
6685
  },
6686
+ async aggregate(options2 = {}) {
6687
+ await ensureMigrated();
6688
+ const where = buildWhereClause(options2);
6689
+ const { sql, params } = buildAggregateSql(tableName, where, options2);
6690
+ const rows = db.query(sql).all(...params);
6691
+ return rows.map(mapAggregateRow);
6692
+ },
6492
6693
  async deleteOlderThan(timestamp) {
6493
6694
  await ensureMigrated();
6494
6695
  const before = timestamp;
@@ -6527,6 +6728,6 @@ async function createDefaultBunSqliteDriver(dbPath = "routstr.sqlite", options)
6527
6728
  return createBunSqliteDriver(dbPath, options);
6528
6729
  }
6529
6730
 
6530
- export { BalanceManager, BunModelManager, CashuSpender, FailoverError, InsufficientBalanceError, MintDiscovery, MintDiscoveryError, MintUnreachableError, BunModelManager as ModelManager, ModelNotFoundError, NoProvidersAvailableError, ProviderBootstrapError, ProviderError, ProviderManager, RoutstrClient, SDK_STORAGE_KEYS, StreamProcessor, StreamingError, TokenOperationError, consoleLogger, createBunModelManager, createBunSqliteDriver, createBunSqliteUsageTrackingDriver2 as createBunSqliteUsageTrackingDriver, createBunSqliteUsageTrackingDriver as createBunSqliteUsageTrackingDriverWithDatabase, createDefaultBunSqliteDriver, createDiscoveryAdapterFromStore, createIndexedDBDriver, createIndexedDBUsageTrackingDriver, createMemoryDriver, createMemoryUsageTrackingDriver, createProviderRegistryFromDiscoveryAdapter, createProviderRegistryFromStore, createSSEParserTransform, createSdkStore, createShardedDiscoveryAdapter, createStorageAdapterFromStore, fetchAIResponse, filterBaseUrlsForTor, getDefaultDiscoveryAdapter, getDefaultProviderRegistry, getDefaultSdkDriver, getDefaultSdkStore, getDefaultStorageAdapter, getDefaultUsageTrackingDriver, getProviderEndpoints, inspectSSEWebStream, isOnionUrl, isTorContext, localStorageDriver, noopLogger, normalizeProviderUrl, routeRequests, setDefaultUsageTrackingDriver };
6731
+ export { BalanceManager, BunModelManager, CashuSpender, FailoverError, InsufficientBalanceError, MintDiscovery, MintDiscoveryError, MintUnreachableError, BunModelManager as ModelManager, ModelNotFoundError, NoProvidersAvailableError, ProviderBootstrapError, ProviderError, ProviderManager, RoutstrClient, SDK_STORAGE_KEYS, StreamProcessor, StreamingError, TokenOperationError, consoleLogger, createBunModelManager, createBunSqliteDriver, createBunSqliteUsageTrackingDriver2 as createBunSqliteUsageTrackingDriver, createBunSqliteUsageTrackingDriver as createBunSqliteUsageTrackingDriverWithDatabase, createDefaultBunSqliteDriver, createDiscoveryAdapterFromStore, createIndexedDBDriver, createIndexedDBUsageTrackingDriver, createMemoryDriver, createMemoryUsageTrackingDriver, createProviderRegistryFromDiscoveryAdapter, createProviderRegistryFromStore, createSSEParserTransform, createSdkStore, createShardedDiscoveryAdapter, createStorageAdapterFromStore, extractResponseId, extractUsageFromResponseBody, extractUsageFromSSEJson, fetchAIResponse, filterBaseUrlsForTor, getDefaultDiscoveryAdapter, getDefaultProviderRegistry, getDefaultSdkDriver, getDefaultSdkStore, getDefaultStorageAdapter, getDefaultUsageTrackingDriver, getProviderEndpoints, inspectSSEWebStream, isOnionUrl, isTorContext, localStorageDriver, noopLogger, normalizeProviderUrl, routeRequests, setDefaultUsageTrackingDriver, toUsageStats };
6531
6732
  //# sourceMappingURL=bun.mjs.map
6532
6733
  //# sourceMappingURL=bun.mjs.map