@calimero-network/mero-js 2.0.0-beta.1 → 2.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/README.md +358 -341
- package/dist/admin-api/admin-client.d.ts +90 -0
- package/dist/admin-api/admin-client.d.ts.map +1 -0
- package/dist/admin-api/admin-client.js +302 -0
- package/dist/admin-api/admin-client.js.map +1 -0
- package/dist/admin-api/admin-factory.d.ts +8 -0
- package/dist/admin-api/admin-factory.d.ts.map +1 -0
- package/dist/admin-api/admin-factory.js +42 -0
- package/dist/admin-api/admin-factory.js.map +1 -0
- package/dist/admin-api/admin-types.d.ts +497 -0
- package/dist/admin-api/admin-types.d.ts.map +1 -0
- package/dist/admin-api/admin-types.js +4 -0
- package/dist/admin-api/admin-types.js.map +1 -0
- package/dist/admin-api/index.d.ts +4 -0
- package/dist/admin-api/index.d.ts.map +1 -0
- package/dist/admin-api/index.js +5 -0
- package/dist/admin-api/index.js.map +1 -0
- package/dist/auth/index.d.ts +26 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +51 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/auth-api/auth-client.d.ts +34 -0
- package/dist/auth-api/auth-client.d.ts.map +1 -0
- package/dist/auth-api/auth-client.js +112 -0
- package/dist/auth-api/auth-client.js.map +1 -0
- package/dist/auth-api/auth-factory.d.ts +8 -0
- package/dist/auth-api/auth-factory.d.ts.map +1 -0
- package/dist/auth-api/auth-factory.js +42 -0
- package/dist/auth-api/auth-factory.js.map +1 -0
- package/dist/auth-api/auth-types.d.ts +127 -0
- package/dist/auth-api/auth-types.d.ts.map +1 -0
- package/dist/auth-api/auth-types.js +3 -0
- package/dist/auth-api/auth-types.js.map +1 -0
- package/dist/auth-api/index.d.ts +4 -0
- package/dist/auth-api/index.d.ts.map +1 -0
- package/dist/auth-api/index.js +5 -0
- package/dist/auth-api/index.js.map +1 -0
- package/dist/cloud/cloud-client.d.ts +20 -0
- package/dist/cloud/cloud-client.d.ts.map +1 -0
- package/dist/cloud/cloud-client.js +26 -0
- package/dist/cloud/cloud-client.js.map +1 -0
- package/dist/cloud/index.d.ts +3 -0
- package/dist/cloud/index.d.ts.map +1 -0
- package/dist/cloud/index.js +2 -0
- package/dist/cloud/index.js.map +1 -0
- package/dist/events/index.d.ts +5 -0
- package/dist/events/index.d.ts.map +1 -0
- package/dist/events/index.js +3 -0
- package/dist/events/index.js.map +1 -0
- package/dist/events/sse.d.ts +41 -0
- package/dist/events/sse.d.ts.map +1 -0
- package/dist/events/sse.js +237 -0
- package/dist/events/sse.js.map +1 -0
- package/dist/events/ws.d.ts +42 -0
- package/dist/events/ws.d.ts.map +1 -0
- package/dist/events/ws.js +178 -0
- package/dist/events/ws.js.map +1 -0
- package/dist/http-client/api-response.d.ts +16 -0
- package/dist/http-client/api-response.d.ts.map +1 -0
- package/dist/http-client/api-response.js +2 -0
- package/dist/http-client/api-response.js.map +1 -0
- package/dist/http-client/index.d.ts +1 -1
- package/dist/http-client/index.d.ts.map +1 -1
- package/dist/http-client/index.js +1 -2
- package/dist/http-client/index.js.map +1 -1
- package/dist/http-client/web-client.d.ts +3 -3
- package/dist/http-client/web-client.d.ts.map +1 -1
- package/dist/http-client/web-client.js +6 -18
- package/dist/http-client/web-client.js.map +1 -1
- package/dist/index.browser.mjs +2 -1
- package/dist/index.browser.mjs.map +4 -4
- package/dist/index.cjs +1033 -1415
- package/dist/index.cjs.map +4 -4
- package/dist/index.d.ts +12 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +15 -7
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1032 -1420
- package/dist/index.mjs.map +4 -4
- package/dist/mero-js.d.ts +44 -189
- package/dist/mero-js.d.ts.map +1 -1
- package/dist/mero-js.js +139 -314
- package/dist/mero-js.js.map +1 -1
- package/dist/rpc/index.d.ts +22 -0
- package/dist/rpc/index.d.ts.map +1 -0
- package/dist/rpc/index.js +38 -0
- package/dist/rpc/index.js.map +1 -0
- package/dist/token-store/index.d.ts +20 -0
- package/dist/token-store/index.d.ts.map +1 -0
- package/dist/token-store/index.js +62 -0
- package/dist/token-store/index.js.map +1 -0
- package/package.json +7 -42
- package/dist/api/admin/aliases.d.ts +0 -54
- package/dist/api/admin/aliases.d.ts.map +0 -1
- package/dist/api/admin/aliases.js +0 -43
- package/dist/api/admin/aliases.js.map +0 -1
- package/dist/api/admin/applications.d.ts +0 -52
- package/dist/api/admin/applications.d.ts.map +0 -1
- package/dist/api/admin/applications.js +0 -31
- package/dist/api/admin/applications.js.map +0 -1
- package/dist/api/admin/blobs.d.ts +0 -24
- package/dist/api/admin/blobs.d.ts.map +0 -1
- package/dist/api/admin/blobs.js +0 -58
- package/dist/api/admin/blobs.js.map +0 -1
- package/dist/api/admin/capabilities.d.ts +0 -26
- package/dist/api/admin/capabilities.d.ts.map +0 -1
- package/dist/api/admin/capabilities.js +0 -13
- package/dist/api/admin/capabilities.js.map +0 -1
- package/dist/api/admin/client.d.ts +0 -63
- package/dist/api/admin/client.d.ts.map +0 -1
- package/dist/api/admin/client.js +0 -103
- package/dist/api/admin/client.js.map +0 -1
- package/dist/api/admin/contexts.d.ts +0 -110
- package/dist/api/admin/contexts.d.ts.map +0 -1
- package/dist/api/admin/contexts.js +0 -61
- package/dist/api/admin/contexts.js.map +0 -1
- package/dist/api/admin/factory.d.ts +0 -4
- package/dist/api/admin/factory.d.ts.map +0 -1
- package/dist/api/admin/factory.js +0 -5
- package/dist/api/admin/factory.js.map +0 -1
- package/dist/api/admin/identity.d.ts +0 -10
- package/dist/api/admin/identity.d.ts.map +0 -1
- package/dist/api/admin/identity.js +0 -10
- package/dist/api/admin/identity.js.map +0 -1
- package/dist/api/admin/index.d.ts +0 -23
- package/dist/api/admin/index.d.ts.map +0 -1
- package/dist/api/admin/index.js +0 -26
- package/dist/api/admin/index.js.map +0 -1
- package/dist/api/admin/network.d.ts +0 -10
- package/dist/api/admin/network.d.ts.map +0 -1
- package/dist/api/admin/network.js +0 -9
- package/dist/api/admin/network.js.map +0 -1
- package/dist/api/admin/proposals.d.ts +0 -49
- package/dist/api/admin/proposals.d.ts.map +0 -1
- package/dist/api/admin/proposals.js +0 -34
- package/dist/api/admin/proposals.js.map +0 -1
- package/dist/api/admin/public.d.ts +0 -15
- package/dist/api/admin/public.d.ts.map +0 -1
- package/dist/api/admin/public.js +0 -18
- package/dist/api/admin/public.js.map +0 -1
- package/dist/api/admin/tee.d.ts +0 -74
- package/dist/api/admin/tee.d.ts.map +0 -1
- package/dist/api/admin/tee.js +0 -16
- package/dist/api/admin/tee.js.map +0 -1
- package/dist/api/auth/client.d.ts +0 -55
- package/dist/api/auth/client.d.ts.map +0 -1
- package/dist/api/auth/client.js +0 -127
- package/dist/api/auth/client.js.map +0 -1
- package/dist/api/auth/factory.d.ts +0 -4
- package/dist/api/auth/factory.d.ts.map +0 -1
- package/dist/api/auth/factory.js +0 -5
- package/dist/api/auth/factory.js.map +0 -1
- package/dist/api/auth/index.d.ts +0 -4
- package/dist/api/auth/index.d.ts.map +0 -1
- package/dist/api/auth/index.js +0 -4
- package/dist/api/auth/index.js.map +0 -1
- package/dist/api/auth/types.d.ts +0 -94
- package/dist/api/auth/types.d.ts.map +0 -1
- package/dist/api/auth/types.js +0 -4
- package/dist/api/auth/types.js.map +0 -1
- package/dist/api/index.d.ts +0 -15
- package/dist/api/index.d.ts.map +0 -1
- package/dist/api/index.js +0 -18
- package/dist/api/index.js.map +0 -1
- package/dist/api/rpc/client.d.ts +0 -76
- package/dist/api/rpc/client.d.ts.map +0 -1
- package/dist/api/rpc/client.js +0 -126
- package/dist/api/rpc/client.js.map +0 -1
- package/dist/api/rpc/index.d.ts +0 -3
- package/dist/api/rpc/index.d.ts.map +0 -1
- package/dist/api/rpc/index.js +0 -2
- package/dist/api/rpc/index.js.map +0 -1
- package/dist/api/rpc/types.d.ts +0 -74
- package/dist/api/rpc/types.d.ts.map +0 -1
- package/dist/api/rpc/types.js +0 -6
- package/dist/api/rpc/types.js.map +0 -1
- package/dist/api/sse/client.d.ts +0 -76
- package/dist/api/sse/client.d.ts.map +0 -1
- package/dist/api/sse/client.js +0 -203
- package/dist/api/sse/client.js.map +0 -1
- package/dist/api/sse/index.d.ts +0 -4
- package/dist/api/sse/index.d.ts.map +0 -1
- package/dist/api/sse/index.js +0 -2
- package/dist/api/sse/index.js.map +0 -1
- package/dist/api/sse/types.d.ts +0 -35
- package/dist/api/sse/types.d.ts.map +0 -1
- package/dist/api/sse/types.js +0 -6
- package/dist/api/sse/types.js.map +0 -1
- package/dist/api/utils.d.ts +0 -68
- package/dist/api/utils.d.ts.map +0 -1
- package/dist/api/utils.js +0 -83
- package/dist/api/utils.js.map +0 -1
- package/dist/api/ws/client.d.ts +0 -72
- package/dist/api/ws/client.d.ts.map +0 -1
- package/dist/api/ws/client.js +0 -202
- package/dist/api/ws/client.js.map +0 -1
- package/dist/api/ws/index.d.ts +0 -4
- package/dist/api/ws/index.d.ts.map +0 -1
- package/dist/api/ws/index.js +0 -2
- package/dist/api/ws/index.js.map +0 -1
- package/dist/api/ws/types.d.ts +0 -32
- package/dist/api/ws/types.d.ts.map +0 -1
- package/dist/api/ws/types.js +0 -6
- package/dist/api/ws/types.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,464 +1,481 @@
|
|
|
1
|
-
# Mero.js
|
|
1
|
+
# Mero.js - Pure JavaScript SDK for Calimero
|
|
2
2
|
|
|
3
|
-
A lightweight, universal JavaScript SDK for
|
|
3
|
+
A lightweight, universal JavaScript SDK for Calimero that works in both browser and Node.js environments using Web Standards.
|
|
4
|
+
|
|
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.
|
|
4
6
|
|
|
5
7
|
## Features
|
|
6
8
|
|
|
7
|
-
- 🌐 **
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
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
|
|
15
17
|
|
|
16
|
-
##
|
|
18
|
+
## Behavior
|
|
17
19
|
|
|
18
|
-
|
|
19
|
-
npm install @calimero-network/mero-js
|
|
20
|
-
# or
|
|
21
|
-
pnpm add @calimero-network/mero-js
|
|
22
|
-
```
|
|
20
|
+
### Error Model (Throwing)
|
|
23
21
|
|
|
24
|
-
|
|
22
|
+
The client **throws** `HTTPError` on any `!response.ok` status. Network/timeout/abort errors are re-thrown as-is:
|
|
25
23
|
|
|
26
24
|
```typescript
|
|
27
|
-
|
|
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
|
+
```
|
|
28
41
|
|
|
29
|
-
|
|
30
|
-
baseUrl: 'http://localhost:2428',
|
|
31
|
-
credentials: {
|
|
32
|
-
username: 'admin',
|
|
33
|
-
password: 'your-password',
|
|
34
|
-
},
|
|
35
|
-
});
|
|
42
|
+
### Parsing Defaults & Override
|
|
36
43
|
|
|
37
|
-
|
|
38
|
-
await mero.authenticate();
|
|
44
|
+
Each method accepts optional `{ parse?: 'json'|'text'|'blob'|'arrayBuffer'|'response' }`:
|
|
39
45
|
|
|
40
|
-
|
|
41
|
-
const apps = await mero.admin.applications.listApplications();
|
|
42
|
-
const contexts = await mero.admin.contexts.listContexts();
|
|
46
|
+
**Default parsing rules:**
|
|
43
47
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
'get',
|
|
48
|
-
{ key: 'myKey' },
|
|
49
|
-
'ed25519:executor-public-key'
|
|
50
|
-
);
|
|
51
|
-
```
|
|
48
|
+
- `Content-Type: application/json` → parse as JSON
|
|
49
|
+
- `Content-Type: text/*` → parse as text
|
|
50
|
+
- Other types → parse as `arrayBuffer`
|
|
52
51
|
|
|
53
|
-
|
|
52
|
+
**Override:**
|
|
54
53
|
|
|
55
|
-
|
|
54
|
+
```typescript
|
|
55
|
+
// Get raw Response object
|
|
56
|
+
const response = await httpClient.get('/api/data', { parse: 'response' });
|
|
57
|
+
```
|
|
56
58
|
|
|
57
|
-
###
|
|
59
|
+
### Retry Policy (`withRetry`)
|
|
58
60
|
|
|
59
|
-
|
|
60
|
-
const mero = new MeroJs({
|
|
61
|
-
baseUrl: 'http://localhost:2428',
|
|
62
|
-
credentials: { username: 'admin', password: 'password' },
|
|
63
|
-
tokenStorage: {
|
|
64
|
-
async get() {
|
|
65
|
-
const data = localStorage.getItem('mero-token');
|
|
66
|
-
return data ? JSON.parse(data) : null;
|
|
67
|
-
},
|
|
68
|
-
async set(token) {
|
|
69
|
-
localStorage.setItem('mero-token', JSON.stringify(token));
|
|
70
|
-
},
|
|
71
|
-
async clear() {
|
|
72
|
-
localStorage.removeItem('mero-token');
|
|
73
|
-
},
|
|
74
|
-
},
|
|
75
|
-
});
|
|
61
|
+
The `withRetry` helper retries on:
|
|
76
62
|
|
|
77
|
-
|
|
78
|
-
|
|
63
|
+
- `HTTPError` with status `429` or `>= 500`
|
|
64
|
+
- `TimeoutError` (internal timeouts)
|
|
65
|
+
- `TypeError` (network failures)
|
|
79
66
|
|
|
80
|
-
|
|
81
|
-
await mero.authenticate();
|
|
82
|
-
}
|
|
83
|
-
```
|
|
67
|
+
**Never retries:**
|
|
84
68
|
|
|
85
|
-
|
|
69
|
+
- `AbortError` (user/caller aborts)
|
|
86
70
|
|
|
87
71
|
```typescript
|
|
88
|
-
import
|
|
89
|
-
|
|
90
|
-
const
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
async get() {
|
|
95
|
-
const data = await AsyncStorage.getItem('mero-token');
|
|
96
|
-
return data ? JSON.parse(data) : null;
|
|
97
|
-
},
|
|
98
|
-
async set(token) {
|
|
99
|
-
await AsyncStorage.setItem('mero-token', JSON.stringify(token));
|
|
100
|
-
},
|
|
101
|
-
async clear() {
|
|
102
|
-
await AsyncStorage.removeItem('mero-token');
|
|
103
|
-
},
|
|
104
|
-
},
|
|
105
|
-
});
|
|
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
|
+
);
|
|
106
78
|
```
|
|
107
79
|
|
|
108
|
-
###
|
|
80
|
+
### Signal Composition
|
|
81
|
+
|
|
82
|
+
The client combines caller signals with internal timeouts:
|
|
109
83
|
|
|
110
84
|
```typescript
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
const mero = new MeroJs({
|
|
116
|
-
baseUrl: 'http://localhost:2428',
|
|
117
|
-
requestCredentials: 'omit', // Required for Tauri
|
|
118
|
-
tokenStorage: {
|
|
119
|
-
async get() {
|
|
120
|
-
return await store.get('mero-token');
|
|
121
|
-
},
|
|
122
|
-
async set(token) {
|
|
123
|
-
await store.set('mero-token', token);
|
|
124
|
-
await store.save();
|
|
125
|
-
},
|
|
126
|
-
async clear() {
|
|
127
|
-
await store.delete('mero-token');
|
|
128
|
-
await store.save();
|
|
129
|
-
},
|
|
130
|
-
},
|
|
85
|
+
const userSignal = new AbortController().signal;
|
|
86
|
+
const data = await httpClient.get('/api/data', {
|
|
87
|
+
signal: userSignal,
|
|
88
|
+
timeoutMs: 5000,
|
|
131
89
|
});
|
|
132
90
|
```
|
|
133
91
|
|
|
134
|
-
|
|
92
|
+
### Header Precedence & Authorization
|
|
135
93
|
|
|
136
|
-
|
|
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)
|
|
137
96
|
|
|
138
|
-
|
|
139
|
-
2. **Reactive** — On 401 with `x-auth-error: token_expired`, automatically refreshes and retries
|
|
97
|
+
### FormData Handling
|
|
140
98
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
│ │ │ │
|
|
149
|
-
│ │ no (within 5min) │
|
|
150
|
-
│ │ │ │
|
|
151
|
-
│ │ ▼ │
|
|
152
|
-
│ │ Refresh token │
|
|
153
|
-
│ │ │ │
|
|
154
|
-
│ 401 + expired ─────┼─────────┘ │
|
|
155
|
-
│ │ │
|
|
156
|
-
│ clearToken() ──────┼──> Token cleared │
|
|
157
|
-
└─────────────────────────────────────────────────┘
|
|
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
|
|
158
106
|
```
|
|
159
107
|
|
|
160
|
-
|
|
108
|
+
### Credentials
|
|
161
109
|
|
|
162
|
-
|
|
110
|
+
No implicit `same-origin` default. Credentials are only set if explicitly provided:
|
|
163
111
|
|
|
164
112
|
```typescript
|
|
165
|
-
|
|
166
|
-
baseUrl:
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
requestCredentials?: RequestCredentials;
|
|
171
|
-
tokenStorage?: TokenStorage; // For persistence
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
const mero = new MeroJs(config);
|
|
175
|
-
|
|
176
|
-
// Lifecycle
|
|
177
|
-
await mero.init(); // Load tokens from storage
|
|
178
|
-
await mero.authenticate(); // Get new tokens
|
|
179
|
-
await mero.clearToken(); // Clear tokens
|
|
180
|
-
mero.isAuthenticated(); // Check auth status
|
|
181
|
-
mero.getTokenData(); // Get current tokens
|
|
113
|
+
const client = createBrowserHttpClient({
|
|
114
|
+
baseUrl: 'https://api.example.com',
|
|
115
|
+
credentials: 'include', // Only if you want to include credentials
|
|
116
|
+
});
|
|
117
|
+
```
|
|
182
118
|
|
|
183
|
-
|
|
184
|
-
mero.auth // Auth API
|
|
185
|
-
mero.admin // Admin API
|
|
186
|
-
mero.rpc // JSON-RPC client
|
|
119
|
+
## Installation
|
|
187
120
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
mero.createSse(); // SSE client
|
|
121
|
+
```bash
|
|
122
|
+
npm install @calimero-network/mero-js
|
|
191
123
|
```
|
|
192
124
|
|
|
193
|
-
|
|
125
|
+
## Quick Start
|
|
126
|
+
|
|
127
|
+
### Browser Usage
|
|
194
128
|
|
|
195
129
|
```typescript
|
|
196
|
-
|
|
197
|
-
await mero.admin.applications.listApplications();
|
|
198
|
-
await mero.admin.applications.getApplication(appId);
|
|
199
|
-
await mero.admin.applications.installApplication({ url, metadata });
|
|
200
|
-
await mero.admin.applications.uninstallApplication(appId);
|
|
201
|
-
|
|
202
|
-
// Contexts
|
|
203
|
-
await mero.admin.contexts.listContexts();
|
|
204
|
-
await mero.admin.contexts.createContext({ applicationId, contextSeed });
|
|
205
|
-
await mero.admin.contexts.getContext(contextId);
|
|
206
|
-
await mero.admin.contexts.deleteContext(contextId);
|
|
207
|
-
await mero.admin.contexts.joinContext({ contextId, invitationPayload });
|
|
208
|
-
|
|
209
|
-
// Blobs
|
|
210
|
-
await mero.admin.blobs.listBlobs();
|
|
211
|
-
await mero.admin.blobs.uploadBlob(data);
|
|
212
|
-
await mero.admin.blobs.getBlob(blobId);
|
|
213
|
-
await mero.admin.blobs.deleteBlob(blobId);
|
|
214
|
-
|
|
215
|
-
// Identity
|
|
216
|
-
await mero.admin.identity.generateContextIdentity();
|
|
217
|
-
|
|
218
|
-
// Network
|
|
219
|
-
await mero.admin.network.getPeersCount();
|
|
220
|
-
|
|
221
|
-
// Public (no auth required)
|
|
222
|
-
await mero.admin.public.health();
|
|
223
|
-
await mero.admin.public.isAuthed();
|
|
224
|
-
```
|
|
130
|
+
import { createBrowserHttpClient } from '@calimero-network/mero-js';
|
|
225
131
|
|
|
226
|
-
|
|
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
|
+
});
|
|
227
138
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
await
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
await mero.auth.getToken(request);
|
|
236
|
-
await mero.auth.refreshToken({ refresh_token });
|
|
237
|
-
await mero.auth.validateToken({ token });
|
|
238
|
-
|
|
239
|
-
// Keys
|
|
240
|
-
await mero.auth.listRootKeys();
|
|
241
|
-
await mero.auth.createRootKey(request);
|
|
242
|
-
await mero.auth.deleteRootKey(publicKey);
|
|
243
|
-
await mero.auth.listClientKeys();
|
|
244
|
-
await mero.auth.generateClientKey(request);
|
|
245
|
-
await mero.auth.deleteClientKey(publicKey);
|
|
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
|
+
}
|
|
246
146
|
```
|
|
247
147
|
|
|
248
|
-
###
|
|
148
|
+
### Node.js Usage
|
|
249
149
|
|
|
250
150
|
```typescript
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
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,
|
|
159
|
+
});
|
|
258
160
|
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
'set',
|
|
263
|
-
{ key: 'myKey', value: 'myValue' },
|
|
264
|
-
'ed25519:executor-public-key'
|
|
265
|
-
);
|
|
161
|
+
const data = await httpClient.get<{ message: string }>('/api/hello');
|
|
162
|
+
console.log(data.message);
|
|
163
|
+
```
|
|
266
164
|
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
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
|
+
},
|
|
273
177
|
});
|
|
274
178
|
```
|
|
275
179
|
|
|
276
|
-
|
|
180
|
+
## API Reference
|
|
277
181
|
|
|
278
|
-
|
|
279
|
-
const ws = mero.createWebSocket();
|
|
182
|
+
### Factory Functions
|
|
280
183
|
|
|
281
|
-
|
|
184
|
+
#### `createBrowserHttpClient(options)`
|
|
282
185
|
|
|
283
|
-
|
|
284
|
-
console.log('Event:', event);
|
|
285
|
-
});
|
|
186
|
+
Creates an HTTP client optimized for browser environments.
|
|
286
187
|
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
188
|
+
#### `createNodeHttpClient(options)`
|
|
189
|
+
|
|
190
|
+
Creates an HTTP client for Node.js environments.
|
|
290
191
|
|
|
291
|
-
|
|
192
|
+
#### `createUniversalHttpClient(options)`
|
|
292
193
|
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
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
|
+
}
|
|
296
209
|
```
|
|
297
210
|
|
|
298
|
-
###
|
|
211
|
+
### HTTP Methods
|
|
299
212
|
|
|
300
213
|
```typescript
|
|
301
|
-
|
|
214
|
+
// GET request
|
|
215
|
+
const response = await httpClient.get<T>('/api/endpoint', init?);
|
|
302
216
|
|
|
303
|
-
|
|
217
|
+
// POST request
|
|
218
|
+
const response = await httpClient.post<T>('/api/endpoint', body?, init?);
|
|
304
219
|
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
});
|
|
220
|
+
// PUT request
|
|
221
|
+
const response = await httpClient.put<T>('/api/endpoint', body?, init?);
|
|
308
222
|
|
|
309
|
-
|
|
223
|
+
// DELETE request
|
|
224
|
+
const response = await httpClient.delete<T>('/api/endpoint', init?);
|
|
310
225
|
|
|
311
|
-
//
|
|
312
|
-
const
|
|
226
|
+
// PATCH request
|
|
227
|
+
const response = await httpClient.patch<T>('/api/endpoint', body?, init?);
|
|
313
228
|
|
|
314
|
-
//
|
|
315
|
-
|
|
316
|
-
```
|
|
229
|
+
// HEAD request
|
|
230
|
+
const response = await httpClient.head<T>('/api/endpoint', init?);
|
|
317
231
|
|
|
318
|
-
|
|
232
|
+
// Generic request
|
|
233
|
+
const response = await httpClient.request<T>('/api/endpoint', init?);
|
|
234
|
+
```
|
|
319
235
|
|
|
320
|
-
|
|
236
|
+
### Request Options
|
|
321
237
|
|
|
322
238
|
```typescript
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
import { createBrowserHttpClient } from '@calimero-network/mero-js/http-client';
|
|
328
|
-
|
|
329
|
-
// Specific API clients
|
|
330
|
-
import { AdminApiClient } from '@calimero-network/mero-js/api/admin';
|
|
331
|
-
import { AuthApiClient } from '@calimero-network/mero-js/api/auth';
|
|
332
|
-
import { RpcClient } from '@calimero-network/mero-js/api/rpc';
|
|
333
|
-
import { WebSocketClient } from '@calimero-network/mero-js/api/ws';
|
|
334
|
-
import { SseClient } from '@calimero-network/mero-js/api/sse';
|
|
239
|
+
interface RequestOptions extends RequestInit {
|
|
240
|
+
parse?: 'json' | 'text' | 'blob' | 'arrayBuffer' | 'response';
|
|
241
|
+
timeoutMs?: number;
|
|
242
|
+
}
|
|
335
243
|
```
|
|
336
244
|
|
|
337
|
-
|
|
245
|
+
### Response Format
|
|
338
246
|
|
|
339
|
-
|
|
247
|
+
All methods return the parsed data directly or throw errors:
|
|
340
248
|
|
|
341
249
|
```typescript
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
const http = createBrowserHttpClient({
|
|
345
|
-
baseUrl: 'https://api.example.com',
|
|
346
|
-
getAuthToken: async () => myTokenStore.getToken(),
|
|
347
|
-
refreshToken: async () => {
|
|
348
|
-
const newToken = await myRefreshLogic();
|
|
349
|
-
return newToken;
|
|
350
|
-
},
|
|
351
|
-
onTokenRefresh: async (token) => {
|
|
352
|
-
await myTokenStore.setToken(token);
|
|
353
|
-
},
|
|
354
|
-
timeoutMs: 10000,
|
|
355
|
-
});
|
|
250
|
+
// Success - returns parsed data
|
|
251
|
+
const data: T = await httpClient.get<T>('/api/data');
|
|
356
252
|
|
|
253
|
+
// Error - throws HTTPError or other errors
|
|
357
254
|
try {
|
|
358
|
-
const data = await
|
|
255
|
+
const data = await httpClient.get('/api/data');
|
|
359
256
|
} catch (error) {
|
|
360
257
|
if (error instanceof HTTPError) {
|
|
361
|
-
console.log(`HTTP ${error.status}: ${error.
|
|
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);
|
|
362
262
|
}
|
|
363
263
|
}
|
|
364
264
|
```
|
|
365
265
|
|
|
366
|
-
##
|
|
266
|
+
## Advanced Usage
|
|
267
|
+
|
|
268
|
+
### Custom Transport
|
|
367
269
|
|
|
368
270
|
```typescript
|
|
369
|
-
import {
|
|
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
|
+
};
|
|
370
279
|
|
|
280
|
+
const httpClient = createHttpClient(transport);
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
### Error Handling
|
|
284
|
+
|
|
285
|
+
```typescript
|
|
371
286
|
try {
|
|
372
|
-
await
|
|
287
|
+
const data = await httpClient.get('/api/data');
|
|
288
|
+
// Success - data is the parsed response
|
|
289
|
+
console.log(data);
|
|
373
290
|
} catch (error) {
|
|
374
291
|
if (error instanceof HTTPError) {
|
|
375
|
-
// HTTP
|
|
376
|
-
console.
|
|
377
|
-
console.
|
|
378
|
-
|
|
379
|
-
// API-level error (in response body)
|
|
380
|
-
console.log(`API Error: ${error.message}`);
|
|
381
|
-
console.log('Type:', error.type);
|
|
382
|
-
console.log('Code:', error.code);
|
|
383
|
-
} else if (error.name === 'AbortError') {
|
|
384
|
-
// Request was cancelled
|
|
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);
|
|
385
296
|
} else if (error.name === 'TimeoutError') {
|
|
386
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);
|
|
387
305
|
}
|
|
388
306
|
}
|
|
389
307
|
```
|
|
390
308
|
|
|
391
|
-
|
|
309
|
+
### Custom Headers
|
|
392
310
|
|
|
393
|
-
```
|
|
394
|
-
|
|
395
|
-
|
|
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
|
+
```
|
|
396
319
|
|
|
397
|
-
|
|
398
|
-
pnpm test:e2e
|
|
320
|
+
### Request Cancellation
|
|
399
321
|
|
|
400
|
-
|
|
401
|
-
|
|
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
|
+
});
|
|
402
331
|
```
|
|
403
332
|
|
|
404
|
-
|
|
333
|
+
### FormData Support
|
|
405
334
|
|
|
406
|
-
```
|
|
407
|
-
|
|
408
|
-
|
|
335
|
+
```typescript
|
|
336
|
+
const formData = new FormData();
|
|
337
|
+
formData.append('file', fileInput.files[0]);
|
|
338
|
+
formData.append('name', 'John Doe');
|
|
409
339
|
|
|
410
|
-
|
|
411
|
-
|
|
340
|
+
const data = await httpClient.post('/api/upload', formData);
|
|
341
|
+
// Content-Type is set by the browser/undici with proper boundary
|
|
342
|
+
```
|
|
412
343
|
|
|
413
|
-
|
|
414
|
-
pnpm lint
|
|
344
|
+
### Response Parsing
|
|
415
345
|
|
|
416
|
-
|
|
417
|
-
|
|
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' });
|
|
418
351
|
|
|
419
|
-
|
|
420
|
-
|
|
352
|
+
// Auto-detection based on Content-Type (default)
|
|
353
|
+
const autoData = await httpClient.get('/api/data');
|
|
421
354
|
```
|
|
422
355
|
|
|
423
|
-
|
|
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
|
+
```
|
|
366
|
+
|
|
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
|
+
});
|
|
380
|
+
```
|
|
381
|
+
|
|
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:
|
|
424
399
|
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
| Browser (minified) | ~29kb | ~9kb |
|
|
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
|
|
430
404
|
|
|
431
405
|
## Browser Support
|
|
432
406
|
|
|
433
|
-
- Modern browsers with `fetch` (Chrome 42+, Firefox 39+, Safari 10.1+)
|
|
434
|
-
- Node.js 18+ (native fetch) or 16+ with `undici`
|
|
435
|
-
|
|
436
|
-
|
|
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`
|
|
409
|
+
|
|
410
|
+
## Bundle Sizes
|
|
411
|
+
|
|
412
|
+
- **ESM**: ~9.4kb (gzipped: ~3.2kb)
|
|
413
|
+
- **CJS**: ~10.5kb (gzipped: ~3.6kb)
|
|
414
|
+
|
|
415
|
+
## Examples
|
|
416
|
+
|
|
417
|
+
See the `examples/` directory for complete usage examples:
|
|
418
|
+
|
|
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)
|
|
422
|
+
|
|
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
|
+
```
|
|
437
435
|
|
|
438
|
-
|
|
436
|
+
### Groups (governance boundaries)
|
|
437
|
+
```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
|
+
```
|
|
439
444
|
|
|
440
|
-
###
|
|
445
|
+
### Contexts (WASM execution instances)
|
|
446
|
+
```typescript
|
|
447
|
+
// Single-service app
|
|
448
|
+
const ctx = await admin.createContext({ applicationId: '...' });
|
|
441
449
|
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
await mero.clearToken();
|
|
449
|
-
```
|
|
450
|
+
// Multi-service app -- specify which service to run
|
|
451
|
+
const ctx = await admin.createContext({
|
|
452
|
+
applicationId: '...',
|
|
453
|
+
serviceName: 'chat',
|
|
454
|
+
});
|
|
455
|
+
```
|
|
450
456
|
|
|
451
|
-
|
|
457
|
+
### Cloud (TEE High Availability)
|
|
458
|
+
```typescript
|
|
459
|
+
import { CloudClient } from '@calimero-network/mero-js';
|
|
460
|
+
const cloud = new CloudClient();
|
|
461
|
+
cloud.enableHA({ groupId, contextId, redirectUrl });
|
|
462
|
+
```
|
|
452
463
|
|
|
453
|
-
|
|
464
|
+
## Development
|
|
454
465
|
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
466
|
+
```bash
|
|
467
|
+
# Install dependencies
|
|
468
|
+
pnpm install
|
|
469
|
+
|
|
470
|
+
# Build
|
|
471
|
+
pnpm build
|
|
472
|
+
|
|
473
|
+
# Test
|
|
474
|
+
pnpm test
|
|
475
|
+
|
|
476
|
+
# Lint
|
|
477
|
+
pnpm lint
|
|
478
|
+
```
|
|
462
479
|
|
|
463
480
|
## License
|
|
464
481
|
|