@secondlayer/sdk 6.22.0 → 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.
@@ -310,1141 +310,1202 @@ interface TransactionProof {
310
310
  reward_set: RewardSet
311
311
  };
312
312
  }
313
- type IndexTip = {
314
- block_height: number
315
- lag_seconds: number
316
- };
317
- /**
318
- * A chain reorg overlapping a returned page's height range. Height-keyed feeds
319
- * (`/transactions`, `/contract-calls`, `/stacking`) populate this so a consumer
320
- * can reconcile: roll back the rows whose `block_height:tx_index` cursor falls in
321
- * `orphaned_range`, then re-fetch from `new_canonical_tip`. Empty when the page
322
- * spans no reorg.
323
- */
324
- type IndexReorg = {
325
- id: string
326
- detected_at: string
327
- fork_point_height: number
328
- old_index_block_hash: string | null
329
- new_index_block_hash: string | null
330
- /** Orphaned cursor span `<block_height>:<tx_index>`, inclusive. */
331
- orphaned_range: {
332
- from: string
333
- to: string
334
- }
335
- /** New canonical tip cursor to resume from. */
336
- new_canonical_tip: string
337
- };
338
- type IndexUsage = {
339
- product: "index"
340
- tier: string
341
- limits: {
342
- rate_limit_per_second: number | null
343
- }
344
- usage: {
345
- decoded_events_today: number
346
- decoded_events_this_month: number
347
- }
348
- };
349
- type FtTransfer = {
350
- cursor: string
351
- block_height: number
352
- tx_id: string
353
- tx_index: number
354
- event_index: number
355
- event_type: "ft_transfer"
356
- contract_id: string
357
- asset_identifier: string
313
+ import { StreamsEventType } from "@secondlayer/shared";
314
+ /** A Clarity value as Streams serves it: the canonical hex string, a typed
315
+ * object carrying that hex (`{ hex }`), or a decoded Clarity-JSON object.
316
+ * Decode helpers (`decodeNftTransfer`, etc.) resolve it to a concrete value. */
317
+ type StreamsClarityValue = string | {
318
+ hex: string
319
+ } | Record<string, unknown>;
320
+ type StxTransferPayload = {
358
321
  sender: string
359
322
  recipient: string
360
323
  amount: string
324
+ memo?: string
361
325
  };
362
- type FtTransfersEnvelope = {
363
- events: FtTransfer[]
364
- next_cursor: string | null
365
- tip: IndexTip
366
- reorgs: IndexReorg[]
367
- };
368
- type FtTransfersListParams = {
369
- cursor?: string | null
370
- fromCursor?: string | null
371
- limit?: number
372
- contractId?: string
373
- sender?: string
374
- recipient?: string
375
- fromHeight?: number
376
- toHeight?: number
377
- };
378
- type FtTransfersWalkParams = Omit<FtTransfersListParams, "limit"> & {
379
- batchSize?: number
380
- signal?: AbortSignal
381
- };
382
- type NftTransfer = {
383
- cursor: string
384
- block_height: number
385
- tx_id: string
386
- tx_index: number
387
- event_index: number
388
- event_type: "nft_transfer"
389
- contract_id: string
390
- asset_identifier: string
391
- sender: string
326
+ type StxMintPayload = {
392
327
  recipient: string
393
- value: string
394
- };
395
- type NftTransfersEnvelope = {
396
- events: NftTransfer[]
397
- next_cursor: string | null
398
- tip: IndexTip
399
- reorgs: IndexReorg[]
400
- };
401
- type NftTransfersListParams = {
402
- cursor?: string | null
403
- fromCursor?: string | null
404
- limit?: number
405
- contractId?: string
406
- assetIdentifier?: string
407
- sender?: string
408
- recipient?: string
409
- fromHeight?: number
410
- toHeight?: number
411
- };
412
- type NftTransfersWalkParams = Omit<NftTransfersListParams, "limit"> & {
413
- batchSize?: number
414
- signal?: AbortSignal
415
- };
416
- type IndexEventBase = {
417
- cursor: string
418
- block_height: number
419
- block_time?: string | null
420
- tx_id: string
421
- tx_index: number
422
- event_index: number
423
- contract_id: string | null
328
+ amount: string
424
329
  };
425
- type IndexFtTransfer = IndexEventBase & {
426
- event_type: "ft_transfer"
427
- asset_identifier: string
330
+ type StxBurnPayload = {
428
331
  sender: string
429
- recipient: string
430
332
  amount: string
431
333
  };
432
- type IndexNftTransfer = IndexEventBase & {
433
- event_type: "nft_transfer"
434
- asset_identifier: string
435
- sender: string
436
- recipient: string
437
- value: string
334
+ type StxLockPayload = {
335
+ locked_address: string
336
+ locked_amount: string
337
+ unlock_height: string
438
338
  };
439
- type IndexStxTransfer = IndexEventBase & {
440
- event_type: "stx_transfer"
339
+ type FtTransferPayload = {
340
+ asset_identifier: string
441
341
  sender: string
442
342
  recipient: string
443
343
  amount: string
444
- memo: string | null
445
344
  };
446
- type IndexStxMint = IndexEventBase & {
447
- event_type: "stx_mint"
345
+ type FtMintPayload = {
346
+ asset_identifier: string
448
347
  recipient: string
449
348
  amount: string
450
349
  };
451
- type IndexStxBurn = IndexEventBase & {
452
- event_type: "stx_burn"
453
- sender: string
454
- amount: string
455
- };
456
- type IndexStxLock = IndexEventBase & {
457
- event_type: "stx_lock"
458
- sender: string
459
- amount: string
460
- payload: {
461
- unlock_height: string | null
462
- }
463
- };
464
- type IndexFtMint = IndexEventBase & {
465
- event_type: "ft_mint"
350
+ type FtBurnPayload = {
466
351
  asset_identifier: string
467
- recipient: string
352
+ sender: string
468
353
  amount: string
469
354
  };
470
- type IndexFtBurn = IndexEventBase & {
471
- event_type: "ft_burn"
355
+ type NftTransferPayload = {
472
356
  asset_identifier: string
473
357
  sender: string
474
- amount: string
358
+ recipient: string
359
+ value: StreamsClarityValue
360
+ /** Canonical serialized hex of `value`, when the stream carries it. */
361
+ raw_value?: string
475
362
  };
476
- type IndexNftMint = IndexEventBase & {
477
- event_type: "nft_mint"
363
+ type NftMintPayload = {
478
364
  asset_identifier: string
479
365
  recipient: string
480
- value: string
366
+ value: StreamsClarityValue
367
+ raw_value?: string
481
368
  };
482
- type IndexNftBurn = IndexEventBase & {
483
- event_type: "nft_burn"
369
+ type NftBurnPayload = {
484
370
  asset_identifier: string
485
371
  sender: string
486
- value: string
487
- };
488
- type IndexPrint = IndexEventBase & {
489
- event_type: "print"
490
- payload: {
491
- topic: string | null
492
- value: unknown
493
- raw_value: string | null
494
- }
495
- };
496
- /** Decoded chain event, discriminated by `event_type`. */
497
- type IndexEvent = IndexFtTransfer | IndexNftTransfer | IndexStxTransfer | IndexStxMint | IndexStxBurn | IndexStxLock | IndexFtMint | IndexFtBurn | IndexNftMint | IndexNftBurn | IndexPrint;
498
- type IndexEventType = IndexEvent["event_type"];
499
- type EventsEnvelope = {
500
- events: IndexEvent[]
501
- next_cursor: string | null
502
- tip: IndexTip
503
- reorgs: IndexReorg[]
504
- };
505
- type EventsListParams = {
506
- /** Required. One of the decoded event types. */
507
- eventType: IndexEventType
508
- cursor?: string | null
509
- fromCursor?: string | null
510
- limit?: number
511
- contractId?: string
512
- assetIdentifier?: string
513
- sender?: string
514
- recipient?: string
515
- fromHeight?: number
516
- toHeight?: number
517
- /** Restrict to contracts conforming to a trait/standard (e.g. "sip-010").
518
- * Mutually exclusive with contractId; contract-keyed event types only. */
519
- trait?: string
372
+ value: StreamsClarityValue
373
+ raw_value?: string
520
374
  };
521
- type EventsWalkParams = Omit<EventsListParams, "limit"> & {
522
- batchSize?: number
523
- signal?: AbortSignal
375
+ type PrintPayload = {
376
+ contract_id?: string | null
377
+ topic?: string
378
+ value?: unknown
379
+ raw_value?: string
524
380
  };
525
- type IndexContractCall = {
381
+ type StreamsEventBase = {
382
+ /**
383
+ * Globally unique, monotonic position of this event (`<block>:<index>`). Use
384
+ * it as the primary key of your projection rows — replaying a batch then
385
+ * upserts cleanly. Don't synthesize your own id from `tx_id`/`event_index`.
386
+ */
526
387
  cursor: string
527
388
  block_height: number
528
- block_time?: string | null
389
+ block_hash: string
390
+ burn_block_height: number
529
391
  tx_id: string
530
392
  tx_index: number
531
- contract_id: string
532
- function_name: string
533
- sender: string
534
- status: string
535
- args: unknown[]
536
- result: unknown
537
- result_hex: string | null
393
+ event_index: number
394
+ contract_id: string | null
395
+ ts: string
396
+ /**
397
+ * True when this event's block is past the finality boundary (immutable).
398
+ * Optional for back-compat; the API always sets it on Streams responses.
399
+ */
400
+ finalized?: boolean
538
401
  };
539
- type ContractCallsEnvelope = {
540
- contract_calls: IndexContractCall[]
541
- next_cursor: string | null
542
- tip: IndexTip
543
- reorgs: IndexReorg[]
402
+ type StreamsEventOf<
403
+ T extends StreamsEventType,
404
+ P
405
+ > = StreamsEventBase & {
406
+ event_type: T
407
+ payload: P
544
408
  };
545
- type ContractCallsListParams = {
546
- cursor?: string | null
547
- fromCursor?: string | null
548
- limit?: number
549
- contractId?: string
550
- functionName?: string
551
- sender?: string
552
- fromHeight?: number
553
- toHeight?: number
554
- /** Restrict to contracts conforming to a trait/standard (e.g. "sip-010").
555
- * Mutually exclusive with contractId. */
556
- trait?: string
557
- };
558
- type ContractCallsWalkParams = Omit<ContractCallsListParams, "limit"> & {
559
- batchSize?: number
560
- signal?: AbortSignal
561
- };
562
- /** One canonical block in the sync map. Lean by design — block + parent hash
563
- * for chain linkage, burn anchor for Bitcoin confirmations. Use `blocks` for
564
- * the full block resource. */
565
- type IndexCanonicalBlock = {
566
- cursor: string
409
+ /** A raw Streams event. Discriminated on `event_type`, so `event.payload`
410
+ * narrows to the matching payload shape once the type is checked. */
411
+ type StreamsEvent = StreamsEventOf<"stx_transfer", StxTransferPayload> | StreamsEventOf<"stx_mint", StxMintPayload> | StreamsEventOf<"stx_burn", StxBurnPayload> | StreamsEventOf<"stx_lock", StxLockPayload> | StreamsEventOf<"ft_transfer", FtTransferPayload> | StreamsEventOf<"ft_mint", FtMintPayload> | StreamsEventOf<"ft_burn", FtBurnPayload> | StreamsEventOf<"nft_transfer", NftTransferPayload> | StreamsEventOf<"nft_mint", NftMintPayload> | StreamsEventOf<"nft_burn", NftBurnPayload> | StreamsEventOf<"print", PrintPayload>;
412
+ type StreamsTip = {
567
413
  block_height: number
568
414
  block_hash: string
569
- parent_hash: string
570
415
  burn_block_height: number
571
- burn_block_hash: string | null
572
- };
573
- type CanonicalEnvelope = {
574
- canonical: IndexCanonicalBlock[]
575
- next_cursor: string | null
576
- tip: IndexTip
577
- };
578
- type CanonicalListParams = {
579
- cursor?: string | null
580
- fromCursor?: string | null
581
- limit?: number
582
- fromHeight?: number
583
- toHeight?: number
584
- };
585
- type CanonicalWalkParams = Omit<CanonicalListParams, "limit"> & {
586
- batchSize?: number
587
- signal?: AbortSignal
416
+ /**
417
+ * Highest Stacks block past the burn-confirmation finality boundary.
418
+ * Optional for back-compat; the API always sets it.
419
+ */
420
+ finalized_height?: number
421
+ lag_seconds: number
422
+ /**
423
+ * Oldest height still seekable on the live API for the caller's tier
424
+ * (`tip - retention`). `null` = unlimited retention. Older reads must use the
425
+ * cold dumps lane. Optional for back-compat.
426
+ */
427
+ oldest_seekable_height?: number | null
428
+ /** Oldest seekable cursor (`<oldest_seekable_height>:0`); `null` = unlimited. */
429
+ oldest_cursor?: string | null
588
430
  };
589
- /** A block resource. Metadata is intentionally thin — only chain-linkage and
590
- * burn-anchor fields are persisted (no miner / tx_count / signer). */
591
- type IndexBlock = {
592
- cursor: string
431
+ type StreamsCanonicalBlock = {
593
432
  block_height: number
594
433
  block_hash: string
595
- parent_hash: string
596
434
  burn_block_height: number
597
435
  burn_block_hash: string | null
598
- block_time: string | null
599
- canonical: boolean
436
+ is_canonical: true
600
437
  };
601
- type BlocksEnvelope = {
602
- blocks: IndexBlock[]
438
+ type StreamsReorg = {
439
+ detected_at: string
440
+ fork_point_height: number
441
+ orphaned_range: {
442
+ from: string
443
+ to: string
444
+ }
445
+ new_canonical_tip: string
446
+ };
447
+ type StreamsEventsEnvelope = {
448
+ events: StreamsEvent[]
603
449
  next_cursor: string | null
604
- tip: IndexTip
450
+ tip: StreamsTip
451
+ reorgs: StreamsReorg[]
605
452
  };
606
- type BlockEnvelope = {
607
- block: IndexBlock
608
- tip: IndexTip
453
+ type StreamsEventsListEnvelope = Omit<StreamsEventsEnvelope, "next_cursor">;
454
+ type StreamsReorgsListParams = {
455
+ since: string
456
+ limit?: number
609
457
  };
610
- type BlocksListParams = {
458
+ type StreamsReorgsListEnvelope = {
459
+ reorgs: StreamsReorg[]
460
+ next_since: string | null
461
+ };
462
+ /** A filter that matches a single value or any value in a list. */
463
+ type StreamsFilterValue = string | readonly string[];
464
+ type StreamsEventsListParams = {
611
465
  cursor?: string | null
612
- fromCursor?: string | null
613
- limit?: number
614
466
  fromHeight?: number
615
467
  toHeight?: number
468
+ types?: readonly StreamsEventType[]
469
+ /** Event types to exclude (applied after `types`). */
470
+ notTypes?: readonly StreamsEventType[]
471
+ contractId?: StreamsFilterValue
472
+ sender?: StreamsFilterValue
473
+ recipient?: StreamsFilterValue
474
+ assetIdentifier?: string
475
+ limit?: number
616
476
  };
617
- type BlocksWalkParams = Omit<BlocksListParams, "limit"> & {
477
+ type StreamsEventsStreamParams = {
478
+ fromCursor?: string | null
479
+ types?: readonly StreamsEventType[]
480
+ notTypes?: readonly StreamsEventType[]
481
+ contractId?: StreamsFilterValue
482
+ sender?: StreamsFilterValue
483
+ recipient?: StreamsFilterValue
484
+ assetIdentifier?: string
618
485
  batchSize?: number
486
+ emptyBackoffMs?: number
487
+ maxPages?: number
488
+ maxEmptyPolls?: number
619
489
  signal?: AbortSignal
620
490
  };
621
- type IndexPostCondition = {
622
- type: "stx"
623
- principal: string
624
- condition_code: number
625
- condition_code_name: string | null
626
- amount: string
627
- } | {
628
- type: "ft"
629
- principal: string
630
- asset_identifier: string
631
- condition_code: number
632
- condition_code_name: string | null
633
- amount: string
634
- } | {
635
- type: "nft"
636
- principal: string
637
- asset_identifier: string
638
- asset_value: unknown
639
- condition_code: number
640
- condition_code_name: string | null
641
- };
642
- /** Full transaction document: columnar fields plus `raw_tx`-decoded enrichment.
643
- * Payload sub-objects are present only for the matching `tx_type`; enrichment
644
- * fields are null when `raw_tx` isn't decodable (e.g. burnchain ops). */
645
- type IndexTransaction = {
646
- cursor: string
647
- tx_id: string
648
- block_height: number
649
- block_time?: string | null
650
- tx_index: number
651
- tx_type: string
652
- sender: string
653
- status: string
654
- fee: string | null
655
- nonce: string | null
656
- sponsored: boolean | null
657
- anchor_mode: string | null
658
- post_condition_mode: string | null
659
- post_conditions: IndexPostCondition[]
660
- contract_call?: {
661
- contract_id: string
662
- function_name: string
663
- function_args: unknown[]
664
- /** Raw hex-encoded ClarityValues; decode(function_args_hex[i]) === function_args[i]. */
665
- function_args_hex: string[]
666
- result: unknown
667
- result_hex: string | null
668
- }
669
- token_transfer?: {
670
- recipient: string
671
- amount: string
672
- memo: string
673
- }
674
- smart_contract?: {
675
- contract_id: string | null
676
- clarity_version: number | null
677
- }
678
- coinbase?: {
679
- alt_recipient: string | null
680
- }
681
- tenure_change?: {
682
- cause: number
683
- }
684
- };
685
- type TransactionsEnvelope = {
686
- transactions: IndexTransaction[]
687
- next_cursor: string | null
688
- tip: IndexTip
689
- reorgs: IndexReorg[]
690
- };
691
- type TransactionEnvelope = {
692
- transaction: IndexTransaction
693
- tip: IndexTip
694
- };
695
- type TransactionsListParams = {
696
- cursor?: string | null
491
+ type StreamsEventsSubscribeParams = {
492
+ /** Resume strictly after this cursor; omit to live-tail from the tip. */
697
493
  fromCursor?: string | null
698
- limit?: number
699
- type?: string
700
- sender?: string
701
- contractId?: string
702
- fromHeight?: number
703
- toHeight?: number
704
- };
705
- type TransactionsWalkParams = Omit<TransactionsListParams, "limit"> & {
706
- batchSize?: number
494
+ types?: readonly StreamsEventType[]
495
+ notTypes?: readonly StreamsEventType[]
496
+ contractId?: StreamsFilterValue
497
+ sender?: StreamsFilterValue
498
+ recipient?: StreamsFilterValue
499
+ assetIdentifier?: string
500
+ /** Abort to unsubscribe (the returned function does the same). */
707
501
  signal?: AbortSignal
502
+ /** Called for each pushed event, in order. */
503
+ onEvent: (event: StreamsEvent) => void | Promise<void>
504
+ /** Called on a connection error; the subscription auto-reconnects from the
505
+ * last delivered cursor unless the signal has aborted. */
506
+ onError?: (err: unknown) => void
708
507
  };
709
- /** A decoded PoX-4 stacking action (one per stacking contract call). */
710
- type IndexStackingAction = {
508
+ /**
509
+ * The checkpoint the SDK computes for a batch. Persist `cursor` inside the same
510
+ * transaction as your projection writes, then resume from it via `fromCursor`.
511
+ * It is the position to advance to: `next_cursor` normally, or the last
512
+ * finalized event when `finalizedOnly` is set.
513
+ */
514
+ type StreamsBatchContext = {
515
+ cursor: string | null
516
+ };
517
+ /**
518
+ * The checkpoint for a reorg rollback. Persist `cursor` (the rewind position)
519
+ * inside the same transaction as your rollback so the two commit atomically.
520
+ */
521
+ type StreamsReorgContext = {
711
522
  cursor: string
712
- block_height: number
713
- block_time?: string | null
714
- burn_block_height: number
715
- tx_id: string
716
- tx_index: number
717
- function_name: string
718
- caller: string
719
- stacker: string | null
720
- delegate_to: string | null
721
- amount_ustx: string | null
722
- lock_period: number | null
723
- pox_addr: {
724
- version: number | null
725
- hashbytes: string | null
726
- btc: string | null
727
- }
728
- start_cycle: number | null
729
- end_cycle: number | null
730
- reward_cycle: number | null
731
- signer_key: string | null
732
- result_ok: boolean
733
523
  };
734
- type StackingEnvelope = {
735
- stacking: IndexStackingAction[]
736
- next_cursor: string | null
737
- tip: IndexTip
738
- reorgs: IndexReorg[]
739
- /** Present only when the PoX-4 decoder is disabled, explaining an empty feed. */
740
- notes?: string
524
+ type StreamsEventsConsumeParams = {
525
+ fromCursor?: string | null
526
+ mode?: "tail" | "bounded"
527
+ /**
528
+ * Emit only finalized (immutable) events and never surface reorgs. The SDK
529
+ * checkpoints at the last finalized event and re-reads the unfinalized tail
530
+ * until it settles. Trades finality lag for zero reorg handling; `onReorg` is
531
+ * ignored.
532
+ */
533
+ finalizedOnly?: boolean
534
+ types?: readonly StreamsEventType[]
535
+ notTypes?: readonly StreamsEventType[]
536
+ contractId?: StreamsFilterValue
537
+ sender?: StreamsFilterValue
538
+ recipient?: StreamsFilterValue
539
+ assetIdentifier?: string
540
+ batchSize?: number
541
+ /**
542
+ * Apply a page of canonical events. Persist `ctx.cursor` in the same
543
+ * transaction as your writes. Returning a cursor overrides `ctx.cursor` as
544
+ * the resume point (advanced manual control); returning nothing uses it.
545
+ */
546
+ onBatch: (events: StreamsEvent[], envelope: StreamsEventsEnvelope, ctx: StreamsBatchContext) => void | string | null | undefined | Promise<void> | Promise<string | null | undefined>
547
+ /**
548
+ * Roll your projection back to `reorg.fork_point_height`, persisting
549
+ * `ctx.cursor` in the same transaction. Called once per *new* reorg
550
+ * (deduped in-memory, fork-ascending) before the SDK rewinds and re-reads the
551
+ * now-canonical events. Omit it to ignore reorgs (events stay canonical, but
552
+ * stale rows from an orphaned fork are left in place).
553
+ */
554
+ onReorg?: (reorg: StreamsReorg, ctx: StreamsReorgContext) => Promise<void> | void
555
+ emptyBackoffMs?: number
556
+ maxPages?: number
557
+ maxEmptyPolls?: number
558
+ signal?: AbortSignal
741
559
  };
742
- type StackingListParams = {
560
+ /**
561
+ * One yielded page from {@link StreamsClient.consume} — the
562
+ * `GET /v1/streams/events` envelope verbatim, with `next_cursor` renamed to
563
+ * `cursor` (the checkpoint to persist and resume from).
564
+ */
565
+ type StreamsBatch = {
566
+ /** Canonical events of this page, in cursor order. */
567
+ events: StreamsEvent[]
568
+ /** Checkpoint after this page — pass back as `consume({ cursor })` to resume. */
569
+ cursor: string | null
570
+ tip: StreamsTip
571
+ /** Chain reorgs reported alongside this page; empty when none. */
572
+ reorgs: StreamsReorg[]
573
+ };
574
+ type StreamsConsumeParams = {
575
+ /** Resume strictly after this cursor; omit to start from the oldest seekable page. */
743
576
  cursor?: string | null
744
- fromCursor?: string | null
745
- limit?: number
746
- functionName?: string
747
- stacker?: string
748
- caller?: string
749
- fromHeight?: number
750
- toHeight?: number
577
+ types?: readonly StreamsEventType[]
578
+ notTypes?: readonly StreamsEventType[]
579
+ contractId?: StreamsFilterValue
580
+ sender?: StreamsFilterValue
581
+ recipient?: StreamsFilterValue
582
+ assetIdentifier?: string
583
+ /** Events per page (the `limit` query param). Default 100. */
584
+ batchSize?: number
585
+ /** Poll interval while caught up at the tip, in ms. Default 2000. */
586
+ intervalMs?: number
587
+ /** Abort to end the iteration. */
588
+ signal?: AbortSignal
751
589
  };
752
- type StackingWalkParams = Omit<StackingListParams, "limit"> & {
590
+ type StreamsEventsConsumeResult = {
591
+ cursor: string | null
592
+ pages: number
593
+ emptyPolls: number
594
+ };
595
+ type StreamsEventsReplayParams = {
596
+ /** Start point: `"genesis"` (default) or a `<block>:<index>` cursor. */
597
+ from?: "genesis" | string
598
+ /**
599
+ * Called once per finalized dump file, in block order, before live tailing.
600
+ * Process the parquet with your own tooling (e.g. DuckDB) — the SDK does not
601
+ * decode parquet. Use `client.dumps.download(file)` to fetch + verify bytes.
602
+ */
603
+ onDumpFile: (file: StreamsDumpFile) => Promise<void> | void
604
+ /** Called per live page after the dump phase, like `consume`. */
605
+ onBatch: (events: StreamsEvent[], envelope: StreamsEventsEnvelope) => Promise<string | null | undefined> | string | null | undefined
606
+ mode?: "tail" | "bounded"
753
607
  batchSize?: number
608
+ emptyBackoffMs?: number
609
+ maxPages?: number
610
+ maxEmptyPolls?: number
754
611
  signal?: AbortSignal
755
612
  };
756
- /** A pending (unconfirmed) transaction. Like a transaction document but
757
- * pre-chain no block_height/tx_index/result/events — with `received_at` and
758
- * a sequence cursor instead of a block position. */
759
- type IndexMempoolTransaction = {
760
- cursor: string
761
- tx_id: string
762
- tx_type: string
763
- sender: string
764
- received_at?: string | null
765
- fee: string | null
766
- nonce: string | null
767
- sponsored: boolean | null
768
- anchor_mode: string | null
769
- post_condition_mode: string | null
770
- post_conditions: IndexPostCondition[]
771
- contract_call?: {
772
- contract_id: string
773
- function_name: string
774
- function_args: unknown[]
613
+ /** One bulk parquet file in the dumps manifest. `path` is the object key under
614
+ * the dumps base URL. */
615
+ type StreamsDumpFile = {
616
+ path: string
617
+ from_block: number
618
+ to_block: number
619
+ min_cursor: string | null
620
+ max_cursor: string | null
621
+ row_count: number
622
+ byte_size: number
623
+ sha256: string
624
+ schema_version: number
625
+ created_at: string
626
+ };
627
+ type StreamsDumpsManifest = {
628
+ dataset: string
629
+ network: string
630
+ version: string
631
+ schema_version: number
632
+ generated_at: string
633
+ producer_version: string
634
+ finality_lag_blocks: number
635
+ /** Cursor at the end of the finalized bulk coverage — hand to live tailing. */
636
+ latest_finalized_cursor: string | null
637
+ coverage: {
638
+ from_block: number
639
+ to_block: number
775
640
  }
776
- token_transfer?: {
777
- recipient: string
778
- amount: string
779
- memo: string
641
+ files: StreamsDumpFile[]
642
+ /** ed25519 signature over the manifest's canonical bytes. Absent on legacy
643
+ * unsigned manifests. Verified by `list()` when `verifyDumpsManifest` is on. */
644
+ signature?: string
645
+ /** Short id of the signing public key. */
646
+ key_id?: string
647
+ };
648
+ type StreamsDumps = {
649
+ /** Fetch and parse the latest dumps manifest. */
650
+ list(): Promise<StreamsDumpsManifest>
651
+ /** Absolute URL for a manifest file. */
652
+ fileUrl(file: StreamsDumpFile): string
653
+ /** Download a parquet file and verify its sha256 against the manifest. */
654
+ download(file: StreamsDumpFile): Promise<Uint8Array>
655
+ };
656
+ type StreamsClient = {
657
+ /**
658
+ * Follow Streams as an async iterator of page batches.
659
+ *
660
+ * Yields one {@link StreamsBatch} per `GET /v1/streams/events` page — the
661
+ * existing envelope (`events`, `next_cursor` → `cursor`, `tip`, `reorgs`)
662
+ * with zero extra API calls. Batches are chosen over per-block groupings
663
+ * because the envelope is page-keyed, so every yield is exactly one fetch.
664
+ * Empty pages are skipped; at the tip the iterator re-polls every
665
+ * `intervalMs` (default 2000) until aborted via `signal`.
666
+ *
667
+ * Reorgs are surfaced on the batch (`batch.reorgs`) but the cursor is not
668
+ * rewound automatically — use `events.consume` with `onReorg` for managed
669
+ * rollback semantics.
670
+ */
671
+ consume(params?: StreamsConsumeParams): AsyncIterableIterator<StreamsBatch>
672
+ events: {
673
+ list(params?: StreamsEventsListParams): Promise<StreamsEventsEnvelope>
674
+ byTxId(txId: string): Promise<StreamsEventsListEnvelope>
675
+ /**
676
+ * Pull pages from Streams and call `onBatch` after each page.
677
+ *
678
+ * Use `consume` for indexers and ETL jobs that own checkpointing. Return
679
+ * the checkpoint cursor from `onBatch`. Default `mode: "tail"` keeps
680
+ * polling when caught up; `mode: "bounded"` exits on the first empty page.
681
+ * The consumer also exits when `maxPages`, `maxEmptyPolls`, or `signal`
682
+ * stops it.
683
+ */
684
+ consume(params: StreamsEventsConsumeParams): Promise<StreamsEventsConsumeResult>
685
+ /**
686
+ * Backfill from bulk dumps, then continue live from the dump→live seam in
687
+ * one call. Iterates finalized dump files (via `onDumpFile`) in block
688
+ * order, then tails live from the manifest's `latest_finalized_cursor`
689
+ * (exclusive input → no gap or duplicate at the seam). Requires
690
+ * `dumpsBaseUrl`.
691
+ */
692
+ replay(params: StreamsEventsReplayParams): Promise<StreamsEventsConsumeResult>
693
+ /**
694
+ * Follow Streams as an async iterator.
695
+ *
696
+ * Use `stream` for live processors and watch-style apps. It tails
697
+ * indefinitely by default and stops when its `AbortSignal`, `maxPages`, or
698
+ * `maxEmptyPolls` stops it.
699
+ */
700
+ stream(params?: StreamsEventsStreamParams): AsyncIterable<StreamsEvent>
701
+ /**
702
+ * Subscribe to the real-time SSE push surface. Calls `onEvent` for each new
703
+ * canonical event as the server pushes it (chain cadence, not poll-bounded),
704
+ * and verifies each frame's inline ed25519 signature when the client was
705
+ * created with `verify`. Returns an unsubscribe function.
706
+ */
707
+ subscribe(params: StreamsEventsSubscribeParams): () => void
780
708
  }
781
- smart_contract?: {
782
- clarity_version: number | null
709
+ blocks: {
710
+ events(heightOrHash: number | string): Promise<StreamsEventsListEnvelope>
783
711
  }
784
- coinbase?: {
785
- alt_recipient: string | null
712
+ reorgs: {
713
+ list(params: StreamsReorgsListParams): Promise<StreamsReorgsListEnvelope>
786
714
  }
787
- tenure_change?: {
788
- cause: number
715
+ /** Bulk parquet dumps. Requires `dumpsBaseUrl` on the client. */
716
+ dumps: StreamsDumps
717
+ canonical(height: number): Promise<StreamsCanonicalBlock>
718
+ tip(): Promise<StreamsTip>
719
+ /** Your own Streams consumption (events today + this month) and tier limits. */
720
+ usage(): Promise<StreamsUsage>
721
+ };
722
+ type StreamsUsage = {
723
+ product: "streams"
724
+ tier: string
725
+ limits: {
726
+ rate_limit_per_second: number | null
727
+ retention_days: number | null
728
+ }
729
+ usage: {
730
+ events_today: number
731
+ events_this_month: number
789
732
  }
790
733
  };
791
- type MempoolEnvelope = {
792
- mempool: IndexMempoolTransaction[]
793
- next_cursor: string | null
794
- tip: IndexTip
734
+ type Sleep = (ms: number, signal?: AbortSignal) => Promise<void>;
735
+ /** Minimum shape a consumed Index row must expose. */
736
+ type IndexFeedItem = {
737
+ cursor: string
738
+ block_height: number
795
739
  };
796
- type MempoolTransactionEnvelope = {
797
- transaction: IndexMempoolTransaction
740
+ /** Minimum envelope shape of a consumable Index feed page. */
741
+ type IndexFeedEnvelope = {
742
+ next_cursor: string | null
798
743
  tip: IndexTip
744
+ reorgs: IndexReorg[]
799
745
  };
800
- type MempoolListParams = {
801
- cursor?: string | null
746
+ /** Consumer options shared by `index.events.consume` and
747
+ * `index.contractCalls.consume`. Same contract as the Streams consumer:
748
+ * commit your writes inside `onBatch`, return the cursor you committed. */
749
+ type IndexConsumeOptions<
750
+ TItem extends IndexFeedItem,
751
+ TEnvelope extends IndexFeedEnvelope
752
+ > = {
753
+ /** Resume from a committed checkpoint. Without it (and without
754
+ * `fromHeight`) the API serves only the recent default window. */
802
755
  fromCursor?: string | null
803
- limit?: number
804
- sender?: string
805
- type?: string
806
- /** Filter to pending calls to a single contract (e.g. `SP….contract`). */
807
- contractId?: string
808
- };
809
- type MempoolWalkParams = Omit<MempoolListParams, "limit"> & {
756
+ /** Start a fresh sweep at this height (e.g. `0` for genesis backfill).
757
+ * Ignored once a cursor exists. */
758
+ fromHeight?: number
759
+ /** `tail` (default) keeps polling at the tip; `bounded` returns on the
760
+ * first empty page. */
761
+ mode?: "tail" | "bounded"
762
+ /** Emit only rows at or below the tip's `finalized_height`; the
763
+ * unfinalized tail is re-read each poll until it settles. Finalized data
764
+ * never reorgs, so `onReorg` is skipped entirely. */
765
+ finalizedOnly?: boolean
810
766
  batchSize?: number
767
+ onBatch: (items: TItem[], envelope: TEnvelope, ctx: {
768
+ cursor: string | null
769
+ }) => void | string | null | undefined | Promise<void> | Promise<string | null | undefined>
770
+ onReorg?: (reorg: IndexReorg, ctx: {
771
+ cursor: string
772
+ }) => Promise<void> | void
773
+ sleep?: Sleep
774
+ emptyBackoffMs?: number
775
+ maxPages?: number
776
+ maxEmptyPolls?: number
811
777
  signal?: AbortSignal
812
778
  };
779
+ type IndexTip = {
780
+ block_height: number
781
+ /** Highest height treated as immutable (past the burn-confirmation
782
+ * finality boundary). Rows at or below it never reorg — `finalizedOnly`
783
+ * consumers gate on this, since Index rows carry no per-event flag. */
784
+ finalized_height: number
785
+ lag_seconds: number
786
+ };
813
787
  /**
814
- * Empirical per-topic print payload schema for a contract, inferred from
815
- * sampled on-chain events. `topics` is sorted by count desc; `sampled` is true
816
- * when the contract has more print events than the windows examined.
788
+ * A chain reorg overlapping a returned page's height range. Height-keyed feeds
789
+ * (`/transactions`, `/contract-calls`, `/stacking`) populate this so a consumer
790
+ * can reconcile: roll back the rows whose `block_height:tx_index` cursor falls in
791
+ * `orphaned_range`, then re-fetch from `new_canonical_tip`. Empty when the page
792
+ * spans no reorg.
817
793
  */
818
- type PrintSchemaResponse = {
819
- contract_id: string
820
- topics: InferredTopicSchema[]
821
- sampled: boolean
822
- total_events: number
823
- /** True when the count hit the server-side cap (total_events is the cap). */
824
- total_events_capped: boolean
825
- sample: {
826
- size: number
827
- newest_height: number | null
828
- oldest_height: number | null
794
+ type IndexReorg = {
795
+ id: string
796
+ detected_at: string
797
+ fork_point_height: number
798
+ old_index_block_hash: string | null
799
+ new_index_block_hash: string | null
800
+ /** Orphaned cursor span `<block_height>:<tx_index>`, inclusive. */
801
+ orphaned_range: {
802
+ from: string
803
+ to: string
804
+ }
805
+ /** New canonical tip cursor to resume from. */
806
+ new_canonical_tip: string
807
+ };
808
+ type IndexUsage = {
809
+ product: "index"
810
+ tier: string
811
+ limits: {
812
+ rate_limit_per_second: number | null
813
+ }
814
+ usage: {
815
+ decoded_events_today: number
816
+ decoded_events_this_month: number
829
817
  }
818
+ };
819
+ type FtTransfer = {
820
+ cursor: string
821
+ block_height: number
822
+ tx_id: string
823
+ tx_index: number
824
+ event_index: number
825
+ event_type: "ft_transfer"
826
+ contract_id: string
827
+ asset_identifier: string
828
+ sender: string
829
+ recipient: string
830
+ amount: string
831
+ };
832
+ type FtTransfersEnvelope = {
833
+ events: FtTransfer[]
834
+ next_cursor: string | null
830
835
  tip: IndexTip
836
+ reorgs: IndexReorg[]
831
837
  };
832
- /**
833
- * `index.ftTransfers` callable shorthand for `.list()`, with `.list`/`.walk`
834
- * still available: `await sl.index.ftTransfers({ contractId })`.
835
- *
836
- * The API accepts `contract_id`/`sender`/`recipient` equality filters only —
837
- * no amount filtering and no asset-slug resolution on /v1/index/ft-transfers.
838
- */
839
- interface FtTransfersResource {
840
- (params?: FtTransfersListParams): Promise<FtTransfersEnvelope>;
841
- list(params?: FtTransfersListParams): Promise<FtTransfersEnvelope>;
842
- walk(params?: FtTransfersWalkParams): AsyncIterable<FtTransfer>;
843
- }
844
- /** `index.nftTransfers` — callable shorthand for `.list()` (see {@link FtTransfersResource}). */
845
- interface NftTransfersResource {
846
- (params?: NftTransfersListParams): Promise<NftTransfersEnvelope>;
847
- list(params?: NftTransfersListParams): Promise<NftTransfersEnvelope>;
848
- walk(params?: NftTransfersWalkParams): AsyncIterable<NftTransfer>;
849
- }
850
- /** `index.events` — callable shorthand for `.list()`; `eventType` is required. */
851
- interface IndexEventsResource {
852
- (params: EventsListParams): Promise<EventsEnvelope>;
853
- list(params: EventsListParams): Promise<EventsEnvelope>;
854
- walk(params: EventsWalkParams): AsyncIterable<IndexEvent>;
855
- }
856
- /** Per-event-type filter vocabulary in the {@link IndexDiscovery} doc. */
857
- type IndexEventTypeFilters = {
858
- columns?: string[]
859
- allowed_filters?: string[]
860
- equality_filters?: string[]
861
- required_non_null?: string[]
838
+ type FtTransfersListParams = {
839
+ cursor?: string | null
840
+ fromCursor?: string | null
841
+ limit?: number
842
+ contractId?: string
843
+ sender?: string
844
+ recipient?: string
845
+ fromHeight?: number
846
+ toHeight?: number
862
847
  };
863
- /** The `GET /v1/index` discovery doc — live endpoint + filter vocabulary.
864
- * Shape is intentionally open (the server may add fields); the agent-relevant
865
- * parts are the per-type filter rules. */
866
- type IndexDiscovery = {
867
- event_type_filters?: Record<string, IndexEventTypeFilters>
868
- [key: string]: unknown
848
+ type FtTransfersWalkParams = Omit<FtTransfersListParams, "limit"> & {
849
+ batchSize?: number
850
+ signal?: AbortSignal
869
851
  };
870
- declare class Index extends BaseClient {
871
- constructor(options?: Partial<SecondLayerOptions>);
872
- /** Your own Index consumption (decoded events today + this month) and tier limits. */
873
- usage(): Promise<IndexUsage>;
874
- /**
875
- * Index discovery doc — the live vocabulary: every endpoint, each event type's
876
- * columns, allowed/equality filters, and required-non-null fields. Read this to
877
- * learn what's queryable (and which types accept `trait`) instead of hardcoding.
878
- */
879
- discover(): Promise<IndexDiscovery>;
880
- /**
881
- * Empirical per-topic print payload schema for a contract — what topics it
882
- * emits and each field's observed Clarity/TS/column types. Anonymous read;
883
- * 404 → null.
884
- */
885
- printSchema(contractId: string): Promise<PrintSchemaResponse | null>;
886
- /** Callable: `index.ftTransfers(params)` ≡ `index.ftTransfers.list(params)`. */
887
- readonly ftTransfers: FtTransfersResource;
888
- /** Callable: `index.nftTransfers(params)` ≡ `index.nftTransfers.list(params)`. */
889
- readonly nftTransfers: NftTransfersResource;
890
- /** Generic decoded events by `event_type` (the full /v1/index/events surface).
891
- * Callable: `index.events(params)` ≡ `index.events.list(params)`. */
892
- readonly events: IndexEventsResource;
893
- readonly contractCalls: {
894
- list: (params?: ContractCallsListParams) => Promise<ContractCallsEnvelope>
895
- walk: (params?: ContractCallsWalkParams) => AsyncIterable<IndexContractCall>
896
- };
897
- /** Canonical block-hash map — sync only the current canonical chain. */
898
- readonly canonical: {
899
- list: (params?: CanonicalListParams) => Promise<CanonicalEnvelope>
900
- walk: (params?: CanonicalWalkParams) => AsyncIterable<IndexCanonicalBlock>
901
- };
902
- /** Canonical blocks: paginated `list`/`walk`, plus `get` by height or hash
903
- * (resolves to null on 404). */
904
- readonly blocks: {
905
- list: (params?: BlocksListParams) => Promise<BlocksEnvelope>
906
- walk: (params?: BlocksWalkParams) => AsyncIterable<IndexBlock>
907
- get: (ref: string | number) => Promise<BlockEnvelope | null>
908
- };
909
- /** Full transaction documents: paginated `list`/`walk`, plus `get` by tx_id
910
- * (resolves to null on 404). */
911
- readonly transactions: {
912
- list: (params?: TransactionsListParams) => Promise<TransactionsEnvelope>
913
- walk: (params?: TransactionsWalkParams) => AsyncIterable<IndexTransaction>
914
- get: (txId: string) => Promise<TransactionEnvelope | null>
915
- getProof: (txId: string) => Promise<TransactionProof | null>
916
- };
917
- /** Decoded PoX-4 stacking actions. Empty (with a `notes` hint) when the
918
- * platform's PoX-4 decoder is disabled. */
919
- readonly stacking: {
920
- list: (params?: StackingListParams) => Promise<StackingEnvelope>
921
- walk: (params?: StackingWalkParams) => AsyncIterable<IndexStackingAction>
922
- };
923
- /** Pending (unconfirmed) transactions: paginated `list`/`walk`, plus `get` by
924
- * tx_id (resolves to null when the tx has confirmed or dropped). */
925
- readonly mempool: {
926
- list: (params?: MempoolListParams) => Promise<MempoolEnvelope>
927
- walk: (params?: MempoolWalkParams) => AsyncIterable<IndexMempoolTransaction>
928
- get: (txId: string) => Promise<MempoolTransactionEnvelope | null>
929
- };
930
- private listFtTransfers;
931
- private listNftTransfers;
932
- private walkFtTransfers;
933
- private walkNftTransfers;
934
- private listEvents;
935
- private walkEvents;
936
- private listContractCalls;
937
- private walkContractCalls;
938
- private listCanonical;
939
- private walkCanonical;
940
- private listBlocks;
941
- private getBlock;
942
- private walkBlocks;
943
- private listTransactions;
944
- private getTransaction;
945
- /** Fetch the inclusion proof for a tx (raw tx + Nakamoto header + merkle path)
946
- * to verify client-side with `verifyTransactionProof`. 404 → null. A 503
947
- * (`PROOF_TX_SET_INCOMPLETE` / `PROOF_NODE_UNAVAILABLE`) surfaces as an
948
- * ApiError — the proof can't be assembled on this deployment right now. */
949
- private getTransactionProof;
950
- private walkTransactions;
951
- private listStacking;
952
- private walkStacking;
953
- private listMempool;
954
- private getMempoolTx;
955
- private walkMempool;
956
- }
957
- /**
958
- * Typed client for project management (`/api/projects/*`).
959
- *
960
- * Projects are the account-scoped containers for work. Every method requires an
961
- * account-level (owner) API key or a dashboard session — scoped read keys are
962
- * rejected. Team mutations (invite/remove/role) are intentionally not exposed
963
- * here; only the read view ({@link Projects.team}) is.
964
- */
965
- interface Project {
966
- id: string;
967
- name: string;
968
- slug: string;
969
- network: string;
970
- nodeRpc: string | null;
971
- settings: Record<string, unknown> | null;
972
- createdAt: string;
973
- updatedAt: string;
974
- }
975
- interface ProjectTeamMember {
976
- id: string;
977
- role: string;
978
- email: string;
979
- displayName: string | null;
980
- avatarUrl: string | null;
981
- createdAt: string;
982
- }
983
- interface ProjectInvitation {
984
- id: string;
985
- email: string;
986
- role: string;
987
- expiresAt: string;
988
- createdAt: string;
989
- }
990
- interface ProjectTeam {
991
- members: ProjectTeamMember[];
992
- invitations: ProjectInvitation[];
993
- }
994
- interface CreateProjectParams {
995
- name: string;
996
- slug?: string;
997
- network?: string;
998
- nodeRpc?: string;
999
- }
1000
- interface UpdateProjectParams {
1001
- name?: string;
1002
- /** Rename the project's URL slug. */
1003
- slug?: string;
1004
- network?: string;
1005
- nodeRpc?: string;
1006
- settings?: Record<string, unknown>;
1007
- }
1008
- declare class Projects extends BaseClient {
1009
- constructor(options?: Partial<SecondLayerOptions>);
1010
- /** All projects owned by the account, newest-relevant first. */
1011
- list(): Promise<{
1012
- projects: Project[]
1013
- }>;
1014
- /** A single project by slug. */
1015
- get(slug: string): Promise<Project>;
1016
- /** Create a project. The creator is added as the project owner. */
1017
- create(params: CreateProjectParams): Promise<Project>;
1018
- /** Update a project's name, slug (rename), network, RPC, or settings. */
1019
- update(slug: string, patch: UpdateProjectParams): Promise<Project>;
1020
- /** Delete a project. The account's last remaining project cannot be deleted. */
1021
- delete(slug: string): Promise<{
1022
- ok: true
1023
- }>;
1024
- /** Team members and pending invitations for a project. */
1025
- team(slug: string): Promise<ProjectTeam>;
1026
- }
1027
- import { StreamsEventType } from "@secondlayer/shared";
1028
- /** A Clarity value as Streams serves it: the canonical hex string, a typed
1029
- * object carrying that hex (`{ hex }`), or a decoded Clarity-JSON object.
1030
- * Decode helpers (`decodeNftTransfer`, etc.) resolve it to a concrete value. */
1031
- type StreamsClarityValue = string | {
1032
- hex: string
1033
- } | Record<string, unknown>;
1034
- type StxTransferPayload = {
852
+ type NftTransfer = {
853
+ cursor: string
854
+ block_height: number
855
+ tx_id: string
856
+ tx_index: number
857
+ event_index: number
858
+ event_type: "nft_transfer"
859
+ contract_id: string
860
+ asset_identifier: string
1035
861
  sender: string
1036
862
  recipient: string
1037
- amount: string
1038
- memo?: string
863
+ value: string
1039
864
  };
1040
- type StxMintPayload = {
1041
- recipient: string
1042
- amount: string
865
+ type NftTransfersEnvelope = {
866
+ events: NftTransfer[]
867
+ next_cursor: string | null
868
+ tip: IndexTip
869
+ reorgs: IndexReorg[]
1043
870
  };
1044
- type StxBurnPayload = {
1045
- sender: string
1046
- amount: string
871
+ type NftTransfersListParams = {
872
+ cursor?: string | null
873
+ fromCursor?: string | null
874
+ limit?: number
875
+ contractId?: string
876
+ assetIdentifier?: string
877
+ sender?: string
878
+ recipient?: string
879
+ fromHeight?: number
880
+ toHeight?: number
1047
881
  };
1048
- type StxLockPayload = {
1049
- locked_address: string
1050
- locked_amount: string
1051
- unlock_height: string
882
+ type NftTransfersWalkParams = Omit<NftTransfersListParams, "limit"> & {
883
+ batchSize?: number
884
+ signal?: AbortSignal
1052
885
  };
1053
- type FtTransferPayload = {
886
+ type IndexEventBase = {
887
+ cursor: string
888
+ block_height: number
889
+ block_time?: string | null
890
+ tx_id: string
891
+ tx_index: number
892
+ event_index: number
893
+ contract_id: string | null
894
+ };
895
+ type IndexFtTransfer = IndexEventBase & {
896
+ event_type: "ft_transfer"
1054
897
  asset_identifier: string
1055
898
  sender: string
1056
899
  recipient: string
1057
900
  amount: string
1058
901
  };
1059
- type FtMintPayload = {
902
+ type IndexNftTransfer = IndexEventBase & {
903
+ event_type: "nft_transfer"
1060
904
  asset_identifier: string
905
+ sender: string
906
+ recipient: string
907
+ value: string
908
+ };
909
+ type IndexStxTransfer = IndexEventBase & {
910
+ event_type: "stx_transfer"
911
+ sender: string
912
+ recipient: string
913
+ amount: string
914
+ memo: string | null
915
+ };
916
+ type IndexStxMint = IndexEventBase & {
917
+ event_type: "stx_mint"
1061
918
  recipient: string
1062
919
  amount: string
1063
920
  };
1064
- type FtBurnPayload = {
1065
- asset_identifier: string
921
+ type IndexStxBurn = IndexEventBase & {
922
+ event_type: "stx_burn"
1066
923
  sender: string
1067
924
  amount: string
1068
925
  };
1069
- type NftTransferPayload = {
1070
- asset_identifier: string
926
+ type IndexStxLock = IndexEventBase & {
927
+ event_type: "stx_lock"
1071
928
  sender: string
929
+ amount: string
930
+ payload: {
931
+ unlock_height: string | null
932
+ }
933
+ };
934
+ type IndexFtMint = IndexEventBase & {
935
+ event_type: "ft_mint"
936
+ asset_identifier: string
1072
937
  recipient: string
1073
- value: StreamsClarityValue
1074
- /** Canonical serialized hex of `value`, when the stream carries it. */
1075
- raw_value?: string
938
+ amount: string
1076
939
  };
1077
- type NftMintPayload = {
940
+ type IndexFtBurn = IndexEventBase & {
941
+ event_type: "ft_burn"
942
+ asset_identifier: string
943
+ sender: string
944
+ amount: string
945
+ };
946
+ type IndexNftMint = IndexEventBase & {
947
+ event_type: "nft_mint"
1078
948
  asset_identifier: string
1079
949
  recipient: string
1080
- value: StreamsClarityValue
1081
- raw_value?: string
950
+ value: string
1082
951
  };
1083
- type NftBurnPayload = {
952
+ type IndexNftBurn = IndexEventBase & {
953
+ event_type: "nft_burn"
1084
954
  asset_identifier: string
1085
955
  sender: string
1086
- value: StreamsClarityValue
1087
- raw_value?: string
956
+ value: string
1088
957
  };
1089
- type PrintPayload = {
1090
- contract_id?: string | null
1091
- topic?: string
1092
- value?: unknown
1093
- raw_value?: string
958
+ type IndexPrint = IndexEventBase & {
959
+ event_type: "print"
960
+ payload: {
961
+ topic: string | null
962
+ value: unknown
963
+ raw_value: string | null
964
+ }
1094
965
  };
1095
- type StreamsEventBase = {
1096
- /**
1097
- * Globally unique, monotonic position of this event (`<block>:<index>`). Use
1098
- * it as the primary key of your projection rows — replaying a batch then
1099
- * upserts cleanly. Don't synthesize your own id from `tx_id`/`event_index`.
1100
- */
966
+ /** Decoded chain event, discriminated by `event_type`. */
967
+ type IndexEvent = IndexFtTransfer | IndexNftTransfer | IndexStxTransfer | IndexStxMint | IndexStxBurn | IndexStxLock | IndexFtMint | IndexFtBurn | IndexNftMint | IndexNftBurn | IndexPrint;
968
+ type IndexEventType = IndexEvent["event_type"];
969
+ type EventsEnvelope = {
970
+ events: IndexEvent[]
971
+ next_cursor: string | null
972
+ tip: IndexTip
973
+ reorgs: IndexReorg[]
974
+ };
975
+ type EventsListParams = {
976
+ /** Required. One of the decoded event types. */
977
+ eventType: IndexEventType
978
+ cursor?: string | null
979
+ fromCursor?: string | null
980
+ limit?: number
981
+ contractId?: string
982
+ assetIdentifier?: string
983
+ sender?: string
984
+ recipient?: string
985
+ fromHeight?: number
986
+ toHeight?: number
987
+ /** Restrict to contracts conforming to a trait/standard (e.g. "sip-010").
988
+ * Mutually exclusive with contractId; contract-keyed event types only. */
989
+ trait?: string
990
+ };
991
+ type EventsWalkParams = Omit<EventsListParams, "limit"> & {
992
+ batchSize?: number
993
+ signal?: AbortSignal
994
+ };
995
+ type EventsConsumeParams = Omit<EventsListParams, "cursor" | "fromCursor" | "limit"> & IndexConsumeOptions<IndexEvent, EventsEnvelope>;
996
+ type IndexContractCall = {
1101
997
  cursor: string
1102
998
  block_height: number
1103
- block_hash: string
1104
- burn_block_height: number
999
+ block_time?: string | null
1105
1000
  tx_id: string
1106
1001
  tx_index: number
1107
- event_index: number
1108
- contract_id: string | null
1109
- ts: string
1110
- /**
1111
- * True when this event's block is past the finality boundary (immutable).
1112
- * Optional for back-compat; the API always sets it on Streams responses.
1113
- */
1114
- finalized?: boolean
1002
+ contract_id: string
1003
+ function_name: string
1004
+ sender: string
1005
+ status: string
1006
+ args: unknown[]
1007
+ result: unknown
1008
+ result_hex: string | null
1115
1009
  };
1116
- type StreamsEventOf<
1117
- T extends StreamsEventType,
1118
- P
1119
- > = StreamsEventBase & {
1120
- event_type: T
1121
- payload: P
1010
+ type ContractCallsEnvelope = {
1011
+ contract_calls: IndexContractCall[]
1012
+ next_cursor: string | null
1013
+ tip: IndexTip
1014
+ reorgs: IndexReorg[]
1122
1015
  };
1123
- /** A raw Streams event. Discriminated on `event_type`, so `event.payload`
1124
- * narrows to the matching payload shape once the type is checked. */
1125
- type StreamsEvent = StreamsEventOf<"stx_transfer", StxTransferPayload> | StreamsEventOf<"stx_mint", StxMintPayload> | StreamsEventOf<"stx_burn", StxBurnPayload> | StreamsEventOf<"stx_lock", StxLockPayload> | StreamsEventOf<"ft_transfer", FtTransferPayload> | StreamsEventOf<"ft_mint", FtMintPayload> | StreamsEventOf<"ft_burn", FtBurnPayload> | StreamsEventOf<"nft_transfer", NftTransferPayload> | StreamsEventOf<"nft_mint", NftMintPayload> | StreamsEventOf<"nft_burn", NftBurnPayload> | StreamsEventOf<"print", PrintPayload>;
1126
- type StreamsTip = {
1016
+ type ContractCallsListParams = {
1017
+ cursor?: string | null
1018
+ fromCursor?: string | null
1019
+ limit?: number
1020
+ contractId?: string
1021
+ functionName?: string
1022
+ sender?: string
1023
+ fromHeight?: number
1024
+ toHeight?: number
1025
+ /** Restrict to contracts conforming to a trait/standard (e.g. "sip-010").
1026
+ * Mutually exclusive with contractId. */
1027
+ trait?: string
1028
+ };
1029
+ type ContractCallsWalkParams = Omit<ContractCallsListParams, "limit"> & {
1030
+ batchSize?: number
1031
+ signal?: AbortSignal
1032
+ };
1033
+ type ContractCallsConsumeParams = Omit<ContractCallsListParams, "cursor" | "fromCursor" | "limit"> & IndexConsumeOptions<IndexContractCall, ContractCallsEnvelope>;
1034
+ /** One canonical block in the sync map. Lean by design — block + parent hash
1035
+ * for chain linkage, burn anchor for Bitcoin confirmations. Use `blocks` for
1036
+ * the full block resource. */
1037
+ type IndexCanonicalBlock = {
1038
+ cursor: string
1127
1039
  block_height: number
1128
1040
  block_hash: string
1041
+ parent_hash: string
1129
1042
  burn_block_height: number
1130
- /**
1131
- * Highest Stacks block past the burn-confirmation finality boundary.
1132
- * Optional for back-compat; the API always sets it.
1133
- */
1134
- finalized_height?: number
1135
- lag_seconds: number
1136
- /**
1137
- * Oldest height still seekable on the live API for the caller's tier
1138
- * (`tip - retention`). `null` = unlimited retention. Older reads must use the
1139
- * cold dumps lane. Optional for back-compat.
1140
- */
1141
- oldest_seekable_height?: number | null
1142
- /** Oldest seekable cursor (`<oldest_seekable_height>:0`); `null` = unlimited. */
1143
- oldest_cursor?: string | null
1043
+ burn_block_hash: string | null
1144
1044
  };
1145
- type StreamsCanonicalBlock = {
1045
+ type CanonicalEnvelope = {
1046
+ canonical: IndexCanonicalBlock[]
1047
+ next_cursor: string | null
1048
+ tip: IndexTip
1049
+ };
1050
+ type CanonicalListParams = {
1051
+ cursor?: string | null
1052
+ fromCursor?: string | null
1053
+ limit?: number
1054
+ fromHeight?: number
1055
+ toHeight?: number
1056
+ };
1057
+ type CanonicalWalkParams = Omit<CanonicalListParams, "limit"> & {
1058
+ batchSize?: number
1059
+ signal?: AbortSignal
1060
+ };
1061
+ /** A block resource. Metadata is intentionally thin — only chain-linkage and
1062
+ * burn-anchor fields are persisted (no miner / tx_count / signer). */
1063
+ type IndexBlock = {
1064
+ cursor: string
1146
1065
  block_height: number
1147
1066
  block_hash: string
1067
+ parent_hash: string
1148
1068
  burn_block_height: number
1149
1069
  burn_block_hash: string | null
1150
- is_canonical: true
1151
- };
1152
- type StreamsReorg = {
1153
- detected_at: string
1154
- fork_point_height: number
1155
- orphaned_range: {
1156
- from: string
1157
- to: string
1158
- }
1159
- new_canonical_tip: string
1070
+ block_time: string | null
1071
+ canonical: boolean
1160
1072
  };
1161
- type StreamsEventsEnvelope = {
1162
- events: StreamsEvent[]
1073
+ type BlocksEnvelope = {
1074
+ blocks: IndexBlock[]
1163
1075
  next_cursor: string | null
1164
- tip: StreamsTip
1165
- reorgs: StreamsReorg[]
1166
- };
1167
- type StreamsEventsListEnvelope = Omit<StreamsEventsEnvelope, "next_cursor">;
1168
- type StreamsReorgsListParams = {
1169
- since: string
1170
- limit?: number
1076
+ tip: IndexTip
1171
1077
  };
1172
- type StreamsReorgsListEnvelope = {
1173
- reorgs: StreamsReorg[]
1174
- next_since: string | null
1078
+ type BlockEnvelope = {
1079
+ block: IndexBlock
1080
+ tip: IndexTip
1175
1081
  };
1176
- /** A filter that matches a single value or any value in a list. */
1177
- type StreamsFilterValue = string | readonly string[];
1178
- type StreamsEventsListParams = {
1082
+ type BlocksListParams = {
1179
1083
  cursor?: string | null
1084
+ fromCursor?: string | null
1085
+ limit?: number
1180
1086
  fromHeight?: number
1181
1087
  toHeight?: number
1182
- types?: readonly StreamsEventType[]
1183
- /** Event types to exclude (applied after `types`). */
1184
- notTypes?: readonly StreamsEventType[]
1185
- contractId?: StreamsFilterValue
1186
- sender?: StreamsFilterValue
1187
- recipient?: StreamsFilterValue
1188
- assetIdentifier?: string
1189
- limit?: number
1190
1088
  };
1191
- type StreamsEventsStreamParams = {
1192
- fromCursor?: string | null
1193
- types?: readonly StreamsEventType[]
1194
- notTypes?: readonly StreamsEventType[]
1195
- contractId?: StreamsFilterValue
1196
- sender?: StreamsFilterValue
1197
- recipient?: StreamsFilterValue
1198
- assetIdentifier?: string
1089
+ type BlocksWalkParams = Omit<BlocksListParams, "limit"> & {
1199
1090
  batchSize?: number
1200
- emptyBackoffMs?: number
1201
- maxPages?: number
1202
- maxEmptyPolls?: number
1203
1091
  signal?: AbortSignal
1204
1092
  };
1205
- type StreamsEventsSubscribeParams = {
1206
- /** Resume strictly after this cursor; omit to live-tail from the tip. */
1207
- fromCursor?: string | null
1208
- types?: readonly StreamsEventType[]
1209
- notTypes?: readonly StreamsEventType[]
1210
- contractId?: StreamsFilterValue
1211
- sender?: StreamsFilterValue
1212
- recipient?: StreamsFilterValue
1213
- assetIdentifier?: string
1214
- /** Abort to unsubscribe (the returned function does the same). */
1215
- signal?: AbortSignal
1216
- /** Called for each pushed event, in order. */
1217
- onEvent: (event: StreamsEvent) => void | Promise<void>
1218
- /** Called on a connection error; the subscription auto-reconnects from the
1219
- * last delivered cursor unless the signal has aborted. */
1220
- onError?: (err: unknown) => void
1221
- };
1222
- /**
1223
- * The checkpoint the SDK computes for a batch. Persist `cursor` inside the same
1224
- * transaction as your projection writes, then resume from it via `fromCursor`.
1225
- * It is the position to advance to: `next_cursor` normally, or the last
1226
- * finalized event when `finalizedOnly` is set.
1227
- */
1228
- type StreamsBatchContext = {
1229
- cursor: string | null
1093
+ type IndexPostCondition = {
1094
+ type: "stx"
1095
+ principal: string
1096
+ condition_code: number
1097
+ condition_code_name: string | null
1098
+ amount: string
1099
+ } | {
1100
+ type: "ft"
1101
+ principal: string
1102
+ asset_identifier: string
1103
+ condition_code: number
1104
+ condition_code_name: string | null
1105
+ amount: string
1106
+ } | {
1107
+ type: "nft"
1108
+ principal: string
1109
+ asset_identifier: string
1110
+ asset_value: unknown
1111
+ condition_code: number
1112
+ condition_code_name: string | null
1230
1113
  };
1231
- /**
1232
- * The checkpoint for a reorg rollback. Persist `cursor` (the rewind position)
1233
- * inside the same transaction as your rollback so the two commit atomically.
1234
- */
1235
- type StreamsReorgContext = {
1114
+ /** Full transaction document: columnar fields plus `raw_tx`-decoded enrichment.
1115
+ * Payload sub-objects are present only for the matching `tx_type`; enrichment
1116
+ * fields are null when `raw_tx` isn't decodable (e.g. burnchain ops). */
1117
+ type IndexTransaction = {
1236
1118
  cursor: string
1119
+ tx_id: string
1120
+ block_height: number
1121
+ block_time?: string | null
1122
+ tx_index: number
1123
+ tx_type: string
1124
+ sender: string
1125
+ status: string
1126
+ fee: string | null
1127
+ nonce: string | null
1128
+ sponsored: boolean | null
1129
+ anchor_mode: string | null
1130
+ post_condition_mode: string | null
1131
+ post_conditions: IndexPostCondition[]
1132
+ contract_call?: {
1133
+ contract_id: string
1134
+ function_name: string
1135
+ function_args: unknown[]
1136
+ /** Raw hex-encoded ClarityValues; decode(function_args_hex[i]) === function_args[i]. */
1137
+ function_args_hex: string[]
1138
+ result: unknown
1139
+ result_hex: string | null
1140
+ }
1141
+ token_transfer?: {
1142
+ recipient: string
1143
+ amount: string
1144
+ memo: string
1145
+ }
1146
+ smart_contract?: {
1147
+ contract_id: string | null
1148
+ clarity_version: number | null
1149
+ }
1150
+ coinbase?: {
1151
+ alt_recipient: string | null
1152
+ }
1153
+ tenure_change?: {
1154
+ cause: number
1155
+ }
1237
1156
  };
1238
- type StreamsEventsConsumeParams = {
1239
- fromCursor?: string | null
1240
- mode?: "tail" | "bounded"
1241
- /**
1242
- * Emit only finalized (immutable) events and never surface reorgs. The SDK
1243
- * checkpoints at the last finalized event and re-reads the unfinalized tail
1244
- * until it settles. Trades finality lag for zero reorg handling; `onReorg` is
1245
- * ignored.
1246
- */
1247
- finalizedOnly?: boolean
1248
- types?: readonly StreamsEventType[]
1249
- notTypes?: readonly StreamsEventType[]
1250
- contractId?: StreamsFilterValue
1251
- sender?: StreamsFilterValue
1252
- recipient?: StreamsFilterValue
1253
- assetIdentifier?: string
1254
- batchSize?: number
1255
- /**
1256
- * Apply a page of canonical events. Persist `ctx.cursor` in the same
1257
- * transaction as your writes. Returning a cursor overrides `ctx.cursor` as
1258
- * the resume point (advanced manual control); returning nothing uses it.
1259
- */
1260
- onBatch: (events: StreamsEvent[], envelope: StreamsEventsEnvelope, ctx: StreamsBatchContext) => void | string | null | undefined | Promise<void> | Promise<string | null | undefined>
1261
- /**
1262
- * Roll your projection back to `reorg.fork_point_height`, persisting
1263
- * `ctx.cursor` in the same transaction. Called once per *new* reorg
1264
- * (deduped in-memory, fork-ascending) before the SDK rewinds and re-reads the
1265
- * now-canonical events. Omit it to ignore reorgs (events stay canonical, but
1266
- * stale rows from an orphaned fork are left in place).
1267
- */
1268
- onReorg?: (reorg: StreamsReorg, ctx: StreamsReorgContext) => Promise<void> | void
1269
- emptyBackoffMs?: number
1270
- maxPages?: number
1271
- maxEmptyPolls?: number
1272
- signal?: AbortSignal
1157
+ type TransactionsEnvelope = {
1158
+ transactions: IndexTransaction[]
1159
+ next_cursor: string | null
1160
+ tip: IndexTip
1161
+ reorgs: IndexReorg[]
1273
1162
  };
1274
- /**
1275
- * One yielded page from {@link StreamsClient.consume} — the
1276
- * `GET /v1/streams/events` envelope verbatim, with `next_cursor` renamed to
1277
- * `cursor` (the checkpoint to persist and resume from).
1278
- */
1279
- type StreamsBatch = {
1280
- /** Canonical events of this page, in cursor order. */
1281
- events: StreamsEvent[]
1282
- /** Checkpoint after this page — pass back as `consume({ cursor })` to resume. */
1283
- cursor: string | null
1284
- tip: StreamsTip
1285
- /** Chain reorgs reported alongside this page; empty when none. */
1286
- reorgs: StreamsReorg[]
1163
+ type TransactionEnvelope = {
1164
+ transaction: IndexTransaction
1165
+ tip: IndexTip
1287
1166
  };
1288
- type StreamsConsumeParams = {
1289
- /** Resume strictly after this cursor; omit to start from the oldest seekable page. */
1167
+ type TransactionsListParams = {
1290
1168
  cursor?: string | null
1291
- types?: readonly StreamsEventType[]
1292
- notTypes?: readonly StreamsEventType[]
1293
- contractId?: StreamsFilterValue
1294
- sender?: StreamsFilterValue
1295
- recipient?: StreamsFilterValue
1296
- assetIdentifier?: string
1297
- /** Events per page (the `limit` query param). Default 100. */
1169
+ fromCursor?: string | null
1170
+ limit?: number
1171
+ type?: string
1172
+ sender?: string
1173
+ contractId?: string
1174
+ fromHeight?: number
1175
+ toHeight?: number
1176
+ };
1177
+ type TransactionsWalkParams = Omit<TransactionsListParams, "limit"> & {
1298
1178
  batchSize?: number
1299
- /** Poll interval while caught up at the tip, in ms. Default 2000. */
1300
- intervalMs?: number
1301
- /** Abort to end the iteration. */
1302
1179
  signal?: AbortSignal
1303
1180
  };
1304
- type StreamsEventsConsumeResult = {
1305
- cursor: string | null
1306
- pages: number
1307
- emptyPolls: number
1308
- };
1309
- type StreamsEventsReplayParams = {
1310
- /** Start point: `"genesis"` (default) or a `<block>:<index>` cursor. */
1311
- from?: "genesis" | string
1312
- /**
1313
- * Called once per finalized dump file, in block order, before live tailing.
1314
- * Process the parquet with your own tooling (e.g. DuckDB) — the SDK does not
1315
- * decode parquet. Use `client.dumps.download(file)` to fetch + verify bytes.
1316
- */
1317
- onDumpFile: (file: StreamsDumpFile) => Promise<void> | void
1318
- /** Called per live page after the dump phase, like `consume`. */
1319
- onBatch: (events: StreamsEvent[], envelope: StreamsEventsEnvelope) => Promise<string | null | undefined> | string | null | undefined
1320
- mode?: "tail" | "bounded"
1321
- batchSize?: number
1322
- emptyBackoffMs?: number
1323
- maxPages?: number
1324
- maxEmptyPolls?: number
1325
- signal?: AbortSignal
1181
+ /** A decoded PoX-4 stacking action (one per stacking contract call). */
1182
+ type IndexStackingAction = {
1183
+ cursor: string
1184
+ block_height: number
1185
+ block_time?: string | null
1186
+ burn_block_height: number
1187
+ tx_id: string
1188
+ tx_index: number
1189
+ function_name: string
1190
+ caller: string
1191
+ stacker: string | null
1192
+ delegate_to: string | null
1193
+ amount_ustx: string | null
1194
+ lock_period: number | null
1195
+ pox_addr: {
1196
+ version: number | null
1197
+ hashbytes: string | null
1198
+ btc: string | null
1199
+ }
1200
+ start_cycle: number | null
1201
+ end_cycle: number | null
1202
+ reward_cycle: number | null
1203
+ signer_key: string | null
1204
+ result_ok: boolean
1326
1205
  };
1327
- /** One bulk parquet file in the dumps manifest. `path` is the object key under
1328
- * the dumps base URL. */
1329
- type StreamsDumpFile = {
1330
- path: string
1331
- from_block: number
1332
- to_block: number
1333
- min_cursor: string | null
1334
- max_cursor: string | null
1335
- row_count: number
1336
- byte_size: number
1337
- sha256: string
1338
- schema_version: number
1339
- created_at: string
1206
+ type StackingEnvelope = {
1207
+ stacking: IndexStackingAction[]
1208
+ next_cursor: string | null
1209
+ tip: IndexTip
1210
+ reorgs: IndexReorg[]
1211
+ /** Present only when the PoX-4 decoder is disabled, explaining an empty feed. */
1212
+ notes?: string
1340
1213
  };
1341
- type StreamsDumpsManifest = {
1342
- dataset: string
1343
- network: string
1344
- version: string
1345
- schema_version: number
1346
- generated_at: string
1347
- producer_version: string
1348
- finality_lag_blocks: number
1349
- /** Cursor at the end of the finalized bulk coverage — hand to live tailing. */
1350
- latest_finalized_cursor: string | null
1351
- coverage: {
1352
- from_block: number
1353
- to_block: number
1354
- }
1355
- files: StreamsDumpFile[]
1356
- /** ed25519 signature over the manifest's canonical bytes. Absent on legacy
1357
- * unsigned manifests. Verified by `list()` when `verifyDumpsManifest` is on. */
1358
- signature?: string
1359
- /** Short id of the signing public key. */
1360
- key_id?: string
1214
+ type StackingListParams = {
1215
+ cursor?: string | null
1216
+ fromCursor?: string | null
1217
+ limit?: number
1218
+ functionName?: string
1219
+ stacker?: string
1220
+ caller?: string
1221
+ fromHeight?: number
1222
+ toHeight?: number
1361
1223
  };
1362
- type StreamsDumps = {
1363
- /** Fetch and parse the latest dumps manifest. */
1364
- list(): Promise<StreamsDumpsManifest>
1365
- /** Absolute URL for a manifest file. */
1366
- fileUrl(file: StreamsDumpFile): string
1367
- /** Download a parquet file and verify its sha256 against the manifest. */
1368
- download(file: StreamsDumpFile): Promise<Uint8Array>
1224
+ type StackingWalkParams = Omit<StackingListParams, "limit"> & {
1225
+ batchSize?: number
1226
+ signal?: AbortSignal
1369
1227
  };
1370
- type StreamsClient = {
1371
- /**
1372
- * Follow Streams as an async iterator of page batches.
1373
- *
1374
- * Yields one {@link StreamsBatch} per `GET /v1/streams/events` page — the
1375
- * existing envelope (`events`, `next_cursor` → `cursor`, `tip`, `reorgs`)
1376
- * with zero extra API calls. Batches are chosen over per-block groupings
1377
- * because the envelope is page-keyed, so every yield is exactly one fetch.
1378
- * Empty pages are skipped; at the tip the iterator re-polls every
1379
- * `intervalMs` (default 2000) until aborted via `signal`.
1380
- *
1381
- * Reorgs are surfaced on the batch (`batch.reorgs`) but the cursor is not
1382
- * rewound automatically — use `events.consume` with `onReorg` for managed
1383
- * rollback semantics.
1384
- */
1385
- consume(params?: StreamsConsumeParams): AsyncIterableIterator<StreamsBatch>
1386
- events: {
1387
- list(params?: StreamsEventsListParams): Promise<StreamsEventsEnvelope>
1388
- byTxId(txId: string): Promise<StreamsEventsListEnvelope>
1389
- /**
1390
- * Pull pages from Streams and call `onBatch` after each page.
1391
- *
1392
- * Use `consume` for indexers and ETL jobs that own checkpointing. Return
1393
- * the checkpoint cursor from `onBatch`. Default `mode: "tail"` keeps
1394
- * polling when caught up; `mode: "bounded"` exits on the first empty page.
1395
- * The consumer also exits when `maxPages`, `maxEmptyPolls`, or `signal`
1396
- * stops it.
1397
- */
1398
- consume(params: StreamsEventsConsumeParams): Promise<StreamsEventsConsumeResult>
1399
- /**
1400
- * Backfill from bulk dumps, then continue live from the dump→live seam in
1401
- * one call. Iterates finalized dump files (via `onDumpFile`) in block
1402
- * order, then tails live from the manifest's `latest_finalized_cursor`
1403
- * (exclusive input → no gap or duplicate at the seam). Requires
1404
- * `dumpsBaseUrl`.
1405
- */
1406
- replay(params: StreamsEventsReplayParams): Promise<StreamsEventsConsumeResult>
1407
- /**
1408
- * Follow Streams as an async iterator.
1409
- *
1410
- * Use `stream` for live processors and watch-style apps. It tails
1411
- * indefinitely by default and stops when its `AbortSignal`, `maxPages`, or
1412
- * `maxEmptyPolls` stops it.
1413
- */
1414
- stream(params?: StreamsEventsStreamParams): AsyncIterable<StreamsEvent>
1415
- /**
1416
- * Subscribe to the real-time SSE push surface. Calls `onEvent` for each new
1417
- * canonical event as the server pushes it (chain cadence, not poll-bounded),
1418
- * and verifies each frame's inline ed25519 signature when the client was
1419
- * created with `verify`. Returns an unsubscribe function.
1420
- */
1421
- subscribe(params: StreamsEventsSubscribeParams): () => void
1228
+ /** A pending (unconfirmed) transaction. Like a transaction document but
1229
+ * pre-chain — no block_height/tx_index/result/events — with `received_at` and
1230
+ * a sequence cursor instead of a block position. */
1231
+ type IndexMempoolTransaction = {
1232
+ cursor: string
1233
+ tx_id: string
1234
+ tx_type: string
1235
+ sender: string
1236
+ received_at?: string | null
1237
+ fee: string | null
1238
+ nonce: string | null
1239
+ sponsored: boolean | null
1240
+ anchor_mode: string | null
1241
+ post_condition_mode: string | null
1242
+ post_conditions: IndexPostCondition[]
1243
+ contract_call?: {
1244
+ contract_id: string
1245
+ function_name: string
1246
+ function_args: unknown[]
1422
1247
  }
1423
- blocks: {
1424
- events(heightOrHash: number | string): Promise<StreamsEventsListEnvelope>
1248
+ token_transfer?: {
1249
+ recipient: string
1250
+ amount: string
1251
+ memo: string
1425
1252
  }
1426
- reorgs: {
1427
- list(params: StreamsReorgsListParams): Promise<StreamsReorgsListEnvelope>
1253
+ smart_contract?: {
1254
+ clarity_version: number | null
1428
1255
  }
1429
- /** Bulk parquet dumps. Requires `dumpsBaseUrl` on the client. */
1430
- dumps: StreamsDumps
1431
- canonical(height: number): Promise<StreamsCanonicalBlock>
1432
- tip(): Promise<StreamsTip>
1433
- /** Your own Streams consumption (events today + this month) and tier limits. */
1434
- usage(): Promise<StreamsUsage>
1435
- };
1436
- type StreamsUsage = {
1437
- product: "streams"
1438
- tier: string
1439
- limits: {
1440
- rate_limit_per_second: number | null
1441
- retention_days: number | null
1256
+ coinbase?: {
1257
+ alt_recipient: string | null
1442
1258
  }
1443
- usage: {
1444
- events_today: number
1445
- events_this_month: number
1259
+ tenure_change?: {
1260
+ cause: number
1446
1261
  }
1447
1262
  };
1263
+ type MempoolEnvelope = {
1264
+ mempool: IndexMempoolTransaction[]
1265
+ next_cursor: string | null
1266
+ tip: IndexTip
1267
+ };
1268
+ type MempoolTransactionEnvelope = {
1269
+ transaction: IndexMempoolTransaction
1270
+ tip: IndexTip
1271
+ };
1272
+ type MempoolListParams = {
1273
+ cursor?: string | null
1274
+ fromCursor?: string | null
1275
+ limit?: number
1276
+ sender?: string
1277
+ type?: string
1278
+ /** Filter to pending calls to a single contract (e.g. `SP….contract`). */
1279
+ contractId?: string
1280
+ };
1281
+ type MempoolWalkParams = Omit<MempoolListParams, "limit"> & {
1282
+ batchSize?: number
1283
+ signal?: AbortSignal
1284
+ };
1285
+ /**
1286
+ * Empirical per-topic print payload schema for a contract, inferred from
1287
+ * sampled on-chain events. `topics` is sorted by count desc; `sampled` is true
1288
+ * when the contract has more print events than the windows examined.
1289
+ */
1290
+ type PrintSchemaResponse = {
1291
+ contract_id: string
1292
+ topics: InferredTopicSchema[]
1293
+ sampled: boolean
1294
+ total_events: number
1295
+ /** True when the count hit the server-side cap (total_events is the cap). */
1296
+ total_events_capped: boolean
1297
+ sample: {
1298
+ size: number
1299
+ newest_height: number | null
1300
+ oldest_height: number | null
1301
+ }
1302
+ tip: IndexTip
1303
+ };
1304
+ /**
1305
+ * `index.ftTransfers` — callable shorthand for `.list()`, with `.list`/`.walk`
1306
+ * still available: `await sl.index.ftTransfers({ contractId })`.
1307
+ *
1308
+ * The API accepts `contract_id`/`sender`/`recipient` equality filters only —
1309
+ * no amount filtering and no asset-slug resolution on /v1/index/ft-transfers.
1310
+ */
1311
+ interface FtTransfersResource {
1312
+ (params?: FtTransfersListParams): Promise<FtTransfersEnvelope>;
1313
+ list(params?: FtTransfersListParams): Promise<FtTransfersEnvelope>;
1314
+ walk(params?: FtTransfersWalkParams): AsyncIterable<FtTransfer>;
1315
+ }
1316
+ /** `index.nftTransfers` — callable shorthand for `.list()` (see {@link FtTransfersResource}). */
1317
+ interface NftTransfersResource {
1318
+ (params?: NftTransfersListParams): Promise<NftTransfersEnvelope>;
1319
+ list(params?: NftTransfersListParams): Promise<NftTransfersEnvelope>;
1320
+ walk(params?: NftTransfersWalkParams): AsyncIterable<NftTransfer>;
1321
+ }
1322
+ /** `index.events` — callable shorthand for `.list()`; `eventType` is required. */
1323
+ interface IndexEventsResource {
1324
+ (params: EventsListParams): Promise<EventsEnvelope>;
1325
+ list(params: EventsListParams): Promise<EventsEnvelope>;
1326
+ walk(params: EventsWalkParams): AsyncIterable<IndexEvent>;
1327
+ consume(params: EventsConsumeParams): Promise<{
1328
+ cursor: string | null
1329
+ pages: number
1330
+ emptyPolls: number
1331
+ }>;
1332
+ }
1333
+ /** Per-event-type filter vocabulary in the {@link IndexDiscovery} doc. */
1334
+ type IndexEventTypeFilters = {
1335
+ columns?: string[]
1336
+ allowed_filters?: string[]
1337
+ equality_filters?: string[]
1338
+ required_non_null?: string[]
1339
+ };
1340
+ /** The `GET /v1/index` discovery doc — live endpoint + filter vocabulary.
1341
+ * Shape is intentionally open (the server may add fields); the agent-relevant
1342
+ * parts are the per-type filter rules. */
1343
+ type IndexDiscovery = {
1344
+ event_type_filters?: Record<string, IndexEventTypeFilters>
1345
+ [key: string]: unknown
1346
+ };
1347
+ declare class Index extends BaseClient {
1348
+ constructor(options?: Partial<SecondLayerOptions>);
1349
+ /** Your own Index consumption (decoded events today + this month) and tier limits. */
1350
+ usage(): Promise<IndexUsage>;
1351
+ /**
1352
+ * Index discovery doc — the live vocabulary: every endpoint, each event type's
1353
+ * columns, allowed/equality filters, and required-non-null fields. Read this to
1354
+ * learn what's queryable (and which types accept `trait`) instead of hardcoding.
1355
+ */
1356
+ discover(): Promise<IndexDiscovery>;
1357
+ /**
1358
+ * Empirical per-topic print payload schema for a contract — what topics it
1359
+ * emits and each field's observed Clarity/TS/column types. Anonymous read;
1360
+ * 404 → null.
1361
+ */
1362
+ printSchema(contractId: string): Promise<PrintSchemaResponse | null>;
1363
+ /** Callable: `index.ftTransfers(params)` ≡ `index.ftTransfers.list(params)`. */
1364
+ readonly ftTransfers: FtTransfersResource;
1365
+ /** Callable: `index.nftTransfers(params)` ≡ `index.nftTransfers.list(params)`. */
1366
+ readonly nftTransfers: NftTransfersResource;
1367
+ /** Generic decoded events by `event_type` (the full /v1/index/events surface).
1368
+ * Callable: `index.events(params)` ≡ `index.events.list(params)`. */
1369
+ readonly events: IndexEventsResource;
1370
+ readonly contractCalls: {
1371
+ list: (params?: ContractCallsListParams) => Promise<ContractCallsEnvelope>
1372
+ walk: (params?: ContractCallsWalkParams) => AsyncIterable<IndexContractCall>
1373
+ consume: (params: ContractCallsConsumeParams) => Promise<{
1374
+ cursor: string | null
1375
+ pages: number
1376
+ emptyPolls: number
1377
+ }>
1378
+ };
1379
+ /** Canonical block-hash map — sync only the current canonical chain. */
1380
+ readonly canonical: {
1381
+ list: (params?: CanonicalListParams) => Promise<CanonicalEnvelope>
1382
+ walk: (params?: CanonicalWalkParams) => AsyncIterable<IndexCanonicalBlock>
1383
+ };
1384
+ /** Canonical blocks: paginated `list`/`walk`, plus `get` by height or hash
1385
+ * (resolves to null on 404). */
1386
+ readonly blocks: {
1387
+ list: (params?: BlocksListParams) => Promise<BlocksEnvelope>
1388
+ walk: (params?: BlocksWalkParams) => AsyncIterable<IndexBlock>
1389
+ get: (ref: string | number) => Promise<BlockEnvelope | null>
1390
+ };
1391
+ /** Full transaction documents: paginated `list`/`walk`, plus `get` by tx_id
1392
+ * (resolves to null on 404). */
1393
+ readonly transactions: {
1394
+ list: (params?: TransactionsListParams) => Promise<TransactionsEnvelope>
1395
+ walk: (params?: TransactionsWalkParams) => AsyncIterable<IndexTransaction>
1396
+ get: (txId: string) => Promise<TransactionEnvelope | null>
1397
+ getProof: (txId: string) => Promise<TransactionProof | null>
1398
+ };
1399
+ /** Decoded PoX-4 stacking actions. Empty (with a `notes` hint) when the
1400
+ * platform's PoX-4 decoder is disabled. */
1401
+ readonly stacking: {
1402
+ list: (params?: StackingListParams) => Promise<StackingEnvelope>
1403
+ walk: (params?: StackingWalkParams) => AsyncIterable<IndexStackingAction>
1404
+ };
1405
+ /** Pending (unconfirmed) transactions: paginated `list`/`walk`, plus `get` by
1406
+ * tx_id (resolves to null when the tx has confirmed or dropped). */
1407
+ readonly mempool: {
1408
+ list: (params?: MempoolListParams) => Promise<MempoolEnvelope>
1409
+ walk: (params?: MempoolWalkParams) => AsyncIterable<IndexMempoolTransaction>
1410
+ get: (txId: string) => Promise<MempoolTransactionEnvelope | null>
1411
+ };
1412
+ private listFtTransfers;
1413
+ private listNftTransfers;
1414
+ private walkFtTransfers;
1415
+ private walkNftTransfers;
1416
+ private listEvents;
1417
+ private walkEvents;
1418
+ private listContractCalls;
1419
+ private walkContractCalls;
1420
+ private listCanonical;
1421
+ private walkCanonical;
1422
+ private listBlocks;
1423
+ private getBlock;
1424
+ private walkBlocks;
1425
+ private listTransactions;
1426
+ private getTransaction;
1427
+ /** Fetch the inclusion proof for a tx (raw tx + Nakamoto header + merkle path)
1428
+ * to verify client-side with `verifyTransactionProof`. 404 → null. A 503
1429
+ * (`PROOF_TX_SET_INCOMPLETE` / `PROOF_NODE_UNAVAILABLE`) surfaces as an
1430
+ * ApiError — the proof can't be assembled on this deployment right now. */
1431
+ private getTransactionProof;
1432
+ private walkTransactions;
1433
+ private listStacking;
1434
+ private walkStacking;
1435
+ private listMempool;
1436
+ private getMempoolTx;
1437
+ private walkMempool;
1438
+ }
1439
+ /**
1440
+ * Typed client for project management (`/api/projects/*`).
1441
+ *
1442
+ * Projects are the account-scoped containers for work. Every method requires an
1443
+ * account-level (owner) API key or a dashboard session — scoped read keys are
1444
+ * rejected. Team mutations (invite/remove/role) are intentionally not exposed
1445
+ * here; only the read view ({@link Projects.team}) is.
1446
+ */
1447
+ interface Project {
1448
+ id: string;
1449
+ name: string;
1450
+ slug: string;
1451
+ network: string;
1452
+ nodeRpc: string | null;
1453
+ settings: Record<string, unknown> | null;
1454
+ createdAt: string;
1455
+ updatedAt: string;
1456
+ }
1457
+ interface ProjectTeamMember {
1458
+ id: string;
1459
+ role: string;
1460
+ email: string;
1461
+ displayName: string | null;
1462
+ avatarUrl: string | null;
1463
+ createdAt: string;
1464
+ }
1465
+ interface ProjectInvitation {
1466
+ id: string;
1467
+ email: string;
1468
+ role: string;
1469
+ expiresAt: string;
1470
+ createdAt: string;
1471
+ }
1472
+ interface ProjectTeam {
1473
+ members: ProjectTeamMember[];
1474
+ invitations: ProjectInvitation[];
1475
+ }
1476
+ interface CreateProjectParams {
1477
+ name: string;
1478
+ slug?: string;
1479
+ network?: string;
1480
+ nodeRpc?: string;
1481
+ }
1482
+ interface UpdateProjectParams {
1483
+ name?: string;
1484
+ /** Rename the project's URL slug. */
1485
+ slug?: string;
1486
+ network?: string;
1487
+ nodeRpc?: string;
1488
+ settings?: Record<string, unknown>;
1489
+ }
1490
+ declare class Projects extends BaseClient {
1491
+ constructor(options?: Partial<SecondLayerOptions>);
1492
+ /** All projects owned by the account, newest-relevant first. */
1493
+ list(): Promise<{
1494
+ projects: Project[]
1495
+ }>;
1496
+ /** A single project by slug. */
1497
+ get(slug: string): Promise<Project>;
1498
+ /** Create a project. The creator is added as the project owner. */
1499
+ create(params: CreateProjectParams): Promise<Project>;
1500
+ /** Update a project's name, slug (rename), network, RPC, or settings. */
1501
+ update(slug: string, patch: UpdateProjectParams): Promise<Project>;
1502
+ /** Delete a project. The account's last remaining project cannot be deleted. */
1503
+ delete(slug: string): Promise<{
1504
+ ok: true
1505
+ }>;
1506
+ /** Team members and pending invitations for a project. */
1507
+ team(slug: string): Promise<ProjectTeam>;
1508
+ }
1448
1509
  import { CreateSubscriptionRequest, CreateSubscriptionResponse, DeadRow, DeliveryRow, ReplayResult, RotateSecretResponse, SubscriptionDetail, SubscriptionSummary, SubscriptionTestResult, UpdateSubscriptionRequest } from "@secondlayer/shared/schemas/subscriptions";
1449
1510
  declare class Subscriptions extends BaseClient {
1450
1511
  list(): Promise<{