@secondlayer/sdk 6.46.1 → 6.48.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.
@@ -14,12 +14,83 @@ import { STREAMS_EVENT_TYPES, StreamsEventType } from "@secondlayer/shared";
14
14
  * The interface is dependency-free on purpose: implementations with real
15
15
  * database drivers live behind subpath exports (`@secondlayer/sdk/sinks/*`)
16
16
  * so the root entry ships no DB dependency.
17
+ *
18
+ * ## The contract
19
+ *
20
+ * Binding on every implementation; the conformance kit
21
+ * (`@secondlayer/sdk/sinks/testing`) probes each one. Violations are SILENT
22
+ * in production — they surface as gaps or duplicates weeks later, never as
23
+ * errors at the violation site — which is why they are spelled out here and
24
+ * mechanically tested.
25
+ *
26
+ * What the loop guarantees the sink:
27
+ *
28
+ * 1. **Init-before-first-page.** `loadCursor` is called exactly once, before
29
+ * the first fetch — even when the caller passed an explicit `fromCursor`.
30
+ * It is the sink's init hook: create checkpoint storage, validate
31
+ * rollback preconditions.
32
+ * 2. **Deterministic replay.** Re-reading from the same cursor yields the
33
+ * same rows in the same order. `cursor` is therefore a valid idempotency
34
+ * key: an append-only sink can dedup on it with no contract change.
35
+ * 3. **At-least-once delivery.** A batch whose commit outcome was lost (crash
36
+ * after commit, before the loop observed it) is re-committed on restart
37
+ * with the SAME cursor and the same rows.
38
+ *
39
+ * What the sink must guarantee — `commitBatch`:
40
+ *
41
+ * 4. **Rows+cursor atomicity.** The handler's writes and `cursor` commit in
42
+ * ONE transaction. Committing them separately is the classic torn-batch
43
+ * bug: a crash between the two either re-delivers (duplicates) or skips
44
+ * (gap) depending on the order.
45
+ * 5. **Abort on throw.** A throw from `write` aborts the WHOLE transaction —
46
+ * neither rows nor cursor land — so a crashed batch is simply re-read.
47
+ * 6. **The lent transaction is the real one.** `write(tx)` receives the same
48
+ * live transaction the cursor commits in; every handler write must go
49
+ * through it. Writes outside `tx` escape atomicity AND rollback.
50
+ * 7. **Replay safety.** Committing the same cursor twice must not corrupt
51
+ * state (per #3 the rows are identical; upsert/dedup make it exact).
52
+ *
53
+ * What the sink must guarantee — `rollback`:
54
+ *
55
+ * 8. **Delete+rewind atomicity.** Undoing rows at/above the fork and
56
+ * committing `rewindCursor` happen in ONE transaction. A crash between
57
+ * them resumes above the fork and the deleted range is never re-read —
58
+ * the silent-gap bug.
59
+ * 9. **Inclusive fork point.** Undo AT OR ABOVE `forkPointHeight` (`>=`) —
60
+ * the new canonical chain re-supplies the fork block itself.
61
+ * 10. **Idempotent.** The loop may re-apply the same rollback after a crash
62
+ * (reorgs are deduped in memory only); a second application must be a
63
+ * harmless no-op.
64
+ * 11. **Scope by height, not cursor.** On a page reporting several forks the
65
+ * loop calls `rollback` once per fork: each call carries its own
66
+ * `forkPointHeight` but ALL carry the same `rewindCursor` (the lowest
67
+ * fork point). Derive the undo range from `forkPointHeight` only; a
68
+ * sink that derives it from `rewindCursor` under-deletes silently.
69
+ *
70
+ * Error semantics and concurrency:
71
+ *
72
+ * 12. **Throw, don't swallow; no internal retry.** The loop owns retry
73
+ * policy. A swallowed commit error advances the loop past unwritten
74
+ * data; an internal retry can double-apply around a partial failure.
75
+ * 13. **Single writer per checkpoint id.** The loop assumes one live
76
+ * consumer per checkpoint identity. A sink that can detect a second
77
+ * writer (e.g. a lock) must fail loudly — never block or interleave.
17
78
  */
18
79
  interface ConsumerSink<Tx = unknown> {
19
80
  /** Phantom marker carrying `Tx` in a directly-inferable position, so the
20
81
  * consume loops' `TTx` type parameter resolves from the `sink` option
21
82
  * (never set at runtime). */
22
83
  readonly _tx?: Tx;
84
+ /** Static capabilities, read by the loop before the first fetch to fail
85
+ * fast on impossible pairings. */
86
+ readonly capabilities?: {
87
+ /** This sink cannot undo committed rows (append-only store, ClickHouse,
88
+ * parquet, …), so `rollback` is unimplementable and following the
89
+ * unfinalized tip would corrupt it on the first fork. The loop throws
90
+ * loudly unless consuming with `finalizedOnly: true` — in that mode
91
+ * reorgs never reach the sink and `rollback` may simply throw. */
92
+ finalizedOnly?: boolean;
93
+ };
23
94
  /** The committed checkpoint, or `null` on first run. Called once, before
24
95
  * the first page. Implementations may create their checkpoint storage
25
96
  * here and SHOULD validate their rollback preconditions (e.g. that every
@@ -39,6 +110,11 @@ interface ConsumerSink<Tx = unknown> {
39
110
  * without the rewound cursor is the classic silent-gap bug: a crash
40
111
  * between the two writes resumes above the fork and the deleted range is
41
112
  * never re-read.
113
+ *
114
+ * On a multi-fork page this is called once PER fork, every call with the
115
+ * same `rewindCursor` (the lowest fork point) but its own
116
+ * `forkPointHeight` — scope the undo by `forkPointHeight` only (contract
117
+ * invariant #11), and expect re-application after a crash (#10).
42
118
  */
43
119
  rollback(forkPointHeight: number, rewindCursor: string): Promise<void>;
44
120
  }
@@ -46,97 +122,97 @@ interface ConsumerSink<Tx = unknown> {
46
122
  * is unchanged (an intersection with `unknown` is an identity, so
47
123
  * contextual typing of `onBatch` callbacks never degrades to a union). */
48
124
  type WithSinkTx<TTx> = [TTx] extends [never] ? unknown : {
49
- tx: TTx
125
+ tx: TTx;
50
126
  };
51
127
  type IndexEventBase = {
52
- cursor: string
53
- block_height: number
54
- block_time?: string | null
55
- tx_id: string
56
- tx_index: number
57
- event_index: number
58
- contract_id: string | null
128
+ cursor: string;
129
+ block_height: number;
130
+ block_time?: string | null;
131
+ tx_id: string;
132
+ tx_index: number;
133
+ event_index: number;
134
+ contract_id: string | null;
59
135
  /** Submitting-transaction context, present only when `txContext: true` was
60
136
  * requested. `tx_sender` is the real tx sender — distinct from a transfer's
61
137
  * asset `sender`, and the only place a `print` event's sender is available.
62
138
  * Lets a consumer build per-event tx context without a `/v1/index/transactions`
63
139
  * call per event. */
64
- tx_sender?: string | null
65
- tx_type?: string | null
66
- tx_status?: string | null
67
- tx_contract_id?: string | null
68
- tx_function_name?: string | null
140
+ tx_sender?: string | null;
141
+ tx_type?: string | null;
142
+ tx_status?: string | null;
143
+ tx_contract_id?: string | null;
144
+ tx_function_name?: string | null;
69
145
  };
70
146
  type IndexFtTransfer = IndexEventBase & {
71
- event_type: "ft_transfer"
72
- asset_identifier: string
73
- sender: string
74
- recipient: string
75
- amount: string
147
+ event_type: "ft_transfer";
148
+ asset_identifier: string;
149
+ sender: string;
150
+ recipient: string;
151
+ amount: string;
76
152
  };
77
153
  type IndexNftTransfer = IndexEventBase & {
78
- event_type: "nft_transfer"
79
- asset_identifier: string
80
- sender: string
81
- recipient: string
82
- value: string
154
+ event_type: "nft_transfer";
155
+ asset_identifier: string;
156
+ sender: string;
157
+ recipient: string;
158
+ value: string;
83
159
  };
84
160
  type IndexStxTransfer = IndexEventBase & {
85
- event_type: "stx_transfer"
86
- sender: string
87
- recipient: string
88
- amount: string
89
- memo: string | null
161
+ event_type: "stx_transfer";
162
+ sender: string;
163
+ recipient: string;
164
+ amount: string;
165
+ memo: string | null;
90
166
  };
91
167
  type IndexStxMint = IndexEventBase & {
92
- event_type: "stx_mint"
93
- recipient: string
94
- amount: string
168
+ event_type: "stx_mint";
169
+ recipient: string;
170
+ amount: string;
95
171
  };
96
172
  type IndexStxBurn = IndexEventBase & {
97
- event_type: "stx_burn"
98
- sender: string
99
- amount: string
173
+ event_type: "stx_burn";
174
+ sender: string;
175
+ amount: string;
100
176
  };
101
177
  type IndexStxLock = IndexEventBase & {
102
- event_type: "stx_lock"
103
- sender: string
104
- amount: string
178
+ event_type: "stx_lock";
179
+ sender: string;
180
+ amount: string;
105
181
  payload: {
106
- unlock_height: string | null
107
- }
182
+ unlock_height: string | null;
183
+ };
108
184
  };
109
185
  type IndexFtMint = IndexEventBase & {
110
- event_type: "ft_mint"
111
- asset_identifier: string
112
- recipient: string
113
- amount: string
186
+ event_type: "ft_mint";
187
+ asset_identifier: string;
188
+ recipient: string;
189
+ amount: string;
114
190
  };
115
191
  type IndexFtBurn = IndexEventBase & {
116
- event_type: "ft_burn"
117
- asset_identifier: string
118
- sender: string
119
- amount: string
192
+ event_type: "ft_burn";
193
+ asset_identifier: string;
194
+ sender: string;
195
+ amount: string;
120
196
  };
121
197
  type IndexNftMint = IndexEventBase & {
122
- event_type: "nft_mint"
123
- asset_identifier: string
124
- recipient: string
125
- value: string
198
+ event_type: "nft_mint";
199
+ asset_identifier: string;
200
+ recipient: string;
201
+ value: string;
126
202
  };
127
203
  type IndexNftBurn = IndexEventBase & {
128
- event_type: "nft_burn"
129
- asset_identifier: string
130
- sender: string
131
- value: string
204
+ event_type: "nft_burn";
205
+ asset_identifier: string;
206
+ sender: string;
207
+ value: string;
132
208
  };
133
209
  type IndexPrint = IndexEventBase & {
134
- event_type: "print"
210
+ event_type: "print";
135
211
  payload: {
136
- topic: string | null
137
- value: unknown
138
- raw_value: string | null
139
- }
212
+ topic: string | null;
213
+ value: unknown;
214
+ raw_value: string | null;
215
+ };
140
216
  };
