@routstr/sdk 0.3.8 → 0.3.9
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.js +80 -25
- package/dist/client/index.js.map +1 -1
- package/dist/client/index.mjs +80 -25
- package/dist/client/index.mjs.map +1 -1
- package/dist/discovery/index.d.mts +37 -3
- package/dist/discovery/index.d.ts +37 -3
- package/dist/discovery/index.js +231 -75
- package/dist/discovery/index.js.map +1 -1
- package/dist/discovery/index.mjs +231 -75
- package/dist/discovery/index.mjs.map +1 -1
- package/dist/index.d.mts +2 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +592 -102
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +591 -103
- package/dist/index.mjs.map +1 -1
- package/dist/storage/index.d.mts +27 -1
- package/dist/storage/index.d.ts +27 -1
- package/dist/storage/index.js +281 -2
- package/dist/storage/index.js.map +1 -1
- package/dist/storage/index.mjs +280 -3
- package/dist/storage/index.mjs.map +1 -1
- package/dist/wallet/index.d.mts +4 -0
- package/dist/wallet/index.d.ts +4 -0
- package/dist/wallet/index.js +11 -4
- package/dist/wallet/index.js.map +1 -1
- package/dist/wallet/index.mjs +11 -4
- package/dist/wallet/index.mjs.map +1 -1
- package/package.json +3 -2
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { D as DiscoveryAdapter } from '../interfaces-Cv1k2EUK.mjs';
|
|
2
2
|
import { S as SdkLogger, e as Model, k as ProviderInfo } from '../types-_21yYFZG.mjs';
|
|
3
|
+
import { EventStore } from 'applesauce-core';
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* ModelManager class for discovering, fetching, and managing models from providers
|
|
@@ -17,12 +18,17 @@ interface ModelManagerConfig {
|
|
|
17
18
|
includeProviderUrls?: string[];
|
|
18
19
|
/** Provider base URLs to exclude */
|
|
19
20
|
excludeProviderUrls?: string[];
|
|
20
|
-
/** Cache TTL in milliseconds (default:
|
|
21
|
+
/** Cache TTL in milliseconds (default: 210 minutes) */
|
|
21
22
|
cacheTTL?: number;
|
|
22
23
|
/** Nostr pubkey for routstr review/model events (kind 38425/38423). Defaults to routstr's key. */
|
|
23
24
|
routstrPubkey?: string;
|
|
24
25
|
/** Optional injectable logger */
|
|
25
26
|
logger?: SdkLogger;
|
|
27
|
+
/** Path to SQLite database for persistent Nostr event storage.
|
|
28
|
+
* If provided, events fetched by ModelManager from relays (kinds 38421,
|
|
29
|
+
* 38423, 38425) are persisted and survive process restarts. The underlying
|
|
30
|
+
* EventStore can also be accessed for advanced/manual event management. */
|
|
31
|
+
eventStoreDbPath?: string;
|
|
26
32
|
}
|
|
27
33
|
/**
|
|
28
34
|
* ModelManager handles all model discovery and caching logic
|
|
@@ -37,12 +43,40 @@ declare class ModelManager {
|
|
|
37
43
|
private readonly routstrPubkey;
|
|
38
44
|
private readonly logger;
|
|
39
45
|
private providerNodePubkeysByUrl;
|
|
46
|
+
/** Persistent event store for relay-fetched events (null if not configured/initialized) */
|
|
47
|
+
private eventStore;
|
|
48
|
+
private eventStoreDb;
|
|
49
|
+
private eventStoreInitPromise;
|
|
50
|
+
private readonly eventStoreDbPath?;
|
|
40
51
|
constructor(adapter: DiscoveryAdapter, config?: ModelManagerConfig);
|
|
41
52
|
/**
|
|
42
53
|
* Get the list of bootstrapped provider base URLs
|
|
43
54
|
* @returns Array of provider base URLs
|
|
44
55
|
*/
|
|
45
56
|
getBaseUrls(): string[];
|
|
57
|
+
/**
|
|
58
|
+
* Lazily initialize the persistent event store.
|
|
59
|
+
* Returns null if no eventStoreDbPath was provided.
|
|
60
|
+
*/
|
|
61
|
+
private ensureEventStore;
|
|
62
|
+
/**
|
|
63
|
+
* Get the persistent event store, initializing it if configured.
|
|
64
|
+
* Returns null if no eventStoreDbPath was provided.
|
|
65
|
+
*/
|
|
66
|
+
getEventStore(): Promise<EventStore | null>;
|
|
67
|
+
private createPersistentEventDatabase;
|
|
68
|
+
/** Close the persistent event store database handle, if configured. */
|
|
69
|
+
closeEventStore(): void;
|
|
70
|
+
private initializeEventStoreMetadata;
|
|
71
|
+
private markEventFetched;
|
|
72
|
+
private getEventFetchedAt;
|
|
73
|
+
/**
|
|
74
|
+
* Check the persistent event store for fresh cached events.
|
|
75
|
+
* Returns events from SQLite if they were fetched within `maxAge`, otherwise
|
|
76
|
+
* returns empty array (caller should hit relays). Events without local fetch
|
|
77
|
+
* metadata fall back to Nostr created_at for backwards compatibility.
|
|
78
|
+
*/
|
|
79
|
+
private getCachedNostrEvents;
|
|
46
80
|
static init(adapter: DiscoveryAdapter, config?: ModelManagerConfig, options?: {
|
|
47
81
|
torMode?: boolean;
|
|
48
82
|
forceRefresh?: boolean;
|
|
@@ -57,7 +91,7 @@ declare class ModelManager {
|
|
|
57
91
|
*/
|
|
58
92
|
bootstrapProviders(torMode?: boolean, forceRefresh?: boolean): Promise<string[]>;
|
|
59
93
|
/**
|
|
60
|
-
* Bootstrap providers from Nostr network (kind
|
|
94
|
+
* Bootstrap providers from Nostr network (kind 38421)
|
|
61
95
|
* @param kind The Nostr kind to fetch
|
|
62
96
|
* @param torMode Whether running in Tor context
|
|
63
97
|
* @returns Array of provider base URLs
|
|
@@ -81,7 +115,7 @@ declare class ModelManager {
|
|
|
81
115
|
* @param baseUrls Current provider base URLs to evaluate
|
|
82
116
|
* @returns Array of provider base URLs disabled by the review set
|
|
83
117
|
*/
|
|
84
|
-
syncReviewedProvidersFromNostr(baseUrls?: string[], providerNodes?: Map<string, Set<string
|
|
118
|
+
syncReviewedProvidersFromNostr(baseUrls?: string[], providerNodes?: Map<string, Set<string>>, forceRefresh?: boolean): Promise<string[]>;
|
|
85
119
|
private addProviderNode;
|
|
86
120
|
/**
|
|
87
121
|
* Fetch models from all providers and select best-priced options
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { D as DiscoveryAdapter } from '../interfaces-iL7CWeG5.js';
|
|
2
2
|
import { S as SdkLogger, e as Model, k as ProviderInfo } from '../types-_21yYFZG.js';
|
|
3
|
+
import { EventStore } from 'applesauce-core';
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* ModelManager class for discovering, fetching, and managing models from providers
|
|
@@ -17,12 +18,17 @@ interface ModelManagerConfig {
|
|
|
17
18
|
includeProviderUrls?: string[];
|
|
18
19
|
/** Provider base URLs to exclude */
|
|
19
20
|
excludeProviderUrls?: string[];
|
|
20
|
-
/** Cache TTL in milliseconds (default:
|
|
21
|
+
/** Cache TTL in milliseconds (default: 210 minutes) */
|
|
21
22
|
cacheTTL?: number;
|
|
22
23
|
/** Nostr pubkey for routstr review/model events (kind 38425/38423). Defaults to routstr's key. */
|
|
23
24
|
routstrPubkey?: string;
|
|
24
25
|
/** Optional injectable logger */
|
|
25
26
|
logger?: SdkLogger;
|
|
27
|
+
/** Path to SQLite database for persistent Nostr event storage.
|
|
28
|
+
* If provided, events fetched by ModelManager from relays (kinds 38421,
|
|
29
|
+
* 38423, 38425) are persisted and survive process restarts. The underlying
|
|
30
|
+
* EventStore can also be accessed for advanced/manual event management. */
|
|
31
|
+
eventStoreDbPath?: string;
|
|
26
32
|
}
|
|
27
33
|
/**
|
|
28
34
|
* ModelManager handles all model discovery and caching logic
|
|
@@ -37,12 +43,40 @@ declare class ModelManager {
|
|
|
37
43
|
private readonly routstrPubkey;
|
|
38
44
|
private readonly logger;
|
|
39
45
|
private providerNodePubkeysByUrl;
|
|
46
|
+
/** Persistent event store for relay-fetched events (null if not configured/initialized) */
|
|
47
|
+
private eventStore;
|
|
48
|
+
private eventStoreDb;
|
|
49
|
+
private eventStoreInitPromise;
|
|
50
|
+
private readonly eventStoreDbPath?;
|
|
40
51
|
constructor(adapter: DiscoveryAdapter, config?: ModelManagerConfig);
|
|
41
52
|
/**
|
|
42
53
|
* Get the list of bootstrapped provider base URLs
|
|
43
54
|
* @returns Array of provider base URLs
|
|
44
55
|
*/
|
|
45
56
|
getBaseUrls(): string[];
|
|
57
|
+
/**
|
|
58
|
+
* Lazily initialize the persistent event store.
|
|
59
|
+
* Returns null if no eventStoreDbPath was provided.
|
|
60
|
+
*/
|
|
61
|
+
private ensureEventStore;
|
|
62
|
+
/**
|
|
63
|
+
* Get the persistent event store, initializing it if configured.
|
|
64
|
+
* Returns null if no eventStoreDbPath was provided.
|
|
65
|
+
*/
|
|
66
|
+
getEventStore(): Promise<EventStore | null>;
|
|
67
|
+
private createPersistentEventDatabase;
|
|
68
|
+
/** Close the persistent event store database handle, if configured. */
|
|
69
|
+
closeEventStore(): void;
|
|
70
|
+
private initializeEventStoreMetadata;
|
|
71
|
+
private markEventFetched;
|
|
72
|
+
private getEventFetchedAt;
|
|
73
|
+
/**
|
|
74
|
+
* Check the persistent event store for fresh cached events.
|
|
75
|
+
* Returns events from SQLite if they were fetched within `maxAge`, otherwise
|
|
76
|
+
* returns empty array (caller should hit relays). Events without local fetch
|
|
77
|
+
* metadata fall back to Nostr created_at for backwards compatibility.
|
|
78
|
+
*/
|
|
79
|
+
private getCachedNostrEvents;
|
|
46
80
|
static init(adapter: DiscoveryAdapter, config?: ModelManagerConfig, options?: {
|
|
47
81
|
torMode?: boolean;
|
|
48
82
|
forceRefresh?: boolean;
|
|
@@ -57,7 +91,7 @@ declare class ModelManager {
|
|
|
57
91
|
*/
|
|
58
92
|
bootstrapProviders(torMode?: boolean, forceRefresh?: boolean): Promise<string[]>;
|
|
59
93
|
/**
|
|
60
|
-
* Bootstrap providers from Nostr network (kind
|
|
94
|
+
* Bootstrap providers from Nostr network (kind 38421)
|
|
61
95
|
* @param kind The Nostr kind to fetch
|
|
62
96
|
* @param torMode Whether running in Tor context
|
|
63
97
|
* @returns Array of provider base URLs
|
|
@@ -81,7 +115,7 @@ declare class ModelManager {
|
|
|
81
115
|
* @param baseUrls Current provider base URLs to evaluate
|
|
82
116
|
* @returns Array of provider base URLs disabled by the review set
|
|
83
117
|
*/
|
|
84
|
-
syncReviewedProvidersFromNostr(baseUrls?: string[], providerNodes?: Map<string, Set<string
|
|
118
|
+
syncReviewedProvidersFromNostr(baseUrls?: string[], providerNodes?: Map<string, Set<string>>, forceRefresh?: boolean): Promise<string[]>;
|
|
85
119
|
private addProviderNode;
|
|
86
120
|
/**
|
|
87
121
|
* Fetch models from all providers and select best-priced options
|
package/dist/discovery/index.js
CHANGED
|
@@ -34,6 +34,9 @@ var NoProvidersAvailableError = class extends Error {
|
|
|
34
34
|
this.name = "NoProvidersAvailableError";
|
|
35
35
|
}
|
|
36
36
|
};
|
|
37
|
+
function isBunRuntime() {
|
|
38
|
+
return typeof Bun !== "undefined";
|
|
39
|
+
}
|
|
37
40
|
var ModelManager = class _ModelManager {
|
|
38
41
|
constructor(adapter, config = {}) {
|
|
39
42
|
this.adapter = adapter;
|
|
@@ -43,6 +46,7 @@ var ModelManager = class _ModelManager {
|
|
|
43
46
|
this.excludeProviderUrls = config.excludeProviderUrls || [];
|
|
44
47
|
this.routstrPubkey = config.routstrPubkey || "4ad6fa2d16e2a9b576c863b4cf7404a70d4dc320c0c447d10ad6ff58993eacc8";
|
|
45
48
|
this.logger = (config.logger ?? consoleLogger).child("ModelManager");
|
|
49
|
+
this.eventStoreDbPath = config.eventStoreDbPath;
|
|
46
50
|
}
|
|
47
51
|
adapter;
|
|
48
52
|
cacheTTL;
|
|
@@ -52,6 +56,11 @@ var ModelManager = class _ModelManager {
|
|
|
52
56
|
routstrPubkey;
|
|
53
57
|
logger;
|
|
54
58
|
providerNodePubkeysByUrl = /* @__PURE__ */ new Map();
|
|
59
|
+
/** Persistent event store for relay-fetched events (null if not configured/initialized) */
|
|
60
|
+
eventStore = null;
|
|
61
|
+
eventStoreDb = null;
|
|
62
|
+
eventStoreInitPromise = null;
|
|
63
|
+
eventStoreDbPath;
|
|
55
64
|
/**
|
|
56
65
|
* Get the list of bootstrapped provider base URLs
|
|
57
66
|
* @returns Array of provider base URLs
|
|
@@ -59,6 +68,104 @@ var ModelManager = class _ModelManager {
|
|
|
59
68
|
getBaseUrls() {
|
|
60
69
|
return this.adapter.getBaseUrlsList();
|
|
61
70
|
}
|
|
71
|
+
/**
|
|
72
|
+
* Lazily initialize the persistent event store.
|
|
73
|
+
* Returns null if no eventStoreDbPath was provided.
|
|
74
|
+
*/
|
|
75
|
+
async ensureEventStore() {
|
|
76
|
+
if (!this.eventStoreDbPath) return null;
|
|
77
|
+
if (this.eventStore) return this.eventStore;
|
|
78
|
+
if (!this.eventStoreInitPromise) {
|
|
79
|
+
this.eventStoreInitPromise = (async () => {
|
|
80
|
+
try {
|
|
81
|
+
const db = await this.createPersistentEventDatabase();
|
|
82
|
+
this.eventStoreDb = db;
|
|
83
|
+
this.eventStore = new applesauceCore.EventStore({ database: db });
|
|
84
|
+
this.initializeEventStoreMetadata();
|
|
85
|
+
this.logger.log(
|
|
86
|
+
`Persistent event store initialized at ${this.eventStoreDbPath}`
|
|
87
|
+
);
|
|
88
|
+
return this.eventStore;
|
|
89
|
+
} catch (error) {
|
|
90
|
+
this.eventStoreInitPromise = null;
|
|
91
|
+
throw new Error(
|
|
92
|
+
`applesauce-sqlite with a supported SQLite driver is required for persistent Nostr event storage. Bun uses bun:sqlite; Node.js uses better-sqlite3. Install optional dependencies or omit eventStoreDbPath. (${error})`
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
})();
|
|
96
|
+
}
|
|
97
|
+
return this.eventStoreInitPromise;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Get the persistent event store, initializing it if configured.
|
|
101
|
+
* Returns null if no eventStoreDbPath was provided.
|
|
102
|
+
*/
|
|
103
|
+
async getEventStore() {
|
|
104
|
+
return this.ensureEventStore();
|
|
105
|
+
}
|
|
106
|
+
async createPersistentEventDatabase() {
|
|
107
|
+
if (isBunRuntime()) {
|
|
108
|
+
const { BunSqliteEventDatabase } = await import('applesauce-sqlite/bun');
|
|
109
|
+
return new BunSqliteEventDatabase(
|
|
110
|
+
this.eventStoreDbPath
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
const { BetterSqlite3EventDatabase } = await import('applesauce-sqlite/better-sqlite3');
|
|
114
|
+
return new BetterSqlite3EventDatabase(
|
|
115
|
+
this.eventStoreDbPath
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
/** Close the persistent event store database handle, if configured. */
|
|
119
|
+
closeEventStore() {
|
|
120
|
+
this.eventStoreDb?.close?.();
|
|
121
|
+
this.eventStore = null;
|
|
122
|
+
this.eventStoreDb = null;
|
|
123
|
+
this.eventStoreInitPromise = null;
|
|
124
|
+
}
|
|
125
|
+
initializeEventStoreMetadata() {
|
|
126
|
+
this.eventStoreDb?.db?.exec(
|
|
127
|
+
`CREATE TABLE IF NOT EXISTS routstr_event_cache_metadata (
|
|
128
|
+
event_id TEXT PRIMARY KEY,
|
|
129
|
+
fetched_at INTEGER NOT NULL
|
|
130
|
+
)`
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
markEventFetched(event, fetchedAt = Date.now()) {
|
|
134
|
+
const db = this.eventStoreDb?.db;
|
|
135
|
+
if (!db) return;
|
|
136
|
+
db.prepare(
|
|
137
|
+
`INSERT INTO routstr_event_cache_metadata (event_id, fetched_at)
|
|
138
|
+
VALUES (?, ?)
|
|
139
|
+
ON CONFLICT(event_id) DO UPDATE SET fetched_at = excluded.fetched_at`
|
|
140
|
+
).run?.(event.id, fetchedAt);
|
|
141
|
+
}
|
|
142
|
+
getEventFetchedAt(event) {
|
|
143
|
+
const db = this.eventStoreDb?.db;
|
|
144
|
+
if (!db) return void 0;
|
|
145
|
+
const row = db.prepare(
|
|
146
|
+
`SELECT fetched_at FROM routstr_event_cache_metadata WHERE event_id = ?`
|
|
147
|
+
).get?.(event.id);
|
|
148
|
+
return typeof row?.fetched_at === "number" ? row.fetched_at : void 0;
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Check the persistent event store for fresh cached events.
|
|
152
|
+
* Returns events from SQLite if they were fetched within `maxAge`, otherwise
|
|
153
|
+
* returns empty array (caller should hit relays). Events without local fetch
|
|
154
|
+
* metadata fall back to Nostr created_at for backwards compatibility.
|
|
155
|
+
*/
|
|
156
|
+
async getCachedNostrEvents(filter, maxAge, forceRefresh = false) {
|
|
157
|
+
const eventStore = await this.ensureEventStore();
|
|
158
|
+
if (forceRefresh) return [];
|
|
159
|
+
if (!eventStore) return [];
|
|
160
|
+
const timeline = eventStore.getTimeline(filter);
|
|
161
|
+
if (timeline.length === 0) return [];
|
|
162
|
+
const cutoff = Date.now() - maxAge;
|
|
163
|
+
const freshest = Math.max(
|
|
164
|
+
...timeline.map((e) => this.getEventFetchedAt(e) ?? e.created_at * 1e3)
|
|
165
|
+
);
|
|
166
|
+
if (freshest < cutoff) return [];
|
|
167
|
+
return timeline;
|
|
168
|
+
}
|
|
62
169
|
static async init(adapter, config = {}, options = {}) {
|
|
63
170
|
const manager = new _ModelManager(adapter, config);
|
|
64
171
|
const torMode = options.torMode ?? false;
|
|
@@ -87,19 +194,31 @@ var ModelManager = class _ModelManager {
|
|
|
87
194
|
torMode
|
|
88
195
|
);
|
|
89
196
|
await this.fetchRoutstr21Models(forceRefresh);
|
|
90
|
-
await this.syncReviewedProvidersFromNostr(
|
|
197
|
+
await this.syncReviewedProvidersFromNostr(
|
|
198
|
+
filteredCachedUrls,
|
|
199
|
+
this.providerNodePubkeysByUrl,
|
|
200
|
+
forceRefresh
|
|
201
|
+
);
|
|
91
202
|
return filteredCachedUrls;
|
|
92
203
|
}
|
|
93
204
|
}
|
|
94
205
|
}
|
|
95
206
|
try {
|
|
96
|
-
const nostrProviders = await this.bootstrapFromNostr(
|
|
207
|
+
const nostrProviders = await this.bootstrapFromNostr(
|
|
208
|
+
38421,
|
|
209
|
+
torMode,
|
|
210
|
+
forceRefresh
|
|
211
|
+
);
|
|
97
212
|
if (nostrProviders.length > 0) {
|
|
98
213
|
const filtered = this.filterBaseUrlsForTor(nostrProviders, torMode);
|
|
99
214
|
this.adapter.setBaseUrlsList(filtered);
|
|
100
215
|
this.adapter.setBaseUrlsLastUpdate(Date.now());
|
|
101
216
|
await this.fetchRoutstr21Models(forceRefresh);
|
|
102
|
-
await this.syncReviewedProvidersFromNostr(
|
|
217
|
+
await this.syncReviewedProvidersFromNostr(
|
|
218
|
+
filtered,
|
|
219
|
+
this.providerNodePubkeysByUrl,
|
|
220
|
+
forceRefresh
|
|
221
|
+
);
|
|
103
222
|
return filtered;
|
|
104
223
|
}
|
|
105
224
|
} catch (e) {
|
|
@@ -108,42 +227,52 @@ var ModelManager = class _ModelManager {
|
|
|
108
227
|
return this.bootstrapFromHttp(torMode, forceRefresh);
|
|
109
228
|
}
|
|
110
229
|
/**
|
|
111
|
-
* Bootstrap providers from Nostr network (kind
|
|
230
|
+
* Bootstrap providers from Nostr network (kind 38421)
|
|
112
231
|
* @param kind The Nostr kind to fetch
|
|
113
232
|
* @param torMode Whether running in Tor context
|
|
114
233
|
* @returns Array of provider base URLs
|
|
115
234
|
*/
|
|
116
|
-
async bootstrapFromNostr(kind, torMode) {
|
|
235
|
+
async bootstrapFromNostr(kind, torMode, forceRefresh = false) {
|
|
117
236
|
const DEFAULT_RELAYS = [
|
|
118
237
|
"wss://relay.primal.net",
|
|
119
238
|
"wss://nos.lol",
|
|
120
239
|
"wss://relay.damus.io"
|
|
121
240
|
];
|
|
122
|
-
const
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
241
|
+
const cached = await this.getCachedNostrEvents(
|
|
242
|
+
{ kinds: [kind] },
|
|
243
|
+
this.cacheTTL,
|
|
244
|
+
forceRefresh
|
|
245
|
+
);
|
|
246
|
+
let sessionEvents = cached;
|
|
247
|
+
if (cached.length === 0) {
|
|
248
|
+
const pool = new applesauceRelay.RelayPool();
|
|
249
|
+
const timeoutMs = 5e3;
|
|
250
|
+
await new Promise((resolve) => {
|
|
251
|
+
pool.req(DEFAULT_RELAYS, {
|
|
252
|
+
kinds: [kind],
|
|
253
|
+
limit: 100
|
|
254
|
+
}).pipe(
|
|
255
|
+
applesauceRelay.onlyEvents(),
|
|
256
|
+
rxjs.tap((event) => {
|
|
257
|
+
sessionEvents.push(event);
|
|
258
|
+
this.eventStore?.add(event);
|
|
259
|
+
this.markEventFetched(event);
|
|
260
|
+
})
|
|
261
|
+
).subscribe({
|
|
262
|
+
complete: () => {
|
|
263
|
+
resolve();
|
|
264
|
+
}
|
|
265
|
+
});
|
|
266
|
+
setTimeout(() => {
|
|
136
267
|
resolve();
|
|
137
|
-
}
|
|
268
|
+
}, timeoutMs);
|
|
138
269
|
});
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
});
|
|
143
|
-
const timeline = localEventStore.getTimeline({ kinds: [kind] });
|
|
270
|
+
} else {
|
|
271
|
+
this.logger.log(`Using ${cached.length} cached kind ${kind} events from persistent store`);
|
|
272
|
+
}
|
|
144
273
|
const bases = /* @__PURE__ */ new Set();
|
|
145
274
|
this.providerNodePubkeysByUrl = /* @__PURE__ */ new Map();
|
|
146
|
-
for (const event of
|
|
275
|
+
for (const event of sessionEvents) {
|
|
147
276
|
const eventUrls = [];
|
|
148
277
|
for (const tag of event.tags) {
|
|
149
278
|
if (tag[0] === "u" && typeof tag[1] === "string") {
|
|
@@ -251,7 +380,11 @@ var ModelManager = class _ModelManager {
|
|
|
251
380
|
this.adapter.setBaseUrlsList(list);
|
|
252
381
|
this.adapter.setBaseUrlsLastUpdate(Date.now());
|
|
253
382
|
await this.fetchRoutstr21Models(forceRefresh);
|
|
254
|
-
await this.syncReviewedProvidersFromNostr(
|
|
383
|
+
await this.syncReviewedProvidersFromNostr(
|
|
384
|
+
list,
|
|
385
|
+
this.providerNodePubkeysByUrl,
|
|
386
|
+
forceRefresh
|
|
387
|
+
);
|
|
255
388
|
}
|
|
256
389
|
return list;
|
|
257
390
|
} catch (e) {
|
|
@@ -270,7 +403,7 @@ var ModelManager = class _ModelManager {
|
|
|
270
403
|
* @param baseUrls Current provider base URLs to evaluate
|
|
271
404
|
* @returns Array of provider base URLs disabled by the review set
|
|
272
405
|
*/
|
|
273
|
-
async syncReviewedProvidersFromNostr(baseUrls = this.adapter.getBaseUrlsList(), providerNodes = this.providerNodePubkeysByUrl) {
|
|
406
|
+
async syncReviewedProvidersFromNostr(baseUrls = this.adapter.getBaseUrlsList(), providerNodes = this.providerNodePubkeysByUrl, forceRefresh = false) {
|
|
274
407
|
if (baseUrls.length === 0) return [];
|
|
275
408
|
if (!this.adapter.setDisabledProviders) {
|
|
276
409
|
this.logger.warn(
|
|
@@ -278,30 +411,43 @@ var ModelManager = class _ModelManager {
|
|
|
278
411
|
);
|
|
279
412
|
return [];
|
|
280
413
|
}
|
|
281
|
-
const LGTM_RELAYS = [
|
|
282
|
-
"wss://relay.primal.net",
|
|
283
|
-
"wss://nos.lol",
|
|
284
|
-
"wss://relay.damus.io",
|
|
285
|
-
"wss://relay.routstr.com"
|
|
286
|
-
];
|
|
287
414
|
const reviewedNodePubkeys = /* @__PURE__ */ new Set();
|
|
288
415
|
{
|
|
289
|
-
const
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
416
|
+
const cached = await this.getCachedNostrEvents(
|
|
417
|
+
{ kinds: [38425], "#t": ["lgtm"], authors: [this.routstrPubkey] },
|
|
418
|
+
this.cacheTTL,
|
|
419
|
+
forceRefresh
|
|
420
|
+
);
|
|
421
|
+
let sessionEvents = cached;
|
|
422
|
+
if (cached.length === 0) {
|
|
423
|
+
const LGTM_RELAYS = [
|
|
424
|
+
"wss://relay.primal.net",
|
|
425
|
+
"wss://nos.lol",
|
|
426
|
+
"wss://relay.damus.io",
|
|
427
|
+
"wss://relay.routstr.com"
|
|
428
|
+
];
|
|
429
|
+
const pool = new applesauceRelay.RelayPool();
|
|
430
|
+
const timeoutMs = 5e3;
|
|
431
|
+
await new Promise((resolve) => {
|
|
432
|
+
pool.req(LGTM_RELAYS, {
|
|
433
|
+
kinds: [38425],
|
|
434
|
+
"#t": ["lgtm"],
|
|
435
|
+
limit: 500,
|
|
436
|
+
authors: [this.routstrPubkey]
|
|
437
|
+
}).pipe(
|
|
438
|
+
applesauceRelay.onlyEvents(),
|
|
439
|
+
rxjs.tap((event) => {
|
|
440
|
+
sessionEvents.push(event);
|
|
441
|
+
this.eventStore?.add(event);
|
|
442
|
+
this.markEventFetched(event);
|
|
443
|
+
})
|
|
444
|
+
).subscribe({ complete: () => resolve() });
|
|
445
|
+
setTimeout(() => resolve(), timeoutMs);
|
|
446
|
+
});
|
|
447
|
+
} else {
|
|
448
|
+
this.logger.log(`Using ${cached.length} cached kind 38425 events from persistent store`);
|
|
449
|
+
}
|
|
450
|
+
for (const event of sessionEvents) {
|
|
305
451
|
const hasLgtmTag = event.tags.some(
|
|
306
452
|
(tag) => tag[0] === "t" && tag[1]?.toLowerCase() === "lgtm"
|
|
307
453
|
);
|
|
@@ -410,7 +556,7 @@ var ModelManager = class _ModelManager {
|
|
|
410
556
|
if (this.isProviderDownError(error)) {
|
|
411
557
|
this.logger.warn(`Provider ${base} is down right now.`);
|
|
412
558
|
} else {
|
|
413
|
-
this.logger.warn(`
|
|
559
|
+
this.logger.warn(`Provider ${base} unreachable: ${error.message}`);
|
|
414
560
|
}
|
|
415
561
|
this.adapter.setProviderLastUpdate(base, Date.now());
|
|
416
562
|
return { success: false, base };
|
|
@@ -530,34 +676,44 @@ var ModelManager = class _ModelManager {
|
|
|
530
676
|
"wss://nos.lol",
|
|
531
677
|
"wss://relay.routstr.com"
|
|
532
678
|
];
|
|
533
|
-
const
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
679
|
+
const cached = await this.getCachedNostrEvents(
|
|
680
|
+
{ kinds: [38423], "#d": ["routstr-21-models"], authors: [this.routstrPubkey] },
|
|
681
|
+
this.cacheTTL,
|
|
682
|
+
forceRefresh
|
|
683
|
+
);
|
|
684
|
+
let sessionEvents = cached;
|
|
685
|
+
if (cached.length === 0) {
|
|
686
|
+
const pool = new applesauceRelay.RelayPool();
|
|
687
|
+
const timeoutMs = 5e3;
|
|
688
|
+
await new Promise((resolve) => {
|
|
689
|
+
pool.req(DEFAULT_RELAYS, {
|
|
690
|
+
kinds: [38423],
|
|
691
|
+
"#d": ["routstr-21-models"],
|
|
692
|
+
limit: 1,
|
|
693
|
+
authors: [this.routstrPubkey]
|
|
694
|
+
}).pipe(
|
|
695
|
+
applesauceRelay.onlyEvents(),
|
|
696
|
+
rxjs.tap((event2) => {
|
|
697
|
+
sessionEvents.push(event2);
|
|
698
|
+
this.eventStore?.add(event2);
|
|
699
|
+
this.markEventFetched(event2);
|
|
700
|
+
})
|
|
701
|
+
).subscribe({
|
|
702
|
+
complete: () => {
|
|
703
|
+
resolve();
|
|
704
|
+
}
|
|
705
|
+
});
|
|
706
|
+
setTimeout(() => {
|
|
549
707
|
resolve();
|
|
550
|
-
}
|
|
708
|
+
}, timeoutMs);
|
|
551
709
|
});
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
const timeline = localEventStore.getTimeline({ kinds: [38423] });
|
|
557
|
-
if (timeline.length === 0) {
|
|
710
|
+
} else {
|
|
711
|
+
this.logger.log(`Using ${cached.length} cached kind 38423 events from persistent store`);
|
|
712
|
+
}
|
|
713
|
+
if (sessionEvents.length === 0) {
|
|
558
714
|
return cachedModels.length > 0 ? cachedModels : [];
|
|
559
715
|
}
|
|
560
|
-
const event =
|
|
716
|
+
const event = sessionEvents[0];
|
|
561
717
|
try {
|
|
562
718
|
const content = JSON.parse(event.content);
|
|
563
719
|
const models = Array.isArray(content?.models) ? content.models : [];
|