@elisym/sdk 0.22.0 → 0.23.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.
@@ -12,16 +12,16 @@ declare const SessionSpendLimitEntrySchema: z.ZodObject<{
12
12
  chain: z.ZodEnum<["solana"]>;
13
13
  token: z.ZodString;
14
14
  mint: z.ZodOptional<z.ZodString>;
15
- amount: z.ZodNumber;
15
+ amount: z.ZodEffects<z.ZodEffects<z.ZodUnion<[z.ZodString, z.ZodNumber]>, string, string | number>, string, string | number>;
16
16
  }, "strict", z.ZodTypeAny, {
17
17
  chain: "solana";
18
18
  token: string;
19
- amount: number;
19
+ amount: string;
20
20
  mint?: string | undefined;
21
21
  }, {
22
22
  chain: "solana";
23
23
  token: string;
24
- amount: number;
24
+ amount: string | number;
25
25
  mint?: string | undefined;
26
26
  }>;
27
27
  declare const GlobalConfigSchema: z.ZodObject<{
@@ -29,30 +29,30 @@ declare const GlobalConfigSchema: z.ZodObject<{
29
29
  chain: z.ZodEnum<["solana"]>;
30
30
  token: z.ZodString;
31
31
  mint: z.ZodOptional<z.ZodString>;
32
- amount: z.ZodNumber;
32
+ amount: z.ZodEffects<z.ZodEffects<z.ZodUnion<[z.ZodString, z.ZodNumber]>, string, string | number>, string, string | number>;
33
33
  }, "strict", z.ZodTypeAny, {
34
34
  chain: "solana";
35
35
  token: string;
36
- amount: number;
36
+ amount: string;
37
37
  mint?: string | undefined;
38
38
  }, {
39
39
  chain: "solana";
40
40
  token: string;
41
- amount: number;
41
+ amount: string | number;
42
42
  mint?: string | undefined;
43
43
  }>, "many">>;
44
44
  }, "strict", z.ZodTypeAny, {
45
45
  session_spend_limits?: {
46
46
  chain: "solana";
47
47
  token: string;
48
- amount: number;
48
+ amount: string;
49
49
  mint?: string | undefined;
50
50
  }[] | undefined;
51
51
  }, {
52
52
  session_spend_limits?: {
53
53
  chain: "solana";
54
54
  token: string;
55
- amount: number;
55
+ amount: string | number;
56
56
  mint?: string | undefined;
57
57
  }[] | undefined;
58
58
  }>;
@@ -12,16 +12,16 @@ declare const SessionSpendLimitEntrySchema: z.ZodObject<{
12
12
  chain: z.ZodEnum<["solana"]>;
13
13
  token: z.ZodString;
14
14
  mint: z.ZodOptional<z.ZodString>;
15
- amount: z.ZodNumber;
15
+ amount: z.ZodEffects<z.ZodEffects<z.ZodUnion<[z.ZodString, z.ZodNumber]>, string, string | number>, string, string | number>;
16
16
  }, "strict", z.ZodTypeAny, {
17
17
  chain: "solana";
18
18
  token: string;
19
- amount: number;
19
+ amount: string;
20
20
  mint?: string | undefined;
21
21
  }, {
22
22
  chain: "solana";
23
23
  token: string;
24
- amount: number;
24
+ amount: string | number;
25
25
  mint?: string | undefined;
26
26
  }>;
27
27
  declare const GlobalConfigSchema: z.ZodObject<{
@@ -29,30 +29,30 @@ declare const GlobalConfigSchema: z.ZodObject<{
29
29
  chain: z.ZodEnum<["solana"]>;
30
30
  token: z.ZodString;
31
31
  mint: z.ZodOptional<z.ZodString>;
32
- amount: z.ZodNumber;
32
+ amount: z.ZodEffects<z.ZodEffects<z.ZodUnion<[z.ZodString, z.ZodNumber]>, string, string | number>, string, string | number>;
33
33
  }, "strict", z.ZodTypeAny, {
34
34
  chain: "solana";
35
35
  token: string;
36
- amount: number;
36
+ amount: string;
37
37
  mint?: string | undefined;
38
38
  }, {
39
39
  chain: "solana";
40
40
  token: string;
41
- amount: number;
41
+ amount: string | number;
42
42
  mint?: string | undefined;
43
43
  }>, "many">>;
44
44
  }, "strict", z.ZodTypeAny, {
45
45
  session_spend_limits?: {
46
46
  chain: "solana";
47
47
  token: string;
48
- amount: number;
48
+ amount: string;
49
49
  mint?: string | undefined;
50
50
  }[] | undefined;
51
51
  }, {
52
52
  session_spend_limits?: {
53
53
  chain: "solana";
54
54
  token: string;
55
- amount: number;
55
+ amount: string | number;
56
56
  mint?: string | undefined;
57
57
  }[] | undefined;
58
58
  }>;
package/dist/index.cjs CHANGED
@@ -1497,6 +1497,7 @@ var DiscoveryService = class {
1497
1497
  return agents;
1498
1498
  }