141
217
  /** Decoded chain event, discriminated by `event_type`. */
142
218
  type IndexEvent = IndexFtTransfer | IndexNftTransfer | IndexStxTransfer | IndexStxMint | IndexStxBurn | IndexStxLock | IndexFtMint | IndexFtBurn | IndexNftMint | IndexNftBurn | IndexPrint;
@@ -144,68 +220,68 @@ type IndexEvent = IndexFtTransfer | IndexNftTransfer | IndexStxTransfer | IndexS
144
220
  * object carrying that hex (`{ hex }`), or a decoded Clarity-JSON object.
145
221
  * Decode helpers (`decodeNftTransfer`, etc.) resolve it to a concrete value. */
146
222
  type StreamsClarityValue = string | {
147
- hex: string
223
+ hex: string;
148
224
  } | Record<string, unknown>;
149
225
  type StxTransferPayload = {
150
- sender: string
151
- recipient: string
152
- amount: string
153
- memo?: string
226
+ sender: string;
227
+ recipient: string;
228
+ amount: string;
229
+ memo?: string;
154
230
  };
155
231
  type StxMintPayload = {
156
- recipient: string
157
- amount: string
232
+ recipient: string;
233
+ amount: string;
158
234
  };
159
235
  type StxBurnPayload = {
160
- sender: string
161
- amount: string
236
+ sender: string;
237
+ amount: string;
162
238
  };
163
239
  type StxLockPayload = {
164
- locked_address: string
165
- locked_amount: string
166
- unlock_height: string
240
+ locked_address: string;
241
+ locked_amount: string;
242
+ unlock_height: string;
167
243
  };
168
244
  type FtTransferPayload = {
169
- asset_identifier: string
170
- sender: string
171
- recipient: string
172
- amount: string
245
+ asset_identifier: string;
246
+ sender: string;
247
+ recipient: string;
248
+ amount: string;
173
249
  };
174
250
  type FtMintPayload = {
175
- asset_identifier: string
176
- recipient: string
177
- amount: string
251
+ asset_identifier: string;
252
+ recipient: string;
253
+ amount: string;
178
254
  };
179
255
  type FtBurnPayload = {
180
- asset_identifier: string
181
- sender: string
182
- amount: string
256
+ asset_identifier: string;
257
+ sender: string;
258
+ amount: string;
183
259
  };
184
260
  type NftTransferPayload = {
185
- asset_identifier: string
186
- sender: string
187
- recipient: string
188
- value: StreamsClarityValue
261
+ asset_identifier: string;
262
+ sender: string;
263
+ recipient: string;
264
+ value: StreamsClarityValue;
189
265
  /** Canonical serialized hex of `value`, when the stream carries it. */
190
- raw_value?: string
266
+ raw_value?: string;
191
267
  };
192
268
  type NftMintPayload = {
193
- asset_identifier: string
194
- recipient: string
195
- value: StreamsClarityValue
196
- raw_value?: string
269
+ asset_identifier: string;
270
+ recipient: string;
271
+ value: StreamsClarityValue;
272
+ raw_value?: string;
197
273
  };
198
274
  type NftBurnPayload = {
199
- asset_identifier: string
200
- sender: string
201
- value: StreamsClarityValue
202
- raw_value?: string
275
+ asset_identifier: string;
276
+ sender: string;
277
+ value: StreamsClarityValue;
278
+ raw_value?: string;
203
279
  };
204
280
  type PrintPayload = {
205
- contract_id?: string | null
206
- topic?: string
207
- value?: unknown
208
- raw_value?: string
281
+ contract_id?: string | null;
282
+ topic?: string;
283
+ value?: unknown;
284
+ raw_value?: string;
209
285
  };
210
286
  /** Union of every Streams payload shape, discriminated by `event_type` on the
211
287
  * parent `StreamsEvent`. */
@@ -216,92 +292,97 @@ type StreamsEventBase = {
216
292
  * it as the primary key of your projection rows — replaying a batch then
217
293
  * upserts cleanly. Don't synthesize your own id from `tx_id`/`event_index`.
218
294
  */
219
- cursor: string
220
- block_height: number
221
- block_hash: string
222
- burn_block_height: number
223
- tx_id: string
224
- tx_index: number
225
- event_index: number
226
- contract_id: string | null
227
- ts: string
295
+ cursor: string;
296
+ block_height: number;
297
+ block_hash: string;
298
+ burn_block_height: number;
299
+ tx_id: string;
300
+ tx_index: number;
301
+ event_index: number;
302
+ contract_id: string | null;
303
+ ts: string;
228
304
  /**
229
305
  * True when this event's block is past the finality boundary (immutable).
230
306
  * Optional for back-compat; the API always sets it on Streams responses.
231
307
  */
232
- finalized?: boolean
308
+ finalized?: boolean;
233
309
  /**
234
310
  * Labels whose filter group this event satisfied, present only when the
235
311
  * request used a labelled `filters` map. The SDK dispatches on it for you
236
312
  * (`on.<label>`), so handlers rarely read it directly.
237
313
  */
238
- matched?: string[]
314
+ matched?: string[];
239
315
  };
240
316
  type StreamsEventOf<
241
317
  T extends StreamsEventType,
242
318
  P
243
319
  > = StreamsEventBase & {
244
- event_type: T
245
- payload: P
320
+ event_type: T;
321
+ payload: P;
246
322
  };
247
323
  /** A raw Streams event. Discriminated on `event_type`, so `event.payload`
248
324
  * narrows to the matching payload shape once the type is checked. */
249
325
  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>;
250
326
  type StreamsTip = {
251
- block_height: number
252
- block_hash: string
253
- burn_block_height: number
327
+ block_height: number;
328
+ block_hash: string;
329
+ burn_block_height: number;
254
330
  /**
255
331
  * Highest Stacks block past the burn-confirmation finality boundary.
256
332
  * Optional for back-compat; the API always sets it.
257
333
  */
258
- finalized_height?: number
259
- lag_seconds: number
334
+ finalized_height?: number;
335
+ lag_seconds: number;
260
336
  /**
261
337
  * Oldest height still seekable on the live API for the caller's tier
262
338
  * (`tip - retention`). `null` = unlimited retention. Older reads must use the
263
339
  * cold dumps lane. Optional for back-compat.
264
340
  */
265
- oldest_seekable_height?: number | null
341
+ oldest_seekable_height?: number | null;
266
342
  /** Oldest seekable cursor (`<oldest_seekable_height>:0`); `null` = unlimited. */
267
- oldest_cursor?: string | null
343
+ oldest_cursor?: string | null;
268
344
  };
