@calimero-network/mero-js 7.0.3 → 7.0.4

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.
Files changed (2) hide show
  1. package/README.md +85 -456
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -1,120 +1,21 @@
1
- # Mero.js - Pure JavaScript SDK for Calimero
1
+ # Mero.js — Pure JavaScript SDK for Calimero
2
2
 
3
- A lightweight, universal JavaScript SDK for Calimero that works in both browser and Node.js environments using Web Standards.
3
+ A lightweight, universal JavaScript/TypeScript SDK for [Calimero](https://calimero-network.github.io/core/).
4
+ Authenticate to a node, drive the admin API, execute WASM methods over JSON-RPC,
5
+ and stream real-time events — from the browser, Node, Deno, Bun, or edge
6
+ runtimes. Zero runtime dependencies; built entirely on Web Platform APIs
7
+ (`fetch`, `WebSocket`, `AbortController`).
4
8
 
5
- > **🚨 Breaking Change (v1.0.0)**: This version removes all legacy Axios-based code. The package now uses only Web Standards (`fetch`, `AbortController`) with zero external dependencies.
9
+ ## Documentation
6
10
 
7
- ## Features
11
+ Full documentation is published at
12
+ **<https://calimero-network.github.io/mero-js/>** — quickstart, guides, and the
13
+ complete API reference (`MeroJs`, admin API, auth API, RPC, events, cloud,
14
+ capabilities, and the error model). The source lives under [`docs/`](docs/).
8
15
 
9
- - 🌐 **Web Standards First**: Built on `fetch`, `AbortController`, and other Web APIs
10
- - 🔄 **Universal**: Works in browsers, Node.js, and edge runtimes
11
- - 📦 **Zero Dependencies**: No external dependencies, uses native Web APIs
12
- - 🔧 **Dependency Injection**: Flexible and testable architecture
13
- - ⚡ **Modern**: ES2020+ with TypeScript support
14
- - 🛡️ **Type Safe**: Full TypeScript definitions
15
- - 🔄 **Smart Retry**: Distinguishes user aborts vs timeouts for intelligent retry logic
16
- - 🎯 **Advanced Cancellation**: Signal combination and proper timeout handling
17
-
18
- ## Behavior
19
-
20
- ### Error Model (Throwing)
21
-
22
- The client **throws** `HTTPError` on any `!response.ok` status. Network/timeout/abort errors are re-thrown as-is:
23
-
24
- ```typescript
25
- try {
26
- const data = await httpClient.get('/api/data');
27
- // Success - data is the parsed response
28
- } catch (error) {
29
- if (error instanceof HTTPError) {
30
- console.log(`HTTP ${error.status}: ${error.statusText}`);
31
- console.log('URL:', error.url);
32
- console.log('Headers:', error.headers);
33
- console.log('Body:', error.bodyText); // Up to 64KB
34
- } else if (error.name === 'TimeoutError') {
35
- // Request timed out
36
- } else if (error.name === 'AbortError') {
37
- // Request was cancelled
38
- }
39
- }
40
- ```
41
-
42
- ### Parsing Defaults & Override
43
-
44
- Each method accepts optional `{ parse?: 'json'|'text'|'blob'|'arrayBuffer'|'response' }`:
45
-
46
- **Default parsing rules:**
47
-
48
- - `Content-Type: application/json` → parse as JSON
49
- - `Content-Type: text/*` → parse as text
50
- - Other types → parse as `arrayBuffer`
51
-
52
- **Override:**
53
-
54
- ```typescript
55
- // Get raw Response object
56
- const response = await httpClient.get('/api/data', { parse: 'response' });
57
- ```
58
-
59
- ### Retry Policy (`withRetry`)
60
-
61
- The `withRetry` helper retries on:
62
-
63
- - `HTTPError` with status `429` or `>= 500`
64
- - `TimeoutError` (internal timeouts)
65
- - `TypeError` (network failures)
66
-
67
- **Never retries:**
68
-
69
- - `AbortError` (user/caller aborts)
70
-
71
- ```typescript
72
- import { withRetry } from '@calimero-network/mero-js';
73
-
74
- const data = await withRetry(
75
- (attempt) => httpClient.get('/api/data'),
76
- { attempts: 3 }, // Default: 3 attempts
77
- );
78
- ```
79
-
80
- ### Signal Composition
81
-
82
- The client combines caller signals with internal timeouts:
83
-
84
- ```typescript
85
- const userSignal = new AbortController().signal;
86
- const data = await httpClient.get('/api/data', {
87
- signal: userSignal,
88
- timeoutMs: 5000,
89
- });
90
- ```
91
-
92
- ### Header Precedence & Authorization
93
-
94
- - **Caller headers win**: Request-level headers override client defaults
95
- - **Authorization rules**: Only set `Authorization: Bearer ${token}` if caller didn't provide any `authorization` header (case-insensitive)
96
-
97
- ### FormData Handling
98
-
99
- For `FormData` bodies, the client does **not** set `content-type` (lets browser/undici add the boundary):
100
-
101
- ```typescript
102
- const formData = new FormData();
103
- formData.append('file', file);
104
- await httpClient.post('/api/upload', formData);
105
- // No content-type header is set by the client
106
- ```
107
-
108
- ### Credentials
109
-
110
- No implicit `same-origin` default. Credentials are only set if explicitly provided:
111
-
112
- ```typescript
113
- const client = createBrowserHttpClient({
114
- baseUrl: 'https://api.example.com',
115
- credentials: 'include', // Only if you want to include credentials
116
- });
117
- ```
16
+ > **Not React?** This is a framework-agnostic SDK. React bindings live in the
17
+ > separate [`@calimero-network/mero-react`](https://github.com/calimero-network/mero-react)
18
+ > package.
118
19
 
119
20
  ## Installation
120
21
 
@@ -122,376 +23,103 @@ const client = createBrowserHttpClient({
122
23
  npm install @calimero-network/mero-js
123
24
  ```
124
25
 
125
- ## Quick Start
26
+ Requires Node.js 18+ (native `fetch`) or any modern browser. The package ships
27
+ ESM, CommonJS, and a minified browser build, is side-effect-free (tree-shakeable),
28
+ and includes its own TypeScript declarations.
126
29
 
127
- ### Browser Usage
30
+ ## Quick start
128
31
 
129
32
  ```typescript
130
- import { createBrowserHttpClient } from '@calimero-network/mero-js';
33
+ import { createMeroJs, HTTPError, RpcError } from '@calimero-network/mero-js';
131
34
 
132
- const httpClient = createBrowserHttpClient({
133
- baseUrl: 'https://api.calimero.network',
134
- getAuthToken: async () => localStorage.getItem('access_token'),
135
- onTokenRefresh: async (newToken) =>
136
- localStorage.setItem('access_token', newToken),
137
- });
138
-
139
- // Make requests
140
- try {
141
- const data = await httpClient.get<{ message: string }>('/api/hello');
142
- console.log(data.message);
143
- } catch (error) {
144
- console.error('Request failed:', error);
145
- }
146
- ```
147
-
148
- ### Node.js Usage
149
-
150
- ```typescript
151
- import { createNodeHttpClient } from '@calimero-network/mero-js';
152
- // For Node.js < 18, install undici: npm install undici
153
- import { fetch as undiciFetch } from 'undici';
154
-
155
- const httpClient = createNodeHttpClient({
156
- baseUrl: 'https://api.calimero.network',
157
- fetch: undiciFetch, // Required for Node.js < 18
158
- getAuthToken: async () => process.env.ACCESS_TOKEN,
35
+ const sdk = createMeroJs({
36
+ baseUrl: 'http://localhost:2528',
37
+ // timeoutMs defaults to 10000; pass a tokenStore to persist auth
159
38
  });
160
39
 
161
- const data = await httpClient.get<{ message: string }>('/api/hello');
162
- console.log(data.message);
163
- ```
164
-
165
- ### Universal Usage
166
-
167
- ```typescript
168
- import { createUniversalHttpClient } from '@calimero-network/mero-js';
169
-
170
- const httpClient = createUniversalHttpClient({
171
- baseUrl: 'https://api.calimero.network',
172
- getAuthToken: async () => {
173
- return typeof window !== 'undefined'
174
- ? localStorage.getItem('access_token')
175
- : process.env.ACCESS_TOKEN;
176
- },
177
- });
178
- ```
179
-
180
- ## API Reference
181
-
182
- ### Factory Functions
183
-
184
- #### `createBrowserHttpClient(options)`
185
-
186
- Creates an HTTP client optimized for browser environments.
40
+ // Authenticate (username/password against the node's auth service)
41
+ await sdk.authenticate({ username: 'dev', password: 'dev' });
187
42
 
188
- #### `createNodeHttpClient(options)`
43
+ // Admin API — list this node's contexts
44
+ const { contexts } = await sdk.admin.getContexts(); // ContextWithGroup[]
45
+ console.log(`found ${contexts.length} contexts`);
189
46
 
190
- Creates an HTTP client for Node.js environments.
191
-
192
- #### `createUniversalHttpClient(options)`
193
-
194
- Creates an HTTP client that works in both browser and Node.js.
195
-
196
- ### Options
197
-
198
- ```typescript
199
- interface HttpClientOptions {
200
- baseUrl: string; // Base URL for all requests
201
- fetch?: typeof fetch; // Custom fetch implementation (Node.js)
202
- getAuthToken?: () => Promise<string | undefined>; // Token getter
203
- onTokenRefresh?: (token: string) => Promise<void>; // Token refresh callback
204
- defaultHeaders?: Record<string, string>; // Default headers
205
- timeoutMs?: number; // Request timeout (default: 30000)
206
- credentials?: RequestCredentials; // CORS credentials (default: 'same-origin' for browser)
207
- defaultAbortSignal?: AbortSignal; // Default abort signal for all requests
208
- }
209
- ```
210
-
211
- ### HTTP Methods
212
-
213
- ```typescript
214
- // GET request
215
- const response = await httpClient.get<T>('/api/endpoint', init?);
216
-
217
- // POST request
218
- const response = await httpClient.post<T>('/api/endpoint', body?, init?);
219
-
220
- // PUT request
221
- const response = await httpClient.put<T>('/api/endpoint', body?, init?);
222
-
223
- // DELETE request
224
- const response = await httpClient.delete<T>('/api/endpoint', init?);
225
-
226
- // PATCH request
227
- const response = await httpClient.patch<T>('/api/endpoint', body?, init?);
228
-
229
- // HEAD request
230
- const response = await httpClient.head<T>('/api/endpoint', init?);
231
-
232
- // Generic request
233
- const response = await httpClient.request<T>('/api/endpoint', init?);
234
- ```
235
-
236
- ### Request Options
237
-
238
- ```typescript
239
- interface RequestOptions extends RequestInit {
240
- parse?: 'json' | 'text' | 'blob' | 'arrayBuffer' | 'response';
241
- timeoutMs?: number;
242
- }
243
- ```
244
-
245
- ### Response Format
246
-
247
- All methods return the parsed data directly or throw errors:
248
-
249
- ```typescript
250
- // Success - returns parsed data
251
- const data: T = await httpClient.get<T>('/api/data');
252
-
253
- // Error - throws HTTPError or other errors
47
+ // Execute a context method over JSON-RPC
254
48
  try {
255
- const data = await httpClient.get('/api/data');
256
- } catch (error) {
257
- if (error instanceof HTTPError) {
258
- console.log(`HTTP ${error.status}: ${error.statusText}`);
259
- console.log('URL:', error.url);
260
- console.log('Headers:', error.headers);
261
- console.log('Body:', error.bodyText);
262
- }
49
+ const value = await sdk.rpc.execute<string>({
50
+ contextId: contexts[0].id,
51
+ method: 'get_value',
52
+ argsJson: { key: 'greeting' },
53
+ });
54
+ console.log(value);
55
+ } catch (err) {
56
+ if (err instanceof RpcError) console.error(`contract error ${err.code}: ${err.message}`);
57
+ else if (err instanceof HTTPError) console.error(`HTTP ${err.status}: ${err.statusText}`);
58
+ else throw err;
263
59
  }
264
- ```
265
-
266
- ## Advanced Usage
267
-
268
- ### Custom Transport
269
-
270
- ```typescript
271
- import { createHttpClient, Transport } from '@calimero-network/mero-js';
272
-
273
- const transport: Transport = {
274
- fetch: customFetch,
275
- baseUrl: 'https://api.example.com',
276
- getAuthToken: async () => 'your-token',
277
- timeoutMs: 5000,
278
- };
279
-
280
- const httpClient = createHttpClient(transport);
281
- ```
282
-
283
- ### Error Handling
284
-
285
- ```typescript
286
- try {
287
- const data = await httpClient.get('/api/data');
288
- // Success - data is the parsed response
289
- console.log(data);
290
- } catch (error) {
291
- if (error instanceof HTTPError) {
292
- // HTTP error (4xx, 5xx)
293
- console.error(`HTTP ${error.status}: ${error.statusText}`);
294
- console.error('URL:', error.url);
295
- console.error('Body:', error.bodyText);
296
- } else if (error.name === 'TimeoutError') {
297
- // Request timed out
298
- console.error('Request timed out');
299
- } else if (error.name === 'AbortError') {
300
- // Request was cancelled
301
- console.error('Request was cancelled');
302
- } else {
303
- // Network or other errors
304
- console.error('Request failed:', error);
305
- }
306
- }
307
- ```
308
-
309
- ### Custom Headers
310
-
311
- ```typescript
312
- const data = await httpClient.post('/api/data', body, {
313
- headers: {
314
- 'Content-Type': 'application/json',
315
- 'X-Custom-Header': 'value',
316
- },
317
- });
318
- ```
319
-
320
- ### Request Cancellation
321
-
322
- ```typescript
323
- const abortController = new AbortController();
324
-
325
- // Cancel request after 5 seconds
326
- setTimeout(() => abortController.abort(), 5000);
327
-
328
- const data = await httpClient.get('/api/slow-endpoint', {
329
- signal: abortController.signal,
330
- });
331
- ```
332
-
333
- ### FormData Support
334
-
335
- ```typescript
336
- const formData = new FormData();
337
- formData.append('file', fileInput.files[0]);
338
- formData.append('name', 'John Doe');
339
-
340
- const data = await httpClient.post('/api/upload', formData);
341
- // Content-Type is set by the browser/undici with proper boundary
342
- ```
343
-
344
- ### Response Parsing
345
-
346
- ```typescript
347
- // Explicit parsing
348
- const jsonData = await httpClient.get('/api/data', { parse: 'json' });
349
- const textData = await httpClient.get('/api/text', { parse: 'text' });
350
- const blobData = await httpClient.get('/api/file', { parse: 'blob' });
351
60
 
352
- // Auto-detection based on Content-Type (default)
353
- const autoData = await httpClient.get('/api/data');
354
- ```
355
-
356
- ### Retry with Exponential Backoff
357
-
358
- ```typescript
359
- import { withRetry } from '@calimero-network/mero-js';
360
-
361
- const data = await withRetry(
362
- (attempt) => httpClient.get('/api/unreliable-endpoint'),
363
- { attempts: 3 }, // Default: 3 attempts
364
- );
365
- ```
61
+ // Stream real-time context events (SSE)
62
+ sdk.events.on('event', (e) => console.log(e.contextId, e.type, e.data));
63
+ await sdk.events.connect();
64
+ await sdk.events.subscribe([contexts[0].id]);
366
65
 
367
- ### Signal Combination
368
-
369
- ```typescript
370
- import { combineSignals, createTimeoutSignal } from '@calimero-network/mero-js';
371
-
372
- // Combine multiple abort signals
373
- const userSignal = new AbortController().signal;
374
- const timeoutSignal = createTimeoutSignal(5000);
375
- const combinedSignal = combineSignals([userSignal, timeoutSignal]);
376
-
377
- const data = await httpClient.get('/api/endpoint', {
378
- signal: combinedSignal,
379
- });
66
+ // Tear down open connections when done
67
+ sdk.close();
380
68
  ```
381
69
 
382
- ### CORS and Credentials
383
-
384
- ```typescript
385
- const httpClient = createBrowserHttpClient({
386
- baseUrl: 'https://api.example.com',
387
- credentials: 'include', // Include cookies in CORS requests
388
- });
389
-
390
- // For APIs that require credentials
391
- const data = await httpClient.get('/api/protected', {
392
- credentials: 'include',
393
- });
394
- ```
395
-
396
- ## Migration from Axios
397
-
398
- If you're migrating from an Axios-based client:
399
-
400
- 1. **Replace imports**: Use the factory functions instead of direct class instantiation
401
- 2. **Update method signatures**: Methods now use `RequestInit` instead of custom options
402
- 3. **Handle responses**: Methods now return parsed data directly or throw errors (no more `ResponseData<T>`)
403
- 4. **Token management**: Use the `getAuthToken` and `onTokenRefresh` callbacks
404
-
405
- ## Browser Support
70
+ `sdk.auth`, `sdk.admin`, `sdk.rpc`, `sdk.events` (SSE) and `sdk.ws` (experimental
71
+ WebSocket) are all reachable from the one `MeroJs` instance. See the
72
+ [quickstart](https://calimero-network.github.io/mero-js/get-started/quickstart/)
73
+ and [authentication guide](https://calimero-network.github.io/mero-js/get-started/authentication/)
74
+ for token persistence and the refresh lifecycle.
406
75
 
407
- - Modern browsers with `fetch` support (Chrome 42+, Firefox 39+, Safari 10.1+)
408
- - Node.js 18+ (native fetch) or Node.js 16+ with `undici`
76
+ ## Error model
409
77
 
410
- ## Bundle Sizes
78
+ Every failure surfaces as a typed error:
411
79
 
412
- - **ESM**: ~9.4kb (gzipped: ~3.2kb)
413
- - **CJS**: ~10.5kb (gzipped: ~3.6kb)
80
+ - **`HTTPError`** — a non-2xx response. Network failures, timeouts, and
81
+ cancellations are also wrapped as `HTTPError` with **`status: 0`** (the
82
+ underlying `AbortError`/`TimeoutError` is not propagated).
83
+ - **`AuthRevokedError`** (extends `HTTPError`) — the refresh token was reused or
84
+ revoked; the session is over. The SDK has already cleared its tokens.
85
+ - **`RpcError`** — the WASM contract returned a JSON-RPC error (`code`, `message`,
86
+ optional `type`/`data`).
414
87
 
415
- ## Examples
88
+ `401`s are handled internally: the SDK refreshes the token and retries once, so
89
+ you only see a `401` if the refresh itself fails. Full details in the
90
+ [error model reference](https://calimero-network.github.io/mero-js/reference/error-model/).
416
91
 
417
- See the `examples/` directory for complete usage examples:
92
+ ## Lower-level HTTP client
418
93
 
419
- - `browser-example.ts` - Browser-specific usage (designed for browser environments)
420
- - `node-example.ts` - Node.js-specific usage (designed for Node.js environments)
421
- - `universal-example.ts` - Universal usage (works in both browser and Node.js)
94
+ If you need raw HTTP against a node (without the `MeroJs` facade), the SDK
95
+ exports composable clients — `createBrowserHttpClient`, `createNodeHttpClient`,
96
+ `createUniversalHttpClient`, `createHttpClient` — plus `withRetry`,
97
+ `combineSignals`, and `createTimeoutSignal`:
422
98
 
423
- **Note**: Run `npm run build` before running the examples, as they import from the built library.
424
-
425
- ## Admin API
426
-
427
- The `AdminApiClient` provides methods for managing Calimero node resources:
428
-
429
- ### Namespaces (application instances)
430
- ```typescript
431
- const namespaces = await admin.listNamespaces();
432
- const identity = await admin.getNamespaceIdentity(namespaceId);
433
- const appNamespaces = await admin.listNamespacesForApplication(appId);
434
- ```
435
-
436
- ### Groups (governance boundaries)
437
99
  ```typescript
438
- const groups = await admin.listGroups();
439
- const group = await admin.createGroup({ applicationId: '...' });
440
- const info = await admin.getGroupInfo(groupId);
441
- const members = await admin.listGroupMembers(groupId);
442
- const contexts = await admin.listGroupContexts(groupId);
443
- ```
444
-
445
- ### Contexts (WASM execution instances)
446
- ```typescript
447
- // Single-service app
448
- const ctx = await admin.createContext({ applicationId: '...' });
100
+ import { createBrowserHttpClient } from '@calimero-network/mero-js';
449
101
 
450
- // Multi-service app -- specify which service to run
451
- const ctx = await admin.createContext({
452
- applicationId: '...',
453
- serviceName: 'chat',
102
+ const http = createBrowserHttpClient({
103
+ baseUrl: 'https://node.example.com',
104
+ getAuthToken: async () => localStorage.getItem('access_token') ?? undefined,
454
105
  });
455
- ```
456
106
 
457
- ### Blobs
458
- ```typescript
459
- const { blobs } = await admin.listBlobs(); // [{ blobId, size }, ...] metadata
460
- const info = await admin.getBlobInfo(blobId); // { blobId, size, hash, mimeType } via HEAD (no download)
461
- const bytes = await admin.getBlob(blobId); // ArrayBuffer — the raw blob content
462
- await admin.deleteBlob(blobId);
463
- ```
464
- > `getBlob` returns the **raw bytes** as an `ArrayBuffer` (the endpoint streams the
465
- > blob, e.g. `application/gzip`, not JSON). Use `listBlobs()` for `{ blobId, size }`
466
- > metadata.
467
-
468
- ### Group settings (TEE admission policy)
469
- ```typescript
470
- await admin.setTeeAdmissionPolicy(groupId, policy);
471
- const current = await admin.getTeeAdmissionPolicy(groupId); // allowed MRTD/RTMR sets, acceptMock, ...
107
+ const data = await http.get<{ message: string }>('/api/hello');
472
108
  ```
473
109
 
474
- ### Cloud (TEE High Availability)
475
- ```typescript
476
- import { CloudClient } from '@calimero-network/mero-js';
477
- const cloud = new CloudClient();
478
- cloud.enableHA({ groupId, contextId, redirectUrl });
479
- ```
110
+ Methods (`get`/`post`/`put`/`delete`/`patch`/`head`/`request`) return parsed data
111
+ directly and support per-call `{ signal, timeoutMs, parse }`. See the
112
+ [HTTP transport guide](https://calimero-network.github.io/mero-js/guides/http-transport/)
113
+ for options, parsing rules, retries, and cancellation.
480
114
 
481
115
  ## Development
482
116
 
483
117
  ```bash
484
- # Install dependencies
485
118
  pnpm install
486
-
487
- # Build
488
119
  pnpm build
489
-
490
- # Test (unit)
491
- pnpm test
492
-
493
- # Lint
120
+ pnpm test # unit tests (mocked, fast)
494
121
  pnpm lint
122
+ pnpm typecheck
495
123
  ```
496
124
 
497
125
  ### Testing & the contract gate
@@ -499,8 +127,8 @@ pnpm lint
499
127
  The SDK mirrors core's HTTP wire types by hand, so two layers guard against drift:
500
128
 
501
129
  - **Unit tests** (`pnpm test`) — mocked, fast, cover the client logic.
502
- - **E2E** (`pnpm test:e2e`) — runs the real SDK against a live `merod`. Point it at a
503
- node and provide credentials:
130
+ - **E2E** (`pnpm test:e2e`) — runs the real SDK against a live `merod`. Point it
131
+ at a node and provide credentials:
504
132
  ```bash
505
133
  NODE_URL=http://localhost:2528 MERO_E2E_USER=dev MERO_E2E_PASS=dev pnpm test:e2e
506
134
  ```
@@ -508,11 +136,12 @@ The SDK mirrors core's HTTP wire types by hand, so two layers guard against drif
508
136
  PR-built `merod` (core's `sdk-e2e`).
509
137
 
510
138
  The e2e records every request as `METHOD /path` (see `tests/e2e/coverage-recorder.ts`).
511
- Core's route-coverage gate is **method-aware**: it fails if any admin route *or verb*
512
- ships without an SDK test — so e.g. `GET /blobs/:id` can't hide behind `DELETE /blobs/:id`.
513
- When you add an SDK method for a new endpoint, exercise it in the e2e (the sweep in
514
- `tests/e2e/coverage-sweep.test.ts` is the catch-all) so coverage stays complete.
139
+ Core's route-coverage gate is **method-aware**: it fails if any admin route *or
140
+ verb* ships without an SDK test — so e.g. `GET /blobs/:id` can't hide behind
141
+ `DELETE /blobs/:id`. When you add an SDK method for a new endpoint, exercise it in
142
+ the e2e (the sweep in `tests/e2e/coverage-sweep.test.ts` is the catch-all) so
143
+ coverage stays complete.
515
144
 
516
145
  ## License
517
146
 
518
- MIT
147
+ MIT — see [LICENSE](LICENSE).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@calimero-network/mero-js",
3
- "version": "7.0.3",
3
+ "version": "7.0.4",
4
4
  "description": "Pure JavaScript SDK for Calimero",
5
5
  "type": "module",
6
6
  "exports": {