@secondlayer/sdk 6.0.0 → 6.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.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;
@@ -311,12 +324,143 @@ class Subgraphs extends BaseClient {
311
324
  };
312
325
  }
313
326
  }
314
- // 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));
327
+ // src/contracts/client.ts
328
+ class Contracts extends BaseClient {
329
+ constructor(options = {}) {
330
+ super(options);
331
+ }
332
+ list(params) {
333
+ return this.request("GET", `/v1/contracts${buildQuery({
334
+ trait: params.trait,
335
+ conformance: params.conformance,
336
+ include: params.include,
337
+ limit: params.limit,
338
+ cursor: params.cursor
339
+ })}`);
340
+ }
341
+ }
342
+
343
+ // src/datasets/client.ts
344
+ var PARAM_KEYS = {
345
+ fromBlock: "from_block",
346
+ toBlock: "to_block",
347
+ functionName: "function_name",
348
+ delegateTo: "delegate_to",
349
+ signerKey: "signer_key",
350
+ rewardCycle: "reward_cycle",
351
+ eventType: "event_type",
352
+ bnsId: "bns_id"
353
+ };
354
+ var CURSOR_SLUGS = {
355
+ "stx-transfers": { path: "stx-transfers", rowKey: "events" },
356
+ "sbtc-events": { path: "sbtc/events", rowKey: "events" },
357
+ "sbtc-token-events": { path: "sbtc/token-events", rowKey: "events" },
358
+ "pox-4-calls": { path: "pox-4/calls", rowKey: "calls" },
359
+ "burnchain-rewards": { path: "burnchain/rewards", rowKey: "rewards" },
360
+ "burnchain-reward-slots": {
361
+ path: "burnchain/reward-slots",
362
+ rowKey: "slots"
363
+ },
364
+ "bns-events": { path: "bns/events", rowKey: "events" },
365
+ "bns-namespace-events": { path: "bns/namespace-events", rowKey: "events" },
366
+ "bns-marketplace-events": {
367
+ path: "bns/marketplace-events",
368
+ rowKey: "events"
369
+ }
370
+ };
371
+
372
+ class Datasets extends BaseClient {
373
+ constructor(options = {}) {
374
+ super(options);
375
+ }
376
+ listDatasets() {
377
+ return this.request("GET", "/v1/datasets");
378
+ }
379
+ async query(slug, params = {}) {
380
+ const d = CURSOR_SLUGS[slug];
381
+ if (!d) {
382
+ throw new Error(`unknown cursor dataset "${slug}" (use one of: ${Object.keys(CURSOR_SLUGS).join(", ")})`);
383
+ }
384
+ const env = await this.get(d.path, this.paramsToQuery(params));
385
+ return {
386
+ rows: env[d.rowKey] ?? [],
387
+ next_cursor: env.next_cursor ?? null,
388
+ tip: env.tip
389
+ };
390
+ }
391
+ stxTransfers = this.cursorDataset("stx-transfers", "events");
392
+ sbtcEvents = this.cursorDataset("sbtc/events", "events");
393
+ sbtcTokenEvents = this.cursorDataset("sbtc/token-events", "events");
394
+ pox4Calls = this.cursorDataset("pox-4/calls", "calls");
395
+ burnchainRewards = this.cursorDataset("burnchain/rewards", "rewards");
396
+ burnchainRewardSlots = this.cursorDataset("burnchain/reward-slots", "slots");
397
+ bnsEvents = this.cursorDataset("bns/events", "events");
398
+ bnsNamespaceEvents = this.cursorDataset("bns/namespace-events", "events");
399
+ bnsMarketplaceEvents = this.cursorDataset("bns/marketplace-events", "events");
400
+ bnsNames(params = {}) {
401
+ return this.get("bns/names", buildQuery({
402
+ namespace: params.namespace,
403
+ owner: params.owner,
404
+ limit: params.limit,
405
+ offset: params.offset
406
+ }));
407
+ }
408
+ bnsNamespaces() {
409
+ return this.get("bns/namespaces", "");
410
+ }
411
+ bnsResolve(fqn) {
412
+ return this.get("bns/resolve", buildQuery({ fqn }));
413
+ }
414
+ networkHealth() {
415
+ return this.get("network-health/summary", "");
416
+ }
417
+ get(path, query) {
418
+ return this.request("GET", `/v1/datasets/${path}${query}`);
419
+ }
420
+ paramsToQuery(params) {
421
+ const mapped = {};
422
+ for (const [k, v] of Object.entries(params)) {
423
+ if (v === undefined || v === null || k === "batchSize" || k === "signal")
424
+ continue;
425
+ mapped[PARAM_KEYS[k] ?? k] = v;
426
+ }
427
+ return buildQuery(mapped);
428
+ }
429
+ cursorDataset(path, rowKey) {
430
+ const list = async (params = {}) => {
431
+ const envelope = await this.get(path, this.paramsToQuery(params));
432
+ return {
433
+ rows: envelope[rowKey] ?? [],
434
+ next_cursor: envelope.next_cursor ?? null,
435
+ tip: envelope.tip
436
+ };
437
+ };
438
+ const walk = async function* (params = {}) {
439
+ const batchSize = params.batchSize ?? 200;
440
+ let cursor = params.cursor ?? null;
441
+ let first = true;
442
+ while (!params.signal?.aborted) {
443
+ const env = await list({
444
+ ...params,
445
+ limit: batchSize,
446
+ cursor: first ? params.cursor : cursor ?? undefined
447
+ });
448
+ for (const row of env.rows) {
449
+ if (params.signal?.aborted)
450
+ return;
451
+ yield row;
452
+ }
453
+ if (!env.next_cursor || env.next_cursor === cursor || env.rows.length < batchSize)
454
+ return;
455
+ cursor = env.next_cursor;
456
+ first = false;
457
+ }
458
+ }.bind(this);
459
+ return { list, walk };
460
+ }
319
461
  }