269
345
  type StreamsCanonicalBlock = {
270
- block_height: number
271
- block_hash: string
272
- burn_block_height: number
273
- burn_block_hash: string | null
274
- is_canonical: true
346
+ block_height: number;
347
+ block_hash: string;
348
+ burn_block_height: number;
349
+ burn_block_hash: string | null;
350
+ is_canonical: true;
275
351
  };
276
352
  type StreamsReorg = {
277
- detected_at: string
278
- fork_point_height: number
353
+ detected_at: string;
354
+ fork_point_height: number;
279
355
  orphaned_range: {
280
- from: string
281
- to: string
282
- }
356
+ from: string;
357
+ to: string;
358
+ };
283
359
  /**
284
360
  * First position of the new canonical chain at the fork, `fork:0`
285
361
  * (INCLUSIVE). Not an exclusive resume token — resuming directly from it
286
362
  * skips `fork:0`. The consumer rewinds to the foot of `fork_point_height`
287
363
  * (`Cursor.atHeight`) to re-read the new run from `fork:0` inclusive.
288
364
  */
289
- new_canonical_tip: string
365
+ new_canonical_tip: string;
290
366
  };
291
- type StreamsEventsEnvelope = {
292
- events: StreamsEvent[]
293
- next_cursor: string | null
294
- tip: StreamsTip
295
- reorgs: StreamsReorg[]
367
+ type StreamsEventsEnvelope<TEvent = StreamsEvent> = {
368
+ events: TEvent[];
369
+ next_cursor: string | null;
370
+ tip: StreamsTip;
371
+ reorgs: StreamsReorg[];
296
372
  };
297
373
  type StreamsEventsListEnvelope = Omit<StreamsEventsEnvelope, "next_cursor">;
374
+ /** The StreamsEvent union narrowed to a `types` selection — what a
375
+ * const-generic `types: ["ft_transfer"]` buys at the type level. */
376
+ type StreamsEventOfTypes<T extends readonly StreamsEventType[]> = Extract<StreamsEvent, {
377
+ event_type: T[number];
378
+ }>;
298
379
  type StreamsReorgsListParams = {
299
- since: string
300
- limit?: number
380
+ since: string;
381
+ limit?: number;
301
382
  };
302
383
  type StreamsReorgsListEnvelope = {
303
- reorgs: StreamsReorg[]
304
- next_since: string | null
384
+ reorgs: StreamsReorg[];
385
+ next_since: string | null;
305
386
  };
306
387
  /** A filter that matches a single value or any value in a list. */
307
388
  type StreamsFilterValue = string | readonly string[];
@@ -310,11 +391,11 @@ type StreamsFilterValue = string | readonly string[];
310
391
  * map OR together server-side.
311
392
  */
312
393
  type StreamsLabelledFilter = {
313
- types?: readonly StreamsEventType[]
314
- contractId?: StreamsFilterValue
315
- sender?: StreamsFilterValue
316
- recipient?: StreamsFilterValue
317
- assetIdentifier?: string
394
+ types?: readonly StreamsEventType[];
395
+ contractId?: StreamsFilterValue;
396
+ sender?: StreamsFilterValue;
397
+ recipient?: StreamsFilterValue;
398
+ assetIdentifier?: string;
318
399
  };
319
400
  /** A map of label → filter group. Labels are yours; the server echoes them. */
320
401
  type StreamsFilterMap = Record<string, StreamsLabelledFilter>;
@@ -327,65 +408,65 @@ type StreamsEventForFilter<
327
408
  F,
328
409
  D extends boolean = false
329
410
  > = F extends {
330
- types: readonly (infer T extends StreamsEventType)[]
411
+ types: readonly (infer T extends StreamsEventType)[];
331
412
  } ? D extends true ? Extract<IndexEvent, {
332
- event_type: T
413
+ event_type: T;
333
414
  }> : Extract<StreamsEvent, {
334
- event_type: T
415
+ event_type: T;
335
416
  }> : D extends true ? IndexEvent : StreamsEvent;
336
417
  type StreamsEventsListParams = {
337
- cursor?: string | null
338
- fromHeight?: number
339
- toHeight?: number
340
- types?: readonly StreamsEventType[]
418
+ cursor?: string | null;
419
+ fromHeight?: number;
420
+ toHeight?: number;
421
+ types?: readonly StreamsEventType[];
341
422
  /** Event types to exclude (applied after `types`). */
342
- notTypes?: readonly StreamsEventType[]
343
- contractId?: StreamsFilterValue
344
- sender?: StreamsFilterValue
345
- recipient?: StreamsFilterValue
346
- assetIdentifier?: string
423
+ notTypes?: readonly StreamsEventType[];
424
+ contractId?: StreamsFilterValue;
425
+ sender?: StreamsFilterValue;
426
+ recipient?: StreamsFilterValue;
427
+ assetIdentifier?: string;
347
428
  /**
348
429
  * Labelled filter groups. The groups OR together in one scan and each
349
430
  * returned event carries the labels it matched (`event.matched`) — two
350
431
  * unrelated concerns share one page, one cursor, one checkpoint.
351
432
  */
352
- filters?: StreamsFilterMap
353
- limit?: number
433
+ filters?: StreamsFilterMap;
434
+ limit?: number;
354
435
  };
355
436
  type StreamsEventsStreamParams = {
356
- fromCursor?: string | null
357
- types?: readonly StreamsEventType[]
358
- notTypes?: readonly StreamsEventType[]
359
- contractId?: StreamsFilterValue
360
- sender?: StreamsFilterValue
361
- recipient?: StreamsFilterValue
362
- assetIdentifier?: string
437
+ fromCursor?: string | null;
438
+ types?: readonly StreamsEventType[];
439
+ notTypes?: readonly StreamsEventType[];
440
+ contractId?: StreamsFilterValue;
441
+ sender?: StreamsFilterValue;
442
+ recipient?: StreamsFilterValue;
443
+ assetIdentifier?: string;
363
444
  /** Labelled filter groups; see {@link StreamsEventsListParams.filters}. */
364
- filters?: StreamsFilterMap
365
- batchSize?: number
366
- emptyBackoffMs?: number
367
- maxPages?: number
368
- maxEmptyPolls?: number
369
- signal?: AbortSignal
445
+ filters?: StreamsFilterMap;
446
+ batchSize?: number;
447
+ emptyBackoffMs?: number;
448
+ maxPages?: number;
449
+ maxEmptyPolls?: number;
450
+ signal?: AbortSignal;
370
451
  };
371
452
  type StreamsEventsSubscribeParams = {
372
453
  /** Resume strictly after this cursor; omit to live-tail from the tip. */
373
- fromCursor?: string | null
374
- types?: readonly StreamsEventType[]
375
- notTypes?: readonly StreamsEventType[]
376
- contractId?: StreamsFilterValue
377
- sender?: StreamsFilterValue
378
- recipient?: StreamsFilterValue
379
- assetIdentifier?: string
454
+ fromCursor?: string | null;
455
+ types?: readonly StreamsEventType[];
456
+ notTypes?: readonly StreamsEventType[];
457
+ contractId?: StreamsFilterValue;
458
+ sender?: StreamsFilterValue;
459
+ recipient?: StreamsFilterValue;
460
+ assetIdentifier?: string;
380
461
  /** Labelled filter groups; see {@link StreamsEventsListParams.filters}. */
381
- filters?: StreamsFilterMap
462
+ filters?: StreamsFilterMap;
382
463
  /** Abort to unsubscribe (the returned function does the same). */
383
- signal?: AbortSignal
464
+ signal?: AbortSignal;
384
465
  /** Called for each pushed event, in order. */
385
- onEvent: (event: StreamsEvent) => void | Promise<void>
466
+ onEvent: (event: StreamsEvent) => void | Promise<void>;
386
467
  /** Called on a connection error; the subscription auto-reconnects from the
387
468
  * last delivered cursor unless the signal has aborted. */
388
- onError?: (err: unknown) => void
469
+ onError?: (err: unknown) => void;
389
470
  };
390
471
  /**
391
472
  * The checkpoint the SDK computes for a batch. Persist `cursor` inside the same
@@ -412,14 +493,14 @@ type ConsumerBatchContext<
412
493
  TReorg = unknown
413
494
  > = {
414
495
  /** Checkpoint to commit alongside your rows. */
415
- cursor: string | null
496
+ cursor: string | null;
416
497
  /** Highest canonical block the sweep has reached. `null` before the first
417
498
  * row of a fresh consume. */
418
- height: number | null
499
+ height: number | null;
419
500
  /** Chain tip as of this page's read. */
420
- tipHeight: number
501
+ tipHeight: number;
421
502
  /** `tipHeight - height`, floored at 0. `null` until `height` is known. */
422
- blocksBehind: number | null
503
+ blocksBehind: number | null;
423
504
  /**
424
505
  * The full tip for this page — `StreamsTip` or `IndexTip` depending on the
425
506
  * surface. Exposed here so a handler never needs the `envelope` parameter,
@@ -427,12 +508,12 @@ type ConsumerBatchContext<
427
508
  * `finalizedOnly` mistake becomes reachable (`return envelope.next_cursor`
428
509
  * jumps the cursor past events that were filtered out and never delivered).
429
510
  */
430
- tip: TTip
511
+ tip: TTip;
431
512
  /**
432
513
  * Reorgs reported alongside this page; empty when none. Rollback still
433
514
  * belongs in `onReorg` — this is for observability inside a batch.
434
515
  */
435
- reorgs: readonly TReorg[]
516
+ reorgs: readonly TReorg[];
436
517
  };
