@secondlayer/sdk 6.0.0 → 6.1.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.js CHANGED
@@ -25,6 +25,19 @@ class VersionConflictError extends ApiError {
25
25
 
26
26
  // src/base.ts
27
27
  var DEFAULT_BASE_URL = "https://api.secondlayer.tools";
28
+ function buildQuery(params) {
29
+ const search = new URLSearchParams;
30
+ for (const [name, value] of Object.entries(params)) {
31
+ if (value === undefined || value === null)
32
+ continue;
33
+ const serialized = Array.isArray(value) ? value.join(",") : String(value);
34
+ if (serialized.length === 0)
35
+ continue;
36
+ search.set(name, serialized);
37
+ }
38
+ const query = search.toString();
39
+ return query ? `?${query}` : "";
40
+ }
28
41
 
29
42
  class BaseClient {
30
43
  baseUrl;
@@ -312,11 +325,6 @@ class Subgraphs extends BaseClient {
312
325
  }
313
326
  }
314
327
  // src/index-api/client.ts
315
- function appendSearchParam(params, name, value) {
316
- if (value === undefined || value === null)
317
- return;
318
- params.set(name, String(value));
319
- }
320
328
  function firstWalkFromHeight(params) {
321
329
  if (params.fromHeight !== undefined)
322
330
  return params.fromHeight;
@@ -346,31 +354,29 @@ class Index extends BaseClient {
346
354
  walk: (params = {}) => this.walkContractCalls(params)
347
355
  };
348
356
  async listFtTransfers(params = {}) {
349
- const searchParams = new URLSearchParams;
350
- appendSearchParam(searchParams, "cursor", params.cursor);
351
- appendSearchParam(searchParams, "from_cursor", params.fromCursor);
352
- appendSearchParam(searchParams, "limit", params.limit);
353
- appendSearchParam(searchParams, "contract_id", params.contractId);
354
- appendSearchParam(searchParams, "sender", params.sender);
355
- appendSearchParam(searchParams, "recipient", params.recipient);
356
- appendSearchParam(searchParams, "from_height", params.fromHeight);
357
- appendSearchParam(searchParams, "to_height", params.toHeight);
358
- const query = searchParams.toString();
359
- return this.request("GET", `/v1/index/ft-transfers${query ? `?${query}` : ""}`);
357
+ return this.request("GET", `/v1/index/ft-transfers${buildQuery({
358
+ cursor: params.cursor,
359
+ from_cursor: params.fromCursor,
360
+ limit: params.limit,
361
+ contract_id: params.contractId,
362
+ sender: params.sender,
363
+ recipient: params.recipient,
364
+ from_height: params.fromHeight,
365
+ to_height: params.toHeight
366
+ })}`);
360
367
  }
361
368
  async listNftTransfers(params = {}) {
362
- const searchParams = new URLSearchParams;
363
- appendSearchParam(searchParams, "cursor", params.cursor);
364
- appendSearchParam(searchParams, "from_cursor", params.fromCursor);
365
- appendSearchParam(searchParams, "limit", params.limit);
366
- appendSearchParam(searchParams, "contract_id", params.contractId);
367
- appendSearchParam(searchParams, "asset_identifier", params.assetIdentifier);
368
- appendSearchParam(searchParams, "sender", params.sender);
369
- appendSearchParam(searchParams, "recipient", params.recipient);
370
- appendSearchParam(searchParams, "from_height", params.fromHeight);
371
- appendSearchParam(searchParams, "to_height", params.toHeight);
372
- const query = searchParams.toString();
373
- return this.request("GET", `/v1/index/nft-transfers${query ? `?${query}` : ""}`);
369
+ return this.request("GET", `/v1/index/nft-transfers${buildQuery({
370
+ cursor: params.cursor,
371
+ from_cursor: params.fromCursor,
372
+ limit: params.limit,
373
+ contract_id: params.contractId,
374
+ asset_identifier: params.assetIdentifier,
375
+ sender: params.sender,
376
+ recipient: params.recipient,
377
+ from_height: params.fromHeight,
378
+ to_height: params.toHeight
379
+ })}`);
374
380
  }
375
381
  async* walkFtTransfers(params = {}) {
376
382
  const batchSize = params.batchSize ?? 200;
@@ -423,18 +429,18 @@ class Index extends BaseClient {
423
429
  }
424
430
  }
425
431
  async listEvents(params) {
426
- const searchParams = new URLSearchParams;
427
- appendSearchParam(searchParams, "event_type", params.eventType);
428
- appendSearchParam(searchParams, "cursor", params.cursor);
429
- appendSearchParam(searchParams, "from_cursor", params.fromCursor);
430
- appendSearchParam(searchParams, "limit", params.limit);
431
- appendSearchParam(searchParams, "contract_id", params.contractId);
432
- appendSearchParam(searchParams, "asset_identifier", params.assetIdentifier);
433
- appendSearchParam(searchParams, "sender", params.sender);
434
- appendSearchParam(searchParams, "recipient", params.recipient);
435
- appendSearchParam(searchParams, "from_height", params.fromHeight);
436
- appendSearchParam(searchParams, "to_height", params.toHeight);
437
- return this.request("GET", `/v1/index/events?${searchParams.toString()}`);
432
+ return this.request("GET", `/v1/index/events${buildQuery({
433
+ event_type: params.eventType,
434
+ cursor: params.cursor,
435
+ from_cursor: params.fromCursor,
436
+ limit: params.limit,
437
+ contract_id: params.contractId,
438
+ asset_identifier: params.assetIdentifier,
439
+ sender: params.sender,
440
+ recipient: params.recipient,
441
+ from_height: params.fromHeight,
442
+ to_height: params.toHeight
443
+ })}`);
438
444
  }
439
445
  async* walkEvents(params) {
440
446
  const batchSize = params.batchSize ?? 200;
@@ -462,17 +468,16 @@ class Index extends BaseClient {
462
468
  }
463
469
  }
464
470
  async listContractCalls(params = {}) {
465
- const searchParams = new URLSearchParams;
466
- appendSearchParam(searchParams, "cursor", params.cursor);
467
- appendSearchParam(searchParams, "from_cursor", params.fromCursor);
468
- appendSearchParam(searchParams, "limit", params.limit);
469
- appendSearchParam(searchParams, "contract_id", params.contractId);
470
- appendSearchParam(searchParams, "function_name", params.functionName);
471
- appendSearchParam(searchParams, "sender", params.sender);
472
- appendSearchParam(searchParams, "from_height", params.fromHeight);
473
- appendSearchParam(searchParams, "to_height", params.toHeight);
474
- const query = searchParams.toString();
475
- return this.request("GET", `/v1/index/contract-calls${query ? `?${query}` : ""}`);
471
+ return this.request("GET", `/v1/index/contract-calls${buildQuery({
472
+ cursor: params.cursor,
473
+ from_cursor: params.fromCursor,
474
+ limit: params.limit,
475
+ contract_id: params.contractId,
476
+ function_name: params.functionName,
477
+ sender: params.sender,
478
+ from_height: params.fromHeight,
479
+ to_height: params.toHeight
480
+ })}`);
476
481
  }
477
482
  async* walkContractCalls(params = {}) {
478
483
  const batchSize = params.batchSize ?? 200;
@@ -504,7 +509,74 @@ class Index extends BaseClient {
504
509
  // src/streams/client.ts
505
510
  import { ed25519 } from "@secondlayer/shared";
506
511
 
512
+ // src/streams/errors.ts
513
+ class AuthError extends Error {
514
+ status = 401;
515
+ constructor(message = "API key invalid or expired.") {
516
+ super(message);
517
+ this.name = "AuthError";
518
+ }
519
+ }
520
+
521
+ class RateLimitError extends Error {
522
+ retryAfter;
523
+ status = 429;
524
+ constructor(message = "Rate limited. Try again later.", retryAfter) {
525
+ super(message);
526
+ this.retryAfter = retryAfter;
527
+ this.name = "RateLimitError";
528
+ }
529
+ }
530
+
531
+ class ValidationError extends Error {
532
+ status;
533
+ body;
534
+ constructor(message, status, body) {
535
+ super(message);
536
+ this.status = status;
537
+ this.body = body;
538
+ this.name = "ValidationError";
539
+ }
540
+ }
541
+
542
+ class StreamsServerError extends Error {
543
+ status;
544
+ body;
545
+ constructor(message, status, body) {
546
+ super(message);
547
+ this.status = status;
548
+ this.body = body;
549
+ this.name = "StreamsServerError";
550
+ }
551
+ }
552
+
553
+ class StreamsSignatureError extends Error {
554
+ constructor(message = "Streams response signature verification failed.") {
555
+ super(message);
556
+ this.name = "StreamsSignatureError";
557
+ }
558
+ }
559
+
560
+ // src/streams/cursor.ts
561
+ var Cursor = {
562
+ atHeight(height) {
563
+ return `${height}:0`;
564
+ },
565
+ parse(cursor) {
566
+ const parts = cursor.split(":");
567
+ const blockHeight = Number(parts[0]);
568
+ const eventIndex = Number(parts[1]);
569
+ if (parts.length !== 2 || !Number.isInteger(blockHeight) || !Number.isInteger(eventIndex)) {
570
+ throw new ValidationError(`Invalid stream cursor "${cursor}"; expected "<block>:<index>" (e.g. "951475:3").`, 400);
571
+ }
572
+ return { blockHeight, eventIndex };
573
+ }
574
+ };
575
+
507
576
  // src/streams/consumer.ts
577
+ function reorgKey(reorg) {
578
+ return `${reorg.detected_at}|${reorg.fork_point_height}|${reorg.new_canonical_tip}`;
579
+ }
508
580
  async function defaultSleep(ms, signal) {
509
581
  if (signal?.aborted)
510
582
  return;
@@ -521,10 +593,12 @@ async function defaultSleep(ms, signal) {
521
593
  async function consumeStreamsEvents(opts) {
522
594
  const sleep = opts.sleep ?? defaultSleep;
523
595
  const mode = opts.mode ?? "tail";
596
+ const finalizedOnly = opts.finalizedOnly ?? false;
524
597
  const emptyBackoffMs = opts.emptyBackoffMs ?? 500;
525
598
  const maxPages = opts.maxPages ?? Number.POSITIVE_INFINITY;
526
599
  const maxEmptyPolls = opts.maxEmptyPolls ?? Number.POSITIVE_INFINITY;
527
600
  let cursor = opts.fromCursor ?? null;
601
+ const handledReorgs = new Set;
528
602
  let pages = 0;
529
603
  let emptyPolls = 0;
530
604
  while (pages < maxPages && emptyPolls < maxEmptyPolls && !opts.signal?.aborted) {
@@ -539,14 +613,32 @@ async function consumeStreamsEvents(opts) {
539
613
  assetIdentifier: opts.assetIdentifier
540
614
  });
541
615
  pages++;
542
- const returnedCursor = await opts.onBatch(envelope.events, envelope);
543
- const nextCursor = returnedCursor ?? envelope.next_cursor;
616
+ if (!finalizedOnly && opts.onReorg) {
617
+ const fresh = envelope.reorgs.filter((reorg) => !handledReorgs.has(reorgKey(reorg))).sort((a, b) => a.fork_point_height - b.fork_point_height);
618
+ if (fresh.length > 0) {
619
+ const forkPoint = Math.min(...fresh.map((reorg) => reorg.fork_point_height));
620
+ const rewind = Cursor.atHeight(forkPoint);
621
+ for (const reorg of fresh) {
622
+ await opts.onReorg(reorg, { cursor: rewind });
623
+ handledReorgs.add(reorgKey(reorg));
624
+ }
625
+ cursor = rewind;
626
+ emptyPolls = 0;
627
+ continue;
628
+ }
629
+ }
630
+ const emitted = finalizedOnly ? envelope.events.filter((event) => event.finalized) : envelope.events;
631
+ const checkpoint = finalizedOnly ? emitted.at(-1)?.cursor ?? cursor : envelope.next_cursor;
632
+ const returnedCursor = await opts.onBatch(emitted, envelope, {
633
+ cursor: checkpoint
634
+ });
635
+ const nextCursor = returnedCursor ?? checkpoint;
544
636
  if (nextCursor && nextCursor !== cursor) {
545
637
  cursor = nextCursor;
546
638
  emptyPolls = 0;
547
639
  continue;
548
640
  }
549
- if (envelope.events.length === 0) {
641
+ if (emitted.length === 0) {
550
642
  emptyPolls++;
551
643
  if (mode === "bounded") {
552
644
  return { cursor, pages, emptyPolls };
@@ -602,56 +694,6 @@ async function* streamStreamsEvents(opts) {
602
694
 
603
695
  // src/streams/dumps.ts
604
696
  import { createHash } from "node:crypto";
605
-
606
- // src/streams/errors.ts
607
- class AuthError extends Error {
608
- status = 401;
609
- constructor(message = "API key invalid or expired.") {
610
- super(message);
611
- this.name = "AuthError";
612
- }
613
- }
614
-
615
- class RateLimitError extends Error {
616
- retryAfter;
617
- status = 429;
618
- constructor(message = "Rate limited. Try again later.", retryAfter) {
619
- super(message);
620
- this.retryAfter = retryAfter;
621
- this.name = "RateLimitError";
622
- }
623
- }
624
-
625
- class ValidationError extends Error {
626
- status;
627
- body;
628
- constructor(message, status, body) {
629
- super(message);
630
- this.status = status;
631
- this.body = body;
632
- this.name = "ValidationError";
633
- }
634
- }
635
-
636
- class StreamsServerError extends Error {
637
- status;
638
- body;
639
- constructor(message, status, body) {
640
- super(message);
641
- this.status = status;
642
- this.body = body;
643
- this.name = "StreamsServerError";
644
- }
645
- }
646
-
647
- class StreamsSignatureError extends Error {
648
- constructor(message = "Streams response signature verification failed.") {
649
- super(message);
650
- this.name = "StreamsSignatureError";
651
- }
652
- }
653
-
654
- // src/streams/dumps.ts
655
697
  function createStreamsDumps(opts) {
656
698
  const baseUrl = opts.baseUrl?.replace(/\/+$/, "");
657
699
  function requireBaseUrl() {
@@ -690,8 +732,12 @@ function createStreamsDumps(opts) {
690
732
  function cursorTuple(cursor) {
691
733
  if (!cursor)
692
734
  return [-1, -1];
693
- const [block, index] = cursor.split(":");
694
- return [Number(block), Number(index)];
735
+ const parts = cursor.split(":");
736
+ const [block, index] = parts.map(Number);
737
+ if (parts.length !== 2 || !Number.isInteger(block) || !Number.isInteger(index)) {
738
+ throw new ValidationError(`Invalid stream cursor "${cursor}"; expected "<block>:<index>" (e.g. "951475:3").`, 400);
739
+ }
740
+ return [block, index];
695
741
  }
696
742
  function maxCursor(a, b) {
697
743
  const [ah, ai] = cursorTuple(a);
@@ -702,18 +748,6 @@ var DEFAULT_STREAMS_BASE_URL = "https://api.secondlayer.tools";
702
748
  function normalizeBaseUrl(baseUrl) {
703
749
  return baseUrl.replace(/\/+$/, "");
704
750
  }
705
- function appendSearchParam2(params, name, value) {
706
- if (value === undefined || value === null)
707
- return;
708
- params.set(name, String(value));
709
- }
710
- function appendListParam(params, name, value) {
711
- if (value === undefined || value === null)
712
- return;
713
- const joined = Array.isArray(value) ? value.join(",") : value;
714
- if (joined.length > 0)
715
- params.set(name, joined);
716
- }
717
751
  async function responseBody(response) {
718
752
  const text = await response.text();
719
753
  if (text.length === 0)
@@ -835,23 +869,18 @@ function createStreamsClient(options) {
835
869
  });
836
870
  };
837
871
  async function listEvents(params = {}) {
838
- const searchParams = new URLSearchParams;
839
- appendSearchParam2(searchParams, "cursor", params.cursor);
840
- appendSearchParam2(searchParams, "from_height", params.fromHeight);
841
- appendSearchParam2(searchParams, "to_height", params.toHeight);
842
- appendSearchParam2(searchParams, "limit", params.limit);
843
- appendListParam(searchParams, "contract_id", params.contractId);
844
- appendListParam(searchParams, "sender", params.sender);
845
- appendListParam(searchParams, "recipient", params.recipient);
846
- appendSearchParam2(searchParams, "asset_identifier", params.assetIdentifier);
847
- if (params.types?.length) {
848
- searchParams.set("types", params.types.join(","));
849
- }
850
- if (params.notTypes?.length) {
851
- searchParams.set("not_types", params.notTypes.join(","));
852
- }
853
- const query = searchParams.toString();
854
- return request(`/v1/streams/events${query ? `?${query}` : ""}`);
872
+ return request(`/v1/streams/events${buildQuery({
873
+ cursor: params.cursor,
874
+ from_height: params.fromHeight,
875
+ to_height: params.toHeight,
876
+ limit: params.limit,
877
+ contract_id: params.contractId,
878
+ sender: params.sender,
879
+ recipient: params.recipient,
880
+ asset_identifier: params.assetIdentifier,
881
+ types: params.types,
882
+ not_types: params.notTypes
883
+ })}`);
855
884
  }
856
885
  return {
857
886
  events: {
@@ -863,6 +892,7 @@ function createStreamsClient(options) {
863
892
  return consumeStreamsEvents({
864
893
  fromCursor: params.fromCursor,
865
894
  mode: params.mode,
895
+ finalizedOnly: params.finalizedOnly,
866
896
  types: params.types,
867
897
  notTypes: params.notTypes,
868
898
  contractId: params.contractId,
@@ -872,6 +902,7 @@ function createStreamsClient(options) {
872
902
  batchSize: params.batchSize ?? 100,
873
903
  fetchEvents,
874
904
  onBatch: params.onBatch,
905
+ onReorg: params.onReorg,
875
906
  emptyBackoffMs: params.emptyBackoffMs,
876
907
  maxPages: params.maxPages,
877
908
  maxEmptyPolls: params.maxEmptyPolls,
@@ -926,11 +957,10 @@ function createStreamsClient(options) {
926
957
  },
927
958
  reorgs: {
928
959
  list(params) {
929
- const searchParams = new URLSearchParams;
930
- appendSearchParam2(searchParams, "since", params.since);
931
- appendSearchParam2(searchParams, "limit", params.limit);
932
- const query = searchParams.toString();
933
- return request(`/v1/streams/reorgs${query ? `?${query}` : ""}`);
960
+ return request(`/v1/streams/reorgs${buildQuery({
961
+ since: params.since,
962
+ limit: params.limit
963
+ })}`);
934
964
  }
935
965
  },
936
966
  dumps,
@@ -1012,127 +1042,8 @@ function getSubgraph(def, options = {}) {
1012
1042
  }
1013
1043
  return new Subgraphs(options).typed(def);
1014
1044
  }
1015
- // src/streams/ft-transfer.ts
1016
- function requireString(payload, field) {
1017
- const value = payload[field];
1018
- if (typeof value !== "string" || value.length === 0) {
1019
- throw new Error(`ft_transfer payload missing ${field}`);
1020
- }
1021
- return value;
1022
- }
1023
- function parseAssetIdentifier(assetIdentifier) {
1024
- const [contractId, tokenName] = assetIdentifier.split("::");
1025
- if (!contractId) {
1026
- throw new Error("ft_transfer payload has malformed asset_identifier");
1027
- }
1028
- return {
1029
- contract_id: contractId,
1030
- token_name: tokenName && tokenName.length > 0 ? tokenName : null
1031
- };
1032
- }
1033
- function isFtTransfer(event) {
1034
- return event.event_type === "ft_transfer";
1035
- }
1036
- function decodeFtTransfer(event) {
1037
- if (!isFtTransfer(event)) {
1038
- throw new Error(`Expected ft_transfer event, got ${event.event_type}`);
1039
- }
1040
- const payload = event.payload;
1041
- const assetIdentifier = requireString(payload, "asset_identifier");
1042
- const sender = requireString(payload, "sender");
1043
- const recipient = requireString(payload, "recipient");
1044
- const amount = requireString(payload, "amount");
1045
- if (!/^(0|[1-9]\d*)$/.test(amount)) {
1046
- throw new Error("ft_transfer payload has malformed amount");
1047
- }
1048
- const { contract_id, token_name } = parseAssetIdentifier(assetIdentifier);
1049
- return {
1050
- cursor: event.cursor,
1051
- block_height: event.block_height,
1052
- tx_id: event.tx_id,
1053
- tx_index: event.tx_index,
1054
- event_index: event.event_index,
1055
- event_type: event.event_type,
1056
- decoded_payload: {
1057
- asset_identifier: assetIdentifier,
1058
- contract_id: event.contract_id ?? contract_id,
1059
- token_name,
1060
- sender,
1061
- recipient,
1062
- amount
1063
- },
1064
- source_cursor: event.cursor
1065
- };
1066
- }
1067
- // src/streams/nft-transfer.ts
1068
- function requireString2(payload, field) {
1069
- const value = payload[field];
1070
- if (typeof value !== "string" || value.length === 0) {
1071
- throw new Error(`nft_transfer payload missing ${field}`);
1072
- }
1073
- return value;
1074
- }
1075
- function requireHexValue(payload) {
1076
- const rawValue = payload.raw_value;
1077
- if (typeof rawValue === "string") {
1078
- if (!/^0x[0-9a-fA-F]*$/.test(rawValue)) {
1079
- throw new Error("nft_transfer payload has malformed value");
1080
- }
1081
- return rawValue;
1082
- }
1083
- const value = payload.value;
1084
- const hex = typeof value === "string" ? value : value && typeof value === "object" && typeof value.hex === "string" ? value.hex : null;
1085
- if (!hex) {
1086
- throw new Error("nft_transfer payload missing value");
1087
- }
1088
- if (!/^0x[0-9a-fA-F]*$/.test(hex)) {
1089
- throw new Error("nft_transfer payload has malformed value");
1090
- }
1091
- return hex;
1092
- }
1093
- function parseAssetIdentifier2(assetIdentifier) {
1094
- const [contractId, tokenName] = assetIdentifier.split("::");
1095
- if (!contractId) {
1096
- throw new Error("nft_transfer payload has malformed asset_identifier");
1097
- }
1098
- return {
1099
- contract_id: contractId,
1100
- token_name: tokenName && tokenName.length > 0 ? tokenName : null
1101
- };
1102
- }
1103
- function isNftTransfer(event) {
1104
- return event.event_type === "nft_transfer";
1105
- }
1106
- function decodeNftTransfer(event) {
1107
- if (!isNftTransfer(event)) {
1108
- throw new Error(`Expected nft_transfer event, got ${event.event_type}`);
1109
- }
1110
- const payload = event.payload;
1111
- const assetIdentifier = requireString2(payload, "asset_identifier");
1112
- const sender = requireString2(payload, "sender");
1113
- const recipient = requireString2(payload, "recipient");
1114
- const value = requireHexValue(payload);
1115
- const { contract_id, token_name } = parseAssetIdentifier2(assetIdentifier);
1116
- return {
1117
- cursor: event.cursor,
1118
- block_height: event.block_height,
1119
- tx_id: event.tx_id,
1120
- tx_index: event.tx_index,
1121
- event_index: event.event_index,
1122
- event_type: event.event_type,
1123
- decoded_payload: {
1124
- asset_identifier: assetIdentifier,
1125
- contract_id: event.contract_id ?? contract_id,
1126
- token_name,
1127
- sender,
1128
- recipient,
1129
- value
1130
- },
1131
- source_cursor: event.cursor
1132
- };
1133
- }
1134
1045
  // src/streams/_payload.ts
1135
- function requireString3(payload, field, eventType) {
1046
+ function requireString(payload, field, eventType) {
1136
1047
  const value = payload[field];
1137
1048
  if (typeof value !== "string" || value.length === 0) {
1138
1049
  throw new Error(`${eventType} payload missing ${field}`);
@@ -1143,7 +1054,7 @@ function optionalString(value) {
1143
1054
  return typeof value === "string" && value.length > 0 ? value : null;
1144
1055
  }
1145
1056
  function requireAmountField(payload, field, eventType) {
1146
- const amount = requireString3(payload, field, eventType);
1057
+ const amount = requireString(payload, field, eventType);
1147
1058
  if (!/^(0|[1-9]\d*)$/.test(amount)) {
1148
1059
  throw new Error(`${eventType} payload has malformed ${field}`);
1149
1060
  }
@@ -1152,7 +1063,7 @@ function requireAmountField(payload, field, eventType) {
1152
1063
  function requireAmount(payload, eventType) {
1153
1064
  return requireAmountField(payload, "amount", eventType);
1154
1065
  }
1155
- function parseAssetIdentifier3(assetIdentifier, eventType) {
1066
+ function parseAssetIdentifier(assetIdentifier, eventType) {
1156
1067
  const [contractId, tokenName] = assetIdentifier.split("::");
1157
1068
  if (!contractId) {
1158
1069
  throw new Error(`${eventType} payload has malformed asset_identifier`);
@@ -1162,7 +1073,7 @@ function parseAssetIdentifier3(assetIdentifier, eventType) {
1162
1073
  token_name: tokenName && tokenName.length > 0 ? tokenName : null
1163
1074
  };
1164
1075
  }
1165
- function requireHexValue2(payload, eventType) {
1076
+ function requireHexValue(payload, eventType) {
1166
1077
  const rawValue = payload.raw_value;
1167
1078
  if (typeof rawValue === "string") {
1168
1079
  if (!/^0x[0-9a-fA-F]*$/.test(rawValue)) {
@@ -1193,6 +1104,52 @@ function decodedRow(event, eventType, decoded_payload) {
1193
1104
  };
1194
1105
  }
1195
1106
 
1107
+ // src/streams/ft-transfer.ts
1108
+ function isFtTransfer(event) {
1109
+ return event.event_type === "ft_transfer";
1110
+ }
1111
+ function decodeFtTransfer(event) {
1112
+ if (!isFtTransfer(event)) {
1113
+ throw new Error(`Expected ft_transfer event, got ${event.event_type}`);
1114
+ }
1115
+ const payload = event.payload;
1116
+ const assetIdentifier = requireString(payload, "asset_identifier", "ft_transfer");
1117
+ const sender = requireString(payload, "sender", "ft_transfer");
1118
+ const recipient = requireString(payload, "recipient", "ft_transfer");
1119
+ const amount = requireAmount(payload, "ft_transfer");
1120
+ const { contract_id, token_name } = parseAssetIdentifier(assetIdentifier, "ft_transfer");
1121
+ return decodedRow(event, "ft_transfer", {
1122
+ asset_identifier: assetIdentifier,
1123
+ contract_id: event.contract_id ?? contract_id,
1124
+ token_name,
1125
+ sender,
1126
+ recipient,
1127
+ amount
1128
+ });
1129
+ }
1130
+ // src/streams/nft-transfer.ts
1131
+ function isNftTransfer(event) {
1132
+ return event.event_type === "nft_transfer";
1133
+ }
1134
+ function decodeNftTransfer(event) {
1135
+ if (!isNftTransfer(event)) {
1136
+ throw new Error(`Expected nft_transfer event, got ${event.event_type}`);
1137
+ }
1138
+ const payload = event.payload;
1139
+ const assetIdentifier = requireString(payload, "asset_identifier", "nft_transfer");
1140
+ const sender = requireString(payload, "sender", "nft_transfer");
1141
+ const recipient = requireString(payload, "recipient", "nft_transfer");
1142
+ const value = requireHexValue(payload, "nft_transfer");
1143
+ const { contract_id, token_name } = parseAssetIdentifier(assetIdentifier, "nft_transfer");
1144
+ return decodedRow(event, "nft_transfer", {
1145
+ asset_identifier: assetIdentifier,
1146
+ contract_id: event.contract_id ?? contract_id,
1147
+ token_name,
1148
+ sender,
1149
+ recipient,
1150
+ value
1151
+ });
1152
+ }
1196
1153
  // src/streams/stx-events.ts
1197
1154
  function isStxTransfer(event) {
1198
1155
  return event.event_type === "stx_transfer";
@@ -1203,8 +1160,8 @@ function decodeStxTransfer(event) {
1203
1160
  }
1204
1161
  const payload = event.payload;
1205
1162
  return decodedRow(event, "stx_transfer", {
1206
- sender: requireString3(payload, "sender", "stx_transfer"),
1207
- recipient: requireString3(payload, "recipient", "stx_transfer"),
1163
+ sender: requireString(payload, "sender", "stx_transfer"),
1164
+ recipient: requireString(payload, "recipient", "stx_transfer"),
1208
1165
  amount: requireAmount(payload, "stx_transfer"),
1209
1166
  memo: optionalString(payload.memo)
1210
1167
  });
@@ -1218,7 +1175,7 @@ function decodeStxMint(event) {
1218
1175
  }
1219
1176
  const payload = event.payload;
1220
1177
  return decodedRow(event, "stx_mint", {
1221
- recipient: requireString3(payload, "recipient", "stx_mint"),
1178
+ recipient: requireString(payload, "recipient", "stx_mint"),
1222
1179
  amount: requireAmount(payload, "stx_mint")
1223
1180
  });
1224
1181
  }
@@ -1231,7 +1188,7 @@ function decodeStxBurn(event) {
1231
1188
  }
1232
1189
  const payload = event.payload;
1233
1190
  return decodedRow(event, "stx_burn", {
1234
- sender: requireString3(payload, "sender", "stx_burn"),
1191
+ sender: requireString(payload, "sender", "stx_burn"),
1235
1192
  amount: requireAmount(payload, "stx_burn")
1236
1193
  });
1237
1194
  }
@@ -1244,15 +1201,15 @@ function decodeStxLock(event) {
1244
1201
  }
1245
1202
  const payload = event.payload;
1246
1203
  return decodedRow(event, "stx_lock", {
1247
- sender: requireString3(payload, "locked_address", "stx_lock"),
1204
+ sender: requireString(payload, "locked_address", "stx_lock"),
1248
1205
  amount: requireAmountField(payload, "locked_amount", "stx_lock"),
1249
1206
  payload: { unlock_height: optionalString(payload.unlock_height) }
1250
1207
  });
1251
1208
  }
1252
1209
  // src/streams/token-mint-burn.ts
1253
1210
  function assetFields(event, eventType) {
1254
- const assetIdentifier = requireString3(event.payload, "asset_identifier", eventType);
1255
- const { contract_id, token_name } = parseAssetIdentifier3(assetIdentifier, eventType);
1211
+ const assetIdentifier = requireString(event.payload, "asset_identifier", eventType);
1212
+ const { contract_id, token_name } = parseAssetIdentifier(assetIdentifier, eventType);
1256
1213
  return {
1257
1214
  asset_identifier: assetIdentifier,
1258
1215
  contract_id: event.contract_id ?? contract_id,
@@ -1268,7 +1225,7 @@ function decodeFtMint(event) {
1268
1225
  }
1269
1226
  return decodedRow(event, "ft_mint", {
1270
1227
  ...assetFields(event, "ft_mint"),
1271
- recipient: requireString3(event.payload, "recipient", "ft_mint"),
1228
+ recipient: requireString(event.payload, "recipient", "ft_mint"),
1272
1229
  amount: requireAmount(event.payload, "ft_mint")
1273
1230
  });
1274
1231
  }
@@ -1281,7 +1238,7 @@ function decodeFtBurn(event) {
1281
1238
  }
1282
1239
  return decodedRow(event, "ft_burn", {
1283
1240
  ...assetFields(event, "ft_burn"),
1284
- sender: requireString3(event.payload, "sender", "ft_burn"),
1241
+ sender: requireString(event.payload, "sender", "ft_burn"),
1285
1242
  amount: requireAmount(event.payload, "ft_burn")
1286
1243
  });
1287
1244
  }
@@ -1294,8 +1251,8 @@ function decodeNftMint(event) {
1294
1251
  }
1295
1252
  return decodedRow(event, "nft_mint", {
1296
1253
  ...assetFields(event, "nft_mint"),
1297
- recipient: requireString3(event.payload, "recipient", "nft_mint"),
1298
- value: requireHexValue2(event.payload, "nft_mint")
1254
+ recipient: requireString(event.payload, "recipient", "nft_mint"),
1255
+ value: requireHexValue(event.payload, "nft_mint")
1299
1256
  });
1300
1257
  }
1301
1258
  function isNftBurn(event) {
@@ -1307,8 +1264,8 @@ function decodeNftBurn(event) {
1307
1264
  }
1308
1265
  return decodedRow(event, "nft_burn", {
1309
1266
  ...assetFields(event, "nft_burn"),
1310
- sender: requireString3(event.payload, "sender", "nft_burn"),
1311
- value: requireHexValue2(event.payload, "nft_burn")
1267
+ sender: requireString(event.payload, "sender", "nft_burn"),
1268
+ value: requireHexValue(event.payload, "nft_burn")
1312
1269
  });
1313
1270
  }
1314
1271
  // src/clarity.ts
@@ -1379,11 +1336,6 @@ var STREAMS_EVENT_TYPES = [
1379
1336
  "print"
1380
1337
  ];
1381
1338
  // src/datasets/client.ts
1382
- function appendParam(params, name, value) {
1383
- if (value === undefined || value === null)
1384
- return;
1385
- params.set(name, String(value));
1386
- }
1387
1339
  var PARAM_KEYS = {
1388
1340
  fromBlock: "from_block",
1389
1341
  toBlock: "to_block",
@@ -1424,7 +1376,7 @@ class Datasets extends BaseClient {
1424
1376
  if (!d) {
1425
1377
  throw new Error(`unknown cursor dataset "${slug}" (use one of: ${Object.keys(CURSOR_SLUGS).join(", ")})`);
1426
1378
  }
1427
- const env = await this.get(d.path, this.buildParams(params));
1379
+ const env = await this.get(d.path, this.paramsToQuery(params));
1428
1380
  return {
1429
1381
  rows: env[d.rowKey] ?? [],
1430
1382
  next_cursor: env.next_cursor ?? null,
@@ -1441,40 +1393,37 @@ class Datasets extends BaseClient {
1441
1393
  bnsNamespaceEvents = this.cursorDataset("bns/namespace-events", "events");
1442
1394
  bnsMarketplaceEvents = this.cursorDataset("bns/marketplace-events", "events");
1443
1395
  bnsNames(params = {}) {
1444
- const sp = new URLSearchParams;
1445
- appendParam(sp, "namespace", params.namespace);
1446
- appendParam(sp, "owner", params.owner);
1447
- appendParam(sp, "limit", params.limit);
1448
- appendParam(sp, "offset", params.offset);
1449
- return this.get("bns/names", sp);
1396
+ return this.get("bns/names", buildQuery({
1397
+ namespace: params.namespace,
1398
+ owner: params.owner,
1399
+ limit: params.limit,
1400
+ offset: params.offset
1401
+ }));
1450
1402
  }
1451
1403
  bnsNamespaces() {
1452
- return this.get("bns/namespaces", new URLSearchParams);
1404
+ return this.get("bns/namespaces", "");
1453
1405
  }
1454
1406
  bnsResolve(fqn) {
1455
- const sp = new URLSearchParams;
1456
- sp.set("fqn", fqn);
1457
- return this.get("bns/resolve", sp);
1407
+ return this.get("bns/resolve", buildQuery({ fqn }));
1458
1408
  }
1459
1409
  networkHealth() {
1460
- return this.get("network-health/summary", new URLSearchParams);
1410
+ return this.get("network-health/summary", "");
1461
1411
  }
1462
- get(path, sp) {
1463
- const qs = sp.toString();
1464
- return this.request("GET", `/v1/datasets/${path}${qs ? `?${qs}` : ""}`);
1412
+ get(path, query) {
1413
+ return this.request("GET", `/v1/datasets/${path}${query}`);
1465
1414
  }
1466
- buildParams(params) {
1467
- const sp = new URLSearchParams;
1415
+ paramsToQuery(params) {
1416
+ const mapped = {};
1468
1417
  for (const [k, v] of Object.entries(params)) {
1469
1418
  if (v === undefined || v === null || k === "batchSize" || k === "signal")
1470
1419
  continue;
1471
- appendParam(sp, PARAM_KEYS[k] ?? k, v);
1420
+ mapped[PARAM_KEYS[k] ?? k] = v;
1472
1421
  }
1473
- return sp;
1422
+ return buildQuery(mapped);
1474
1423
  }
1475
1424
  cursorDataset(path, rowKey) {
1476
1425
  const list = async (params = {}) => {
1477
- const envelope = await this.get(path, this.buildParams(params));
1426
+ const envelope = await this.get(path, this.paramsToQuery(params));
1478
1427
  return {
1479
1428
  rows: envelope[rowKey] ?? [],
1480
1429
  next_cursor: envelope.next_cursor ?? null,
@@ -1586,10 +1535,11 @@ export {
1586
1535
  RateLimitError,
1587
1536
  Index,
1588
1537
  Datasets,
1538
+ Cursor,
1589
1539
  CURSOR_SLUGS,
1590
1540
  AuthError,
1591
1541
  ApiError
1592
1542
  };
1593
1543
 
1594
- //# debugId=4712778CA4B6FFB664756E2164756E21
1544
+ //# debugId=DF9925BCF7B82FB964756E2164756E21
1595
1545
  //# sourceMappingURL=index.js.map