462
+
463
+ // src/index-api/client.ts
320
464
  function firstWalkFromHeight(params) {
321
465
  if (params.fromHeight !== undefined)
322
466
  return params.fromHeight;
@@ -346,31 +490,29 @@ class Index extends BaseClient {
346
490
  walk: (params = {}) => this.walkContractCalls(params)
347
491
  };
348
492
  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}` : ""}`);
493
+ return this.request("GET", `/v1/index/ft-transfers${buildQuery({
494
+ cursor: params.cursor,
495
+ from_cursor: params.fromCursor,
496
+ limit: params.limit,
497
+ contract_id: params.contractId,
498
+ sender: params.sender,
499
+ recipient: params.recipient,
500
+ from_height: params.fromHeight,
501
+ to_height: params.toHeight
502
+ })}`);
360
503
  }
361
504
  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}` : ""}`);
505
+ return this.request("GET", `/v1/index/nft-transfers${buildQuery({
506
+ cursor: params.cursor,
507
+ from_cursor: params.fromCursor,
508
+ limit: params.limit,
509
+ contract_id: params.contractId,
510
+ asset_identifier: params.assetIdentifier,
511
+ sender: params.sender,
512
+ recipient: params.recipient,
513
+ from_height: params.fromHeight,
514
+ to_height: params.toHeight
515
+ })}`);
374
516
  }
375
517
  async* walkFtTransfers(params = {}) {
376
518
  const batchSize = params.batchSize ?? 200;
@@ -423,18 +565,18 @@ class Index extends BaseClient {
423
565
  }
424
566
  }