437
518
  /** @deprecated Use {@link ConsumerBatchContext} — the Index and Streams loops
438
519
  * share one shape now. Kept as an alias so existing annotations compile. */
@@ -442,20 +523,20 @@ type StreamsBatchContext = ConsumerBatchContext;
442
523
  * inside the same transaction as your rollback so the two commit atomically.
443
524
  */
444
525
  type StreamsReorgContext = {
445
- cursor: string
526
+ cursor: string;
446
527
  };
447
528
  type StreamsEventsConsumeParams<
448
529
  TTx = never,
449
530
  D extends boolean = false,
450
531
  F extends StreamsFilterMap = Record<never, never>
451
532
  > = {
452
- fromCursor?: string | null
533
+ fromCursor?: string | null;
453
534
  /**
454
535
  * Deliver events pre-decoded as the flat, `event_type`-discriminated rows
455
536
  * Index serves (`IndexEvent`), so Streams consumption reads identically
456
537
  * to Index consumption — no guard+decode pairs in your handler.
457
538
  */
458
- decoded?: D
539
+ decoded?: D;
459
540
  /**
460
541
  * Destination adapter that owns the checkpoint + rollback transaction
461
542
  * (e.g. `kyselySink` from `@secondlayer/sdk/sinks/kysely`). With a sink:
@@ -464,29 +545,29 @@ type StreamsEventsConsumeParams<
464
545
  * transaction), reorg rollback is automatic, and `onBatch`'s return value
465
546
  * is ignored.
466
547
  */
467
- sink?: ConsumerSink<TTx>
548
+ sink?: ConsumerSink<TTx>;
468
549
  /** Fires once per page, before `onBatch` and before any early return. */
469
- onProgress?: (ctx: ConsumerBatchContext) => void
470
- mode?: "tail" | "bounded"
550
+ onProgress?: (ctx: ConsumerBatchContext) => void;
551
+ mode?: "tail" | "bounded";
471
552
  /**
472
553
  * Emit only finalized (immutable) events and never surface reorgs. The SDK
473
554
  * checkpoints at the last finalized event and re-reads the unfinalized tail
474
555
  * until it settles. Trades finality lag for zero reorg handling; `onReorg` is
475
556
  * ignored.
476
557
  */
477
- finalizedOnly?: boolean
478
- types?: readonly StreamsEventType[]
479
- notTypes?: readonly StreamsEventType[]
480
- contractId?: StreamsFilterValue
481
- sender?: StreamsFilterValue
482
- recipient?: StreamsFilterValue
483
- assetIdentifier?: string
558
+ finalizedOnly?: boolean;
559
+ types?: readonly StreamsEventType[];
560
+ notTypes?: readonly StreamsEventType[];
561
+ contractId?: StreamsFilterValue;
562
+ sender?: StreamsFilterValue;
563
+ recipient?: StreamsFilterValue;
564
+ assetIdentifier?: string;
484
565
  /**
485
566
  * Labelled filter groups. The groups OR together in ONE server-side scan,
486
567
  * so two unrelated concerns share one page, one cursor, and one checkpoint
487
568
  * instead of two consume loops. Pair with `on` to handle each label.
488
569
  */
489
- filters?: F
570
+ filters?: F;
490
571
  /**
491
572
  * One handler per label in `filters`. Every label must be handled, so
492
573
  * adding a label is a compile error until its handler exists.
@@ -497,8 +578,8 @@ type StreamsEventsConsumeParams<
497
578
  * labels do not interleave within a page — add `onBatch` when you need
498
579
  * strict global order across labels.
499
580
  */
500
- on?: { [K in keyof F] : (events: StreamsEventForFilter<F[K], D>[], ctx: StreamsBatchContext & WithSinkTx<TTx>) => void | Promise<void> }
501
- batchSize?: number
581
+ on?: { [K in keyof F] : (events: StreamsEventForFilter<F[K], D>[], ctx: StreamsBatchContext & WithSinkTx<TTx>) => void | Promise<void> };
582
+ batchSize?: number;
502
583
  /**
503
584
  * Apply a page of canonical events. Persist `ctx.cursor` in the same
504
585
  * transaction as your writes. Returning a cursor overrides `ctx.cursor` as
@@ -507,7 +588,7 @@ type StreamsEventsConsumeParams<
507
588
  * Optional only when `on` handles the page instead; a consume call with
508
589
  * neither throws.
509
590
  */
510
- onBatch?: (events: D extends true ? IndexEvent[] : StreamsEvent[], envelope: StreamsEventsEnvelope, ctx: StreamsBatchContext & WithSinkTx<TTx>) => void | string | null | undefined | Promise<void> | Promise<string | null | undefined>
591
+ onBatch?: (events: D extends true ? IndexEvent[] : StreamsEvent[], envelope: StreamsEventsEnvelope, ctx: StreamsBatchContext & WithSinkTx<TTx>) => void | string | null | undefined | Promise<void> | Promise<string | null | undefined>;
511
592
  /**
512
593
  * Roll your projection back to `reorg.fork_point_height`, persisting
513
594
  * `ctx.cursor` in the same transaction. Called once per *new* reorg
@@ -515,127 +596,137 @@ type StreamsEventsConsumeParams<
515
596
  * now-canonical events. Omit it to ignore reorgs (events stay canonical, but
516
597
  * stale rows from an orphaned fork are left in place).
517
598
  */
518
- onReorg?: (reorg: StreamsReorg, ctx: StreamsReorgContext) => Promise<void> | void
599
+ onReorg?: (reorg: StreamsReorg, ctx: StreamsReorgContext) => Promise<void> | void;
519
600
  /** Page-fetch retries after the first failure (429/5xx/network only —
520
601
  * 4xx and handler throws always propagate). Default 3; `0` disables. */
521
- retryCount?: number
602
+ retryCount?: number;
522
603
  /** Base retry delay in ms; the n-th retry waits `retryDelay * n`. A server
523
604
  * `Retry-After` overrides it. Default 1000. */
524
- retryDelay?: number
605
+ retryDelay?: number;
525
606
  /** Void observer, called before each retry sleep (metrics/logging). */
526
607
  onError?: (err: unknown, ctx: {
527
- attempt: number
528
- retriesLeft: number
529
- delayMs: number
530
- }) => void
531
- emptyBackoffMs?: number
532
- maxPages?: number
533
- maxEmptyPolls?: number
534
- signal?: AbortSignal
608
+ attempt: number;
609
+ retriesLeft: number;
610
+ delayMs: number;
611
+ }) => void;
612
+ emptyBackoffMs?: number;
613
+ maxPages?: number;
614
+ maxEmptyPolls?: number;
615
+ signal?: AbortSignal;
535
616
  };
536
617
  /**
537
618
  * One yielded page from {@link StreamsClient.consume} — the
538
619
  * `GET /v1/streams/events` envelope verbatim, with `next_cursor` renamed to
539
620
  * `cursor` (the checkpoint to persist and resume from).
540
621
  */
