cantonjs-react 0.0.1 → 0.3.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.
- package/README.md +213 -0
- package/package.json +4 -2
package/README.md
ADDED
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
# cantonjs-react
|
|
2
|
+
|
|
3
|
+
React hooks for Canton Network dApps, powered by [TanStack Query](https://tanstack.com/query).
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/cantonjs-react)
|
|
6
|
+
[](https://github.com/merged-one/cantonjs/blob/main/LICENSE)
|
|
7
|
+
|
|
8
|
+
## Install
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
npm install cantonjs cantonjs-react @tanstack/react-query
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Quick Start
|
|
15
|
+
|
|
16
|
+
```tsx
|
|
17
|
+
import { CantonProvider, useContracts, useCreateContract } from 'cantonjs-react'
|
|
18
|
+
import { createLedgerClient, jsonApi } from 'cantonjs'
|
|
19
|
+
|
|
20
|
+
const client = createLedgerClient({
|
|
21
|
+
transport: jsonApi({ url: 'http://localhost:7575', token: jwt }),
|
|
22
|
+
actAs: 'Alice::1234',
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
function App() {
|
|
26
|
+
return (
|
|
27
|
+
<CantonProvider client={client}>
|
|
28
|
+
<AssetList />
|
|
29
|
+
</CantonProvider>
|
|
30
|
+
)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function AssetList() {
|
|
34
|
+
const { data: assets, isLoading } = useContracts({
|
|
35
|
+
templateId: '#my-pkg:Main:Asset',
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
const { mutate: create, isPending } = useCreateContract({
|
|
39
|
+
templateId: '#my-pkg:Main:Asset',
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
if (isLoading) return <div>Loading...</div>
|
|
43
|
+
|
|
44
|
+
return (
|
|
45
|
+
<div>
|
|
46
|
+
<button
|
|
47
|
+
disabled={isPending}
|
|
48
|
+
onClick={() => create({ createArguments: { owner: 'Alice', value: 100 } })}
|
|
49
|
+
>
|
|
50
|
+
Create Asset
|
|
51
|
+
</button>
|
|
52
|
+
<ul>
|
|
53
|
+
{assets?.map(c => (
|
|
54
|
+
<li key={c.createdEvent.contractId}>
|
|
55
|
+
{JSON.stringify(c.createdEvent.createArgument)}
|
|
56
|
+
</li>
|
|
57
|
+
))}
|
|
58
|
+
</ul>
|
|
59
|
+
</div>
|
|
60
|
+
)
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Public Scan Data Alongside Ledger Hooks
|
|
65
|
+
|
|
66
|
+
`cantonjs-react` stays focused on participant-private ledger state. For public Splice data, use TanStack Query directly with `cantonjs-splice-scan`:
|
|
67
|
+
|
|
68
|
+
```tsx
|
|
69
|
+
import { useQuery } from '@tanstack/react-query'
|
|
70
|
+
import { useContracts } from 'cantonjs-react'
|
|
71
|
+
import { createScanClient } from 'cantonjs-splice-scan'
|
|
72
|
+
|
|
73
|
+
const scan = createScanClient({
|
|
74
|
+
url: import.meta.env.VITE_SPLICE_SCAN_URL,
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
function NetworkDashboard() {
|
|
78
|
+
const { data: dso } = useQuery({
|
|
79
|
+
queryKey: ['scan', 'dso'],
|
|
80
|
+
queryFn: () => scan.getDsoInfo(),
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
const { data: assets } = useContracts({
|
|
84
|
+
templateId: '#my-pkg:Main:Asset',
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
return (
|
|
88
|
+
<div>
|
|
89
|
+
<pre>{JSON.stringify(dso, null, 2)}</pre>
|
|
90
|
+
<pre>{JSON.stringify(assets, null, 2)}</pre>
|
|
91
|
+
</div>
|
|
92
|
+
)
|
|
93
|
+
}
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
This keeps public Scan reads and party-private ledger reads clearly separated. See [`../../docs/examples/react.md`](../../docs/examples/react.md) for the full example.
|
|
97
|
+
|
|
98
|
+
## Hooks
|
|
99
|
+
|
|
100
|
+
### `useContracts(options)`
|
|
101
|
+
|
|
102
|
+
Query active contracts with automatic caching and deduplication.
|
|
103
|
+
|
|
104
|
+
```tsx
|
|
105
|
+
const { data, isLoading, error } = useContracts({
|
|
106
|
+
templateId: '#my-pkg:Main:Asset',
|
|
107
|
+
enabled: true, // optional, default true
|
|
108
|
+
refetchInterval: 5000, // optional, auto-refetch in ms
|
|
109
|
+
})
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### `useCreateContract(options)`
|
|
113
|
+
|
|
114
|
+
Mutation hook for creating contracts. Automatically invalidates related queries on success.
|
|
115
|
+
|
|
116
|
+
```tsx
|
|
117
|
+
const { mutate: create, isPending, error } = useCreateContract({
|
|
118
|
+
templateId: '#my-pkg:Main:Asset',
|
|
119
|
+
onSuccess: (event) => console.log('Created:', event.contractId),
|
|
120
|
+
})
|
|
121
|
+
|
|
122
|
+
create({ createArguments: { owner: 'Alice', value: 100 } })
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### `useExercise(options)`
|
|
126
|
+
|
|
127
|
+
Mutation hook for exercising choices. Automatically invalidates related queries on success.
|
|
128
|
+
|
|
129
|
+
```tsx
|
|
130
|
+
const { mutate: exercise, isPending } = useExercise({
|
|
131
|
+
templateId: '#my-pkg:Main:Asset',
|
|
132
|
+
choice: 'Transfer',
|
|
133
|
+
})
|
|
134
|
+
|
|
135
|
+
exercise({
|
|
136
|
+
contractId: 'contract-id',
|
|
137
|
+
choiceArgument: { newOwner: 'Bob' },
|
|
138
|
+
})
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### `useStreamContracts(options)`
|
|
142
|
+
|
|
143
|
+
Polling-based live contract updates (5-second interval).
|
|
144
|
+
|
|
145
|
+
```tsx
|
|
146
|
+
const { contracts, isLoading, error } = useStreamContracts({
|
|
147
|
+
templateId: '#my-pkg:Main:Asset',
|
|
148
|
+
enabled: true, // optional
|
|
149
|
+
})
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### `useCantonClient()`
|
|
153
|
+
|
|
154
|
+
Access the `LedgerClient` directly for advanced use cases.
|
|
155
|
+
|
|
156
|
+
```tsx
|
|
157
|
+
const client = useCantonClient()
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### `useParty()`
|
|
161
|
+
|
|
162
|
+
Get the current `actAs` party identity.
|
|
163
|
+
|
|
164
|
+
```tsx
|
|
165
|
+
const party = useParty()
|
|
166
|
+
// 'Alice::1234'
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
## Provider
|
|
170
|
+
|
|
171
|
+
Wrap your app with `CantonProvider`. Optionally pass a custom `QueryClient`:
|
|
172
|
+
|
|
173
|
+
```tsx
|
|
174
|
+
import { QueryClient } from '@tanstack/react-query'
|
|
175
|
+
|
|
176
|
+
const queryClient = new QueryClient({
|
|
177
|
+
defaultOptions: { queries: { staleTime: 10_000 } },
|
|
178
|
+
})
|
|
179
|
+
|
|
180
|
+
<CantonProvider client={ledgerClient} queryClient={queryClient}>
|
|
181
|
+
<App />
|
|
182
|
+
</CantonProvider>
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
## Cache Invalidation
|
|
186
|
+
|
|
187
|
+
Mutations automatically invalidate contract queries for the same template:
|
|
188
|
+
|
|
189
|
+
- `useCreateContract` invalidates `['canton', 'contracts', templateId]`
|
|
190
|
+
- `useExercise` invalidates `['canton', 'contracts', templateId]`
|
|
191
|
+
|
|
192
|
+
This means `useContracts` queries refresh automatically after mutations complete.
|
|
193
|
+
|
|
194
|
+
## Peer Dependencies
|
|
195
|
+
|
|
196
|
+
| Package | Version |
|
|
197
|
+
|---------|---------|
|
|
198
|
+
| `react` | ^18.0.0 \|\| ^19.0.0 |
|
|
199
|
+
| `@tanstack/react-query` | ^5.0.0 |
|
|
200
|
+
|
|
201
|
+
## Requirements
|
|
202
|
+
|
|
203
|
+
- Node.js >= 18
|
|
204
|
+
- React 18 or 19
|
|
205
|
+
|
|
206
|
+
## Related
|
|
207
|
+
|
|
208
|
+
- [cantonjs](https://github.com/merged-one/cantonjs) — Core TypeScript library for Canton
|
|
209
|
+
- [cantonjs-codegen](https://github.com/merged-one/cantonjs/tree/main/packages/cantonjs-codegen) — DAR-to-TypeScript code generation
|
|
210
|
+
|
|
211
|
+
## License
|
|
212
|
+
|
|
213
|
+
[Apache-2.0](https://github.com/merged-one/cantonjs/blob/main/LICENSE)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cantonjs-react",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "React hooks for Canton Network dApps — built on cantonjs",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
"typecheck": "tsc --noEmit",
|
|
12
12
|
"test": "vitest run",
|
|
13
13
|
"test:watch": "vitest",
|
|
14
|
+
"test:coverage": "node ../../scripts/verify-coverage-exclusions.mjs && vitest run --coverage",
|
|
14
15
|
"lint": "eslint src",
|
|
15
16
|
"clean": "rm -rf dist",
|
|
16
17
|
"prepublishOnly": "npm run clean && npm run build"
|
|
@@ -35,7 +36,7 @@
|
|
|
35
36
|
},
|
|
36
37
|
"peerDependencies": {
|
|
37
38
|
"@tanstack/react-query": "^5.0.0",
|
|
38
|
-
"cantonjs": "^0.0
|
|
39
|
+
"cantonjs": "^0.3.0",
|
|
39
40
|
"react": "^18.0.0 || ^19.0.0"
|
|
40
41
|
},
|
|
41
42
|
"peerDependenciesMeta": {
|
|
@@ -48,6 +49,7 @@
|
|
|
48
49
|
"@testing-library/dom": "^10.4.1",
|
|
49
50
|
"@testing-library/react": "^16.0.0",
|
|
50
51
|
"@types/react": "^18.0.0",
|
|
52
|
+
"@vitest/coverage-v8": "^3.0.0",
|
|
51
53
|
"jsdom": "^29.0.1",
|
|
52
54
|
"react": "^18.0.0",
|
|
53
55
|
"react-dom": "^18.0.0",
|