@secondlayer/sdk 6.21.2 → 6.23.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -442,6 +442,280 @@ class Contracts extends BaseClient {
442
442
  }
443
443
  }
444
444
 
445
+ // src/streams/errors.ts
446
+ class AuthError extends Error {
447
+ status = 401;
448
+ constructor(message = "API key invalid or expired.") {
449
+ super(message);
450
+ this.name = "AuthError";
451
+ }
452
+ }
453
+
454
+ class RateLimitError extends Error {
455
+ retryAfter;
456
+ status = 429;
457
+ constructor(message = "Rate limited. Try again later.", retryAfter) {
458
+ super(message);
459
+ this.retryAfter = retryAfter;
460
+ this.name = "RateLimitError";
461
+ }
462
+ }
463
+
464
+ class ValidationError extends Error {
465
+ status;
466
+ body;
467
+ constructor(message, status, body) {
468
+ super(message);
469
+ this.status = status;
470
+ this.body = body;
471
+ this.name = "ValidationError";
472
+ }
473
+ }
474
+
475
+ class StreamsServerError extends Error {
476
+ status;
477
+ body;
478
+ constructor(message, status, body) {
479
+ super(message);
480
+ this.status = status;
481
+ this.body = body;
482
+ this.name = "StreamsServerError";
483
+ }
484
+ }
485
+
486
+ class StreamsSignatureError extends Error {
487
+ constructor(message = "Streams response signature verification failed.") {
488
+ super(message);
489
+ this.name = "StreamsSignatureError";
490
+ }
491
+ }
492
+
493
+ // src/streams/cursor.ts
494
+ var Cursor = {
495
+ atHeight(height) {
496
+ return `${height}:0`;
497
+ },
498
+ parse(cursor) {
499
+ const parts = cursor.split(":");
500
+ const blockHeight = Number(parts[0]);
501
+ const eventIndex = Number(parts[1]);
502
+ if (parts.length !== 2 || !Number.isInteger(blockHeight) || !Number.isInteger(eventIndex)) {
503
+ throw new ValidationError(`Invalid stream cursor "${cursor}"; expected "<block>:<index>" (e.g. "951475:3").`, 400);
504
+ }
505
+ return { blockHeight, eventIndex };
506
+ }
507
+ };
508
+
509
+ // src/streams/consumer.ts
510
+ function reorgKey(reorg) {
511
+ return `${reorg.detected_at}|${reorg.fork_point_height}|${reorg.new_canonical_tip}`;
512
+ }
513
+ async function defaultSleep(ms, signal) {
514
+ if (signal?.aborted)
515
+ return;
516
+ await new Promise((resolve) => {
517
+ const timeout = setTimeout(resolve, ms);
518
+ if (!signal)
519
+ return;
520
+ signal.addEventListener("abort", () => {
521
+ clearTimeout(timeout);
522
+ resolve();
523
+ }, { once: true });
524
+ });
525
+ }
526
+ async function consumeStreamsEvents(opts) {
527
+ const sleep = opts.sleep ?? defaultSleep;
528
+ const mode = opts.mode ?? "tail";
529
+ const finalizedOnly = opts.finalizedOnly ?? false;
530
+ const emptyBackoffMs = opts.emptyBackoffMs ?? 500;
531
+ const maxPages = opts.maxPages ?? Number.POSITIVE_INFINITY;
532
+ const maxEmptyPolls = opts.maxEmptyPolls ?? Number.POSITIVE_INFINITY;
533
+ let cursor = opts.fromCursor ?? null;
534
+ const handledReorgs = new Set;
535
+ let pages = 0;
536
+ let emptyPolls = 0;
537
+ while (pages < maxPages && emptyPolls < maxEmptyPolls && !opts.signal?.aborted) {
538
+ const envelope = await opts.fetchEvents({
539
+ cursor,
540
+ limit: opts.batchSize,
541
+ types: opts.types,
542
+ notTypes: opts.notTypes,
543
+ contractId: opts.contractId,
544
+ sender: opts.sender,
545
+ recipient: opts.recipient,
546
+ assetIdentifier: opts.assetIdentifier
547
+ });
548
+ pages++;
549
+ if (!finalizedOnly && opts.onReorg) {
550
+ const fresh = envelope.reorgs.filter((reorg) => !handledReorgs.has(reorgKey(reorg))).sort((a, b) => a.fork_point_height - b.fork_point_height);
551
+ if (fresh.length > 0) {
552
+ const forkPoint = Math.min(...fresh.map((reorg) => reorg.fork_point_height));
553
+ const rewind = Cursor.atHeight(forkPoint);
554
+ for (const reorg of fresh) {
555
+ await opts.onReorg(reorg, { cursor: rewind });
556
+ handledReorgs.add(reorgKey(reorg));
557
+ }
558
+ cursor = rewind;
559
+ emptyPolls = 0;
560
+ continue;
561
+ }
562
+ }
563
+ const emitted = finalizedOnly ? envelope.events.filter((event) => event.finalized) : envelope.events;
564
+ const checkpoint = finalizedOnly ? emitted.at(-1)?.cursor ?? cursor : envelope.next_cursor;
565
+ const returnedCursor = await opts.onBatch(emitted, envelope, {
566
+ cursor: checkpoint
567
+ });
568
+ const nextCursor = returnedCursor ?? checkpoint;
569
+ if (nextCursor && nextCursor !== cursor) {
570
+ cursor = nextCursor;
571
+ emptyPolls = 0;
572
+ continue;
573
+ }
574
+ if (emitted.length === 0) {
575
+ emptyPolls++;
576
+ if (mode === "bounded") {
577
+ return { cursor, pages, emptyPolls };
578
+ }
579
+ await sleep(emptyBackoffMs, opts.signal);
580
+ continue;
581
+ }
582
+ return { cursor, pages, emptyPolls };
583
+ }
584
+ return { cursor, pages, emptyPolls };
585
+ }
586
+ async function* iterateStreamsBatches(opts) {
587
+ const sleep = opts.sleep ?? defaultSleep;
588
+ let cursor = opts.fromCursor ?? null;
589
+ while (!opts.signal?.aborted) {
590
+ const envelope = await opts.fetchEvents({
591
+ cursor,
592
+ limit: opts.batchSize,
593
+ types: opts.types,
594
+ notTypes: opts.notTypes,
595
+ contractId: opts.contractId,
596
+ sender: opts.sender,
597
+ recipient: opts.recipient,
598
+ assetIdentifier: opts.assetIdentifier
599
+ });
600
+ const checkpoint = envelope.next_cursor ?? cursor;
601
+ if (envelope.events.length > 0 || envelope.reorgs.length > 0) {
602
+ yield {
603
+ events: envelope.events,
604
+ cursor: checkpoint,
605
+ tip: envelope.tip,
606
+ reorgs: envelope.reorgs
607
+ };
608
+ }
609
+ const advanced = checkpoint !== null && checkpoint !== cursor;
610
+ cursor = checkpoint;
611
+ if (!advanced && envelope.events.length === 0) {
612
+ if (opts.signal?.aborted)
613
+ return;
614
+ await sleep(opts.intervalMs, opts.signal);
615
+ }
616
+ }
617
+ }
618
+ async function* streamStreamsEvents(opts) {
619
+ const sleep = opts.sleep ?? defaultSleep;
620
+ const emptyBackoffMs = opts.emptyBackoffMs ?? 500;
621
+ const maxPages = opts.maxPages ?? Number.POSITIVE_INFINITY;
622
+ const maxEmptyPolls = opts.maxEmptyPolls ?? Number.POSITIVE_INFINITY;
623
+ let cursor = opts.fromCursor ?? null;
624
+ let pages = 0;
625
+ let emptyPolls = 0;
626
+ while (pages < maxPages && emptyPolls < maxEmptyPolls && !opts.signal?.aborted) {
627
+ const envelope = await opts.fetchEvents({
628
+ cursor,
629
+ limit: opts.batchSize,
630
+ types: opts.types,
631
+ notTypes: opts.notTypes,
632
+ contractId: opts.contractId,
633
+ sender: opts.sender,
634
+ recipient: opts.recipient,
635
+ assetIdentifier: opts.assetIdentifier
636
+ });
637
+ pages++;
638
+ for (const event of envelope.events) {
639
+ if (opts.signal?.aborted)
640
+ return;
641
+ yield event;
642
+ }
643
+ const nextCursor = envelope.next_cursor;
644
+ if (nextCursor && nextCursor !== cursor) {
645
+ cursor = nextCursor;
646
+ emptyPolls = 0;
647
+ continue;
648
+ }
649
+ if (envelope.events.length === 0) {
650
+ emptyPolls++;
651
+ if (emptyPolls >= maxEmptyPolls || pages >= maxPages)
652
+ return;
653
+ await sleep(emptyBackoffMs, opts.signal);
654
+ continue;
655
+ }
656
+ return;
657
+ }
658
+ }
659
+
660
+ // src/index-api/consumer.ts
661
+ async function consumeIndexFeed(opts) {
662
+ const sleep = opts.sleep ?? defaultSleep;
663
+ const mode = opts.mode ?? "tail";
664
+ const finalizedOnly = opts.finalizedOnly ?? false;
665
+ const batchSize = opts.batchSize ?? 200;
666
+ const emptyBackoffMs = opts.emptyBackoffMs ?? 500;
667
+ const maxPages = opts.maxPages ?? Number.POSITIVE_INFINITY;
668
+ const maxEmptyPolls = opts.maxEmptyPolls ?? Number.POSITIVE_INFINITY;
669
+ let cursor = opts.fromCursor ?? null;
670
+ const handledReorgs = new Set;
671
+ let pages = 0;
672
+ let emptyPolls = 0;
673
+ while (pages < maxPages && emptyPolls < maxEmptyPolls && !opts.signal?.aborted) {
674
+ const envelope = await opts.fetchPage({
675
+ cursor,
676
+ fromHeight: cursor === null ? opts.fromHeight : undefined,
677
+ limit: batchSize
678
+ });
679
+ pages++;
680
+ if (!finalizedOnly && opts.onReorg) {
681
+ const fresh = envelope.reorgs.filter((reorg) => !handledReorgs.has(reorg.id)).sort((a, b) => a.fork_point_height - b.fork_point_height);
682
+ if (fresh.length > 0) {
683
+ const forkPoint = Math.min(...fresh.map((reorg) => reorg.fork_point_height));
684
+ const rewind = Cursor.atHeight(forkPoint);
685
+ for (const reorg of fresh) {
686
+ await opts.onReorg(reorg, { cursor: rewind });
687
+ handledReorgs.add(reorg.id);
688
+ }
689
+ cursor = rewind;
690
+ emptyPolls = 0;
691
+ continue;
692
+ }
693
+ }
694
+ const items = opts.itemsOf(envelope);
695
+ const emitted = finalizedOnly ? items.filter((item) => item.block_height <= envelope.tip.finalized_height) : items;
696
+ const checkpoint = finalizedOnly ? emitted.at(-1)?.cursor ?? cursor : envelope.next_cursor;
697
+ const returnedCursor = await opts.onBatch(emitted, envelope, {
698
+ cursor: checkpoint
699
+ });
700
+ const nextCursor = returnedCursor ?? checkpoint;
701
+ if (nextCursor && nextCursor !== cursor) {
702
+ cursor = nextCursor;
703
+ emptyPolls = 0;
704
+ continue;
705
+ }
706
+ if (emitted.length === 0) {
707
+ emptyPolls++;
708
+ if (mode === "bounded") {
709
+ return { cursor, pages, emptyPolls };
710
+ }
711
+ await sleep(emptyBackoffMs, opts.signal);
712
+ continue;
713
+ }
714
+ return { cursor, pages, emptyPolls };
715
+ }
716
+ return { cursor, pages, emptyPolls };
717
+ }
718
+
445
719
  // src/index-api/client.ts
