@calimero-network/mero-react 1.0.0-beta.1 → 1.1.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 +201 -125
- package/dist/index.cjs +1301 -201
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +296 -31
- package/dist/index.d.ts +296 -31
- package/dist/index.js +1248 -199
- package/dist/index.js.map +1 -1
- package/package.json +24 -10
package/README.md
CHANGED
|
@@ -1,220 +1,296 @@
|
|
|
1
1
|
# @calimero-network/mero-react
|
|
2
2
|
|
|
3
|
-
React bindings for [
|
|
3
|
+
React bindings for [@calimero-network/mero-js](../mero-js) — the Calimero Network SDK.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
- **MeroProvider** - React Context provider that manages MeroJs instance
|
|
8
|
-
- **useMero** - Hook to access MeroJs and authentication state
|
|
9
|
-
- **ConnectButton** - Ready-to-use connection button component
|
|
10
|
-
- **LoginModal** - Modal for node selection (local/remote)
|
|
11
|
-
- **localStorage TokenStorage** - Built-in token persistence
|
|
5
|
+
No UI components. No styled-components. No axios. Just a provider, hooks, and storage helpers.
|
|
12
6
|
|
|
13
7
|
## Installation
|
|
14
8
|
|
|
15
9
|
```bash
|
|
16
|
-
npm install @calimero-network/mero-react @calimero-network/mero-js
|
|
17
|
-
# or
|
|
18
10
|
pnpm add @calimero-network/mero-react @calimero-network/mero-js
|
|
19
11
|
```
|
|
20
12
|
|
|
21
|
-
|
|
13
|
+
Peer dependencies: `react` ^18 || ^19, `react-dom` ^18 || ^19.
|
|
14
|
+
|
|
15
|
+
## Quick start
|
|
22
16
|
|
|
23
17
|
```tsx
|
|
24
|
-
import { MeroProvider,
|
|
18
|
+
import { MeroProvider, useMero, useExecute, useSubscription, AppMode } from '@calimero-network/mero-react';
|
|
25
19
|
|
|
26
20
|
function App() {
|
|
27
21
|
return (
|
|
28
|
-
<MeroProvider
|
|
29
|
-
mode={AppMode.SingleContext}
|
|
30
|
-
packageName="my-app"
|
|
31
|
-
>
|
|
22
|
+
<MeroProvider mode={AppMode.SingleContext} packageName="com.calimero.my-app">
|
|
32
23
|
<MyApp />
|
|
33
24
|
</MeroProvider>
|
|
34
25
|
);
|
|
35
26
|
}
|
|
36
27
|
|
|
37
28
|
function MyApp() {
|
|
38
|
-
const {
|
|
29
|
+
const { isAuthenticated, connectToNode, logout, contextId, contextIdentity } = useMero();
|
|
39
30
|
|
|
40
|
-
if (
|
|
41
|
-
return <
|
|
31
|
+
if (!isAuthenticated) {
|
|
32
|
+
return <button onClick={() => connectToNode('http://localhost:4001')}>Connect</button>;
|
|
42
33
|
}
|
|
43
34
|
|
|
44
|
-
return
|
|
45
|
-
<div>
|
|
46
|
-
<ConnectButton />
|
|
47
|
-
|
|
48
|
-
{isAuthenticated && mero && (
|
|
49
|
-
<Dashboard mero={mero} />
|
|
50
|
-
)}
|
|
51
|
-
</div>
|
|
52
|
-
);
|
|
35
|
+
return <Dashboard />;
|
|
53
36
|
}
|
|
54
37
|
|
|
55
|
-
function Dashboard(
|
|
56
|
-
const
|
|
38
|
+
function Dashboard() {
|
|
39
|
+
const { contextId, contextIdentity } = useMero();
|
|
40
|
+
const { execute, loading } = useExecute(contextId, contextIdentity);
|
|
41
|
+
const [items, setItems] = useState([]);
|
|
57
42
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
43
|
+
// Real-time updates via SSE
|
|
44
|
+
useSubscription(
|
|
45
|
+
contextId ? [contextId] : [],
|
|
46
|
+
() => fetchItems(),
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
const fetchItems = async () => {
|
|
50
|
+
const data = await execute('list');
|
|
51
|
+
if (data) setItems(data);
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
const addItem = async (title: string) => {
|
|
55
|
+
await execute('add', { title });
|
|
56
|
+
await fetchItems();
|
|
57
|
+
};
|
|
63
58
|
|
|
64
59
|
return (
|
|
65
|
-
<
|
|
66
|
-
{
|
|
67
|
-
|
|
68
|
-
))}
|
|
69
|
-
</
|
|
60
|
+
<div>
|
|
61
|
+
{loading && <p>Loading...</p>}
|
|
62
|
+
{items.map(item => <div key={item.id}>{item.title}</div>)}
|
|
63
|
+
<button onClick={() => addItem('New item')}>Add</button>
|
|
64
|
+
</div>
|
|
70
65
|
);
|
|
71
66
|
}
|
|
72
67
|
```
|
|
73
68
|
|
|
74
|
-
##
|
|
69
|
+
## API reference
|
|
70
|
+
|
|
71
|
+
### `<MeroProvider>`
|
|
72
|
+
|
|
73
|
+
Wraps your app with a MeroJs instance, auth state, and SSE connectivity.
|
|
75
74
|
|
|
76
75
|
```tsx
|
|
77
76
|
<MeroProvider
|
|
78
|
-
//
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
// Package-based (recommended)
|
|
82
|
-
packageName="@my-org/my-app"
|
|
83
|
-
packageVersion="1.0.0" // optional, defaults to latest
|
|
84
|
-
registryUrl="https://registry.calimero.network" // optional
|
|
85
|
-
|
|
86
|
-
// OR Legacy: Application ID
|
|
87
|
-
applicationId="app-hash-id"
|
|
88
|
-
applicationPath="/my-app"
|
|
89
|
-
|
|
90
|
-
// Optional
|
|
91
|
-
eventStreamMode={EventStreamMode.WebSocket | EventStreamMode.SSE}
|
|
92
|
-
timeoutMs={30000}
|
|
77
|
+
mode={AppMode.SingleContext} // required
|
|
78
|
+
packageName="com.calimero.my-app" // for package-based apps
|
|
79
|
+
timeoutMs={30000} // optional, default 30s
|
|
93
80
|
>
|
|
94
81
|
{children}
|
|
95
82
|
</MeroProvider>
|
|
96
83
|
```
|
|
97
84
|
|
|
98
|
-
|
|
85
|
+
Props (`MeroProviderConfig & { children }`):
|
|
86
|
+
|
|
87
|
+
| Prop | Type | Required | Description |
|
|
88
|
+
|------|------|----------|-------------|
|
|
89
|
+
| `mode` | `AppMode` | Yes | `SingleContext`, `MultiContext`, or `Admin` |
|
|
90
|
+
| `packageName` | `string` | No | Package name for registry/node lookup |
|
|
91
|
+
| `packageVersion` | `string` | No | Specific version (defaults to latest) |
|
|
92
|
+
| `registryUrl` | `string` | No | Registry URL override |
|
|
93
|
+
| `timeoutMs` | `number` | No | HTTP request timeout (default 30000) |
|
|
94
|
+
|
|
95
|
+
Modes and their permissions:
|
|
99
96
|
|
|
100
|
-
| Mode | Permissions | Use
|
|
97
|
+
| Mode | Permissions | Use case |
|
|
101
98
|
|------|-------------|----------|
|
|
102
99
|
| `SingleContext` | `context:execute` | Apps that work with one context |
|
|
103
100
|
| `MultiContext` | `context:create`, `context:list`, `context:execute` | Apps managing multiple contexts |
|
|
104
101
|
| `Admin` | `admin` | Admin dashboards, dev tools |
|
|
105
102
|
|
|
106
|
-
|
|
103
|
+
Auth flow: when `connectToNode(url)` is called, the provider redirects to the node's auth page. After login, the node redirects back with tokens in the URL hash. The provider processes these once (StrictMode-safe via ref) and sets `isAuthenticated = true`.
|
|
104
|
+
|
|
105
|
+
Online detection: the provider opens an SSE connection to the node after auth. `isOnline` reflects the SSE connection state — no polling.
|
|
106
|
+
|
|
107
|
+
### `useMero()`
|
|
108
|
+
|
|
109
|
+
Access the MeroJs instance, auth state, and actions.
|
|
107
110
|
|
|
108
111
|
```tsx
|
|
109
112
|
const {
|
|
110
|
-
mero,
|
|
111
|
-
isAuthenticated,
|
|
112
|
-
isOnline,
|
|
113
|
-
isLoading,
|
|
114
|
-
nodeUrl,
|
|
115
|
-
applicationId,
|
|
116
|
-
|
|
117
|
-
|
|
113
|
+
mero, // MeroJs | null — the SDK instance
|
|
114
|
+
isAuthenticated, // boolean
|
|
115
|
+
isOnline, // boolean — SSE connection state
|
|
116
|
+
isLoading, // boolean — initial session restore
|
|
117
|
+
nodeUrl, // string | null
|
|
118
|
+
applicationId, // string | null — resolved from auth callback
|
|
119
|
+
contextId, // string | null — from auth callback
|
|
120
|
+
contextIdentity, // string | null — executor public key from auth callback
|
|
121
|
+
connectToNode, // (url: string) => void — starts auth redirect
|
|
122
|
+
logout, // () => void — clears tokens and state
|
|
118
123
|
} = useMero();
|
|
119
124
|
```
|
|
120
125
|
|
|
121
|
-
|
|
126
|
+
Through `mero` you access the full MeroJs API:
|
|
122
127
|
|
|
123
128
|
```tsx
|
|
124
|
-
|
|
129
|
+
// Admin API (flat methods, NOT nested)
|
|
130
|
+
await mero.admin.healthCheck();
|
|
131
|
+
await mero.admin.getContexts();
|
|
132
|
+
await mero.admin.getContext(contextId);
|
|
133
|
+
await mero.admin.getContextIdentitiesOwned(contextId);
|
|
134
|
+
await mero.admin.listApplications();
|
|
135
|
+
await mero.admin.getApplication(appId);
|
|
136
|
+
await mero.admin.installApplication(request);
|
|
137
|
+
await mero.admin.createContext(request);
|
|
138
|
+
await mero.admin.uploadBlob(request);
|
|
139
|
+
await mero.admin.getPeersCount();
|
|
140
|
+
|
|
141
|
+
// Auth API
|
|
142
|
+
await mero.auth.getProviders();
|
|
143
|
+
await mero.auth.generateTokens(request);
|
|
144
|
+
await mero.auth.refreshToken(request);
|
|
125
145
|
|
|
126
|
-
//
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
// Only remote
|
|
130
|
-
<ConnectButton connectionType={ConnectionType.Remote} />
|
|
146
|
+
// RPC
|
|
147
|
+
await mero.rpc.execute({ contextId, method, argsJson, executorPublicKey });
|
|
131
148
|
|
|
132
|
-
//
|
|
133
|
-
|
|
149
|
+
// SSE events
|
|
150
|
+
mero.events.connect();
|
|
151
|
+
mero.events.subscribe(contextIds);
|
|
152
|
+
mero.events.on('event', handler);
|
|
134
153
|
|
|
135
|
-
//
|
|
136
|
-
|
|
154
|
+
// Tokens
|
|
155
|
+
mero.getTokenData(); // { access_token, refresh_token, expires_at } | null
|
|
156
|
+
mero.isAuthenticated(); // boolean
|
|
137
157
|
```
|
|
138
158
|
|
|
139
|
-
|
|
159
|
+
### `useExecute(contextId, executorId)`
|
|
140
160
|
|
|
141
|
-
|
|
161
|
+
Wraps `mero.rpc.execute()` with loading/error state. Unmount-safe.
|
|
142
162
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
--mero-error: #ff4d4d;
|
|
151
|
-
/* ... see styles.css for all variables */
|
|
152
|
-
}
|
|
163
|
+
```tsx
|
|
164
|
+
const { execute, loading, error } = useExecute(contextId, contextIdentity);
|
|
165
|
+
|
|
166
|
+
// Generic typed
|
|
167
|
+
const todos = await execute<Todo[]>('list');
|
|
168
|
+
await execute('add', { title: 'Buy milk' });
|
|
169
|
+
await execute('toggle', { id: '1' });
|
|
153
170
|
```
|
|
154
171
|
|
|
155
|
-
|
|
172
|
+
| Return | Type | Description |
|
|
173
|
+
|--------|------|-------------|
|
|
174
|
+
| `execute` | `<T>(method, params?) => Promise<T \| null>` | Call a contract method |
|
|
175
|
+
| `loading` | `boolean` | Request in flight |
|
|
176
|
+
| `error` | `Error \| null` | Last error |
|
|
177
|
+
|
|
178
|
+
### `useSubscription(contextIds, callback)`
|
|
179
|
+
|
|
180
|
+
Manages SSE event subscription lifecycle. StrictMode-safe — connects once per MeroJs instance, cleans up on unmount.
|
|
181
|
+
|
|
156
182
|
```tsx
|
|
157
|
-
|
|
183
|
+
useSubscription(
|
|
184
|
+
contextId ? [contextId] : [],
|
|
185
|
+
(event) => {
|
|
186
|
+
console.log('Context event:', event.contextId, event.data);
|
|
187
|
+
refreshData();
|
|
188
|
+
},
|
|
189
|
+
);
|
|
158
190
|
```
|
|
159
191
|
|
|
160
|
-
|
|
192
|
+
| Param | Type | Description |
|
|
193
|
+
|-------|------|-------------|
|
|
194
|
+
| `contextIds` | `string[]` | Context IDs to subscribe to (empty array = no subscription) |
|
|
195
|
+
| `callback` | `(event: SseEventData) => void` | Called on each context event |
|
|
161
196
|
|
|
162
|
-
|
|
197
|
+
The SSE connection is shared — multiple `useSubscription` hooks reuse the same connection. The first one to mount calls `connect()`, subsequent ones just add handlers.
|
|
163
198
|
|
|
164
|
-
|
|
199
|
+
### `useContexts(applicationId?)`
|
|
200
|
+
|
|
201
|
+
Fetches contexts from the node, optionally filtered by application ID.
|
|
202
|
+
|
|
203
|
+
```tsx
|
|
204
|
+
const { contexts, loading, error, refetch } = useContexts(applicationId);
|
|
205
|
+
|
|
206
|
+
// contexts: Array<{ contextId: string; applicationId: string }>
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
### Storage helpers
|
|
210
|
+
|
|
211
|
+
Persist/read node URL, application ID, context ID, and context identity in localStorage.
|
|
165
212
|
|
|
166
213
|
```tsx
|
|
167
214
|
import {
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
setNodeUrl,
|
|
171
|
-
getApplicationId,
|
|
215
|
+
getNodeUrl, setNodeUrl, clearNodeUrl,
|
|
216
|
+
getApplicationId, setApplicationId, clearApplicationId,
|
|
172
217
|
clearAllStorage,
|
|
173
218
|
} from '@calimero-network/mero-react';
|
|
174
|
-
|
|
175
|
-
// localStorageTokenStorage implements MeroJs TokenStorage interface
|
|
176
|
-
// It's automatically used by MeroProvider
|
|
177
219
|
```
|
|
178
220
|
|
|
179
|
-
|
|
221
|
+
These are used internally by `MeroProvider` but exported for apps that need direct access.
|
|
180
222
|
|
|
181
|
-
|
|
223
|
+
### Re-exports from mero-js
|
|
224
|
+
|
|
225
|
+
mero-react re-exports everything from mero-js via `export * from '@calimero-network/mero-js'`. Any new API added to mero-js is automatically available from mero-react — no manual sync needed.
|
|
182
226
|
|
|
183
227
|
```tsx
|
|
184
|
-
|
|
228
|
+
// All of these work from a single import
|
|
229
|
+
import {
|
|
230
|
+
MeroProvider, useMero, useExecute, useSubscription, // react
|
|
231
|
+
MeroJs, RpcClient, SseClient, WsClient, // core
|
|
232
|
+
parseAuthCallback, buildAuthLoginUrl, // auth helpers
|
|
233
|
+
LocalStorageTokenStore, MemoryTokenStore, // token stores
|
|
234
|
+
} from '@calimero-network/mero-react';
|
|
235
|
+
```
|
|
185
236
|
|
|
186
|
-
|
|
187
|
-
await mero.admin.applications.listApplications();
|
|
188
|
-
await mero.admin.contexts.createContext({ applicationId, ... });
|
|
189
|
-
await mero.admin.blobs.uploadBlob(file);
|
|
237
|
+
## Enums
|
|
190
238
|
|
|
191
|
-
|
|
192
|
-
await mero.auth.getHealth();
|
|
193
|
-
await mero.auth.refreshToken();
|
|
239
|
+
```tsx
|
|
194
240
|
|
|
195
|
-
//
|
|
196
|
-
|
|
241
|
+
AppMode.SingleContext // 'single-context'
|
|
242
|
+
AppMode.MultiContext // 'multi-context'
|
|
243
|
+
AppMode.Admin // 'admin'
|
|
197
244
|
|
|
198
|
-
//
|
|
199
|
-
|
|
245
|
+
ConnectionType.Custom // 'custom'
|
|
246
|
+
ConnectionType.Local // 'local'
|
|
247
|
+
ConnectionType.Remote // 'remote'
|
|
200
248
|
|
|
201
|
-
// SSE subscriptions
|
|
202
|
-
mero.sse.subscribe(contextId, onEvent);
|
|
203
249
|
```
|
|
204
250
|
|
|
205
|
-
##
|
|
206
|
-
|
|
207
|
-
Full TypeScript support:
|
|
251
|
+
## Types
|
|
208
252
|
|
|
209
253
|
```tsx
|
|
210
254
|
import type {
|
|
211
|
-
MeroContextValue,
|
|
212
|
-
MeroProviderConfig,
|
|
213
|
-
|
|
214
|
-
|
|
255
|
+
MeroContextValue, // useMero() return type
|
|
256
|
+
MeroProviderConfig, // MeroProvider props (without children)
|
|
257
|
+
MeroProviderProps, // MeroProvider props (with children)
|
|
258
|
+
CustomConnectionConfig,// { type: ConnectionType.Custom, url: string }
|
|
259
|
+
AppContext, // { contextId, executorId, applicationId }
|
|
260
|
+
ExecutionResult, // { success, result?, error? }
|
|
215
261
|
} from '@calimero-network/mero-react';
|
|
216
262
|
```
|
|
217
263
|
|
|
264
|
+
## Full exports list
|
|
265
|
+
|
|
266
|
+
```
|
|
267
|
+
// Provider & hooks (mero-react)
|
|
268
|
+
MeroProvider, useMero, MeroContext
|
|
269
|
+
useExecute, useSubscription, useContexts
|
|
270
|
+
|
|
271
|
+
// Enums (mero-react)
|
|
272
|
+
|
|
273
|
+
// Types (mero-react)
|
|
274
|
+
MeroContextValue, MeroProviderConfig, MeroProviderProps
|
|
275
|
+
CustomConnectionConfig, AppContext, ExecutionResult
|
|
276
|
+
|
|
277
|
+
// Storage (mero-react)
|
|
278
|
+
localStorageTokenStorage
|
|
279
|
+
getNodeUrl, setNodeUrl, clearNodeUrl
|
|
280
|
+
getApplicationId, setApplicationId, clearApplicationId
|
|
281
|
+
clearAllStorage
|
|
282
|
+
|
|
283
|
+
// Everything from @calimero-network/mero-js (auto re-exported)
|
|
284
|
+
MeroJs, createMeroJs, MeroJsConfig, TokenData
|
|
285
|
+
RpcClient, RpcError, ExecuteParams
|
|
286
|
+
SseClient, SseEventData, WsClient, WsEventData
|
|
287
|
+
AuthApiClient, AdminApiClient
|
|
288
|
+
LocalStorageTokenStore, MemoryTokenStore, TokenStore
|
|
289
|
+
parseAuthCallback, buildAuthLoginUrl, AuthCallbackResult, AuthLoginOptions
|
|
290
|
+
WebHttpClient, HttpClient, HTTPError
|
|
291
|
+
// ...and all other mero-js exports
|
|
292
|
+
```
|
|
293
|
+
|
|
218
294
|
## License
|
|
219
295
|
|
|
220
296
|
MIT
|