541
- type StreamsBatch = {
622
+ type StreamsBatch<TEvent = StreamsEvent> = {
542
623
  /** Canonical events of this page, in cursor order. */
543
- events: StreamsEvent[]
624
+ events: TEvent[];
544
625
  /** Checkpoint after this page — pass back as `consume({ cursor })` to resume. */
545
- cursor: string | null
546
- tip: StreamsTip
626
+ cursor: string | null;
627
+ tip: StreamsTip;
547
628
  /** Chain reorgs reported alongside this page; empty when none. */
548
- reorgs: StreamsReorg[]
629
+ reorgs: StreamsReorg[];
549
630
  };
550
631
  type StreamsConsumeParams = {
551
632
  /** Resume strictly after this cursor; omit to start from the oldest seekable page. */
552
- cursor?: string | null
553
- types?: readonly StreamsEventType[]
554
- notTypes?: readonly StreamsEventType[]
555
- contractId?: StreamsFilterValue
556
- sender?: StreamsFilterValue
557
- recipient?: StreamsFilterValue
558
- assetIdentifier?: string
633
+ cursor?: string | null;
634
+ types?: readonly StreamsEventType[];
635
+ notTypes?: readonly StreamsEventType[];
636
+ contractId?: StreamsFilterValue;
637
+ sender?: StreamsFilterValue;
638
+ recipient?: StreamsFilterValue;
639
+ assetIdentifier?: string;
640
+ /** Labelled OR-groups — same semantics as `events.consume`; each returned
641
+ * event echoes the labels it matched. */
642
+ filters?: StreamsFilterMap;
559
643
  /** Events per page (the `limit` query param). Default 100. */
560
- batchSize?: number
644
+ batchSize?: number;
561
645
  /** Poll interval while caught up at the tip, in ms. Default 2000. */
562
- intervalMs?: number
646
+ intervalMs?: number;
563
647
  /** Abort to end the iteration. */
564
- signal?: AbortSignal
648
+ signal?: AbortSignal;
565
649
  };
566
650
  type StreamsEventsConsumeResult = {
567
- cursor: string | null
568
- pages: number
569
- emptyPolls: number
651
+ cursor: string | null;
652
+ pages: number;
653
+ emptyPolls: number;
570
654
  };
571
655
  type StreamsEventsReplayParams = {
572
656
  /** Start point: `"genesis"` (default) or a `<block>:<index>` cursor. */
573
- from?: "genesis" | string
657
+ from?: "genesis" | string;
574
658
  /**
575
659
  * Called once per finalized dump file, in block order, before live tailing.
576
660
  * Process the parquet with your own tooling (e.g. DuckDB) — the SDK does not
577
661
  * decode parquet. Use `client.dumps.download(file)` to fetch + verify bytes.
578
662
  */
579
- onDumpFile: (file: StreamsDumpFile) => Promise<void> | void
663
+ onDumpFile: (file: StreamsDumpFile) => Promise<void> | void;
580
664
  /** Called per live page after the dump phase, like `consume`. */
581
- onBatch: (events: StreamsEvent[], envelope: StreamsEventsEnvelope) => Promise<string | null | undefined> | string | null | undefined
665
+ onBatch: (events: StreamsEvent[], envelope: StreamsEventsEnvelope) => Promise<string | null | undefined> | string | null | undefined;
582
666
  /**
583
667
  * Called when the live-tail phase (after the dump backfill) crosses a reorg,
584
668
  * before the cursor rewinds and re-reads the now-canonical events — same
585
669
  * contract as `consume`. The dump-backfill phase is finalized and never
586
670
  * reorgs; omit this to leave stale rows from an orphaned fork in place.
587
671
  */
588
- onReorg?: (reorg: StreamsReorg, ctx: StreamsReorgContext) => Promise<void> | void
589
- mode?: "tail" | "bounded"
590
- batchSize?: number
591
- emptyBackoffMs?: number
592
- maxPages?: number
593
- maxEmptyPolls?: number
594
- signal?: AbortSignal
672
+ onReorg?: (reorg: StreamsReorg, ctx: StreamsReorgContext) => Promise<void> | void;
673
+ mode?: "tail" | "bounded";
674
+ batchSize?: number;
675
+ emptyBackoffMs?: number;
676
+ maxPages?: number;
677
+ maxEmptyPolls?: number;
678
+ signal?: AbortSignal;
679
+ /** Narrow the LIVE TAIL after the dump phase. The dump files themselves are
680
+ * always all-type (block-partitioned parquet) — filter those in your own
681
+ * tooling while processing each file. */
682
+ types?: readonly StreamsEventType[];
683
+ notTypes?: readonly StreamsEventType[];
684
+ /** Labelled OR-groups for the live tail, like `consume`. */
685
+ filters?: StreamsFilterMap;
595
686
  };
596
687
  type FetchLike2 = (input: string | URL | Request, init?: RequestInit) => Promise<Response>;
597
688
  /** One bulk parquet file in the dumps manifest. `path` is the object key under
598
689
  * the dumps base URL. */
599
690
  type StreamsDumpFile = {
600
- path: string
601
- from_block: number
602
- to_block: number
603
- min_cursor: string | null
604
- max_cursor: string | null
605
- row_count: number
606
- byte_size: number
607
- sha256: string
608
- schema_version: number
609
- created_at: string
691
+ path: string;
692
+ from_block: number;
693
+ to_block: number;
694
+ min_cursor: string | null;
695
+ max_cursor: string | null;
696
+ row_count: number;
697
+ byte_size: number;
698
+ sha256: string;
699
+ schema_version: number;
700
+ created_at: string;
610
701
  };
611
702
  type StreamsDumpsManifest = {
612
- dataset: string
613
- network: string
614
- version: string
615
- schema_version: number
616
- generated_at: string
617
- producer_version: string
618
- finality_lag_blocks: number
703
+ dataset: string;
704
+ network: string;
705
+ version: string;
706
+ schema_version: number;
707
+ generated_at: string;
708
+ producer_version: string;
709
+ finality_lag_blocks: number;
619
710
  /** Cursor at the end of the finalized bulk coverage — hand to live tailing. */
620
- latest_finalized_cursor: string | null
711
+ latest_finalized_cursor: string | null;
621
712
  coverage: {
622
- from_block: number
623
- to_block: number
624
- }
625
- files: StreamsDumpFile[]
713
+ from_block: number;
714
+ to_block: number;
715
+ };
716
+ files: StreamsDumpFile[];
626
717
  /** ed25519 signature over the manifest's canonical bytes. Absent on legacy
627
718
  * unsigned manifests. Verified by `list()` when `verifyDumpsManifest` is on. */
628
- signature?: string
719
+ signature?: string;
629
720
  /** Short id of the signing public key. */
630
- key_id?: string
721
+ key_id?: string;
631
722
  };
632
723
  type StreamsDumps = {
633
724
  /** Fetch and parse the latest dumps manifest. */
634
- list(): Promise<StreamsDumpsManifest>
725
+ list(): Promise<StreamsDumpsManifest>;
635
726
  /** Absolute URL for a manifest file. */
636
- fileUrl(file: StreamsDumpFile): string
727
+ fileUrl(file: StreamsDumpFile): string;
637
728
  /** Download a parquet file and verify its sha256 against the manifest. */
638
- download(file: StreamsDumpFile): Promise<Uint8Array>
729
+ download(file: StreamsDumpFile): Promise<Uint8Array>;
639
730
  };
