@routstr/sdk 0.3.5 → 0.3.6

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.
@@ -38,13 +38,16 @@ var ModelManager = class _ModelManager {
38
38
  this.cacheTTL = config.cacheTTL || 210 * 60 * 1e3;
39
39
  this.includeProviderUrls = config.includeProviderUrls || [];
40
40
  this.excludeProviderUrls = config.excludeProviderUrls || [];
41
+ this.routstrPubkey = config.routstrPubkey || "4ad6fa2d16e2a9b576c863b4cf7404a70d4dc320c0c447d10ad6ff58993eacc8";
41
42
  this.logger = (config.logger ?? consoleLogger).child("ModelManager");
42
43
  }
43
44
  cacheTTL;
44
45
  providerDirectoryUrl;
45
46
  includeProviderUrls;
46
47
  excludeProviderUrls;
48
+ routstrPubkey;
47
49
  logger;
50
+ providerNodePubkeysByUrl = /* @__PURE__ */ new Map();
48
51
  /**
49
52
  * Get the list of bootstrapped provider base URLs
50
53
  * @returns Array of provider base URLs
@@ -75,8 +78,13 @@ var ModelManager = class _ModelManager {
75
78
  const lastUpdate = this.adapter.getBaseUrlsLastUpdate();
76
79
  const cacheValid = lastUpdate && Date.now() - lastUpdate <= this.cacheTTL;
77
80
  if (cacheValid) {
81
+ const filteredCachedUrls = this.filterBaseUrlsForTor(
82
+ cachedUrls,
83
+ torMode
84
+ );
78
85
  await this.fetchRoutstr21Models(forceRefresh);
79
- return this.filterBaseUrlsForTor(cachedUrls, torMode);
86
+ await this.syncReviewedProvidersFromNostr(filteredCachedUrls);
87
+ return filteredCachedUrls;
80
88
  }
81
89
  }
82
90
  }
@@ -87,6 +95,7 @@ var ModelManager = class _ModelManager {
87
95
  this.adapter.setBaseUrlsList(filtered);
88
96
  this.adapter.setBaseUrlsLastUpdate(Date.now());
89
97
  await this.fetchRoutstr21Models(forceRefresh);
98
+ await this.syncReviewedProvidersFromNostr(filtered);
90
99
  return filtered;
91
100
  }
92
101
  } catch (e) {
@@ -129,6 +138,7 @@ var ModelManager = class _ModelManager {
129
138
  });
130
139
  const timeline = localEventStore.getTimeline({ kinds: [kind] });
131
140
  const bases = /* @__PURE__ */ new Set();
141
+ this.providerNodePubkeysByUrl = /* @__PURE__ */ new Map();
132
142
  for (const event of timeline) {
133
143
  const eventUrls = [];
134
144
  for (const tag of event.tags) {
@@ -141,6 +151,11 @@ var ModelManager = class _ModelManager {
141
151
  const normalized = this.normalizeUrl(url);
142
152
  if (!torMode || normalized.includes(".onion")) {
143
153
  bases.add(normalized);
154
+ this.addProviderNode(
155
+ this.providerNodePubkeysByUrl,
156
+ normalized,
157
+ event.pubkey
158
+ );
144
159
  }
145
160
  }
146
161
  continue;
@@ -152,6 +167,11 @@ var ModelManager = class _ModelManager {
152
167
  const endpoints = this.getProviderEndpoints(p, torMode);
153
168
  for (const endpoint of endpoints) {
154
169
  bases.add(endpoint);
170
+ this.addProviderNode(
171
+ this.providerNodePubkeysByUrl,
172
+ endpoint,
173
+ p?.pubkey || event.pubkey
174
+ );
155
175
  }
156
176
  }
157
177
  } catch {
@@ -162,11 +182,19 @@ var ModelManager = class _ModelManager {
162
182
  const endpoints = this.getProviderEndpoints(p, torMode);
163
183
  for (const endpoint of endpoints) {
164
184
  bases.add(endpoint);
185
+ this.addProviderNode(
186
+ this.providerNodePubkeysByUrl,
187
+ endpoint,
188
+ p?.pubkey || event.pubkey
189
+ );
165
190
  }
166
191
  }
167
192
  }
168
193
  } catch {
169
- this.logger.warn("NostrBootstrap: failed to parse event content:", event.id);
194
+ this.logger.warn(
195
+ "NostrBootstrap: failed to parse event content:",
196
+ event.id
197
+ );
170
198
  }
171
199
  }
172
200
  }