446
720
  function firstWalkFromHeight(params) {
447
721
  if (params.fromHeight !== undefined)
@@ -461,6 +735,15 @@ class Index extends BaseClient {
461
735
  discover() {
462
736
  return this.request("GET", "/v1/index");
463
737
  }
738
+ async printSchema(contractId) {
739
+ try {
740
+ return await this.request("GET", `/v1/index/contracts/${encodeURIComponent(contractId)}/print-schema`);
741
+ } catch (err) {
742
+ if (err instanceof ApiError && err.status === 404)
743
+ return null;
744
+ throw err;
745
+ }
746
+ }
464
747
  ftTransfers = Object.assign((params = {}) => this.listFtTransfers(params), {
465
748
  list: (params = {}) => this.listFtTransfers(params),
466
749
  walk: (params = {}) => this.walkFtTransfers(params)
@@ -471,11 +754,41 @@ class Index extends BaseClient {
471
754
  });
472
755
  events = Object.assign((params) => this.listEvents(params), {
473
756
  list: (params) => this.listEvents(params),
474
- walk: (params) => this.walkEvents(params)
757
+ walk: (params) => this.walkEvents(params),
758
+ consume: (params) => consumeIndexFeed({
759
+ ...params,
760
+ fetchPage: ({ cursor, fromHeight, limit }) => this.listEvents({
761
+ eventType: params.eventType,
762
+ contractId: params.contractId,
763
+ assetIdentifier: params.assetIdentifier,
764
+ sender: params.sender,
765
+ recipient: params.recipient,
766
+ trait: params.trait,
767
+ toHeight: params.toHeight,
768
+ cursor,
769
+ fromHeight,
770
+ limit
771
+ }),
772
+ itemsOf: (envelope) => envelope.events
773
+ })
475
774
  });
476
775
  contractCalls = {
477
776
  list: (params = {}) => this.listContractCalls(params),
478
- walk: (params = {}) => this.walkContractCalls(params)
777
+ walk: (params = {}) => this.walkContractCalls(params),
778
+ consume: (params) => consumeIndexFeed({
779
+ ...params,
780
+ fetchPage: ({ cursor, fromHeight, limit }) => this.listContractCalls({
781
+ contractId: params.contractId,
782
+ functionName: params.functionName,
783
+ sender: params.sender,
784
+ trait: params.trait,
785
+ toHeight: params.toHeight,
786
+ cursor,
787
+ fromHeight,
788
+ limit
789
+ }),
790
+ itemsOf: (envelope) => envelope.contract_calls
791
+ })
479
792
  };
480
793
  canonical = {
481
794
  list: (params = {}) => this.listCanonical(params),
@@ -896,221 +1209,6 @@ class Projects extends BaseClient {
896
1209
  // src/streams/client.ts
897
1210
  import { ed25519 as ed255192 } from "@secondlayer/shared";
898
1211
 
899
- // src/streams/errors.ts
900
- class AuthError extends Error {
901
- status = 401;
902
- constructor(message = "API key invalid or expired.") {
903
- super(message);
904
- this.name = "AuthError";
905
- }
906
- }
907
-
908
- class RateLimitError extends Error {
909
- retryAfter;
910
- status = 429;
911
- constructor(message = "Rate limited. Try again later.", retryAfter) {
912
- super(message);
913
- this.retryAfter = retryAfter;
914
- this.name = "RateLimitError";
915
- }
916
- }
917
-
918
- class ValidationError extends Error {
919
- status;
920
- body;
921
- constructor(message, status, body) {
922
- super(message);
923
- this.status = status;
924
- this.body = body;
925
- this.name = "ValidationError";
926
- }
927
- }
928
-
929
- class StreamsServerError extends Error {
930
- status;
931
- body;
932
- constructor(message, status, body) {
933
- super(message);
934
- this.status = status;
935
- this.body = body;
936
- this.name = "StreamsServerError";
937
- }
938
- }
939
-
940
- class StreamsSignatureError extends Error {
941
- constructor(message = "Streams response signature verification failed.") {
942
- super(message);
943
- this.name = "StreamsSignatureError";
944
- }
945
- }
946
-
947
- // src/streams/cursor.ts
948
- var Cursor = {
949
- atHeight(height) {
950
- return `${height}:0`;
951
- },
952
- parse(cursor) {
953
- const parts = cursor.split(":");
954
- const blockHeight = Number(parts[0]);
955
- const eventIndex = Number(parts[1]);
956
- if (parts.length !== 2 || !Number.isInteger(blockHeight) || !Number.isInteger(eventIndex)) {
957
- throw new ValidationError(`Invalid stream cursor "${cursor}"; expected "<block>:<index>" (e.g. "951475:3").`, 400);
958
- }
959
- return { blockHeight, eventIndex };
960
- }
961
- };
962
-
963
- // src/streams/consumer.ts
964
- function reorgKey(reorg) {
965
- return `${reorg.detected_at}|${reorg.fork_point_height}|${reorg.new_canonical_tip}`;
966
- }
967
- async function defaultSleep(ms, signal) {
968
- if (signal?.aborted)
969
- return;
970
- await new Promise((resolve) => {
971
- const timeout = setTimeout(resolve, ms);
972
- if (!signal)
973
- return;
974
- signal.addEventListener("abort", () => {
975
- clearTimeout(timeout);
976
- resolve();
977
- }, { once: true });
978
- });
979
- }
980
- async function consumeStreamsEvents(opts) {
981
- const sleep = opts.sleep ?? defaultSleep;
982
- const mode = opts.mode ?? "tail";
983
- const finalizedOnly = opts.finalizedOnly ?? false;
984
- const emptyBackoffMs = opts.emptyBackoffMs ?? 500;
985
- const maxPages = opts.maxPages ?? Number.POSITIVE_INFINITY;
986
- const maxEmptyPolls = opts.maxEmptyPolls ?? Number.POSITIVE_INFINITY;
987
- let cursor = opts.fromCursor ?? null;
988
- const handledReorgs = new Set;
989
- let pages = 0;
990
- let emptyPolls = 0;
991
- while (pages < maxPages && emptyPolls < maxEmptyPolls && !opts.signal?.aborted) {
992
- const envelope = await opts.fetchEvents({
993
- cursor,
994
- limit: opts.batchSize,
995
- types: opts.types,
996
- notTypes: opts.notTypes,
997
- contractId: opts.contractId,
998
- sender: opts.sender,
999
- recipient: opts.recipient,
1000
- assetIdentifier: opts.assetIdentifier
1001
- });
1002
- pages++;
1003
- if (!finalizedOnly && opts.onReorg) {
1004
- const fresh = envelope.reorgs.filter((reorg) => !handledReorgs.has(reorgKey(reorg))).sort((a, b) => a.fork_point_height - b.fork_point_height);
1005
- if (fresh.length > 0) {
1006
- const forkPoint = Math.min(...fresh.map((reorg) => reorg.fork_point_height));
1007
- const rewind = Cursor.atHeight(forkPoint);
1008
- for (const reorg of fresh) {
1009
- await opts.onReorg(reorg, { cursor: rewind });
1010
- handledReorgs.add(reorgKey(reorg));
1011
- }
1012
- cursor = rewind;
1013
- emptyPolls = 0;
1014
- continue;
1015
- }
1016
- }
1017
- const emitted = finalizedOnly ? envelope.events.filter((event) => event.finalized) : envelope.events;
1018
- const checkpoint = finalizedOnly ? emitted.at(-1)?.cursor ?? cursor : envelope.next_cursor;
1019
- const returnedCursor = await opts.onBatch(emitted, envelope, {
1020
- cursor: checkpoint
1021
- });
1022
- const nextCursor = returnedCursor ?? checkpoint;
1023
- if (nextCursor && nextCursor !== cursor) {
1024
- cursor = nextCursor;
1025
- emptyPolls = 0;
1026
- continue;
1027
- }
1028
- if (emitted.length === 0) {
1029
- emptyPolls++;
1030
- if (mode === "bounded") {
1031
- return { cursor, pages, emptyPolls };
1032
- }
1033
- await sleep(emptyBackoffMs, opts.signal);
1034
- continue;
1035
- }
1036
- return { cursor, pages, emptyPolls };
1037
- }
1038
- return { cursor, pages, emptyPolls };
1039
- }
1040
- async function* iterateStreamsBatches(opts) {
1041
- const sleep = opts.sleep ?? defaultSleep;
1042
- let cursor = opts.fromCursor ?? null;
1043
- while (!opts.signal?.aborted) {
1044
- const envelope = await opts.fetchEvents({
1045
- cursor,
1046
- limit: opts.batchSize,
1047
- types: opts.types,
1048
- notTypes: opts.notTypes,
1049
- contractId: opts.contractId,
1050
- sender: opts.sender,
1051
- recipient: opts.recipient,
1052
- assetIdentifier: opts.assetIdentifier
1053
- });
1054
- const checkpoint = envelope.next_cursor ?? cursor;
1055
- if (envelope.events.length > 0 || envelope.reorgs.length > 0) {
1056
- yield {
1057
- events: envelope.events,
1058
- cursor: checkpoint,
1059
- tip: envelope.tip,
1060
- reorgs: envelope.reorgs
1061
- };
1062
- }
1063
- const advanced = checkpoint !== null && checkpoint !== cursor;
1064
- cursor = checkpoint;
1065
- if (!advanced && envelope.events.length === 0) {
1066
- if (opts.signal?.aborted)
1067
- return;
1068
- await sleep(opts.intervalMs, opts.signal);
1069
- }
1070
- }
1071
- }
1072
- async function* streamStreamsEvents(opts) {
1073
- const sleep = opts.sleep ?? defaultSleep;
1074
- const emptyBackoffMs = opts.emptyBackoffMs ?? 500;
1075
- const maxPages = opts.maxPages ?? Number.POSITIVE_INFINITY;
1076
- const maxEmptyPolls = opts.maxEmptyPolls ?? Number.POSITIVE_INFINITY;
1077
- let cursor = opts.fromCursor ?? null;
1078
- let pages = 0;
1079
- let emptyPolls = 0;
1080
- while (pages < maxPages && emptyPolls < maxEmptyPolls && !opts.signal?.aborted) {
1081
- const envelope = await opts.fetchEvents({
1082
- cursor,
1083
- limit: opts.batchSize,
1084
- types: opts.types,
1085
- notTypes: opts.notTypes,
1086
- contractId: opts.contractId,
1087
- sender: opts.sender,
1088
- recipient: opts.recipient,
1089
- assetIdentifier: opts.assetIdentifier
1090
- });
1091
- pages++;
1092
- for (const event of envelope.events) {
1093
- if (opts.signal?.aborted)
1094
- return;
1095
- yield event;
1096
- }
1097
- const nextCursor = envelope.next_cursor;
1098
- if (nextCursor && nextCursor !== cursor) {
1099
- cursor = nextCursor;
1100
- emptyPolls = 0;
1101
- continue;
1102
- }
1103
- if (envelope.events.length === 0) {
1104
- emptyPolls++;
1105
- if (emptyPolls >= maxEmptyPolls || pages >= maxPages)
1106
- return;
1107
- await sleep(emptyBackoffMs, opts.signal);
1108
- continue;
1109
- }
1110
- return;
1111
- }
1112
- }
1113
-
1114
1212
  // src/streams/dumps.ts
1115
1213
  import { createHash } from "node:crypto";
1116
1214
  import { verifyStreamsBulkManifestSignature } from "@secondlayer/shared/streams-bulk-manifest";
@@ -2373,6 +2471,7 @@ export {
2373
2471
  decodeClarityValue,
2374
2472
  createX402Client,
2375
2473
  createStreamsClient,
2474
+ consumeIndexFeed,
2376
2475
  buildSignedX402Payment,
2377
2476
  X402SpendGuardError,
2378
2477
  VersionConflictError,
@@ -2394,5 +2493,5 @@ export {
2394
2493
  ApiError
2395
2494
  };
2396
2495
 
2397
- //# debugId=EAC231197163FBBB64756E2164756E21
2496
+ //# debugId=97CCB6EA784D158564756E2164756E21
2398
2497
  //# sourceMappingURL=index.js.map