640
731
  type StreamsClient = {
641
732
  /**
@@ -652,10 +743,19 @@ type StreamsClient = {
652
743
  * rewound automatically — use `events.consume` with `onReorg` for managed
653
744
  * rollback semantics.
654
745
  */
655
- consume(params?: StreamsConsumeParams): AsyncIterableIterator<StreamsBatch>
746
+ /** Narrowing overload: a literal `types` array narrows every batch's
747
+ * event union to exactly those members. */
748
+ consume<const T extends readonly StreamsEventType[]>(params: StreamsConsumeParams & {
749
+ types: T;
750
+ }): AsyncIterableIterator<StreamsBatch<StreamsEventOfTypes<T>>>;
751
+ consume(params?: StreamsConsumeParams): AsyncIterableIterator<StreamsBatch>;
656
752
  events: {
657
- list(params?: StreamsEventsListParams): Promise<StreamsEventsEnvelope>
658
- byTxId(txId: string): Promise<StreamsEventsListEnvelope>
753
+ /** Narrowing overload, matching `consume`. */
754
+ list<const T extends readonly StreamsEventType[]>(params: StreamsEventsListParams & {
755
+ types: T;
756
+ }): Promise<StreamsEventsEnvelope<StreamsEventOfTypes<T>>>;
757
+ list(params?: StreamsEventsListParams): Promise<StreamsEventsEnvelope>;
758
+ byTxId(txId: string): Promise<StreamsEventsListEnvelope>;
659
759
  /**
660
760
  * Pull pages from Streams and call `onBatch` after each page.
661
761
  *
@@ -670,8 +770,8 @@ type StreamsClient = {
670
770
  TTx = never,
671
771
  D extends boolean = false
672
772
  >(params: StreamsEventsConsumeParams<TTx, D, F> & {
673
- sink?: ConsumerSink<TTx>
674
- }): Promise<StreamsEventsConsumeResult>
773
+ sink?: ConsumerSink<TTx>;
774
+ }): Promise<StreamsEventsConsumeResult>;
675
775
  /**
676
776
  * Backfill from bulk dumps, then continue live from the dump→live seam in
677
777
  * one call. Iterates finalized dump files (via `onDumpFile`) in block
@@ -679,7 +779,7 @@ type StreamsClient = {
679
779
  * (exclusive input → no gap or duplicate at the seam). Requires
680
780
  * `dumpsBaseUrl`.
681
781
  */
682
- replay(params: StreamsEventsReplayParams): Promise<StreamsEventsConsumeResult>
782
+ replay(params: StreamsEventsReplayParams): Promise<StreamsEventsConsumeResult>;
683
783
  /**
684
784
  * Follow Streams as an async iterator.
685
785
  *
@@ -687,49 +787,53 @@ type StreamsClient = {
687
787
  * indefinitely by default and stops when its `AbortSignal`, `maxPages`, or
688
788
  * `maxEmptyPolls` stops it.
689
789
  */
690
- stream(params?: StreamsEventsStreamParams): AsyncIterable<StreamsEvent>
790
+ /** Narrowing overload, matching `consume`. */
791
+ stream<const T extends readonly StreamsEventType[]>(params: StreamsEventsStreamParams & {
792
+ types: T;
793
+ }): AsyncIterable<StreamsEventOfTypes<T>>;
794
+ stream(params?: StreamsEventsStreamParams): AsyncIterable<StreamsEvent>;
691
795
  /**
692
796
  * Subscribe to the real-time SSE push surface. Calls `onEvent` for each new
693
797
  * canonical event as the server pushes it (chain cadence, not poll-bounded),
694
798
  * and verifies each frame's inline ed25519 signature when the client was
695
799
  * created with `verify`. Returns an unsubscribe function.
696
800
  */
697
- subscribe(params: StreamsEventsSubscribeParams): () => void
698
- }
801
+ subscribe(params: StreamsEventsSubscribeParams): () => void;
802
+ };
699
803
  blocks: {
700
- events(heightOrHash: number | string): Promise<StreamsEventsListEnvelope>
701
- }
804
+ events(heightOrHash: number | string): Promise<StreamsEventsListEnvelope>;
805
+ };
702
806
  reorgs: {
703
- list(params: StreamsReorgsListParams): Promise<StreamsReorgsListEnvelope>
704
- }
807
+ list(params: StreamsReorgsListParams): Promise<StreamsReorgsListEnvelope>;
808
+ };
705
809
  /** Bulk parquet dumps. Requires `dumpsBaseUrl` on the client. */
706
- dumps: StreamsDumps
707
- canonical(height: number): Promise<StreamsCanonicalBlock>
708
- tip(): Promise<StreamsTip>
810
+ dumps: StreamsDumps;
811
+ canonical(height: number): Promise<StreamsCanonicalBlock>;
812
+ tip(): Promise<StreamsTip>;
709
813
  /** Your own Streams consumption (events today + this month) and tier limits. */
710
- usage(): Promise<StreamsUsage>
814
+ usage(): Promise<StreamsUsage>;
711
815
  };
712
816
  type StreamsUsage = {
713
- product: "streams"
714
- tier: string
817
+ product: "streams";
818
+ tier: string;
715
819
  limits: {
716
- rate_limit_per_second: number | null
717
- retention_days: number | null
718
- }
820
+ rate_limit_per_second: number | null;
821
+ retention_days: number | null;
822
+ };
719
823
  usage: {
720
- events_today: number
721
- events_this_month: number
722
- }
824
+ events_today: number;
825
+ events_this_month: number;
826
+ };
723
827
  };
724
828
  type CreateStreamsClientOptions = {
725
- apiKey: string
726
- baseUrl?: string
727
- fetchImpl?: FetchLike2
829
+ apiKey: string;
830
+ baseUrl?: string;
831
+ fetchImpl?: FetchLike2;
728
832
  /**
729
833
  * Public base URL for bulk parquet dumps (the R2/CDN bucket root). Required
730
834
  * to use `client.dumps`. See `GET /public/streams/dumps/manifest`.
731
835
  */
732
- dumpsBaseUrl?: string
836
+ dumpsBaseUrl?: string;
733
837
  /**
734
838
  * Verify the ed25519 `X-Signature` on every REST response and per-frame SSE
735
839
  * signature. Three states:
@@ -748,8 +852,8 @@ type CreateStreamsClientOptions = {
748
852
  * rotated `X-Signature-KeyId` triggers one refresh) unless a PEM is pinned.
749
853
  */
750
854
  verify?: boolean | {
751
- publicKey: string
752
- }
855
+ publicKey: string;
856
+ };
753
857
  /**
754
858
  * Verify the bulk dumps manifest's ed25519 signature in `client.dumps.list()`
755
859
  * before trusting any file sha256 (default ON). Uses the same key source as
@@ -757,7 +861,7 @@ type CreateStreamsClientOptions = {
757
861
  * `false` to opt out. A missing or invalid signature throws
758
862
  * `StreamsSignatureError`.
759
863
  */
760
- verifyDumpsManifest?: boolean
864
+ verifyDumpsManifest?: boolean;
761
865
  };
762
866
  declare function createStreamsClient(options: CreateStreamsClientOptions): StreamsClient;
763
867
  /**
@@ -820,14 +924,14 @@ declare class SecondLayerError extends Error {
820
924
  */
821
925
  walk(fn?: (err: unknown) => boolean): unknown;
822
926
  toJSON(): {
823
- name: string
824
- message: string
825
- shortMessage: string
826
- cause: string | undefined
827
- code: string | undefined
828
- docsUrl: string | undefined
829
- retryable: boolean
830
- retryAfterSeconds: number | undefined
927
+ name: string;
928
+ message: string;
929
+ shortMessage: string;
930
+ cause: string | undefined;
931
+ code: string | undefined;
932
+ docsUrl: string | undefined;
933
+ retryable: boolean;
934
+ retryAfterSeconds: number | undefined;
831
935
  };
832
936
  }
833
937
  /**
@@ -861,9 +965,9 @@ declare class AuthError extends ApiError {
861
965
  * with `retryAfterSeconds` parsed from the `Retry-After` header when sent. */
862
966
  declare class RateLimitError extends ApiError {
863
967
  /** Raw `Retry-After` header value (seconds or HTTP-date). */
864
- readonly retryAfter?: string;
968
+ readonly retryAfter?: string | undefined;
865
969
  readonly status: 429;
866
- constructor(message?: string, retryAfter?: string);
970
+ constructor(message?: string, retryAfter?: string | undefined);
867
971
  }
868
972
  /** Thrown on a 4xx the caller can fix (bad cursor, bad params). Never retried. */
