@secondlayer/sdk 6.21.2 → 6.23.0

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