@routstr/sdk 0.3.10 → 0.3.12

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 (64) hide show
  1. package/README.md +19 -6
  2. package/dist/browser.d.mts +2 -2
  3. package/dist/browser.d.ts +2 -2
  4. package/dist/browser.js +201 -66
  5. package/dist/browser.js.map +1 -1
  6. package/dist/browser.mjs +198 -67
  7. package/dist/browser.mjs.map +1 -1
  8. package/dist/bun.d.mts +5 -5
  9. package/dist/bun.d.ts +5 -5
  10. package/dist/bun.js +275 -66
  11. package/dist/bun.js.map +1 -1
  12. package/dist/bun.mjs +272 -67
  13. package/dist/bun.mjs.map +1 -1
  14. package/dist/{bunSqlite-BMTseLIz.d.ts → bunSqlite-BmXWNc25.d.ts} +1 -1
  15. package/dist/{bunSqlite-D6AreVE2.d.mts → bunSqlite-Bro9efsl.d.mts} +1 -1
  16. package/dist/client/index.d.mts +31 -10
  17. package/dist/client/index.d.ts +31 -10
  18. package/dist/client/index.js +185 -36
  19. package/dist/client/index.js.map +1 -1
  20. package/dist/client/index.mjs +182 -37
  21. package/dist/client/index.mjs.map +1 -1
  22. package/dist/discovery/index.d.mts +3 -3
  23. package/dist/discovery/index.d.ts +3 -3
  24. package/dist/discovery/index.js +12 -20
  25. package/dist/discovery/index.js.map +1 -1
  26. package/dist/discovery/index.mjs +12 -20
  27. package/dist/discovery/index.mjs.map +1 -1
  28. package/dist/index.d.mts +8 -6
  29. package/dist/index.d.ts +8 -6
  30. package/dist/index.js +201 -66
  31. package/dist/index.js.map +1 -1
  32. package/dist/index.mjs +198 -67
  33. package/dist/index.mjs.map +1 -1
  34. package/dist/node.d.mts +2 -2
  35. package/dist/node.d.ts +2 -2
  36. package/dist/node.js +276 -66
  37. package/dist/node.js.map +1 -1
  38. package/dist/node.mjs +273 -67
  39. package/dist/node.mjs.map +1 -1
  40. package/dist/storage/bun.d.mts +4 -4
  41. package/dist/storage/bun.d.ts +4 -4
  42. package/dist/storage/bun.js +173 -0
  43. package/dist/storage/bun.js.map +1 -1
  44. package/dist/storage/bun.mjs +173 -0
  45. package/dist/storage/bun.mjs.map +1 -1
  46. package/dist/storage/index.d.mts +2 -2
  47. package/dist/storage/index.d.ts +2 -2
  48. package/dist/storage/index.js +99 -0
  49. package/dist/storage/index.js.map +1 -1
  50. package/dist/storage/index.mjs +99 -0
  51. package/dist/storage/index.mjs.map +1 -1
  52. package/dist/storage/node.d.mts +2 -2
  53. package/dist/storage/node.d.ts +2 -2
  54. package/dist/storage/node.js +174 -0
  55. package/dist/storage/node.js.map +1 -1
  56. package/dist/storage/node.mjs +174 -0
  57. package/dist/storage/node.mjs.map +1 -1
  58. package/dist/{store-C8MZlfuz.d.ts → store-CAQLSbEj.d.ts} +38 -1
  59. package/dist/{store-BiuM2V9N.d.mts → store-CuXwe5Rg.d.mts} +38 -1
  60. package/dist/wallet/index.js +38 -24
  61. package/dist/wallet/index.js.map +1 -1
  62. package/dist/wallet/index.mjs +38 -24
  63. package/dist/wallet/index.mjs.map +1 -1
  64. package/package.json +7 -3