@@ -197,10 +225,12 @@ var ModelManager = class _ModelManager {
197
225
  const data = await res.json();
198
226
  const providers = Array.isArray(data?.providers) ? data.providers : [];
199
227
  const bases = /* @__PURE__ */ new Set();
228
+ this.providerNodePubkeysByUrl = /* @__PURE__ */ new Map();
200
229
  for (const p of providers) {
201
230
  const endpoints = this.getProviderEndpoints(p, torMode);
202
231
  for (const endpoint of endpoints) {
203
232
  bases.add(endpoint);
233
+ this.addProviderNode(this.providerNodePubkeysByUrl, endpoint, p?.pubkey);
204
234
  }
205
235
  }
206
236
  for (const url of this.includeProviderUrls) {
@@ -217,6 +247,7 @@ var ModelManager = class _ModelManager {
217
247
  this.adapter.setBaseUrlsList(list);
218
248
  this.adapter.setBaseUrlsLastUpdate(Date.now());
219
249
  await this.fetchRoutstr21Models(forceRefresh);
250
+ await this.syncReviewedProvidersFromNostr(list);
220
251
  }
221
252
  return list;
222
253
  } catch (e) {
@@ -224,6 +255,93 @@ var ModelManager = class _ModelManager {
224
255
  throw new ProviderBootstrapError([], `Provider bootstrap failed: ${e}`);
225
256
  }
226
257
  }
258
+ /**
259
+ * Fetch Routstr review events from Nostr (kind 38425) and disable providers
260
+ * whose 38421 node pubkey does not have at least one review tagged `t=lgtm`.
261
+ *
262
+ * Review events are expected to have:
263
+ * - `node`: the reviewed 38421 provider event pubkey
264
+ * - `t`: review label, where `lgtm` means the node looks good
265
+ *
266
+ * @param baseUrls Current provider base URLs to evaluate
267
+ * @returns Array of provider base URLs disabled by the review set
268
+ */
269
+ async syncReviewedProvidersFromNostr(baseUrls = this.adapter.getBaseUrlsList(), providerNodes = this.providerNodePubkeysByUrl) {
270
+ if (baseUrls.length === 0) return [];
271
+ if (!this.adapter.setDisabledProviders) {
272
+ this.logger.warn(
273
+ "NostrReviews: adapter does not support setDisabledProviders; skipping provider disable sync"
274
+ );
275
+ return [];
276
+ }
277
+ const LGTM_RELAYS = [
278
+ "wss://relay.primal.net",
279
+ "wss://nos.lol",
280
+ "wss://relay.damus.io",
281
+ "wss://relay.routstr.com"
282
+ ];
283
+ const reviewedNodePubkeys = /* @__PURE__ */ new Set();
284
+ {
285
+ const pool = new RelayPool();
286
+ const store = new EventStore();
287
+ const timeoutMs = 5e3;
288
+ await new Promise((resolve) => {
289
+ pool.req(LGTM_RELAYS, {
290
+ kinds: [38425],
291
+ "#t": ["lgtm"],
292
+ limit: 500,
293
+ authors: [this.routstrPubkey]
294
+ }).pipe(
295
+ onlyEvents(),
296
+ tap((event) => store.add(event))
297
+ ).subscribe({ complete: () => resolve() });
298
+ setTimeout(() => resolve(), timeoutMs);
299
+ });
300
+ for (const event of store.getTimeline({ kinds: [38425] })) {
301
+ const hasLgtmTag = event.tags.some(
302
+ (tag) => tag[0] === "t" && tag[1]?.toLowerCase() === "lgtm"
303
+ );
304
+ if (!hasLgtmTag) continue;
305
+ for (const tag of event.tags) {
306
+ if (tag[0] === "node" && typeof tag[1] === "string" && tag[1]) {
307
+ reviewedNodePubkeys.add(tag[1]);
308
+ }
309
+ }
310
+ }
311
+ }
312
+ if (reviewedNodePubkeys.size === 0) {
313
+ this.logger.warn(
314
+ "NostrReviews: no kind 38425 lgtm reviews found; keeping disabled providers unchanged"
315
+ );
316
+ return [];
317
+ }
318
+ if (providerNodes.size === 0) {
319
+ this.logger.warn(
320
+ "NostrReviews: no kind 38421 provider node metadata found; keeping disabled providers unchanged"
321
+ );
322
+ return [];
323
+ }
324
+ const disabledByReview = [];
325
+ for (const url of baseUrls) {
326
+ const normalized = this.normalizeUrl(url);
327
+ const nodePubkeys = providerNodes.get(normalized) || /* @__PURE__ */ new Set();
328
+ const hasLgtmReview = Array.from(nodePubkeys).some(
329
+ (pubkey) => reviewedNodePubkeys.has(pubkey)
330
+ );
331
+ if (!hasLgtmReview) {
332
+ disabledByReview.push(normalized);
333
+ }
334
+ }
335
+ this.adapter.setDisabledProviders(Array.from(new Set(disabledByReview)));
336
+ return disabledByReview;
337
+ }
338
+ addProviderNode(map, url, pubkey) {
339
+ if (!pubkey) return;
340
+ const normalized = this.normalizeUrl(url);
341
+ const existing = map.get(normalized) || /* @__PURE__ */ new Set();
342
+ existing.add(pubkey);
343
+ map.set(normalized, existing);
344
+ }
227
345
  /**
228
346
  * Fetch models from all providers and select best-priced options
229
347
  * Uses cache if available and not expired
@@ -416,9 +534,7 @@ var ModelManager = class _ModelManager {
416
534
  kinds: [38423],
417
535
  "#d": ["routstr-21-models"],
418
536
  limit: 1,
419
- authors: [
420
- "4ad6fa2d16e2a9b576c863b4cf7404a70d4dc320c0c447d10ad6ff58993eacc8"
421
- ]
537
+ authors: [this.routstrPubkey]
422
538
  }).pipe(
423
539
  onlyEvents(),
424
540
  tap((event2) => {
@@ -445,7 +561,10 @@ var ModelManager = class _ModelManager {
445
561
  this.adapter.setRoutstr21ModelsLastUpdate(Date.now());
446
562
  return models;
447
563
  } catch {
448
- this.logger.warn("Routstr21Models: failed to parse Nostr event content:", event.id);
564
+ this.logger.warn(
565
+ "Routstr21Models: failed to parse Nostr event content:",
566
+ event.id
567
+ );
449
568
  return cachedModels.length > 0 ? cachedModels : [];
450
569
  }
451
570
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../core/types.ts","../../core/errors.ts","../../discovery/ModelManager.ts","../../discovery/MintDiscovery.ts"],"names":["event"],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * Core types for the Routstr SDK\n * These types are shared across wallet and client modules\n */\n\nexport interface SdkLogger {\n log(...args: unknown[]): void;\n warn(...args: unknown[]): void;\n error(...args: unknown[]): void;\n debug(...args: unknown[]): void;\n child(prefix: string): SdkLogger;\n}\n\nfunction makeConsoleLogger(prefix?: string): SdkLogger {\n const fmt = (args: unknown[]) => (prefix ? [prefix, ...args] : args);\n return {\n log: (...args) => console.log(...fmt(args)),\n warn: (...args) => console.warn(...fmt(args)),\n error: (...args) => console.error(...fmt(args)),\n debug: (...args) => console.log(...fmt(args)),\n child: (p) => makeConsoleLogger(prefix ? `${prefix}:${p}` : p),\n };\n}\n\nexport const consoleLogger: SdkLogger = makeConsoleLogger();\n\nexport const noopLogger: SdkLogger = {\n log: () => {},\n warn: () => {},\n error: () => {},\n debug: () => {},\n child: () => noopLogger,\n};\n\nexport interface MessageContentType {\n type: \"text\" | \"image_url\" | \"file\";\n text?: string;\n image_url?: {\n url: string;\n storageId?: string;\n };\n file?: {\n url: string;\n name?: string;\n mimeType?: string;\n size?: number;\n };\n hidden?: boolean;\n thinking?: string;\n citations?: string[];\n}\n\nexport interface Message {\n role: string;\n content: string | MessageContentType[];\n _eventId?: string;\n _prevId?: string;\n _createdAt?: number;\n _modelId?: string;\n satsSpent?: number;\n}\n\nexport interface TransactionHistory {\n type: \"spent\" | \"mint\" | \"send\" | \"import\" | \"refund\";\n amount: number;\n timestamp: number;\n status: \"success\" | \"failed\";\n model?: string;\n message?: string;\n balance?: number;\n}\n\nexport interface ModelPricing {\n prompt: number;\n completion: number;\n request: number;\n image: number;\n web_search: number;\n internal_reasoning: number;\n}\n\nexport interface ModelSatsPricing extends ModelPricing {\n max_completion_cost: number;\n max_prompt_cost: number;\n max_cost: number;\n}\n\nexport interface ModelArchitecture {\n modality: string;\n input_modalities: readonly string[];\n output_modalities: readonly string[];\n tokenizer: string;\n instruct_type: string | null;\n}\n\nexport interface PerRequestLimits {\n readonly prompt_tokens?: number;\n readonly completion_tokens?: number;\n readonly requests_per_minute?: number;\n readonly images_per_minute?: number;\n readonly web_searches_per_minute?: number;\n readonly [key: string]: number | undefined;\n}\n\nexport interface Model {\n id: string;\n name: string;\n created?: number;\n description?: string;\n context_length?: number;\n architecture?: ModelArchitecture;\n pricing?: ModelPricing;\n sats_pricing: ModelSatsPricing;\n per_request_limits?: PerRequestLimits;\n}\n\n/**\n * Result from spending cashu tokens\n */\nexport interface SpendResult {\n token: string | null;\n status: \"success\" | \"failed\";\n balance: number;\n unit?: \"sat\" | \"msat\";\n error?: string;\n errorDetails?: {\n required: number;\n available: number;\n maxMintBalance: number;\n maxMintUrl: string;\n };\n}\n\n/**\n * Result from refund operations\n */\nexport interface RefundResult {\n success: boolean;\n refundedAmount?: number;\n message?: string;\n requestId?: string;\n}\n\n/**\n * Result from top up operations\n */\nexport interface TopUpResult {\n success: boolean;\n toppedUpAmount?: number;\n message?: string;\n requestId?: string;\n recoveredToken?: boolean;\n}\n\n/**\n * API error verdict for retry logic\n */\nexport interface APIErrorVerdict {\n retry: boolean;\n reason: string;\n newBaseUrl?: string; // New provider to retry with (for 50X errors)\n}\n\n/**\n * Image data from API response\n */\nexport interface ImageData {\n type: \"image_url\";\n image_url: {\n url: string;\n };\n index?: number;\n}\n\n/**\n * Annotation data from API response\n */\nexport interface AnnotationData {\n type: \"url_citation\";\n start_index: number;\n end_index: number;\n url: string;\n title: string;\n}\n\n/**\n * Usage statistics from API response\n */\nexport interface UsageStats {\n total_tokens?: number;\n prompt_tokens?: number;\n completion_tokens?: number;\n cost?: number;\n sats_cost?: number;\n}\n\n/**\n * Result from streaming response processing\n */\nexport interface StreamingResult {\n content: string;\n thinking?: string;\n images?: ImageData[];\n usage?: UsageStats;\n model?: string;\n responseId?: string;\n finish_reason?: string;\n citations?: string[];\n annotations?: AnnotationData[];\n}\n\n/**\n * Parameters for fetching AI response\n */\nexport interface FetchAIResponseParams {\n messageHistory: Message[];\n selectedModel: Model;\n baseUrl: string;\n mintUrl: string;\n balance: number;\n transactionHistory: TransactionHistory[];\n}\n\n/**\n * Candidate provider for failover\n */\nexport interface CandidateProvider {\n baseUrl: string;\n model: Model;\n cost: number;\n}\n\n/**\n * Mint selection result\n */\nexport interface MintSelection {\n selectedMintUrl: string | null;\n selectedMintBalance: number;\n}\n\n/**\n * Pending token entry\n */\nexport interface PendingTokenEntry {\n baseUrl: string;\n amount: number;\n}\n\n/**\n * Provider information from /v1/info endpoint\n */\nexport interface ProviderInfo {\n mints?: string[];\n [key: string]: any;\n}\n\n/**\n * Model discovery result\n */\nexport interface ModelDiscoveryResult {\n models: Model[];\n bestById: Map<string, { model: Model; base: string }>;\n totalProcessed: number;\n}\n\n/**\n * Mint discovery result\n */\nexport interface MintDiscoveryResult {\n mintsFromProviders: Record<string, string[]>;\n infoFromProviders: Record<string, ProviderInfo>;\n}\n","/**\n * Custom error classes for the Routstr SDK\n * Provides specific error types for different failure modes\n */\n\n/**\n * Error thrown when balance is insufficient for an operation\n */\nexport class InsufficientBalanceError extends Error {\n constructor(\n public required: number,\n public available: number,\n public maxMintBalance: number = 0,\n public maxMintUrl: string = \"\",\n customMessage?: string\n ) {\n super(\n customMessage ??\n (`Insufficient balance: need ${required} sats, have ${available} sats available. ` +\n (maxMintBalance > 0\n ? `Largest mint balance: ${maxMintBalance} sats from ${maxMintUrl}`\n : \"\"))\n );\n this.name = \"InsufficientBalanceError\";\n }\n}\n\n/**\n * Error thrown when a provider returns an error response\n */\nexport class ProviderError extends Error {\n constructor(\n public baseUrl: string,\n public statusCode: number,\n message: string,\n public requestId?: string\n ) {\n super(\n `Provider ${baseUrl} returned ${statusCode}: ${message}` +\n (requestId ? ` (Request ID: ${requestId})` : \"\")\n );\n this.name = \"ProviderError\";\n }\n}\n\n/**\n * Error thrown when a mint is unreachable\n */\nexport class MintUnreachableError extends Error {\n constructor(public mintUrl: string) {\n super(\n `Your mint ${mintUrl} is unreachable or is blocking your IP. Please try again later or switch mints.`\n );\n this.name = \"MintUnreachableError\";\n }\n}\n\n/**\n * Error thrown when a token operation fails\n */\nexport class TokenOperationError extends Error {\n constructor(\n message: string,\n public operation: \"send\" | \"receive\" | \"refund\",\n public mintUrl?: string\n ) {\n super(message);\n this.name = \"TokenOperationError\";\n }\n}\n\n/**\n * Error thrown when provider failover fails\n */\nexport class FailoverError extends Error {\n constructor(\n public originalProvider: string,\n public failedProviders: string[],\n message?: string\n ) {\n super(\n message ||\n `All providers failed. Original: ${originalProvider}, Failed: ${failedProviders.join(\", \")}`\n );\n this.name = \"FailoverError\";\n }\n}\n\n/**\n * Error thrown when streaming response processing fails\n */\nexport class StreamingError extends Error {\n constructor(\n message: string,\n public finishReason?: string,\n public accumulatedContent?: string\n ) {\n super(message);\n this.name = \"StreamingError\";\n }\n}\n\n/**\n * Error thrown when model is not found on a provider\n */\nexport class ModelNotFoundError extends Error {\n constructor(public modelId: string, public baseUrl: string) {\n super(`Model '${modelId}' not found on provider ${baseUrl}`);\n this.name = \"ModelNotFoundError\";\n }\n}\n\n/**\n * Error thrown when provider bootstrap fails\n */\nexport class ProviderBootstrapError extends Error {\n constructor(\n public failedProviders: string[],\n message?: string\n ) {\n super(\n message || `Failed to bootstrap providers. Tried: ${failedProviders.join(\", \")}`\n );\n this.name = \"ProviderBootstrapError\";\n }\n}\n\n/**\n * Error thrown when no providers are available\n */\nexport class NoProvidersAvailableError extends Error {\n constructor() {\n super(\"No providers are available for model discovery\");\n this.name = \"NoProvidersAvailableError\";\n }\n}\n\n/**\n * Error thrown when mint discovery fails\n */\nexport class MintDiscoveryError extends Error {\n constructor(\n public baseUrl: string,\n message?: string\n ) {\n super(message || `Failed to discover mints from provider ${baseUrl}`);\n this.name = \"MintDiscoveryError\";\n }\n}\n","/**\n * ModelManager class for discovering, fetching, and managing models from providers\n * Core responsibility: fetching models from providers, caching them, and selecting the best option\n * (lowest cost) across multiple providers\n */\n\nimport type { Model, SdkLogger } from \"../core/types\";\nimport { consoleLogger } from \"../core/types\";\nimport type { DiscoveryAdapter, ProviderInfo } from \"./interfaces\";\nimport {\n NoProvidersAvailableError,\n ProviderBootstrapError,\n} from \"../core/errors\";\nimport { onlyEvents, RelayPool } from \"applesauce-relay\";\nimport { EventStore } from \"applesauce-core\";\nimport { tap } from \"rxjs\";\n\n/**\n * Configuration for ModelManager\n */\nexport interface ModelManagerConfig {\n /** URL to fetch provider directory from */\n providerDirectoryUrl?: string;\n /** Additional provider base URLs to include */\n includeProviderUrls?: string[];\n /** Provider base URLs to exclude */\n excludeProviderUrls?: string[];\n /** Cache TTL in milliseconds (default: 21 minutes) */\n cacheTTL?: number;\n /** Optional injectable logger */\n logger?: SdkLogger;\n}\n\n/**\n * ModelManager handles all model discovery and caching logic\n * Abstracts away storage details via DiscoveryAdapter\n */\nexport class ModelManager {\n private readonly cacheTTL: number;\n private readonly providerDirectoryUrl: string;\n private readonly includeProviderUrls: string[];\n private readonly excludeProviderUrls: string[];\n private readonly logger: SdkLogger;\n\n constructor(\n private adapter: DiscoveryAdapter,\n config: ModelManagerConfig = {}\n ) {\n this.providerDirectoryUrl =\n config.providerDirectoryUrl || \"https://api.routstr.com/v1/providers/\";\n this.cacheTTL = config.cacheTTL || 210 * 60 * 1000; // 21 minutes\n this.includeProviderUrls = config.includeProviderUrls || [];\n this.excludeProviderUrls = config.excludeProviderUrls || [];\n this.logger = (config.logger ?? consoleLogger).child(\"ModelManager\");\n }\n\n /**\n * Get the list of bootstrapped provider base URLs\n * @returns Array of provider base URLs\n */\n getBaseUrls(): string[] {\n return this.adapter.getBaseUrlsList();\n }\n\n static async init(\n adapter: DiscoveryAdapter,\n config: ModelManagerConfig = {},\n options: { torMode?: boolean; forceRefresh?: boolean } = {}\n ): Promise<ModelManager> {\n const manager = new ModelManager(adapter, config);\n const torMode = options.torMode ?? false;\n const forceRefresh = options.forceRefresh ?? false;\n const providers = await manager.bootstrapProviders(torMode, forceRefresh);\n await manager.fetchModels(providers, forceRefresh);\n return manager;\n }\n\n /**\n * Bootstrap provider list from the provider directory\n * First tries to fetch from Nostr (kind 30421), falls back to HTTP\n * @param torMode Whether running in Tor context\n * @param forceRefresh Ignore provider cache and refresh provider sources\n * @returns Array of provider base URLs\n * @throws ProviderBootstrapError if all providers fail to fetch\n */\n async bootstrapProviders(\n torMode: boolean = false,\n forceRefresh: boolean = false\n ): Promise<string[]> {\n // First try cache\n if (!forceRefresh) {\n const cachedUrls = this.adapter.getBaseUrlsList();\n if (cachedUrls.length > 0) {\n const lastUpdate = this.adapter.getBaseUrlsLastUpdate();\n const cacheValid =\n lastUpdate && Date.now() - lastUpdate <= this.cacheTTL;\n if (cacheValid) {\n await this.fetchRoutstr21Models(forceRefresh);\n return this.filterBaseUrlsForTor(cachedUrls, torMode);\n }\n }\n }\n\n // Try Nostr first (kind 38421)\n try {\n const nostrProviders = await this.bootstrapFromNostr(38421, torMode);\n if (nostrProviders.length > 0) {\n const filtered = this.filterBaseUrlsForTor(nostrProviders, torMode);\n this.adapter.setBaseUrlsList(filtered);\n this.adapter.setBaseUrlsLastUpdate(Date.now());\n await this.fetchRoutstr21Models(forceRefresh);\n return filtered;\n }\n } catch (e) {\n this.logger.warn(\"Nostr bootstrap failed, falling back to HTTP:\", e);\n }\n\n // Fall back to HTTP\n return this.bootstrapFromHttp(torMode, forceRefresh);\n }\n\n /**\n * Bootstrap providers from Nostr network (kind 30421)\n * @param kind The Nostr kind to fetch\n * @param torMode Whether running in Tor context\n * @returns Array of provider base URLs\n */\n private async bootstrapFromNostr(\n kind: number,\n torMode: boolean\n ): Promise<string[]> {\n const DEFAULT_RELAYS = [\n \"wss://relay.primal.net\",\n \"wss://nos.lol\",\n \"wss://relay.damus.io\",\n ];\n\n const pool = new RelayPool();\n const localEventStore = new EventStore();\n\n const timeoutMs = 5000;\n\n await new Promise<void>((resolve) => {\n pool\n .req(DEFAULT_RELAYS, {\n kinds: [kind],\n limit: 100,\n })\n .pipe(\n onlyEvents(),\n tap((event) => {\n localEventStore.add(event);\n })\n )\n .subscribe({\n complete: () => {\n resolve();\n },\n });\n\n setTimeout(() => {\n resolve();\n }, timeoutMs);\n });\n\n const timeline = localEventStore.getTimeline({ kinds: [kind] });\n\n const bases = new Set<string>();\n\n for (const event of timeline) {\n const eventUrls: string[] = [];\n\n for (const tag of event.tags) {\n if (tag[0] === \"u\" && typeof tag[1] === \"string\") {\n eventUrls.push(tag[1]);\n }\n }\n\n if (eventUrls.length > 0) {\n for (const url of eventUrls) {\n const normalized = this.normalizeUrl(url);\n if (!torMode || normalized.includes(\".onion\")) {\n bases.add(normalized);\n }\n }\n continue;\n }\n\n try {\n const content = JSON.parse(event.content);\n const providers = Array.isArray(content)\n ? content\n : content.providers || [];\n\n for (const p of providers) {\n const endpoints = this.getProviderEndpoints(p, torMode);\n for (const endpoint of endpoints) {\n bases.add(endpoint);\n }\n }\n } catch {\n try {\n const providers = JSON.parse(event.content);\n if (Array.isArray(providers)) {\n for (const p of providers) {\n const endpoints = this.getProviderEndpoints(p, torMode);\n for (const endpoint of endpoints) {\n bases.add(endpoint);\n }\n }\n }\n } catch {\n this.logger.warn(\"NostrBootstrap: failed to parse event content:\", event.id);\n }\n }\n }\n\n // Add additional configured providers\n for (const url of this.includeProviderUrls) {\n const normalized = this.normalizeUrl(url);\n if (!torMode || normalized.includes(\".onion\")) {\n bases.add(normalized);\n }\n }\n\n const excluded = new Set(\n this.excludeProviderUrls.map((url) => this.normalizeUrl(url))\n );\n\n const result = Array.from(bases).filter((base) => !excluded.has(base));\n\n return result;\n }\n\n /**\n * Bootstrap providers from HTTP endpoint\n * @param torMode Whether running in Tor context\n * @param forceRefresh Ignore routstr21 cache and fetch fresh data\n * @returns Array of provider base URLs\n */\n private async bootstrapFromHttp(\n torMode: boolean,\n forceRefresh: boolean = false\n ): Promise<string[]> {\n try {\n const res = await fetch(this.providerDirectoryUrl);\n if (!res.ok) {\n throw new Error(`Failed to fetch providers: ${res.status}`);\n }\n\n const data = await res.json();\n const providers = Array.isArray(data?.providers) ? data.providers : [];\n\n const bases = new Set<string>();\n for (const p of providers) {\n const endpoints = this.getProviderEndpoints(p, torMode);\n for (const endpoint of endpoints) {\n bases.add(endpoint);\n }\n }\n\n for (const url of this.includeProviderUrls) {\n const normalized = this.normalizeUrl(url);\n if (!torMode || normalized.includes(\".onion\")) {\n bases.add(normalized);\n }\n }\n\n const excluded = new Set(\n this.excludeProviderUrls.map((url) => this.normalizeUrl(url))\n );\n\n const list = Array.from(bases).filter((base) => !excluded.has(base));\n\n if (list.length > 0) {\n this.adapter.setBaseUrlsList(list);\n this.adapter.setBaseUrlsLastUpdate(Date.now());\n await this.fetchRoutstr21Models(forceRefresh);\n }\n\n return list;\n } catch (e) {\n this.logger.error(\"Failed to bootstrap providers\", e);\n throw new ProviderBootstrapError([], `Provider bootstrap failed: ${e}`);\n }\n }\n\n /**\n * Fetch models from all providers and select best-priced options\n * Uses cache if available and not expired\n * @param baseUrls List of provider base URLs to fetch from\n * @param forceRefresh Ignore cache and fetch fresh data\n * @param onProgress Callback fired after each provider completes with current combined models\n * @returns Array of unique models with best prices selected\n */\n async fetchModels(\n baseUrls: string[],\n forceRefresh: boolean = false,\n onProgress?: (models: Model[]) => void\n ): Promise<Model[]> {\n if (baseUrls.length === 0) {\n throw new NoProvidersAvailableError();\n }\n\n const bestById = new Map<string, { model: Model; base: string }>();\n const modelsFromAllProviders: Record<string, Model[]> = {};\n const disabledProviders = this.adapter.getDisabledProviders();\n\n // Helper to estimate minimum cost for a model\n const estimateMinCost = (m: Model): number => {\n return m?.sats_pricing?.completion ?? 0;\n };\n\n // Helper to emit current progress\n const emitProgress = () => {\n if (onProgress) {\n const currentModels = Array.from(bestById.values()).map((v) => v.model);\n onProgress(currentModels);\n }\n };\n\n // Fetch from all providers in parallel with progressive updates\n const fetchPromises = baseUrls.map(async (url) => {\n const base = url.endsWith(\"/\") ? url : `${url}/`;\n try {\n // Check cache if not forcing refresh\n let list: Model[];\n\n if (!forceRefresh) {\n const lastUpdate = this.adapter.getProviderLastUpdate(base);\n const cacheValid =\n lastUpdate && Date.now() - lastUpdate <= this.cacheTTL;\n\n if (cacheValid) {\n const cachedModels = this.adapter.getCachedModels();\n const cachedList = cachedModels[base] || [];\n list = cachedList;\n } else {\n // Cache expired or doesn't exist, fetch fresh\n list = await this.fetchModelsFromProvider(base);\n }\n } else {\n // Force refresh\n list = await this.fetchModelsFromProvider(base);\n }\n\n modelsFromAllProviders[base] = list;\n this.adapter.setProviderLastUpdate(base, Date.now());\n\n // Update best-priced models if provider not disabled\n if (!disabledProviders.includes(base)) {\n for (const m of list) {\n const existing = bestById.get(m.id);\n\n // Skip models without sats pricing\n if (!m.sats_pricing) continue;\n\n if (!existing) {\n bestById.set(m.id, { model: m, base });\n continue;\n }\n\n // Replace if this provider has lower cost\n const currentCost = estimateMinCost(m);\n const existingCost = estimateMinCost(existing.model);\n if (currentCost < existingCost && m.sats_pricing) {\n bestById.set(m.id, { model: m, base });\n }\n }\n }\n\n emitProgress();\n\n return { success: true, base, list };\n } catch (error) {\n if (this.isProviderDownError(error)) {\n this.logger.warn(`Provider ${base} is down right now.`);\n } else {\n this.logger.warn(`Failed to fetch models from ${base}:`, error);\n }\n this.adapter.setProviderLastUpdate(base, Date.now());\n return { success: false, base };\n }\n });\n\n await Promise.allSettled(fetchPromises);\n\n // Cache all provider results\n const existingCache = this.adapter.getCachedModels();\n this.adapter.setCachedModels({\n ...existingCache,\n ...modelsFromAllProviders,\n });\n\n // Return combined models array\n return Array.from(bestById.values()).map((v) => v.model);\n }\n\n /**\n * Fetch models from a single provider\n * @param baseUrl Provider base URL\n * @returns Array of models from provider\n */\n private async fetchModelsFromProvider(baseUrl: string): Promise<Model[]> {\n const res = await fetch(`${baseUrl}v1/models`);\n if (!res.ok) {\n throw new Error(`Failed to fetch models: ${res.status}`);\n }\n\n const json = await res.json();\n const list = Array.isArray(json?.data) ? json.data : [];\n\n return list;\n }\n\n private isProviderDownError(error: unknown): boolean {\n if (!(error instanceof Error)) return false;\n const msg = error.message.toLowerCase();\n if (msg.includes(\"fetch failed\")) return true;\n if (msg.includes(\"429\")) return true;\n if (msg.includes(\"502\")) return true;\n if (msg.includes(\"503\")) return true;\n if (msg.includes(\"504\")) return true;\n const cause = error.cause as { code?: string } | undefined;\n return cause?.code === \"ENOTFOUND\";\n }\n\n /**\n * Get all cached models from all providers\n * @returns Record mapping baseUrl -> models\n */\n getAllCachedModels(): Record<string, Model[]> {\n return this.adapter.getCachedModels();\n }\n\n /**\n * Clear cache for a specific provider\n * @param baseUrl Provider base URL\n */\n clearProviderCache(baseUrl: string): void {\n const base = baseUrl.endsWith(\"/\") ? baseUrl : `${baseUrl}/`;\n const cached = this.adapter.getCachedModels();\n delete cached[base];\n this.adapter.setCachedModels(cached);\n this.adapter.setProviderLastUpdate(base, 0);\n }\n\n /**\n * Clear all model caches\n */\n clearAllCache(): void {\n this.adapter.setCachedModels({});\n }\n\n /**\n * Filter base URLs based on Tor context\n * @param baseUrls Provider URLs to filter\n * @param torMode Whether in Tor context\n * @returns Filtered URLs appropriate for Tor mode\n */\n filterBaseUrlsForTor(baseUrls: string[], torMode: boolean): string[] {\n if (!torMode) {\n // In normal mode, exclude onion URLs\n return baseUrls.filter((url) => !url.includes(\".onion\"));\n }\n // In Tor mode, only include onion URLs\n return baseUrls.filter((url) => url.includes(\".onion\"));\n }\n\n /**\n * Get provider endpoints from provider info\n * @param provider Provider object from directory\n * @param torMode Whether in Tor context\n * @returns Array of endpoint URLs\n */\n private getProviderEndpoints(provider: any, torMode: boolean): string[] {\n const endpoints: string[] = [];\n\n if (torMode && provider.onion_url) {\n endpoints.push(this.normalizeUrl(provider.onion_url));\n } else if (provider.endpoint_url) {\n endpoints.push(this.normalizeUrl(provider.endpoint_url));\n }\n\n return endpoints;\n }\n\n /**\n * Normalize provider URL with trailing slash\n * @param url URL to normalize\n * @returns Normalized URL\n */\n private normalizeUrl(url: string): string {\n if (!url.startsWith(\"http\")) {\n url = `https://${url}`;\n }\n return url.endsWith(\"/\") ? url : `${url}/`;\n }\n\n /**\n * Fetch routstr21 models from Nostr network (kind 38423)\n * Uses cache if available and not expired\n * @returns Array of model IDs or empty array if not found\n */\n async fetchRoutstr21Models(forceRefresh: boolean = false): Promise<string[]> {\n // Check cache first\n const cachedModels = this.adapter.getRoutstr21Models();\n if (!forceRefresh && cachedModels.length > 0) {\n const lastUpdate = this.adapter.getRoutstr21ModelsLastUpdate();\n const cacheValid = lastUpdate && Date.now() - lastUpdate <= this.cacheTTL;\n if (cacheValid) {\n return cachedModels;\n }\n }\n\n const DEFAULT_RELAYS = [\n \"wss://relay.damus.io\",\n \"wss://nos.lol\",\n \"wss://relay.routstr.com\",\n ];\n\n const pool = new RelayPool();\n const localEventStore = new EventStore();\n\n const timeoutMs = 5000;\n\n await new Promise<void>((resolve) => {\n pool\n .req(DEFAULT_RELAYS, {\n kinds: [38423],\n \"#d\": [\"routstr-21-models\"],\n limit: 1,\n authors: [\n \"4ad6fa2d16e2a9b576c863b4cf7404a70d4dc320c0c447d10ad6ff58993eacc8\",\n ],\n })\n .pipe(\n onlyEvents(),\n tap((event) => {\n localEventStore.add(event);\n })\n )\n .subscribe({\n complete: () => {\n resolve();\n },\n });\n\n setTimeout(() => {\n resolve();\n }, timeoutMs);\n });\n\n const timeline = localEventStore.getTimeline({ kinds: [38423] });\n\n if (timeline.length === 0) {\n return cachedModels.length > 0 ? cachedModels : [];\n }\n\n const event = timeline[0];\n\n try {\n const content = JSON.parse(event.content);\n const models = Array.isArray(content?.models) ? content.models : [];\n this.adapter.setRoutstr21Models(models);\n this.adapter.setRoutstr21ModelsLastUpdate(Date.now());\n return models;\n } catch {\n this.logger.warn(\"Routstr21Models: failed to parse Nostr event content:\", event.id);\n return cachedModels.length > 0 ? cachedModels : [];\n }\n }\n}\n","/**\n * MintDiscovery class for discovering mints and provider info\n * Core responsibility: fetching mint information from providers and caching it\n */\n\nimport type { DiscoveryAdapter, ProviderInfo } from \"./interfaces\";\nimport type { SdkLogger } from \"../core/types\";\nimport { consoleLogger } from \"../core/types\";\n\n/**\n * Configuration for MintDiscovery\n */\nexport interface MintDiscoveryConfig {\n /** Cache TTL in milliseconds (default: 21 minutes) */\n cacheTTL?: number;\n /** Optional injectable logger */\n logger?: SdkLogger;\n}\n\n/**\n * MintDiscovery handles mint and provider info discovery\n * Abstracts away storage details via DiscoveryAdapter\n */\nexport class MintDiscovery {\n private readonly cacheTTL: number;\n private readonly logger: SdkLogger;\n\n constructor(\n private adapter: DiscoveryAdapter,\n config: MintDiscoveryConfig = {}\n ) {\n this.cacheTTL = config.cacheTTL || 21 * 60 * 1000; // 21 minutes\n this.logger = (config.logger ?? consoleLogger).child(\"MintDiscovery\");\n }\n\n /**\n * Fetch mints from all providers via their /v1/info endpoints\n * Caches mints and full provider info for later access\n * @param baseUrls List of provider base URLs to fetch from\n * @returns Object with mints and provider info from all providers\n */\n async discoverMints(\n baseUrls: string[],\n options: { forceRefresh?: boolean } = {}\n ): Promise<{\n mintsFromProviders: Record<string, string[]>;\n infoFromProviders: Record<string, ProviderInfo>;\n }> {\n if (baseUrls.length === 0) {\n return { mintsFromProviders: {}, infoFromProviders: {} };\n }\n\n const mintsFromAllProviders: Record<string, string[]> = {};\n const infoFromAllProviders: Record<string, ProviderInfo> = {};\n const forceRefresh = options.forceRefresh ?? false;\n\n // Fetch info from each provider\n const fetchPromises = baseUrls.map(async (url) => {\n const base = url.endsWith(\"/\") ? url : `${url}/`;\n try {\n if (!forceRefresh) {\n const lastUpdate = this.adapter.getProviderLastUpdate(base);\n const cacheValid =\n lastUpdate && Date.now() - lastUpdate <= this.cacheTTL;\n if (cacheValid) {\n const cachedMints = this.adapter.getCachedMints()[base] || [];\n const cachedInfo = this.adapter.getCachedProviderInfo()[base];\n mintsFromAllProviders[base] = cachedMints;\n if (cachedInfo) {\n infoFromAllProviders[base] = cachedInfo;\n }\n return {\n success: true,\n base,\n mints: cachedMints,\n info: cachedInfo,\n };\n }\n }\n\n const res = await fetch(`${base}v1/info`);\n if (!res.ok) {\n throw new Error(`Failed to fetch info: ${res.status}`);\n }\n\n const json = await res.json();\n\n // Extract mints array from response\n const mints: string[] = Array.isArray(json?.mints) ? json.mints : [];\n\n // Normalize mint URLs (remove trailing slashes for consistency)\n const normalizedMints = mints.map((mint) =>\n mint.endsWith(\"/\") ? mint.slice(0, -1) : mint\n );\n\n // Save provider mints and full info\n mintsFromAllProviders[base] = normalizedMints;\n infoFromAllProviders[base] = json;\n this.adapter.setProviderLastUpdate(base, Date.now());\n\n return { success: true, base, mints: normalizedMints, info: json };\n } catch (error) {\n this.adapter.setProviderLastUpdate(base, Date.now());\n if (this.isProviderDownError(error)) {\n this.logger.warn(`Provider ${base} is down right now.`);\n } else {\n this.logger.warn(`Failed to fetch mints from ${base}:`, error);\n }\n return { success: false, base, mints: [], info: null };\n }\n });\n\n // Wait for all to complete (but allow individual failures)\n const results = await Promise.allSettled(fetchPromises);\n\n // Handle results\n for (const result of results) {\n if (result.status === \"fulfilled\") {\n const { base, mints, info } = result.value;\n mintsFromAllProviders[base] = mints;\n if (info) {\n infoFromAllProviders[base] = info;\n }\n } else {\n this.logger.error(\"Mint discovery error:\", result.reason);\n }\n }\n\n // Cache all results\n try {\n this.adapter.setCachedMints(mintsFromAllProviders);\n this.adapter.setCachedProviderInfo(infoFromAllProviders);\n } catch (error) {\n this.logger.error(\"Error caching mint discovery results:\", error);\n }\n\n return {\n mintsFromProviders: mintsFromAllProviders,\n infoFromProviders: infoFromAllProviders,\n };\n }\n\n /**\n * Get cached mints from all providers\n * @returns Record mapping baseUrl -> mint URLs\n */\n getCachedMints(): Record<string, string[]> {\n return this.adapter.getCachedMints();\n }\n\n /**\n * Get cached provider info from all providers\n * @returns Record mapping baseUrl -> provider info\n */\n getCachedProviderInfo(): Record<string, ProviderInfo> {\n return this.adapter.getCachedProviderInfo();\n }\n\n /**\n * Get mints for a specific provider\n * @param baseUrl Provider base URL\n * @returns Array of mint URLs for the provider\n */\n getProviderMints(baseUrl: string): string[] {\n const normalized = baseUrl.endsWith(\"/\") ? baseUrl : `${baseUrl}/`;\n const allMints = this.getCachedMints();\n return allMints[normalized] || [];\n }\n\n /**\n * Get info for a specific provider\n * @param baseUrl Provider base URL\n * @returns Provider info object or null if not found\n */\n getProviderInfo(baseUrl: string): ProviderInfo | null {\n const normalized = baseUrl.endsWith(\"/\") ? baseUrl : `${baseUrl}/`;\n const allInfo = this.getCachedProviderInfo();\n return allInfo[normalized] || null;\n }\n\n /**\n * Clear mint cache for a specific provider\n * @param baseUrl Provider base URL\n */\n clearProviderMintCache(baseUrl: string): void {\n const normalized = baseUrl.endsWith(\"/\") ? baseUrl : `${baseUrl}/`;\n\n const mints = this.getCachedMints();\n delete mints[normalized];\n this.adapter.setCachedMints(mints);\n\n const info = this.getCachedProviderInfo();\n delete info[normalized];\n this.adapter.setCachedProviderInfo(info);\n }\n\n /**\n * Clear all mint caches\n */\n clearAllCache(): void {\n this.adapter.setCachedMints({});\n this.adapter.setCachedProviderInfo({});\n }\n\n private isProviderDownError(error: unknown): boolean {\n if (!(error instanceof Error)) return false;\n const msg = error.message.toLowerCase();\n if (msg.includes(\"fetch failed\")) return true;\n if (msg.includes(\"429\")) return true;\n if (msg.includes(\"502\")) return true;\n if (msg.includes(\"503\")) return true;\n if (msg.includes(\"504\")) return true;\n const cause = error.cause as { code?: string } | undefined;\n if (cause?.code === \"ENOTFOUND\") return true;\n return false;\n }\n}\n"]}
1
+ {"version":3,"sources":["../../core/types.ts","../../core/errors.ts","../../discovery/ModelManager.ts","../../discovery/MintDiscovery.ts"],"names":["event"],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * Core types for the Routstr SDK\n * These types are shared across wallet and client modules\n */\n\nexport interface SdkLogger {\n log(...args: unknown[]): void;\n warn(...args: unknown[]): void;\n error(...args: unknown[]): void;\n debug(...args: unknown[]): void;\n child(prefix: string): SdkLogger;\n}\n\nfunction makeConsoleLogger(prefix?: string): SdkLogger {\n const fmt = (args: unknown[]) => (prefix ? [prefix, ...args] : args);\n return {\n log: (...args) => console.log(...fmt(args)),\n warn: (...args) => console.warn(...fmt(args)),\n error: (...args) => console.error(...fmt(args)),\n debug: (...args) => console.log(...fmt(args)),\n child: (p) => makeConsoleLogger(prefix ? `${prefix}:${p}` : p),\n };\n}\n\nexport const consoleLogger: SdkLogger = makeConsoleLogger();\n\nexport const noopLogger: SdkLogger = {\n log: () => {},\n warn: () => {},\n error: () => {},\n debug: () => {},\n child: () => noopLogger,\n};\n\nexport interface MessageContentType {\n type: \"text\" | \"image_url\" | \"file\";\n text?: string;\n image_url?: {\n url: string;\n storageId?: string;\n };\n file?: {\n url: string;\n name?: string;\n mimeType?: string;\n size?: number;\n };\n hidden?: boolean;\n thinking?: string;\n citations?: string[];\n}\n\nexport interface Message {\n role: string;\n content: string | MessageContentType[];\n _eventId?: string;\n _prevId?: string;\n _createdAt?: number;\n _modelId?: string;\n satsSpent?: number;\n}\n\nexport interface TransactionHistory {\n type: \"spent\" | \"mint\" | \"send\" | \"import\" | \"refund\";\n amount: number;\n timestamp: number;\n status: \"success\" | \"failed\";\n model?: string;\n message?: string;\n balance?: number;\n}\n\nexport interface ModelPricing {\n prompt: number;\n completion: number;\n request: number;\n image: number;\n web_search: number;\n internal_reasoning: number;\n}\n\nexport interface ModelSatsPricing extends ModelPricing {\n max_completion_cost: number;\n max_prompt_cost: number;\n max_cost: number;\n}\n\nexport interface ModelArchitecture {\n modality: string;\n input_modalities: readonly string[];\n output_modalities: readonly string[];\n tokenizer: string;\n instruct_type: string | null;\n}\n\nexport interface PerRequestLimits {\n readonly prompt_tokens?: number;\n readonly completion_tokens?: number;\n readonly requests_per_minute?: number;\n readonly images_per_minute?: number;\n readonly web_searches_per_minute?: number;\n readonly [key: string]: number | undefined;\n}\n\nexport interface Model {\n id: string;\n name: string;\n created?: number;\n description?: string;\n context_length?: number;\n architecture?: ModelArchitecture;\n pricing?: ModelPricing;\n sats_pricing: ModelSatsPricing;\n per_request_limits?: PerRequestLimits;\n}\n\n/**\n * Result from spending cashu tokens\n */\nexport interface SpendResult {\n token: string | null;\n status: \"success\" | \"failed\";\n balance: number;\n unit?: \"sat\" | \"msat\";\n error?: string;\n errorDetails?: {\n required: number;\n available: number;\n maxMintBalance: number;\n maxMintUrl: string;\n };\n}\n\n/**\n * Result from refund operations\n */\nexport interface RefundResult {\n success: boolean;\n refundedAmount?: number;\n message?: string;\n requestId?: string;\n}\n\n/**\n * Result from top up operations\n */\nexport interface TopUpResult {\n success: boolean;\n toppedUpAmount?: number;\n message?: string;\n requestId?: string;\n recoveredToken?: boolean;\n}\n\n/**\n * API error verdict for retry logic\n */\nexport interface APIErrorVerdict {\n retry: boolean;\n reason: string;\n newBaseUrl?: string; // New provider to retry with (for 50X errors)\n}\n\n/**\n * Image data from API response\n */\nexport interface ImageData {\n type: \"image_url\";\n image_url: {\n url: string;\n };\n index?: number;\n}\n\n/**\n * Annotation data from API response\n */\nexport interface AnnotationData {\n type: \"url_citation\";\n start_index: number;\n end_index: number;\n url: string;\n title: string;\n}\n\n/**\n * Usage statistics from API response\n */\nexport interface UsageStats {\n total_tokens?: number;\n prompt_tokens?: number;\n completion_tokens?: number;\n cost?: number;\n sats_cost?: number;\n}\n\n/**\n * Result from streaming response processing\n */\nexport interface StreamingResult {\n content: string;\n thinking?: string;\n images?: ImageData[];\n usage?: UsageStats;\n model?: string;\n responseId?: string;\n finish_reason?: string;\n citations?: string[];\n annotations?: AnnotationData[];\n}\n\n/**\n * Parameters for fetching AI response\n */\nexport interface FetchAIResponseParams {\n messageHistory: Message[];\n selectedModel: Model;\n baseUrl: string;\n mintUrl: string;\n balance: number;\n transactionHistory: TransactionHistory[];\n}\n\n/**\n * Candidate provider for failover\n */\nexport interface CandidateProvider {\n baseUrl: string;\n model: Model;\n cost: number;\n}\n\n/**\n * Mint selection result\n */\nexport interface MintSelection {\n selectedMintUrl: string | null;\n selectedMintBalance: number;\n}\n\n/**\n * Pending token entry\n */\nexport interface PendingTokenEntry {\n baseUrl: string;\n amount: number;\n}\n\n/**\n * Provider information from /v1/info endpoint\n */\nexport interface ProviderInfo {\n mints?: string[];\n [key: string]: any;\n}\n\n/**\n * Model discovery result\n */\nexport interface ModelDiscoveryResult {\n models: Model[];\n bestById: Map<string, { model: Model; base: string }>;\n totalProcessed: number;\n}\n\n/**\n * Mint discovery result\n */\nexport interface MintDiscoveryResult {\n mintsFromProviders: Record<string, string[]>;\n infoFromProviders: Record<string, ProviderInfo>;\n}\n","/**\n * Custom error classes for the Routstr SDK\n * Provides specific error types for different failure modes\n */\n\n/**\n * Error thrown when balance is insufficient for an operation\n */\nexport class InsufficientBalanceError extends Error {\n constructor(\n public required: number,\n public available: number,\n public maxMintBalance: number = 0,\n public maxMintUrl: string = \"\",\n customMessage?: string\n ) {\n super(\n customMessage ??\n (`Insufficient balance: need ${required} sats, have ${available} sats available. ` +\n (maxMintBalance > 0\n ? `Largest mint balance: ${maxMintBalance} sats from ${maxMintUrl}`\n : \"\"))\n );\n this.name = \"InsufficientBalanceError\";\n }\n}\n\n/**\n * Error thrown when a provider returns an error response\n */\nexport class ProviderError extends Error {\n constructor(\n public baseUrl: string,\n public statusCode: number,\n message: string,\n public requestId?: string\n ) {\n super(\n `Provider ${baseUrl} returned ${statusCode}: ${message}` +\n (requestId ? ` (Request ID: ${requestId})` : \"\")\n );\n this.name = \"ProviderError\";\n }\n}\n\n/**\n * Error thrown when a mint is unreachable\n */\nexport class MintUnreachableError extends Error {\n constructor(public mintUrl: string) {\n super(\n `Your mint ${mintUrl} is unreachable or is blocking your IP. Please try again later or switch mints.`\n );\n this.name = \"MintUnreachableError\";\n }\n}\n\n/**\n * Error thrown when a token operation fails\n */\nexport class TokenOperationError extends Error {\n constructor(\n message: string,\n public operation: \"send\" | \"receive\" | \"refund\",\n public mintUrl?: string\n ) {\n super(message);\n this.name = \"TokenOperationError\";\n }\n}\n\n/**\n * Error thrown when provider failover fails\n */\nexport class FailoverError extends Error {\n constructor(\n public originalProvider: string,\n public failedProviders: string[],\n message?: string\n ) {\n super(\n message ||\n `All providers failed. Original: ${originalProvider}, Failed: ${failedProviders.join(\", \")}`\n );\n this.name = \"FailoverError\";\n }\n}\n\n/**\n * Error thrown when streaming response processing fails\n */\nexport class StreamingError extends Error {\n constructor(\n message: string,\n public finishReason?: string,\n public accumulatedContent?: string\n ) {\n super(message);\n this.name = \"StreamingError\";\n }\n}\n\n/**\n * Error thrown when model is not found on a provider\n */\nexport class ModelNotFoundError extends Error {\n constructor(public modelId: string, public baseUrl: string) {\n super(`Model '${modelId}' not found on provider ${baseUrl}`);\n this.name = \"ModelNotFoundError\";\n }\n}\n\n/**\n * Error thrown when provider bootstrap fails\n */\nexport class ProviderBootstrapError extends Error {\n constructor(\n public failedProviders: string[],\n message?: string\n ) {\n super(\n message || `Failed to bootstrap providers. Tried: ${failedProviders.join(\", \")}`\n );\n this.name = \"ProviderBootstrapError\";\n }\n}\n\n/**\n * Error thrown when no providers are available\n */\nexport class NoProvidersAvailableError extends Error {\n constructor() {\n super(\"No providers are available for model discovery\");\n this.name = \"NoProvidersAvailableError\";\n }\n}\n\n/**\n * Error thrown when mint discovery fails\n */\nexport class MintDiscoveryError extends Error {\n constructor(\n public baseUrl: string,\n message?: string\n ) {\n super(message || `Failed to discover mints from provider ${baseUrl}`);\n this.name = \"MintDiscoveryError\";\n }\n}\n","/**\n * ModelManager class for discovering, fetching, and managing models from providers\n * Core responsibility: fetching models from providers, caching them, and selecting the best option\n * (lowest cost) across multiple providers\n */\n\nimport type { Model, SdkLogger } from \"../core/types\";\nimport { consoleLogger } from \"../core/types\";\nimport type { DiscoveryAdapter, ProviderInfo } from \"./interfaces\";\nimport {\n NoProvidersAvailableError,\n ProviderBootstrapError,\n} from \"../core/errors\";\nimport { onlyEvents, RelayPool } from \"applesauce-relay\";\nimport { EventStore } from \"applesauce-core\";\nimport { tap } from \"rxjs\";\n\n/**\n * Configuration for ModelManager\n */\nexport interface ModelManagerConfig {\n /** URL to fetch provider directory from */\n providerDirectoryUrl?: string;\n /** Additional provider base URLs to include */\n includeProviderUrls?: string[];\n /** Provider base URLs to exclude */\n excludeProviderUrls?: string[];\n /** Cache TTL in milliseconds (default: 21 minutes) */\n cacheTTL?: number;\n /** Nostr pubkey for routstr review/model events (kind 38425/38423). Defaults to routstr's key. */\n routstrPubkey?: string;\n /** Optional injectable logger */\n logger?: SdkLogger;\n}\n\n/**\n * ModelManager handles all model discovery and caching logic\n * Abstracts away storage details via DiscoveryAdapter\n */\nexport class ModelManager {\n private readonly cacheTTL: number;\n private readonly providerDirectoryUrl: string;\n private readonly includeProviderUrls: string[];\n private readonly excludeProviderUrls: string[];\n private readonly routstrPubkey: string;\n private readonly logger: SdkLogger;\n private providerNodePubkeysByUrl = new Map<string, Set<string>>();\n\n constructor(\n private adapter: DiscoveryAdapter,\n config: ModelManagerConfig = {}\n ) {\n this.providerDirectoryUrl =\n config.providerDirectoryUrl || \"https://api.routstr.com/v1/providers/\";\n this.cacheTTL = config.cacheTTL || 210 * 60 * 1000; // 21 minutes\n this.includeProviderUrls = config.includeProviderUrls || [];\n this.excludeProviderUrls = config.excludeProviderUrls || [];\n this.routstrPubkey =\n config.routstrPubkey ||\n \"4ad6fa2d16e2a9b576c863b4cf7404a70d4dc320c0c447d10ad6ff58993eacc8\";\n this.logger = (config.logger ?? consoleLogger).child(\"ModelManager\");\n }\n\n /**\n * Get the list of bootstrapped provider base URLs\n * @returns Array of provider base URLs\n */\n getBaseUrls(): string[] {\n return this.adapter.getBaseUrlsList();\n }\n\n static async init(\n adapter: DiscoveryAdapter,\n config: ModelManagerConfig = {},\n options: { torMode?: boolean; forceRefresh?: boolean } = {}\n ): Promise<ModelManager> {\n const manager = new ModelManager(adapter, config);\n const torMode = options.torMode ?? false;\n const forceRefresh = options.forceRefresh ?? false;\n const providers = await manager.bootstrapProviders(torMode, forceRefresh);\n await manager.fetchModels(providers, forceRefresh);\n return manager;\n }\n\n /**\n * Bootstrap provider list from the provider directory\n * First tries to fetch from Nostr (kind 30421), falls back to HTTP\n * @param torMode Whether running in Tor context\n * @param forceRefresh Ignore provider cache and refresh provider sources\n * @returns Array of provider base URLs\n * @throws ProviderBootstrapError if all providers fail to fetch\n */\n async bootstrapProviders(\n torMode: boolean = false,\n forceRefresh: boolean = false\n ): Promise<string[]> {\n // First try cache\n if (!forceRefresh) {\n const cachedUrls = this.adapter.getBaseUrlsList();\n if (cachedUrls.length > 0) {\n const lastUpdate = this.adapter.getBaseUrlsLastUpdate();\n const cacheValid =\n lastUpdate && Date.now() - lastUpdate <= this.cacheTTL;\n if (cacheValid) {\n const filteredCachedUrls = this.filterBaseUrlsForTor(\n cachedUrls,\n torMode\n );\n await this.fetchRoutstr21Models(forceRefresh);\n await this.syncReviewedProvidersFromNostr(filteredCachedUrls);\n return filteredCachedUrls;\n }\n }\n }\n\n // Try Nostr first (kind 38421)\n try {\n const nostrProviders = await this.bootstrapFromNostr(38421, torMode);\n if (nostrProviders.length > 0) {\n const filtered = this.filterBaseUrlsForTor(nostrProviders, torMode);\n this.adapter.setBaseUrlsList(filtered);\n this.adapter.setBaseUrlsLastUpdate(Date.now());\n await this.fetchRoutstr21Models(forceRefresh);\n await this.syncReviewedProvidersFromNostr(filtered);\n return filtered;\n }\n } catch (e) {\n this.logger.warn(\"Nostr bootstrap failed, falling back to HTTP:\", e);\n }\n\n // Fall back to HTTP\n return this.bootstrapFromHttp(torMode, forceRefresh);\n }\n\n /**\n * Bootstrap providers from Nostr network (kind 30421)\n * @param kind The Nostr kind to fetch\n * @param torMode Whether running in Tor context\n * @returns Array of provider base URLs\n */\n private async bootstrapFromNostr(\n kind: number,\n torMode: boolean\n ): Promise<string[]> {\n const DEFAULT_RELAYS = [\n \"wss://relay.primal.net\",\n \"wss://nos.lol\",\n \"wss://relay.damus.io\",\n ];\n\n const pool = new RelayPool();\n const localEventStore = new EventStore();\n\n const timeoutMs = 5000;\n\n await new Promise<void>((resolve) => {\n pool\n .req(DEFAULT_RELAYS, {\n kinds: [kind],\n limit: 100,\n })\n .pipe(\n onlyEvents(),\n tap((event) => {\n localEventStore.add(event);\n })\n )\n .subscribe({\n complete: () => {\n resolve();\n },\n });\n\n setTimeout(() => {\n resolve();\n }, timeoutMs);\n });\n\n const timeline = localEventStore.getTimeline({ kinds: [kind] });\n\n const bases = new Set<string>();\n this.providerNodePubkeysByUrl = new Map();\n\n for (const event of timeline) {\n const eventUrls: string[] = [];\n\n for (const tag of event.tags) {\n if (tag[0] === \"u\" && typeof tag[1] === \"string\") {\n eventUrls.push(tag[1]);\n }\n }\n\n if (eventUrls.length > 0) {\n for (const url of eventUrls) {\n const normalized = this.normalizeUrl(url);\n if (!torMode || normalized.includes(\".onion\")) {\n bases.add(normalized);\n this.addProviderNode(\n this.providerNodePubkeysByUrl,\n normalized,\n event.pubkey\n );\n }\n }\n continue;\n }\n\n try {\n const content = JSON.parse(event.content);\n const providers = Array.isArray(content)\n ? content\n : content.providers || [];\n\n for (const p of providers) {\n const endpoints = this.getProviderEndpoints(p, torMode);\n for (const endpoint of endpoints) {\n bases.add(endpoint);\n this.addProviderNode(\n this.providerNodePubkeysByUrl,\n endpoint,\n p?.pubkey || event.pubkey\n );\n }\n }\n } catch {\n try {\n const providers = JSON.parse(event.content);\n if (Array.isArray(providers)) {\n for (const p of providers) {\n const endpoints = this.getProviderEndpoints(p, torMode);\n for (const endpoint of endpoints) {\n bases.add(endpoint);\n this.addProviderNode(\n this.providerNodePubkeysByUrl,\n endpoint,\n p?.pubkey || event.pubkey\n );\n }\n }\n }\n } catch {\n this.logger.warn(\n \"NostrBootstrap: failed to parse event content:\",\n event.id\n );\n }\n }\n }\n\n // Add additional configured providers\n for (const url of this.includeProviderUrls) {\n const normalized = this.normalizeUrl(url);\n if (!torMode || normalized.includes(\".onion\")) {\n bases.add(normalized);\n }\n }\n\n const excluded = new Set(\n this.excludeProviderUrls.map((url) => this.normalizeUrl(url))\n );\n\n const result = Array.from(bases).filter((base) => !excluded.has(base));\n\n return result;\n }\n\n /**\n * Bootstrap providers from HTTP endpoint\n * @param torMode Whether running in Tor context\n * @param forceRefresh Ignore routstr21 cache and fetch fresh data\n * @returns Array of provider base URLs\n */\n private async bootstrapFromHttp(\n torMode: boolean,\n forceRefresh: boolean = false\n ): Promise<string[]> {\n try {\n const res = await fetch(this.providerDirectoryUrl);\n if (!res.ok) {\n throw new Error(`Failed to fetch providers: ${res.status}`);\n }\n\n const data = await res.json();\n const providers = Array.isArray(data?.providers) ? data.providers : [];\n\n const bases = new Set<string>();\n this.providerNodePubkeysByUrl = new Map();\n for (const p of providers) {\n const endpoints = this.getProviderEndpoints(p, torMode);\n for (const endpoint of endpoints) {\n bases.add(endpoint);\n this.addProviderNode(this.providerNodePubkeysByUrl, endpoint, p?.pubkey);\n }\n }\n\n for (const url of this.includeProviderUrls) {\n const normalized = this.normalizeUrl(url);\n if (!torMode || normalized.includes(\".onion\")) {\n bases.add(normalized);\n }\n }\n\n const excluded = new Set(\n this.excludeProviderUrls.map((url) => this.normalizeUrl(url))\n );\n\n const list = Array.from(bases).filter((base) => !excluded.has(base));\n\n if (list.length > 0) {\n this.adapter.setBaseUrlsList(list);\n this.adapter.setBaseUrlsLastUpdate(Date.now());\n await this.fetchRoutstr21Models(forceRefresh);\n await this.syncReviewedProvidersFromNostr(list);\n }\n\n return list;\n } catch (e) {\n this.logger.error(\"Failed to bootstrap providers\", e);\n throw new ProviderBootstrapError([], `Provider bootstrap failed: ${e}`);\n }\n }\n\n /**\n * Fetch Routstr review events from Nostr (kind 38425) and disable providers\n * whose 38421 node pubkey does not have at least one review tagged `t=lgtm`.\n *\n * Review events are expected to have:\n * - `node`: the reviewed 38421 provider event pubkey\n * - `t`: review label, where `lgtm` means the node looks good\n *\n * @param baseUrls Current provider base URLs to evaluate\n * @returns Array of provider base URLs disabled by the review set\n */\n async syncReviewedProvidersFromNostr(\n baseUrls: string[] = this.adapter.getBaseUrlsList(),\n providerNodes: Map<string, Set<string>> = this.providerNodePubkeysByUrl\n ): Promise<string[]> {\n if (baseUrls.length === 0) return [];\n\n if (!this.adapter.setDisabledProviders) {\n this.logger.warn(\n \"NostrReviews: adapter does not support setDisabledProviders; skipping provider disable sync\"\n );\n return [];\n }\n\n // Fetch kind 38425 lgtm reviews\n const LGTM_RELAYS = [\n \"wss://relay.primal.net\",\n \"wss://nos.lol\",\n \"wss://relay.damus.io\",\n \"wss://relay.routstr.com\",\n ];\n const reviewedNodePubkeys = new Set<string>();\n {\n const pool = new RelayPool();\n const store = new EventStore();\n const timeoutMs = 5000;\n await new Promise<void>((resolve) => {\n pool\n .req(LGTM_RELAYS, {\n kinds: [38425],\n \"#t\": [\"lgtm\"],\n limit: 500,\n authors: [this.routstrPubkey],\n })\n .pipe(\n onlyEvents(),\n tap((event) => store.add(event))\n )\n .subscribe({ complete: () => resolve() });\n setTimeout(() => resolve(), timeoutMs);\n });\n for (const event of store.getTimeline({ kinds: [38425] })) {\n const hasLgtmTag = event.tags.some(\n (tag) => tag[0] === \"t\" && tag[1]?.toLowerCase() === \"lgtm\"\n );\n if (!hasLgtmTag) continue;\n for (const tag of event.tags) {\n if (tag[0] === \"node\" && typeof tag[1] === \"string\" && tag[1]) {\n reviewedNodePubkeys.add(tag[1]);\n }\n }\n }\n }\n\n if (reviewedNodePubkeys.size === 0) {\n this.logger.warn(\n \"NostrReviews: no kind 38425 lgtm reviews found; keeping disabled providers unchanged\"\n );\n return [];\n }\n\n if (providerNodes.size === 0) {\n this.logger.warn(\n \"NostrReviews: no kind 38421 provider node metadata found; keeping disabled providers unchanged\"\n );\n return [];\n }\n\n const disabledByReview: string[] = [];\n for (const url of baseUrls) {\n const normalized = this.normalizeUrl(url);\n const nodePubkeys = providerNodes.get(normalized) || new Set<string>();\n const hasLgtmReview = Array.from(nodePubkeys).some((pubkey) =>\n reviewedNodePubkeys.has(pubkey)\n );\n if (!hasLgtmReview) {\n disabledByReview.push(normalized);\n }\n }\n\n this.adapter.setDisabledProviders(Array.from(new Set(disabledByReview)));\n\n return disabledByReview;\n }\n\n private addProviderNode(\n map: Map<string, Set<string>>,\n url: string,\n pubkey?: string\n ): void {\n if (!pubkey) return;\n const normalized = this.normalizeUrl(url);\n const existing = map.get(normalized) || new Set<string>();\n existing.add(pubkey);\n map.set(normalized, existing);\n }\n\n\n /**\n * Fetch models from all providers and select best-priced options\n * Uses cache if available and not expired\n * @param baseUrls List of provider base URLs to fetch from\n * @param forceRefresh Ignore cache and fetch fresh data\n * @param onProgress Callback fired after each provider completes with current combined models\n * @returns Array of unique models with best prices selected\n */\n async fetchModels(\n baseUrls: string[],\n forceRefresh: boolean = false,\n onProgress?: (models: Model[]) => void\n ): Promise<Model[]> {\n if (baseUrls.length === 0) {\n throw new NoProvidersAvailableError();\n }\n\n const bestById = new Map<string, { model: Model; base: string }>();\n const modelsFromAllProviders: Record<string, Model[]> = {};\n const disabledProviders = this.adapter.getDisabledProviders();\n\n // Helper to estimate minimum cost for a model\n const estimateMinCost = (m: Model): number => {\n return m?.sats_pricing?.completion ?? 0;\n };\n\n // Helper to emit current progress\n const emitProgress = () => {\n if (onProgress) {\n const currentModels = Array.from(bestById.values()).map((v) => v.model);\n onProgress(currentModels);\n }\n };\n\n // Fetch from all providers in parallel with progressive updates\n const fetchPromises = baseUrls.map(async (url) => {\n const base = url.endsWith(\"/\") ? url : `${url}/`;\n try {\n // Check cache if not forcing refresh\n let list: Model[];\n\n if (!forceRefresh) {\n const lastUpdate = this.adapter.getProviderLastUpdate(base);\n const cacheValid =\n lastUpdate && Date.now() - lastUpdate <= this.cacheTTL;\n\n if (cacheValid) {\n const cachedModels = this.adapter.getCachedModels();\n const cachedList = cachedModels[base] || [];\n list = cachedList;\n } else {\n // Cache expired or doesn't exist, fetch fresh\n list = await this.fetchModelsFromProvider(base);\n }\n } else {\n // Force refresh\n list = await this.fetchModelsFromProvider(base);\n }\n\n modelsFromAllProviders[base] = list;\n this.adapter.setProviderLastUpdate(base, Date.now());\n\n // Update best-priced models if provider not disabled\n if (!disabledProviders.includes(base)) {\n for (const m of list) {\n const existing = bestById.get(m.id);\n\n // Skip models without sats pricing\n if (!m.sats_pricing) continue;\n\n if (!existing) {\n bestById.set(m.id, { model: m, base });\n continue;\n }\n\n // Replace if this provider has lower cost\n const currentCost = estimateMinCost(m);\n const existingCost = estimateMinCost(existing.model);\n if (currentCost < existingCost && m.sats_pricing) {\n bestById.set(m.id, { model: m, base });\n }\n }\n }\n\n emitProgress();\n\n return { success: true, base, list };\n } catch (error) {\n if (this.isProviderDownError(error)) {\n this.logger.warn(`Provider ${base} is down right now.`);\n } else {\n this.logger.warn(`Failed to fetch models from ${base}:`, error);\n }\n this.adapter.setProviderLastUpdate(base, Date.now());\n return { success: false, base };\n }\n });\n\n await Promise.allSettled(fetchPromises);\n\n // Cache all provider results\n const existingCache = this.adapter.getCachedModels();\n this.adapter.setCachedModels({\n ...existingCache,\n ...modelsFromAllProviders,\n });\n\n // Return combined models array\n return Array.from(bestById.values()).map((v) => v.model);\n }\n\n /**\n * Fetch models from a single provider\n * @param baseUrl Provider base URL\n * @returns Array of models from provider\n */\n private async fetchModelsFromProvider(baseUrl: string): Promise<Model[]> {\n const res = await fetch(`${baseUrl}v1/models`);\n if (!res.ok) {\n throw new Error(`Failed to fetch models: ${res.status}`);\n }\n\n const json = await res.json();\n const list = Array.isArray(json?.data) ? json.data : [];\n\n return list;\n }\n\n private isProviderDownError(error: unknown): boolean {\n if (!(error instanceof Error)) return false;\n const msg = error.message.toLowerCase();\n if (msg.includes(\"fetch failed\")) return true;\n if (msg.includes(\"429\")) return true;\n if (msg.includes(\"502\")) return true;\n if (msg.includes(\"503\")) return true;\n if (msg.includes(\"504\")) return true;\n const cause = error.cause as { code?: string } | undefined;\n return cause?.code === \"ENOTFOUND\";\n }\n\n /**\n * Get all cached models from all providers\n * @returns Record mapping baseUrl -> models\n */\n getAllCachedModels(): Record<string, Model[]> {\n return this.adapter.getCachedModels();\n }\n\n /**\n * Clear cache for a specific provider\n * @param baseUrl Provider base URL\n */\n clearProviderCache(baseUrl: string): void {\n const base = baseUrl.endsWith(\"/\") ? baseUrl : `${baseUrl}/`;\n const cached = this.adapter.getCachedModels();\n delete cached[base];\n this.adapter.setCachedModels(cached);\n this.adapter.setProviderLastUpdate(base, 0);\n }\n\n /**\n * Clear all model caches\n */\n clearAllCache(): void {\n this.adapter.setCachedModels({});\n }\n\n /**\n * Filter base URLs based on Tor context\n * @param baseUrls Provider URLs to filter\n * @param torMode Whether in Tor context\n * @returns Filtered URLs appropriate for Tor mode\n */\n filterBaseUrlsForTor(baseUrls: string[], torMode: boolean): string[] {\n if (!torMode) {\n // In normal mode, exclude onion URLs\n return baseUrls.filter((url) => !url.includes(\".onion\"));\n }\n // In Tor mode, only include onion URLs\n return baseUrls.filter((url) => url.includes(\".onion\"));\n }\n\n /**\n * Get provider endpoints from provider info\n * @param provider Provider object from directory\n * @param torMode Whether in Tor context\n * @returns Array of endpoint URLs\n */\n private getProviderEndpoints(provider: any, torMode: boolean): string[] {\n const endpoints: string[] = [];\n\n if (torMode && provider.onion_url) {\n endpoints.push(this.normalizeUrl(provider.onion_url));\n } else if (provider.endpoint_url) {\n endpoints.push(this.normalizeUrl(provider.endpoint_url));\n }\n\n return endpoints;\n }\n\n /**\n * Normalize provider URL with trailing slash\n * @param url URL to normalize\n * @returns Normalized URL\n */\n private normalizeUrl(url: string): string {\n if (!url.startsWith(\"http\")) {\n url = `https://${url}`;\n }\n return url.endsWith(\"/\") ? url : `${url}/`;\n }\n\n /**\n * Fetch routstr21 models from Nostr network (kind 38423)\n * Uses cache if available and not expired\n * @returns Array of model IDs or empty array if not found\n */\n async fetchRoutstr21Models(forceRefresh: boolean = false): Promise<string[]> {\n // Check cache first\n const cachedModels = this.adapter.getRoutstr21Models();\n if (!forceRefresh && cachedModels.length > 0) {\n const lastUpdate = this.adapter.getRoutstr21ModelsLastUpdate();\n const cacheValid = lastUpdate && Date.now() - lastUpdate <= this.cacheTTL;\n if (cacheValid) {\n return cachedModels;\n }\n }\n\n const DEFAULT_RELAYS = [\n \"wss://relay.damus.io\",\n \"wss://nos.lol\",\n \"wss://relay.routstr.com\",\n ];\n\n const pool = new RelayPool();\n const localEventStore = new EventStore();\n\n const timeoutMs = 5000;\n\n await new Promise<void>((resolve) => {\n pool\n .req(DEFAULT_RELAYS, {\n kinds: [38423],\n \"#d\": [\"routstr-21-models\"],\n limit: 1,\n authors: [this.routstrPubkey],\n })\n .pipe(\n onlyEvents(),\n tap((event) => {\n localEventStore.add(event);\n })\n )\n .subscribe({\n complete: () => {\n resolve();\n },\n });\n\n setTimeout(() => {\n resolve();\n }, timeoutMs);\n });\n\n const timeline = localEventStore.getTimeline({ kinds: [38423] });\n\n if (timeline.length === 0) {\n return cachedModels.length > 0 ? cachedModels : [];\n }\n\n const event = timeline[0];\n\n try {\n const content = JSON.parse(event.content);\n const models = Array.isArray(content?.models) ? content.models : [];\n this.adapter.setRoutstr21Models(models);\n this.adapter.setRoutstr21ModelsLastUpdate(Date.now());\n return models;\n } catch {\n this.logger.warn(\n \"Routstr21Models: failed to parse Nostr event content:\",\n event.id\n );\n return cachedModels.length > 0 ? cachedModels : [];\n }\n }\n}\n","/**\n * MintDiscovery class for discovering mints and provider info\n * Core responsibility: fetching mint information from providers and caching it\n */\n\nimport type { DiscoveryAdapter, ProviderInfo } from \"./interfaces\";\nimport type { SdkLogger } from \"../core/types\";\nimport { consoleLogger } from \"../core/types\";\n\n/**\n * Configuration for MintDiscovery\n */\nexport interface MintDiscoveryConfig {\n /** Cache TTL in milliseconds (default: 21 minutes) */\n cacheTTL?: number;\n /** Optional injectable logger */\n logger?: SdkLogger;\n}\n\n/**\n * MintDiscovery handles mint and provider info discovery\n * Abstracts away storage details via DiscoveryAdapter\n */\nexport class MintDiscovery {\n private readonly cacheTTL: number;\n private readonly logger: SdkLogger;\n\n constructor(\n private adapter: DiscoveryAdapter,\n config: MintDiscoveryConfig = {}\n ) {\n this.cacheTTL = config.cacheTTL || 21 * 60 * 1000; // 21 minutes\n this.logger = (config.logger ?? consoleLogger).child(\"MintDiscovery\");\n }\n\n /**\n * Fetch mints from all providers via their /v1/info endpoints\n * Caches mints and full provider info for later access\n * @param baseUrls List of provider base URLs to fetch from\n * @returns Object with mints and provider info from all providers\n */\n async discoverMints(\n baseUrls: string[],\n options: { forceRefresh?: boolean } = {}\n ): Promise<{\n mintsFromProviders: Record<string, string[]>;\n infoFromProviders: Record<string, ProviderInfo>;\n }> {\n if (baseUrls.length === 0) {\n return { mintsFromProviders: {}, infoFromProviders: {} };\n }\n\n const mintsFromAllProviders: Record<string, string[]> = {};\n const infoFromAllProviders: Record<string, ProviderInfo> = {};\n const forceRefresh = options.forceRefresh ?? false;\n\n // Fetch info from each provider\n const fetchPromises = baseUrls.map(async (url) => {\n const base = url.endsWith(\"/\") ? url : `${url}/`;\n try {\n if (!forceRefresh) {\n const lastUpdate = this.adapter.getProviderLastUpdate(base);\n const cacheValid =\n lastUpdate && Date.now() - lastUpdate <= this.cacheTTL;\n if (cacheValid) {\n const cachedMints = this.adapter.getCachedMints()[base] || [];\n const cachedInfo = this.adapter.getCachedProviderInfo()[base];\n mintsFromAllProviders[base] = cachedMints;\n if (cachedInfo) {\n infoFromAllProviders[base] = cachedInfo;\n }\n return {\n success: true,\n base,\n mints: cachedMints,\n info: cachedInfo,\n };\n }\n }\n\n const res = await fetch(`${base}v1/info`);\n if (!res.ok) {\n throw new Error(`Failed to fetch info: ${res.status}`);\n }\n\n const json = await res.json();\n\n // Extract mints array from response\n const mints: string[] = Array.isArray(json?.mints) ? json.mints : [];\n\n // Normalize mint URLs (remove trailing slashes for consistency)\n const normalizedMints = mints.map((mint) =>\n mint.endsWith(\"/\") ? mint.slice(0, -1) : mint\n );\n\n // Save provider mints and full info\n mintsFromAllProviders[base] = normalizedMints;\n infoFromAllProviders[base] = json;\n this.adapter.setProviderLastUpdate(base, Date.now());\n\n return { success: true, base, mints: normalizedMints, info: json };\n } catch (error) {\n this.adapter.setProviderLastUpdate(base, Date.now());\n if (this.isProviderDownError(error)) {\n this.logger.warn(`Provider ${base} is down right now.`);\n } else {\n this.logger.warn(`Failed to fetch mints from ${base}:`, error);\n }\n return { success: false, base, mints: [], info: null };\n }\n });\n\n // Wait for all to complete (but allow individual failures)\n const results = await Promise.allSettled(fetchPromises);\n\n // Handle results\n for (const result of results) {\n if (result.status === \"fulfilled\") {\n const { base, mints, info } = result.value;\n mintsFromAllProviders[base] = mints;\n if (info) {\n infoFromAllProviders[base] = info;\n }\n } else {\n this.logger.error(\"Mint discovery error:\", result.reason);\n }\n }\n\n // Cache all results\n try {\n this.adapter.setCachedMints(mintsFromAllProviders);\n this.adapter.setCachedProviderInfo(infoFromAllProviders);\n } catch (error) {\n this.logger.error(\"Error caching mint discovery results:\", error);\n }\n\n return {\n mintsFromProviders: mintsFromAllProviders,\n infoFromProviders: infoFromAllProviders,\n };\n }\n\n /**\n * Get cached mints from all providers\n * @returns Record mapping baseUrl -> mint URLs\n */\n getCachedMints(): Record<string, string[]> {\n return this.adapter.getCachedMints();\n }\n\n /**\n * Get cached provider info from all providers\n * @returns Record mapping baseUrl -> provider info\n */\n getCachedProviderInfo(): Record<string, ProviderInfo> {\n return this.adapter.getCachedProviderInfo();\n }\n\n /**\n * Get mints for a specific provider\n * @param baseUrl Provider base URL\n * @returns Array of mint URLs for the provider\n */\n getProviderMints(baseUrl: string): string[] {\n const normalized = baseUrl.endsWith(\"/\") ? baseUrl : `${baseUrl}/`;\n const allMints = this.getCachedMints();\n return allMints[normalized] || [];\n }\n\n /**\n * Get info for a specific provider\n * @param baseUrl Provider base URL\n * @returns Provider info object or null if not found\n */\n getProviderInfo(baseUrl: string): ProviderInfo | null {\n const normalized = baseUrl.endsWith(\"/\") ? baseUrl : `${baseUrl}/`;\n const allInfo = this.getCachedProviderInfo();\n return allInfo[normalized] || null;\n }\n\n /**\n * Clear mint cache for a specific provider\n * @param baseUrl Provider base URL\n */\n clearProviderMintCache(baseUrl: string): void {\n const normalized = baseUrl.endsWith(\"/\") ? baseUrl : `${baseUrl}/`;\n\n const mints = this.getCachedMints();\n delete mints[normalized];\n this.adapter.setCachedMints(mints);\n\n const info = this.getCachedProviderInfo();\n delete info[normalized];\n this.adapter.setCachedProviderInfo(info);\n }\n\n /**\n * Clear all mint caches\n */\n clearAllCache(): void {\n this.adapter.setCachedMints({});\n this.adapter.setCachedProviderInfo({});\n }\n\n private isProviderDownError(error: unknown): boolean {\n if (!(error instanceof Error)) return false;\n const msg = error.message.toLowerCase();\n if (msg.includes(\"fetch failed\")) return true;\n if (msg.includes(\"429\")) return true;\n if (msg.includes(\"502\")) return true;\n if (msg.includes(\"503\")) return true;\n if (msg.includes(\"504\")) return true;\n const cause = error.cause as { code?: string } | undefined;\n if (cause?.code === \"ENOTFOUND\") return true;\n return false;\n }\n}\n"]}
package/dist/index.d.mts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { S as SdkLogger, M as Model } from './types-DPQM6tIG.mjs';
2
2
  export { A as APIErrorVerdict, b as AnnotationData, C as CandidateProvider, F as FetchAIResponseParams, I as ImageData, a as Message, c as MessageContentType, d as MintDiscoveryResult, e as MintSelection, f as ModelArchitecture, g as ModelDiscoveryResult, h as ModelPricing, i as ModelSatsPricing, j as PendingTokenEntry, k as PerRequestLimits, P as ProviderInfo, R as RefundResult, l as SpendResult, m as StreamingResult, n as TopUpResult, T as TransactionHistory, U as UsageStats, o as consoleLogger, p as noopLogger } from './types-DPQM6tIG.mjs';
