@elisym/sdk 0.21.1 → 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.
package/dist/index.cjs CHANGED
@@ -98,6 +98,11 @@ var DEFAULTS = {
98
98
  var LIMITS = {
99
99
  MAX_INPUT_LENGTH: 1e5,
100
100
  MAX_TIMEOUT_SECS: 600,
101
+ // Upper bound for execution budgets (`max_execution_secs` / `execution_timeout_secs`).
102
+ // Distinct from MAX_TIMEOUT_SECS (the result-wait cap): execution budgets may be
103
+ // hours, so this exists only to keep `secs * 1000` within Node's setTimeout limit
104
+ // (2_147_483_647 ms) - a larger value overflows and fires the timer immediately.
105
+ MAX_EXECUTION_SECS: 2147483,
101
106
  MAX_CAPABILITIES: 20,
102
107
  MAX_DESCRIPTION_LENGTH: 500,
103
108
  MAX_AGENT_NAME_LENGTH: 64,
@@ -1492,6 +1497,7 @@ var DiscoveryService = class {
1492
1497
  return agents;
1493
1498
  }
1494
1499
  const deliveredJobsByProvider = /* @__PURE__ */ new Map();
1500
+ const customerByJob = /* @__PURE__ */ new Map();
1495
1501
  for (const ev of resultEvents) {
1496
1502
  if (!nostrTools.verifyEvent(ev)) {
1497
1503
  continue;
@@ -1511,8 +1517,13 @@ var DiscoveryService = class {
1511
1517
  deliveredJobsByProvider.set(ev.pubkey, delivered);
1512
1518
  }
1513
1519
  delivered.add(jobEventId);
1520
+ const customerPubkey = ev.tags.find((tag) => tag[0] === "p")?.[1];
1521
+ if (customerPubkey) {
1522
+ customerByJob.set(jobEventId, customerPubkey);
1523
+ }
1514
1524
  }
1515
1525
  }
1526
+ const countedRatings = /* @__PURE__ */ new Set();
1516
1527
  for (const ev of feedbackEvents) {
1517
1528
  if (!nostrTools.verifyEvent(ev)) {
1518
1529
  continue;
@@ -1528,19 +1539,25 @@ var DiscoveryService = class {
1528
1539
  if (ev.created_at > agent.lastSeen) {
1529
1540
  agent.lastSeen = ev.created_at;
1530
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;
1531
1546
  const rating = ev.tags.find((tag) => tag[0] === "rating")?.[1];
1532
- if (rating === "1" || rating === "0") {
1533
- agent.totalRatingCount = (agent.totalRatingCount ?? 0) + 1;
1534
- if (rating === "1") {
1535
- 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
+ }
1536
1555
  }
1537
1556
  }
1538
1557
  const status = ev.tags.find((tag) => tag[0] === "status")?.[1];
1539
1558
  const txTag = ev.tags.find((tag) => tag[0] === "tx");
1540
1559
  const txSignature = txTag?.[1];
1541
- const jobEventId = ev.tags.find((tag) => tag[0] === "e")?.[1];
1542
- const hasDeliveredResult = jobEventId !== void 0 && deliveredJobsByProvider.get(targetPubkey)?.has(jobEventId) === true;
1543
- if (status === "payment-completed" && typeof txSignature === "string" && txSignature && hasDeliveredResult) {
1560
+ if (status === "payment-completed" && typeof txSignature === "string" && txSignature && hasDeliveredResult && authoredByCustomer) {
1544
1561
  if (!agent.lastPaidJobAt || ev.created_at > agent.lastPaidJobAt) {
1545
1562
  agent.lastPaidJobAt = ev.created_at;
1546
1563
  agent.lastPaidJobTx = txSignature;
@@ -2016,7 +2033,11 @@ var MarketplaceService = class {
2016
2033
  if (!resolved) {
2017
2034
  done();
2018
2035
  try {
2019
- cb.onError?.(`Timed out waiting for response (${timeoutMs / 1e3}s).`);
2036
+ if (cb.onTimeout) {
2037
+ cb.onTimeout(timeoutMs);
2038
+ } else {
2039
+ cb.onError?.(`Timed out waiting for response (${timeoutMs / 1e3}s).`);
2040
+ }
2020
2041
  } catch {
2021
2042
  }
2022
2043
  }
@@ -3262,6 +3283,14 @@ function classifyJobError(message) {
3262
3283
  }
3263
3284
  return "unknown";
3264
3285
  }
3286
+ var JobWaitTimeoutError = class extends Error {
3287
+ constructor(timeoutMs) {
3288
+ super(
3289
+ timeoutMs === void 0 ? "Timed out waiting for job result" : `Timed out waiting for job result (${Math.round(timeoutMs / 1e3)}s)`
3290
+ );
3291
+ this.name = "JobWaitTimeoutError";
3292
+ }
3293
+ };
3265
3294
  var DEFAULT_COMPUTE_UNIT_LIMIT2 = 2e5;
3266
3295
  var DEFAULT_PRIORITY_FEE_PERCENTILE2 = 75;
3267
3296
  var BASE_FEE_LAMPORTS_PER_SIGNATURE = 5000n;
@@ -3412,35 +3441,43 @@ function formatNetworkBaseline(estimate) {
3412
3441
  return `Estimated network gas: ${total} SOL (${parts.join(" + ")}).`;
3413
3442
  }
3414
3443
  var NEGATIVE_CACHE_TTL_MS = 6e4;
3444
+ var MAX_CACHE_ENTRIES = 5e3;
3415
3445
  var verifyCache = /* @__PURE__ */ new Map();
3416
3446
  function clearQuickVerifyCache() {
3417
3447
  verifyCache.clear();
3418
3448
  }
3419
3449
  async function verifyJobPaymentQuick(rpc, txSignature, expectedRecipient) {
3420
3450
  if (!txSignature) {
3421
- return { verified: false, txSignature: "", reason: "invalid_input" };
3451
+ return { receivedFunds: false, txSignature: "", reason: "invalid_input" };
3422
3452
  }
3423
3453
  if (!expectedRecipient || !kit.isAddress(expectedRecipient)) {
3424
- return { verified: false, txSignature, reason: "invalid_input" };
3454
+ return { receivedFunds: false, txSignature, reason: "invalid_input" };
3425
3455
  }
3426
3456
  const cacheKey2 = `${txSignature}:${expectedRecipient}`;
3427
3457
  const cached = verifyCache.get(cacheKey2);
3428
3458
  if (cached) {
3429
- if (cached.result.verified) {
3459
+ if (cached.result.receivedFunds) {
3430
3460
  return cached.result;
3431
3461
  }
3432
3462
  if (Date.now() - cached.cachedAt < NEGATIVE_CACHE_TTL_MS) {
3433
3463
  return cached.result;
3434
3464
  }
3465
+ verifyCache.delete(cacheKey2);
3435
3466
  }
3436
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
+ }
3437
3474
  verifyCache.set(cacheKey2, { result, cachedAt: Date.now() });
3438
3475
  return result;
3439
3476
  }
3440
3477
  async function doVerifyOnce(rpc, txSignature, expectedRecipient) {
3441
3478
  const sigStr = txSignature;
3442
3479
  if (!rpc || typeof rpc.getTransaction !== "function") {
3443
- return { verified: false, txSignature: sigStr, reason: "rpc_error" };
3480
+ return { receivedFunds: false, txSignature: sigStr, reason: "rpc_error" };
3444
3481
  }
3445
3482
  let tx;
3446
3483
  try {
@@ -3450,13 +3487,13 @@ async function doVerifyOnce(rpc, txSignature, expectedRecipient) {
3450
3487
  maxSupportedTransactionVersion: 0
3451
3488
  }).send();
3452
3489
  } catch {
3453
- return { verified: false, txSignature: sigStr, reason: "rpc_error" };
3490
+ return { receivedFunds: false, txSignature: sigStr, reason: "rpc_error" };
3454
3491
  }
3455
3492
  if (!tx) {
3456
- return { verified: false, txSignature: sigStr, reason: "not_found" };
3493
+ return { receivedFunds: false, txSignature: sigStr, reason: "not_found" };
3457
3494
  }
3458
3495
  if (!tx.meta || tx.meta.err) {
3459
- return { verified: false, txSignature: sigStr, reason: "tx_failed" };
3496
+ return { receivedFunds: false, txSignature: sigStr, reason: "tx_failed" };
3460
3497
  }
3461
3498
  const accountKeys = tx.transaction.message.accountKeys;
3462
3499
  const recipientStr = expectedRecipient;
@@ -3470,7 +3507,7 @@ async function doVerifyOnce(rpc, txSignature, expectedRecipient) {
3470
3507
  if (pre !== void 0 && post !== void 0) {
3471
3508
  const delta = BigInt(post) - BigInt(pre);
3472
3509
  if (delta > 0n) {
3473
- return { verified: true, txSignature: sigStr };
3510
+ return { receivedFunds: true, txSignature: sigStr };
3474
3511
  }
3475
3512
  }
3476
3513
  }
@@ -3488,11 +3525,11 @@ async function doVerifyOnce(rpc, txSignature, expectedRecipient) {
3488
3525
  const preAmount = pre ? BigInt(pre.uiTokenAmount.amount) : 0n;
3489
3526
  const postAmount = BigInt(post.uiTokenAmount.amount);
3490
3527
  if (postAmount > preAmount) {
3491
- return { verified: true, txSignature: sigStr };
3528
+ return { receivedFunds: true, txSignature: sigStr };
3492
3529
  }
3493
3530
  }
3494
3531
  }
3495
- return { verified: false, txSignature: sigStr, reason: "recipient_mismatch" };
3532
+ return { receivedFunds: false, txSignature: sigStr, reason: "recipient_mismatch" };
3496
3533
  }
3497
3534
  var DEFAULT_LIMIT = 1e3;
3498
3535
  var NATIVE_KEY = "native";
@@ -3587,7 +3624,12 @@ var SessionSpendLimitEntrySchema = zod.z.object({
3587
3624
  chain: zod.z.enum(["solana"]),
3588
3625
  token: zod.z.string().min(1).max(16).regex(/^[a-z0-9]+$/, "token must be lowercase alphanumeric"),
3589
3626
  mint: zod.z.string().min(1).max(64).optional(),
3590
- 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
+ })
3591
3633
  }).strict();
3592
3634
  var GlobalConfigSchema = zod.z.object({
3593
3635
  session_spend_limits: zod.z.array(SessionSpendLimitEntrySchema).max(16).optional()
@@ -3797,6 +3839,7 @@ exports.ElisymClient = ElisymClient;
3797
3839
  exports.ElisymIdentity = ElisymIdentity;
3798
3840
  exports.GlobalConfigSchema = GlobalConfigSchema;
3799
3841
  exports.INPUT_REDACT_PATHS = INPUT_REDACT_PATHS;
3842
+ exports.JobWaitTimeoutError = JobWaitTimeoutError;
3800
3843
  exports.KIND_APP_HANDLER = KIND_APP_HANDLER;
3801
3844
  exports.KIND_JOB_FEEDBACK = KIND_JOB_FEEDBACK;
3802
3845
  exports.KIND_JOB_REQUEST = KIND_JOB_REQUEST;