package/dist/node.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);
@@ -6257,6 +6446,8 @@ var createSqliteDriver = (options = {}) => {
6257
6446
  const initDb = async () => {
6258
6447
  if (!db) {
6259
6448
  db = await loadDatabase(dbPath);
6449
+ db.exec("PRAGMA journal_mode = WAL");
6450
+ db.exec("PRAGMA busy_timeout = 5000");
6260
6451
  db.exec(
6261
6452
  `CREATE TABLE IF NOT EXISTS ${tableName} (key TEXT PRIMARY KEY, value TEXT NOT NULL)`
6262
6453
  );
@@ -6375,6 +6566,11 @@ var buildWhereClause = (options = {}) => {
6375
6566
  clauses.push("client = ?");
6376
6567
  params.push(options.client);
6377
6568
  }
6569
+ if (options.clients && options.clients.length > 0) {
6570
+ const placeholders = options.clients.map(() => "?").join(", ");
6571
+ clauses.push(`client IN (${placeholders})`);
6572
+ params.push(...options.clients);
6573
+ }
6378
6574
  if (options.provider) {
6379
6575
  clauses.push("provider = ?");
6380
6576
  params.push(options.provider);
@@ -6394,6 +6590,8 @@ var createSqliteUsageTrackingDriver = (options = {}) => {
6394
6590
  const initDb = async () => {
6395
6591
  if (!db) {
6396
6592
  db = await loadDatabase2(dbPath);
6593
+ db.exec("PRAGMA journal_mode = WAL");
6594
+ db.exec("PRAGMA busy_timeout = 5000");
6397
6595
  db.exec(`
6398
6596
  CREATE TABLE IF NOT EXISTS ${tableName} (
6399
6597
  id TEXT PRIMARY KEY,
@@ -6564,6 +6762,14 @@ var createSqliteUsageTrackingDriver = (options = {}) => {
6564
6762
  const row = stmt.get(...params);
6565
6763
  return Number(row?.count ?? 0);
6566
6764
  },
6765
+ async aggregate(options2 = {}) {
6766
+ await ensureInit();
6767
+ await ensureMigrated();
6768
+ const where = buildWhereClause(options2);
6769
+ const { sql, params } = buildAggregateSql(tableName, where, options2);
6770
+ const rows = db.prepare(sql).all(...params);
6771
+ return rows.map(mapAggregateRow);
6772
+ },
6567
6773
  async deleteOlderThan(timestamp) {
6568
6774
  await ensureInit();
6569
6775
  await ensureMigrated();
@@ -6594,6 +6800,6 @@ var NodeModelManager = class extends ModelManager {
6594
6800
  };
6595
6801
  var createNodeModelManager = (adapter, config = {}) => new NodeModelManager(adapter, config);
6596
6802
 
6597
- export { BalanceManager, CashuSpender, FailoverError, InsufficientBalanceError, MintDiscovery, MintDiscoveryError, MintUnreachableError, NodeModelManager as ModelManager, ModelNotFoundError, NoProvidersAvailableError, NodeModelManager, ProviderBootstrapError, ProviderError, ProviderManager, RoutstrClient, SDK_STORAGE_KEYS, StreamProcessor, StreamingError, TokenOperationError, consoleLogger, createDiscoveryAdapterFromStore, createIndexedDBDriver, createIndexedDBUsageTrackingDriver, createMemoryDriver, createMemoryUsageTrackingDriver, createNodeModelManager, createProviderRegistryFromDiscoveryAdapter, createProviderRegistryFromStore, createSSEParserTransform, createSdkStore, createShardedDiscoveryAdapter, createSqliteDriver, createSqliteUsageTrackingDriver, createStorageAdapterFromStore, fetchAIResponse, filterBaseUrlsForTor, getDefaultDiscoveryAdapter, getDefaultProviderRegistry, getDefaultSdkDriver, getDefaultSdkStore, getDefaultStorageAdapter, getDefaultUsageTrackingDriver, getProviderEndpoints, inspectSSEWebStream, isOnionUrl, isTorContext, localStorageDriver, noopLogger, normalizeProviderUrl, routeRequests, setDefaultUsageTrackingDriver };
6803
+ export { BalanceManager, CashuSpender, FailoverError, InsufficientBalanceError, MintDiscovery, MintDiscoveryError, MintUnreachableError, NodeModelManager as ModelManager, ModelNotFoundError, NoProvidersAvailableError, NodeModelManager, ProviderBootstrapError, ProviderError, ProviderManager, RoutstrClient, SDK_STORAGE_KEYS, StreamProcessor, StreamingError, TokenOperationError, consoleLogger, createDiscoveryAdapterFromStore, createIndexedDBDriver, createIndexedDBUsageTrackingDriver, createMemoryDriver, createMemoryUsageTrackingDriver, createNodeModelManager, createProviderRegistryFromDiscoveryAdapter, createProviderRegistryFromStore, createSSEParserTransform, createSdkStore, createShardedDiscoveryAdapter, createSqliteDriver, createSqliteUsageTrackingDriver, createStorageAdapterFromStore, extractResponseId, extractUsageFromResponseBody, extractUsageFromSSEJson, fetchAIResponse, filterBaseUrlsForTor, getDefaultDiscoveryAdapter, getDefaultProviderRegistry, getDefaultSdkDriver, getDefaultSdkStore, getDefaultStorageAdapter, getDefaultUsageTrackingDriver, getProviderEndpoints, inspectSSEWebStream, isOnionUrl, isTorContext, localStorageDriver, noopLogger, normalizeProviderUrl, routeRequests, setDefaultUsageTrackingDriver, toUsageStats };
6598
6804
  //# sourceMappingURL=node.mjs.map
6599
6805
  //# sourceMappingURL=node.mjs.map