@valve-tech/tx-tracker 0.6.0 → 0.7.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.
@@ -0,0 +1,165 @@
1
+ /**
2
+ * `createTxTracker` — the per-tx state machine that turns a
3
+ * `ChainSource`'s block + mempool stream into a stream of neutral
4
+ * observations per tracked hash.
5
+ *
6
+ * Per `docs/tx-tracker-spec.md` §5.2 + §6 + §11 + §12. This file is
7
+ * the load-bearing piece of `@valve-tech/tx-tracker`; everything
8
+ * else is supporting infrastructure (events, store, reorg detector,
9
+ * selectors).
10
+ *
11
+ * Design rules carried in from the spec and the contributing skill:
12
+ *
13
+ * - **Three consumption shapes, one underlying stream** (§5.3).
14
+ * `getTxStatus(hash)` reads the cached snapshot; `subscribe(hash, cb)`
15
+ * attaches a callback; `track(hash)` returns an async iterator.
16
+ * All three see consistent state because they read from one
17
+ * internal `Subscriptions<TxEvent>` per hash.
18
+ *
19
+ * - **Neutral observations only** (§2.1). The tracker emits
20
+ * `seen-in-mempool` / `seen-in-block` / `vanished-from-block` /
21
+ * `replaced-by` / `unseen-for-N-blocks` and lets the consumer
22
+ * write the policy that says "confirmed" or "stuck" in their
23
+ * UX voice.
24
+ *
25
+ * - **No silent downgrade** (§2.2). Every emitted event carries a
26
+ * `source` discriminator. When the source's `capabilities()`
27
+ * change between ticks, the tracker emits `signal-degraded` /
28
+ * `signal-recovered` per affected capability.
29
+ *
30
+ * - **No own poll cycle** (§3.1, contributing-skill rule 3). The
31
+ * tracker hangs off `source.subscribeBlocks` and
32
+ * `source.subscribeMempool`; every per-tick computation runs
33
+ * inside those callbacks.
34
+ *
35
+ * - **Browser/mobile safe** (§2.4). No Node-only deps; the
36
+ * pub/sub primitive is `chain-source`'s `Subscriptions<E>`.
37
+ */
38
+ import type { ChainSource, Capabilities, RawTx } from '@valve-tech/chain-source';
39
+ import { type Address, type At, type Hash, type TxEvent, type TxStatus } from './events.js';
40
+ import { type BulkSelector, type TxTrackerStore } from './store.js';
41
+ /**
42
+ * Lost-signal policy (spec §8). `'emit-uncertain'` is the default
43
+ * — every transition to a degraded source emits `signal-degraded`.
44
+ * `'silent'` keeps the events to itself; `'receipt-poll-fallback'`
45
+ * is reserved for relay/settlement consumers and is not yet
46
+ * implemented (the type is accepted but the runtime falls back to
47
+ * `'emit-uncertain'`; a follow-up PR adds the per-block receipt
48
+ * fetch path).
49
+ */
50
+ export type LostSignalPolicy = 'emit-uncertain' | 'silent' | {
51
+ strategy: 'receipt-poll-fallback';
52
+ pollEveryBlocks: number;
53
+ };
54
+ /**
55
+ * Per-subscription overrides on top of the tracker defaults. See
56
+ * spec §5.4.
57
+ */
58
+ export interface TrackOptions {
59
+ /**
60
+ * Emit a synthetic `started` event on subscribe even if no real
61
+ * observation has fired yet. Default true. Wallets use this to
62
+ * render an "awaiting first observation" state without polling.
63
+ */
64
+ emitInitial?: boolean;
65
+ /**
66
+ * Persist this subscription via the store. Default false — the
67
+ * subscription survives only the current process. Indexer / relay
68
+ * consumers set this true.
69
+ */
70
+ durable?: boolean;
71
+ /** Per-subscription override of the tracker's `lostSignalPolicy`. */
72
+ lostSignalPolicy?: LostSignalPolicy;
73
+ /**
74
+ * How many consecutive blocks the hash must be unseen (not in
75
+ * mempool, not in the canonical block) before
76
+ * `unseen-for-N-blocks` fires. Default 30 (spec §6.1).
77
+ */
78
+ unseenThresholdBlocks?: number;
79
+ }
80
+ /** Bulk subscription options — extends per-hash `TrackOptions`. */
81
+ export interface BulkTrackOptions extends TrackOptions {
82
+ /**
83
+ * Auto-track every tx the selector matches by starting an
84
+ * implicit per-hash subscription for it. Default true — an
85
+ * indexer wiring `trackFromAddress(treasury)` typically wants
86
+ * the per-hash event stream too. Set false to receive only the
87
+ * raw `matched` stream without per-hash detail.
88
+ */
89
+ autoTrackMatched?: boolean;
90
+ }
91
+ /** One emit from a bulk subscription — see spec §11.1. */
92
+ export interface TxMatchEvent {
93
+ kind: 'matched';
94
+ hash: Hash;
95
+ matchedBy: 'from' | 'to' | 'predicate';
96
+ selector: BulkSelector;
97
+ tx: RawTx;
98
+ source: 'mempool-snapshot' | 'block-poll';
99
+ at: At;
100
+ }
101
+ /** Handle returned by every bulk-track method. */
102
+ export interface TxSubscription {
103
+ /**
104
+ * Async iterator over the raw `matched` stream. Iteration ends
105
+ * when `stop()` is called or the tracker stops.
106
+ */
107
+ events(): AsyncIterable<TxMatchEvent>;
108
+ /**
109
+ * Imperative subscription to per-hash events on every matched tx.
110
+ * Returns an unsubscribe handle.
111
+ */
112
+ subscribe(cb: (event: TxEvent) => void): () => void;
113
+ /**
114
+ * Stop the bulk subscription. Per-hash subscriptions auto-tracked
115
+ * via this bulk subscription continue under their own retention
116
+ * rules (spec §11.1).
117
+ */
118
+ stop(): void;
119
+ }
120
+ /** Factory options. */
121
+ export interface CreateTxTrackerOptions {
122
+ source: ChainSource;
123
+ chainId: number;
124
+ store?: TxTrackerStore;
125
+ lostSignalPolicy?: LostSignalPolicy;
126
+ reorgDepthBlocks?: number;
127
+ /** Default `unseenThresholdBlocks` for new subscriptions. */
128
+ unseenThresholdBlocks?: number;
129
+ /** Cap on simultaneous bulk subscriptions (spec §11.3). */
130
+ maxBulkSubscriptions?: number;
131
+ onError?: (method: string, err: unknown) => void;
132
+ lifecycle?: 'eager' | 'lazy';
133
+ }
134
+ /** Public surface returned by `createTxTracker`. */
135
+ export interface TxTracker {
136
+ start(): void;
137
+ stop(): void;
138
+ getTxStatus(hash: Hash): TxStatus | null;
139
+ track(hash: Hash, options?: TrackOptions): AsyncIterable<TxEvent>;
140
+ subscribe(hash: Hash, cb: (event: TxEvent) => void, options?: TrackOptions): () => void;
141
+ trackFromAddress(address: Address, options?: BulkTrackOptions): TxSubscription;
142
+ trackToAddress(address: Address, options?: BulkTrackOptions): TxSubscription;
143
+ trackPredicate(match: (tx: RawTx) => boolean, options?: BulkTrackOptions): TxSubscription;
144
+ capabilities(): Capabilities;
145
+ subscribeAll(cb: (event: TxEvent) => void): () => void;
146
+ }
147
+ /**
148
+ * Build a configured tracker.
149
+ *
150
+ * @example
151
+ * import { createChainSource } from '@valve-tech/chain-source'
152
+ * import { createTxTracker } from '@valve-tech/tx-tracker'
153
+ *
154
+ * const source = createChainSource({ client })
155
+ * const tracker = createTxTracker({ source, chainId: 1 })
156
+ *
157
+ * source.start()
158
+ * tracker.start()
159
+ *
160
+ * for await (const event of tracker.track('0xabc...')) {
161
+ * if (event.kind === 'seen-in-block' && event.confirmations >= 3) break
162
+ * }
163
+ */
164
+ export declare const createTxTracker: (options: CreateTxTrackerOptions) => TxTracker;
165
+ //# sourceMappingURL=tracker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tracker.d.ts","sourceRoot":"","sources":["../src/tracker.ts"],"names":[],"mappings":"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"}