@dappql/react 1.0.5 → 1.0.9

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/README.md ADDED
@@ -0,0 +1,143 @@
1
+ # @dappql/react
2
+
3
+ > React hooks for [DappQL](https://github.com/dappql/core). Typed, batched smart-contract reads and writes on top of [wagmi](https://wagmi.sh) + [viem](https://viem.sh), with automatic multicall fusion across your entire component tree, per-block reactivity, iterator queries, and mutation tracking.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install @dappql/react wagmi viem @tanstack/react-query
9
+ ```
10
+
11
+ Pair with the [`dappql`](https://www.npmjs.com/package/dappql) CLI to generate your typed contract modules.
12
+
13
+ ## Provider
14
+
15
+ ```tsx
16
+ import { WagmiProvider } from 'wagmi'
17
+ import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
18
+ import { DappQLProvider } from '@dappql/react'
19
+
20
+ const queryClient = new QueryClient()
21
+
22
+ export function Root({ children }) {
23
+ return (
24
+ <WagmiProvider config={wagmiConfig}>
25
+ <QueryClientProvider client={queryClient}>
26
+ <DappQLProvider watchBlocks>{children}</DappQLProvider>
27
+ </QueryClientProvider>
28
+ </WagmiProvider>
29
+ )
30
+ }
31
+ ```
32
+
33
+ Provider options:
34
+
35
+ | Option | Purpose |
36
+ | --- | --- |
37
+ | `watchBlocks` | Refetch on every new block, makes reads reactive to chain state. |
38
+ | `simulateMutations` | Preflight every tx via `eth_call`. Aborts on revert. |
39
+ | `onMutationUpdate` | Single callback for every transaction lifecycle event, one place to drive toasts, analytics, receipts. |
40
+ | `addressResolver` | Function that resolves contract names to addresses, for registries, proxies, multi-deploy. |
41
+ | `AddressResolverComponent` | Async alternative to `addressResolver` when the resolver needs hooks. |
42
+
43
+ ## Reads
44
+
45
+ ### `useContextQuery`: the default
46
+
47
+ Batches calls across your **entire** component tree into one multicall.
48
+
49
+ ```tsx
50
+ import { Token, ToDo } from './contracts'
51
+ import { useContextQuery } from '@dappql/react'
52
+
53
+ function Dashboard({ account }) {
54
+ const { data, isLoading } = useContextQuery({
55
+ balance: Token.call.balanceOf(account),
56
+ symbol: Token.call.symbol(),
57
+ totalTasks: ToDo.call.totalTasks(),
58
+ })
59
+
60
+ if (isLoading) return <Spinner />
61
+ return <p>{data.balance.toString()} {data.symbol}</p>
62
+ }
63
+ ```
64
+
65
+ If `<Dashboard>` and `<Sidebar>` both use `useContextQuery`, their calls fuse into one RPC, not two.
66
+
67
+ ### `useQuery`: component-scoped batching
68
+
69
+ Same shape as `useContextQuery`, but scoped to this hook call. Use when you need `blockNumber`, `paused`, custom `refetchInterval`, or `batchSize` overrides.
70
+
71
+ ### `useSingleQuery` / `useSingleContextQuery`
72
+
73
+ ```tsx
74
+ const { data } = useSingleContextQuery(Token.call.balanceOf(account))
75
+ // data: bigint (inferred from the ABI)
76
+ ```
77
+
78
+ ### `useIteratorQuery`: on-chain arrays
79
+
80
+ ```tsx
81
+ import { useIteratorQuery } from '@dappql/react'
82
+
83
+ const { data } = useIteratorQuery(totalTasks, (i) => ToDo.call.taskAt(account, i))
84
+ ```
85
+
86
+ ## Writes
87
+
88
+ ```tsx
89
+ import { useMutation } from '@dappql/react'
90
+ import { ToDo } from './contracts'
91
+
92
+ function NewTask() {
93
+ const mutation = useMutation(ToDo.mutation.addItem, 'Add task')
94
+
95
+ return (
96
+ <button
97
+ disabled={mutation.isLoading}
98
+ onClick={() => mutation.send('Buy milk', 0n)}
99
+ >
100
+ {mutation.confirmation.isSuccess ? 'Added' : 'Add task'}
101
+ </button>
102
+ )
103
+ }
104
+ ```
105
+
106
+ Surface:
107
+
108
+ ```ts
109
+ mutation.send(...args) // broadcast; spread args, not array
110
+ mutation.simulate(...args) // manual preflight
111
+ mutation.estimate(...args) // gas estimate
112
+ mutation.isPending // awaiting signature
113
+ mutation.isLoading // awaiting signature OR mining
114
+ mutation.confirmation.isSuccess // receipt confirmed
115
+ mutation.reset()
116
+ ```
117
+
118
+ ## Fluent request API
119
+
120
+ Every generated call exposes a small fluent API for overrides:
121
+
122
+ ```ts
123
+ Token.call.balanceOf(account)
124
+ .at('0x...') // override deploy address
125
+ .defaultTo(0n) // default value until the call resolves
126
+ ```
127
+
128
+ ## Related packages
129
+
130
+ | Package | Purpose |
131
+ | --- | --- |
132
+ | [`dappql`](https://www.npmjs.com/package/dappql) | Codegen CLI, generates the typed contract modules you import above |
133
+ | [`@dappql/async`](https://www.npmjs.com/package/@dappql/async) | Non-React runtime, same typed calls, no React required |
134
+ | [`@dappql/codegen`](https://www.npmjs.com/package/@dappql/codegen) | Framework-agnostic codegen engine |
135
+ | [`@dappql/mcp`](https://www.npmjs.com/package/@dappql/mcp) | MCP server, live contract context for AI coding agents |
136
+
137
+ ## Full documentation
138
+
139
+ [github.com/dappql/core](https://github.com/dappql/core)
140
+
141
+ ## License
142
+
143
+ MIT
@@ -1 +1 @@
1
- {"version":3,"file":"ContextQueryManager.d.ts","sourceRoot":"","sources":["../src/ContextQueryManager.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,EAAE,GAAG,EAAa,OAAO,EAAE,MAAM,MAAM,CAAA;AAE9C,OAAO,EAAE,iBAAiB,EAAE,uBAAuB,EAAW,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA;AAGxH,KAAK,KAAK,GAAG;IAAE,UAAU,EAAE,iBAAiB,CAAC;IAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,mBAAmB,KAAK,IAAI,CAAA;CAAE,CAAA;AAC/F;;GAEG;AACH,KAAK,IAAI,GAAG;IACV,OAAO,EAAE,MAAM,CAAA;IACf,GAAG,EAAE,GAAG,CAAA;IACR,YAAY,EAAE,MAAM,CAAA;IACpB,IAAI,EAAE,SAAS,GAAG,EAAE,CAAA;IACpB,OAAO,EAAE,OAAO,CAAA;CACjB,CAAA;AAED;;GAEG;AACH,KAAK,YAAY,GAAG;IAClB,OAAO,EAAE,MAAM,CAAA;IACf,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC7B,KAAK,EAAE,IAAI,EAAE,CAAA;CACd,CAAA;AAED;;GAEG;AACH,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,OAAO,CAA4B;IAC3C,OAAO,CAAC,aAAa,CAAyB;IAC9C,OAAO,CAAC,UAAU,CAAqD;IACvE,OAAO,CAAC,OAAO,CAAI;IACnB,OAAO,CAAC,OAAO,CAAY;IAC3B,OAAO,CAAC,eAAe,CAAC,CAAyB;IACjD,OAAO,CAAC,QAAQ,CAAsC;IAEtD;;;;OAIG;gBACS,QAAQ,EAAE,CAAC,YAAY,EAAE,YAAY,KAAK,GAAG,EAAE,eAAe,CAAC,EAAE,uBAAuB;IAKpG,eAAe,IAAI,YAAY;IAI/B,UAAU,IAAI,MAAM;IAIpB,QAAQ,CAAC,KAAK,EAAE,KAAK,GAAG,MAAM;IAQ9B,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAM7B,OAAO,CAAC,gBAAgB;IAsCxB,kBAAkB,CAAC,QAAQ,CAAC,EAAE,uBAAuB;IAKrD,QAAQ,CAAC,MAAM,EAAE,mBAAmB,EAAE,OAAO,EAAE,MAAM;CAuBtD;AAID;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,EACnC,QAAQ,EACR,gBAAgB,EAChB,WAAW,EACX,qBAAqB,GACtB,EAAE;IAAE,QAAQ,EAAE,GAAG,CAAA;CAAE,GAAG,iBAAiB,2CAiCvC;AAED,wBAAgB,uBAAuB,wBAEtC"}
1
+ {"version":3,"file":"ContextQueryManager.d.ts","sourceRoot":"","sources":["../src/ContextQueryManager.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,EAAE,GAAG,EAAa,OAAO,EAAE,MAAM,MAAM,CAAA;AAE9C,OAAO,EAAE,iBAAiB,EAAE,uBAAuB,EAAW,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA;AAGxH,KAAK,KAAK,GAAG;IAAE,UAAU,EAAE,iBAAiB,CAAC;IAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,mBAAmB,KAAK,IAAI,CAAA;CAAE,CAAA;AAC/F;;GAEG;AACH,KAAK,IAAI,GAAG;IACV,OAAO,EAAE,MAAM,CAAA;IACf,GAAG,EAAE,GAAG,CAAA;IACR,YAAY,EAAE,MAAM,CAAA;IACpB,IAAI,EAAE,SAAS,GAAG,EAAE,CAAA;IACpB,OAAO,EAAE,OAAO,CAAA;CACjB,CAAA;AAED;;GAEG;AACH,KAAK,YAAY,GAAG;IAClB,OAAO,EAAE,MAAM,CAAA;IACf,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC7B,KAAK,EAAE,IAAI,EAAE,CAAA;CACd,CAAA;AAED;;GAEG;AACH,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,OAAO,CAA4B;IAC3C,OAAO,CAAC,aAAa,CAAyB;IAC9C,OAAO,CAAC,UAAU,CAAqD;IACvE,OAAO,CAAC,OAAO,CAAI;IACnB,OAAO,CAAC,OAAO,CAAY;IAC3B,OAAO,CAAC,eAAe,CAAC,CAAyB;IACjD,OAAO,CAAC,QAAQ,CAAsC;IAEtD;;;;OAIG;gBACS,QAAQ,EAAE,CAAC,YAAY,EAAE,YAAY,KAAK,GAAG,EAAE,eAAe,CAAC,EAAE,uBAAuB;IAKpG,eAAe,IAAI,YAAY;IAI/B,UAAU,IAAI,MAAM;IAIpB,QAAQ,CAAC,KAAK,EAAE,KAAK,GAAG,MAAM;IAQ9B,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAM7B,OAAO,CAAC,gBAAgB;IAsCxB,kBAAkB,CAAC,QAAQ,CAAC,EAAE,uBAAuB;IAKrD,QAAQ,CAAC,MAAM,EAAE,mBAAmB,EAAE,OAAO,EAAE,MAAM;CAuBtD;AAID;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,EACnC,QAAQ,EACR,gBAAgB,EAChB,WAAW,EACX,qBAAqB,GACtB,EAAE;IAAE,QAAQ,EAAE,GAAG,CAAA;CAAE,GAAG,iBAAiB,2CAwCvC;AAED,wBAAgB,uBAAuB,wBAEtC"}
@@ -116,7 +116,13 @@ export function ContextQueryProvider({ children, defaultBatchSize, watchBlocks,
116
116
  const queryManager = useMemo(() => new ContextQueryManager(setQuery, addressResolver), []);
117
117
  const [blockNumber, setBlockNumber] = useState();
118
118
  useEffect(() => {
119
- const unsubscribe = onBlockChange((blockNumber) => setBlockNumber(blockNumber));
119
+ const unsubscribe = onBlockChange((block) => {
120
+ // Only set block number if it's a real block (not genesis)
121
+ // This prevents querying at block 0 before the subscription initializes
122
+ if (block > 0n) {
123
+ setBlockNumber(block);
124
+ }
125
+ });
120
126
  return () => {
121
127
  unsubscribe();
122
128
  };
@@ -130,7 +136,8 @@ export function ContextQueryProvider({ children, defaultBatchSize, watchBlocks,
130
136
  notifyOnChangeProps: ['data', 'error'],
131
137
  },
132
138
  batchSize: defaultBatchSize,
133
- blockNumber: blockNumber,
139
+ // Don't pass blockNumber until we have a real one - let wagmi use "latest"
140
+ blockNumber: blockNumber && blockNumber > 0n ? blockNumber : undefined,
134
141
  });
135
142
  useRefetchOnBlockChange(result.refetch, watchBlocks && !!query.calls.length, blocksRefetchInterval);
136
143
  useEffect(() => {
@@ -3,7 +3,7 @@ export declare class BlockSubscriptionManager {
3
3
  private subscribers;
4
4
  private currentBlock;
5
5
  subscribe(callback: Subscriber): () => boolean;
6
- onBlockUptated(newBlock: bigint): void;
6
+ onBlockUpdated(newBlock: bigint): void;
7
7
  }
8
8
  export declare function useBlockNumberSubscriber(): (callback: Subscriber) => () => boolean;
9
9
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"blocksHandler.d.ts","sourceRoot":"","sources":["../src/blocksHandler.ts"],"names":[],"mappings":"AAGA,KAAK,UAAU,GAAG,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,CAAA;AAE/C,qBAAa,wBAAwB;IACnC,OAAO,CAAC,WAAW,CAAwB;IAC3C,OAAO,CAAC,YAAY,CAAa;IAEjC,SAAS,CAAC,QAAQ,EAAE,UAAU;IAO9B,cAAc,CAAC,QAAQ,EAAE,MAAM;CAIhC;AAED,wBAAgB,wBAAwB,eAazB,UAAU,mBAKxB"}
1
+ {"version":3,"file":"blocksHandler.d.ts","sourceRoot":"","sources":["../src/blocksHandler.ts"],"names":[],"mappings":"AAGA,KAAK,UAAU,GAAG,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,CAAA;AAE/C,qBAAa,wBAAwB;IACnC,OAAO,CAAC,WAAW,CAAwB;IAC3C,OAAO,CAAC,YAAY,CAAgC;IAEpD,SAAS,CAAC,QAAQ,EAAE,UAAU;IAS9B,cAAc,CAAC,QAAQ,EAAE,MAAM;CAIhC;AAED,wBAAgB,wBAAwB,eAazB,UAAU,mBAKxB"}
@@ -3,15 +3,17 @@ import { usePublicClient } from 'wagmi';
3
3
  export class BlockSubscriptionManager {
4
4
  constructor() {
5
5
  this.subscribers = new Set();
6
- this.currentBlock = 0n;
6
+ this.currentBlock = undefined;
7
7
  }
8
8
  subscribe(callback) {
9
9
  this.subscribers.add(callback);
10
- // Immediately call with current value
11
- callback(this.currentBlock);
10
+ // Only call immediately if we have a real block number
11
+ if (this.currentBlock !== undefined && this.currentBlock > 0n) {
12
+ callback(this.currentBlock);
13
+ }
12
14
  return () => this.subscribers.delete(callback);
13
15
  }
14
- onBlockUptated(newBlock) {
16
+ onBlockUpdated(newBlock) {
15
17
  this.currentBlock = newBlock;
16
18
  this.subscribers.forEach((sub) => sub(newBlock));
17
19
  }
@@ -22,7 +24,7 @@ export function useBlockNumberSubscriber() {
22
24
  useEffect(() => {
23
25
  return client?.watchBlockNumber({
24
26
  onBlockNumber: (blockNumber) => {
25
- manager.onBlockUptated(blockNumber);
27
+ manager.onBlockUpdated(blockNumber);
26
28
  },
27
29
  });
28
30
  }, [client, manager]);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dappql/react",
3
- "version": "1.0.5",
3
+ "version": "1.0.9",
4
4
  "description": "Streamlined smart contract data fetching library for React dApps with TypeScript support",
5
5
  "author": "DappQL Team",
6
6
  "type": "module",
@@ -28,12 +28,12 @@
28
28
  },
29
29
  "repository": {
30
30
  "type": "git",
31
- "url": "git+https://github.com/dappql/monorepo.git"
31
+ "url": "git+https://github.com/dappql/core.git"
32
32
  },
33
33
  "bugs": {
34
- "url": "https://github.com/dappql/monorepo/issues"
34
+ "url": "https://github.com/dappql/core/issues"
35
35
  },
36
- "homepage": "https://github.com/dappql/monorepo#readme",
36
+ "homepage": "https://github.com/dappql/core#readme",
37
37
  "license": "MIT",
38
38
  "peerDependencies": {
39
39
  "@tanstack/react-query": ">=5.0.0",