@dappql/react 1.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/dist/react/src/Context.d.ts +35 -0
- package/dist/react/src/Context.d.ts.map +1 -0
- package/dist/react/src/Context.js +42 -0
- package/dist/react/src/ContextQuery.d.ts +66 -0
- package/dist/react/src/ContextQuery.d.ts.map +1 -0
- package/dist/react/src/ContextQuery.js +94 -0
- package/dist/react/src/ContextQueryManager.d.ts +71 -0
- package/dist/react/src/ContextQueryManager.d.ts.map +1 -0
- package/dist/react/src/ContextQueryManager.js +135 -0
- package/dist/react/src/Mutation.d.ts +79 -0
- package/dist/react/src/Mutation.d.ts.map +1 -0
- package/dist/react/src/Mutation.js +147 -0
- package/dist/react/src/Provider.d.ts +34 -0
- package/dist/react/src/Provider.d.ts.map +1 -0
- package/dist/react/src/Provider.js +39 -0
- package/dist/react/src/Query.d.ts +52 -0
- package/dist/react/src/Query.d.ts.map +1 -0
- package/dist/react/src/Query.js +92 -0
- package/dist/react/src/blocksHandler.d.ts +10 -0
- package/dist/react/src/blocksHandler.d.ts.map +1 -0
- package/dist/react/src/blocksHandler.js +32 -0
- package/dist/react/src/buildIteratorQuery.d.ts +5 -0
- package/dist/react/src/buildIteratorQuery.d.ts.map +1 -0
- package/dist/react/src/buildIteratorQuery.js +9 -0
- package/dist/react/src/index.d.ts +7 -0
- package/dist/react/src/index.d.ts.map +1 -0
- package/dist/react/src/index.js +7 -0
- package/dist/react/src/queryHooks.d.ts +31 -0
- package/dist/react/src/queryHooks.d.ts.map +1 -0
- package/dist/react/src/queryHooks.js +49 -0
- package/dist/react/src/useTransactionUpdates.d.ts +3 -0
- package/dist/react/src/useTransactionUpdates.d.ts.map +1 -0
- package/dist/react/src/useTransactionUpdates.js +112 -0
- package/dist/shared/types.d.ts +105 -0
- package/dist/shared/types.d.ts.map +1 -0
- package/dist/shared/types.js +2 -0
- package/package.json +74 -0
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { useCallback, useEffect } from 'react';
|
|
2
|
+
import { usePublicClient } from 'wagmi';
|
|
3
|
+
// Store refs for watching state outside the effect
|
|
4
|
+
const storageKey = 'pending-transactions';
|
|
5
|
+
class TransactionWatcher {
|
|
6
|
+
constructor(client, onUpdate) {
|
|
7
|
+
this.watchingTransactions = new Set();
|
|
8
|
+
this.abortControllers = new Map();
|
|
9
|
+
this.handleStorageChange = (e) => {
|
|
10
|
+
if (e.key !== storageKey || !e.newValue)
|
|
11
|
+
return;
|
|
12
|
+
this.processTransactions(JSON.parse(e.newValue));
|
|
13
|
+
};
|
|
14
|
+
this.client = client;
|
|
15
|
+
this.onUpdate = onUpdate;
|
|
16
|
+
window.addEventListener('storage', this.handleStorageChange);
|
|
17
|
+
this.processExistingTransactions();
|
|
18
|
+
}
|
|
19
|
+
processExistingTransactions() {
|
|
20
|
+
const existingData = localStorage.getItem(storageKey);
|
|
21
|
+
if (existingData) {
|
|
22
|
+
this.processTransactions(JSON.parse(existingData));
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
async processTransaction(txInfo) {
|
|
26
|
+
const txHash = txInfo.txHash;
|
|
27
|
+
if (!txHash || this.watchingTransactions.has(txHash))
|
|
28
|
+
return;
|
|
29
|
+
this.watchingTransactions.add(txHash);
|
|
30
|
+
const controller = new AbortController();
|
|
31
|
+
this.abortControllers.set(txHash, controller);
|
|
32
|
+
try {
|
|
33
|
+
const receipt = await this.client.waitForTransactionReceipt({
|
|
34
|
+
hash: txHash,
|
|
35
|
+
});
|
|
36
|
+
if (this.watchingTransactions.has(txHash)) {
|
|
37
|
+
const mutationUpdate = {
|
|
38
|
+
...txInfo,
|
|
39
|
+
status: receipt.status === 'success' ? 'success' : 'error',
|
|
40
|
+
error: receipt.status === 'success' ? undefined : new Error('Transaction failed'),
|
|
41
|
+
receipt,
|
|
42
|
+
};
|
|
43
|
+
handleMutationUpdate(mutationUpdate, this.onUpdate);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
catch (error) {
|
|
47
|
+
if (!controller.signal.aborted) {
|
|
48
|
+
console.error(`Error watching transaction ${txHash}:`, error);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
processTransactions(transactions) {
|
|
53
|
+
transactions.forEach((item) => {
|
|
54
|
+
const txInfo = JSON.parse(item);
|
|
55
|
+
this.processTransaction(txInfo);
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
watchTransaction(txInfo) {
|
|
59
|
+
this.processTransaction(txInfo);
|
|
60
|
+
}
|
|
61
|
+
cleanup() {
|
|
62
|
+
window.removeEventListener('storage', this.handleStorageChange);
|
|
63
|
+
this.abortControllers.forEach((controller) => controller.abort());
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
let globalWatcher = null;
|
|
67
|
+
function handleMutationUpdate(mutation, onUpdate) {
|
|
68
|
+
onUpdate(mutation);
|
|
69
|
+
if (!mutation.txHash)
|
|
70
|
+
return;
|
|
71
|
+
const txInfo = JSON.stringify({
|
|
72
|
+
id: mutation.id,
|
|
73
|
+
txHash: mutation.txHash,
|
|
74
|
+
account: mutation.account,
|
|
75
|
+
address: mutation.address,
|
|
76
|
+
contractName: mutation.contractName,
|
|
77
|
+
functionName: mutation.functionName,
|
|
78
|
+
transactionName: mutation.transactionName,
|
|
79
|
+
});
|
|
80
|
+
const currentData = localStorage.getItem(storageKey);
|
|
81
|
+
const transactions = currentData ? JSON.parse(currentData) : [];
|
|
82
|
+
switch (mutation.status) {
|
|
83
|
+
case 'signed':
|
|
84
|
+
// Add to storage and start watching
|
|
85
|
+
const newTransactions = [...transactions, txInfo];
|
|
86
|
+
localStorage.setItem(storageKey, JSON.stringify(newTransactions));
|
|
87
|
+
globalWatcher?.watchTransaction(JSON.parse(txInfo));
|
|
88
|
+
break;
|
|
89
|
+
case 'success':
|
|
90
|
+
case 'error':
|
|
91
|
+
// Remove from storage
|
|
92
|
+
localStorage.setItem(storageKey, JSON.stringify(transactions.filter((t) => t !== txInfo)));
|
|
93
|
+
break;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
export default function useTransactionUpdates(onUpdate) {
|
|
97
|
+
const client = usePublicClient();
|
|
98
|
+
useEffect(() => {
|
|
99
|
+
if (!client || !onUpdate)
|
|
100
|
+
return;
|
|
101
|
+
globalWatcher = new TransactionWatcher(client, onUpdate);
|
|
102
|
+
return () => {
|
|
103
|
+
globalWatcher?.cleanup();
|
|
104
|
+
globalWatcher = null;
|
|
105
|
+
};
|
|
106
|
+
}, [client, onUpdate]);
|
|
107
|
+
return useCallback((mutation) => {
|
|
108
|
+
if (!client || !onUpdate)
|
|
109
|
+
return;
|
|
110
|
+
handleMutationUpdate(mutation, onUpdate);
|
|
111
|
+
}, [client, onUpdate]);
|
|
112
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import type { Abi, AbiFunction, Address, TransactionReceipt } from 'viem';
|
|
2
|
+
export type Request = {
|
|
3
|
+
contractName: string;
|
|
4
|
+
method: AbiFunction['name'];
|
|
5
|
+
args?: readonly any[];
|
|
6
|
+
address?: Address;
|
|
7
|
+
deployAddress?: Address;
|
|
8
|
+
defaultValue?: unknown;
|
|
9
|
+
chainId?: number;
|
|
10
|
+
getAbi: () => Abi;
|
|
11
|
+
};
|
|
12
|
+
export type RequestCollection = Record<string, Request>;
|
|
13
|
+
export type MutationConfig<M extends string, Args extends readonly any[]> = {
|
|
14
|
+
contractName: string;
|
|
15
|
+
functionName: M;
|
|
16
|
+
deployAddress?: Address;
|
|
17
|
+
argsType?: Args;
|
|
18
|
+
chainId?: number;
|
|
19
|
+
getAbi: () => Abi;
|
|
20
|
+
};
|
|
21
|
+
export type MutationCollection<T extends Record<string, MutationConfig<any, any>>> = T;
|
|
22
|
+
export type ExtractArgs<T> = T extends (...args: infer P) => any ? P : never;
|
|
23
|
+
/**
|
|
24
|
+
* Configuration options for query operations
|
|
25
|
+
*/
|
|
26
|
+
export type QueryOptions = {
|
|
27
|
+
/**
|
|
28
|
+
* If true, the query will not automatically update when new blocks arrive.
|
|
29
|
+
* Use this for data that you know won't change, like historical events
|
|
30
|
+
* or immutable contract state.
|
|
31
|
+
*/
|
|
32
|
+
isStatic?: boolean;
|
|
33
|
+
/** If true, the query will be refetched on new blocks */
|
|
34
|
+
watchBlocks?: boolean;
|
|
35
|
+
/** Optional block number to query at a specific block */
|
|
36
|
+
blockNumber?: bigint;
|
|
37
|
+
/** Optional interval (in ms) to refetch the data */
|
|
38
|
+
refetchInterval?: number;
|
|
39
|
+
/** Optional batch size for multicalls */
|
|
40
|
+
batchSize?: number;
|
|
41
|
+
/** If true, the query will be paused. */
|
|
42
|
+
paused?: boolean;
|
|
43
|
+
/** How many blocks to wait before refetching the query */
|
|
44
|
+
blocksRefetchInterval?: number;
|
|
45
|
+
};
|
|
46
|
+
export type MutationInfo = {
|
|
47
|
+
id: string;
|
|
48
|
+
status: 'submitted' | 'signed' | 'success' | 'error';
|
|
49
|
+
account?: Address;
|
|
50
|
+
address: Address;
|
|
51
|
+
contractName: string;
|
|
52
|
+
functionName: string;
|
|
53
|
+
transactionName?: string;
|
|
54
|
+
txHash?: Address;
|
|
55
|
+
args?: readonly any[];
|
|
56
|
+
error?: Error;
|
|
57
|
+
receipt?: TransactionReceipt;
|
|
58
|
+
};
|
|
59
|
+
/**
|
|
60
|
+
* Callback functions for different mutation states
|
|
61
|
+
*/
|
|
62
|
+
export type MutationCallbacks = {
|
|
63
|
+
/** Called when a mutation changes state */
|
|
64
|
+
onMutationUpdate?: (info: MutationInfo) => any;
|
|
65
|
+
};
|
|
66
|
+
/**
|
|
67
|
+
* Function type for resolving contract names to addresses
|
|
68
|
+
*/
|
|
69
|
+
export type AddressResolverFunction = (contractName: string) => Address;
|
|
70
|
+
/**
|
|
71
|
+
* Props for the AddressResolver component
|
|
72
|
+
*/
|
|
73
|
+
export type AddressResolverProps = {
|
|
74
|
+
/** Callback when resolver is ready */
|
|
75
|
+
onResolved: (resolver: AddressResolverFunction) => any;
|
|
76
|
+
};
|
|
77
|
+
export type ReadContractsResult = {
|
|
78
|
+
isLoading?: boolean;
|
|
79
|
+
isError?: boolean;
|
|
80
|
+
error?: Error | null;
|
|
81
|
+
data?: ({
|
|
82
|
+
error?: undefined;
|
|
83
|
+
result: unknown;
|
|
84
|
+
status: 'success';
|
|
85
|
+
} | {
|
|
86
|
+
error: Error;
|
|
87
|
+
result?: undefined;
|
|
88
|
+
status: 'failure';
|
|
89
|
+
})[] | undefined;
|
|
90
|
+
};
|
|
91
|
+
/**
|
|
92
|
+
* Function type for generating item queries at specific indices
|
|
93
|
+
*/
|
|
94
|
+
export type GetItemCallFunction<T> = (index: bigint) => Request & {
|
|
95
|
+
defaultValue: T;
|
|
96
|
+
};
|
|
97
|
+
export type QueryContextProps = {
|
|
98
|
+
/** Whether to update queries on new blocks */
|
|
99
|
+
watchBlocks?: boolean;
|
|
100
|
+
/** How many blocks to wait before refecthing queries*/
|
|
101
|
+
blocksRefetchInterval?: number;
|
|
102
|
+
/** Default batch size for multicalls */
|
|
103
|
+
defaultBatchSize?: number;
|
|
104
|
+
};
|
|
105
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../shared/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,WAAW,EAAE,OAAO,EAAE,kBAAkB,EAAE,MAAM,MAAM,CAAA;AAEzE,MAAM,MAAM,OAAO,GAAG;IACpB,YAAY,EAAE,MAAM,CAAA;IACpB,MAAM,EAAE,WAAW,CAAC,MAAM,CAAC,CAAA;IAC3B,IAAI,CAAC,EAAE,SAAS,GAAG,EAAE,CAAA;IACrB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,MAAM,GAAG,CAAA;CAClB,CAAA;AACD,MAAM,MAAM,iBAAiB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;AAEvD,MAAM,MAAM,cAAc,CAAC,CAAC,SAAS,MAAM,EAAE,IAAI,SAAS,SAAS,GAAG,EAAE,IAAI;IAC1E,YAAY,EAAE,MAAM,CAAA;IACpB,YAAY,EAAE,CAAC,CAAA;IACf,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,QAAQ,CAAC,EAAE,IAAI,CAAA;IACf,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,MAAM,GAAG,CAAA;CAClB,CAAA;AACD,MAAM,MAAM,kBAAkB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC,CAAA;AAEtF,MAAM,MAAM,WAAW,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,MAAM,CAAC,KAAK,GAAG,GAAG,CAAC,GAAG,KAAK,CAAA;AAE5E;;GAEG;AACH,MAAM,MAAM,YAAY,GAAG;IACzB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,yDAAyD;IACzD,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,yDAAyD;IACzD,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,oDAAoD;IACpD,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,yCAAyC;IACzC,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,yCAAyC;IACzC,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,0DAA0D;IAC1D,qBAAqB,CAAC,EAAE,MAAM,CAAA;CAC/B,CAAA;AAED,MAAM,MAAM,YAAY,GAAG;IACzB,EAAE,EAAE,MAAM,CAAA;IACV,MAAM,EAAE,WAAW,GAAG,QAAQ,GAAG,SAAS,GAAG,OAAO,CAAA;IACpD,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,OAAO,EAAE,OAAO,CAAA;IAChB,YAAY,EAAE,MAAM,CAAA;IACpB,YAAY,EAAE,MAAM,CAAA;IACpB,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,IAAI,CAAC,EAAE,SAAS,GAAG,EAAE,CAAA;IACrB,KAAK,CAAC,EAAE,KAAK,CAAA;IACb,OAAO,CAAC,EAAE,kBAAkB,CAAA;CAC7B,CAAA;AAED;;GAEG;AACH,MAAM,MAAM,iBAAiB,GAAG;IAC9B,2CAA2C;IAC3C,gBAAgB,CAAC,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK,GAAG,CAAA;CAC/C,CAAA;AAED;;GAEG;AACH,MAAM,MAAM,uBAAuB,GAAG,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAA;AAEvE;;GAEG;AACH,MAAM,MAAM,oBAAoB,GAAG;IACjC,sCAAsC;IACtC,UAAU,EAAE,CAAC,QAAQ,EAAE,uBAAuB,KAAK,GAAG,CAAA;CACvD,CAAA;AAED,MAAM,MAAM,mBAAmB,GAAG;IAChC,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,KAAK,CAAC,EAAE,KAAK,GAAG,IAAI,CAAA;IACpB,IAAI,CAAC,EACD,CACI;QACE,KAAK,CAAC,EAAE,SAAS,CAAA;QACjB,MAAM,EAAE,OAAO,CAAA;QACf,MAAM,EAAE,SAAS,CAAA;KAClB,GACD;QACE,KAAK,EAAE,KAAK,CAAA;QACZ,MAAM,CAAC,EAAE,SAAS,CAAA;QAClB,MAAM,EAAE,SAAS,CAAA;KAClB,CACJ,EAAE,GACH,SAAS,CAAA;CACd,CAAA;AAED;;GAEG;AACH,MAAM,MAAM,mBAAmB,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,GAAG;IAChE,YAAY,EAAE,CAAC,CAAA;CAChB,CAAA;AAED,MAAM,MAAM,iBAAiB,GAAG;IAC9B,8CAA8C;IAC9C,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,uDAAuD;IACvD,qBAAqB,CAAC,EAAE,MAAM,CAAA;IAC9B,wCAAwC;IACxC,gBAAgB,CAAC,EAAE,MAAM,CAAA;CAC1B,CAAA"}
|
package/package.json
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@dappql/react",
|
|
3
|
+
"version": "1.0.1",
|
|
4
|
+
"description": "Streamlined smart contract data fetching library for React dApps with TypeScript support",
|
|
5
|
+
"author": "DappQL Team",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"keywords": [
|
|
8
|
+
"wagmi",
|
|
9
|
+
"viem",
|
|
10
|
+
"typescript",
|
|
11
|
+
"blockchain",
|
|
12
|
+
"smart-contracts",
|
|
13
|
+
"dapp",
|
|
14
|
+
"hooks",
|
|
15
|
+
"react hooks",
|
|
16
|
+
"query"
|
|
17
|
+
],
|
|
18
|
+
"main": "dist/react/src/index.js",
|
|
19
|
+
"types": "dist/react/src/index.d.ts",
|
|
20
|
+
"files": [
|
|
21
|
+
"dist"
|
|
22
|
+
],
|
|
23
|
+
"exports": {
|
|
24
|
+
".": {
|
|
25
|
+
"types": "./dist/react/src/index.d.ts",
|
|
26
|
+
"default": "./dist/react/src/index.js"
|
|
27
|
+
},
|
|
28
|
+
"./shared/*": {
|
|
29
|
+
"types": "./dist/shared/*.d.ts",
|
|
30
|
+
"default": "./dist/shared/*.js"
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
"repository": {
|
|
34
|
+
"type": "git",
|
|
35
|
+
"url": "git+https://github.com/dappql/monorepo.git"
|
|
36
|
+
},
|
|
37
|
+
"bugs": {
|
|
38
|
+
"url": "https://github.com/dappql/monorepo/issues"
|
|
39
|
+
},
|
|
40
|
+
"homepage": "https://github.com/dappql/monorepo#readme",
|
|
41
|
+
"license": "MIT",
|
|
42
|
+
"peerDependencies": {
|
|
43
|
+
"@tanstack/react-query": ">=5.0.0",
|
|
44
|
+
"react": ">=18",
|
|
45
|
+
"typescript": ">=5.0.4",
|
|
46
|
+
"viem": "2.x",
|
|
47
|
+
"wagmi": "^2"
|
|
48
|
+
},
|
|
49
|
+
"devDependencies": {
|
|
50
|
+
"@testing-library/jest-dom": "^6.6.3",
|
|
51
|
+
"@testing-library/react": "^16.1.0",
|
|
52
|
+
"@types/react": "^18.3.12",
|
|
53
|
+
"@typescript-eslint/eslint-plugin": "^5.46.1",
|
|
54
|
+
"@typescript-eslint/parser": "^5.46.1",
|
|
55
|
+
"@vitejs/plugin-react": "^4.3.4",
|
|
56
|
+
"@vitest/coverage-v8": "2.1.8",
|
|
57
|
+
"eslint": "^8.29.0",
|
|
58
|
+
"eslint-config-universe": "^11.1.1",
|
|
59
|
+
"happy-dom": "^15.11.7",
|
|
60
|
+
"jsdom": "^25.0.1",
|
|
61
|
+
"typescript": "^5.6.3",
|
|
62
|
+
"vitest": "^2.1.8"
|
|
63
|
+
},
|
|
64
|
+
"scripts": {
|
|
65
|
+
"clean": "rm -rf ./node_modules && rm -rf ./dist && rm -rf ./.turbo",
|
|
66
|
+
"test": "vitest run --coverage",
|
|
67
|
+
"test:watch": "vitest --coverage",
|
|
68
|
+
"dev": "pnpm exec tsc -b -w",
|
|
69
|
+
"build": "del-cli dist && tsc",
|
|
70
|
+
"version:bump": "bump patch --commit --push",
|
|
71
|
+
"publish:npm": "pnpm publish --access public --no-workspace-root",
|
|
72
|
+
"ship": "pnpm run build && pnpm run version:bump && pnpm run publish:npm --no-git-checks --access public"
|
|
73
|
+
}
|
|
74
|
+
}
|