@secondlayer/sdk 5.9.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) {
@@ -532,20 +606,39 @@ async function consumeStreamsEvents(opts) {
532
606
  cursor,
533
607
  limit: opts.batchSize,
534
608
  types: opts.types,
609
+ notTypes: opts.notTypes,
535
610
  contractId: opts.contractId,
536
611
  sender: opts.sender,
537
612
  recipient: opts.recipient,
538
613
  assetIdentifier: opts.assetIdentifier
539
614
  });
540
615
  pages++;
541
- const returnedCursor = await opts.onBatch(envelope.events, envelope);
542
- 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;
543
636
  if (nextCursor && nextCursor !== cursor) {
544
637
  cursor = nextCursor;
545
638
  emptyPolls = 0;
546
639
  continue;
547
640
  }
548
- if (envelope.events.length === 0) {
641
+ if (emitted.length === 0) {
549
642
  emptyPolls++;
550
643
  if (mode === "bounded") {
551
644
  return { cursor, pages, emptyPolls };
@@ -570,6 +663,7 @@ async function* streamStreamsEvents(opts) {
570
663
  cursor,
571
664
  limit: opts.batchSize,
572
665
  types: opts.types,
666
+ notTypes: opts.notTypes,
573
667
  contractId: opts.contractId,
574
668
  sender: opts.sender,
575
669
  recipient: opts.recipient,
@@ -600,56 +694,6 @@ async function* streamStreamsEvents(opts) {
600
694
 
601
695
  // src/streams/dumps.ts
602
696
  import { createHash } from "node:crypto";
603
-
604
- // src/streams/errors.ts
605
- class AuthError extends Error {
606
- status = 401;
607
- constructor(message = "API key invalid or expired.") {
608
- super(message);
609
- this.name = "AuthError";
610
- }
611
- }
612
-
613
- class RateLimitError extends Error {
614
- retryAfter;
615
- status = 429;
616
- constructor(message = "Rate limited. Try again later.", retryAfter) {
617
- super(message);
618
- this.retryAfter = retryAfter;
619
- this.name = "RateLimitError";
620
- }
621
- }
622
-
623
- class ValidationError extends Error {
624
- status;
625
- body;
626
- constructor(message, status, body) {
627
- super(message);
628
- this.status = status;
629
- this.body = body;
630
- this.name = "ValidationError";
631
- }
632
- }
633
-
634
- class StreamsServerError extends Error {
635
- status;
636
- body;
637
- constructor(message, status, body) {
638
- super(message);
639
- this.status = status;
640
- this.body = body;
641
- this.name = "StreamsServerError";
642
- }
643
- }
644
-
645
- class StreamsSignatureError extends Error {
646
- constructor(message = "Streams response signature verification failed.") {
647
- super(message);
648
- this.name = "StreamsSignatureError";
649
- }
650
- }
651
-
652
- // src/streams/dumps.ts
653
697
  function createStreamsDumps(opts) {
654
698
  const baseUrl = opts.baseUrl?.replace(/\/+$/, "");
655
699
  function requireBaseUrl() {
@@ -688,8 +732,12 @@ function createStreamsDumps(opts) {
688
732
  function cursorTuple(cursor) {
689
733
  if (!cursor)
690
734
  return [-1, -1];
691
- const [block, index] = cursor.split(":");
692
- 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];
693
741
  }
694
742
  function maxCursor(a, b) {
695
743
  const [ah, ai] = cursorTuple(a);
@@ -700,11 +748,6 @@ var DEFAULT_STREAMS_BASE_URL = "https://api.secondlayer.tools";
700
748
  function normalizeBaseUrl(baseUrl) {
701
749
  return baseUrl.replace(/\/+$/, "");
702
750
  }
703
- function appendSearchParam2(params, name, value) {
704
- if (value === undefined || value === null)
705
- return;
706
- params.set(name, String(value));
707
- }
708
751
  async function responseBody(response) {
709
752
  const text = await response.text();
710
753
  if (text.length === 0)
@@ -748,13 +791,16 @@ function createStreamsClient(options) {
748
791
  baseUrl: options.dumpsBaseUrl,
749
792
  fetchImpl
750
793
  });
751
- let publicKeyPromise = null;
752
- function getPublicKey() {
753
- if (publicKeyPromise)
754
- return publicKeyPromise;
755
- publicKeyPromise = (async () => {
794
+ let keyPromise = null;
795
+ function loadKey() {
796
+ if (keyPromise)
797
+ return keyPromise;
798
+ keyPromise = (async () => {
756
799
  if (typeof verify === "object") {
757
- return ed25519.loadEd25519PublicKey(verify.publicKey);
800
+ return {
801
+ keyId: ed25519.ed25519KeyId(verify.publicKey),
802
+ publicKey: ed25519.loadEd25519PublicKey(verify.publicKey)
803
+ };
758
804
  }
759
805
  const res = await fetchImpl(`${baseUrl}/public/streams/signing-key`);
760
806
  if (!res.ok) {
@@ -764,9 +810,12 @@ function createStreamsClient(options) {
764
810
  if (!body.public_key_pem) {
765
811
  throw new StreamsSignatureError("Signing key response missing key.");
766
812
  }
767
- return ed25519.loadEd25519PublicKey(body.public_key_pem);
813
+ return {
814
+ keyId: body.key_id ?? ed25519.ed25519KeyId(body.public_key_pem),
815
+ publicKey: ed25519.loadEd25519PublicKey(body.public_key_pem)
816
+ };
768
817
  })();
769
- return publicKeyPromise;
818
+ return keyPromise;
770
819
  }
771
820
  async function request(path) {
772
821
  const response = await fetchImpl(`${baseUrl}${path}`, {
@@ -780,8 +829,19 @@ function createStreamsClient(options) {
780
829
  if (!signature) {
781
830
  throw new StreamsSignatureError("Response is missing X-Signature.");
782
831
  }
783
- const publicKey = await getPublicKey();
784
- if (!ed25519.verifyEd25519(text, signature, publicKey)) {
832
+ const responseKeyId = response.headers.get("X-Signature-KeyId");
833
+ let key = await loadKey();
834
+ if (responseKeyId && responseKeyId !== key.keyId) {
835
+ if (typeof verify === "object") {
836
+ throw new StreamsSignatureError(`Response signed with key '${responseKeyId}', expected pinned key '${key.keyId}'.`);
837
+ }
838
+ keyPromise = null;
839
+ key = await loadKey();
840
+ if (responseKeyId !== key.keyId) {
841
+ throw new StreamsSignatureError(`Response signed with key '${responseKeyId}' not served by the signing-key endpoint.`);
842
+ }
843
+ }
844
+ if (!ed25519.verifyEd25519(text, signature, key.publicKey)) {
785
845
  throw new StreamsSignatureError;
786
846
  }
787
847
  }
@@ -791,6 +851,7 @@ function createStreamsClient(options) {
791
851
  cursor,
792
852
  limit,
793
853
  types,
854
+ notTypes,
794
855
  contractId,
795
856
  sender,
796
857
  recipient,
@@ -800,6 +861,7 @@ function createStreamsClient(options) {
800
861
  cursor,
801
862
  limit,
802
863
  types,
864
+ notTypes,
803
865
  contractId,
804
866
  sender,
805
867
  recipient,
@@ -807,20 +869,18 @@ function createStreamsClient(options) {
807
869
  });
808
870
  };
809
871
  async function listEvents(params = {}) {
810
- const searchParams = new URLSearchParams;
811
- appendSearchParam2(searchParams, "cursor", params.cursor);
812
- appendSearchParam2(searchParams, "from_height", params.fromHeight);
813
- appendSearchParam2(searchParams, "to_height", params.toHeight);
814
- appendSearchParam2(searchParams, "limit", params.limit);
815
- appendSearchParam2(searchParams, "contract_id", params.contractId);
816
- appendSearchParam2(searchParams, "sender", params.sender);
817
- appendSearchParam2(searchParams, "recipient", params.recipient);
818
- appendSearchParam2(searchParams, "asset_identifier", params.assetIdentifier);
819
- if (params.types?.length) {
820
- searchParams.set("types", params.types.join(","));
821
- }
822
- const query = searchParams.toString();
823
- 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
+ })}`);
824
884
  }
825
885
  return {
826
886
  events: {
@@ -832,7 +892,9 @@ function createStreamsClient(options) {
832
892
  return consumeStreamsEvents({
833
893
  fromCursor: params.fromCursor,
834
894
  mode: params.mode,
895
+ finalizedOnly: params.finalizedOnly,
835
896
  types: params.types,
897
+ notTypes: params.notTypes,
836
898
  contractId: params.contractId,
837
899
  sender: params.sender,
838
900
  recipient: params.recipient,
@@ -840,6 +902,7 @@ function createStreamsClient(options) {
840
902
  batchSize: params.batchSize ?? 100,
841
903
  fetchEvents,
842
904
  onBatch: params.onBatch,
905
+ onReorg: params.onReorg,
843
906
  emptyBackoffMs: params.emptyBackoffMs,
844
907
  maxPages: params.maxPages,
845
908
  maxEmptyPolls: params.maxEmptyPolls,
@@ -850,6 +913,7 @@ function createStreamsClient(options) {
850
913
  return streamStreamsEvents({
851
914
  fromCursor: params.fromCursor,
852
915
  types: params.types,
916
+ notTypes: params.notTypes,
853
917
  contractId: params.contractId,
854
918
  sender: params.sender,
855
919
  recipient: params.recipient,
@@ -893,11 +957,10 @@ function createStreamsClient(options) {
893
957
  },
894
958
  reorgs: {
895
959
  list(params) {
896
- const searchParams = new URLSearchParams;
897
- appendSearchParam2(searchParams, "since", params.since);
898
- appendSearchParam2(searchParams, "limit", params.limit);
899
- const query = searchParams.toString();
900
- return request(`/v1/streams/reorgs${query ? `?${query}` : ""}`);
960
+ return request(`/v1/streams/reorgs${buildQuery({
961
+ since: params.since,
962
+ limit: params.limit
963
+ })}`);
901
964
  }
902
965
  },
903
966
  dumps,
@@ -979,127 +1042,8 @@ function getSubgraph(def, options = {}) {
979
1042
  }
980
1043
  return new Subgraphs(options).typed(def);
981
1044
  }
982
- // src/streams/ft-transfer.ts
983
- function requireString(payload, field) {
984
- const value = payload[field];
985
- if (typeof value !== "string" || value.length === 0) {
986
- throw new Error(`ft_transfer payload missing ${field}`);
987
- }
988
- return value;
989
- }
990
- function parseAssetIdentifier(assetIdentifier) {
991
- const [contractId, tokenName] = assetIdentifier.split("::");
992
- if (!contractId) {
993
- throw new Error("ft_transfer payload has malformed asset_identifier");
994
- }
995
- return {
996
- contract_id: contractId,
997
- token_name: tokenName && tokenName.length > 0 ? tokenName : null
998
- };
999
- }
1000
- function isFtTransfer(event) {
1001
- return event.event_type === "ft_transfer";
1002
- }
1003
- function decodeFtTransfer(event) {
1004
- if (!isFtTransfer(event)) {
1005
- throw new Error(`Expected ft_transfer event, got ${event.event_type}`);
1006
- }
1007
- const payload = event.payload;
1008
- const assetIdentifier = requireString(payload, "asset_identifier");
1009
- const sender = requireString(payload, "sender");
1010
- const recipient = requireString(payload, "recipient");
1011
- const amount = requireString(payload, "amount");
1012
- if (!/^(0|[1-9]\d*)$/.test(amount)) {
1013
- throw new Error("ft_transfer payload has malformed amount");
1014
- }
1015
- const { contract_id, token_name } = parseAssetIdentifier(assetIdentifier);
1016
- return {
1017
- cursor: event.cursor,
1018
- block_height: event.block_height,
1019
- tx_id: event.tx_id,
1020
- tx_index: event.tx_index,
1021
- event_index: event.event_index,
1022
- event_type: event.event_type,
1023
- decoded_payload: {
1024
- asset_identifier: assetIdentifier,
1025
- contract_id: event.contract_id ?? contract_id,
1026
- token_name,
1027
- sender,
1028
- recipient,
1029
- amount
1030
- },
1031
- source_cursor: event.cursor
1032
- };
1033
- }
1034
- // src/streams/nft-transfer.ts
1035
- function requireString2(payload, field) {
1036
- const value = payload[field];
1037
- if (typeof value !== "string" || value.length === 0) {
1038
- throw new Error(`nft_transfer payload missing ${field}`);
1039
- }
1040
- return value;
1041
- }
1042
- function requireHexValue(payload) {
1043
- const rawValue = payload.raw_value;
1044
- if (typeof rawValue === "string") {
1045
- if (!/^0x[0-9a-fA-F]*$/.test(rawValue)) {
1046
- throw new Error("nft_transfer payload has malformed value");
1047
- }
1048
- return rawValue;
1049
- }
1050
- const value = payload.value;
1051
- const hex = typeof value === "string" ? value : value && typeof value === "object" && typeof value.hex === "string" ? value.hex : null;
1052
- if (!hex) {
1053
- throw new Error("nft_transfer payload missing value");
1054
- }
1055
- if (!/^0x[0-9a-fA-F]*$/.test(hex)) {
1056
- throw new Error("nft_transfer payload has malformed value");
1057
- }
1058
- return hex;
1059
- }
1060
- function parseAssetIdentifier2(assetIdentifier) {
1061
- const [contractId, tokenName] = assetIdentifier.split("::");
1062
- if (!contractId) {
1063
- throw new Error("nft_transfer payload has malformed asset_identifier");
1064
- }
1065
- return {
1066
- contract_id: contractId,
1067
- token_name: tokenName && tokenName.length > 0 ? tokenName : null
1068
- };
1069
- }
1070
- function isNftTransfer(event) {
1071
- return event.event_type === "nft_transfer";
1072
- }
1073
- function decodeNftTransfer(event) {
1074
- if (!isNftTransfer(event)) {
1075
- throw new Error(`Expected nft_transfer event, got ${event.event_type}`);
1076
- }
1077
- const payload = event.payload;
1078
- const assetIdentifier = requireString2(payload, "asset_identifier");
1079
- const sender = requireString2(payload, "sender");
1080
- const recipient = requireString2(payload, "recipient");
1081
- const value = requireHexValue(payload);
1082
- const { contract_id, token_name } = parseAssetIdentifier2(assetIdentifier);
1083
- return {
1084
- cursor: event.cursor,
1085
- block_height: event.block_height,
1086
- tx_id: event.tx_id,
1087
- tx_index: event.tx_index,
1088
- event_index: event.event_index,
1089
- event_type: event.event_type,
1090
- decoded_payload: {
1091
- asset_identifier: assetIdentifier,
1092
- contract_id: event.contract_id ?? contract_id,
1093
- token_name,
1094
- sender,
1095
- recipient,
1096
- value
1097
- },
1098
- source_cursor: event.cursor
1099
- };
1100
- }
1101
1045
  // src/streams/_payload.ts
1102
- function requireString3(payload, field, eventType) {
1046
+ function requireString(payload, field, eventType) {
1103
1047
  const value = payload[field];
1104
1048
  if (typeof value !== "string" || value.length === 0) {
1105
1049
  throw new Error(`${eventType} payload missing ${field}`);
@@ -1110,7 +1054,7 @@ function optionalString(value) {
1110
1054
  return typeof value === "string" && value.length > 0 ? value : null;
1111
1055
  }
1112
1056
  function requireAmountField(payload, field, eventType) {
1113
- const amount = requireString3(payload, field, eventType);
1057
+ const amount = requireString(payload, field, eventType);
1114
1058
  if (!/^(0|[1-9]\d*)$/.test(amount)) {
1115
1059
  throw new Error(`${eventType} payload has malformed ${field}`);
1116
1060
  }
@@ -1119,7 +1063,7 @@ function requireAmountField(payload, field, eventType) {
1119
1063
  function requireAmount(payload, eventType) {
1120
1064
  return requireAmountField(payload, "amount", eventType);
1121
1065
  }
1122
- function parseAssetIdentifier3(assetIdentifier, eventType) {
1066
+ function parseAssetIdentifier(assetIdentifier, eventType) {
1123
1067
  const [contractId, tokenName] = assetIdentifier.split("::");
1124
1068
  if (!contractId) {
1125
1069
  throw new Error(`${eventType} payload has malformed asset_identifier`);
@@ -1129,7 +1073,7 @@ function parseAssetIdentifier3(assetIdentifier, eventType) {
1129
1073
  token_name: tokenName && tokenName.length > 0 ? tokenName : null
1130
1074
  };
1131
1075
  }
1132
- function requireHexValue2(payload, eventType) {
1076
+ function requireHexValue(payload, eventType) {
1133
1077
  const rawValue = payload.raw_value;
1134
1078
  if (typeof rawValue === "string") {
1135
1079
  if (!/^0x[0-9a-fA-F]*$/.test(rawValue)) {
@@ -1160,6 +1104,52 @@ function decodedRow(event, eventType, decoded_payload) {
1160
1104
  };
1161
1105
  }
1162
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
+ }
1163
1153
  // src/streams/stx-events.ts
1164
1154
  function isStxTransfer(event) {
1165
1155
  return event.event_type === "stx_transfer";
@@ -1170,8 +1160,8 @@ function decodeStxTransfer(event) {
1170
1160
  }
1171
1161
  const payload = event.payload;
1172
1162
  return decodedRow(event, "stx_transfer", {
1173
- sender: requireString3(payload, "sender", "stx_transfer"),
1174
- recipient: requireString3(payload, "recipient", "stx_transfer"),
1163
+ sender: requireString(payload, "sender", "stx_transfer"),
1164
+ recipient: requireString(payload, "recipient", "stx_transfer"),
1175
1165
  amount: requireAmount(payload, "stx_transfer"),
1176
1166
  memo: optionalString(payload.memo)
1177
1167
  });
@@ -1185,7 +1175,7 @@ function decodeStxMint(event) {
1185
1175
  }
1186
1176
  const payload = event.payload;
1187
1177
  return decodedRow(event, "stx_mint", {
1188
- recipient: requireString3(payload, "recipient", "stx_mint"),
1178
+ recipient: requireString(payload, "recipient", "stx_mint"),
1189
1179
  amount: requireAmount(payload, "stx_mint")
1190
1180
  });
1191
1181
  }
@@ -1198,7 +1188,7 @@ function decodeStxBurn(event) {
1198
1188
  }
1199
1189
  const payload = event.payload;
1200
1190
  return decodedRow(event, "stx_burn", {
1201
- sender: requireString3(payload, "sender", "stx_burn"),
1191
+ sender: requireString(payload, "sender", "stx_burn"),
1202
1192
  amount: requireAmount(payload, "stx_burn")
1203
1193
  });
1204
1194
  }
@@ -1211,15 +1201,15 @@ function decodeStxLock(event) {
1211
1201
  }
1212
1202
  const payload = event.payload;
1213
1203
  return decodedRow(event, "stx_lock", {
1214
- sender: requireString3(payload, "locked_address", "stx_lock"),
1204
+ sender: requireString(payload, "locked_address", "stx_lock"),
1215
1205
  amount: requireAmountField(payload, "locked_amount", "stx_lock"),
1216
1206
  payload: { unlock_height: optionalString(payload.unlock_height) }
1217
1207
  });
1218
1208
  }
1219
1209
  // src/streams/token-mint-burn.ts
1220
1210
  function assetFields(event, eventType) {
1221
- const assetIdentifier = requireString3(event.payload, "asset_identifier", eventType);
1222
- 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);
1223
1213
  return {
1224
1214
  asset_identifier: assetIdentifier,
1225
1215
  contract_id: event.contract_id ?? contract_id,
@@ -1235,7 +1225,7 @@ function decodeFtMint(event) {
1235
1225
  }
1236
1226
  return decodedRow(event, "ft_mint", {
1237
1227
  ...assetFields(event, "ft_mint"),
1238
- recipient: requireString3(event.payload, "recipient", "ft_mint"),
1228
+ recipient: requireString(event.payload, "recipient", "ft_mint"),
1239
1229
  amount: requireAmount(event.payload, "ft_mint")
1240
1230
  });
1241
1231
  }
@@ -1248,7 +1238,7 @@ function decodeFtBurn(event) {
1248
1238
  }
1249
1239
  return decodedRow(event, "ft_burn", {
1250
1240
  ...assetFields(event, "ft_burn"),
1251
- sender: requireString3(event.payload, "sender", "ft_burn"),
1241
+ sender: requireString(event.payload, "sender", "ft_burn"),
1252
1242
  amount: requireAmount(event.payload, "ft_burn")
1253
1243
  });
1254
1244
  }
@@ -1261,8 +1251,8 @@ function decodeNftMint(event) {
1261
1251
  }
1262
1252
  return decodedRow(event, "nft_mint", {
1263
1253
  ...assetFields(event, "nft_mint"),
1264
- recipient: requireString3(event.payload, "recipient", "nft_mint"),
1265
- value: requireHexValue2(event.payload, "nft_mint")
1254
+ recipient: requireString(event.payload, "recipient", "nft_mint"),
1255
+ value: requireHexValue(event.payload, "nft_mint")
1266
1256
  });
1267
1257
  }
1268
1258
  function isNftBurn(event) {
@@ -1274,8 +1264,8 @@ function decodeNftBurn(event) {
1274
1264
  }
1275
1265
  return decodedRow(event, "nft_burn", {
1276
1266
  ...assetFields(event, "nft_burn"),
1277
- sender: requireString3(event.payload, "sender", "nft_burn"),
1278
- value: requireHexValue2(event.payload, "nft_burn")
1267
+ sender: requireString(event.payload, "sender", "nft_burn"),
1268
+ value: requireHexValue(event.payload, "nft_burn")
1279
1269
  });
1280
1270
  }
1281
1271
  // src/clarity.ts
@@ -1346,11 +1336,6 @@ var STREAMS_EVENT_TYPES = [
1346
1336
  "print"
1347
1337
  ];
1348
1338
  // src/datasets/client.ts
1349
- function appendParam(params, name, value) {
1350
- if (value === undefined || value === null)
1351
- return;
1352
- params.set(name, String(value));
1353
- }
1354
1339
  var PARAM_KEYS = {
1355
1340
  fromBlock: "from_block",
1356
1341
  toBlock: "to_block",
@@ -1391,7 +1376,7 @@ class Datasets extends BaseClient {
1391
1376
  if (!d) {
1392
1377
  throw new Error(`unknown cursor dataset "${slug}" (use one of: ${Object.keys(CURSOR_SLUGS).join(", ")})`);
1393
1378
  }
1394
- const env = await this.get(d.path, this.buildParams(params));
1379
+ const env = await this.get(d.path, this.paramsToQuery(params));
1395
1380
  return {
1396
1381
  rows: env[d.rowKey] ?? [],
1397
1382
  next_cursor: env.next_cursor ?? null,
@@ -1408,40 +1393,37 @@ class Datasets extends BaseClient {
1408
1393
  bnsNamespaceEvents = this.cursorDataset("bns/namespace-events", "events");
1409
1394
  bnsMarketplaceEvents = this.cursorDataset("bns/marketplace-events", "events");
1410
1395
  bnsNames(params = {}) {
1411
- const sp = new URLSearchParams;
1412
- appendParam(sp, "namespace", params.namespace);
1413
- appendParam(sp, "owner", params.owner);
1414
- appendParam(sp, "limit", params.limit);
1415
- appendParam(sp, "offset", params.offset);
1416
- 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
+ }));
1417
1402
  }
1418
1403
  bnsNamespaces() {
1419
- return this.get("bns/namespaces", new URLSearchParams);
1404
+ return this.get("bns/namespaces", "");
1420
1405
  }
1421
1406
  bnsResolve(fqn) {
1422
- const sp = new URLSearchParams;
1423
- sp.set("fqn", fqn);
1424
- return this.get("bns/resolve", sp);
1407
+ return this.get("bns/resolve", buildQuery({ fqn }));
1425
1408
  }
1426
1409
  networkHealth() {
1427
- return this.get("network-health/summary", new URLSearchParams);
1410
+ return this.get("network-health/summary", "");
1428
1411
  }
1429
- get(path, sp) {
1430
- const qs = sp.toString();
1431
- return this.request("GET", `/v1/datasets/${path}${qs ? `?${qs}` : ""}`);
1412
+ get(path, query) {
1413
+ return this.request("GET", `/v1/datasets/${path}${query}`);
1432
1414
  }
1433
- buildParams(params) {
1434
- const sp = new URLSearchParams;
1415
+ paramsToQuery(params) {
1416
+ const mapped = {};
1435
1417
  for (const [k, v] of Object.entries(params)) {
1436
1418
  if (v === undefined || v === null || k === "batchSize" || k === "signal")
1437
1419
  continue;
1438
- appendParam(sp, PARAM_KEYS[k] ?? k, v);
1420
+ mapped[PARAM_KEYS[k] ?? k] = v;
1439
1421
  }
1440
- return sp;
1422
+ return buildQuery(mapped);
1441
1423
  }
1442
1424
  cursorDataset(path, rowKey) {
1443
1425
  const list = async (params = {}) => {
1444
- const envelope = await this.get(path, this.buildParams(params));
1426
+ const envelope = await this.get(path, this.paramsToQuery(params));
1445
1427
  return {
1446
1428
  rows: envelope[rowKey] ?? [],
1447
1429
  next_cursor: envelope.next_cursor ?? null,
@@ -1553,10 +1535,11 @@ export {
1553
1535
  RateLimitError,
1554
1536
  Index,
1555
1537
  Datasets,
1538
+ Cursor,
1556
1539
  CURSOR_SLUGS,
1557
1540
  AuthError,
1558
1541
  ApiError
1559
1542
  };
1560
1543
 
1561
- //# debugId=54289A1292072EB864756E2164756E21
1544
+ //# debugId=DF9925BCF7B82FB964756E2164756E21
1562
1545
  //# sourceMappingURL=index.js.map