1499
1499
  const deliveredJobsByProvider = /* @__PURE__ */ new Map();
1500
+ const customerByJob = /* @__PURE__ */ new Map();
1500
1501
  for (const ev of resultEvents) {
1501
1502
  if (!nostrTools.verifyEvent(ev)) {
1502
1503
  continue;
@@ -1516,8 +1517,13 @@ var DiscoveryService = class {
1516
1517
  deliveredJobsByProvider.set(ev.pubkey, delivered);
1517
1518
  }
1518
1519
  delivered.add(jobEventId);
1520
+ const customerPubkey = ev.tags.find((tag) => tag[0] === "p")?.[1];
1521
+ if (customerPubkey) {
1522
+ customerByJob.set(jobEventId, customerPubkey);
1523
+ }
1519
1524
  }
1520
1525
  }
1526
+ const countedRatings = /* @__PURE__ */ new Set();
1521
1527
  for (const ev of feedbackEvents) {
1522
1528
  if (!nostrTools.verifyEvent(ev)) {
1523
1529
  continue;
@@ -1533,19 +1539,25 @@ var DiscoveryService = class {
1533
1539
  if (ev.created_at > agent.lastSeen) {
1534
1540
  agent.lastSeen = ev.created_at;
1535
1541
  }
1542
+ const jobEventId = ev.tags.find((tag) => tag[0] === "e")?.[1];
1543
+ const hasDeliveredResult = jobEventId !== void 0 && deliveredJobsByProvider.get(targetPubkey)?.has(jobEventId) === true;
1544
+ const jobCustomer = jobEventId !== void 0 ? customerByJob.get(jobEventId) : void 0;
1545
+ const authoredByCustomer = jobCustomer !== void 0 && ev.pubkey === jobCustomer;
1536
1546
  const rating = ev.tags.find((tag) => tag[0] === "rating")?.[1];
1537
- if (rating === "1" || rating === "0") {
1538
- agent.totalRatingCount = (agent.totalRatingCount ?? 0) + 1;
1539
- if (rating === "1") {
1540
- agent.positiveCount = (agent.positiveCount ?? 0) + 1;
1547
+ if ((rating === "1" || rating === "0") && hasDeliveredResult && authoredByCustomer) {
1548
+ const ratingKey = `${ev.pubkey}:${jobEventId}`;
1549
+ if (!countedRatings.has(ratingKey)) {
1550
+ countedRatings.add(ratingKey);
1551
+ agent.totalRatingCount = (agent.totalRatingCount ?? 0) + 1;
1552
+ if (rating === "1") {
1553
+ agent.positiveCount = (agent.positiveCount ?? 0) + 1;
1554
+ }
1541
1555
  }
1542
1556
  }
1543
1557
  const status = ev.tags.find((tag) => tag[0] === "status")?.[1];
1544
1558
  const txTag = ev.tags.find((tag) => tag[0] === "tx");
1545
1559
  const txSignature = txTag?.[1];
1546
- const jobEventId = ev.tags.find((tag) => tag[0] === "e")?.[1];
1547
- const hasDeliveredResult = jobEventId !== void 0 && deliveredJobsByProvider.get(targetPubkey)?.has(jobEventId) === true;
1548
- if (status === "payment-completed" && typeof txSignature === "string" && txSignature && hasDeliveredResult) {
1560
+ if (status === "payment-completed" && typeof txSignature === "string" && txSignature && hasDeliveredResult && authoredByCustomer) {
1549
1561
  if (!agent.lastPaidJobAt || ev.created_at > agent.lastPaidJobAt) {
1550
1562
  agent.lastPaidJobAt = ev.created_at;
1551
1563
  agent.lastPaidJobTx = txSignature;
@@ -3429,35 +3441,43 @@ function formatNetworkBaseline(estimate) {
3429
3441
  return `Estimated network gas: ${total} SOL (${parts.join(" + ")}).`;
3430
3442
  }
3431
3443
  var NEGATIVE_CACHE_TTL_MS = 6e4;
3444
+ var MAX_CACHE_ENTRIES = 5e3;
3432
3445
  var verifyCache = /* @__PURE__ */ new Map();
3433
3446
  function clearQuickVerifyCache() {
3434
3447
  verifyCache.clear();
3435
3448
  }
3436
3449
  async function verifyJobPaymentQuick(rpc, txSignature, expectedRecipient) {
3437
3450
  if (!txSignature) {
3438
- return { verified: false, txSignature: "", reason: "invalid_input" };
3451
+ return { receivedFunds: false, txSignature: "", reason: "invalid_input" };
3439
3452
  }
3440
3453
  if (!expectedRecipient || !kit.isAddress(expectedRecipient)) {
3441
- return { verified: false, txSignature, reason: "invalid_input" };
3454
+ return { receivedFunds: false, txSignature, reason: "invalid_input" };
3442
3455
  }
3443
3456
  const cacheKey2 = `${txSignature}:${expectedRecipient}`;
3444
3457
  const cached = verifyCache.get(cacheKey2);
3445
3458
  if (cached) {
3446
- if (cached.result.verified) {
3459
+ if (cached.result.receivedFunds) {
3447
3460
  return cached.result;
3448
3461
  }
3449
3462
  if (Date.now() - cached.cachedAt < NEGATIVE_CACHE_TTL_MS) {
3450
3463
  return cached.result;
3451
3464
  }
3465
+ verifyCache.delete(cacheKey2);
3452
3466
  }
3453
3467
  const result = await doVerifyOnce(rpc, txSignature, expectedRecipient);
3468
+ if (verifyCache.size >= MAX_CACHE_ENTRIES) {
3469
+ const oldest = verifyCache.keys().next().value;
3470
+ if (oldest !== void 0) {
3471
+ verifyCache.delete(oldest);
3472
+ }
3473
+ }
3454
3474
  verifyCache.set(cacheKey2, { result, cachedAt: Date.now() });
3455
3475
  return result;
3456
3476
  }
3457
3477
  async function doVerifyOnce(rpc, txSignature, expectedRecipient) {
3458
3478
  const sigStr = txSignature;
3459
3479
  if (!rpc || typeof rpc.getTransaction !== "function") {
3460
- return { verified: false, txSignature: sigStr, reason: "rpc_error" };
3480
+ return { receivedFunds: false, txSignature: sigStr, reason: "rpc_error" };
3461
3481
  }
3462
3482
  let tx;
3463
3483
  try {
@@ -3467,13 +3487,13 @@ async function doVerifyOnce(rpc, txSignature, expectedRecipient) {
3467
3487
  maxSupportedTransactionVersion: 0
3468
3488
  }).send();
3469
3489
  } catch {
3470
- return { verified: false, txSignature: sigStr, reason: "rpc_error" };
3490
+ return { receivedFunds: false, txSignature: sigStr, reason: "rpc_error" };
3471
3491
  }
3472
3492
  if (!tx) {
3473
- return { verified: false, txSignature: sigStr, reason: "not_found" };
3493
+ return { receivedFunds: false, txSignature: sigStr, reason: "not_found" };
3474
3494
  }
3475
3495
  if (!tx.meta || tx.meta.err) {
3476
- return { verified: false, txSignature: sigStr, reason: "tx_failed" };
3496
+ return { receivedFunds: false, txSignature: sigStr, reason: "tx_failed" };
3477
3497
  }
3478
3498
  const accountKeys = tx.transaction.message.accountKeys;
3479
3499
  const recipientStr = expectedRecipient;
@@ -3487,7 +3507,7 @@ async function doVerifyOnce(rpc, txSignature, expectedRecipient) {
3487
3507
  if (pre !== void 0 && post !== void 0) {
3488
3508
  const delta = BigInt(post) - BigInt(pre);
3489
3509
  if (delta > 0n) {
3490
- return { verified: true, txSignature: sigStr };
3510
+ return { receivedFunds: true, txSignature: sigStr };
3491
3511
  }
3492
3512
  }
3493
3513
  }
@@ -3505,11 +3525,11 @@ async function doVerifyOnce(rpc, txSignature, expectedRecipient) {
3505
3525
  const preAmount = pre ? BigInt(pre.uiTokenAmount.amount) : 0n;
3506
3526
  const postAmount = BigInt(post.uiTokenAmount.amount);
3507
3527
  if (postAmount > preAmount) {
3508
- return { verified: true, txSignature: sigStr };
3528
+ return { receivedFunds: true, txSignature: sigStr };
3509
3529
  }
3510
3530
  }
3511
3531
  }
3512
- return { verified: false, txSignature: sigStr, reason: "recipient_mismatch" };
3532
+ return { receivedFunds: false, txSignature: sigStr, reason: "recipient_mismatch" };
3513
3533
  }
3514
3534
  var DEFAULT_LIMIT = 1e3;
3515
3535
  var NATIVE_KEY = "native";
@@ -3604,7 +3624,12 @@ var SessionSpendLimitEntrySchema = zod.z.object({
3604
3624
  chain: zod.z.enum(["solana"]),
3605
3625
  token: zod.z.string().min(1).max(16).regex(/^[a-z0-9]+$/, "token must be lowercase alphanumeric"),
3606
3626
  mint: zod.z.string().min(1).max(64).optional(),
3607
- amount: zod.z.number().positive().finite()
3627
+ // Stored as a string to preserve the operator's exact decimal text (avoids
3628
+ // Number round-tripping to scientific notation). Legacy configs persisted a
3629
+ // number; accept both and normalize to a positive-decimal string.
3630
+ amount: zod.z.union([zod.z.string(), zod.z.number()]).transform((value) => typeof value === "number" ? String(value) : value.trim()).refine((value) => /^\d+(?:\.\d+)?$/.test(value) && /[1-9]/.test(value), {
3631
+ message: 'amount must be a positive decimal (e.g. "0.5", "1")'
3632
+ })
3608
3633
  }).strict();
3609
3634
  var GlobalConfigSchema = zod.z.object({
3610
3635
  session_spend_limits: zod.z.array(SessionSpendLimitEntrySchema).max(16).optional()