@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.
- package/dist/client/index.d.mts +2 -2
- package/dist/client/index.d.ts +2 -2
- package/dist/client/index.js +7 -2
- package/dist/client/index.js.map +1 -1
- package/dist/client/index.mjs +7 -2
- package/dist/client/index.mjs.map +1 -1
- package/dist/discovery/index.d.mts +18 -1
- package/dist/discovery/index.d.ts +18 -1
- package/dist/discovery/index.js +125 -6
- package/dist/discovery/index.js.map +1 -1
- package/dist/discovery/index.mjs +125 -6
- package/dist/discovery/index.mjs.map +1 -1
- package/dist/index.d.mts +5 -3
- package/dist/index.d.ts +5 -3
- package/dist/index.js +134 -8
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +134 -8
- package/dist/index.mjs.map +1 -1
- package/dist/{interfaces-Cxi8R4TT.d.mts → interfaces-Cqkt41QR.d.mts} +6 -0
- package/dist/{interfaces-CIfd_phZ.d.ts → interfaces-D9qI1ym6.d.ts} +6 -0
- package/dist/storage/index.d.mts +3 -3
- package/dist/storage/index.d.ts +3 -3
- package/dist/storage/index.js +8 -2
- package/dist/storage/index.js.map +1 -1
- package/dist/storage/index.mjs +8 -2
- package/dist/storage/index.mjs.map +1 -1
- package/dist/{store-BD5zF9Hp.d.ts → store-BFUGGr_v.d.ts} +1 -1
- package/dist/{store-CBSyK2qg.d.mts → store-C4FyyOnO.d.mts} +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -126,13 +126,16 @@ var ModelManager = class _ModelManager {
|
|
|
126
126
|
this.cacheTTL = config.cacheTTL || 210 * 60 * 1e3;
|
|
127
127
|
this.includeProviderUrls = config.includeProviderUrls || [];
|
|
128
128
|
this.excludeProviderUrls = config.excludeProviderUrls || [];
|
|
129
|
+
this.routstrPubkey = config.routstrPubkey || "4ad6fa2d16e2a9b576c863b4cf7404a70d4dc320c0c447d10ad6ff58993eacc8";
|
|
129
130
|
this.logger = (config.logger ?? consoleLogger).child("ModelManager");
|
|
130
131
|
}
|
|
131
132
|
cacheTTL;
|
|
132
133
|
providerDirectoryUrl;
|
|
133
134
|
includeProviderUrls;
|
|
134
135
|
excludeProviderUrls;
|
|
136
|
+
routstrPubkey;
|
|
135
137
|
logger;
|
|
138
|
+
providerNodePubkeysByUrl = /* @__PURE__ */ new Map();
|
|
136
139
|
/**
|
|
137
140
|
* Get the list of bootstrapped provider base URLs
|
|
138
141
|
* @returns Array of provider base URLs
|
|
@@ -163,8 +166,13 @@ var ModelManager = class _ModelManager {
|
|
|
163
166
|
const lastUpdate = this.adapter.getBaseUrlsLastUpdate();
|
|
164
167
|
const cacheValid = lastUpdate && Date.now() - lastUpdate <= this.cacheTTL;
|
|
165
168
|
if (cacheValid) {
|
|
169
|
+
const filteredCachedUrls = this.filterBaseUrlsForTor(
|
|
170
|
+
cachedUrls,
|
|
171
|
+
torMode
|
|
172
|
+
);
|
|
166
173
|
await this.fetchRoutstr21Models(forceRefresh);
|
|
167
|
-
|
|
174
|
+
await this.syncReviewedProvidersFromNostr(filteredCachedUrls);
|
|
175
|
+
return filteredCachedUrls;
|
|
168
176
|
}
|
|
169
177
|
}
|
|
170
178
|
}
|
|
@@ -175,6 +183,7 @@ var ModelManager = class _ModelManager {
|
|
|
175
183
|
this.adapter.setBaseUrlsList(filtered);
|
|
176
184
|
this.adapter.setBaseUrlsLastUpdate(Date.now());
|
|
177
185
|
await this.fetchRoutstr21Models(forceRefresh);
|
|
186
|
+
await this.syncReviewedProvidersFromNostr(filtered);
|
|
178
187
|
return filtered;
|
|
179
188
|
}
|
|
180
189
|
} catch (e) {
|
|
@@ -217,6 +226,7 @@ var ModelManager = class _ModelManager {
|
|
|
217
226
|
});
|
|
218
227
|
const timeline = localEventStore.getTimeline({ kinds: [kind] });
|
|
219
228
|
const bases = /* @__PURE__ */ new Set();
|
|
229
|
+
this.providerNodePubkeysByUrl = /* @__PURE__ */ new Map();
|
|
220
230
|
for (const event of timeline) {
|
|
221
231
|
const eventUrls = [];
|
|
222
232
|
for (const tag of event.tags) {
|
|
@@ -229,6 +239,11 @@ var ModelManager = class _ModelManager {
|
|
|
229
239
|
const normalized = this.normalizeUrl(url);
|
|
230
240
|
if (!torMode || normalized.includes(".onion")) {
|
|
231
241
|
bases.add(normalized);
|
|
242
|
+
this.addProviderNode(
|
|
243
|
+
this.providerNodePubkeysByUrl,
|
|
244
|
+
normalized,
|
|
245
|
+
event.pubkey
|
|
246
|
+
);
|
|
232
247
|
}
|
|
233
248
|
}
|
|
234
249
|
continue;
|
|
@@ -240,6 +255,11 @@ var ModelManager = class _ModelManager {
|
|
|
240
255
|
const endpoints = this.getProviderEndpoints(p, torMode);
|
|
241
256
|
for (const endpoint of endpoints) {
|
|
242
257
|
bases.add(endpoint);
|
|
258
|
+
this.addProviderNode(
|
|
259
|
+
this.providerNodePubkeysByUrl,
|
|
260
|
+
endpoint,
|
|
261
|
+
p?.pubkey || event.pubkey
|
|
262
|
+
);
|
|
243
263
|
}
|
|
244
264
|
}
|
|
245
265
|
} catch {
|
|
@@ -250,11 +270,19 @@ var ModelManager = class _ModelManager {
|
|
|
250
270
|
const endpoints = this.getProviderEndpoints(p, torMode);
|
|
251
271
|
for (const endpoint of endpoints) {
|
|
252
272
|
bases.add(endpoint);
|
|
273
|
+
this.addProviderNode(
|
|
274
|
+
this.providerNodePubkeysByUrl,
|
|
275
|
+
endpoint,
|
|
276
|
+
p?.pubkey || event.pubkey
|
|
277
|
+
);
|
|
253
278
|
}
|
|
254
279
|
}
|
|
255
280
|
}
|
|
256
281
|
} catch {
|
|
257
|
-
this.logger.warn(
|
|
282
|
+
this.logger.warn(
|
|
283
|
+
"NostrBootstrap: failed to parse event content:",
|
|
284
|
+
event.id
|
|
285
|
+
);
|
|
258
286
|
}
|
|
259
287
|
}
|
|
260
288
|
}
|
|
@@ -285,10 +313,12 @@ var ModelManager = class _ModelManager {
|
|
|
285
313
|
const data = await res.json();
|
|
286
314
|
const providers = Array.isArray(data?.providers) ? data.providers : [];
|
|
287
315
|
const bases = /* @__PURE__ */ new Set();
|
|
316
|
+
this.providerNodePubkeysByUrl = /* @__PURE__ */ new Map();
|
|
288
317
|
for (const p of providers) {
|
|
289
318
|
const endpoints = this.getProviderEndpoints(p, torMode);
|
|
290
319
|
for (const endpoint of endpoints) {
|
|
291
320
|
bases.add(endpoint);
|
|
321
|
+
this.addProviderNode(this.providerNodePubkeysByUrl, endpoint, p?.pubkey);
|
|
292
322
|
}
|
|
293
323
|
}
|
|
294
324
|
for (const url of this.includeProviderUrls) {
|
|
@@ -305,6 +335,7 @@ var ModelManager = class _ModelManager {
|
|
|
305
335
|
this.adapter.setBaseUrlsList(list);
|
|
306
336
|
this.adapter.setBaseUrlsLastUpdate(Date.now());
|
|
307
337
|
await this.fetchRoutstr21Models(forceRefresh);
|
|
338
|
+
await this.syncReviewedProvidersFromNostr(list);
|
|
308
339
|
}
|
|
309
340
|
return list;
|
|
310
341
|
} catch (e) {
|
|
@@ -312,6 +343,93 @@ var ModelManager = class _ModelManager {
|
|
|
312
343
|
throw new ProviderBootstrapError([], `Provider bootstrap failed: ${e}`);
|
|
313
344
|
}
|
|
314
345
|
}
|
|
346
|
+
/**
|
|
347
|
+
* Fetch Routstr review events from Nostr (kind 38425) and disable providers
|
|
348
|
+
* whose 38421 node pubkey does not have at least one review tagged `t=lgtm`.
|
|
349
|
+
*
|
|
350
|
+
* Review events are expected to have:
|
|
351
|
+
* - `node`: the reviewed 38421 provider event pubkey
|
|
352
|
+
* - `t`: review label, where `lgtm` means the node looks good
|
|
353
|
+
*
|
|
354
|
+
* @param baseUrls Current provider base URLs to evaluate
|
|
355
|
+
* @returns Array of provider base URLs disabled by the review set
|
|
356
|
+
*/
|
|
357
|
+
async syncReviewedProvidersFromNostr(baseUrls = this.adapter.getBaseUrlsList(), providerNodes = this.providerNodePubkeysByUrl) {
|
|
358
|
+
if (baseUrls.length === 0) return [];
|
|
359
|
+
if (!this.adapter.setDisabledProviders) {
|
|
360
|
+
this.logger.warn(
|
|
361
|
+
"NostrReviews: adapter does not support setDisabledProviders; skipping provider disable sync"
|
|
362
|
+
);
|
|
363
|
+
return [];
|
|
364
|
+
}
|
|
365
|
+
const LGTM_RELAYS = [
|
|
366
|
+
"wss://relay.primal.net",
|
|
367
|
+
"wss://nos.lol",
|
|
368
|
+
"wss://relay.damus.io",
|
|
369
|
+
"wss://relay.routstr.com"
|
|
370
|
+
];
|
|
371
|
+
const reviewedNodePubkeys = /* @__PURE__ */ new Set();
|
|
372
|
+
{
|
|
373
|
+
const pool = new RelayPool();
|
|
374
|
+
const store = new EventStore();
|
|
375
|
+
const timeoutMs = 5e3;
|
|
376
|
+
await new Promise((resolve) => {
|
|
377
|
+
pool.req(LGTM_RELAYS, {
|
|
378
|
+
kinds: [38425],
|
|
379
|
+
"#t": ["lgtm"],
|
|
380
|
+
limit: 500,
|
|
381
|
+
authors: [this.routstrPubkey]
|
|
382
|
+
}).pipe(
|
|
383
|
+
onlyEvents(),
|
|
384
|
+
tap((event) => store.add(event))
|
|
385
|
+
).subscribe({ complete: () => resolve() });
|
|
386
|
+
setTimeout(() => resolve(), timeoutMs);
|
|
387
|
+
});
|
|
388
|
+
for (const event of store.getTimeline({ kinds: [38425] })) {
|
|
389
|
+
const hasLgtmTag = event.tags.some(
|
|
390
|
+
(tag) => tag[0] === "t" && tag[1]?.toLowerCase() === "lgtm"
|
|
391
|
+
);
|
|
392
|
+
if (!hasLgtmTag) continue;
|
|
393
|
+
for (const tag of event.tags) {
|
|
394
|
+
if (tag[0] === "node" && typeof tag[1] === "string" && tag[1]) {
|
|
395
|
+
reviewedNodePubkeys.add(tag[1]);
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
if (reviewedNodePubkeys.size === 0) {
|
|
401
|
+
this.logger.warn(
|
|
402
|
+
"NostrReviews: no kind 38425 lgtm reviews found; keeping disabled providers unchanged"
|
|
403
|
+
);
|
|
404
|
+
return [];
|
|
405
|
+
}
|
|
406
|
+
if (providerNodes.size === 0) {
|
|
407
|
+
this.logger.warn(
|
|
408
|
+
"NostrReviews: no kind 38421 provider node metadata found; keeping disabled providers unchanged"
|
|
409
|
+
);
|
|
410
|
+
return [];
|
|
411
|
+
}
|
|
412
|
+
const disabledByReview = [];
|
|
413
|
+
for (const url of baseUrls) {
|
|
414
|
+
const normalized = this.normalizeUrl(url);
|
|
415
|
+
const nodePubkeys = providerNodes.get(normalized) || /* @__PURE__ */ new Set();
|
|
416
|
+
const hasLgtmReview = Array.from(nodePubkeys).some(
|
|
417
|
+
(pubkey) => reviewedNodePubkeys.has(pubkey)
|
|
418
|
+
);
|
|
419
|
+
if (!hasLgtmReview) {
|
|
420
|
+
disabledByReview.push(normalized);
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
this.adapter.setDisabledProviders(Array.from(new Set(disabledByReview)));
|
|
424
|
+
return disabledByReview;
|
|
425
|
+
}
|
|
426
|
+
addProviderNode(map, url, pubkey) {
|
|
427
|
+
if (!pubkey) return;
|
|
428
|
+
const normalized = this.normalizeUrl(url);
|
|
429
|
+
const existing = map.get(normalized) || /* @__PURE__ */ new Set();
|
|
430
|
+
existing.add(pubkey);
|
|
431
|
+
map.set(normalized, existing);
|
|
432
|
+
}
|
|
315
433
|
/**
|
|
316
434
|
* Fetch models from all providers and select best-priced options
|
|
317
435
|
* Uses cache if available and not expired
|
|
@@ -504,9 +622,7 @@ var ModelManager = class _ModelManager {
|
|
|
504
622
|
kinds: [38423],
|
|
505
623
|
"#d": ["routstr-21-models"],
|
|
506
624
|
limit: 1,
|
|
507
|
-
authors: [
|
|
508
|
-
"4ad6fa2d16e2a9b576c863b4cf7404a70d4dc320c0c447d10ad6ff58993eacc8"
|
|
509
|
-
]
|
|
625
|
+
authors: [this.routstrPubkey]
|
|
510
626
|
}).pipe(
|
|
511
627
|
onlyEvents(),
|
|
512
628
|
tap((event2) => {
|
|
@@ -533,7 +649,10 @@ var ModelManager = class _ModelManager {
|
|
|
533
649
|
this.adapter.setRoutstr21ModelsLastUpdate(Date.now());
|
|
534
650
|
return models;
|
|
535
651
|
} catch {
|
|
536
|
-
this.logger.warn(
|
|
652
|
+
this.logger.warn(
|
|
653
|
+
"Routstr21Models: failed to parse Nostr event content:",
|
|
654
|
+
event.id
|
|
655
|
+
);
|
|
537
656
|
return cachedModels.length > 0 ? cachedModels : [];
|
|
538
657
|
}
|
|
539
658
|
}
|
|
@@ -4140,7 +4259,10 @@ var hydrateStoreFromDriver = async (store, driver) => {
|
|
|
4140
4259
|
driver.getItem(SDK_STORAGE_KEYS.CLIENT_IDS, []),
|
|
4141
4260
|
driver.getItem(SDK_STORAGE_KEYS.FAILED_PROVIDERS, []),
|
|
4142
4261
|
driver.getItem(SDK_STORAGE_KEYS.LAST_FAILED, {}),
|
|
4143
|
-
driver.getItem(
|
|
4262
|
+
driver.getItem(
|
|
4263
|
+
SDK_STORAGE_KEYS.PROVIDERS_ON_COOLDOWN,
|
|
4264
|
+
[]
|
|
4265
|
+
)
|
|
4144
4266
|
]);
|
|
4145
4267
|
const modelsFromAllProviders = Object.fromEntries(
|
|
4146
4268
|
Object.entries(rawModels).map(([baseUrl, models]) => [
|
|
@@ -4208,7 +4330,9 @@ var hydrateStoreFromDriver = async (store, driver) => {
|
|
|
4208
4330
|
createdAt: entry.createdAt ?? Date.now(),
|
|
4209
4331
|
lastUsed: entry.lastUsed ?? null
|
|
4210
4332
|
}));
|
|
4211
|
-
const failedProviders = rawFailedProviders.map(
|
|
4333
|
+
const failedProviders = rawFailedProviders.map(
|
|
4334
|
+
(url) => normalizeBaseUrl5(url)
|
|
4335
|
+
);
|
|
4212
4336
|
const lastFailed = Object.fromEntries(
|
|
4213
4337
|
Object.entries(rawLastFailed).map(([baseUrl, timestamp]) => [
|
|
4214
4338
|
normalizeBaseUrl5(baseUrl),
|
|
@@ -4270,6 +4394,7 @@ var createDiscoveryAdapterFromStore = (store) => ({
|
|
|
4270
4394
|
getLastUsedModel: () => store.getState().lastUsedModel,
|
|
4271
4395
|
setLastUsedModel: (modelId) => store.getState().setLastUsedModel(modelId),
|
|
4272
4396
|
getDisabledProviders: () => store.getState().disabledProviders,
|
|
4397
|
+
setDisabledProviders: (urls) => store.getState().setDisabledProviders(urls),
|
|
4273
4398
|
getBaseUrlsList: () => store.getState().baseUrlsList,
|
|
4274
4399
|
setBaseUrlsList: (urls) => store.getState().setBaseUrlsList(urls),
|
|
4275
4400
|
getBaseUrlsLastUpdate: () => store.getState().lastBaseUrlsUpdate,
|
|
@@ -5942,6 +6067,7 @@ async function resolveRouteRequestContext(options) {
|
|
|
5942
6067
|
} else {
|
|
5943
6068
|
modelManager = new ModelManager(discoveryAdapter, {
|
|
5944
6069
|
includeProviderUrls: forcedProvider ? [forcedProvider, ...includeProviderUrls] : includeProviderUrls,
|
|
6070
|
+
routstrPubkey: options.routstrPubkey,
|
|
5945
6071
|
logger
|
|
5946
6072
|
});
|
|
5947
6073
|
providers = await modelManager.bootstrapProviders(torMode);
|