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