@valve-tech/tx-flight-react 0.0.1
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.
- package/CHANGELOG.md +17 -0
- package/LICENSE +21 -0
- package/README.md +283 -0
- package/dist/components/actions.d.ts +32 -0
- package/dist/components/actions.d.ts.map +1 -0
- package/dist/components/actions.js +10 -0
- package/dist/components/actions.js.map +1 -0
- package/dist/components/age.d.ts +21 -0
- package/dist/components/age.d.ts.map +1 -0
- package/dist/components/age.js +29 -0
- package/dist/components/age.js.map +1 -0
- package/dist/components/hash-link.d.ts +26 -0
- package/dist/components/hash-link.d.ts.map +1 -0
- package/dist/components/hash-link.js +20 -0
- package/dist/components/hash-link.js.map +1 -0
- package/dist/components/item.d.ts +27 -0
- package/dist/components/item.d.ts.map +1 -0
- package/dist/components/item.js +18 -0
- package/dist/components/item.js.map +1 -0
- package/dist/components/list.d.ts +27 -0
- package/dist/components/list.d.ts.map +1 -0
- package/dist/components/list.js +14 -0
- package/dist/components/list.js.map +1 -0
- package/dist/components/status-icon.d.ts +20 -0
- package/dist/components/status-icon.d.ts.map +1 -0
- package/dist/components/status-icon.js +28 -0
- package/dist/components/status-icon.js.map +1 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +19 -0
- package/dist/index.js.map +1 -0
- package/dist/integrations/tx-tracker.d.ts +48 -0
- package/dist/integrations/tx-tracker.d.ts.map +1 -0
- package/dist/integrations/tx-tracker.js +169 -0
- package/dist/integrations/tx-tracker.js.map +1 -0
- package/dist/integrations/wallet-adapter.d.ts +34 -0
- package/dist/integrations/wallet-adapter.d.ts.map +1 -0
- package/dist/integrations/wallet-adapter.js +97 -0
- package/dist/integrations/wallet-adapter.js.map +1 -0
- package/dist/provider.d.ts +67 -0
- package/dist/provider.d.ts.map +1 -0
- package/dist/provider.js +182 -0
- package/dist/provider.js.map +1 -0
- package/dist/storage/index.d.ts +7 -0
- package/dist/storage/index.d.ts.map +1 -0
- package/dist/storage/index.js +7 -0
- package/dist/storage/index.js.map +1 -0
- package/dist/storage/indexed-db.d.ts +21 -0
- package/dist/storage/indexed-db.d.ts.map +1 -0
- package/dist/storage/indexed-db.js +58 -0
- package/dist/storage/indexed-db.js.map +1 -0
- package/dist/storage/local-storage.d.ts +18 -0
- package/dist/storage/local-storage.d.ts.map +1 -0
- package/dist/storage/local-storage.js +39 -0
- package/dist/storage/local-storage.js.map +1 -0
- package/dist/storage/memory.d.ts +7 -0
- package/dist/storage/memory.d.ts.map +1 -0
- package/dist/storage/memory.js +17 -0
- package/dist/storage/memory.js.map +1 -0
- package/dist/storage/serialize.d.ts +13 -0
- package/dist/storage/serialize.d.ts.map +1 -0
- package/dist/storage/serialize.js +29 -0
- package/dist/storage/serialize.js.map +1 -0
- package/dist/store/reducers.d.ts +53 -0
- package/dist/store/reducers.d.ts.map +1 -0
- package/dist/store/reducers.js +135 -0
- package/dist/store/reducers.js.map +1 -0
- package/dist/store/store.d.ts +56 -0
- package/dist/store/store.d.ts.map +1 -0
- package/dist/store/store.js +93 -0
- package/dist/store/store.js.map +1 -0
- package/dist/types.d.ts +96 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +21 -0
- package/dist/types.js.map +1 -0
- package/dist/use-tx-flight.d.ts +31 -0
- package/dist/use-tx-flight.d.ts.map +1 -0
- package/dist/use-tx-flight.js +47 -0
- package/dist/use-tx-flight.js.map +1 -0
- package/package.json +83 -0
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
const STATUS_LABEL = {
|
|
3
|
+
preparing: 'Preparing',
|
|
4
|
+
'awaiting-signature': 'Awaiting signature',
|
|
5
|
+
pending: 'Pending',
|
|
6
|
+
confirmed: 'Confirmed',
|
|
7
|
+
failed: 'Failed',
|
|
8
|
+
replaced: 'Replaced',
|
|
9
|
+
dropped: 'Dropped',
|
|
10
|
+
};
|
|
11
|
+
const STATUS_COLOR = {
|
|
12
|
+
preparing: '#9ca3af',
|
|
13
|
+
'awaiting-signature': '#3b82f6',
|
|
14
|
+
pending: '#f59e0b',
|
|
15
|
+
confirmed: '#10b981',
|
|
16
|
+
failed: '#ef4444',
|
|
17
|
+
replaced: '#a855f7',
|
|
18
|
+
dropped: '#6b7280',
|
|
19
|
+
};
|
|
20
|
+
export const TxFlightStatusIcon = ({ status, size = 16, className, style, }) => (_jsx("span", { role: "img", "aria-label": STATUS_LABEL[status], "data-status": status, className: className, style: {
|
|
21
|
+
display: 'inline-block',
|
|
22
|
+
width: size,
|
|
23
|
+
height: size,
|
|
24
|
+
borderRadius: '50%',
|
|
25
|
+
backgroundColor: STATUS_COLOR[status],
|
|
26
|
+
...style,
|
|
27
|
+
} }));
|
|
28
|
+
//# sourceMappingURL=status-icon.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status-icon.js","sourceRoot":"","sources":["../../src/components/status-icon.tsx"],"names":[],"mappings":";AAcA,MAAM,YAAY,GAAoC;IACpD,SAAS,EAAE,WAAW;IACtB,oBAAoB,EAAE,oBAAoB;IAC1C,OAAO,EAAE,SAAS;IAClB,SAAS,EAAE,WAAW;IACtB,MAAM,EAAE,QAAQ;IAChB,QAAQ,EAAE,UAAU;IACpB,OAAO,EAAE,SAAS;CACnB,CAAA;AAED,MAAM,YAAY,GAAoC;IACpD,SAAS,EAAE,SAAS;IACpB,oBAAoB,EAAE,SAAS;IAC/B,OAAO,EAAE,SAAS;IAClB,SAAS,EAAE,SAAS;IACpB,MAAM,EAAE,SAAS;IACjB,QAAQ,EAAE,SAAS;IACnB,OAAO,EAAE,SAAS;CACnB,CAAA;AAUD,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,EACjC,MAAM,EACN,IAAI,GAAG,EAAE,EACT,SAAS,EACT,KAAK,GACmB,EAAa,EAAE,CAAC,CACxC,eACE,IAAI,EAAC,KAAK,gBACE,YAAY,CAAC,MAAM,CAAC,iBACnB,MAAM,EACnB,SAAS,EAAE,SAAS,EACpB,KAAK,EAAE;QACL,OAAO,EAAE,cAAc;QACvB,KAAK,EAAE,IAAI;QACX,MAAM,EAAE,IAAI;QACZ,YAAY,EAAE,KAAK;QACnB,eAAe,EAAE,YAAY,CAAC,MAAM,CAAC;QACrC,GAAG,KAAK;KACT,GACD,CACH,CAAA"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Public API of `@valve-tech/tx-flight-react`.
|
|
3
|
+
*
|
|
4
|
+
* Public surface lands progressively across tasks 2-12 of
|
|
5
|
+
* `docs/superpowers/plans/2026-05-07-tx-flight-react.md`. This file
|
|
6
|
+
* is the single entrypoint; storage adapters live at the
|
|
7
|
+
* `./storage` sub-export.
|
|
8
|
+
*/
|
|
9
|
+
export type { AddWithWalletAdapterInput, AddByHashInput, AddManualInput, TxFlightStorage, TrackedTx, TxFlow, } from './types.js';
|
|
10
|
+
export { TxFlightProvider, type TxFlightProviderProps, } from './provider.js';
|
|
11
|
+
export { useTxFlight, type UseTxFlightReturn } from './use-tx-flight.js';
|
|
12
|
+
export { TxFlightStatusIcon, type TxFlightStatusIconProps, } from './components/status-icon.js';
|
|
13
|
+
export { TxFlightHashLink, type TxFlightHashLinkProps, type HashTruncate, } from './components/hash-link.js';
|
|
14
|
+
export { TxFlightAge, type TxFlightAgeProps } from './components/age.js';
|
|
15
|
+
export { TxFlightActions, type TxFlightActionsProps, type TxFlightActionsShow, } from './components/actions.js';
|
|
16
|
+
export { TxFlightItem, type TxFlightItemProps, type TxFlightItemRenderParts, } from './components/item.js';
|
|
17
|
+
export { TxFlightList, type TxFlightListProps } from './components/list.js';
|
|
18
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,YAAY,EACV,yBAAyB,EACzB,cAAc,EACd,cAAc,EACd,eAAe,EACf,SAAS,EACT,MAAM,GACP,MAAM,YAAY,CAAA;AAInB,OAAO,EACL,gBAAgB,EAChB,KAAK,qBAAqB,GAC3B,MAAM,eAAe,CAAA;AAEtB,OAAO,EAAE,WAAW,EAAE,KAAK,iBAAiB,EAAE,MAAM,oBAAoB,CAAA;AAIxE,OAAO,EACL,kBAAkB,EAClB,KAAK,uBAAuB,GAC7B,MAAM,6BAA6B,CAAA;AACpC,OAAO,EACL,gBAAgB,EAChB,KAAK,qBAAqB,EAC1B,KAAK,YAAY,GAClB,MAAM,2BAA2B,CAAA;AAClC,OAAO,EAAE,WAAW,EAAE,KAAK,gBAAgB,EAAE,MAAM,qBAAqB,CAAA;AACxE,OAAO,EACL,eAAe,EACf,KAAK,oBAAoB,EACzB,KAAK,mBAAmB,GACzB,MAAM,yBAAyB,CAAA;AAChC,OAAO,EACL,YAAY,EACZ,KAAK,iBAAiB,EACtB,KAAK,uBAAuB,GAC7B,MAAM,sBAAsB,CAAA;AAC7B,OAAO,EAAE,YAAY,EAAE,KAAK,iBAAiB,EAAE,MAAM,sBAAsB,CAAA"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Public API of `@valve-tech/tx-flight-react`.
|
|
3
|
+
*
|
|
4
|
+
* Public surface lands progressively across tasks 2-12 of
|
|
5
|
+
* `docs/superpowers/plans/2026-05-07-tx-flight-react.md`. This file
|
|
6
|
+
* is the single entrypoint; storage adapters live at the
|
|
7
|
+
* `./storage` sub-export.
|
|
8
|
+
*/
|
|
9
|
+
// ─── Provider + hook ───────────────────────────────────────────────────────
|
|
10
|
+
export { TxFlightProvider, } from './provider.js';
|
|
11
|
+
export { useTxFlight } from './use-tx-flight.js';
|
|
12
|
+
// ─── Components ────────────────────────────────────────────────────────────
|
|
13
|
+
export { TxFlightStatusIcon, } from './components/status-icon.js';
|
|
14
|
+
export { TxFlightHashLink, } from './components/hash-link.js';
|
|
15
|
+
export { TxFlightAge } from './components/age.js';
|
|
16
|
+
export { TxFlightActions, } from './components/actions.js';
|
|
17
|
+
export { TxFlightItem, } from './components/item.js';
|
|
18
|
+
export { TxFlightList } from './components/list.js';
|
|
19
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAaH,8EAA8E;AAE9E,OAAO,EACL,gBAAgB,GAEjB,MAAM,eAAe,CAAA;AAEtB,OAAO,EAAE,WAAW,EAA0B,MAAM,oBAAoB,CAAA;AAExE,8EAA8E;AAE9E,OAAO,EACL,kBAAkB,GAEnB,MAAM,6BAA6B,CAAA;AACpC,OAAO,EACL,gBAAgB,GAGjB,MAAM,2BAA2B,CAAA;AAClC,OAAO,EAAE,WAAW,EAAyB,MAAM,qBAAqB,CAAA;AACxE,OAAO,EACL,eAAe,GAGhB,MAAM,yBAAyB,CAAA;AAChC,OAAO,EACL,YAAY,GAGb,MAAM,sBAAsB,CAAA;AAC7B,OAAO,EAAE,YAAY,EAA0B,MAAM,sBAAsB,CAAA"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview tx-tracker integration for `addByHash`.
|
|
3
|
+
*
|
|
4
|
+
* Dynamic-imports `@valve-tech/tx-tracker` and `@valve-tech/chain-source`
|
|
5
|
+
* inside the call so wallet-adapter-only consumers don't pay the
|
|
6
|
+
* bundle cost. This is what makes `addByHash` async (the only async
|
|
7
|
+
* method on the hook).
|
|
8
|
+
*
|
|
9
|
+
* Internally builds a private `ChainSource` + `TxTracker` pair (same
|
|
10
|
+
* pattern as `watchTransaction` in tx-tracker), subscribes to the
|
|
11
|
+
* hash, and routes every relevant event into a `store.dispatch.update`
|
|
12
|
+
* patch. The watcher-unsub is registered with the tx so `remove(id)`
|
|
13
|
+
* (and Provider unmount via `dispatch.clear`) cleans up the
|
|
14
|
+
* subscription.
|
|
15
|
+
*
|
|
16
|
+
* Tests inject a stub `ChainSource` via `_sourceOverride`; this
|
|
17
|
+
* mirrors the seam used by `watchTransaction` and keeps test runs
|
|
18
|
+
* hermetic (no real RPC, no live timers).
|
|
19
|
+
*/
|
|
20
|
+
import type { ChainSource } from '@valve-tech/chain-source';
|
|
21
|
+
import type { TrackedTx } from '@valve-tech/wallet-adapter';
|
|
22
|
+
import type { PublicClient } from 'viem';
|
|
23
|
+
import type { AddByHashInput } from '../types.js';
|
|
24
|
+
import type { TxFlightStore } from '../store/store.js';
|
|
25
|
+
/**
|
|
26
|
+
* Internal options — not part of the public API.
|
|
27
|
+
*
|
|
28
|
+
* `_sourceOverride` is a test-only seam (mirrors the pattern in
|
|
29
|
+
* `watchTransaction`'s `WatchTransactionInternalOptions`). Production
|
|
30
|
+
* callers never use it.
|
|
31
|
+
*
|
|
32
|
+
* @internal
|
|
33
|
+
*/
|
|
34
|
+
export interface AddByHashInternalOptions {
|
|
35
|
+
_sourceOverride?: ChainSource;
|
|
36
|
+
}
|
|
37
|
+
export declare const addByHashImpl: (store: TxFlightStore, input: AddByHashInput, onError?: (method: string, err: unknown) => void, internal?: AddByHashInternalOptions) => Promise<string>;
|
|
38
|
+
/**
|
|
39
|
+
* Resume watching an already-persisted TrackedTx. Used by Provider on
|
|
40
|
+
* rehydrate to re-attach a tx-tracker subscription to a `pending` tx
|
|
41
|
+
* we loaded from storage. Overwrites the existing entry with itself
|
|
42
|
+
* plus the new watcher.
|
|
43
|
+
*
|
|
44
|
+
* No-op if `tx.hash` is missing — those entries were caught earlier
|
|
45
|
+
* in the rehydrate path and translated to `failed`.
|
|
46
|
+
*/
|
|
47
|
+
export declare const resumeByHashWatcher: (store: TxFlightStore, tx: TrackedTx, client: PublicClient, onError?: (method: string, err: unknown) => void, internal?: AddByHashInternalOptions) => Promise<void>;
|
|
48
|
+
//# sourceMappingURL=tx-tracker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tx-tracker.d.ts","sourceRoot":"","sources":["../../src/integrations/tx-tracker.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAA;AAE3D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAA;AAC3D,OAAO,KAAK,EAAO,YAAY,EAAE,MAAM,MAAM,CAAA;AAE7C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AACjD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AAmDtD;;;;;;;;GAQG;AACH,MAAM,WAAW,wBAAwB;IACvC,eAAe,CAAC,EAAE,WAAW,CAAA;CAC9B;AA6DD,eAAO,MAAM,aAAa,UACjB,aAAa,SACb,cAAc,YACX,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,KAAK,IAAI,aACrC,wBAAwB,KAClC,OAAO,CAAC,MAAM,CA2BhB,CAAA;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,mBAAmB,UACvB,aAAa,MAChB,SAAS,UACL,YAAY,YACV,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,KAAK,IAAI,aACrC,wBAAwB,KAClC,OAAO,CAAC,IAAI,CA8Bd,CAAA"}
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview tx-tracker integration for `addByHash`.
|
|
3
|
+
*
|
|
4
|
+
* Dynamic-imports `@valve-tech/tx-tracker` and `@valve-tech/chain-source`
|
|
5
|
+
* inside the call so wallet-adapter-only consumers don't pay the
|
|
6
|
+
* bundle cost. This is what makes `addByHash` async (the only async
|
|
7
|
+
* method on the hook).
|
|
8
|
+
*
|
|
9
|
+
* Internally builds a private `ChainSource` + `TxTracker` pair (same
|
|
10
|
+
* pattern as `watchTransaction` in tx-tracker), subscribes to the
|
|
11
|
+
* hash, and routes every relevant event into a `store.dispatch.update`
|
|
12
|
+
* patch. The watcher-unsub is registered with the tx so `remove(id)`
|
|
13
|
+
* (and Provider unmount via `dispatch.clear`) cleans up the
|
|
14
|
+
* subscription.
|
|
15
|
+
*
|
|
16
|
+
* Tests inject a stub `ChainSource` via `_sourceOverride`; this
|
|
17
|
+
* mirrors the seam used by `watchTransaction` and keeps test runs
|
|
18
|
+
* hermetic (no real RPC, no live timers).
|
|
19
|
+
*/
|
|
20
|
+
const DEFAULT_CONFIRMATIONS = 1;
|
|
21
|
+
const DEFAULT_STALE_AFTER_BLOCKS = 12;
|
|
22
|
+
const DEFAULT_FLOW = 'unknown';
|
|
23
|
+
let txIdCounter = 0;
|
|
24
|
+
const generateTxId = () => `txflight-${Date.now()}-${++txIdCounter}`;
|
|
25
|
+
/**
|
|
26
|
+
* Translate a tx-tracker event into a TrackedTx patch (or `null` to
|
|
27
|
+
* skip). The translation is conservative: events that don't change
|
|
28
|
+
* lifecycle state (`started`, `stopped`, signal-*, `left-mempool`)
|
|
29
|
+
* return null.
|
|
30
|
+
*
|
|
31
|
+
* Confirmations gate: a `seen-in-block` event only flips to
|
|
32
|
+
* `confirmed` when `event.confirmations >= input.confirmations`. With
|
|
33
|
+
* receipts, a reverted receipt flips to `failed` instead.
|
|
34
|
+
*
|
|
35
|
+
* `staleAfterBlocks` is enforced by the tracker via the
|
|
36
|
+
* `unseenThresholdBlocks` option; this function trusts the threshold
|
|
37
|
+
* and turns every `unseen-for-N-blocks` it receives into `dropped`.
|
|
38
|
+
*/
|
|
39
|
+
const patchFromTxEvent = (event, confirmations) => {
|
|
40
|
+
switch (event.kind) {
|
|
41
|
+
case 'seen-in-mempool':
|
|
42
|
+
return { status: 'pending' };
|
|
43
|
+
case 'seen-in-block': {
|
|
44
|
+
if (event.confirmations < confirmations)
|
|
45
|
+
return null;
|
|
46
|
+
if (event.receipt && event.receipt.status === 'reverted') {
|
|
47
|
+
return { status: 'failed', notes: 'Transaction reverted', hash: event.hash };
|
|
48
|
+
}
|
|
49
|
+
return { status: 'confirmed', hash: event.hash };
|
|
50
|
+
}
|
|
51
|
+
case 'vanished-from-block':
|
|
52
|
+
return { status: 'pending' };
|
|
53
|
+
case 'replaced-by':
|
|
54
|
+
return {
|
|
55
|
+
status: 'replaced',
|
|
56
|
+
replacedBy: event.replacementHash,
|
|
57
|
+
};
|
|
58
|
+
case 'unseen-for-N-blocks':
|
|
59
|
+
return { status: 'dropped' };
|
|
60
|
+
default:
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
/** Build the private ChainSource + TxTracker pair and return a single unsub. */
|
|
65
|
+
const subscribeWatcher = async (opts) => {
|
|
66
|
+
// Dynamic import — keeps the bundle cost off the wallet-adapter-only
|
|
67
|
+
// consumer path. Resolves the workspace packages on demand.
|
|
68
|
+
const [{ createChainSource }, { createTxTracker }] = await Promise.all([
|
|
69
|
+
import('@valve-tech/chain-source'),
|
|
70
|
+
import('@valve-tech/tx-tracker'),
|
|
71
|
+
]);
|
|
72
|
+
const ownsSource = opts.sourceOverride === undefined;
|
|
73
|
+
const source = opts.sourceOverride ?? createChainSource({
|
|
74
|
+
client: opts.client,
|
|
75
|
+
onError: opts.onError,
|
|
76
|
+
});
|
|
77
|
+
const tracker = createTxTracker({
|
|
78
|
+
source,
|
|
79
|
+
chainId: opts.chainId,
|
|
80
|
+
onError: opts.onError,
|
|
81
|
+
});
|
|
82
|
+
source.start();
|
|
83
|
+
tracker.start();
|
|
84
|
+
const trackerUnsub = tracker.subscribe(opts.hash, (event) => {
|
|
85
|
+
const patch = patchFromTxEvent(event, opts.confirmations);
|
|
86
|
+
if (patch !== null)
|
|
87
|
+
opts.store.dispatch.update(opts.txId, patch);
|
|
88
|
+
}, {
|
|
89
|
+
emitInitial: false,
|
|
90
|
+
withReceipts: opts.withReceipts,
|
|
91
|
+
unseenThresholdBlocks: opts.staleAfterBlocks,
|
|
92
|
+
});
|
|
93
|
+
return () => {
|
|
94
|
+
trackerUnsub();
|
|
95
|
+
tracker.stop();
|
|
96
|
+
// Don't stop a source we don't own — the test seam owns it.
|
|
97
|
+
if (ownsSource)
|
|
98
|
+
source.stop();
|
|
99
|
+
};
|
|
100
|
+
};
|
|
101
|
+
export const addByHashImpl = async (store, input, onError, internal) => {
|
|
102
|
+
const id = generateTxId();
|
|
103
|
+
const unsub = await subscribeWatcher({
|
|
104
|
+
store,
|
|
105
|
+
txId: id,
|
|
106
|
+
hash: input.hash,
|
|
107
|
+
chainId: input.chainId,
|
|
108
|
+
client: input.client,
|
|
109
|
+
confirmations: input.confirmations ?? DEFAULT_CONFIRMATIONS,
|
|
110
|
+
staleAfterBlocks: input.staleAfterBlocks ?? DEFAULT_STALE_AFTER_BLOCKS,
|
|
111
|
+
withReceipts: input.withReceipts,
|
|
112
|
+
onError,
|
|
113
|
+
sourceOverride: internal?._sourceOverride,
|
|
114
|
+
});
|
|
115
|
+
const initialTx = {
|
|
116
|
+
id,
|
|
117
|
+
hash: input.hash,
|
|
118
|
+
chainId: input.chainId,
|
|
119
|
+
flow: input.flow ?? DEFAULT_FLOW,
|
|
120
|
+
submittedAt: Date.now(),
|
|
121
|
+
submittedTier: 'standard',
|
|
122
|
+
status: 'pending',
|
|
123
|
+
};
|
|
124
|
+
store.dispatch.addWithTx(initialTx, unsub);
|
|
125
|
+
return id;
|
|
126
|
+
};
|
|
127
|
+
/**
|
|
128
|
+
* Resume watching an already-persisted TrackedTx. Used by Provider on
|
|
129
|
+
* rehydrate to re-attach a tx-tracker subscription to a `pending` tx
|
|
130
|
+
* we loaded from storage. Overwrites the existing entry with itself
|
|
131
|
+
* plus the new watcher.
|
|
132
|
+
*
|
|
133
|
+
* No-op if `tx.hash` is missing — those entries were caught earlier
|
|
134
|
+
* in the rehydrate path and translated to `failed`.
|
|
135
|
+
*/
|
|
136
|
+
export const resumeByHashWatcher = async (store, tx, client, onError, internal) => {
|
|
137
|
+
if (tx.hash === undefined)
|
|
138
|
+
return;
|
|
139
|
+
let unsub;
|
|
140
|
+
try {
|
|
141
|
+
unsub = await subscribeWatcher({
|
|
142
|
+
store,
|
|
143
|
+
txId: tx.id,
|
|
144
|
+
hash: tx.hash,
|
|
145
|
+
chainId: tx.chainId,
|
|
146
|
+
client,
|
|
147
|
+
confirmations: DEFAULT_CONFIRMATIONS,
|
|
148
|
+
staleAfterBlocks: DEFAULT_STALE_AFTER_BLOCKS,
|
|
149
|
+
withReceipts: undefined,
|
|
150
|
+
onError,
|
|
151
|
+
sourceOverride: internal?._sourceOverride,
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
catch (err) {
|
|
155
|
+
onError?.('rehydrate-watcher', err);
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
// The current state still holds the entry — overwrite with the same
|
|
159
|
+
// tx + the new watcher unsub.
|
|
160
|
+
const current = store.getState().txs.get(tx.id);
|
|
161
|
+
if (!current) {
|
|
162
|
+
// Tx was removed (e.g., user dispatched remove) before our async
|
|
163
|
+
// subscribe completed. Tear down rather than reattach.
|
|
164
|
+
unsub();
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
store.dispatch.addWithTx(current, unsub);
|
|
168
|
+
};
|
|
169
|
+
//# sourceMappingURL=tx-tracker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tx-tracker.js","sourceRoot":"","sources":["../../src/integrations/tx-tracker.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview wallet-adapter integration for `addWithWalletAdapter`.
|
|
3
|
+
*
|
|
4
|
+
* Two pieces:
|
|
5
|
+
*
|
|
6
|
+
* - `wrapHooks(userHooks, store, txId, onError?)`: returns a new
|
|
7
|
+
* `WriteHookParams` bag where every named callback fans out to
|
|
8
|
+
* BOTH the consumer's original callback AND a `store.dispatch.update`
|
|
9
|
+
* that reflects the new lifecycle state on the strip's TrackedTx.
|
|
10
|
+
* Errors thrown by user callbacks are routed to `onError` and
|
|
11
|
+
* swallowed so a buggy user callback can't break the store update.
|
|
12
|
+
*
|
|
13
|
+
* - `addWithWalletAdapterImpl(store, input, onError?)`: builds the
|
|
14
|
+
* initial `preparing`-status TrackedTx, inserts it via
|
|
15
|
+
* `store.dispatch.addWithTx`, and returns `{ id, hooks }` so the
|
|
16
|
+
* consumer can pipe the wrapped hooks straight into
|
|
17
|
+
* `sendTransactionWithHooks`.
|
|
18
|
+
*
|
|
19
|
+
* No runtime `import` from `@valve-tech/wallet-adapter` — only `import
|
|
20
|
+
* type`. wallet-adapter is an optional peer dep; consumers who never
|
|
21
|
+
* use `addWithWalletAdapter` shouldn't pay the dependency cost. The
|
|
22
|
+
* status values (`'preparing'`, `'pending'`, etc.) live as string
|
|
23
|
+
* literals here, typed against `TrackedTxStatus`.
|
|
24
|
+
*/
|
|
25
|
+
import type { WriteHookParams } from '@valve-tech/wallet-adapter';
|
|
26
|
+
import type { AddWithWalletAdapterInput } from '../types.js';
|
|
27
|
+
import type { TxFlightStore } from '../store/store.js';
|
|
28
|
+
export declare const wrapHooks: (userHooks: WriteHookParams, store: TxFlightStore, txId: string, onError?: (method: string, err: unknown) => void) => WriteHookParams;
|
|
29
|
+
export interface AddWithWalletAdapterResult {
|
|
30
|
+
id: string;
|
|
31
|
+
hooks: WriteHookParams;
|
|
32
|
+
}
|
|
33
|
+
export declare const addWithWalletAdapterImpl: (store: TxFlightStore, input: AddWithWalletAdapterInput, onError?: (method: string, err: unknown) => void) => AddWithWalletAdapterResult;
|
|
34
|
+
//# sourceMappingURL=wallet-adapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wallet-adapter.d.ts","sourceRoot":"","sources":["../../src/integrations/wallet-adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,KAAK,EAEV,eAAe,EAChB,MAAM,4BAA4B,CAAA;AAEnC,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,aAAa,CAAA;AAC5D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AAkBtD,eAAO,MAAM,SAAS,cACT,eAAe,SACnB,aAAa,QACd,MAAM,YACF,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,KAAK,IAAI,KAC/C,eA0CD,CAAA;AAEF,MAAM,WAAW,0BAA0B;IACzC,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,eAAe,CAAA;CACvB;AAED,eAAO,MAAM,wBAAwB,UAC5B,aAAa,SACb,yBAAyB,YACtB,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,KAAK,IAAI,KAC/C,0BAeF,CAAA"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview wallet-adapter integration for `addWithWalletAdapter`.
|
|
3
|
+
*
|
|
4
|
+
* Two pieces:
|
|
5
|
+
*
|
|
6
|
+
* - `wrapHooks(userHooks, store, txId, onError?)`: returns a new
|
|
7
|
+
* `WriteHookParams` bag where every named callback fans out to
|
|
8
|
+
* BOTH the consumer's original callback AND a `store.dispatch.update`
|
|
9
|
+
* that reflects the new lifecycle state on the strip's TrackedTx.
|
|
10
|
+
* Errors thrown by user callbacks are routed to `onError` and
|
|
11
|
+
* swallowed so a buggy user callback can't break the store update.
|
|
12
|
+
*
|
|
13
|
+
* - `addWithWalletAdapterImpl(store, input, onError?)`: builds the
|
|
14
|
+
* initial `preparing`-status TrackedTx, inserts it via
|
|
15
|
+
* `store.dispatch.addWithTx`, and returns `{ id, hooks }` so the
|
|
16
|
+
* consumer can pipe the wrapped hooks straight into
|
|
17
|
+
* `sendTransactionWithHooks`.
|
|
18
|
+
*
|
|
19
|
+
* No runtime `import` from `@valve-tech/wallet-adapter` — only `import
|
|
20
|
+
* type`. wallet-adapter is an optional peer dep; consumers who never
|
|
21
|
+
* use `addWithWalletAdapter` shouldn't pay the dependency cost. The
|
|
22
|
+
* status values (`'preparing'`, `'pending'`, etc.) live as string
|
|
23
|
+
* literals here, typed against `TrackedTxStatus`.
|
|
24
|
+
*/
|
|
25
|
+
let txIdCounter = 0;
|
|
26
|
+
const generateTxId = () => `txflight-${Date.now()}-${++txIdCounter}`;
|
|
27
|
+
const safeFire = (fn, arg, onError) => {
|
|
28
|
+
if (!fn)
|
|
29
|
+
return;
|
|
30
|
+
try {
|
|
31
|
+
fn(arg);
|
|
32
|
+
}
|
|
33
|
+
catch (err) {
|
|
34
|
+
onError?.('user-hook', err);
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
export const wrapHooks = (userHooks, store, txId, onError) => ({
|
|
38
|
+
onAwaitingSignature: (info) => {
|
|
39
|
+
safeFire(userHooks.onAwaitingSignature, info, onError);
|
|
40
|
+
store.dispatch.update(txId, { status: 'awaiting-signature' });
|
|
41
|
+
},
|
|
42
|
+
onTransactionHash: (info) => {
|
|
43
|
+
safeFire(userHooks.onTransactionHash, info, onError);
|
|
44
|
+
store.dispatch.update(txId, { status: 'pending', hash: info.hash });
|
|
45
|
+
},
|
|
46
|
+
onConfirmed: (info) => {
|
|
47
|
+
safeFire(userHooks.onConfirmed, info, onError);
|
|
48
|
+
store.dispatch.update(txId, { status: 'confirmed', hash: info.hash });
|
|
49
|
+
},
|
|
50
|
+
onFailed: (info) => {
|
|
51
|
+
safeFire(userHooks.onFailed, info, onError);
|
|
52
|
+
const patch = {
|
|
53
|
+
status: 'failed',
|
|
54
|
+
notes: info.error.message,
|
|
55
|
+
};
|
|
56
|
+
if (info.hash !== undefined)
|
|
57
|
+
patch.hash = info.hash;
|
|
58
|
+
store.dispatch.update(txId, patch);
|
|
59
|
+
},
|
|
60
|
+
onDropped: (info) => {
|
|
61
|
+
safeFire(userHooks.onDropped, info, onError);
|
|
62
|
+
store.dispatch.update(txId, { status: 'dropped', hash: info.hash });
|
|
63
|
+
},
|
|
64
|
+
onReplaced: (info) => {
|
|
65
|
+
safeFire(userHooks.onReplaced, info, onError);
|
|
66
|
+
store.dispatch.update(txId, {
|
|
67
|
+
status: 'replaced',
|
|
68
|
+
replacedBy: info.replacement,
|
|
69
|
+
hash: info.original,
|
|
70
|
+
});
|
|
71
|
+
},
|
|
72
|
+
// `onPhase` only fans out to the consumer's onPhase; the named-hook
|
|
73
|
+
// path above is what writes to the store. wallet-adapter fires both
|
|
74
|
+
// shapes for every transition, so we don't lose any updates by
|
|
75
|
+
// attaching the dispatch to one side only — and we avoid double-
|
|
76
|
+
// writes when the same transition fires both shapes.
|
|
77
|
+
onPhase: (event) => {
|
|
78
|
+
safeFire(userHooks.onPhase, event, onError);
|
|
79
|
+
},
|
|
80
|
+
});
|
|
81
|
+
export const addWithWalletAdapterImpl = (store, input, onError) => {
|
|
82
|
+
const id = generateTxId();
|
|
83
|
+
const initialTx = {
|
|
84
|
+
id,
|
|
85
|
+
chainId: input.chainId,
|
|
86
|
+
flow: input.flow,
|
|
87
|
+
submittedAt: Date.now(),
|
|
88
|
+
// Default tier; addManual is the path for consumers who need a
|
|
89
|
+
// specific gas-oracle tier echoed onto the record.
|
|
90
|
+
submittedTier: 'standard',
|
|
91
|
+
status: 'preparing',
|
|
92
|
+
};
|
|
93
|
+
store.dispatch.addWithTx(initialTx, null);
|
|
94
|
+
const hooks = wrapHooks(input.hooks, store, id, onError);
|
|
95
|
+
return { id, hooks };
|
|
96
|
+
};
|
|
97
|
+
//# sourceMappingURL=wallet-adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wallet-adapter.js","sourceRoot":"","sources":["../../src/integrations/wallet-adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAUH,IAAI,WAAW,GAAG,CAAC,CAAA;AACnB,MAAM,YAAY,GAAG,GAAW,EAAE,CAAC,YAAY,IAAI,CAAC,GAAG,EAAE,IAAI,EAAE,WAAW,EAAE,CAAA;AAE5E,MAAM,QAAQ,GAAG,CACf,EAAkC,EAClC,GAAM,EACN,OAA6D,EACvD,EAAE;IACR,IAAI,CAAC,EAAE;QAAE,OAAM;IACf,IAAI,CAAC;QACH,EAAE,CAAC,GAAG,CAAC,CAAA;IACT,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,EAAE,CAAC,WAAW,EAAE,GAAG,CAAC,CAAA;IAC7B,CAAC;AACH,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,SAAS,GAAG,CACvB,SAA0B,EAC1B,KAAoB,EACpB,IAAY,EACZ,OAAgD,EAC/B,EAAE,CAAC,CAAC;IACrB,mBAAmB,EAAE,CAAC,IAAI,EAAE,EAAE;QAC5B,QAAQ,CAAC,SAAS,CAAC,mBAAmB,EAAE,IAAI,EAAE,OAAO,CAAC,CAAA;QACtD,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,oBAAoB,EAAE,CAAC,CAAA;IAC/D,CAAC;IACD,iBAAiB,EAAE,CAAC,IAAI,EAAE,EAAE;QAC1B,QAAQ,CAAC,SAAS,CAAC,iBAAiB,EAAE,IAAI,EAAE,OAAO,CAAC,CAAA;QACpD,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,CAAA;IACrE,CAAC;IACD,WAAW,EAAE,CAAC,IAAI,EAAE,EAAE;QACpB,QAAQ,CAAC,SAAS,CAAC,WAAW,EAAE,IAAI,EAAE,OAAO,CAAC,CAAA;QAC9C,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,CAAA;IACvE,CAAC;IACD,QAAQ,EAAE,CAAC,IAAI,EAAE,EAAE;QACjB,QAAQ,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,OAAO,CAAC,CAAA;QAC3C,MAAM,KAAK,GAAuB;YAChC,MAAM,EAAE,QAAQ;YAChB,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,OAAO;SAC1B,CAAA;QACD,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS;YAAE,KAAK,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAA;QACnD,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,CAAA;IACpC,CAAC;IACD,SAAS,EAAE,CAAC,IAAI,EAAE,EAAE;QAClB,QAAQ,CAAC,SAAS,CAAC,SAAS,EAAE,IAAI,EAAE,OAAO,CAAC,CAAA;QAC5C,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,CAAA;IACrE,CAAC;IACD,UAAU,EAAE,CAAC,IAAI,EAAE,EAAE;QACnB,QAAQ,CAAC,SAAS,CAAC,UAAU,EAAE,IAAI,EAAE,OAAO,CAAC,CAAA;QAC7C,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE;YAC1B,MAAM,EAAE,UAAU;YAClB,UAAU,EAAE,IAAI,CAAC,WAAW;YAC5B,IAAI,EAAE,IAAI,CAAC,QAAQ;SACpB,CAAC,CAAA;IACJ,CAAC;IACD,oEAAoE;IACpE,oEAAoE;IACpE,+DAA+D;IAC/D,iEAAiE;IACjE,qDAAqD;IACrD,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE;QACjB,QAAQ,CAAC,SAAS,CAAC,OAAO,EAAE,KAAK,EAAE,OAAO,CAAC,CAAA;IAC7C,CAAC;CACF,CAAC,CAAA;AAOF,MAAM,CAAC,MAAM,wBAAwB,GAAG,CACtC,KAAoB,EACpB,KAAgC,EAChC,OAAgD,EACpB,EAAE;IAC9B,MAAM,EAAE,GAAG,YAAY,EAAE,CAAA;IACzB,MAAM,SAAS,GAAc;QAC3B,EAAE;QACF,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,WAAW,EAAE,IAAI,CAAC,GAAG,EAAE;QACvB,+DAA+D;QAC/D,mDAAmD;QACnD,aAAa,EAAE,UAAU;QACzB,MAAM,EAAE,WAAW;KACpB,CAAA;IACD,KAAK,CAAC,QAAQ,CAAC,SAAS,CAAC,SAAS,EAAE,IAAI,CAAC,CAAA;IACzC,MAAM,KAAK,GAAG,SAAS,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,EAAE,OAAO,CAAC,CAAA;IACxD,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,CAAA;AACtB,CAAC,CAAA"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview <TxFlightProvider> — wraps the React tree with a
|
|
3
|
+
* tx-flight store, scoped by `id`.
|
|
4
|
+
*
|
|
5
|
+
* Lifecycle:
|
|
6
|
+
* - First render: lazy `useState` acquires (or reuses) a store
|
|
7
|
+
* registered under `id` in a module-level registry. Two Providers
|
|
8
|
+
* with the same `id` silently share the same store via refCount.
|
|
9
|
+
* - First commit: `useEffect` starts the side-effect machinery —
|
|
10
|
+
* eviction interval, debounced storage save subscription, storage
|
|
11
|
+
* rehydrate. Idempotent across same-id mounts via `entry.started`.
|
|
12
|
+
* - Unmount: `useEffect` cleanup decrements refCount; if 0, the
|
|
13
|
+
* entry is disposed (timers cleared, final save flushed) and
|
|
14
|
+
* removed from the registry.
|
|
15
|
+
*
|
|
16
|
+
* Why eager registration: the children's first render calls
|
|
17
|
+
* `useTxFlight`, which throws if no store is registered for the id.
|
|
18
|
+
* Lazy `useState` runs once per component instance and is safe to
|
|
19
|
+
* mutate the registry from (no Strict-Mode double-invoke).
|
|
20
|
+
*
|
|
21
|
+
* SSR: `'use client'` keeps Next.js RSC from running this on the
|
|
22
|
+
* server. Other SSR frameworks (renderToString) will reach the lazy
|
|
23
|
+
* registration; that's acceptable for v0.9.0 because side effects
|
|
24
|
+
* (timers, storage IO) are gated by `useEffect`. Task 12 audits the
|
|
25
|
+
* surface for residual `window`/`document` access.
|
|
26
|
+
*/
|
|
27
|
+
import { type ReactNode } from 'react';
|
|
28
|
+
import type { PublicClient } from 'viem';
|
|
29
|
+
import { type TxFlightStore } from './store/store.js';
|
|
30
|
+
import type { TxFlightStorage } from './types.js';
|
|
31
|
+
export type TxFlightClientFactory = (chainId: number) => PublicClient | undefined;
|
|
32
|
+
/** @internal — read by `useTxFlight` to find the store for an id. */
|
|
33
|
+
export declare const _getStoreForId: (id: string) => TxFlightStore | undefined;
|
|
34
|
+
/** @internal — test escape hatch; tears down every entry. */
|
|
35
|
+
export declare const _resetRegistry: () => void;
|
|
36
|
+
interface ContextValue {
|
|
37
|
+
id: string;
|
|
38
|
+
}
|
|
39
|
+
/** @internal — read by `useTxFlight` to resolve the ambient id. */
|
|
40
|
+
export declare const _useTxFlightContext: () => ContextValue | null;
|
|
41
|
+
export interface TxFlightProviderProps {
|
|
42
|
+
children: ReactNode;
|
|
43
|
+
/** Scopes both in-memory state and storage key. Default: 'default'. */
|
|
44
|
+
id?: string;
|
|
45
|
+
/**
|
|
46
|
+
* Pluggable persistence. Pass `null` to disable persistence
|
|
47
|
+
* (memory-only). Default: `localStorageAdapter()`.
|
|
48
|
+
*/
|
|
49
|
+
storage?: TxFlightStorage | null;
|
|
50
|
+
/** Max retained entries before eviction prunes. Default: 50. */
|
|
51
|
+
maxItems?: number;
|
|
52
|
+
/** How long terminals linger after settling (ms). Default: 60_000. */
|
|
53
|
+
terminalRetentionMs?: number;
|
|
54
|
+
/** Surfaced for storage failures, watcher errors. */
|
|
55
|
+
onError?: (method: string, err: unknown) => void;
|
|
56
|
+
/**
|
|
57
|
+
* Optional. Returns a `PublicClient` for the given `chainId`, or
|
|
58
|
+
* `undefined` if not configured. Required only if you want
|
|
59
|
+
* persisted `pending` entries to auto-resume tx-tracker watching
|
|
60
|
+
* after a reload. Without this, persisted `pending` entries stay
|
|
61
|
+
* 'pending' until the consumer manually re-issues `addByHash`.
|
|
62
|
+
*/
|
|
63
|
+
clientFactory?: TxFlightClientFactory;
|
|
64
|
+
}
|
|
65
|
+
export declare const TxFlightProvider: (props: TxFlightProviderProps) => ReactNode;
|
|
66
|
+
export {};
|
|
67
|
+
//# sourceMappingURL=provider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../src/provider.tsx"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,EAKL,KAAK,SAAS,EACf,MAAM,OAAO,CAAA;AACd,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,MAAM,CAAA;AAIxC,OAAO,EAAuB,KAAK,aAAa,EAAE,MAAM,kBAAkB,CAAA;AAC1E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAEjD,MAAM,MAAM,qBAAqB,GAAG,CAAC,OAAO,EAAE,MAAM,KAAK,YAAY,GAAG,SAAS,CAAA;AAmBjF,qEAAqE;AACrE,eAAO,MAAM,cAAc,OAAQ,MAAM,KAAG,aAAa,GAAG,SACnC,CAAA;AAEzB,6DAA6D;AAC7D,eAAO,MAAM,cAAc,QAAO,IAGjC,CAAA;AAED,UAAU,YAAY;IACpB,EAAE,EAAE,MAAM,CAAA;CACX;AAID,mEAAmE;AACnE,eAAO,MAAM,mBAAmB,QAAO,YAAY,GAAG,IACzB,CAAA;AAE7B,MAAM,WAAW,qBAAqB;IACpC,QAAQ,EAAE,SAAS,CAAA;IACnB,uEAAuE;IACvE,EAAE,CAAC,EAAE,MAAM,CAAA;IACX;;;OAGG;IACH,OAAO,CAAC,EAAE,eAAe,GAAG,IAAI,CAAA;IAChC,gEAAgE;IAChE,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,sEAAsE;IACtE,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAC5B,qDAAqD;IACrD,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,KAAK,IAAI,CAAA;IAChD;;;;;;OAMG;IACH,aAAa,CAAC,EAAE,qBAAqB,CAAA;CACtC;AAqFD,eAAO,MAAM,gBAAgB,UAAW,qBAAqB,KAAG,SAoE/D,CAAA"}
|