869
973
  declare class ValidationError extends ApiError {
@@ -878,210 +982,210 @@ declare class StreamsSignatureError extends SecondLayerError {
878
982
  constructor(message?: string);
879
983
  }
880
984
  type FtTransferEvent = Extract<StreamsEvent, {
881
- event_type: "ft_transfer"
985
+ event_type: "ft_transfer";
882
986
  }>;
883
987
  type DecodedFtTransferPayload = {
884
- asset_identifier: string
885
- contract_id: string
886
- token_name: string | null
887
- sender: string
888
- recipient: string
889
- amount: string
988
+ asset_identifier: string;
989
+ contract_id: string;
990
+ token_name: string | null;
991
+ sender: string;
992
+ recipient: string;
993
+ amount: string;
890
994
  };
891
995
  type DecodedFtTransfer = {
892
- cursor: string
893
- block_height: number
894
- tx_id: string
895
- tx_index: number
896
- event_index: number
897
- event_type: "ft_transfer"
898
- decoded_payload: DecodedFtTransferPayload
899
- source_cursor: string
996
+ cursor: string;
997
+ block_height: number;
998
+ tx_id: string;
999
+ tx_index: number;
1000
+ event_index: number;
1001
+ event_type: "ft_transfer";
1002
+ decoded_payload: DecodedFtTransferPayload;
1003
+ source_cursor: string;
900
1004
  };
901
1005
  declare function isFtTransfer(event: StreamsEvent): event is FtTransferEvent;
902
1006
  declare function decodeFtTransfer(event: StreamsEvent): DecodedFtTransfer;
903
1007
  type NftTransferEvent = Extract<StreamsEvent, {
904
- event_type: "nft_transfer"
1008
+ event_type: "nft_transfer";
905
1009
  }>;
906
1010
  type DecodedNftTransferPayload = {
907
- asset_identifier: string
908
- contract_id: string
909
- token_name: string | null
910
- sender: string
911
- recipient: string
912
- value: string
1011
+ asset_identifier: string;
1012
+ contract_id: string;
1013
+ token_name: string | null;
1014
+ sender: string;
1015
+ recipient: string;
1016
+ value: string;
913
1017
  };
914
1018
  type DecodedNftTransfer = {
915
- cursor: string
916
- block_height: number
917
- tx_id: string
918
- tx_index: number
919
- event_index: number
920
- event_type: "nft_transfer"
921
- decoded_payload: DecodedNftTransferPayload
922
- source_cursor: string
1019
+ cursor: string;
1020
+ block_height: number;
1021
+ tx_id: string;
1022
+ tx_index: number;
1023
+ event_index: number;
1024
+ event_type: "nft_transfer";
1025
+ decoded_payload: DecodedNftTransferPayload;
1026
+ source_cursor: string;
923
1027
  };
924
1028
  declare function isNftTransfer(event: StreamsEvent): event is NftTransferEvent;
925
1029
  declare function decodeNftTransfer(event: StreamsEvent): DecodedNftTransfer;
926
1030
  type DecodedStxTransferPayload = {
927
- sender: string
928
- recipient: string
929
- amount: string
930
- memo: string | null
1031
+ sender: string;
1032
+ recipient: string;
1033
+ amount: string;
1034
+ memo: string | null;
931
1035
  };
932
1036
  type DecodedStxTransfer = {
933
- cursor: string
934
- block_height: number
935
- tx_id: string
936
- tx_index: number
937
- event_index: number
938
- event_type: "stx_transfer"
939
- decoded_payload: DecodedStxTransferPayload
940
- source_cursor: string
1037
+ cursor: string;
1038
+ block_height: number;
1039
+ tx_id: string;
1040
+ tx_index: number;
1041
+ event_index: number;
1042
+ event_type: "stx_transfer";
1043
+ decoded_payload: DecodedStxTransferPayload;
1044
+ source_cursor: string;
941
1045
  };
942
1046
  type DecodedStxMintPayload = {
943
- recipient: string
944
- amount: string
1047
+ recipient: string;
1048
+ amount: string;
945
1049
  };
946
1050
  type DecodedStxMint = {
947
- cursor: string
948
- block_height: number
949
- tx_id: string
950
- tx_index: number
951
- event_index: number
952
- event_type: "stx_mint"
953
- decoded_payload: DecodedStxMintPayload
954
- source_cursor: string
1051
+ cursor: string;
1052
+ block_height: number;
1053
+ tx_id: string;
1054
+ tx_index: number;
1055
+ event_index: number;
1056
+ event_type: "stx_mint";
1057
+ decoded_payload: DecodedStxMintPayload;
1058
+ source_cursor: string;
955
1059
  };
956
1060
  type DecodedStxBurnPayload = {
957
- sender: string
958
- amount: string
1061
+ sender: string;
1062
+ amount: string;
959
1063
  };
960
1064
  type DecodedStxBurn = {
961
- cursor: string
962
- block_height: number
963
- tx_id: string
964
- tx_index: number
965
- event_index: number
966
- event_type: "stx_burn"
967
- decoded_payload: DecodedStxBurnPayload
968
- source_cursor: string
1065
+ cursor: string;
1066
+ block_height: number;
1067
+ tx_id: string;
1068
+ tx_index: number;
1069
+ event_index: number;
1070
+ event_type: "stx_burn";
1071
+ decoded_payload: DecodedStxBurnPayload;
1072
+ source_cursor: string;
969
1073
  };
970
1074
  declare function isStxTransfer(event: StreamsEvent): event is StreamsEvent & {
971
- event_type: "stx_transfer"
1075
+ event_type: "stx_transfer";
972
1076
  };
973
1077
  declare function decodeStxTransfer(event: StreamsEvent): DecodedStxTransfer;
974
1078
  declare function isStxMint(event: StreamsEvent): event is StreamsEvent & {
975
- event_type: "stx_mint"
1079
+ event_type: "stx_mint";
976
1080
  };
977
1081
  declare function decodeStxMint(event: StreamsEvent): DecodedStxMint;
978
1082
  declare function isStxBurn(event: StreamsEvent): event is StreamsEvent & {
979
- event_type: "stx_burn"
1083
+ event_type: "stx_burn";
980
1084
  };
981
1085
  declare function decodeStxBurn(event: StreamsEvent): DecodedStxBurn;
982
1086
  type DecodedStxLockPayload = {
983
- sender: string
984
- amount: string
1087
+ sender: string;
1088
+ amount: string;
985
1089
  payload: {
986
- unlock_height: string | null
987
- }
1090
+ unlock_height: string | null;
1091
+ };
988
1092
  };
989
1093
  type DecodedStxLock = {
990
- cursor: string
991
- block_height: number
992
- tx_id: string
993
- tx_index: number
994
- event_index: number
995
- event_type: "stx_lock"
996
- decoded_payload: DecodedStxLockPayload
997
- source_cursor: string
1094
+ cursor: string;
1095
+ block_height: number;
1096
+ tx_id: string;
1097
+ tx_index: number;
1098
+ event_index: number;
1099
+ event_type: "stx_lock";
1100
+ decoded_payload: DecodedStxLockPayload;
1101
+ source_cursor: string;
998
1102
  };
999
1103
  declare function isStxLock(event: StreamsEvent): event is StreamsEvent & {
1000
- event_type: "stx_lock"
1104
+ event_type: "stx_lock";
1001
1105
  };
1002
1106
  declare function decodeStxLock(event: StreamsEvent): DecodedStxLock;
1003
1107
  type DecodedFtMintPayload = {
1004
- asset_identifier: string
1005
- contract_id: string
1006
- token_name: string | null
1007
- recipient: string
1008
- amount: string
1108
+ asset_identifier: string;
1109
+ contract_id: string;
1110
+ token_name: string | null;
1111
+ recipient: string;
1112
+ amount: string;
1009
1113
  };
1010
1114
  type DecodedFtMint = {
1011
- cursor: string
1012
- block_height: number
1013
- tx_id: string
1014
- tx_index: number
1015
- event_index: number
1016
- event_type: "ft_mint"
1017
- decoded_payload: DecodedFtMintPayload
1018
- source_cursor: string
1115
+ cursor: string;
1116
+ block_height: number;
1117
+ tx_id: string;
1118
+ tx_index: number;
1119
+ event_index: number;
1120
+ event_type: "ft_mint";
1121
+ decoded_payload: DecodedFtMintPayload;
1122
+ source_cursor: string;
1019
1123
  };
1020
1124
  type DecodedFtBurnPayload = {
1021
- asset_identifier: string
1022
- contract_id: string
1023
- token_name: string | null
1024
- sender: string
1025
- amount: string
1125
+ asset_identifier: string;
1126
+ contract_id: string;
1127
+ token_name: string | null;
1128
+ sender: string;
1129
+ amount: string;
1026
1130
  };
1027
1131
  type DecodedFtBurn = {
1028
- cursor: string
1029
- block_height: number
1030
- tx_id: string
1031
- tx_index: number
1032
- event_index: number
1033
- event_type: "ft_burn"
1034
- decoded_payload: DecodedFtBurnPayload
1035
- source_cursor: string
1132
+ cursor: string;
1133
+ block_height: number;
1134
+ tx_id: string;
1135
+ tx_index: number;
1136
+ event_index: number;
1137
+ event_type: "ft_burn";
1138
+ decoded_payload: DecodedFtBurnPayload;
1139
+ source_cursor: string;
1036
1140
  };
1037
1141
  type DecodedNftMintPayload = {
1038
- asset_identifier: string
1039
- contract_id: string
1040
- token_name: string | null
1041
- recipient: string
1042
- value: string
1142
+ asset_identifier: string;
1143
+ contract_id: string;
1144
+ token_name: string | null;
1145
+ recipient: string;
1146
+ value: string;
1043
1147
  };
