@elisym/sdk 0.10.2 → 0.10.4

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.d.cts CHANGED
@@ -73,6 +73,7 @@ interface Agent {
73
73
  /** Count of all rated feedback events targeting this agent (last 30 days). */
74
74
  totalRatingCount?: number;
75
75
  picture?: string;
76
+ banner?: string;
76
77
  name?: string;
77
78
  about?: string;
78
79
  }
@@ -380,18 +381,20 @@ declare class DiscoveryService {
380
381
  *
381
382
  * Ranking algorithm:
382
383
  * 1. Bucket each agent into 1-minute slots by `lastPaidJobAt` (newest
383
- * `payment-completed` feedback timestamp). Cold-start agents go into a
384
- * sentinel bucket below all populated buckets.
384
+ * `payment-completed` feedback timestamp, gated by a matching kind:6xxx
385
+ * result from the provider on the same job event). Cold-start agents go
386
+ * into a sentinel bucket below all populated buckets.
385
387
  * 2. Within a bucket, sort by positive review rate descending.
386
388
  * 3. Tiebreak by raw `lastPaidJobAt`, then `lastSeen` (NIP-89 freshness).
387
389
  *
388
- * NOTE: We trust the `payment-completed` feedback timestamp directly; we do
389
- * not verify the embedded `tx` signature on-chain. Public Solana devnet RPC
390
- * rate-limits trivially exceed what discovery needs (N agents * up-to-5
391
- * candidates), and the resulting 429s blocked discovery entirely. This
392
- * means a malicious customer can publish a fake `payment-completed` to lift
393
- * an agent's ranking. Acceptable trade-off for devnet / MVP; tighten via
394
- * recipient-tied checks when the network moves to mainnet with a paid RPC
390
+ * NOTE: We do not verify the `tx` signature on-chain - public Solana devnet
391
+ * RPC rate-limits trivially exceed what discovery needs (N agents * up-to-5
392
+ * candidates), and the resulting 429s blocked discovery entirely. As a
393
+ * lighter sybil mitigation we cross-check `payment-completed` feedback
394
+ * against a kind:6xxx result event authored by the provider on the same
395
+ * job: a customer can publish a fake `payment-completed`, but they cannot
396
+ * forge a result event signed by the provider. Tighten with recipient-tied
397
+ * on-chain checks when the network moves to mainnet with a paid RPC
395
398
  * provider.
396
399
  */
397
400
  fetchAgents(network?: Network, limit?: number): Promise<Agent[]>;
package/dist/index.d.ts CHANGED
@@ -73,6 +73,7 @@ interface Agent {
73
73
  /** Count of all rated feedback events targeting this agent (last 30 days). */
74
74
  totalRatingCount?: number;
75
75
  picture?: string;
76
+ banner?: string;
76
77
  name?: string;
77
78
  about?: string;
78
79
  }
@@ -380,18 +381,20 @@ declare class DiscoveryService {
380
381
  *
381
382
  * Ranking algorithm:
382
383
  * 1. Bucket each agent into 1-minute slots by `lastPaidJobAt` (newest
383
- * `payment-completed` feedback timestamp). Cold-start agents go into a
384
- * sentinel bucket below all populated buckets.
384
+ * `payment-completed` feedback timestamp, gated by a matching kind:6xxx
385
+ * result from the provider on the same job event). Cold-start agents go
386
+ * into a sentinel bucket below all populated buckets.
385
387
  * 2. Within a bucket, sort by positive review rate descending.
386
388
  * 3. Tiebreak by raw `lastPaidJobAt`, then `lastSeen` (NIP-89 freshness).
387
389
  *
388
- * NOTE: We trust the `payment-completed` feedback timestamp directly; we do
389
- * not verify the embedded `tx` signature on-chain. Public Solana devnet RPC
390
- * rate-limits trivially exceed what discovery needs (N agents * up-to-5
391
- * candidates), and the resulting 429s blocked discovery entirely. This
392
- * means a malicious customer can publish a fake `payment-completed` to lift
393
- * an agent's ranking. Acceptable trade-off for devnet / MVP; tighten via
394
- * recipient-tied checks when the network moves to mainnet with a paid RPC
390
+ * NOTE: We do not verify the `tx` signature on-chain - public Solana devnet
391
+ * RPC rate-limits trivially exceed what discovery needs (N agents * up-to-5
392
+ * candidates), and the resulting 429s blocked discovery entirely. As a
393
+ * lighter sybil mitigation we cross-check `payment-completed` feedback
394
+ * against a kind:6xxx result event authored by the provider on the same
395
+ * job: a customer can publish a fake `payment-completed`, but they cannot
396
+ * forge a result event signed by the provider. Tighten with recipient-tied
397
+ * on-chain checks when the network moves to mainnet with a paid RPC
395
398
  * provider.
396
399
  */
397
400
  fetchAgents(network?: Network, limit?: number): Promise<Agent[]>;
