@elisym/sdk 0.11.0 → 0.12.0
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/index.cjs +247 -79
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +40 -1
- package/dist/index.d.ts +40 -1
- package/dist/index.js +247 -79
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1032,6 +1032,7 @@ async function createPaymentRequestWithOnchainConfig(rpc, programId, recipient,
|
|
|
1032
1032
|
var RANKING_ACTIVITY_WINDOW_SECS = 30 * 24 * 60 * 60;
|
|
1033
1033
|
var RANKING_BUCKET_SIZE_SECS = 60;
|
|
1034
1034
|
var COLD_START_BUCKET = -Infinity;
|
|
1035
|
+
var NEVER_ABORTED_SIGNAL = new AbortController().signal;
|
|
1035
1036
|
function toDTag(name) {
|
|
1036
1037
|
const tag = name.toLowerCase().replace(/[^a-z0-9\s-]/g, (ch) => "_" + ch.charCodeAt(0).toString(16).padStart(2, "0")).replace(/\s+/g, "-").replace(/^-+|-+$/g, "");
|
|
1037
1038
|
if (!tag) {
|
|
@@ -1061,13 +1062,63 @@ function compareAgentsByRank(a, b) {
|
|
|
1061
1062
|
}
|
|
1062
1063
|
return kb.lastSeen - ka.lastSeen;
|
|
1063
1064
|
}
|
|
1065
|
+
function parseCapabilityEvent(event, network) {
|
|
1066
|
+
if (!nostrTools.verifyEvent(event)) {
|
|
1067
|
+
return null;
|
|
1068
|
+
}
|
|
1069
|
+
if (!event.content) {
|
|
1070
|
+
return null;
|
|
1071
|
+
}
|
|
1072
|
+
let raw;
|
|
1073
|
+
try {
|
|
1074
|
+
raw = JSON.parse(event.content);
|
|
1075
|
+
} catch {
|
|
1076
|
+
return null;
|
|
1077
|
+
}
|
|
1078
|
+
if (!raw || typeof raw !== "object") {
|
|
1079
|
+
return null;
|
|
1080
|
+
}
|
|
1081
|
+
const candidate = raw;
|
|
1082
|
+
if (typeof candidate.name !== "string" || !candidate.name) {
|
|
1083
|
+
return null;
|
|
1084
|
+
}
|
|
1085
|
+
if (typeof candidate.description !== "string") {
|
|
1086
|
+
return null;
|
|
1087
|
+
}
|
|
1088
|
+
if (!Array.isArray(candidate.capabilities) || !candidate.capabilities.every((cap) => typeof cap === "string")) {
|
|
1089
|
+
return null;
|
|
1090
|
+
}
|
|
1091
|
+
if (candidate.deleted) {
|
|
1092
|
+
return null;
|
|
1093
|
+
}
|
|
1094
|
+
const card = candidate;
|
|
1095
|
+
if (card.payment && (typeof card.payment.chain !== "string" || typeof card.payment.network !== "string" || typeof card.payment.address !== "string")) {
|
|
1096
|
+
return null;
|
|
1097
|
+
}
|
|
1098
|
+
if (card.payment?.job_price !== null && card.payment?.job_price !== void 0 && (!Number.isInteger(card.payment.job_price) || card.payment.job_price < 0)) {
|
|
1099
|
+
return null;
|
|
1100
|
+
}
|
|
1101
|
+
const agentNetwork = card.payment?.network ?? "devnet";
|
|
1102
|
+
if (agentNetwork !== network) {
|
|
1103
|
+
return null;
|
|
1104
|
+
}
|
|
1105
|
+
const kTags = event.tags.filter((tag) => tag[0] === "k").map((tag) => parseInt(tag[1] ?? "", 10)).filter((kind) => !isNaN(kind));
|
|
1106
|
+
return {
|
|
1107
|
+
pubkey: event.pubkey,
|
|
1108
|
+
npub: nostrTools.nip19.npubEncode(event.pubkey),
|
|
1109
|
+
cards: [card],
|
|
1110
|
+
eventId: event.id,
|
|
1111
|
+
supportedKinds: kTags,
|
|
1112
|
+
lastSeen: event.created_at
|
|
1113
|
+
};
|
|
1114
|
+
}
|
|
1064
1115
|
function buildAgentsFromEvents(events, network) {
|
|
1065
1116
|
const latestByDTag = /* @__PURE__ */ new Map();
|
|
1066
1117
|
for (const event of events) {
|
|
1067
1118
|
if (!nostrTools.verifyEvent(event)) {
|
|
1068
1119
|
continue;
|
|
1069
1120
|
}
|
|
1070
|
-
const dTag = event.tags.find((
|
|
1121
|
+
const dTag = event.tags.find((tag) => tag[0] === "d")?.[1] ?? "";
|
|
1071
1122
|
const key = `${event.pubkey}:${dTag}`;
|
|
1072
1123
|
const prev = latestByDTag.get(key);
|
|
1073
1124
|
if (!prev || event.created_at > prev.created_at) {
|
|
@@ -1076,82 +1127,51 @@ function buildAgentsFromEvents(events, network) {
|
|
|
1076
1127
|
}
|
|
1077
1128
|
const accumMap = /* @__PURE__ */ new Map();
|
|
1078
1129
|
for (const event of latestByDTag.values()) {
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
if (raw.deleted) {
|
|
1097
|
-
continue;
|
|
1098
|
-
}
|
|
1099
|
-
const card = raw;
|
|
1100
|
-
if (card.payment && (typeof card.payment.chain !== "string" || typeof card.payment.network !== "string" || typeof card.payment.address !== "string")) {
|
|
1101
|
-
continue;
|
|
1102
|
-
}
|
|
1103
|
-
if (card.payment?.job_price !== null && card.payment?.job_price !== void 0 && (!Number.isInteger(card.payment.job_price) || card.payment.job_price < 0)) {
|
|
1104
|
-
continue;
|
|
1105
|
-
}
|
|
1106
|
-
const agentNetwork = card.payment?.network ?? "devnet";
|
|
1107
|
-
if (agentNetwork !== network) {
|
|
1108
|
-
continue;
|
|
1109
|
-
}
|
|
1110
|
-
const kTags = event.tags.filter((t) => t[0] === "k").map((t) => parseInt(t[1] ?? "", 10)).filter((k) => !isNaN(k));
|
|
1111
|
-
const entry = { card, kTags, createdAt: event.created_at };
|
|
1112
|
-
const existing = accumMap.get(event.pubkey);
|
|
1113
|
-
if (existing) {
|
|
1114
|
-
const dupIndex = existing.entries.findIndex((e) => e.card.name === card.name);
|
|
1115
|
-
if (dupIndex >= 0) {
|
|
1116
|
-
if (entry.createdAt >= existing.entries[dupIndex].createdAt) {
|
|
1117
|
-
existing.entries[dupIndex] = entry;
|
|
1130
|
+
const parsed = parseCapabilityEvent(event, network);
|
|
1131
|
+
if (!parsed) {
|
|
1132
|
+
continue;
|
|
1133
|
+
}
|
|
1134
|
+
const card = parsed.cards[0];
|
|
1135
|
+
const cardKinds = parsed.supportedKinds;
|
|
1136
|
+
const createdAt = parsed.lastSeen;
|
|
1137
|
+
const existing = accumMap.get(parsed.pubkey);
|
|
1138
|
+
if (existing) {
|
|
1139
|
+
const prevForName = existing.perCard.get(card.name);
|
|
1140
|
+
if (prevForName) {
|
|
1141
|
+
if (createdAt >= prevForName.createdAt) {
|
|
1142
|
+
const idx = existing.agent.cards.findIndex(
|
|
1143
|
+
(existingCard) => existingCard.name === card.name
|
|
1144
|
+
);
|
|
1145
|
+
if (idx >= 0) {
|
|
1146
|
+
existing.agent.cards[idx] = card;
|
|
1118
1147
|
}
|
|
1119
|
-
|
|
1120
|
-
existing.entries.push(entry);
|
|
1121
|
-
}
|
|
1122
|
-
if (event.created_at > existing.lastSeen) {
|
|
1123
|
-
existing.lastSeen = event.created_at;
|
|
1124
|
-
existing.eventId = event.id;
|
|
1148
|
+
existing.perCard.set(card.name, { createdAt, kTags: cardKinds });
|
|
1125
1149
|
}
|
|
1126
1150
|
} else {
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
npub: nostrTools.nip19.npubEncode(event.pubkey),
|
|
1130
|
-
entries: [entry],
|
|
1131
|
-
eventId: event.id,
|
|
1132
|
-
lastSeen: event.created_at
|
|
1133
|
-
});
|
|
1151
|
+
existing.agent.cards.push(card);
|
|
1152
|
+
existing.perCard.set(card.name, { createdAt, kTags: cardKinds });
|
|
1134
1153
|
}
|
|
1135
|
-
|
|
1154
|
+
if (createdAt > existing.agent.lastSeen) {
|
|
1155
|
+
existing.agent.lastSeen = createdAt;
|
|
1156
|
+
existing.agent.eventId = parsed.eventId;
|
|
1157
|
+
}
|
|
1158
|
+
} else {
|
|
1159
|
+
accumMap.set(parsed.pubkey, {
|
|
1160
|
+
agent: parsed,
|
|
1161
|
+
perCard: /* @__PURE__ */ new Map([[card.name, { createdAt, kTags: cardKinds }]])
|
|
1162
|
+
});
|
|
1136
1163
|
}
|
|
1137
1164
|
}
|
|
1138
1165
|
const agentMap = /* @__PURE__ */ new Map();
|
|
1139
1166
|
for (const [pubkey, acc] of accumMap) {
|
|
1140
1167
|
const kindsSet = /* @__PURE__ */ new Set();
|
|
1141
|
-
for (const
|
|
1142
|
-
for (const
|
|
1143
|
-
kindsSet.add(
|
|
1144
|
-
}
|
|
1145
|
-
}
|
|
1146
|
-
|
|
1147
|
-
agentMap.set(pubkey,
|
|
1148
|
-
pubkey: acc.pubkey,
|
|
1149
|
-
npub: acc.npub,
|
|
1150
|
-
cards: acc.entries.map((e) => e.card),
|
|
1151
|
-
eventId: acc.eventId,
|
|
1152
|
-
supportedKinds,
|
|
1153
|
-
lastSeen: acc.lastSeen
|
|
1154
|
-
});
|
|
1168
|
+
for (const { kTags } of acc.perCard.values()) {
|
|
1169
|
+
for (const kind of kTags) {
|
|
1170
|
+
kindsSet.add(kind);
|
|
1171
|
+
}
|
|
1172
|
+
}
|
|
1173
|
+
acc.agent.supportedKinds = [...kindsSet];
|
|
1174
|
+
agentMap.set(pubkey, acc.agent);
|
|
1155
1175
|
}
|
|
1156
1176
|
return agentMap;
|
|
1157
1177
|
}
|
|
@@ -1266,6 +1286,19 @@ var DiscoveryService = class {
|
|
|
1266
1286
|
const events = await this.pool.querySync(filter);
|
|
1267
1287
|
const agentMap = buildAgentsFromEvents(events, network);
|
|
1268
1288
|
const agents = Array.from(agentMap.values());
|
|
1289
|
+
return this.runEnrichment(agents, agentMap, NEVER_ABORTED_SIGNAL);
|
|
1290
|
+
}
|
|
1291
|
+
/**
|
|
1292
|
+
* Enrich an agent map with paid-job stats, feedback counters, and kind:0
|
|
1293
|
+
* metadata, then return them sorted by `compareAgentsByRank`. Mutates the
|
|
1294
|
+
* passed-in `Agent` objects in place.
|
|
1295
|
+
*
|
|
1296
|
+
* Shared between `fetchAgents` (one-shot) and `streamAgents` (post-EOSE
|
|
1297
|
+
* second pass). The `signal` short-circuits the post-query work; in-flight
|
|
1298
|
+
* pool queries are not cancellable today (they fall through to the standard
|
|
1299
|
+
* timeout) and the caller drops the resolved value.
|
|
1300
|
+
*/
|
|
1301
|
+
async runEnrichment(agents, agentMap, signal) {
|
|
1269
1302
|
const agentPubkeys = Array.from(agentMap.keys());
|
|
1270
1303
|
if (agentPubkeys.length === 0) {
|
|
1271
1304
|
return agents;
|
|
@@ -1273,9 +1306,9 @@ var DiscoveryService = class {
|
|
|
1273
1306
|
const activitySince = Math.floor(Date.now() / 1e3) - RANKING_ACTIVITY_WINDOW_SECS;
|
|
1274
1307
|
const resultKinds = /* @__PURE__ */ new Set();
|
|
1275
1308
|
for (const agent of agentMap.values()) {
|
|
1276
|
-
for (const
|
|
1277
|
-
if (
|
|
1278
|
-
resultKinds.add(KIND_JOB_RESULT_BASE + (
|
|
1309
|
+
for (const supportedKind of agent.supportedKinds) {
|
|
1310
|
+
if (supportedKind >= KIND_JOB_REQUEST_BASE && supportedKind < KIND_JOB_RESULT_BASE) {
|
|
1311
|
+
resultKinds.add(KIND_JOB_RESULT_BASE + (supportedKind - KIND_JOB_REQUEST_BASE));
|
|
1279
1312
|
}
|
|
1280
1313
|
}
|
|
1281
1314
|
}
|
|
@@ -1295,6 +1328,9 @@ var DiscoveryService = class {
|
|
|
1295
1328
|
),
|
|
1296
1329
|
this.enrichWithMetadata(agents)
|
|
1297
1330
|
]);
|
|
1331
|
+
if (signal.aborted) {
|
|
1332
|
+
return agents;
|
|
1333
|
+
}
|
|
1298
1334
|
const deliveredJobsByProvider = /* @__PURE__ */ new Map();
|
|
1299
1335
|
for (const ev of resultEvents) {
|
|
1300
1336
|
if (!nostrTools.verifyEvent(ev)) {
|
|
@@ -1307,7 +1343,7 @@ var DiscoveryService = class {
|
|
|
1307
1343
|
if (ev.created_at > agent.lastSeen) {
|
|
1308
1344
|
agent.lastSeen = ev.created_at;
|
|
1309
1345
|
}
|
|
1310
|
-
const jobEventId = ev.tags.find((
|
|
1346
|
+
const jobEventId = ev.tags.find((tag) => tag[0] === "e")?.[1];
|
|
1311
1347
|
if (jobEventId) {
|
|
1312
1348
|
let delivered = deliveredJobsByProvider.get(ev.pubkey);
|
|
1313
1349
|
if (!delivered) {
|
|
@@ -1321,7 +1357,7 @@ var DiscoveryService = class {
|
|
|
1321
1357
|
if (!nostrTools.verifyEvent(ev)) {
|
|
1322
1358
|
continue;
|
|
1323
1359
|
}
|
|
1324
|
-
const targetPubkey = ev.tags.find((
|
|
1360
|
+
const targetPubkey = ev.tags.find((tag) => tag[0] === "p")?.[1];
|
|
1325
1361
|
if (!targetPubkey) {
|
|
1326
1362
|
continue;
|
|
1327
1363
|
}
|
|
@@ -1332,17 +1368,17 @@ var DiscoveryService = class {
|
|
|
1332
1368
|
if (ev.created_at > agent.lastSeen) {
|
|
1333
1369
|
agent.lastSeen = ev.created_at;
|
|
1334
1370
|
}
|
|
1335
|
-
const rating = ev.tags.find((
|
|
1371
|
+
const rating = ev.tags.find((tag) => tag[0] === "rating")?.[1];
|
|
1336
1372
|
if (rating === "1" || rating === "0") {
|
|
1337
1373
|
agent.totalRatingCount = (agent.totalRatingCount ?? 0) + 1;
|
|
1338
1374
|
if (rating === "1") {
|
|
1339
1375
|
agent.positiveCount = (agent.positiveCount ?? 0) + 1;
|
|
1340
1376
|
}
|
|
1341
1377
|
}
|
|
1342
|
-
const status = ev.tags.find((
|
|
1343
|
-
const txTag = ev.tags.find((
|
|
1378
|
+
const status = ev.tags.find((tag) => tag[0] === "status")?.[1];
|
|
1379
|
+
const txTag = ev.tags.find((tag) => tag[0] === "tx");
|
|
1344
1380
|
const txSignature = txTag?.[1];
|
|
1345
|
-
const jobEventId = ev.tags.find((
|
|
1381
|
+
const jobEventId = ev.tags.find((tag) => tag[0] === "e")?.[1];
|
|
1346
1382
|
const hasDeliveredResult = jobEventId !== void 0 && deliveredJobsByProvider.get(targetPubkey)?.has(jobEventId) === true;
|
|
1347
1383
|
if (status === "payment-completed" && typeof txSignature === "string" && txSignature && hasDeliveredResult) {
|
|
1348
1384
|
if (!agent.lastPaidJobAt || ev.created_at > agent.lastPaidJobAt) {
|
|
@@ -1354,6 +1390,135 @@ var DiscoveryService = class {
|
|
|
1354
1390
|
agents.sort(compareAgentsByRank);
|
|
1355
1391
|
return agents;
|
|
1356
1392
|
}
|
|
1393
|
+
/**
|
|
1394
|
+
* Stream elisym agents progressively as relays deliver events.
|
|
1395
|
+
*
|
|
1396
|
+
* Two live subscriptions:
|
|
1397
|
+
* - kind:31990 (capability cards) - emits `onAgent(agent)` for every new or
|
|
1398
|
+
* updated `(pubkey, d-tag)`. The emitted Agent is the merged view across
|
|
1399
|
+
* all surviving cards for that author.
|
|
1400
|
+
* - kind:6100 (default-offset job results) tagged `t=elisym` since 30d ago -
|
|
1401
|
+
* emits `onPaidJob(pubkey, ts)` for each delivered result. Custom-kind
|
|
1402
|
+
* results (offset != 100) are not on this stream; they enter the final
|
|
1403
|
+
* ranking via the post-EOSE enrichment pass.
|
|
1404
|
+
*
|
|
1405
|
+
* After capabilities EOSE, an enrichment pass runs in parallel to the live
|
|
1406
|
+
* subscriptions and produces a ranked snapshot via `onComplete`. The snapshot
|
|
1407
|
+
* is a clone, so further live updates do not mutate it.
|
|
1408
|
+
*
|
|
1409
|
+
* `closer.close()` tears down both subscriptions and aborts an in-flight
|
|
1410
|
+
* enrichment. If `opts.signal` is provided, aborting it does the same.
|
|
1411
|
+
*/
|
|
1412
|
+
streamAgents(network, opts) {
|
|
1413
|
+
const eventsByPubkey = /* @__PURE__ */ new Map();
|
|
1414
|
+
const agentByPubkey = /* @__PURE__ */ new Map();
|
|
1415
|
+
const eoseSeen = { caps: false, results: false };
|
|
1416
|
+
let enrichmentStarted = false;
|
|
1417
|
+
const enrichmentAbort = new AbortController();
|
|
1418
|
+
const onExternalAbort = () => enrichmentAbort.abort();
|
|
1419
|
+
if (opts.signal) {
|
|
1420
|
+
if (opts.signal.aborted) {
|
|
1421
|
+
enrichmentAbort.abort();
|
|
1422
|
+
} else {
|
|
1423
|
+
opts.signal.addEventListener("abort", onExternalAbort, { once: true });
|
|
1424
|
+
}
|
|
1425
|
+
}
|
|
1426
|
+
const checkEose = () => {
|
|
1427
|
+
if (eoseSeen.caps && eoseSeen.results) {
|
|
1428
|
+
opts.onEose?.();
|
|
1429
|
+
}
|
|
1430
|
+
};
|
|
1431
|
+
const startEnrichment = () => {
|
|
1432
|
+
if (enrichmentStarted) {
|
|
1433
|
+
return;
|
|
1434
|
+
}
|
|
1435
|
+
enrichmentStarted = true;
|
|
1436
|
+
const snapshotAgents = Array.from(agentByPubkey.values()).map((agent) => ({ ...agent }));
|
|
1437
|
+
const snapshotMap = new Map(snapshotAgents.map((agent) => [agent.pubkey, agent]));
|
|
1438
|
+
void this.runEnrichment(snapshotAgents, snapshotMap, enrichmentAbort.signal).then(
|
|
1439
|
+
(sorted) => {
|
|
1440
|
+
if (enrichmentAbort.signal.aborted) {
|
|
1441
|
+
return;
|
|
1442
|
+
}
|
|
1443
|
+
opts.onComplete?.(sorted);
|
|
1444
|
+
},
|
|
1445
|
+
() => {
|
|
1446
|
+
}
|
|
1447
|
+
);
|
|
1448
|
+
};
|
|
1449
|
+
const capSub = this.pool.subscribe(
|
|
1450
|
+
{ kinds: [KIND_APP_HANDLER], "#t": ["elisym"] },
|
|
1451
|
+
(event) => {
|
|
1452
|
+
const dTag = event.tags.find((tag) => tag[0] === "d")?.[1] ?? "";
|
|
1453
|
+
let perDTag = eventsByPubkey.get(event.pubkey);
|
|
1454
|
+
const prev = perDTag?.get(dTag);
|
|
1455
|
+
if (prev && event.created_at <= prev.created_at) {
|
|
1456
|
+
return;
|
|
1457
|
+
}
|
|
1458
|
+
if (!nostrTools.verifyEvent(event)) {
|
|
1459
|
+
return;
|
|
1460
|
+
}
|
|
1461
|
+
if (!event.content) {
|
|
1462
|
+
return;
|
|
1463
|
+
}
|
|
1464
|
+
let payload;
|
|
1465
|
+
try {
|
|
1466
|
+
payload = JSON.parse(event.content);
|
|
1467
|
+
} catch {
|
|
1468
|
+
return;
|
|
1469
|
+
}
|
|
1470
|
+
const isTombstone = payload !== null && typeof payload === "object" && Boolean(payload.deleted);
|
|
1471
|
+
if (!isTombstone && !parseCapabilityEvent(event, network)) {
|
|
1472
|
+
return;
|
|
1473
|
+
}
|
|
1474
|
+
if (!perDTag) {
|
|
1475
|
+
perDTag = /* @__PURE__ */ new Map();
|
|
1476
|
+
eventsByPubkey.set(event.pubkey, perDTag);
|
|
1477
|
+
}
|
|
1478
|
+
perDTag.set(dTag, event);
|
|
1479
|
+
const merged = buildAgentsFromEvents(Array.from(perDTag.values()), network).get(
|
|
1480
|
+
event.pubkey
|
|
1481
|
+
);
|
|
1482
|
+
if (!merged) {
|
|
1483
|
+
agentByPubkey.delete(event.pubkey);
|
|
1484
|
+
return;
|
|
1485
|
+
}
|
|
1486
|
+
agentByPubkey.set(event.pubkey, merged);
|
|
1487
|
+
opts.onAgent(merged);
|
|
1488
|
+
},
|
|
1489
|
+
{
|
|
1490
|
+
oneose: () => {
|
|
1491
|
+
eoseSeen.caps = true;
|
|
1492
|
+
startEnrichment();
|
|
1493
|
+
checkEose();
|
|
1494
|
+
}
|
|
1495
|
+
}
|
|
1496
|
+
);
|
|
1497
|
+
const activitySince = Math.floor(Date.now() / 1e3) - RANKING_ACTIVITY_WINDOW_SECS;
|
|
1498
|
+
const resultsSub = this.pool.subscribe(
|
|
1499
|
+
{ kinds: [KIND_JOB_RESULT], "#t": ["elisym"], since: activitySince },
|
|
1500
|
+
(event) => {
|
|
1501
|
+
if (!nostrTools.verifyEvent(event)) {
|
|
1502
|
+
return;
|
|
1503
|
+
}
|
|
1504
|
+
opts.onPaidJob?.(event.pubkey, event.created_at);
|
|
1505
|
+
},
|
|
1506
|
+
{
|
|
1507
|
+
oneose: () => {
|
|
1508
|
+
eoseSeen.results = true;
|
|
1509
|
+
checkEose();
|
|
1510
|
+
}
|
|
1511
|
+
}
|
|
1512
|
+
);
|
|
1513
|
+
return {
|
|
1514
|
+
close: (reason) => {
|
|
1515
|
+
capSub.close(reason);
|
|
1516
|
+
resultsSub.close(reason);
|
|
1517
|
+
enrichmentAbort.abort();
|
|
1518
|
+
opts.signal?.removeEventListener("abort", onExternalAbort);
|
|
1519
|
+
}
|
|
1520
|
+
};
|
|
1521
|
+
}
|
|
1357
1522
|
/**
|
|
1358
1523
|
* Publish a capability card (kind:31990) as a provider.
|
|
1359
1524
|
* Solana address is validated for Base58 format only - full decode
|
|
@@ -2569,8 +2734,11 @@ var NostrPool = class {
|
|
|
2569
2734
|
throw new Error(`Failed to publish to all ${this.relays.length} relays`);
|
|
2570
2735
|
}
|
|
2571
2736
|
}
|
|
2572
|
-
subscribe(filter, onEvent) {
|
|
2573
|
-
const rawSub = this.pool.subscribeMany(this.relays, filter, {
|
|
2737
|
+
subscribe(filter, onEvent, opts) {
|
|
2738
|
+
const rawSub = this.pool.subscribeMany(this.relays, filter, {
|
|
2739
|
+
onevent: onEvent,
|
|
2740
|
+
oneose: opts?.oneose
|
|
2741
|
+
});
|
|
2574
2742
|
const tracked = {
|
|
2575
2743
|
close: (reason) => {
|
|
2576
2744
|
this.activeSubscriptions.delete(tracked);
|