@beeperbot/sdk 0.1.0 → 0.2.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
@@ -2,8 +2,8 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
- var zod = require('zod');
6
5
  var crypto = require('crypto');
6
+ var zod = require('zod');
7
7
 
8
8
  // src/client/http.ts
9
9
 
@@ -50,6 +50,7 @@ var ErrorCodes = {
50
50
  DRAFT_NOT_FOUND: "DRAFT_NOT_FOUND",
51
51
  DRAFT_INVALID: "DRAFT_INVALID",
52
52
  // Generic
53
+ NOT_FOUND: "NOT_FOUND",
53
54
  UNKNOWN_ERROR: "UNKNOWN_ERROR"
54
55
  };
55
56
  var RETRYABLE_ERROR_CODES = [
@@ -67,8 +68,7 @@ var HTTP_STATUS_TO_ERROR_CODE = {
67
68
  400: ErrorCodes.VALIDATION_ERROR,
68
69
  401: ErrorCodes.UNAUTHORIZED,
69
70
  403: ErrorCodes.FORBIDDEN,
70
- 404: ErrorCodes.UNKNOWN_ERROR,
71
- // Specific 404s are mapped differently
71
+ 404: ErrorCodes.NOT_FOUND,
72
72
  408: ErrorCodes.TIMEOUT,
73
73
  429: ErrorCodes.RATE_LIMITED,
74
74
  500: ErrorCodes.INTERNAL_ERROR,
@@ -201,16 +201,35 @@ var BeeperError = class _BeeperError extends Error {
201
201
  * Create from an HTTP response
202
202
  */
203
203
  static fromHttpResponse(statusCode, body, requestId) {
204
- const rawBody = body;
205
- const errorData = rawBody?.error ?? rawBody;
206
- const code = errorData?.code ?? ErrorCodes.UNKNOWN_ERROR;
207
- const message = errorData?.message ?? `HTTP ${statusCode} error`;
204
+ let code = ErrorCodes.UNKNOWN_ERROR;
205
+ let message = `HTTP ${statusCode} error`;
206
+ let details;
207
+ if (body && typeof body === "object") {
208
+ const errorBody = body.error;
209
+ const parsed = errorBody && typeof errorBody === "object" ? errorBody : body;
210
+ if (parsed.code && typeof parsed.code === "string") {
211
+ const knownCodes = Object.values(ErrorCodes);
212
+ code = knownCodes.includes(parsed.code) ? parsed.code : ErrorCodes.UNKNOWN_ERROR;
213
+ }
214
+ if (parsed.message && typeof parsed.message === "string") {
215
+ message = parsed.message;
216
+ }
217
+ if (parsed.details && typeof parsed.details === "object") {
218
+ details = parsed.details;
219
+ }
220
+ }
221
+ if (code === ErrorCodes.UNKNOWN_ERROR) {
222
+ const statusFallback = HTTP_STATUS_TO_ERROR_CODE[statusCode];
223
+ if (statusFallback) {
224
+ code = statusFallback;
225
+ }
226
+ }
208
227
  const context = { statusCode };
209
228
  if (requestId !== void 0) {
210
229
  context.requestId = requestId;
211
230
  }
212
- if (errorData?.details !== void 0) {
213
- context.details = errorData.details;
231
+ if (details !== void 0) {
232
+ context.details = details;
214
233
  }
215
234
  return new _BeeperError({
216
235
  code,
@@ -228,22 +247,10 @@ var API_BASE_URLS = {
228
247
  };
229
248
  var TIMEOUTS = {
230
249
  /** Default request timeout */
231
- DEFAULT: 3e4,
232
- /** Timeout for quote requests */
233
- QUOTE: 1e4,
234
- /** Timeout for execute requests (longer due to blockchain) */
235
- EXECUTE: 6e4,
236
- /** Timeout for health checks */
237
- HEALTH: 5e3
238
- };
239
- var ENDPOINTS = {
240
- HEALTH: "/send/health",
241
- QUOTES: "/send/quotes",
242
- KEYS: "/keys"
250
+ DEFAULT: 3e4
243
251
  };
244
252
  var HEADERS = {
245
253
  IDEMPOTENCY_KEY: "Idempotency-Key",
246
- AUTHORIZATION: "Authorization",
247
254
  REQUEST_ID: "X-Request-Id",
248
255
  CONTENT_TYPE: "Content-Type"
249
256
  };
@@ -536,7 +543,7 @@ var HttpClient = class {
536
543
  buildHeaders(options) {
537
544
  const headers = {
538
545
  [HEADERS.CONTENT_TYPE]: "application/json",
539
- [HEADERS.AUTHORIZATION]: `Bearer ${this.config.apiKey}`,
546
+ "Authorization": `Bearer ${this.config.apiKey}`,
540
547
  "User-Agent": `beeper-sdk/${SDK_VERSION}`,
541
548
  ...options.headers
542
549
  };
@@ -586,8 +593,8 @@ var HttpClient = class {
586
593
  mergeSignals(signal1, signal2) {
587
594
  const controller = new AbortController();
588
595
  const abort = () => controller.abort();
589
- signal1.addEventListener("abort", abort);
590
- signal2.addEventListener("abort", abort);
596
+ signal1.addEventListener("abort", abort, { once: true });
597
+ signal2.addEventListener("abort", abort, { once: true });
591
598
  if (signal1.aborted || signal2.aborted) {
592
599
  controller.abort();
593
600
  }
@@ -595,9 +602,7 @@ var HttpClient = class {
595
602
  }
596
603
  };
597
604
  function generateIdempotencyKey() {
598
- const timestamp = Date.now().toString(36);
599
- const random = Math.random().toString(36).substring(2, 15);
600
- return `${timestamp}-${random}`;
605
+ return `idk_${crypto.randomUUID()}`;
601
606
  }
602
607
 
603
608
  // src/client/filters.schema.ts
@@ -895,7 +900,7 @@ function generateFilterDocumentation() {
895
900
  }
896
901
 
897
902
  // src/client/AgentClient.ts
898
- var ENDPOINTS2 = {
903
+ var ENDPOINTS = {
899
904
  LOOKUP: "/agent/lookup",
900
905
  INTENT: "/agent/intent",
901
906
  PRICE: "/agent/price",
@@ -905,8 +910,6 @@ var ENDPOINTS2 = {
905
910
  };
906
911
  var AgentClient = class {
907
912
  http;
908
- // @ts-expect-error Reserved for future use
909
- _debug;
910
913
  constructor(config) {
911
914
  if (!config.apiKey) {
912
915
  throw BeeperError.validation("API key is required");
@@ -920,7 +923,6 @@ var AgentClient = class {
920
923
  ...config.debug && { debug: config.debug }
921
924
  });
922
925
  this.http = new HttpClient(httpConfig);
923
- this._debug = config.debug ?? false;
924
926
  }
925
927
  /**
926
928
  * Look up a user by username, FID, or wallet address
@@ -938,7 +940,7 @@ var AgentClient = class {
938
940
  async lookup(identifier) {
939
941
  const params = typeof identifier === "number" ? { fid: identifier } : { q: identifier };
940
942
  const response = await this.http.get(
941
- ENDPOINTS2.LOOKUP,
943
+ ENDPOINTS.LOOKUP,
942
944
  { params }
943
945
  );
944
946
  return response.data.data;
@@ -958,7 +960,7 @@ var AgentClient = class {
958
960
  async getPrice(identifier) {
959
961
  const params = typeof identifier === "number" ? { fid: identifier } : { q: identifier };
960
962
  const response = await this.http.get(
961
- ENDPOINTS2.PRICE,
963
+ ENDPOINTS.PRICE,
962
964
  { params }
963
965
  );
964
966
  return response.data.data;
@@ -992,7 +994,7 @@ var AgentClient = class {
992
994
  throw BeeperError.validation("Amount must be a positive number");
993
995
  }
994
996
  const response = await this.http.post(
995
- ENDPOINTS2.INTENT,
997
+ ENDPOINTS.INTENT,
996
998
  {
997
999
  to: input.to,
998
1000
  amountUsd: amountStr,
@@ -1050,7 +1052,7 @@ var AgentClient = class {
1050
1052
  throw BeeperError.validation("Budget must be a positive number");
1051
1053
  }
1052
1054
  const response = await this.http.post(
1053
- ENDPOINTS2.ESTIMATE,
1055
+ ENDPOINTS.ESTIMATE,
1054
1056
  {
1055
1057
  filters: input.filters,
1056
1058
  budgetUsd: budgetStr,
@@ -1080,7 +1082,7 @@ var AgentClient = class {
1080
1082
  async preview(input) {
1081
1083
  const limit = Math.min(input.limit ?? 10, 20);
1082
1084
  const response = await this.http.post(
1083
- ENDPOINTS2.PREVIEW,
1085
+ ENDPOINTS.PREVIEW,
1084
1086
  {
1085
1087
  filters: input.filters,
1086
1088
  limit
@@ -1112,7 +1114,7 @@ var AgentClient = class {
1112
1114
  throw BeeperError.validation("Budget must be a positive number");
1113
1115
  }
1114
1116
  const response = await this.http.post(
1115
- ENDPOINTS2.BULK_INTENT,
1117
+ ENDPOINTS.BULK_INTENT,
1116
1118
  {
1117
1119
  filters: input.filters,
1118
1120
  budgetUsd: budgetStr,
@@ -1186,9 +1188,6 @@ function getApiKeyEnvironment(apiKey) {
1186
1188
  }
1187
1189
  return null;
1188
1190
  }
1189
- function createAuthorizationHeader(apiKey) {
1190
- return `Bearer ${apiKey}`;
1191
- }
1192
1191
  function maskApiKey(apiKey) {
1193
1192
  if (!apiKey || apiKey.length < 12) {
1194
1193
  return "***";
@@ -1217,15 +1216,7 @@ var QuoteSchema = zod.z.object({
1217
1216
  depositChainId: zod.z.number(),
1218
1217
  depositTokenAddress: zod.z.string(),
1219
1218
  expiresAt: zod.z.string(),
1220
- input: zod.z.object({
1221
- filter: zod.z.record(zod.z.unknown()),
1222
- tokenAddress: zod.z.string(),
1223
- chainId: zod.z.number(),
1224
- amountPerRecipient: zod.z.string(),
1225
- budgetCap: zod.z.string(),
1226
- memo: zod.z.string().optional(),
1227
- metadata: zod.z.record(zod.z.unknown()).optional()
1228
- }),
1219
+ input: zod.z.record(zod.z.unknown()),
1229
1220
  createdAt: zod.z.string(),
1230
1221
  updatedAt: zod.z.string()
1231
1222
  });
@@ -1250,18 +1241,24 @@ var ConfirmResultSchema = zod.z.object({
1250
1241
  status: zod.z.enum(["confirmed", "pending_verification"]),
1251
1242
  detectedAmount: zod.z.string(),
1252
1243
  sufficient: zod.z.boolean(),
1253
- blockNumber: zod.z.number(),
1254
- confirmedAt: zod.z.string()
1244
+ blockNumber: zod.z.number().int().optional(),
1245
+ confirmedAt: zod.z.string().datetime().optional()
1255
1246
  });
1256
1247
  var ExecuteResultSchema = zod.z.object({
1257
1248
  quoteId: zod.z.string(),
1258
- status: zod.z.enum(["executing", "queued"]),
1259
- estimatedCompletionAt: zod.z.string(),
1260
- batchId: zod.z.string()
1249
+ status: zod.z.enum(["executing", "queued", "pending_deployment"]),
1250
+ estimatedCompletionAt: zod.z.string().datetime().optional(),
1251
+ batchId: zod.z.string().optional(),
1252
+ deployment: zod.z.object({
1253
+ to: zod.z.string(),
1254
+ data: zod.z.string(),
1255
+ value: zod.z.string(),
1256
+ chainId: zod.z.number()
1257
+ }).optional()
1261
1258
  });
1262
1259
  var ReceiptSchema = zod.z.object({
1263
1260
  quoteId: zod.z.string(),
1264
- status: zod.z.enum(["completed", "partial", "failed"]),
1261
+ status: zod.z.enum(["completed", "partial", "failed", "executing"]),
1265
1262
  successCount: zod.z.number(),
1266
1263
  failureCount: zod.z.number(),
1267
1264
  totalSent: zod.z.string(),
@@ -1276,7 +1273,12 @@ var ReceiptSchema = zod.z.object({
1276
1273
  error: zod.z.string().optional()
1277
1274
  })
1278
1275
  ),
1279
- completedAt: zod.z.string()
1276
+ completedAt: zod.z.string().datetime().optional()
1277
+ });
1278
+ var ConfirmDeploymentResultSchema = zod.z.object({
1279
+ quoteId: zod.z.string(),
1280
+ status: zod.z.string(),
1281
+ escrowId: zod.z.string().optional()
1280
1282
  });
1281
1283
  var HealthSchema = zod.z.object({
1282
1284
  status: zod.z.enum(["healthy", "degraded", "unhealthy"]),
@@ -1288,7 +1290,7 @@ var HealthSchema = zod.z.object({
1288
1290
  oracle: zod.z.enum(["up", "down"])
1289
1291
  })
1290
1292
  });
1291
- var ENDPOINTS3 = {
1293
+ var ENDPOINTS2 = {
1292
1294
  QUOTES: "/api/v1/sdk/send/quotes",
1293
1295
  HEALTH: "/api/v1/sdk/send/health"
1294
1296
  };
@@ -1369,7 +1371,7 @@ var BeeperClient = class {
1369
1371
  ttlSeconds: opts?.ttlSeconds ?? 300
1370
1372
  };
1371
1373
  const response = await this.http.post(
1372
- ENDPOINTS3.QUOTES,
1374
+ ENDPOINTS2.QUOTES,
1373
1375
  body,
1374
1376
  {},
1375
1377
  QuoteSchema
@@ -1425,7 +1427,7 @@ var BeeperClient = class {
1425
1427
  ttlSeconds: opts?.ttlSeconds ?? 300
1426
1428
  };
1427
1429
  const response = await this.http.post(
1428
- ENDPOINTS3.QUOTES,
1430
+ ENDPOINTS2.QUOTES,
1429
1431
  body,
1430
1432
  {},
1431
1433
  AttentionQuoteSchema
@@ -1439,7 +1441,7 @@ var BeeperClient = class {
1439
1441
  */
1440
1442
  async getQuote(quoteId) {
1441
1443
  const response = await this.http.get(
1442
- `${ENDPOINTS3.QUOTES}/${quoteId}`,
1444
+ `${ENDPOINTS2.QUOTES}/${quoteId}`,
1443
1445
  {},
1444
1446
  QuoteSchema
1445
1447
  );
@@ -1459,7 +1461,7 @@ var BeeperClient = class {
1459
1461
  throw BeeperError.validation("Invalid transaction hash format");
1460
1462
  }
1461
1463
  const response = await this.http.post(
1462
- `${ENDPOINTS3.QUOTES}/${quoteId}/confirm`,
1464
+ `${ENDPOINTS2.QUOTES}/${quoteId}/confirm`,
1463
1465
  { txHash: params.txHash },
1464
1466
  { idempotencyKey: params.idempotencyKey },
1465
1467
  ConfirmResultSchema
@@ -1469,21 +1471,46 @@ var BeeperClient = class {
1469
1471
  /**
1470
1472
  * Triggers execution of the send
1471
1473
  * @param quoteId - The quote ID
1472
- * @param params - Execution parameters including idempotencyKey
1474
+ * @param params - Execution parameters including idempotencyKey and optional deploymentMode
1473
1475
  * @returns Execution result
1474
1476
  */
1475
1477
  async executeSend(quoteId, params) {
1476
1478
  if (!params.idempotencyKey) {
1477
1479
  throw BeeperError.validation("Idempotency key is required for executeSend");
1478
1480
  }
1481
+ const body = {};
1482
+ if (params.deploymentMode) {
1483
+ body.deploymentMode = params.deploymentMode;
1484
+ }
1479
1485
  const response = await this.http.post(
1480
- `${ENDPOINTS3.QUOTES}/${quoteId}/execute`,
1481
- {},
1486
+ `${ENDPOINTS2.QUOTES}/${quoteId}/execute`,
1487
+ body,
1482
1488
  { idempotencyKey: params.idempotencyKey },
1483
1489
  ExecuteResultSchema
1484
1490
  );
1485
1491
  return response.data;
1486
1492
  }
1493
+ /**
1494
+ * Confirms a client-side deployment transaction
1495
+ * @param quoteId - The quote ID
1496
+ * @param input - Deployment confirmation parameters including txHash
1497
+ * @returns Deployment confirmation result
1498
+ */
1499
+ async confirmDeployment(quoteId, input) {
1500
+ if (!quoteId) {
1501
+ throw BeeperError.validation("quoteId is required");
1502
+ }
1503
+ if (!input.txHash) {
1504
+ throw BeeperError.validation("txHash is required");
1505
+ }
1506
+ const response = await this.http.post(
1507
+ `${ENDPOINTS2.QUOTES}/${quoteId}/confirm-deployment`,
1508
+ { txHash: input.txHash },
1509
+ { idempotencyKey: `cdep_${quoteId}_${input.txHash.slice(0, 10)}` },
1510
+ ConfirmDeploymentResultSchema
1511
+ );
1512
+ return response.data;
1513
+ }
1487
1514
  /**
1488
1515
  * Gets the receipt for a completed (or failed) execution
1489
1516
  * @param quoteId - The quote ID
@@ -1491,7 +1518,7 @@ var BeeperClient = class {
1491
1518
  */
1492
1519
  async getReceiptByQuoteId(quoteId) {
1493
1520
  const response = await this.http.get(
1494
- `${ENDPOINTS3.QUOTES}/${quoteId}/receipt`,
1521
+ `${ENDPOINTS2.QUOTES}/${quoteId}/receipt`,
1495
1522
  {},
1496
1523
  ReceiptSchema
1497
1524
  );
@@ -1537,7 +1564,7 @@ var BeeperClient = class {
1537
1564
  */
1538
1565
  async health() {
1539
1566
  const response = await this.http.get(
1540
- ENDPOINTS3.HEALTH,
1567
+ ENDPOINTS2.HEALTH,
1541
1568
  {},
1542
1569
  HealthSchema
1543
1570
  );
@@ -2159,6 +2186,18 @@ function updateDraft(draft, updates) {
2159
2186
  function isReadyForQuote(draft) {
2160
2187
  return draft.status === "draft" && draft.name.length > 0 && parseFloat(draft.amount) > 0;
2161
2188
  }
2189
+
2190
+ // src/send/validation.ts
2191
+ function validateQuoteId(quoteId) {
2192
+ if (!quoteId || typeof quoteId !== "string") {
2193
+ throw BeeperError.validation("quoteId is required");
2194
+ }
2195
+ if (!/^qt_[a-zA-Z0-9]+$/.test(quoteId)) {
2196
+ throw BeeperError.validation(`Invalid quoteId format: ${quoteId}. Expected format: qt_<id>`);
2197
+ }
2198
+ }
2199
+
2200
+ // src/send/quotes.ts
2162
2201
  var ApiQuoteResponseSchema = zod.z.object({
2163
2202
  id: zod.z.string().regex(/^qt_[a-zA-Z0-9]+$/),
2164
2203
  status: zod.z.enum([
@@ -2201,13 +2240,7 @@ async function createQuote(httpClient, draft, opts) {
2201
2240
  return response.data;
2202
2241
  }
2203
2242
  async function getQuote(httpClient, quoteId) {
2204
- if (!quoteId.match(/^qt_[a-zA-Z0-9]+$/)) {
2205
- throw new BeeperError({
2206
- code: ErrorCodes.VALIDATION_ERROR,
2207
- message: "Invalid quote ID format. Expected format: qt_xxxxx",
2208
- retryable: false
2209
- });
2210
- }
2243
+ validateQuoteId(quoteId);
2211
2244
  const response = await httpClient.get(
2212
2245
  `/api/v1/sdk/send/quotes/${quoteId}`,
2213
2246
  {},
@@ -2229,7 +2262,11 @@ function getChainId(network) {
2229
2262
  polygon: 137,
2230
2263
  optimism: 10
2231
2264
  };
2232
- return chainIds[network] ?? 1;
2265
+ const id = chainIds[network];
2266
+ if (id === void 0) {
2267
+ throw BeeperError.validation(`Unsupported network: ${network}`);
2268
+ }
2269
+ return id;
2233
2270
  }
2234
2271
  function getTokenAddress(token, network) {
2235
2272
  const addresses = {
@@ -2248,15 +2285,19 @@ function getTokenAddress(token, network) {
2248
2285
  optimism: "0x94b008aA00579c1307B0EF2c499aD98a8ce58e58"
2249
2286
  }
2250
2287
  };
2251
- return addresses[token]?.[network] ?? "0x0000000000000000000000000000000000000000";
2288
+ const addr = addresses[token]?.[network];
2289
+ if (!addr) {
2290
+ throw BeeperError.validation(`Unsupported token ${token} on network ${network}`);
2291
+ }
2292
+ return addr;
2252
2293
  }
2253
2294
  var ConfirmDepositResponseSchema = zod.z.object({
2254
2295
  quoteId: zod.z.string(),
2255
2296
  status: zod.z.enum(["confirmed", "pending_verification"]),
2256
2297
  detectedAmount: zod.z.string(),
2257
2298
  sufficient: zod.z.boolean(),
2258
- blockNumber: zod.z.number().int(),
2259
- confirmedAt: zod.z.string().datetime()
2299
+ blockNumber: zod.z.number().int().optional(),
2300
+ confirmedAt: zod.z.string().datetime().optional()
2260
2301
  });
2261
2302
  async function confirmDeposit(httpClient, quoteId, params) {
2262
2303
  validateQuoteId(quoteId);
@@ -2295,26 +2336,23 @@ function validateTxHash(txHash) {
2295
2336
  });
2296
2337
  }
2297
2338
  }
2298
- function validateQuoteId(quoteId) {
2299
- if (!quoteId.match(/^qt_[a-zA-Z0-9]+$/)) {
2300
- throw new BeeperError({
2301
- code: ErrorCodes.VALIDATION_ERROR,
2302
- message: "Invalid quote ID format. Expected format: qt_xxxxx",
2303
- retryable: false
2304
- });
2305
- }
2306
- }
2307
2339
  function generateDepositIdempotencyKey(quoteId) {
2308
2340
  return `confirm-${quoteId}`;
2309
2341
  }
2310
2342
  var ExecuteSendResponseSchema = zod.z.object({
2311
2343
  quoteId: zod.z.string(),
2312
- status: zod.z.enum(["executing", "queued"]),
2313
- estimatedCompletionAt: zod.z.string().datetime(),
2314
- batchId: zod.z.string()
2315
- });
2316
- async function executeSend(httpClient, quoteId, params) {
2317
- validateQuoteId2(quoteId);
2344
+ status: zod.z.enum(["executing", "queued", "pending_deployment"]),
2345
+ estimatedCompletionAt: zod.z.string().datetime().optional(),
2346
+ batchId: zod.z.string().optional(),
2347
+ deployment: zod.z.object({
2348
+ to: zod.z.string(),
2349
+ data: zod.z.string(),
2350
+ value: zod.z.string(),
2351
+ chainId: zod.z.number()
2352
+ }).optional()
2353
+ });
2354
+ async function executeSend(httpClient, quoteId, params, options) {
2355
+ validateQuoteId(quoteId);
2318
2356
  if (!params.idempotencyKey || params.idempotencyKey.length === 0) {
2319
2357
  throw new BeeperError({
2320
2358
  code: ErrorCodes.VALIDATION_ERROR,
@@ -2322,10 +2360,13 @@ async function executeSend(httpClient, quoteId, params) {
2322
2360
  retryable: false
2323
2361
  });
2324
2362
  }
2363
+ const body = {};
2364
+ if (options?.deploymentMode) {
2365
+ body.deploymentMode = options.deploymentMode;
2366
+ }
2325
2367
  const response = await httpClient.post(
2326
2368
  `/api/v1/sdk/send/quotes/${quoteId}/execute`,
2327
- {},
2328
- // Empty body as per HTTP contract
2369
+ body,
2329
2370
  { idempotencyKey: params.idempotencyKey },
2330
2371
  ExecuteSendResponseSchema
2331
2372
  );
@@ -2335,19 +2376,13 @@ function isExecuting(result) {
2335
2376
  return result.status === "executing" || result.status === "queued";
2336
2377
  }
2337
2378
  function getEstimatedTimeRemaining(result) {
2379
+ if (!result.estimatedCompletionAt) {
2380
+ return 0;
2381
+ }
2338
2382
  const estimatedCompletion = new Date(result.estimatedCompletionAt);
2339
2383
  const now = /* @__PURE__ */ new Date();
2340
2384
  return Math.max(0, estimatedCompletion.getTime() - now.getTime());
2341
2385
  }
2342
- function validateQuoteId2(quoteId) {
2343
- if (!quoteId.match(/^qt_[a-zA-Z0-9]+$/)) {
2344
- throw new BeeperError({
2345
- code: ErrorCodes.VALIDATION_ERROR,
2346
- message: "Invalid quote ID format. Expected format: qt_xxxxx",
2347
- retryable: false
2348
- });
2349
- }
2350
- }
2351
2386
  function generateExecuteIdempotencyKey(quoteId) {
2352
2387
  return `execute-${quoteId}`;
2353
2388
  }
@@ -2360,25 +2395,19 @@ var ReceiptTransactionSchema = zod.z.object({
2360
2395
  });
2361
2396
  var ApiReceiptResponseSchema = zod.z.object({
2362
2397
  quoteId: zod.z.string(),
2363
- status: zod.z.enum(["completed", "partial", "failed"]),
2398
+ status: zod.z.enum(["completed", "partial", "failed", "executing"]),
2364
2399
  successCount: zod.z.number().int().min(0),
2365
2400
  failureCount: zod.z.number().int().min(0),
2366
2401
  totalSent: zod.z.string(),
2367
2402
  refundAmount: zod.z.string(),
2368
2403
  refundTxHash: zod.z.string().nullable().optional(),
2369
2404
  transactions: zod.z.array(ReceiptTransactionSchema),
2370
- completedAt: zod.z.string().datetime()
2405
+ completedAt: zod.z.string().datetime().optional()
2371
2406
  });
2372
2407
  var DEFAULT_MAX_ATTEMPTS = 60;
2373
2408
  var DEFAULT_INTERVAL_MS = 5e3;
2374
2409
  async function getReceipt(httpClient, quoteId) {
2375
- if (!quoteId.match(/^qt_[a-zA-Z0-9]+$/)) {
2376
- throw new BeeperError({
2377
- code: ErrorCodes.VALIDATION_ERROR,
2378
- message: "Invalid quote ID format. Expected format: qt_xxxxx",
2379
- retryable: false
2380
- });
2381
- }
2410
+ validateQuoteId(quoteId);
2382
2411
  const response = await httpClient.get(
2383
2412
  `/api/v1/sdk/send/quotes/${quoteId}/receipt`,
2384
2413
  {},
@@ -2410,7 +2439,7 @@ async function pollUntilComplete(httpClient, quoteId, opts) {
2410
2439
  }
2411
2440
  }
2412
2441
  throw new BeeperError({
2413
- code: ErrorCodes.QUOTE_EXPIRED,
2442
+ code: ErrorCodes.TIMEOUT,
2414
2443
  message: `Polling timed out after ${maxAttempts} attempts`,
2415
2444
  context: { details: { quoteId, maxAttempts } },
2416
2445
  retryable: false
@@ -2431,11 +2460,27 @@ function getFailedTransactions(receipt) {
2431
2460
  }
2432
2461
  function sleep(ms, signal) {
2433
2462
  return new Promise((resolve, reject) => {
2434
- const timeoutId = setTimeout(resolve, ms);
2435
- signal?.addEventListener("abort", () => {
2436
- clearTimeout(timeoutId);
2437
- reject(new Error("Aborted"));
2438
- });
2463
+ if (signal?.aborted) {
2464
+ reject(new BeeperError({
2465
+ code: ErrorCodes.TIMEOUT,
2466
+ message: "Poll aborted by signal",
2467
+ retryable: false
2468
+ }));
2469
+ return;
2470
+ }
2471
+ const timer = setTimeout(() => {
2472
+ if (signal) signal.removeEventListener("abort", onAbort);
2473
+ resolve();
2474
+ }, ms);
2475
+ function onAbort() {
2476
+ clearTimeout(timer);
2477
+ reject(new BeeperError({
2478
+ code: ErrorCodes.TIMEOUT,
2479
+ message: "Poll aborted by signal",
2480
+ retryable: false
2481
+ }));
2482
+ }
2483
+ if (signal) signal.addEventListener("abort", onAbort, { once: true });
2439
2484
  });
2440
2485
  }
2441
2486
 
@@ -2470,7 +2515,7 @@ var FilterExpression = class {
2470
2515
  return FilterBuilder.not(this);
2471
2516
  }
2472
2517
  };
2473
- var FilterBuilder = class {
2518
+ var FilterBuilder = class _FilterBuilder {
2474
2519
  // ===========================================================================
2475
2520
  // Logical Combinators
2476
2521
  // ===========================================================================
@@ -2480,7 +2525,7 @@ var FilterBuilder = class {
2480
2525
  */
2481
2526
  static and(filters) {
2482
2527
  if (filters.length === 0) {
2483
- throw new Error("and() requires at least one filter");
2528
+ throw BeeperError.validation("and() requires at least one filter");
2484
2529
  }
2485
2530
  if (filters.length === 1) {
2486
2531
  return filters[0];
@@ -2495,7 +2540,7 @@ var FilterBuilder = class {
2495
2540
  */
2496
2541
  static or(filters) {
2497
2542
  if (filters.length === 0) {
2498
- throw new Error("or() requires at least one filter");
2543
+ throw BeeperError.validation("or() requires at least one filter");
2499
2544
  }
2500
2545
  if (filters.length === 1) {
2501
2546
  return filters[0];
@@ -2532,7 +2577,7 @@ var FilterBuilder = class {
2532
2577
  */
2533
2578
  static activeInLastDays(days) {
2534
2579
  if (days < 1 || days > 365) {
2535
- throw new Error("activeInLastDays must be between 1 and 365");
2580
+ throw BeeperError.validation("activeInLastDays must be between 1 and 365");
2536
2581
  }
2537
2582
  return new FilterExpression({ activeInLastDays: days });
2538
2583
  }
@@ -2545,7 +2590,7 @@ var FilterBuilder = class {
2545
2590
  */
2546
2591
  static neynarScoreMin(score) {
2547
2592
  if (score < 0 || score > 1) {
2548
- throw new Error("neynarScoreMin must be between 0 and 1");
2593
+ throw BeeperError.validation("neynarScoreMin must be between 0 and 1");
2549
2594
  }
2550
2595
  return new FilterExpression({ neynarScoreMin: score });
2551
2596
  }
@@ -2555,7 +2600,7 @@ var FilterBuilder = class {
2555
2600
  */
2556
2601
  static neynarScoreMax(score) {
2557
2602
  if (score < 0 || score > 1) {
2558
- throw new Error("neynarScoreMax must be between 0 and 1");
2603
+ throw BeeperError.validation("neynarScoreMax must be between 0 and 1");
2559
2604
  }
2560
2605
  return new FilterExpression({ neynarScoreMax: score });
2561
2606
  }
@@ -2566,10 +2611,10 @@ var FilterBuilder = class {
2566
2611
  */
2567
2612
  static neynarScoreRange(min, max) {
2568
2613
  if (min !== void 0 && (min < 0 || min > 1)) {
2569
- throw new Error("neynarScoreRange min must be between 0 and 1");
2614
+ throw BeeperError.validation("neynarScoreRange min must be between 0 and 1");
2570
2615
  }
2571
2616
  if (max !== void 0 && (max < 0 || max > 1)) {
2572
- throw new Error("neynarScoreRange max must be between 0 and 1");
2617
+ throw BeeperError.validation("neynarScoreRange max must be between 0 and 1");
2573
2618
  }
2574
2619
  const range = {};
2575
2620
  if (min !== void 0) range.min = min;
@@ -2584,11 +2629,10 @@ var FilterBuilder = class {
2584
2629
  return new FilterExpression({ spamLabel: label });
2585
2630
  }
2586
2631
  /**
2587
- * Filter to exclude spam users (convenience method)
2588
- * @deprecated Use spamLabel('not_spam_only') instead
2632
+ * Convenience method: exclude spam users (shorthand for spamLabel('not_spam_only'))
2589
2633
  */
2590
2634
  static excludeSpam() {
2591
- return new FilterExpression({ spamLabel: "not_spam_only" });
2635
+ return _FilterBuilder.spamLabel("not_spam_only");
2592
2636
  }
2593
2637
  // ===========================================================================
2594
2638
  // Social Graph Filters (Followers)
@@ -2599,7 +2643,7 @@ var FilterBuilder = class {
2599
2643
  */
2600
2644
  static minFollowers(count) {
2601
2645
  if (count < 0) {
2602
- throw new Error("minFollowers must be >= 0");
2646
+ throw BeeperError.validation("minFollowers must be >= 0");
2603
2647
  }
2604
2648
  return new FilterExpression({ minFollowers: count });
2605
2649
  }
@@ -2609,7 +2653,7 @@ var FilterBuilder = class {
2609
2653
  */
2610
2654
  static maxFollowers(count) {
2611
2655
  if (count < 0) {
2612
- throw new Error("maxFollowers must be >= 0");
2656
+ throw BeeperError.validation("maxFollowers must be >= 0");
2613
2657
  }
2614
2658
  return new FilterExpression({ maxFollowers: count });
2615
2659
  }
@@ -2620,10 +2664,10 @@ var FilterBuilder = class {
2620
2664
  */
2621
2665
  static followerRange(min, max) {
2622
2666
  if (min !== void 0 && min < 0) {
2623
- throw new Error("followerRange min must be >= 0");
2667
+ throw BeeperError.validation("followerRange min must be >= 0");
2624
2668
  }
2625
2669
  if (max !== void 0 && max < 0) {
2626
- throw new Error("followerRange max must be >= 0");
2670
+ throw BeeperError.validation("followerRange max must be >= 0");
2627
2671
  }
2628
2672
  const range = {};
2629
2673
  if (min !== void 0) range.min = min;
@@ -2636,7 +2680,7 @@ var FilterBuilder = class {
2636
2680
  */
2637
2681
  static followersOf(fid) {
2638
2682
  if (fid < 1) {
2639
- throw new Error("followersOf FID must be >= 1");
2683
+ throw BeeperError.validation("followersOf FID must be >= 1");
2640
2684
  }
2641
2685
  return new FilterExpression({ followersOf: fid });
2642
2686
  }
@@ -2646,7 +2690,7 @@ var FilterBuilder = class {
2646
2690
  */
2647
2691
  static mutualsWith(fid) {
2648
2692
  if (fid < 1) {
2649
- throw new Error("mutualsWith FID must be >= 1");
2693
+ throw BeeperError.validation("mutualsWith FID must be >= 1");
2650
2694
  }
2651
2695
  return new FilterExpression({ mutualsWith: fid });
2652
2696
  }
@@ -2659,7 +2703,7 @@ var FilterBuilder = class {
2659
2703
  */
2660
2704
  static maxAttentionPriceUsd(usd) {
2661
2705
  if (usd < 0) {
2662
- throw new Error("maxAttentionPriceUsd must be >= 0");
2706
+ throw BeeperError.validation("maxAttentionPriceUsd must be >= 0");
2663
2707
  }
2664
2708
  return new FilterExpression({ maxAttentionPriceUsd: usd });
2665
2709
  }
@@ -2672,11 +2716,11 @@ var FilterBuilder = class {
2672
2716
  */
2673
2717
  static tokenHolder(opts) {
2674
2718
  if (!/^0x[a-fA-F0-9]{40}$/.test(opts.tokenAddress)) {
2675
- throw new Error("tokenAddress must be a valid Ethereum address");
2719
+ throw BeeperError.validation("tokenAddress must be a valid Ethereum address");
2676
2720
  }
2677
2721
  if (opts.minBalance !== void 0) {
2678
2722
  if (!/^[0-9]+$/.test(opts.minBalance)) {
2679
- throw new Error("minBalance must be a numeric string (wei)");
2723
+ throw BeeperError.validation("minBalance must be a numeric string (wei)");
2680
2724
  }
2681
2725
  return new FilterExpression({
2682
2726
  walletMinBalance: {
@@ -2699,24 +2743,26 @@ var FilterBuilder = class {
2699
2743
  */
2700
2744
  static tokenHolders(opts) {
2701
2745
  if (opts.length === 0) {
2702
- throw new Error("tokenHolders requires at least one token option");
2746
+ throw BeeperError.validation("tokenHolders requires at least one token option");
2703
2747
  }
2704
2748
  if (opts.length > 10) {
2705
2749
  throw new Error("tokenHolders cannot exceed 10 tokens");
2706
2750
  }
2707
2751
  for (const opt of opts) {
2708
2752
  if (!/^0x[a-fA-F0-9]{40}$/.test(opt.tokenAddress)) {
2709
- throw new Error("tokenAddress must be a valid Ethereum address");
2753
+ throw BeeperError.validation("tokenAddress must be a valid Ethereum address");
2710
2754
  }
2711
2755
  if (opt.minBalance !== void 0 && !/^[0-9]+$/.test(opt.minBalance)) {
2712
- throw new Error("minBalance must be a numeric string (wei)");
2756
+ throw BeeperError.validation("minBalance must be a numeric string (wei)");
2713
2757
  }
2714
2758
  }
2715
2759
  return new FilterExpression({
2716
2760
  tokenHolders: opts.map((o) => ({
2717
- tokenAddress: o.tokenAddress,
2718
- chainId: o.chainId,
2719
- ...o.minBalance !== void 0 ? { minBalance: o.minBalance } : {}
2761
+ contractAddress: o.tokenAddress,
2762
+ chain: o.chainId === 8453 ? "base" : "ethereum",
2763
+ tokenStandard: o.tokenStandard ?? "ERC20",
2764
+ ...o.minBalance !== void 0 ? { minBalance: o.minBalance } : {},
2765
+ ...o.tokenId !== void 0 ? { tokenId: o.tokenId } : {}
2720
2766
  }))
2721
2767
  });
2722
2768
  }
@@ -2739,11 +2785,14 @@ var FilterBuilder = class {
2739
2785
  throw new Error("minBalance must be a numeric string (wei)");
2740
2786
  }
2741
2787
  }
2788
+ const chainNames = { 1: "ethereum", 8453: "base", 42161: "arbitrum", 10: "optimism", 137: "polygon" };
2742
2789
  return new FilterExpression({
2743
2790
  cachedTokenHolders: opts.map((o) => ({
2744
- tokenAddress: o.tokenAddress,
2745
- chainId: o.chainId,
2746
- ...o.minBalance !== void 0 ? { minBalance: o.minBalance } : {}
2791
+ contractAddress: o.tokenAddress,
2792
+ chain: chainNames[o.chainId] ?? String(o.chainId),
2793
+ tokenStandard: o.tokenStandard ?? "ERC20",
2794
+ ...o.minBalance !== void 0 ? { minBalance: o.minBalance } : {},
2795
+ ...o.tokenId !== void 0 ? { tokenId: o.tokenId } : {}
2747
2796
  }))
2748
2797
  });
2749
2798
  }
@@ -2805,7 +2854,7 @@ var FilterBuilder = class {
2805
2854
  */
2806
2855
  static minTenureDays(days) {
2807
2856
  if (days < 0) {
2808
- throw new Error("minTenureDays must be >= 0");
2857
+ throw BeeperError.validation("minTenureDays must be >= 0");
2809
2858
  }
2810
2859
  return new FilterExpression({ minTenureDays: days });
2811
2860
  }
@@ -2825,10 +2874,10 @@ var FilterBuilder = class {
2825
2874
  */
2826
2875
  static userIds(ids) {
2827
2876
  if (ids.length === 0) {
2828
- throw new Error("userIds requires at least one ID");
2877
+ throw BeeperError.validation("userIds requires at least one ID");
2829
2878
  }
2830
2879
  if (ids.length > 1e3) {
2831
- throw new Error("userIds cannot exceed 1000 IDs");
2880
+ throw BeeperError.validation("userIds cannot exceed 1000 IDs");
2832
2881
  }
2833
2882
  return new FilterExpression({ userIds: ids });
2834
2883
  }
@@ -2845,10 +2894,10 @@ var FilterBuilder = class {
2845
2894
  */
2846
2895
  static fids(fids) {
2847
2896
  if (fids.length === 0) {
2848
- throw new Error("fids requires at least one FID");
2897
+ throw BeeperError.validation("fids requires at least one FID");
2849
2898
  }
2850
2899
  if (fids.length > 1e3) {
2851
- throw new Error("fids cannot exceed 1000 FIDs");
2900
+ throw BeeperError.validation("fids cannot exceed 1000 FIDs");
2852
2901
  }
2853
2902
  return new FilterExpression({ fids });
2854
2903
  }
@@ -2861,7 +2910,7 @@ var FilterBuilder = class {
2861
2910
  */
2862
2911
  static hasTag(tag) {
2863
2912
  if (tag.length > 64) {
2864
- throw new Error("Tag must be 64 characters or less");
2913
+ throw BeeperError.validation("Tag must be 64 characters or less");
2865
2914
  }
2866
2915
  return new FilterExpression({ hasTag: tag });
2867
2916
  }
@@ -2871,7 +2920,7 @@ var FilterBuilder = class {
2871
2920
  */
2872
2921
  static hasAnyTag(tags) {
2873
2922
  if (tags.length === 0 || tags.length > 20) {
2874
- throw new Error("hasAnyTag requires 1-20 tags");
2923
+ throw BeeperError.validation("hasAnyTag requires 1-20 tags");
2875
2924
  }
2876
2925
  return new FilterExpression({ hasAnyTag: tags });
2877
2926
  }
@@ -2881,7 +2930,7 @@ var FilterBuilder = class {
2881
2930
  */
2882
2931
  static hasAllTags(tags) {
2883
2932
  if (tags.length === 0 || tags.length > 20) {
2884
- throw new Error("hasAllTags requires 1-20 tags");
2933
+ throw BeeperError.validation("hasAllTags requires 1-20 tags");
2885
2934
  }
2886
2935
  return new FilterExpression({ hasAllTags: tags });
2887
2936
  }
@@ -2952,17 +3001,17 @@ var FilterBuilder = class {
2952
3001
  */
2953
3002
  static timezones(zones) {
2954
3003
  if (zones.length === 0) {
2955
- throw new Error("timezones requires at least one timezone");
3004
+ throw BeeperError.validation("timezones requires at least one timezone");
2956
3005
  }
2957
3006
  if (zones.length > 24) {
2958
3007
  throw new Error("timezones cannot exceed 24 entries");
2959
3008
  }
2960
3009
  for (const zone of zones) {
2961
3010
  if (zone.offset < -12 || zone.offset > 14) {
2962
- throw new Error("timezone offset must be between -12 and 14");
3011
+ throw BeeperError.validation("timezone offset must be between -12 and 14");
2963
3012
  }
2964
3013
  if (zone.range !== void 0 && (zone.range < 0 || zone.range > 12)) {
2965
- throw new Error("timezone range must be between 0 and 12");
3014
+ throw BeeperError.validation("timezone range must be between 0 and 12");
2966
3015
  }
2967
3016
  }
2968
3017
  return new FilterExpression({ timezones: zones });
@@ -2973,28 +3022,28 @@ var FilterBuilder = class {
2973
3022
  */
2974
3023
  static countries(codes) {
2975
3024
  if (codes.length === 0) {
2976
- throw new Error("countries requires at least one country code");
3025
+ throw BeeperError.validation("countries requires at least one country code");
2977
3026
  }
2978
3027
  if (codes.length > 50) {
2979
3028
  throw new Error("countries cannot exceed 50 country codes");
2980
3029
  }
2981
3030
  for (const code of codes) {
2982
3031
  if (!/^[A-Z]{2}$/.test(code)) {
2983
- throw new Error("Country codes must be ISO 3166-1 alpha-2 format (e.g., US, CA, GB)");
3032
+ throw BeeperError.validation("Country codes must be ISO 3166-1 alpha-2 format (e.g., US, CA, GB)");
2984
3033
  }
2985
3034
  }
2986
- return new FilterExpression({ countries: codes.map((code) => ({ code })) });
3035
+ return new FilterExpression({ countries: codes.map((c) => ({ code: c })) });
2987
3036
  }
2988
3037
  // ===========================================================================
2989
3038
  // Engagement & Quality Filters
2990
3039
  // ===========================================================================
2991
3040
  /**
2992
3041
  * Filter users with quotient score >= minimum
2993
- * @param score - Minimum quotient score (0-1, where 0.5=Casual, 0.75=Influential, 0.9=Exceptional)
3042
+ * @param score - Minimum quotient score (0-1)
2994
3043
  */
2995
3044
  static quotientScoreMin(score) {
2996
3045
  if (score < 0 || score > 1) {
2997
- throw new Error("quotientScoreMin must be between 0 and 1");
3046
+ throw BeeperError.validation("quotientScoreMin must be between 0 and 1");
2998
3047
  }
2999
3048
  return new FilterExpression({ quotientScoreMin: score });
3000
3049
  }
@@ -3004,7 +3053,7 @@ var FilterBuilder = class {
3004
3053
  */
3005
3054
  static quotientScoreMax(score) {
3006
3055
  if (score < 0 || score > 1) {
3007
- throw new Error("quotientScoreMax must be between 0 and 1");
3056
+ throw BeeperError.validation("quotientScoreMax must be between 0 and 1");
3008
3057
  }
3009
3058
  return new FilterExpression({ quotientScoreMax: score });
3010
3059
  }
@@ -3031,7 +3080,7 @@ var FilterBuilder = class {
3031
3080
  */
3032
3081
  static minBatteryPercentage(pct) {
3033
3082
  if (pct < 0 || pct > 100) {
3034
- throw new Error("minBatteryPercentage must be between 0 and 100");
3083
+ throw BeeperError.validation("minBatteryPercentage must be between 0 and 100");
3035
3084
  }
3036
3085
  return new FilterExpression({ minBatteryPercentage: pct });
3037
3086
  }
@@ -3041,7 +3090,7 @@ var FilterBuilder = class {
3041
3090
  */
3042
3091
  static hasRechargedInLastDays(days) {
3043
3092
  if (days < 1) {
3044
- throw new Error("hasRechargedInLastDays must be >= 1");
3093
+ throw BeeperError.validation("hasRechargedInLastDays must be >= 1");
3045
3094
  }
3046
3095
  return new FilterExpression({ hasRechargedInLastDays: days });
3047
3096
  }
@@ -3075,7 +3124,7 @@ var FilterBuilder = class {
3075
3124
  */
3076
3125
  static minCastCount(count) {
3077
3126
  if (count < 0) {
3078
- throw new Error("minCastCount must be >= 0");
3127
+ throw BeeperError.validation("minCastCount must be >= 0");
3079
3128
  }
3080
3129
  return new FilterExpression({ minCastCount: count });
3081
3130
  }
@@ -3089,18 +3138,6 @@ var FilterBuilder = class {
3089
3138
  static orderBy(order) {
3090
3139
  return new FilterExpression({ orderBy: order });
3091
3140
  }
3092
- /**
3093
- * Limit the number of results
3094
- * @param n - Maximum number of results
3095
- * @deprecated Limit is controlled by budgetCap, not this filter. This method will be removed.
3096
- */
3097
- static limit(n) {
3098
- console.warn("FilterBuilder.limit() is deprecated. Use budgetCap to control result count.");
3099
- if (n < 1 || n > 1e4) {
3100
- throw new Error("limit must be between 1 and 10000");
3101
- }
3102
- return new FilterExpression({ limit: n });
3103
- }
3104
3141
  };
3105
3142
  var GasTierSchema = zod.z.enum(["slow", "standard", "fast"]);
3106
3143
  var QuoteOptionsSchema = zod.z.object({
@@ -3220,7 +3257,6 @@ exports.DraftInputSchema = DraftInputSchema;
3220
3257
  exports.DraftSchema = DraftSchema;
3221
3258
  exports.DraftStatusSchema = DraftStatusSchema;
3222
3259
  exports.DraftUpdateSchema = DraftUpdateSchema;
3223
- exports.ENDPOINTS = ENDPOINTS;
3224
3260
  exports.ErrorCodes = ErrorCodes;
3225
3261
  exports.ExcludePingedTodayFilterSchema = ExcludePingedTodayFilterSchema;
3226
3262
  exports.ExcludeUsersFilterSchema = ExcludeUsersFilterSchema;
@@ -3299,7 +3335,6 @@ exports.TokenHolderFilterSchema = TokenHolderFilterSchema;
3299
3335
  exports.TokenTypeSchema = TokenTypeSchema;
3300
3336
  exports.TransferStatusSchema = TransferStatusSchema;
3301
3337
  exports.VerifiedOnlyFilterSchema = VerifiedOnlyFilterSchema;
3302
- exports.createAuthorizationHeader = createAuthorizationHeader;
3303
3338
  exports.createHttpConfig = createHttpConfig;
3304
3339
  exports.default = BeeperClient_default;
3305
3340
  exports.describeFilters = describeFilters;