package/dist/index.js CHANGED
@@ -1191,6 +1191,9 @@ var DiscoveryService = class {
1191
1191
  if (typeof meta.picture === "string") {
1192
1192
  agent.picture = meta.picture;
1193
1193
  }
1194
+ if (typeof meta.banner === "string") {
1195
+ agent.banner = meta.banner;
1196
+ }
1194
1197
  if (typeof meta.name === "string") {
1195
1198
  agent.name = meta.name;
1196
1199
  }
@@ -1208,18 +1211,20 @@ var DiscoveryService = class {
1208
1211
  *
1209
1212
  * Ranking algorithm:
1210
1213
  * 1. Bucket each agent into 1-minute slots by `lastPaidJobAt` (newest
1211
- * `payment-completed` feedback timestamp). Cold-start agents go into a
1212
- * sentinel bucket below all populated buckets.
1214
+ * `payment-completed` feedback timestamp, gated by a matching kind:6xxx
1215
+ * result from the provider on the same job event). Cold-start agents go
1216
+ * into a sentinel bucket below all populated buckets.
1213
1217
  * 2. Within a bucket, sort by positive review rate descending.
1214
1218
  * 3. Tiebreak by raw `lastPaidJobAt`, then `lastSeen` (NIP-89 freshness).
1215
1219
  *
1216
- * NOTE: We trust the `payment-completed` feedback timestamp directly; we do
1217
- * not verify the embedded `tx` signature on-chain. Public Solana devnet RPC
1218
- * rate-limits trivially exceed what discovery needs (N agents * up-to-5
1219
- * candidates), and the resulting 429s blocked discovery entirely. This
1220
- * means a malicious customer can publish a fake `payment-completed` to lift
1221
- * an agent's ranking. Acceptable trade-off for devnet / MVP; tighten via
1222
- * recipient-tied checks when the network moves to mainnet with a paid RPC
1220
+ * NOTE: We do not verify the `tx` signature on-chain - public Solana devnet
1221
+ * RPC rate-limits trivially exceed what discovery needs (N agents * up-to-5
1222
+ * candidates), and the resulting 429s blocked discovery entirely. As a
1223
+ * lighter sybil mitigation we cross-check `payment-completed` feedback
1224
+ * against a kind:6xxx result event authored by the provider on the same
1225
+ * job: a customer can publish a fake `payment-completed`, but they cannot
1226
+ * forge a result event signed by the provider. Tighten with recipient-tied
1227
+ * on-chain checks when the network moves to mainnet with a paid RPC
1223
1228
  * provider.
1224
1229
  */
1225
1230
  async fetchAgents(network = "devnet", limit) {
@@ -1262,14 +1267,27 @@ var DiscoveryService = class {
1262
1267
  ),
1263
1268
  this.enrichWithMetadata(agents)
1264
1269
  ]);
1270
+ const deliveredJobsByProvider = /* @__PURE__ */ new Map();
1265
1271
  for (const ev of resultEvents) {
1266
1272
  if (!verifyEvent(ev)) {
1267
1273
  continue;
1268
1274
  }
1269
1275
  const agent = agentMap.get(ev.pubkey);
1270
- if (agent && ev.created_at > agent.lastSeen) {
1276
+ if (!agent) {
1277
+ continue;
1278
+ }
1279
+ if (ev.created_at > agent.lastSeen) {
1271
1280
  agent.lastSeen = ev.created_at;
1272
1281
  }
1282
+ const jobEventId = ev.tags.find((t) => t[0] === "e")?.[1];
1283
+ if (jobEventId) {
1284
+ let delivered = deliveredJobsByProvider.get(ev.pubkey);
1285
+ if (!delivered) {
1286
+ delivered = /* @__PURE__ */ new Set();
1287
+ deliveredJobsByProvider.set(ev.pubkey, delivered);
1288
+ }
1289
+ delivered.add(jobEventId);
1290
+ }
1273
1291
  }
1274
1292
  for (const ev of feedbackEvents) {
1275
1293
  if (!verifyEvent(ev)) {
@@ -1296,7 +1314,9 @@ var DiscoveryService = class {
1296
1314
  const status = ev.tags.find((t) => t[0] === "status")?.[1];
1297
1315
  const txTag = ev.tags.find((t) => t[0] === "tx");
1298
1316
  const txSignature = txTag?.[1];
1299
- if (status === "payment-completed" && typeof txSignature === "string" && txSignature) {
1317
+ const jobEventId = ev.tags.find((t) => t[0] === "e")?.[1];
1318
+ const hasDeliveredResult = jobEventId !== void 0 && deliveredJobsByProvider.get(targetPubkey)?.has(jobEventId) === true;
1319
+ if (status === "payment-completed" && typeof txSignature === "string" && txSignature && hasDeliveredResult) {
1300
1320
  if (!agent.lastPaidJobAt || ev.created_at > agent.lastPaidJobAt) {
1301
1321
  agent.lastPaidJobAt = ev.created_at;
1302
1322
  agent.lastPaidJobTx = txSignature;