@secondlayer/sdk 6.37.1 → 6.38.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.
@@ -399,7 +399,7 @@ async function consumeStreamsEvents(opts) {
399
399
  const emptyBackoffMs = opts.emptyBackoffMs ?? 500;
400
400
  const maxPages = opts.maxPages ?? Number.POSITIVE_INFINITY;
401
401
  const maxEmptyPolls = opts.maxEmptyPolls ?? Number.POSITIVE_INFINITY;
402
- let cursor = opts.fromCursor ?? null;
402
+ let cursor = opts.fromCursor ?? await opts.sink?.loadCursor() ?? null;
403
403
  const handledReorgs = new Set;
404
404
  let pages = 0;
405
405
  let emptyPolls = 0;
@@ -422,13 +422,14 @@ async function consumeStreamsEvents(opts) {
422
422
  signal: opts.signal
423
423
  });
424
424
  pages++;
425
- if (!finalizedOnly && opts.onReorg) {
425
+ if (!finalizedOnly && (opts.onReorg || opts.sink)) {
426
426
  const fresh = envelope.reorgs.filter((reorg) => !handledReorgs.has(reorgKey(reorg))).sort((a, b) => a.fork_point_height - b.fork_point_height);
427
427
  if (fresh.length > 0) {
428
428
  const forkPoint = Math.min(...fresh.map((reorg) => reorg.fork_point_height));
429
429
  const rewind = Cursor.atHeight(forkPoint);
430
430
  for (const reorg of fresh) {
431
- await opts.onReorg(reorg, { cursor: rewind });
431
+ await opts.sink?.rollback(reorg.fork_point_height, rewind);
432
+ await opts.onReorg?.(reorg, { cursor: rewind });
432
433
  handledReorgs.add(reorgKey(reorg));
433
434
  }
434
435
  cursor = rewind;
@@ -440,10 +441,26 @@ async function consumeStreamsEvents(opts) {
440
441
  const emitted = finalizedOnly ? envelope.events.filter((event) => event.finalized) : envelope.events;
441
442
  const checkpoint = finalizedOnly ? emitted.at(-1)?.cursor ?? cursor : envelope.next_cursor;
442
443
  height = emitted.at(-1)?.block_height ?? height;
443
- const returnedCursor = await opts.onBatch(emitted, envelope, batchContext(checkpoint, height, envelope.tip.block_height));
444
- if (finalizedOnly)
445
- assertFinalizedCheckpoint(returnedCursor, checkpoint);
446
- const nextCursor = returnedCursor ?? checkpoint;
444
+ const ctx = batchContext(checkpoint, height, envelope.tip.block_height);
445
+ opts.onProgress?.(ctx);
446
+ let nextCursor;
447
+ if (opts.sink) {
448
+ const sink = opts.sink;
449
+ if (checkpoint !== null && (checkpoint !== cursor || emitted.length > 0)) {
450
+ await sink.commitBatch(checkpoint, async (tx) => {
451
+ await opts.onBatch(emitted, envelope, {
452
+ ...ctx,
453
+ tx
454
+ });
455
+ });
456
+ }
457
+ nextCursor = checkpoint;
458
+ } else {
459
+ const returnedCursor = await opts.onBatch(emitted, envelope, ctx);
460
+ if (finalizedOnly)
461
+ assertFinalizedCheckpoint(returnedCursor, checkpoint);
462
+ nextCursor = returnedCursor ?? checkpoint;
463
+ }
447
464
  if (nextCursor && nextCursor !== cursor) {
448
465
  cursor = nextCursor;
449
466
  emptyPolls = 0;
@@ -535,6 +552,175 @@ async function* streamStreamsEvents(opts) {
535
552
  }
536
553
  }
537
554
 
555
+ // src/streams/_payload.ts
556
+ function requireString(payload, field, eventType) {
557
+ const value = payload[field];
558
+ if (typeof value !== "string" || value.length === 0) {
559
+ throw new Error(`${eventType} payload missing ${field}`);
560
+ }
561
+ return value;
562
+ }
563
+ function optionalString(value) {
564
+ return typeof value === "string" && value.length > 0 ? value : null;
565
+ }
566
+ function requireAmountField(payload, field, eventType) {
567
+ const amount = requireString(payload, field, eventType);
568
+ if (!/^(0|[1-9]\d*)$/.test(amount)) {
569
+ throw new Error(`${eventType} payload has malformed ${field}`);
570
+ }
571
+ return amount;
572
+ }
573
+ function requireAmount(payload, eventType) {
574
+ return requireAmountField(payload, "amount", eventType);
575
+ }
576
+ function parseAssetIdentifier(assetIdentifier, eventType) {
577
+ const [contractId, tokenName] = assetIdentifier.split("::");
578
+ if (!contractId) {
579
+ throw new Error(`${eventType} payload has malformed asset_identifier`);
580
+ }
581
+ return {
582
+ contract_id: contractId,
583
+ token_name: tokenName && tokenName.length > 0 ? tokenName : null
584
+ };
585
+ }
586
+ function requireHexValue(payload, eventType) {
587
+ const rawValue = payload.raw_value;
588
+ if (typeof rawValue === "string") {
589
+ if (!/^0x[0-9a-fA-F]*$/.test(rawValue)) {
590
+ throw new Error(`${eventType} payload has malformed value`);
591
+ }
592
+ return rawValue;
593
+ }
594
+ const value = payload.value;
595
+ const hex = typeof value === "string" ? value : value && typeof value === "object" && typeof value.hex === "string" ? value.hex : null;
596
+ if (!hex) {
597
+ throw new Error(`${eventType} payload missing value`);
598
+ }
599
+ if (!/^0x[0-9a-fA-F]*$/.test(hex)) {
600
+ throw new Error(`${eventType} payload has malformed value`);
601
+ }
602
+ return hex;
603
+ }
604
+ function decodedRow(event, eventType, decoded_payload) {
605
+ return {
606
+ cursor: event.cursor,
607
+ block_height: event.block_height,
608
+ tx_id: event.tx_id,
609
+ tx_index: event.tx_index,
610
+ event_index: event.event_index,
611
+ event_type: eventType,
612
+ decoded_payload,
613
+ source_cursor: event.cursor
614
+ };
615
+ }
616
+
617
+ // src/streams/decode.ts
618
+ function decode(event) {
619
+ const base = {
620
+ cursor: event.cursor,
621
+ block_height: event.block_height,
622
+ block_time: event.ts,
623
+ tx_id: event.tx_id,
624
+ tx_index: event.tx_index,
625
+ event_index: event.event_index,
626
+ contract_id: event.contract_id
627
+ };
628
+ const p = event.payload;
629
+ switch (event.event_type) {
630
+ case "stx_transfer":
631
+ return {
632
+ ...base,
633
+ event_type: "stx_transfer",
634
+ sender: requireString(p, "sender", event.event_type),
635
+ recipient: requireString(p, "recipient", event.event_type),
636
+ amount: requireAmountField(p, "amount", event.event_type),
637
+ memo: optionalString(p.memo)
638
+ };
639
+ case "stx_mint":
640
+ return {
641
+ ...base,
642
+ event_type: "stx_mint",
643
+ recipient: requireString(p, "recipient", event.event_type),
644
+ amount: requireAmountField(p, "amount", event.event_type)
645
+ };
646
+ case "stx_burn":
647
+ return {
648
+ ...base,
649
+ event_type: "stx_burn",
650
+ sender: requireString(p, "sender", event.event_type),
651
+ amount: requireAmountField(p, "amount", event.event_type)
652
+ };
653
+ case "stx_lock":
654
+ return {
655
+ ...base,
656
+ event_type: "stx_lock",
657
+ sender: requireString(p, "locked_address", event.event_type),
658
+ amount: requireAmountField(p, "locked_amount", event.event_type),
659
+ payload: { unlock_height: optionalString(p.unlock_height) }
660
+ };
661
+ case "ft_transfer":
662
+ return {
663
+ ...base,
664
+ event_type: "ft_transfer",
665
+ asset_identifier: requireString(p, "asset_identifier", event.event_type),
666
+ sender: requireString(p, "sender", event.event_type),
667
+ recipient: requireString(p, "recipient", event.event_type),
668
+ amount: requireAmountField(p, "amount", event.event_type)
669
+ };
670
+ case "ft_mint":
671
+ return {
672
+ ...base,
673
+ event_type: "ft_mint",
674
+ asset_identifier: requireString(p, "asset_identifier", event.event_type),
675
+ recipient: requireString(p, "recipient", event.event_type),
676
+ amount: requireAmountField(p, "amount", event.event_type)
677
+ };
678
+ case "ft_burn":
679
+ return {
680
+ ...base,
681
+ event_type: "ft_burn",
682
+ asset_identifier: requireString(p, "asset_identifier", event.event_type),
683
+ sender: requireString(p, "sender", event.event_type),
684
+ amount: requireAmountField(p, "amount", event.event_type)
685
+ };
686
+ case "nft_transfer":
687
+ return {
688
+ ...base,
689
+ event_type: "nft_transfer",
690
+ asset_identifier: requireString(p, "asset_identifier", event.event_type),
691
+ sender: requireString(p, "sender", event.event_type),
692
+ recipient: requireString(p, "recipient", event.event_type),
693
+ value: requireHexValue(p, event.event_type)
694
+ };
695
+ case "nft_mint":
696
+ return {
697
+ ...base,
698
+ event_type: "nft_mint",
699
+ asset_identifier: requireString(p, "asset_identifier", event.event_type),
700
+ recipient: requireString(p, "recipient", event.event_type),
701
+ value: requireHexValue(p, event.event_type)
702
+ };
703
+ case "nft_burn":
704
+ return {
705
+ ...base,
706
+ event_type: "nft_burn",
707
+ asset_identifier: requireString(p, "asset_identifier", event.event_type),
708
+ sender: requireString(p, "sender", event.event_type),
709
+ value: requireHexValue(p, event.event_type)
710
+ };
711
+ case "print":
712
+ return {
713
+ ...base,
714
+ event_type: "print",
715
+ payload: {
716
+ topic: optionalString(p.topic),
717
+ value: p.value,
718
+ raw_value: optionalString(p.raw_value)
719
+ }
720
+ };
721
+ }
722
+ }
723
+
538
724
  // src/streams/dumps.ts
539
725
  import { createHash } from "node:crypto";
540
726
  import { verifyStreamsBulkManifestSignature } from "@secondlayer/shared/streams-bulk-manifest";
@@ -909,8 +1095,11 @@ function createStreamsClient(options) {
909
1095
  return request(`/v1/streams/events/${encodeURIComponent(txId)}`);
910
1096
  },
911
1097
  consume(params) {
1098
+ const onBatch = params.decoded ? (events, envelope, ctx) => params.onBatch(events.map(decode), envelope, ctx) : params.onBatch;
912
1099
  return consumeStreamsEvents({
913
1100
  fromCursor: params.fromCursor,
1101
+ sink: params.sink,
1102
+ onProgress: params.onProgress,
914
1103
  mode: params.mode,
915
1104
  finalizedOnly: params.finalizedOnly,
916
1105
  types: params.types,
@@ -921,7 +1110,7 @@ function createStreamsClient(options) {
921
1110
  assetIdentifier: params.assetIdentifier,
922
1111
  batchSize: params.batchSize ?? 100,
923
1112
  fetchEvents,
924
- onBatch: params.onBatch,
1113
+ onBatch,
925
1114
  onReorg: params.onReorg,
926
1115
  emptyBackoffMs: params.emptyBackoffMs,
927
1116
  maxPages: params.maxPages,
@@ -1009,68 +1198,6 @@ function createStreamsClient(options) {
1009
1198
  }
1010
1199
  };
1011
1200
  }
1012
- // src/streams/_payload.ts
1013
- function requireString(payload, field, eventType) {
1014
- const value = payload[field];
1015
- if (typeof value !== "string" || value.length === 0) {
1016
- throw new Error(`${eventType} payload missing ${field}`);
1017
- }
1018
- return value;
1019
- }
1020
- function optionalString(value) {
1021
- return typeof value === "string" && value.length > 0 ? value : null;
1022
- }
1023
- function requireAmountField(payload, field, eventType) {
1024
- const amount = requireString(payload, field, eventType);
1025
- if (!/^(0|[1-9]\d*)$/.test(amount)) {
1026
- throw new Error(`${eventType} payload has malformed ${field}`);
1027
- }
1028
- return amount;
1029
- }
1030
- function requireAmount(payload, eventType) {
1031
- return requireAmountField(payload, "amount", eventType);
1032
- }
1033
- function parseAssetIdentifier(assetIdentifier, eventType) {
1034
- const [contractId, tokenName] = assetIdentifier.split("::");
1035
- if (!contractId) {
1036
- throw new Error(`${eventType} payload has malformed asset_identifier`);
1037
- }
1038
- return {
1039
- contract_id: contractId,
1040
- token_name: tokenName && tokenName.length > 0 ? tokenName : null
1041
- };
1042
- }
1043
- function requireHexValue(payload, eventType) {
1044
- const rawValue = payload.raw_value;
1045
- if (typeof rawValue === "string") {
1046
- if (!/^0x[0-9a-fA-F]*$/.test(rawValue)) {
1047
- throw new Error(`${eventType} payload has malformed value`);
1048
- }
1049
- return rawValue;
1050
- }
1051
- const value = payload.value;
1052
- const hex = typeof value === "string" ? value : value && typeof value === "object" && typeof value.hex === "string" ? value.hex : null;
1053
- if (!hex) {
1054
- throw new Error(`${eventType} payload missing value`);
1055
- }
1056
- if (!/^0x[0-9a-fA-F]*$/.test(hex)) {
1057
- throw new Error(`${eventType} payload has malformed value`);
1058
- }
1059
- return hex;
1060
- }
1061
- function decodedRow(event, eventType, decoded_payload) {
1062
- return {
1063
- cursor: event.cursor,
1064
- block_height: event.block_height,
1065
- tx_id: event.tx_id,
1066
- tx_index: event.tx_index,
1067
- event_index: event.event_index,
1068
- event_type: eventType,
1069
- decoded_payload,
1070
- source_cursor: event.cursor
1071
- };
1072
- }
1073
-
1074
1201
  // src/streams/ft-transfer.ts
1075
1202
  function isFtTransfer(event) {
1076
1203
  return event.event_type === "ft_transfer";
@@ -1315,6 +1442,7 @@ export {
1315
1442
  decodeFtTransfer,
1316
1443
  decodeFtMint,
1317
1444
  decodeFtBurn,
1445
+ decode,
1318
1446
  createStreamsClient,
1319
1447
  ValidationError,
1320
1448
  StreamsSignatureError,
@@ -1325,5 +1453,5 @@ export {
1325
1453
  AuthError
1326
1454
  };
1327
1455
 
1328
- //# debugId=9793637197EFD6F364756E2164756E21
1456
+ //# debugId=5CDDE8F307DF3D9164756E2164756E21
1329
1457
  //# sourceMappingURL=index.js.map