@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.d.cts CHANGED
@@ -3,7 +3,7 @@ import { Filter, Event } from 'nostr-tools';
3
3
  import { A as Asset } from './assets-C-nzSYD4.cjs';
4
4
  export { C as Chain, K as KNOWN_ASSETS, N as NATIVE_SOL, U as USDC_SOLANA_DEVNET, a as assetByKey, b as assetKey, f as formatAssetAmount, p as parseAssetAmount, r as resolveAssetFromPaymentRequest, c as resolveKnownAsset } from './assets-C-nzSYD4.cjs';
5
5
  import { z } from 'zod';
6
- export { G as GlobalConfig, a as GlobalConfigSchema, S as SessionSpendLimitEntry, b as SessionSpendLimitEntrySchema } from './global-schema-CddHP2nk.cjs';
6
+ export { G as GlobalConfig, a as GlobalConfigSchema, S as SessionSpendLimitEntry, b as SessionSpendLimitEntrySchema } from './global-schema-BsVFDtkt.cjs';
7
7
  export { R as RateLimitDecision, S as SlidingWindowLimiter, a as SlidingWindowLimiterOptions, c as createSlidingWindowLimiter } from './rateLimiter-CoEmZkSX.cjs';
8
8
 
9
9
  declare class ElisymIdentity {
@@ -151,6 +151,13 @@ interface JobUpdateCallbacks {
151
151
  onFeedback?: (status: string, amount?: number, paymentRequest?: string, senderPubkey?: string) => void;
152
152
  onResult?: (content: string, eventId: string) => void;
153
153
  onError?: (error: string) => void;
154
+ /**
155
+ * Fired when the result wait window expires without a result - a distinct,
156
+ * structured signal from `onError`. When omitted, the timeout is delivered
157
+ * through `onError` as a "Timed out waiting..." string for backwards
158
+ * compatibility.
159
+ */
160
+ onTimeout?: (timeoutMs: number) => void;
154
161
  }
155
162
  interface JobSubscriptionOptions {
156
163
  jobEventId: string;
@@ -709,6 +716,17 @@ type JobErrorKind = 'agent-unavailable' | 'unknown';
709
716
  * `unknown` for everything else (timeouts, validation errors, transport).
710
717
  */
711
718
  declare function classifyJobError(message: string): JobErrorKind;
719
+ /**
720
+ * Signalled via `JobUpdateCallbacks.onTimeout` (and thrown by helpers that
721
+ * await a result) when the wait window expires without a result. This is a
722
+ * distinct, structured signal from a genuine provider/transport error, so
723
+ * callers can branch on the type instead of substring-matching "timed out"
724
+ * on a free-form error message (which masks real errors that happen to
725
+ * mention a timeout).
726
+ */
727
+ declare class JobWaitTimeoutError extends Error {
728
+ constructor(timeoutMs?: number);
729
+ }
712
730
 
713
731
  declare class SolanaPaymentStrategy implements PaymentStrategy {
714
732
  readonly chain = "solana";
@@ -1035,7 +1053,16 @@ declare function parsePaymentRequest(input: string, options?: ParseOptions): Par
1035
1053
  */
1036
1054
  type QuickVerifyReason = 'not_found' | 'tx_failed' | 'recipient_mismatch' | 'rpc_error' | 'invalid_input';
1037
1055
  interface QuickVerifyResult {
1038
- verified: boolean;
1056
+ /**
1057
+ * True when the recipient address received funds in this transaction.
1058
+ *
1059
+ * NOTE: this is NOT proof of a valid elisym job payment. It does not check
1060
+ * the payment `reference` key or that the amount matches the job price - it
1061
+ * is a best-effort signal for the fast discovery-ranking path, where the
1062
+ * original payment request is unavailable. For an authoritative check
1063
+ * (amount + reference) use `SolanaPaymentStrategy.verifyPayment`.
1064
+ */
1065
+ receivedFunds: boolean;
1039
1066
  txSignature: string;
1040
1067
  reason?: QuickVerifyReason;
1041
1068
  }
@@ -1087,6 +1114,12 @@ declare function aggregateNetworkStats(rpc: Rpc<SolanaRpcApi>, options?: Aggrega
1087
1114
  * Returns `null` when the PDA has not been initialized yet (admin must call
1088
1115
  * `initialize_stats` once after program upgrade).
1089
1116
  */
1117
+ /**
1118
+ * Best-effort network counters read from the on-chain PDA. These are NOT bound
1119
+ * to verified transfers and can be inflated by a malicious caller, so present
1120
+ * them as approximate/unverified, never as authoritative proof of activity. For
1121
+ * a transfer-derived figure use `aggregateNetworkStats`.
1122
+ */
1090
1123
  interface OnchainNetworkStats {
1091
1124
  jobCount: number;
1092
1125
  volumeNative: bigint;
@@ -1260,6 +1293,7 @@ declare const DEFAULTS: {
1260
1293
  declare const LIMITS: {
1261
1294
  readonly MAX_INPUT_LENGTH: 100000;
1262
1295
  readonly MAX_TIMEOUT_SECS: 600;
1296
+ readonly MAX_EXECUTION_SECS: 2147483;
1263
1297
  readonly MAX_CAPABILITIES: 20;
1264
1298
  readonly MAX_DESCRIPTION_LENGTH: 500;
1265
1299
  readonly MAX_AGENT_NAME_LENGTH: 64;
@@ -1272,4 +1306,4 @@ declare const LIMITS: {
1272
1306
  readonly MAX_POLICY_VERSION_LENGTH: 32;
1273
1307
  };
1274
1308
 
1275
- export { type Agent, type AgentPolicy, type AggregateNetworkStatsOptions, Asset, BoundedSet, type BuildTransactionOptions, type CapabilityCard, DEFAULTS, DEFAULT_KIND_OFFSET, DEFAULT_REDACT_PATHS, DiscoveryService, ELISYM_PROTOCOL_TAG, ElisymClient, type ElisymClientConfig, type ElisymClientFullConfig, ElisymIdentity, type EstimatePriorityFeeOptions, type EstimateSolFeeOptions, type GetProtocolConfigOptions, INPUT_REDACT_PATHS, type Job, type JobErrorKind, type JobStatus, type JobSubscriptionOptions, type JobUpdateCallbacks, KIND_APP_HANDLER, KIND_JOB_FEEDBACK, KIND_JOB_REQUEST, KIND_JOB_REQUEST_BASE, KIND_JOB_RESULT, KIND_JOB_RESULT_BASE, KIND_LONG_FORM_ARTICLE, KIND_PING, KIND_PONG, LAMPORTS_PER_SOL, LIMITS, MarketplaceService, MediaService, type Network, type NetworkBaselineEstimate, type NetworkBaselineOptions, type NetworkStats, type NetworkStatsResult, NostrPool, type OnchainNetworkStats, POLICY_D_TAG_PREFIX, POLICY_TYPE_REGEX, POLICY_T_TAG, PROTOCOL_PROGRAM_ID_DEVNET, type ParseOptions, type ParseResult, type ParsedPaymentRequest, type PaymentAssetRef, type PaymentInfo, type PaymentRequestData, PaymentRequestSchema, type PaymentStrategy, type PaymentValidationCode, type PaymentValidationError, type PingResult, PingService, PoliciesService, type PolicyInput, type ProtocolCluster, type ProtocolConfig, type ProtocolConfigInput, type QuickVerifyReason, type QuickVerifyResult, RELAYS, type RankKey, SECRET_REDACT_PATHS, type Signer, type SolFeeEstimate, SolanaPaymentStrategy, type SubCloser, type SubmitJobOptions, type VerifyOptions, type VerifyResult, aggregateNetworkStats, assertExpiry, assertLamports, buildPaymentInstructions, calculateProtocolFee, classifyJobError, clearPriorityFeeCache, clearProtocolConfigCache, clearQuickVerifyCache, compareAgentsByRank, computeRankKey, createPaymentRequestWithOnchainConfig, estimateNetworkBaseline, estimatePriorityFeeMicroLamports, estimateSolFeeLamports, formatFeeBreakdown, formatNetworkBaseline, formatSol, getNetworkStats, getProtocolConfig, getProtocolProgramId, jobRequestKind, jobResultKind, makeCensor, nip44Decrypt, nip44Encrypt, parsePaymentRequest, pickPercentileFee, timeAgo, toDTag, truncateKey, validateAgentName, validateExpiry, verifyJobPaymentQuick };
1309
+ export { type Agent, type AgentPolicy, type AggregateNetworkStatsOptions, Asset, BoundedSet, type BuildTransactionOptions, type CapabilityCard, DEFAULTS, DEFAULT_KIND_OFFSET, DEFAULT_REDACT_PATHS, DiscoveryService, ELISYM_PROTOCOL_TAG, ElisymClient, type ElisymClientConfig, type ElisymClientFullConfig, ElisymIdentity, type EstimatePriorityFeeOptions, type EstimateSolFeeOptions, type GetProtocolConfigOptions, INPUT_REDACT_PATHS, type Job, type JobErrorKind, type JobStatus, type JobSubscriptionOptions, type JobUpdateCallbacks, JobWaitTimeoutError, KIND_APP_HANDLER, KIND_JOB_FEEDBACK, KIND_JOB_REQUEST, KIND_JOB_REQUEST_BASE, KIND_JOB_RESULT, KIND_JOB_RESULT_BASE, KIND_LONG_FORM_ARTICLE, KIND_PING, KIND_PONG, LAMPORTS_PER_SOL, LIMITS, MarketplaceService, MediaService, type Network, type NetworkBaselineEstimate, type NetworkBaselineOptions, type NetworkStats, type NetworkStatsResult, NostrPool, type OnchainNetworkStats, POLICY_D_TAG_PREFIX, POLICY_TYPE_REGEX, POLICY_T_TAG, PROTOCOL_PROGRAM_ID_DEVNET, type ParseOptions, type ParseResult, type ParsedPaymentRequest, type PaymentAssetRef, type PaymentInfo, type PaymentRequestData, PaymentRequestSchema, type PaymentStrategy, type PaymentValidationCode, type PaymentValidationError, type PingResult, PingService, PoliciesService, type PolicyInput, type ProtocolCluster, type ProtocolConfig, type ProtocolConfigInput, type QuickVerifyReason, type QuickVerifyResult, RELAYS, type RankKey, SECRET_REDACT_PATHS, type Signer, type SolFeeEstimate, SolanaPaymentStrategy, type SubCloser, type SubmitJobOptions, type VerifyOptions, type VerifyResult, aggregateNetworkStats, assertExpiry, assertLamports, buildPaymentInstructions, calculateProtocolFee, classifyJobError, clearPriorityFeeCache, clearProtocolConfigCache, clearQuickVerifyCache, compareAgentsByRank, computeRankKey, createPaymentRequestWithOnchainConfig, estimateNetworkBaseline, estimatePriorityFeeMicroLamports, estimateSolFeeLamports, formatFeeBreakdown, formatNetworkBaseline, formatSol, getNetworkStats, getProtocolConfig, getProtocolProgramId, jobRequestKind, jobResultKind, makeCensor, nip44Decrypt, nip44Encrypt, parsePaymentRequest, pickPercentileFee, timeAgo, toDTag, truncateKey, validateAgentName, validateExpiry, verifyJobPaymentQuick };
package/dist/index.d.ts CHANGED
@@ -3,7 +3,7 @@ import { Filter, Event } from 'nostr-tools';
3
3
  import { A as Asset } from './assets-C-nzSYD4.js';
4
4
  export { C as Chain, K as KNOWN_ASSETS, N as NATIVE_SOL, U as USDC_SOLANA_DEVNET, a as assetByKey, b as assetKey, f as formatAssetAmount, p as parseAssetAmount, r as resolveAssetFromPaymentRequest, c as resolveKnownAsset } from './assets-C-nzSYD4.js';
5
5
  import { z } from 'zod';
6
- export { G as GlobalConfig, a as GlobalConfigSchema, S as SessionSpendLimitEntry, b as SessionSpendLimitEntrySchema } from './global-schema-CddHP2nk.js';
6
+ export { G as GlobalConfig, a as GlobalConfigSchema, S as SessionSpendLimitEntry, b as SessionSpendLimitEntrySchema } from './global-schema-BsVFDtkt.js';
7
7
  export { R as RateLimitDecision, S as SlidingWindowLimiter, a as SlidingWindowLimiterOptions, c as createSlidingWindowLimiter } from './rateLimiter-CoEmZkSX.js';
8
8
 
9
9
  declare class ElisymIdentity {
@@ -151,6 +151,13 @@ interface JobUpdateCallbacks {
151
151
  onFeedback?: (status: string, amount?: number, paymentRequest?: string, senderPubkey?: string) => void;
152
152
  onResult?: (content: string, eventId: string) => void;
153
153
  onError?: (error: string) => void;
154
+ /**
155
+ * Fired when the result wait window expires without a result - a distinct,
156
+ * structured signal from `onError`. When omitted, the timeout is delivered
157
+ * through `onError` as a "Timed out waiting..." string for backwards
158
+ * compatibility.
159
+ */
160
+ onTimeout?: (timeoutMs: number) => void;
154
161
  }
155
162
  interface JobSubscriptionOptions {
156
163
  jobEventId: string;
@@ -709,6 +716,17 @@ type JobErrorKind = 'agent-unavailable' | 'unknown';
709
716
  * `unknown` for everything else (timeouts, validation errors, transport).
710
717
  */
711
718
  declare function classifyJobError(message: string): JobErrorKind;
719
+ /**
720
+ * Signalled via `JobUpdateCallbacks.onTimeout` (and thrown by helpers that
721
+ * await a result) when the wait window expires without a result. This is a
722
+ * distinct, structured signal from a genuine provider/transport error, so
723
+ * callers can branch on the type instead of substring-matching "timed out"
724
+ * on a free-form error message (which masks real errors that happen to
725
+ * mention a timeout).
726
+ */
727
+ declare class JobWaitTimeoutError extends Error {
728
+ constructor(timeoutMs?: number);
729
+ }
712
730
 
713
731
  declare class SolanaPaymentStrategy implements PaymentStrategy {
714
732
  readonly chain = "solana";
@@ -1035,7 +1053,16 @@ declare function parsePaymentRequest(input: string, options?: ParseOptions): Par
1035
1053
  */
1036
1054
  type QuickVerifyReason = 'not_found' | 'tx_failed' | 'recipient_mismatch' | 'rpc_error' | 'invalid_input';
1037
1055
  interface QuickVerifyResult {
1038
- verified: boolean;
1056
+ /**
1057
+ * True when the recipient address received funds in this transaction.
1058
+ *
1059
+ * NOTE: this is NOT proof of a valid elisym job payment. It does not check
1060
+ * the payment `reference` key or that the amount matches the job price - it
1061
+ * is a best-effort signal for the fast discovery-ranking path, where the
1062
+ * original payment request is unavailable. For an authoritative check
1063
+ * (amount + reference) use `SolanaPaymentStrategy.verifyPayment`.
1064
+ */
1065
+ receivedFunds: boolean;
1039
1066
  txSignature: string;
1040
1067
  reason?: QuickVerifyReason;
1041
1068
  }
@@ -1087,6 +1114,12 @@ declare function aggregateNetworkStats(rpc: Rpc<SolanaRpcApi>, options?: Aggrega
1087
1114
  * Returns `null` when the PDA has not been initialized yet (admin must call
1088
1115
  * `initialize_stats` once after program upgrade).
1089
1116
  */
1117
+ /**
1118
+ * Best-effort network counters read from the on-chain PDA. These are NOT bound
1119
+ * to verified transfers and can be inflated by a malicious caller, so present
1120
+ * them as approximate/unverified, never as authoritative proof of activity. For
1121
+ * a transfer-derived figure use `aggregateNetworkStats`.
1122
+ */
1090
1123
  interface OnchainNetworkStats {
1091
1124
  jobCount: number;
1092
1125
  volumeNative: bigint;
@@ -1260,6 +1293,7 @@ declare const DEFAULTS: {
1260
1293
  declare const LIMITS: {
1261
1294
  readonly MAX_INPUT_LENGTH: 100000;
1262
1295
  readonly MAX_TIMEOUT_SECS: 600;
1296
+ readonly MAX_EXECUTION_SECS: 2147483;
1263
1297
  readonly MAX_CAPABILITIES: 20;
1264
1298
  readonly MAX_DESCRIPTION_LENGTH: 500;
1265
1299
  readonly MAX_AGENT_NAME_LENGTH: 64;
@@ -1272,4 +1306,4 @@ declare const LIMITS: {
1272
1306
  readonly MAX_POLICY_VERSION_LENGTH: 32;
1273
1307
  };
1274
1308
 
1275
- export { type Agent, type AgentPolicy, type AggregateNetworkStatsOptions, Asset, BoundedSet, type BuildTransactionOptions, type CapabilityCard, DEFAULTS, DEFAULT_KIND_OFFSET, DEFAULT_REDACT_PATHS, DiscoveryService, ELISYM_PROTOCOL_TAG, ElisymClient, type ElisymClientConfig, type ElisymClientFullConfig, ElisymIdentity, type EstimatePriorityFeeOptions, type EstimateSolFeeOptions, type GetProtocolConfigOptions, INPUT_REDACT_PATHS, type Job, type JobErrorKind, type JobStatus, type JobSubscriptionOptions, type JobUpdateCallbacks, KIND_APP_HANDLER, KIND_JOB_FEEDBACK, KIND_JOB_REQUEST, KIND_JOB_REQUEST_BASE, KIND_JOB_RESULT, KIND_JOB_RESULT_BASE, KIND_LONG_FORM_ARTICLE, KIND_PING, KIND_PONG, LAMPORTS_PER_SOL, LIMITS, MarketplaceService, MediaService, type Network, type NetworkBaselineEstimate, type NetworkBaselineOptions, type NetworkStats, type NetworkStatsResult, NostrPool, type OnchainNetworkStats, POLICY_D_TAG_PREFIX, POLICY_TYPE_REGEX, POLICY_T_TAG, PROTOCOL_PROGRAM_ID_DEVNET, type ParseOptions, type ParseResult, type ParsedPaymentRequest, type PaymentAssetRef, type PaymentInfo, type PaymentRequestData, PaymentRequestSchema, type PaymentStrategy, type PaymentValidationCode, type PaymentValidationError, type PingResult, PingService, PoliciesService, type PolicyInput, type ProtocolCluster, type ProtocolConfig, type ProtocolConfigInput, type QuickVerifyReason, type QuickVerifyResult, RELAYS, type RankKey, SECRET_REDACT_PATHS, type Signer, type SolFeeEstimate, SolanaPaymentStrategy, type SubCloser, type SubmitJobOptions, type VerifyOptions, type VerifyResult, aggregateNetworkStats, assertExpiry, assertLamports, buildPaymentInstructions, calculateProtocolFee, classifyJobError, clearPriorityFeeCache, clearProtocolConfigCache, clearQuickVerifyCache, compareAgentsByRank, computeRankKey, createPaymentRequestWithOnchainConfig, estimateNetworkBaseline, estimatePriorityFeeMicroLamports, estimateSolFeeLamports, formatFeeBreakdown, formatNetworkBaseline, formatSol, getNetworkStats, getProtocolConfig, getProtocolProgramId, jobRequestKind, jobResultKind, makeCensor, nip44Decrypt, nip44Encrypt, parsePaymentRequest, pickPercentileFee, timeAgo, toDTag, truncateKey, validateAgentName, validateExpiry, verifyJobPaymentQuick };
1309
+ export { type Agent, type AgentPolicy, type AggregateNetworkStatsOptions, Asset, BoundedSet, type BuildTransactionOptions, type CapabilityCard, DEFAULTS, DEFAULT_KIND_OFFSET, DEFAULT_REDACT_PATHS, DiscoveryService, ELISYM_PROTOCOL_TAG, ElisymClient, type ElisymClientConfig, type ElisymClientFullConfig, ElisymIdentity, type EstimatePriorityFeeOptions, type EstimateSolFeeOptions, type GetProtocolConfigOptions, INPUT_REDACT_PATHS, type Job, type JobErrorKind, type JobStatus, type JobSubscriptionOptions, type JobUpdateCallbacks, JobWaitTimeoutError, KIND_APP_HANDLER, KIND_JOB_FEEDBACK, KIND_JOB_REQUEST, KIND_JOB_REQUEST_BASE, KIND_JOB_RESULT, KIND_JOB_RESULT_BASE, KIND_LONG_FORM_ARTICLE, KIND_PING, KIND_PONG, LAMPORTS_PER_SOL, LIMITS, MarketplaceService, MediaService, type Network, type NetworkBaselineEstimate, type NetworkBaselineOptions, type NetworkStats, type NetworkStatsResult, NostrPool, type OnchainNetworkStats, POLICY_D_TAG_PREFIX, POLICY_TYPE_REGEX, POLICY_T_TAG, PROTOCOL_PROGRAM_ID_DEVNET, type ParseOptions, type ParseResult, type ParsedPaymentRequest, type PaymentAssetRef, type PaymentInfo, type PaymentRequestData, PaymentRequestSchema, type PaymentStrategy, type PaymentValidationCode, type PaymentValidationError, type PingResult, PingService, PoliciesService, type PolicyInput, type ProtocolCluster, type ProtocolConfig, type ProtocolConfigInput, type QuickVerifyReason, type QuickVerifyResult, RELAYS, type RankKey, SECRET_REDACT_PATHS, type Signer, type SolFeeEstimate, SolanaPaymentStrategy, type SubCloser, type SubmitJobOptions, type VerifyOptions, type VerifyResult, aggregateNetworkStats, assertExpiry, assertLamports, buildPaymentInstructions, calculateProtocolFee, classifyJobError, clearPriorityFeeCache, clearProtocolConfigCache, clearQuickVerifyCache, compareAgentsByRank, computeRankKey, createPaymentRequestWithOnchainConfig, estimateNetworkBaseline, estimatePriorityFeeMicroLamports, estimateSolFeeLamports, formatFeeBreakdown, formatNetworkBaseline, formatSol, getNetworkStats, getProtocolConfig, getProtocolProgramId, jobRequestKind, jobResultKind, makeCensor, nip44Decrypt, nip44Encrypt, parsePaymentRequest, pickPercentileFee, timeAgo, toDTag, truncateKey, validateAgentName, validateExpiry, verifyJobPaymentQuick };
package/dist/index.js CHANGED
@@ -73,6 +73,11 @@ var DEFAULTS = {
73
73
  var LIMITS = {
74
74
  MAX_INPUT_LENGTH: 1e5,
75
75
  MAX_TIMEOUT_SECS: 600,
76
+ // Upper bound for execution budgets (`max_execution_secs` / `execution_timeout_secs`).
77
+ // Distinct from MAX_TIMEOUT_SECS (the result-wait cap): execution budgets may be
78
+ // hours, so this exists only to keep `secs * 1000` within Node's setTimeout limit
79
+ // (2_147_483_647 ms) - a larger value overflows and fires the timer immediately.
80
+ MAX_EXECUTION_SECS: 2147483,
76
81
  MAX_CAPABILITIES: 20,
77
82
  MAX_DESCRIPTION_LENGTH: 500,
78
83
  MAX_AGENT_NAME_LENGTH: 64,
@@ -1467,6 +1472,7 @@ var DiscoveryService = class {
1467
1472
  return agents;
1468
1473
  }
1469
1474
  const deliveredJobsByProvider = /* @__PURE__ */ new Map();
1475
+ const customerByJob = /* @__PURE__ */ new Map();
1470
1476
  for (const ev of resultEvents) {
1471
1477
  if (!verifyEvent(ev)) {
1472
1478
  continue;
@@ -1486,8 +1492,13 @@ var DiscoveryService = class {
1486
1492
  deliveredJobsByProvider.set(ev.pubkey, delivered);
1487
1493
  }
1488
1494
  delivered.add(jobEventId);
1495
+ const customerPubkey = ev.tags.find((tag) => tag[0] === "p")?.[1];
1496
+ if (customerPubkey) {
1497
+ customerByJob.set(jobEventId, customerPubkey);
1498
+ }
1489
1499
  }
1490
1500
  }
1501
+ const countedRatings = /* @__PURE__ */ new Set();
1491
1502
  for (const ev of feedbackEvents) {
1492
1503
  if (!verifyEvent(ev)) {
1493
1504
  continue;
@@ -1503,19 +1514,25 @@ var DiscoveryService = class {
1503
1514
  if (ev.created_at > agent.lastSeen) {
1504
1515
  agent.lastSeen = ev.created_at;
1505
1516
  }
1517
+ const jobEventId = ev.tags.find((tag) => tag[0] === "e")?.[1];
1518
+ const hasDeliveredResult = jobEventId !== void 0 && deliveredJobsByProvider.get(targetPubkey)?.has(jobEventId) === true;
1519
+ const jobCustomer = jobEventId !== void 0 ? customerByJob.get(jobEventId) : void 0;
1520
+ const authoredByCustomer = jobCustomer !== void 0 && ev.pubkey === jobCustomer;
1506
1521
  const rating = ev.tags.find((tag) => tag[0] === "rating")?.[1];
1507
- if (rating === "1" || rating === "0") {
1508
- agent.totalRatingCount = (agent.totalRatingCount ?? 0) + 1;
1509
- if (rating === "1") {
1510
- agent.positiveCount = (agent.positiveCount ?? 0) + 1;
1522
+ if ((rating === "1" || rating === "0") && hasDeliveredResult && authoredByCustomer) {
1523
+ const ratingKey = `${ev.pubkey}:${jobEventId}`;
1524
+ if (!countedRatings.has(ratingKey)) {
1525
+ countedRatings.add(ratingKey);
1526
+ agent.totalRatingCount = (agent.totalRatingCount ?? 0) + 1;
1527
+ if (rating === "1") {
1528
+ agent.positiveCount = (agent.positiveCount ?? 0) + 1;
1529
+ }
1511
1530
  }
1512
1531
  }
1513
1532
  const status = ev.tags.find((tag) => tag[0] === "status")?.[1];
1514
1533
  const txTag = ev.tags.find((tag) => tag[0] === "tx");
1515
1534
  const txSignature = txTag?.[1];
1516
- const jobEventId = ev.tags.find((tag) => tag[0] === "e")?.[1];
1517
- const hasDeliveredResult = jobEventId !== void 0 && deliveredJobsByProvider.get(targetPubkey)?.has(jobEventId) === true;
1518
- if (status === "payment-completed" && typeof txSignature === "string" && txSignature && hasDeliveredResult) {
1535
+ if (status === "payment-completed" && typeof txSignature === "string" && txSignature && hasDeliveredResult && authoredByCustomer) {
1519
1536
  if (!agent.lastPaidJobAt || ev.created_at > agent.lastPaidJobAt) {
1520
1537
  agent.lastPaidJobAt = ev.created_at;
1521
1538
  agent.lastPaidJobTx = txSignature;
@@ -1991,7 +2008,11 @@ var MarketplaceService = class {
1991
2008
  if (!resolved) {
1992
2009
  done();
1993
2010
  try {
1994
- cb.onError?.(`Timed out waiting for response (${timeoutMs / 1e3}s).`);
2011
+ if (cb.onTimeout) {
2012
+ cb.onTimeout(timeoutMs);
2013
+ } else {
2014
+ cb.onError?.(`Timed out waiting for response (${timeoutMs / 1e3}s).`);
2015
+ }
1995
2016
  } catch {
1996
2017
  }
1997
2018
  }
@@ -3237,6 +3258,14 @@ function classifyJobError(message) {
3237
3258
  }
3238
3259
  return "unknown";
3239
3260
  }
3261
+ var JobWaitTimeoutError = class extends Error {
3262
+ constructor(timeoutMs) {
3263
+ super(
3264
+ timeoutMs === void 0 ? "Timed out waiting for job result" : `Timed out waiting for job result (${Math.round(timeoutMs / 1e3)}s)`
3265
+ );
3266
+ this.name = "JobWaitTimeoutError";
3267
+ }
3268
+ };
3240
3269
  var DEFAULT_COMPUTE_UNIT_LIMIT2 = 2e5;
3241
3270
  var DEFAULT_PRIORITY_FEE_PERCENTILE2 = 75;
3242
3271
  var BASE_FEE_LAMPORTS_PER_SIGNATURE = 5000n;
@@ -3387,35 +3416,43 @@ function formatNetworkBaseline(estimate) {
3387
3416
  return `Estimated network gas: ${total} SOL (${parts.join(" + ")}).`;
3388
3417
  }
3389
3418
  var NEGATIVE_CACHE_TTL_MS = 6e4;
3419
+ var MAX_CACHE_ENTRIES = 5e3;
3390
3420
  var verifyCache = /* @__PURE__ */ new Map();
3391
3421
  function clearQuickVerifyCache() {
3392
3422
  verifyCache.clear();
3393
3423
  }
3394
3424
  async function verifyJobPaymentQuick(rpc, txSignature, expectedRecipient) {
3395
3425
  if (!txSignature) {
3396
- return { verified: false, txSignature: "", reason: "invalid_input" };
3426
+ return { receivedFunds: false, txSignature: "", reason: "invalid_input" };
3397
3427
  }
3398
3428
  if (!expectedRecipient || !isAddress(expectedRecipient)) {
3399
- return { verified: false, txSignature, reason: "invalid_input" };
3429
+ return { receivedFunds: false, txSignature, reason: "invalid_input" };
3400
3430
  }
3401
3431
  const cacheKey2 = `${txSignature}:${expectedRecipient}`;
3402
3432
  const cached = verifyCache.get(cacheKey2);
3403
3433
  if (cached) {
3404
- if (cached.result.verified) {
3434
+ if (cached.result.receivedFunds) {
3405
3435
  return cached.result;
3406
3436
  }
3407
3437
  if (Date.now() - cached.cachedAt < NEGATIVE_CACHE_TTL_MS) {
3408
3438
  return cached.result;
3409
3439
  }
3440
+ verifyCache.delete(cacheKey2);
3410
3441
  }
3411
3442
  const result = await doVerifyOnce(rpc, txSignature, expectedRecipient);
3443
+ if (verifyCache.size >= MAX_CACHE_ENTRIES) {
3444
+ const oldest = verifyCache.keys().next().value;
3445
+ if (oldest !== void 0) {
3446
+ verifyCache.delete(oldest);
3447
+ }
3448
+ }
3412
3449
  verifyCache.set(cacheKey2, { result, cachedAt: Date.now() });
3413
3450
  return result;
3414
3451
  }
3415
3452
  async function doVerifyOnce(rpc, txSignature, expectedRecipient) {
3416
3453
  const sigStr = txSignature;
3417
3454
  if (!rpc || typeof rpc.getTransaction !== "function") {
3418
- return { verified: false, txSignature: sigStr, reason: "rpc_error" };
3455
+ return { receivedFunds: false, txSignature: sigStr, reason: "rpc_error" };
3419
3456
  }
3420
3457
  let tx;
3421
3458
  try {
@@ -3425,13 +3462,13 @@ async function doVerifyOnce(rpc, txSignature, expectedRecipient) {
3425
3462
  maxSupportedTransactionVersion: 0
3426
3463
  }).send();
3427
3464
  } catch {
3428
- return { verified: false, txSignature: sigStr, reason: "rpc_error" };
3465
+ return { receivedFunds: false, txSignature: sigStr, reason: "rpc_error" };
3429
3466
  }
3430
3467
  if (!tx) {
3431
- return { verified: false, txSignature: sigStr, reason: "not_found" };
3468
+ return { receivedFunds: false, txSignature: sigStr, reason: "not_found" };
3432
3469
  }
3433
3470
  if (!tx.meta || tx.meta.err) {
3434
- return { verified: false, txSignature: sigStr, reason: "tx_failed" };
3471
+ return { receivedFunds: false, txSignature: sigStr, reason: "tx_failed" };
3435
3472
  }
3436
3473
  const accountKeys = tx.transaction.message.accountKeys;
3437
3474
  const recipientStr = expectedRecipient;
@@ -3445,7 +3482,7 @@ async function doVerifyOnce(rpc, txSignature, expectedRecipient) {
3445
3482
  if (pre !== void 0 && post !== void 0) {
3446
3483
  const delta = BigInt(post) - BigInt(pre);
3447
3484
  if (delta > 0n) {
3448
- return { verified: true, txSignature: sigStr };
3485
+ return { receivedFunds: true, txSignature: sigStr };
3449
3486
  }
3450
3487
  }
3451
3488
  }
@@ -3463,11 +3500,11 @@ async function doVerifyOnce(rpc, txSignature, expectedRecipient) {
3463
3500
  const preAmount = pre ? BigInt(pre.uiTokenAmount.amount) : 0n;
3464
3501
  const postAmount = BigInt(post.uiTokenAmount.amount);
3465
3502
  if (postAmount > preAmount) {
3466
- return { verified: true, txSignature: sigStr };
3503
+ return { receivedFunds: true, txSignature: sigStr };
3467
3504
  }
3468
3505
  }
3469
3506
  }
3470
- return { verified: false, txSignature: sigStr, reason: "recipient_mismatch" };
3507
+ return { receivedFunds: false, txSignature: sigStr, reason: "recipient_mismatch" };
3471
3508
  }
3472
3509
  var DEFAULT_LIMIT = 1e3;
3473
3510
  var NATIVE_KEY = "native";
@@ -3562,7 +3599,12 @@ var SessionSpendLimitEntrySchema = z.object({
3562
3599
  chain: z.enum(["solana"]),
3563
3600
  token: z.string().min(1).max(16).regex(/^[a-z0-9]+$/, "token must be lowercase alphanumeric"),
3564
3601
  mint: z.string().min(1).max(64).optional(),
3565
- amount: z.number().positive().finite()
3602
+ // Stored as a string to preserve the operator's exact decimal text (avoids
3603
+ // Number round-tripping to scientific notation). Legacy configs persisted a
3604
+ // number; accept both and normalize to a positive-decimal string.
3605
+ amount: z.union([z.string(), z.number()]).transform((value) => typeof value === "number" ? String(value) : value.trim()).refine((value) => /^\d+(?:\.\d+)?$/.test(value) && /[1-9]/.test(value), {
3606
+ message: 'amount must be a positive decimal (e.g. "0.5", "1")'
3607
+ })
3566
3608
  }).strict();
3567
3609
  var GlobalConfigSchema = z.object({
3568
3610
  session_spend_limits: z.array(SessionSpendLimitEntrySchema).max(16).optional()
@@ -3762,6 +3804,6 @@ function makeCensor() {
3762
3804
  };
3763
3805
  }
3764
3806
 
3765
- export { BoundedSet, DEFAULTS, DEFAULT_KIND_OFFSET, DEFAULT_REDACT_PATHS, DiscoveryService, ELISYM_PROTOCOL_TAG, ElisymClient, ElisymIdentity, GlobalConfigSchema, INPUT_REDACT_PATHS, KIND_APP_HANDLER, KIND_JOB_FEEDBACK, KIND_JOB_REQUEST, KIND_JOB_REQUEST_BASE, KIND_JOB_RESULT, KIND_JOB_RESULT_BASE, KIND_LONG_FORM_ARTICLE, KIND_PING, KIND_PONG, KNOWN_ASSETS, LAMPORTS_PER_SOL, LIMITS, MarketplaceService, MediaService, NATIVE_SOL, NostrPool, POLICY_D_TAG_PREFIX, POLICY_TYPE_REGEX, POLICY_T_TAG, PROTOCOL_PROGRAM_ID_DEVNET, PaymentRequestSchema, PingService, PoliciesService, RELAYS, SECRET_REDACT_PATHS, SessionSpendLimitEntrySchema, SolanaPaymentStrategy, USDC_SOLANA_DEVNET, aggregateNetworkStats, assertExpiry, assertLamports, assetByKey, assetKey, buildPaymentInstructions, calculateProtocolFee, classifyJobError, clearPriorityFeeCache, clearProtocolConfigCache, clearQuickVerifyCache, compareAgentsByRank, computeRankKey, createPaymentRequestWithOnchainConfig, createSlidingWindowLimiter, estimateNetworkBaseline, estimatePriorityFeeMicroLamports, estimateSolFeeLamports, formatAssetAmount, formatFeeBreakdown, formatNetworkBaseline, formatSol, getNetworkStats, getProtocolConfig, getProtocolProgramId, jobRequestKind, jobResultKind, makeCensor, nip44Decrypt, nip44Encrypt, parseAssetAmount, parsePaymentRequest, pickPercentileFee, resolveAssetFromPaymentRequest, resolveKnownAsset, timeAgo, toDTag, truncateKey, validateAgentName, validateExpiry, verifyJobPaymentQuick };
3807
+ export { BoundedSet, DEFAULTS, DEFAULT_KIND_OFFSET, DEFAULT_REDACT_PATHS, DiscoveryService, ELISYM_PROTOCOL_TAG, ElisymClient, ElisymIdentity, GlobalConfigSchema, INPUT_REDACT_PATHS, JobWaitTimeoutError, KIND_APP_HANDLER, KIND_JOB_FEEDBACK, KIND_JOB_REQUEST, KIND_JOB_REQUEST_BASE, KIND_JOB_RESULT, KIND_JOB_RESULT_BASE, KIND_LONG_FORM_ARTICLE, KIND_PING, KIND_PONG, KNOWN_ASSETS, LAMPORTS_PER_SOL, LIMITS, MarketplaceService, MediaService, NATIVE_SOL, NostrPool, POLICY_D_TAG_PREFIX, POLICY_TYPE_REGEX, POLICY_T_TAG, PROTOCOL_PROGRAM_ID_DEVNET, PaymentRequestSchema, PingService, PoliciesService, RELAYS, SECRET_REDACT_PATHS, SessionSpendLimitEntrySchema, SolanaPaymentStrategy, USDC_SOLANA_DEVNET, aggregateNetworkStats, assertExpiry, assertLamports, assetByKey, assetKey, buildPaymentInstructions, calculateProtocolFee, classifyJobError, clearPriorityFeeCache, clearProtocolConfigCache, clearQuickVerifyCache, compareAgentsByRank, computeRankKey, createPaymentRequestWithOnchainConfig, createSlidingWindowLimiter, estimateNetworkBaseline, estimatePriorityFeeMicroLamports, estimateSolFeeLamports, formatAssetAmount, formatFeeBreakdown, formatNetworkBaseline, formatSol, getNetworkStats, getProtocolConfig, getProtocolProgramId, jobRequestKind, jobResultKind, makeCensor, nip44Decrypt, nip44Encrypt, parseAssetAmount, parsePaymentRequest, pickPercentileFee, resolveAssetFromPaymentRequest, resolveKnownAsset, timeAgo, toDTag, truncateKey, validateAgentName, validateExpiry, verifyJobPaymentQuick };
3766
3808
  //# sourceMappingURL=index.js.map
3767
3809
  //# sourceMappingURL=index.js.map