425
567
  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()}`);
568
+ return this.request("GET", `/v1/index/events${buildQuery({
569
+ event_type: params.eventType,
570
+ cursor: params.cursor,
571
+ from_cursor: params.fromCursor,
572
+ limit: params.limit,
573
+ contract_id: params.contractId,
574
+ asset_identifier: params.assetIdentifier,
575
+ sender: params.sender,
576
+ recipient: params.recipient,
577
+ from_height: params.fromHeight,
578
+ to_height: params.toHeight
579
+ })}`);
438
580
  }
439
581
  async* walkEvents(params) {
440
582
  const batchSize = params.batchSize ?? 200;
@@ -462,17 +604,16 @@ class Index extends BaseClient {
462
604
  }
463
605
  }
464
606
  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}` : ""}`);
607
+ return this.request("GET", `/v1/index/contract-calls${buildQuery({
608
+ cursor: params.cursor,
609
+ from_cursor: params.fromCursor,
610
+ limit: params.limit,
611
+ contract_id: params.contractId,
612
+ function_name: params.functionName,
613
+ sender: params.sender,
614
+ from_height: params.fromHeight,
615
+ to_height: params.toHeight
616
+ })}`);
476
617
  }
477
618
  async* walkContractCalls(params = {}) {
478
619
  const batchSize = params.batchSize ?? 200;
@@ -504,7 +645,74 @@ class Index extends BaseClient {
504
645
  // src/streams/client.ts
505
646
  import { ed25519 } from "@secondlayer/shared";
506
647
 
648
+ // src/streams/errors.ts
649
+ class AuthError extends Error {
650
+ status = 401;
651
+ constructor(message = "API key invalid or expired.") {
652
+ super(message);
653
+ this.name = "AuthError";
654
+ }
655
+ }
656
+
657
+ class RateLimitError extends Error {
658
+ retryAfter;
659
+ status = 429;
660
+ constructor(message = "Rate limited. Try again later.", retryAfter) {
661
+ super(message);
662
+ this.retryAfter = retryAfter;
663
+ this.name = "RateLimitError";
664
+ }
665
+ }
666
+
667
+ class ValidationError extends Error {
668
+ status;
669
+ body;
670
+ constructor(message, status, body) {
671
+ super(message);
672
+ this.status = status;
673
+ this.body = body;
674
+ this.name = "ValidationError";
675
+ }
676
+ }
677
+
678
+ class StreamsServerError extends Error {
679
+ status;
680
+ body;
681
+ constructor(message, status, body) {
682
+ super(message);
683
+ this.status = status;
684
+ this.body = body;
685
+ this.name = "StreamsServerError";
686
+ }
687
+ }
688
+
689
+ class StreamsSignatureError extends Error {
690
+ constructor(message = "Streams response signature verification failed.") {
691
+ super(message);
692
+ this.name = "StreamsSignatureError";
693
+ }
694
+ }
695
+
696
+ // src/streams/cursor.ts
697
+ var Cursor = {
698
+ atHeight(height) {
699
+ return `${height}:0`;
700
+ },
701
+ parse(cursor) {
702
+ const parts = cursor.split(":");
703
+ const blockHeight = Number(parts[0]);
704
+ const eventIndex = Number(parts[1]);
705
+ if (parts.length !== 2 || !Number.isInteger(blockHeight) || !Number.isInteger(eventIndex)) {
706
+ throw new ValidationError(`Invalid stream cursor "${cursor}"; expected "<block>:<index>" (e.g. "951475:3").`, 400);
707
+ }
708
+ return { blockHeight, eventIndex };
709
+ }
710
+ };
711
+
507
712
  // src/streams/consumer.ts
713
+ function reorgKey(reorg) {
714
+ return `${reorg.detected_at}|${reorg.fork_point_height}|${reorg.new_canonical_tip}`;
715
+ }
508
716
  async function defaultSleep(ms, signal) {
509
717
  if (signal?.aborted)
510
718
  return;
@@ -521,10 +729,12 @@ async function defaultSleep(ms, signal) {
521
729
  async function consumeStreamsEvents(opts) {
522
730
  const sleep = opts.sleep ?? defaultSleep;
523
731
  const mode = opts.mode ?? "tail";
732
+ const finalizedOnly = opts.finalizedOnly ?? false;
524
733
  const emptyBackoffMs = opts.emptyBackoffMs ?? 500;
525
734
  const maxPages = opts.maxPages ?? Number.POSITIVE_INFINITY;
526
735
  const maxEmptyPolls = opts.maxEmptyPolls ?? Number.POSITIVE_INFINITY;
527
736
  let cursor = opts.fromCursor ?? null;
737
+ const handledReorgs = new Set;
528
738
  let pages = 0;
529
739
  let emptyPolls = 0;
530
740
  while (pages < maxPages && emptyPolls < maxEmptyPolls && !opts.signal?.aborted) {
@@ -539,14 +749,32 @@ async function consumeStreamsEvents(opts) {
539
749
  assetIdentifier: opts.assetIdentifier
540
750
  });
541
751
  pages++;
542
- const returnedCursor = await opts.onBatch(envelope.events, envelope);
543
- const nextCursor = returnedCursor ?? envelope.next_cursor;
752
+ if (!finalizedOnly && opts.onReorg) {
753
+ const fresh = envelope.reorgs.filter((reorg) => !handledReorgs.has(reorgKey(reorg))).sort((a, b) => a.fork_point_height - b.fork_point_height);
754
+ if (fresh.length > 0) {
755
+ const forkPoint = Math.min(...fresh.map((reorg) => reorg.fork_point_height));
756
+ const rewind = Cursor.atHeight(forkPoint);
757
+ for (const reorg of fresh) {
758
+ await opts.onReorg(reorg, { cursor: rewind });
759
+ handledReorgs.add(reorgKey(reorg));
760
+ }
761
+ cursor = rewind;
762
+ emptyPolls = 0;
763
+ continue;
764
+ }
765
+ }
766
+ const emitted = finalizedOnly ? envelope.events.filter((event) => event.finalized) : envelope.events;
767
+ const checkpoint = finalizedOnly ? emitted.at(-1)?.cursor ?? cursor : envelope.next_cursor;
768
+ const returnedCursor = await opts.onBatch(emitted, envelope, {
769
+ cursor: checkpoint
770
+ });
771
+ const nextCursor = returnedCursor ?? checkpoint;
544
772
  if (nextCursor && nextCursor !== cursor) {
545
773
  cursor = nextCursor;
546
774
  emptyPolls = 0;
547
775
  continue;
548
776
  }
549
- if (envelope.events.length === 0) {
777
+ if (emitted.length === 0) {
550
778
  emptyPolls++;
551
779
  if (mode === "bounded") {
552
780
  return { cursor, pages, emptyPolls };
@@ -602,56 +830,6 @@ async function* streamStreamsEvents(opts) {
602
830
 
603
831
  // src/streams/dumps.ts
604
832
  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
833
  function createStreamsDumps(opts) {
656
834
  const baseUrl = opts.baseUrl?.replace(/\/+$/, "");
657
835
  function requireBaseUrl() {
@@ -690,8 +868,12 @@ function createStreamsDumps(opts) {
690
868
  function cursorTuple(cursor) {
691
869
  if (!cursor)
692
870
  return [-1, -1];
693
- const [block, index] = cursor.split(":");
694
- return [Number(block), Number(index)];
871
+ const parts = cursor.split(":");
872
+ const [block, index] = parts.map(Number);
873
+ if (parts.length !== 2 || !Number.isInteger(block) || !Number.isInteger(index)) {
874
+ throw new ValidationError(`Invalid stream cursor "${cursor}"; expected "<block>:<index>" (e.g. "951475:3").`, 400);
875
+ }
876
+ return [block, index];
695
877
  }
696
878
  function maxCursor(a, b) {
697
879
  const [ah, ai] = cursorTuple(a);
@@ -702,18 +884,6 @@ var DEFAULT_STREAMS_BASE_URL = "https://api.secondlayer.tools";
702
884
  function normalizeBaseUrl(baseUrl) {
703
885
  return baseUrl.replace(/\/+$/, "");
704
886
  }
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
887
  async function responseBody(response) {
718
888
  const text = await response.text();
719
889
  if (text.length === 0)
@@ -835,23 +1005,18 @@ function createStreamsClient(options) {
835
1005
  });
836
1006
  };
837
1007
  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}` : ""}`);
1008
+ return request(`/v1/streams/events${buildQuery({
1009
+ cursor: params.cursor,
1010
+ from_height: params.fromHeight,
1011
+ to_height: params.toHeight,
1012
+ limit: params.limit,
1013
+ contract_id: params.contractId,
1014
+ sender: params.sender,
1015
+ recipient: params.recipient,
1016
+ asset_identifier: params.assetIdentifier,
1017
+ types: params.types,
1018
+ not_types: params.notTypes
1019
+ })}`);
855
1020
  }
856
1021
  return {
857
1022
  events: {
@@ -863,6 +1028,7 @@ function createStreamsClient(options) {
863
1028
  return consumeStreamsEvents({
864
1029
  fromCursor: params.fromCursor,
865
1030
  mode: params.mode,
1031
+ finalizedOnly: params.finalizedOnly,
866
1032
  types: params.types,
867
1033
  notTypes: params.notTypes,
868
1034
  contractId: params.contractId,
@@ -872,6 +1038,7 @@ function createStreamsClient(options) {
872
1038
  batchSize: params.batchSize ?? 100,
873
1039
  fetchEvents,
874
1040
  onBatch: params.onBatch,
1041
+ onReorg: params.onReorg,
875
1042
  emptyBackoffMs: params.emptyBackoffMs,
876
1043
  maxPages: params.maxPages,
877
1044
  maxEmptyPolls: params.maxEmptyPolls,
@@ -926,11 +1093,10 @@ function createStreamsClient(options) {
926
1093
  },
927
1094
  reorgs: {
928
1095
  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}` : ""}`);
1096
+ return request(`/v1/streams/reorgs${buildQuery({
1097
+ since: params.since,
1098
+ limit: params.limit
1099
+ })}`);
934
1100
  }
935
1101
  },
936
1102
  dumps,
@@ -987,6 +1153,8 @@ class Subscriptions extends BaseClient {
987
1153
  class SecondLayer extends BaseClient {
988
1154
  streams;
989
1155
  index;
1156
+ datasets;
1157
+ contracts;
990
1158
  subgraphs;
991
1159
  subscriptions;
992
1160
  constructor(options = {}) {
@@ -997,6 +1165,8 @@ class SecondLayer extends BaseClient {
997
1165
  fetchImpl: options.fetchImpl
998
1166
  });
999
1167
  this.index = new Index(options);
1168
+ this.datasets = new Datasets(options);
1169
+ this.contracts = new Contracts(options);
1000
1170
  this.subgraphs = new Subgraphs(options);
1001
1171
  this.subscriptions = new Subscriptions(options);
1002
1172
  }
@@ -1012,127 +1182,8 @@ function getSubgraph(def, options = {}) {
1012
1182
  }
1013
1183
  return new Subgraphs(options).typed(def);
1014
1184
  }
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
1185
  // src/streams/_payload.ts
1135
- function requireString3(payload, field, eventType) {
1186
+ function requireString(payload, field, eventType) {
1136
1187
  const value = payload[field];
1137
1188
  if (typeof value !== "string" || value.length === 0) {
1138
1189
  throw new Error(`${eventType} payload missing ${field}`);
@@ -1143,7 +1194,7 @@ function optionalString(value) {
1143
1194
  return typeof value === "string" && value.length > 0 ? value : null;
1144
1195
  }
1145
1196
  function requireAmountField(payload, field, eventType) {
1146
- const amount = requireString3(payload, field, eventType);
1197
+ const amount = requireString(payload, field, eventType);
1147
1198
  if (!/^(0|[1-9]\d*)$/.test(amount)) {
1148
1199
  throw new Error(`${eventType} payload has malformed ${field}`);
1149
1200
  }
@@ -1152,7 +1203,7 @@ function requireAmountField(payload, field, eventType) {
1152
1203
  function requireAmount(payload, eventType) {
1153
1204
  return requireAmountField(payload, "amount", eventType);
1154
1205
  }
1155
- function parseAssetIdentifier3(assetIdentifier, eventType) {
1206
+ function parseAssetIdentifier(assetIdentifier, eventType) {
1156
1207
  const [contractId, tokenName] = assetIdentifier.split("::");
1157
1208
  if (!contractId) {
1158
1209
  throw new Error(`${eventType} payload has malformed asset_identifier`);
@@ -1162,7 +1213,7 @@ function parseAssetIdentifier3(assetIdentifier, eventType) {
1162
1213
  token_name: tokenName && tokenName.length > 0 ? tokenName : null
1163
1214
  };
1164
1215
  }
1165
- function requireHexValue2(payload, eventType) {
1216
+ function requireHexValue(payload, eventType) {
1166
1217
  const rawValue = payload.raw_value;
1167
1218
  if (typeof rawValue === "string") {
1168
1219
  if (!/^0x[0-9a-fA-F]*$/.test(rawValue)) {
@@ -1193,6 +1244,52 @@ function decodedRow(event, eventType, decoded_payload) {
1193
1244
  };
1194
1245
  }
1195
1246
 
1247
+ // src/streams/ft-transfer.ts
1248
+ function isFtTransfer(event) {
1249
+ return event.event_type === "ft_transfer";
1250
+ }
1251
+ function decodeFtTransfer(event) {
1252
+ if (!isFtTransfer(event)) {
1253
+ throw new Error(`Expected ft_transfer event, got ${event.event_type}`);
1254
+ }
1255
+ const payload = event.payload;
1256
+ const assetIdentifier = requireString(payload, "asset_identifier", "ft_transfer");
1257
+ const sender = requireString(payload, "sender", "ft_transfer");
1258
+ const recipient = requireString(payload, "recipient", "ft_transfer");
1259
+ const amount = requireAmount(payload, "ft_transfer");
1260
+ const { contract_id, token_name } = parseAssetIdentifier(assetIdentifier, "ft_transfer");
1261
+ return decodedRow(event, "ft_transfer", {
1262
+ asset_identifier: assetIdentifier,
1263
+ contract_id: event.contract_id ?? contract_id,
1264
+ token_name,
1265
+ sender,
1266
+ recipient,
1267
+ amount
1268
+ });
1269
+ }
1270
+ // src/streams/nft-transfer.ts
1271
+ function isNftTransfer(event) {
1272
+ return event.event_type === "nft_transfer";
1273
+ }
1274
+ function decodeNftTransfer(event) {
1275
+ if (!isNftTransfer(event)) {
1276
+ throw new Error(`Expected nft_transfer event, got ${event.event_type}`);
1277
+ }
1278
+ const payload = event.payload;
1279
+ const assetIdentifier = requireString(payload, "asset_identifier", "nft_transfer");
1280
+ const sender = requireString(payload, "sender", "nft_transfer");
1281
+ const recipient = requireString(payload, "recipient", "nft_transfer");
1282
+ const value = requireHexValue(payload, "nft_transfer");
1283
+ const { contract_id, token_name } = parseAssetIdentifier(assetIdentifier, "nft_transfer");
1284
+ return decodedRow(event, "nft_transfer", {
1285
+ asset_identifier: assetIdentifier,
1286
+ contract_id: event.contract_id ?? contract_id,
1287
+ token_name,
1288
+ sender,
1289
+ recipient,
1290
+ value
1291
+ });
1292
+ }
1196
1293
  // src/streams/stx-events.ts
1197
1294
  function isStxTransfer(event) {
1198
1295
  return event.event_type === "stx_transfer";
@@ -1203,8 +1300,8 @@ function decodeStxTransfer(event) {
1203
1300
  }
1204
1301
  const payload = event.payload;
1205
1302
  return decodedRow(event, "stx_transfer", {
1206
- sender: requireString3(payload, "sender", "stx_transfer"),
1207
- recipient: requireString3(payload, "recipient", "stx_transfer"),
1303
+ sender: requireString(payload, "sender", "stx_transfer"),
1304
+ recipient: requireString(payload, "recipient", "stx_transfer"),
1208
1305
  amount: requireAmount(payload, "stx_transfer"),
1209
1306
  memo: optionalString(payload.memo)
1210
1307
  });
@@ -1218,7 +1315,7 @@ function decodeStxMint(event) {
1218
1315
  }
1219
1316
  const payload = event.payload;
1220
1317
  return decodedRow(event, "stx_mint", {
1221
- recipient: requireString3(payload, "recipient", "stx_mint"),
1318
+ recipient: requireString(payload, "recipient", "stx_mint"),
1222
1319
  amount: requireAmount(payload, "stx_mint")
1223
1320
  });
1224
1321
  }
@@ -1231,7 +1328,7 @@ function decodeStxBurn(event) {
1231
1328
  }
1232
1329
  const payload = event.payload;
1233
1330
  return decodedRow(event, "stx_burn", {
1234
- sender: requireString3(payload, "sender", "stx_burn"),
1331
+ sender: requireString(payload, "sender", "stx_burn"),
1235
1332
  amount: requireAmount(payload, "stx_burn")
1236
1333
  });
1237
1334
  }
@@ -1244,15 +1341,15 @@ function decodeStxLock(event) {
1244
1341
  }
1245
1342
  const payload = event.payload;
1246
1343
  return decodedRow(event, "stx_lock", {
1247
- sender: requireString3(payload, "locked_address", "stx_lock"),
1344
+ sender: requireString(payload, "locked_address", "stx_lock"),
1248
1345
  amount: requireAmountField(payload, "locked_amount", "stx_lock"),
1249
1346
  payload: { unlock_height: optionalString(payload.unlock_height) }
1250
1347
  });
1251
1348
  }
1252
1349
  // src/streams/token-mint-burn.ts
1253
1350
  function assetFields(event, eventType) {
1254
- const assetIdentifier = requireString3(event.payload, "asset_identifier", eventType);
1255
- const { contract_id, token_name } = parseAssetIdentifier3(assetIdentifier, eventType);
1351
+ const assetIdentifier = requireString(event.payload, "asset_identifier", eventType);
1352
+ const { contract_id, token_name } = parseAssetIdentifier(assetIdentifier, eventType);
1256
1353
  return {
1257
1354
  asset_identifier: assetIdentifier,
1258
1355
  contract_id: event.contract_id ?? contract_id,
@@ -1268,7 +1365,7 @@ function decodeFtMint(event) {
1268
1365
  }
1269
1366
  return decodedRow(event, "ft_mint", {
1270
1367
  ...assetFields(event, "ft_mint"),
1271
- recipient: requireString3(event.payload, "recipient", "ft_mint"),
1368
+ recipient: requireString(event.payload, "recipient", "ft_mint"),
1272
1369
  amount: requireAmount(event.payload, "ft_mint")
1273
1370
  });
1274
1371
  }
@@ -1281,7 +1378,7 @@ function decodeFtBurn(event) {
1281
1378
  }
1282
1379
  return decodedRow(event, "ft_burn", {
1283
1380
  ...assetFields(event, "ft_burn"),
1284
- sender: requireString3(event.payload, "sender", "ft_burn"),
1381
+ sender: requireString(event.payload, "sender", "ft_burn"),
1285
1382
  amount: requireAmount(event.payload, "ft_burn")
1286
1383
  });
1287
1384
  }
@@ -1294,8 +1391,8 @@ function decodeNftMint(event) {
1294
1391
  }
1295
1392
  return decodedRow(event, "nft_mint", {
1296
1393
  ...assetFields(event, "nft_mint"),
1297
- recipient: requireString3(event.payload, "recipient", "nft_mint"),
1298
- value: requireHexValue2(event.payload, "nft_mint")
1394
+ recipient: requireString(event.payload, "recipient", "nft_mint"),
1395
+ value: requireHexValue(event.payload, "nft_mint")
1299
1396
  });
1300
1397
  }
1301
1398
  function isNftBurn(event) {
@@ -1307,8 +1404,8 @@ function decodeNftBurn(event) {
1307
1404
  }
1308
1405
  return decodedRow(event, "nft_burn", {
1309
1406
  ...assetFields(event, "nft_burn"),
1310
- sender: requireString3(event.payload, "sender", "nft_burn"),
1311
- value: requireHexValue2(event.payload, "nft_burn")
1407
+ sender: requireString(event.payload, "sender", "nft_burn"),
1408
+ value: requireHexValue(event.payload, "nft_burn")
1312
1409
  });
1313
1410
  }
1314
1411
  // src/clarity.ts
@@ -1378,133 +1475,6 @@ var STREAMS_EVENT_TYPES = [
1378
1475
  "nft_burn",
1379
1476
  "print"
1380
1477
  ];
1381
- // 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
- var PARAM_KEYS = {
1388
- fromBlock: "from_block",
1389
- toBlock: "to_block",
1390
- functionName: "function_name",
1391
- delegateTo: "delegate_to",
1392
- signerKey: "signer_key",
1393
- rewardCycle: "reward_cycle",
1394
- eventType: "event_type",
1395
- bnsId: "bns_id"
1396
- };
1397
- var CURSOR_SLUGS = {
1398
- "stx-transfers": { path: "stx-transfers", rowKey: "events" },
1399
- "sbtc-events": { path: "sbtc/events", rowKey: "events" },
1400
- "sbtc-token-events": { path: "sbtc/token-events", rowKey: "events" },
1401
- "pox-4-calls": { path: "pox-4/calls", rowKey: "calls" },
1402
- "burnchain-rewards": { path: "burnchain/rewards", rowKey: "rewards" },
1403
- "burnchain-reward-slots": {
1404
- path: "burnchain/reward-slots",
1405
- rowKey: "slots"
1406
- },
1407
- "bns-events": { path: "bns/events", rowKey: "events" },
1408
- "bns-namespace-events": { path: "bns/namespace-events", rowKey: "events" },
1409
- "bns-marketplace-events": {
1410
- path: "bns/marketplace-events",
1411
- rowKey: "events"
1412
- }
1413
- };
1414
-
1415
- class Datasets extends BaseClient {
1416
- constructor(options = {}) {
1417
- super(options);
1418
- }
1419
- listDatasets() {
1420
- return this.request("GET", "/v1/datasets");
1421
- }
1422
- async query(slug, params = {}) {
1423
- const d = CURSOR_SLUGS[slug];
1424
- if (!d) {
1425
- throw new Error(`unknown cursor dataset "${slug}" (use one of: ${Object.keys(CURSOR_SLUGS).join(", ")})`);
1426
- }
1427
- const env = await this.get(d.path, this.buildParams(params));
1428
- return {
1429
- rows: env[d.rowKey] ?? [],
1430
- next_cursor: env.next_cursor ?? null,
1431
- tip: env.tip
1432
- };
1433
- }
1434
- stxTransfers = this.cursorDataset("stx-transfers", "events");
1435
- sbtcEvents = this.cursorDataset("sbtc/events", "events");
1436
- sbtcTokenEvents = this.cursorDataset("sbtc/token-events", "events");
1437
- pox4Calls = this.cursorDataset("pox-4/calls", "calls");
1438
- burnchainRewards = this.cursorDataset("burnchain/rewards", "rewards");
1439
- burnchainRewardSlots = this.cursorDataset("burnchain/reward-slots", "slots");
1440
- bnsEvents = this.cursorDataset("bns/events", "events");
1441
- bnsNamespaceEvents = this.cursorDataset("bns/namespace-events", "events");
1442
- bnsMarketplaceEvents = this.cursorDataset("bns/marketplace-events", "events");
1443
- 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);
1450
- }
1451
- bnsNamespaces() {
1452
- return this.get("bns/namespaces", new URLSearchParams);
1453
- }
1454
- bnsResolve(fqn) {
1455
- const sp = new URLSearchParams;
1456
- sp.set("fqn", fqn);
1457
- return this.get("bns/resolve", sp);
1458
- }
1459
- networkHealth() {
1460
- return this.get("network-health/summary", new URLSearchParams);
1461
- }
1462
- get(path, sp) {
1463
- const qs = sp.toString();
1464
- return this.request("GET", `/v1/datasets/${path}${qs ? `?${qs}` : ""}`);
1465
- }
1466
- buildParams(params) {
1467
- const sp = new URLSearchParams;
1468
- for (const [k, v] of Object.entries(params)) {
1469
- if (v === undefined || v === null || k === "batchSize" || k === "signal")
1470
- continue;
1471
- appendParam(sp, PARAM_KEYS[k] ?? k, v);
1472
- }
1473
- return sp;
1474
- }
1475
- cursorDataset(path, rowKey) {
1476
- const list = async (params = {}) => {
1477
- const envelope = await this.get(path, this.buildParams(params));
1478
- return {
1479
- rows: envelope[rowKey] ?? [],
1480
- next_cursor: envelope.next_cursor ?? null,
1481
- tip: envelope.tip
1482
- };
1483
- };
1484
- const walk = async function* (params = {}) {
1485
- const batchSize = params.batchSize ?? 200;
1486
- let cursor = params.cursor ?? null;
1487
- let first = true;
1488
- while (!params.signal?.aborted) {
1489
- const env = await list({
1490
- ...params,
1491
- limit: batchSize,
1492
- cursor: first ? params.cursor : cursor ?? undefined
1493
- });
1494
- for (const row of env.rows) {
1495
- if (params.signal?.aborted)
1496
- return;
1497
- yield row;
1498
- }
1499
- if (!env.next_cursor || env.next_cursor === cursor || env.rows.length < batchSize)
1500
- return;
1501
- cursor = env.next_cursor;
1502
- first = false;
1503
- }
1504
- }.bind(this);
1505
- return { list, walk };
1506
- }
1507
- }
1508
1478
  // src/webhooks.ts
1509
1479
  import {
1510
1480
  verify
@@ -1586,10 +1556,12 @@ export {
1586
1556
  RateLimitError,
1587
1557
  Index,
1588
1558
  Datasets,
1559
+ Cursor,
1560
+ Contracts,
1589
1561
  CURSOR_SLUGS,
1590
1562
  AuthError,
1591
1563
  ApiError
1592
1564
  };
1593
1565
 
1594
- //# debugId=4712778CA4B6FFB664756E2164756E21
1566
+ //# debugId=C7330C1F713D815864756E2164756E21
1595
1567
  //# sourceMappingURL=index.js.map