1044
1148
  type DecodedNftMint = {
1045
- cursor: string
1046
- block_height: number
1047
- tx_id: string
1048
- tx_index: number
1049
- event_index: number
1050
- event_type: "nft_mint"
1051
- decoded_payload: DecodedNftMintPayload
1052
- source_cursor: string
1149
+ cursor: string;
1150
+ block_height: number;
1151
+ tx_id: string;
1152
+ tx_index: number;
1153
+ event_index: number;
1154
+ event_type: "nft_mint";
1155
+ decoded_payload: DecodedNftMintPayload;
1156
+ source_cursor: string;
1053
1157
  };
1054
1158
  type DecodedNftBurnPayload = {
1055
- asset_identifier: string
1056
- contract_id: string
1057
- token_name: string | null
1058
- sender: string
1059
- value: string
1159
+ asset_identifier: string;
1160
+ contract_id: string;
1161
+ token_name: string | null;
1162
+ sender: string;
1163
+ value: string;
1060
1164
  };
1061
1165
  type DecodedNftBurn = {
1062
- cursor: string
1063
- block_height: number
1064
- tx_id: string
1065
- tx_index: number
1066
- event_index: number
1067
- event_type: "nft_burn"
1068
- decoded_payload: DecodedNftBurnPayload
1069
- source_cursor: string
1166
+ cursor: string;
1167
+ block_height: number;
1168
+ tx_id: string;
1169
+ tx_index: number;
1170
+ event_index: number;
1171
+ event_type: "nft_burn";
1172
+ decoded_payload: DecodedNftBurnPayload;
1173
+ source_cursor: string;
1070
1174
  };
1071
1175
  declare function isFtMint(event: StreamsEvent): event is StreamsEvent & {
1072
- event_type: "ft_mint"
1176
+ event_type: "ft_mint";
1073
1177
  };
1074
1178
  declare function decodeFtMint(event: StreamsEvent): DecodedFtMint;
1075
1179
  declare function isFtBurn(event: StreamsEvent): event is StreamsEvent & {
1076
- event_type: "ft_burn"
1180
+ event_type: "ft_burn";
1077
1181
  };
1078
1182
  declare function decodeFtBurn(event: StreamsEvent): DecodedFtBurn;
1079
1183
  declare function isNftMint(event: StreamsEvent): event is StreamsEvent & {
1080
- event_type: "nft_mint"
1184
+ event_type: "nft_mint";
1081
1185
  };
1082
1186
  declare function decodeNftMint(event: StreamsEvent): DecodedNftMint;
1083
1187
  declare function isNftBurn(event: StreamsEvent): event is StreamsEvent & {
1084
- event_type: "nft_burn"
1188
+ event_type: "nft_burn";
1085
1189
  };
1086
1190
  declare function decodeNftBurn(event: StreamsEvent): DecodedNftBurn;
1087
1191
  /** Decoded form of a Clarity `print` event:
@@ -1090,41 +1194,41 @@ declare function decodeNftBurn(event: StreamsEvent): DecodedNftBurn;
1090
1194
  * `0x…` hex, tuples as objects)
1091
1195
  * - `raw_value`: the canonical serialized hex, for byte-exact consumers */
1092
1196
  type DecodedPrintValue = {
1093
- topic: string | null
1094
- value: unknown
1095
- raw_value: string | null
1197
+ topic: string | null;
1198
+ value: unknown;
1199
+ raw_value: string | null;
1096
1200
  };
1097
1201
  type DecodedPrintPayload = {
1098
- contract_id: string | null
1099
- payload: DecodedPrintValue
1202
+ contract_id: string | null;
1203
+ payload: DecodedPrintValue;
1100
1204
  };
1101
1205
  type DecodedPrint = {
1102
- cursor: string
1103
- block_height: number
1104
- tx_id: string
1105
- tx_index: number
1106
- event_index: number
1107
- event_type: "print"
1108
- decoded_payload: DecodedPrintPayload
1109
- source_cursor: string
1206
+ cursor: string;
1207
+ block_height: number;
1208
+ tx_id: string;
1209
+ tx_index: number;
1210
+ event_index: number;
1211
+ event_type: "print";
1212
+ decoded_payload: DecodedPrintPayload;
1213
+ source_cursor: string;
1110
1214
  };
1111
1215
  declare function isPrint(event: StreamsEvent): event is StreamsEvent & {
1112
- event_type: "print"
1216
+ event_type: "print";
1113
1217
  };
1114
1218
  declare function decodePrint(event: StreamsEvent): DecodedPrint;
1115
1219
  /** Superset of the columns the decoded_events table holds. Every decoded
1116
1220
  * event's `decoded_payload` is assignable to this, so the indexer's writer
1117
1221
  * can map columns generically instead of per-event-type. */
1118
1222
  type DecodedEventColumns = {
1119
- contract_id?: string | null
1120
- asset_identifier?: string | null
1121
- sender?: string | null
1122
- recipient?: string | null
1123
- amount?: string | null
1124
- value?: string | null
1125
- memo?: string | null
1223
+ contract_id?: string | null;
1224
+ asset_identifier?: string | null;
1225
+ sender?: string | null;
1226
+ recipient?: string | null;
1227
+ amount?: string | null;
1228
+ value?: string | null;
1229
+ memo?: string | null;
1126
1230
  /** JSONB overflow for non-flat types (e.g. print's decoded value). */
1127
- payload?: unknown
1231
+ payload?: unknown;
1128
1232
  };
1129
1233
  /**
1130
1234
  * Helpers for Streams cursors. A cursor is the opaque `<block>:<index>` string
@@ -1149,12 +1253,12 @@ declare const Cursor: {
1149
1253
  * type), larger than any real index, so nothing at `height - 1` survives the
1150
1254
  * keyset and the next returned row is exactly `(height, 0)`.
1151
1255
  */
1152
- atHeight(height: number): string
1256
+ atHeight(height: number): string;
1153
1257
  /** Parse a `<block>:<index>` cursor. Throws `ValidationError` if malformed. */
1154
1258
  parse(cursor: string): {
1155
- blockHeight: number
1156
- eventIndex: number
1157
- }
1259
+ blockHeight: number;
1260
+ eventIndex: number;
1261
+ };
1158
1262
  };
1159
1263
  type DecodedEventRow = DecodedFtTransfer | DecodedNftTransfer | DecodedStxTransfer | DecodedStxMint | DecodedStxBurn | DecodedStxLock | DecodedFtMint | DecodedFtBurn | DecodedNftMint | DecodedNftBurn | DecodedPrint;
1160
1264
  export { isStxTransfer, isStxMint, isStxLock, isStxBurn, isPrint, isNftTransfer, isNftMint, isNftBurn, isFtTransfer, isFtMint, isFtBurn, decodeStxTransfer, decodeStxMint, decodeStxLock, decodeStxBurn, decodePrint, decodeNftTransfer, decodeNftMint, decodeNftBurn, decodeFtTransfer, decodeFtMint, decodeFtBurn, decode, createStreamsClient, ValidationError, StreamsUsage, StreamsTip, StreamsSignatureError, StreamsServerError, StreamsReorgsListParams, StreamsReorgsListEnvelope, StreamsReorgContext, StreamsReorg, StreamsEventsSubscribeParams, StreamsEventsStreamParams, StreamsEventsListParams, StreamsEventsListEnvelope, StreamsEventsEnvelope, StreamsEventsConsumeResult, StreamsEventsConsumeParams, StreamsEventType, StreamsEventPayload, StreamsEvent, StreamsDumpsManifest, StreamsDumps, StreamsDumpFile, StreamsConsumeParams, StreamsClient, StreamsCanonicalBlock, StreamsBatchContext, StreamsBatch, STREAMS_EVENT_TYPES, RateLimitError, NftTransferPayload, NftTransferEvent, FtTransferPayload, FtTransferEvent, FetchLike2 as FetchLike, DecodedStxTransferPayload, DecodedStxTransfer, DecodedStxMintPayload, DecodedStxMint, DecodedStxLockPayload, DecodedStxLock, DecodedStxBurnPayload, DecodedStxBurn, DecodedPrintValue, DecodedPrintPayload, DecodedPrint, DecodedNftTransferPayload, DecodedNftTransfer, DecodedNftMintPayload, DecodedNftMint, DecodedNftBurnPayload, DecodedNftBurn, DecodedFtTransferPayload, DecodedFtTransfer, DecodedFtMintPayload, DecodedFtMint, DecodedFtBurnPayload, DecodedFtBurn, DecodedEventRow, DecodedEventColumns, Cursor, ConsumerBatchContext, AuthError };