3
- import { D as DiscoveryAdapter } from './interfaces-Cxi8R4TT.mjs';
3
+ import { D as DiscoveryAdapter } from './interfaces-Cqkt41QR.mjs';
4
4
  import { ModelManager } from './discovery/index.mjs';
5
5
  export { MintDiscovery, ModelManagerConfig } from './discovery/index.mjs';
6
6
  import { W as WalletAdapter, S as StorageAdapter, P as ProviderRegistry } from './interfaces-Bp0Ngmqv.mjs';
@@ -9,8 +9,8 @@ export { BalanceManager, BalanceState, CashuSpender, CreateProviderTokenOptions,
9
9
  import { DebugLevel, ProviderManager } from './client/index.mjs';
10
10
  export { AlertLevel, FetchOptions, ModelProviderPrice, RouteRequestParams, RoutstrClient, RoutstrClientConfig, RoutstrClientMode, StreamCallbacks, StreamProcessor, createSSEParserTransform, inspectSSEWebStream } from './client/index.mjs';
11
11
  export { SDK_STORAGE_KEYS, createBunSqliteDriver, createBunSqliteUsageTrackingDriver, createIndexedDBDriver, createIndexedDBUsageTrackingDriver, createMemoryDriver, createMemoryUsageTrackingDriver, createSqliteDriver, createSqliteUsageTrackingDriver, getDefaultDiscoveryAdapter, getDefaultProviderRegistry, getDefaultSdkDriver, getDefaultSdkStore, getDefaultStorageAdapter, getDefaultUsageTrackingDriver, localStorageDriver, setDefaultUsageTrackingDriver } from './storage/index.mjs';
12
- import { U as UsageTrackingDriver, S as SdkStore } from './store-CBSyK2qg.mjs';
13
- export { L as ListUsageTrackingOptions, a as StorageDriver, b as UsageTrackingEntry, c as createDiscoveryAdapterFromStore, d as createProviderRegistryFromStore, e as createSdkStore, f as createStorageAdapterFromStore } from './store-CBSyK2qg.mjs';
12
+ import { U as UsageTrackingDriver, S as SdkStore } from './store-C4FyyOnO.mjs';
13
+ export { L as ListUsageTrackingOptions, a as StorageDriver, b as UsageTrackingEntry, c as createDiscoveryAdapterFromStore, d as createProviderRegistryFromStore, e as createSdkStore, f as createStorageAdapterFromStore } from './store-C4FyyOnO.mjs';
14
14
  import 'stream';
15
15
  import 'zustand/vanilla';
16
16
 
@@ -157,6 +157,8 @@ interface RouteRequestOptions {
157
157
  sdkStore?: SdkStore;
158
158
  /** Optional: shared ProviderManager instance for consistent failure tracking */
159
159
  providerManager?: ProviderManager;
160
+ /** Nostr pubkey for routstr review/model events (kind 38425/38423). Defaults to routstr's key. */
161
+ routstrPubkey?: string;
160
162
  /** Optional: injectable logger for structured/prefixed logging */
161
163
  logger?: SdkLogger;
162
164
  }
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { S as SdkLogger, M as Model } from './types-DPQM6tIG.js';
2
2
  export { A as APIErrorVerdict, b as AnnotationData, C as CandidateProvider, F as FetchAIResponseParams, I as ImageData, a as Message, c as MessageContentType, d as MintDiscoveryResult, e as MintSelection, f as ModelArchitecture, g as ModelDiscoveryResult, h as ModelPricing, i as ModelSatsPricing, j as PendingTokenEntry, k as PerRequestLimits, P as ProviderInfo, R as RefundResult, l as SpendResult, m as StreamingResult, n as TopUpResult, T as TransactionHistory, U as UsageStats, o as consoleLogger, p as noopLogger } from './types-DPQM6tIG.js';
3
- import { D as DiscoveryAdapter } from './interfaces-CIfd_phZ.js';
3
+ import { D as DiscoveryAdapter } from './interfaces-D9qI1ym6.js';
4
4
  import { ModelManager } from './discovery/index.js';
5
5
  export { MintDiscovery, ModelManagerConfig } from './discovery/index.js';
6
6
  import { W as WalletAdapter, S as StorageAdapter, P as ProviderRegistry } from './interfaces-D2FDCLyP.js';
@@ -9,8 +9,8 @@ export { BalanceManager, BalanceState, CashuSpender, CreateProviderTokenOptions,
9
9
  import { DebugLevel, ProviderManager } from './client/index.js';
10
10
  export { AlertLevel, FetchOptions, ModelProviderPrice, RouteRequestParams, RoutstrClient, RoutstrClientConfig, RoutstrClientMode, StreamCallbacks, StreamProcessor, createSSEParserTransform, inspectSSEWebStream } from './client/index.js';
11
11
  export { SDK_STORAGE_KEYS, createBunSqliteDriver, createBunSqliteUsageTrackingDriver, createIndexedDBDriver, createIndexedDBUsageTrackingDriver, createMemoryDriver, createMemoryUsageTrackingDriver, createSqliteDriver, createSqliteUsageTrackingDriver, getDefaultDiscoveryAdapter, getDefaultProviderRegistry, getDefaultSdkDriver, getDefaultSdkStore, getDefaultStorageAdapter, getDefaultUsageTrackingDriver, localStorageDriver, setDefaultUsageTrackingDriver } from './storage/index.js';
12
- import { U as UsageTrackingDriver, S as SdkStore } from './store-BD5zF9Hp.js';
13
- export { L as ListUsageTrackingOptions, a as StorageDriver, b as UsageTrackingEntry, c as createDiscoveryAdapterFromStore, d as createProviderRegistryFromStore, e as createSdkStore, f as createStorageAdapterFromStore } from './store-BD5zF9Hp.js';
12
+ import { U as UsageTrackingDriver, S as SdkStore } from './store-BFUGGr_v.js';
13
+ export { L as ListUsageTrackingOptions, a as StorageDriver, b as UsageTrackingEntry, c as createDiscoveryAdapterFromStore, d as createProviderRegistryFromStore, e as createSdkStore, f as createStorageAdapterFromStore } from './store-BFUGGr_v.js';
14
14
  import 'stream';
15
15
  import 'zustand/vanilla';
16
16
 
@@ -157,6 +157,8 @@ interface RouteRequestOptions {
157
157
  sdkStore?: SdkStore;
158
158
  /** Optional: shared ProviderManager instance for consistent failure tracking */
159
159
  providerManager?: ProviderManager;
160
+ /** Nostr pubkey for routstr review/model events (kind 38425/38423). Defaults to routstr's key. */
161
+ routstrPubkey?: string;
160
162
  /** Optional: injectable logger for structured/prefixed logging */
161
163
  logger?: SdkLogger;
162
164
  }