@calimero-network/mero-react 1.0.0-beta.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 +220 -0
- package/dist/index.cjs +913 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +193 -0
- package/dist/index.d.ts +193 -0
- package/dist/index.js +893 -0
- package/dist/index.js.map +1 -0
- package/package.json +61 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,893 @@
|
|
|
1
|
+
import { createContext, useState, useRef, useCallback, useEffect, useMemo, useContext } from 'react';
|
|
2
|
+
import { MeroJs } from '@calimero-network/mero-js';
|
|
3
|
+
export { MeroJs } from '@calimero-network/mero-js';
|
|
4
|
+
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
5
|
+
import { createPortal } from 'react-dom';
|
|
6
|
+
|
|
7
|
+
// src/context/MeroContext.tsx
|
|
8
|
+
|
|
9
|
+
// src/storage/index.ts
|
|
10
|
+
var STORAGE_KEYS = {
|
|
11
|
+
ACCESS_TOKEN: "mero:access_token",
|
|
12
|
+
REFRESH_TOKEN: "mero:refresh_token",
|
|
13
|
+
EXPIRES_AT: "mero:expires_at",
|
|
14
|
+
NODE_URL: "mero:node_url",
|
|
15
|
+
APPLICATION_ID: "mero:application_id",
|
|
16
|
+
CONTEXT_ID: "mero:context_id"
|
|
17
|
+
};
|
|
18
|
+
function isLocalStorageAvailable() {
|
|
19
|
+
try {
|
|
20
|
+
if (typeof window === "undefined" || !window.localStorage) {
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
const testKey = "__mero_test__";
|
|
24
|
+
localStorage.setItem(testKey, "test");
|
|
25
|
+
localStorage.removeItem(testKey);
|
|
26
|
+
return true;
|
|
27
|
+
} catch {
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
var localStorageTokenStorage = {
|
|
32
|
+
async get() {
|
|
33
|
+
if (!isLocalStorageAvailable()) {
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
try {
|
|
37
|
+
const accessToken = localStorage.getItem(STORAGE_KEYS.ACCESS_TOKEN);
|
|
38
|
+
const refreshToken = localStorage.getItem(STORAGE_KEYS.REFRESH_TOKEN);
|
|
39
|
+
const expiresAt = localStorage.getItem(STORAGE_KEYS.EXPIRES_AT);
|
|
40
|
+
if (!accessToken || !refreshToken) {
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
return {
|
|
44
|
+
access_token: accessToken,
|
|
45
|
+
refresh_token: refreshToken,
|
|
46
|
+
expires_at: expiresAt ? parseInt(expiresAt, 10) : Date.now() + 36e5
|
|
47
|
+
};
|
|
48
|
+
} catch (e) {
|
|
49
|
+
console.error("[mero-react] Failed to get token from storage:", e);
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
async set(token) {
|
|
54
|
+
if (!isLocalStorageAvailable()) {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
try {
|
|
58
|
+
localStorage.setItem(STORAGE_KEYS.ACCESS_TOKEN, token.access_token);
|
|
59
|
+
localStorage.setItem(STORAGE_KEYS.REFRESH_TOKEN, token.refresh_token);
|
|
60
|
+
localStorage.setItem(STORAGE_KEYS.EXPIRES_AT, token.expires_at.toString());
|
|
61
|
+
} catch (e) {
|
|
62
|
+
console.error("[mero-react] Failed to save token to storage:", e);
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
async clear() {
|
|
66
|
+
if (!isLocalStorageAvailable()) {
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
try {
|
|
70
|
+
localStorage.removeItem(STORAGE_KEYS.ACCESS_TOKEN);
|
|
71
|
+
localStorage.removeItem(STORAGE_KEYS.REFRESH_TOKEN);
|
|
72
|
+
localStorage.removeItem(STORAGE_KEYS.EXPIRES_AT);
|
|
73
|
+
} catch (e) {
|
|
74
|
+
console.error("[mero-react] Failed to clear token from storage:", e);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
function getNodeUrl() {
|
|
79
|
+
if (!isLocalStorageAvailable()) return null;
|
|
80
|
+
return localStorage.getItem(STORAGE_KEYS.NODE_URL);
|
|
81
|
+
}
|
|
82
|
+
function setNodeUrl(url) {
|
|
83
|
+
if (!isLocalStorageAvailable()) return;
|
|
84
|
+
localStorage.setItem(STORAGE_KEYS.NODE_URL, url);
|
|
85
|
+
}
|
|
86
|
+
function clearNodeUrl() {
|
|
87
|
+
if (!isLocalStorageAvailable()) return;
|
|
88
|
+
localStorage.removeItem(STORAGE_KEYS.NODE_URL);
|
|
89
|
+
}
|
|
90
|
+
function getApplicationId() {
|
|
91
|
+
if (!isLocalStorageAvailable()) return null;
|
|
92
|
+
return localStorage.getItem(STORAGE_KEYS.APPLICATION_ID);
|
|
93
|
+
}
|
|
94
|
+
function setApplicationId(id) {
|
|
95
|
+
if (!isLocalStorageAvailable()) return;
|
|
96
|
+
localStorage.setItem(STORAGE_KEYS.APPLICATION_ID, id);
|
|
97
|
+
}
|
|
98
|
+
function clearApplicationId() {
|
|
99
|
+
if (!isLocalStorageAvailable()) return;
|
|
100
|
+
localStorage.removeItem(STORAGE_KEYS.APPLICATION_ID);
|
|
101
|
+
}
|
|
102
|
+
function getContextId() {
|
|
103
|
+
if (!isLocalStorageAvailable()) return null;
|
|
104
|
+
return localStorage.getItem(STORAGE_KEYS.CONTEXT_ID);
|
|
105
|
+
}
|
|
106
|
+
function setContextId(id) {
|
|
107
|
+
if (!isLocalStorageAvailable()) return;
|
|
108
|
+
localStorage.setItem(STORAGE_KEYS.CONTEXT_ID, id);
|
|
109
|
+
}
|
|
110
|
+
function clearAllStorage() {
|
|
111
|
+
if (!isLocalStorageAvailable()) return;
|
|
112
|
+
Object.values(STORAGE_KEYS).forEach((key) => {
|
|
113
|
+
localStorage.removeItem(key);
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// src/types.ts
|
|
118
|
+
var AppMode = /* @__PURE__ */ ((AppMode2) => {
|
|
119
|
+
AppMode2["SingleContext"] = "single-context";
|
|
120
|
+
AppMode2["MultiContext"] = "multi-context";
|
|
121
|
+
AppMode2["Admin"] = "admin";
|
|
122
|
+
return AppMode2;
|
|
123
|
+
})(AppMode || {});
|
|
124
|
+
var ConnectionType = /* @__PURE__ */ ((ConnectionType2) => {
|
|
125
|
+
ConnectionType2["RemoteAndLocal"] = "remote-and-local";
|
|
126
|
+
ConnectionType2["Remote"] = "remote";
|
|
127
|
+
ConnectionType2["Local"] = "local";
|
|
128
|
+
ConnectionType2["Custom"] = "custom";
|
|
129
|
+
return ConnectionType2;
|
|
130
|
+
})(ConnectionType || {});
|
|
131
|
+
var EventStreamMode = /* @__PURE__ */ ((EventStreamMode2) => {
|
|
132
|
+
EventStreamMode2["WebSocket"] = "websocket";
|
|
133
|
+
EventStreamMode2["SSE"] = "sse";
|
|
134
|
+
return EventStreamMode2;
|
|
135
|
+
})(EventStreamMode || {});
|
|
136
|
+
var defaultContextValue = {
|
|
137
|
+
mero: null,
|
|
138
|
+
isAuthenticated: false,
|
|
139
|
+
isOnline: true,
|
|
140
|
+
nodeUrl: null,
|
|
141
|
+
applicationId: null,
|
|
142
|
+
contextId: null,
|
|
143
|
+
connectToNode: () => {
|
|
144
|
+
},
|
|
145
|
+
logout: () => {
|
|
146
|
+
},
|
|
147
|
+
isLoading: true
|
|
148
|
+
};
|
|
149
|
+
var MeroContext = createContext(defaultContextValue);
|
|
150
|
+
function getPermissionsForMode(mode) {
|
|
151
|
+
switch (mode) {
|
|
152
|
+
case "single-context" /* SingleContext */:
|
|
153
|
+
return ["context:execute"];
|
|
154
|
+
case "multi-context" /* MultiContext */:
|
|
155
|
+
return ["context:create", "context:list", "context:execute"];
|
|
156
|
+
case "admin" /* Admin */:
|
|
157
|
+
return ["admin"];
|
|
158
|
+
default:
|
|
159
|
+
throw new Error(`Unsupported application mode: ${mode}`);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
function redirectToAuthLogin(params) {
|
|
163
|
+
const authParams = new URLSearchParams();
|
|
164
|
+
authParams.append("callback-url", params.callbackUrl);
|
|
165
|
+
authParams.append("permissions", params.permissions.join(","));
|
|
166
|
+
authParams.append("mode", params.mode);
|
|
167
|
+
if (params.packageName) {
|
|
168
|
+
authParams.append("package-name", params.packageName);
|
|
169
|
+
if (params.packageVersion) {
|
|
170
|
+
authParams.append("package-version", params.packageVersion);
|
|
171
|
+
}
|
|
172
|
+
if (params.registryUrl) {
|
|
173
|
+
authParams.append("registry-url", params.registryUrl);
|
|
174
|
+
}
|
|
175
|
+
} else if (params.applicationId) {
|
|
176
|
+
authParams.append("application-id", params.applicationId);
|
|
177
|
+
}
|
|
178
|
+
if (params.applicationPath) {
|
|
179
|
+
authParams.append("application-path", params.applicationPath);
|
|
180
|
+
}
|
|
181
|
+
authParams.append("app-url", params.nodeUrl);
|
|
182
|
+
window.location.href = `${params.nodeUrl}/auth/login?${authParams.toString()}`;
|
|
183
|
+
}
|
|
184
|
+
function MeroProvider({
|
|
185
|
+
children,
|
|
186
|
+
mode,
|
|
187
|
+
packageName,
|
|
188
|
+
packageVersion,
|
|
189
|
+
registryUrl,
|
|
190
|
+
applicationId: propApplicationId,
|
|
191
|
+
applicationPath,
|
|
192
|
+
timeoutMs = 3e4
|
|
193
|
+
}) {
|
|
194
|
+
const [mero, setMero] = useState(null);
|
|
195
|
+
const [isAuthenticated, setIsAuthenticated] = useState(false);
|
|
196
|
+
const [isOnline, setIsOnline] = useState(true);
|
|
197
|
+
const [isLoading, setIsLoading] = useState(true);
|
|
198
|
+
const [nodeUrl, setNodeUrlState] = useState(() => getNodeUrl());
|
|
199
|
+
const [applicationId, setApplicationIdState] = useState(
|
|
200
|
+
() => getApplicationId() || propApplicationId || null
|
|
201
|
+
);
|
|
202
|
+
const [contextId, setContextIdState] = useState(() => getContextId());
|
|
203
|
+
const meroRef = useRef(null);
|
|
204
|
+
const createMeroInstance = useCallback(
|
|
205
|
+
(url) => {
|
|
206
|
+
const instance = new MeroJs({
|
|
207
|
+
baseUrl: url,
|
|
208
|
+
tokenStorage: localStorageTokenStorage,
|
|
209
|
+
timeoutMs
|
|
210
|
+
});
|
|
211
|
+
meroRef.current = instance;
|
|
212
|
+
return instance;
|
|
213
|
+
},
|
|
214
|
+
[timeoutMs]
|
|
215
|
+
);
|
|
216
|
+
const checkAuth = useCallback(async (instance) => {
|
|
217
|
+
try {
|
|
218
|
+
await instance.admin.contexts.listContexts();
|
|
219
|
+
return true;
|
|
220
|
+
} catch {
|
|
221
|
+
return false;
|
|
222
|
+
}
|
|
223
|
+
}, []);
|
|
224
|
+
const processAuthCallback = useCallback(() => {
|
|
225
|
+
const url = new URL(window.location.href);
|
|
226
|
+
const rawHash = url.hash;
|
|
227
|
+
const hash = rawHash.slice(1);
|
|
228
|
+
console.log("========== AUTH CALLBACK DEBUG ==========");
|
|
229
|
+
console.log("Raw URL:", window.location.href);
|
|
230
|
+
console.log("Raw hash:", rawHash);
|
|
231
|
+
console.log("Hash (without #):", hash);
|
|
232
|
+
if (!hash) {
|
|
233
|
+
console.log("No hash found, skipping auth callback");
|
|
234
|
+
console.log("==========================================");
|
|
235
|
+
return false;
|
|
236
|
+
}
|
|
237
|
+
const params = new URLSearchParams(hash);
|
|
238
|
+
console.log("All hash params:");
|
|
239
|
+
for (const [key, value] of params.entries()) {
|
|
240
|
+
console.log(` ${key}: ${value.substring(0, 50)}${value.length > 50 ? "..." : ""}`);
|
|
241
|
+
}
|
|
242
|
+
console.log("==========================================");
|
|
243
|
+
const accessToken = params.get("access_token");
|
|
244
|
+
const refreshToken = params.get("refresh_token");
|
|
245
|
+
const appId = params.get("application_id") || params.get("applicationId") || params.get("app_id");
|
|
246
|
+
const ctxId = params.get("context_id") || params.get("contextId") || params.get("context");
|
|
247
|
+
const expiresIn = params.get("expires_in");
|
|
248
|
+
const nodeUrlParam = params.get("node_url") || params.get("nodeUrl") || params.get("node");
|
|
249
|
+
if (!accessToken || !refreshToken) return false;
|
|
250
|
+
if (nodeUrlParam) {
|
|
251
|
+
const decodedNodeUrl = decodeURIComponent(nodeUrlParam);
|
|
252
|
+
setNodeUrl(decodedNodeUrl);
|
|
253
|
+
setNodeUrlState(decodedNodeUrl);
|
|
254
|
+
console.log("[mero-react] SSO: Node URL from hash params:", decodedNodeUrl);
|
|
255
|
+
}
|
|
256
|
+
try {
|
|
257
|
+
const decodedAccess = decodeURIComponent(accessToken);
|
|
258
|
+
const decodedRefresh = decodeURIComponent(refreshToken);
|
|
259
|
+
let expiresAt = Date.now() + 36e5;
|
|
260
|
+
if (expiresIn) {
|
|
261
|
+
expiresAt = Date.now() + parseInt(expiresIn, 10) * 1e3;
|
|
262
|
+
} else {
|
|
263
|
+
try {
|
|
264
|
+
const parts = decodedAccess.split(".");
|
|
265
|
+
if (parts.length === 3) {
|
|
266
|
+
const payload = JSON.parse(atob(parts[1]));
|
|
267
|
+
if (payload.exp) {
|
|
268
|
+
expiresAt = payload.exp * 1e3;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
} catch {
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
localStorageTokenStorage.set({
|
|
275
|
+
access_token: decodedAccess,
|
|
276
|
+
refresh_token: decodedRefresh,
|
|
277
|
+
expires_at: expiresAt
|
|
278
|
+
});
|
|
279
|
+
if (appId) {
|
|
280
|
+
setApplicationId(appId);
|
|
281
|
+
setApplicationIdState(appId);
|
|
282
|
+
}
|
|
283
|
+
if (ctxId) {
|
|
284
|
+
setContextId(ctxId);
|
|
285
|
+
setContextIdState(ctxId);
|
|
286
|
+
}
|
|
287
|
+
params.delete("access_token");
|
|
288
|
+
params.delete("refresh_token");
|
|
289
|
+
params.delete("application_id");
|
|
290
|
+
params.delete("applicationId");
|
|
291
|
+
params.delete("app_id");
|
|
292
|
+
params.delete("context_id");
|
|
293
|
+
params.delete("contextId");
|
|
294
|
+
params.delete("context");
|
|
295
|
+
params.delete("expires_in");
|
|
296
|
+
params.delete("node_url");
|
|
297
|
+
params.delete("nodeUrl");
|
|
298
|
+
params.delete("node");
|
|
299
|
+
const newHash = params.toString();
|
|
300
|
+
url.hash = newHash ? `#${newHash}` : "";
|
|
301
|
+
window.history.replaceState({}, document.title, url.toString());
|
|
302
|
+
console.log("[mero-react] Stored contextId:", ctxId, "applicationId:", appId);
|
|
303
|
+
return true;
|
|
304
|
+
} catch (e) {
|
|
305
|
+
console.error("[mero-react] Failed to process auth callback:", e);
|
|
306
|
+
return false;
|
|
307
|
+
}
|
|
308
|
+
}, []);
|
|
309
|
+
const connectToNode = useCallback(
|
|
310
|
+
(url) => {
|
|
311
|
+
setNodeUrl(url);
|
|
312
|
+
setNodeUrlState(url);
|
|
313
|
+
const callbackUrl = new URL(window.location.href);
|
|
314
|
+
if (callbackUrl.hash) {
|
|
315
|
+
const hashParams = new URLSearchParams(callbackUrl.hash.substring(1));
|
|
316
|
+
hashParams.delete("access_token");
|
|
317
|
+
hashParams.delete("refresh_token");
|
|
318
|
+
hashParams.delete("application_id");
|
|
319
|
+
callbackUrl.hash = hashParams.toString() ? `#${hashParams.toString()}` : "";
|
|
320
|
+
}
|
|
321
|
+
const permissions = getPermissionsForMode(mode);
|
|
322
|
+
redirectToAuthLogin({
|
|
323
|
+
nodeUrl: url,
|
|
324
|
+
callbackUrl: callbackUrl.toString(),
|
|
325
|
+
permissions,
|
|
326
|
+
mode,
|
|
327
|
+
packageName,
|
|
328
|
+
packageVersion,
|
|
329
|
+
registryUrl,
|
|
330
|
+
applicationId: propApplicationId,
|
|
331
|
+
applicationPath
|
|
332
|
+
});
|
|
333
|
+
},
|
|
334
|
+
[mode, packageName, packageVersion, registryUrl, propApplicationId, applicationPath]
|
|
335
|
+
);
|
|
336
|
+
const logout = useCallback(async () => {
|
|
337
|
+
if (meroRef.current) {
|
|
338
|
+
await meroRef.current.clearToken();
|
|
339
|
+
}
|
|
340
|
+
clearAllStorage();
|
|
341
|
+
setMero(null);
|
|
342
|
+
setIsAuthenticated(false);
|
|
343
|
+
setNodeUrlState(null);
|
|
344
|
+
setApplicationIdState(null);
|
|
345
|
+
setContextIdState(null);
|
|
346
|
+
meroRef.current = null;
|
|
347
|
+
}, []);
|
|
348
|
+
useEffect(() => {
|
|
349
|
+
const init = async () => {
|
|
350
|
+
console.log("[mero-react] Init starting...");
|
|
351
|
+
console.log("[mero-react] Current URL:", window.location.href);
|
|
352
|
+
console.log("[mero-react] Stored nodeUrl:", getNodeUrl());
|
|
353
|
+
console.log("[mero-react] Stored contextId:", getContextId());
|
|
354
|
+
console.log("[mero-react] Stored applicationId:", getApplicationId());
|
|
355
|
+
const hasCallback = processAuthCallback();
|
|
356
|
+
console.log("[mero-react] hasCallback:", hasCallback);
|
|
357
|
+
const savedUrl = getNodeUrl();
|
|
358
|
+
if (!savedUrl) {
|
|
359
|
+
setIsLoading(false);
|
|
360
|
+
return;
|
|
361
|
+
}
|
|
362
|
+
const instance = createMeroInstance(savedUrl);
|
|
363
|
+
await instance.init();
|
|
364
|
+
const authed = await checkAuth(instance);
|
|
365
|
+
if (authed) {
|
|
366
|
+
setMero(instance);
|
|
367
|
+
setIsAuthenticated(true);
|
|
368
|
+
setIsOnline(true);
|
|
369
|
+
} else if (hasCallback) {
|
|
370
|
+
setMero(instance);
|
|
371
|
+
setIsAuthenticated(false);
|
|
372
|
+
}
|
|
373
|
+
setIsLoading(false);
|
|
374
|
+
};
|
|
375
|
+
init();
|
|
376
|
+
}, [createMeroInstance, checkAuth, processAuthCallback]);
|
|
377
|
+
useEffect(() => {
|
|
378
|
+
if (!isAuthenticated || !meroRef.current) return;
|
|
379
|
+
const interval = setInterval(async () => {
|
|
380
|
+
const instance = meroRef.current;
|
|
381
|
+
if (!instance) return;
|
|
382
|
+
const healthy = await checkAuth(instance);
|
|
383
|
+
if (!healthy && isOnline) {
|
|
384
|
+
setIsOnline(false);
|
|
385
|
+
} else if (healthy && !isOnline) {
|
|
386
|
+
setIsOnline(true);
|
|
387
|
+
}
|
|
388
|
+
}, 5e3);
|
|
389
|
+
return () => clearInterval(interval);
|
|
390
|
+
}, [isAuthenticated, isOnline, checkAuth]);
|
|
391
|
+
useEffect(() => {
|
|
392
|
+
if (propApplicationId && !applicationId) {
|
|
393
|
+
setApplicationIdState(propApplicationId);
|
|
394
|
+
}
|
|
395
|
+
}, [propApplicationId, applicationId]);
|
|
396
|
+
const contextValue = useMemo(
|
|
397
|
+
() => ({
|
|
398
|
+
mero,
|
|
399
|
+
isAuthenticated,
|
|
400
|
+
isOnline,
|
|
401
|
+
nodeUrl,
|
|
402
|
+
applicationId,
|
|
403
|
+
contextId,
|
|
404
|
+
connectToNode,
|
|
405
|
+
logout,
|
|
406
|
+
isLoading
|
|
407
|
+
}),
|
|
408
|
+
[mero, isAuthenticated, isOnline, nodeUrl, applicationId, contextId, connectToNode, logout, isLoading]
|
|
409
|
+
);
|
|
410
|
+
return /* @__PURE__ */ jsx(MeroContext.Provider, { value: contextValue, children });
|
|
411
|
+
}
|
|
412
|
+
function useMero() {
|
|
413
|
+
const context = useContext(MeroContext);
|
|
414
|
+
if (context === void 0) {
|
|
415
|
+
throw new Error("useMero must be used within a MeroProvider");
|
|
416
|
+
}
|
|
417
|
+
return context;
|
|
418
|
+
}
|
|
419
|
+
function isValidUrl(urlString) {
|
|
420
|
+
if (!urlString || urlString.trim() === "") {
|
|
421
|
+
return false;
|
|
422
|
+
}
|
|
423
|
+
try {
|
|
424
|
+
const urlToTest = urlString.startsWith("http://") || urlString.startsWith("https://") ? urlString : `https://${urlString}`;
|
|
425
|
+
const url = new URL(urlToTest);
|
|
426
|
+
if (url.protocol !== "http:" && url.protocol !== "https:") {
|
|
427
|
+
return false;
|
|
428
|
+
}
|
|
429
|
+
if (!url.hostname) {
|
|
430
|
+
return false;
|
|
431
|
+
}
|
|
432
|
+
const hostname = url.hostname;
|
|
433
|
+
if (hostname === "localhost") {
|
|
434
|
+
return true;
|
|
435
|
+
}
|
|
436
|
+
const ipv4Regex = /^(\d{1,3}\.){3}\d{1,3}$/;
|
|
437
|
+
if (ipv4Regex.test(hostname)) {
|
|
438
|
+
const octets = hostname.split(".").map(Number);
|
|
439
|
+
return octets.every((octet) => octet >= 0 && octet <= 255);
|
|
440
|
+
}
|
|
441
|
+
const domainRegex = /^[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/;
|
|
442
|
+
return domainRegex.test(hostname);
|
|
443
|
+
} catch {
|
|
444
|
+
return false;
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
var styles = {
|
|
448
|
+
overlay: {
|
|
449
|
+
position: "fixed",
|
|
450
|
+
top: 0,
|
|
451
|
+
left: 0,
|
|
452
|
+
right: 0,
|
|
453
|
+
bottom: 0,
|
|
454
|
+
backgroundColor: "rgba(0, 0, 0, 0.75)",
|
|
455
|
+
display: "flex",
|
|
456
|
+
alignItems: "center",
|
|
457
|
+
justifyContent: "center",
|
|
458
|
+
zIndex: 1e4,
|
|
459
|
+
padding: "1rem"
|
|
460
|
+
},
|
|
461
|
+
content: {
|
|
462
|
+
backgroundColor: "#1f2937",
|
|
463
|
+
borderRadius: "12px",
|
|
464
|
+
padding: "2rem",
|
|
465
|
+
maxWidth: "400px",
|
|
466
|
+
width: "100%",
|
|
467
|
+
position: "relative",
|
|
468
|
+
border: "1px solid #374151",
|
|
469
|
+
boxShadow: "0 25px 50px -12px rgba(0, 0, 0, 0.5)"
|
|
470
|
+
},
|
|
471
|
+
closeButton: {
|
|
472
|
+
position: "absolute",
|
|
473
|
+
top: "1rem",
|
|
474
|
+
right: "1rem",
|
|
475
|
+
background: "none",
|
|
476
|
+
border: "none",
|
|
477
|
+
fontSize: "1.5rem",
|
|
478
|
+
color: "#9ca3af",
|
|
479
|
+
cursor: "pointer",
|
|
480
|
+
padding: "0.25rem",
|
|
481
|
+
lineHeight: 1
|
|
482
|
+
},
|
|
483
|
+
header: {
|
|
484
|
+
display: "flex",
|
|
485
|
+
flexDirection: "column",
|
|
486
|
+
alignItems: "center",
|
|
487
|
+
gap: "0.75rem",
|
|
488
|
+
marginBottom: "1.5rem"
|
|
489
|
+
},
|
|
490
|
+
title: {
|
|
491
|
+
fontSize: "1.25rem",
|
|
492
|
+
fontWeight: 600,
|
|
493
|
+
color: "#f3f4f6",
|
|
494
|
+
margin: 0
|
|
495
|
+
},
|
|
496
|
+
info: {
|
|
497
|
+
color: "#9ca3af",
|
|
498
|
+
textAlign: "center",
|
|
499
|
+
marginBottom: "1.5rem",
|
|
500
|
+
fontSize: "0.875rem"
|
|
501
|
+
},
|
|
502
|
+
error: {
|
|
503
|
+
color: "#ef4444",
|
|
504
|
+
backgroundColor: "rgba(239, 68, 68, 0.1)",
|
|
505
|
+
border: "1px solid rgba(239, 68, 68, 0.3)",
|
|
506
|
+
borderRadius: "6px",
|
|
507
|
+
padding: "0.75rem",
|
|
508
|
+
marginBottom: "1rem",
|
|
509
|
+
fontSize: "0.875rem",
|
|
510
|
+
textAlign: "center"
|
|
511
|
+
},
|
|
512
|
+
radioGroup: {
|
|
513
|
+
display: "flex",
|
|
514
|
+
gap: "1rem",
|
|
515
|
+
marginBottom: "1rem",
|
|
516
|
+
justifyContent: "center"
|
|
517
|
+
},
|
|
518
|
+
radioLabel: {
|
|
519
|
+
display: "flex",
|
|
520
|
+
alignItems: "center",
|
|
521
|
+
gap: "0.5rem",
|
|
522
|
+
color: "#e5e7eb",
|
|
523
|
+
cursor: "pointer",
|
|
524
|
+
padding: "0.5rem 1rem",
|
|
525
|
+
borderRadius: "6px",
|
|
526
|
+
border: "1px solid #374151",
|
|
527
|
+
backgroundColor: "#111827",
|
|
528
|
+
transition: "all 0.2s"
|
|
529
|
+
},
|
|
530
|
+
radioLabelActive: {
|
|
531
|
+
borderColor: "#3b82f6",
|
|
532
|
+
backgroundColor: "rgba(59, 130, 246, 0.1)"
|
|
533
|
+
},
|
|
534
|
+
input: {
|
|
535
|
+
width: "100%",
|
|
536
|
+
padding: "0.75rem 1rem",
|
|
537
|
+
borderRadius: "6px",
|
|
538
|
+
border: "1px solid #374151",
|
|
539
|
+
backgroundColor: "#111827",
|
|
540
|
+
color: "#f3f4f6",
|
|
541
|
+
fontSize: "0.875rem",
|
|
542
|
+
outline: "none",
|
|
543
|
+
marginBottom: "1rem",
|
|
544
|
+
boxSizing: "border-box"
|
|
545
|
+
},
|
|
546
|
+
localInfo: {
|
|
547
|
+
color: "#9ca3af",
|
|
548
|
+
fontSize: "0.875rem",
|
|
549
|
+
textAlign: "center",
|
|
550
|
+
padding: "0.75rem",
|
|
551
|
+
backgroundColor: "#111827",
|
|
552
|
+
borderRadius: "6px",
|
|
553
|
+
marginBottom: "1rem"
|
|
554
|
+
},
|
|
555
|
+
buttonGroup: {
|
|
556
|
+
display: "flex",
|
|
557
|
+
justifyContent: "center"
|
|
558
|
+
},
|
|
559
|
+
button: {
|
|
560
|
+
padding: "0.75rem 2rem",
|
|
561
|
+
borderRadius: "6px",
|
|
562
|
+
border: "none",
|
|
563
|
+
fontSize: "0.875rem",
|
|
564
|
+
fontWeight: 600,
|
|
565
|
+
cursor: "pointer",
|
|
566
|
+
backgroundColor: "#3b82f6",
|
|
567
|
+
color: "white",
|
|
568
|
+
transition: "all 0.2s"
|
|
569
|
+
},
|
|
570
|
+
buttonDisabled: {
|
|
571
|
+
opacity: 0.5,
|
|
572
|
+
cursor: "not-allowed"
|
|
573
|
+
},
|
|
574
|
+
loading: {
|
|
575
|
+
display: "flex",
|
|
576
|
+
flexDirection: "column",
|
|
577
|
+
alignItems: "center",
|
|
578
|
+
gap: "1rem",
|
|
579
|
+
padding: "2rem",
|
|
580
|
+
color: "#9ca3af"
|
|
581
|
+
},
|
|
582
|
+
spinner: {
|
|
583
|
+
width: "2rem",
|
|
584
|
+
height: "2rem",
|
|
585
|
+
border: "3px solid #374151",
|
|
586
|
+
borderTopColor: "#3b82f6",
|
|
587
|
+
borderRadius: "50%",
|
|
588
|
+
animation: "spin 1s linear infinite"
|
|
589
|
+
}
|
|
590
|
+
};
|
|
591
|
+
function LoginModal({
|
|
592
|
+
onConnect,
|
|
593
|
+
onClose,
|
|
594
|
+
connectionType,
|
|
595
|
+
isOpen
|
|
596
|
+
}) {
|
|
597
|
+
const [nodeType, setNodeType] = useState("local");
|
|
598
|
+
const [nodeUrl, setNodeUrl2] = useState("");
|
|
599
|
+
const [isValid, setIsValid] = useState(true);
|
|
600
|
+
const [loading, setLoading] = useState(false);
|
|
601
|
+
const [error, setError] = useState(null);
|
|
602
|
+
const shouldShowLocal = connectionType === "remote-and-local" /* RemoteAndLocal */ || connectionType === "local" /* Local */;
|
|
603
|
+
const shouldShowRemote = connectionType === "remote-and-local" /* RemoteAndLocal */ || connectionType === "remote" /* Remote */;
|
|
604
|
+
const shouldShowRadioGroup = shouldShowLocal && shouldShowRemote;
|
|
605
|
+
useEffect(() => {
|
|
606
|
+
const savedUrl = localStorage.getItem("mero:node_url");
|
|
607
|
+
if (savedUrl) {
|
|
608
|
+
setNodeUrl2(savedUrl);
|
|
609
|
+
}
|
|
610
|
+
}, []);
|
|
611
|
+
useEffect(() => {
|
|
612
|
+
if (connectionType === "local" /* Local */) {
|
|
613
|
+
setNodeType("local");
|
|
614
|
+
} else if (connectionType === "remote" /* Remote */) {
|
|
615
|
+
setNodeType("remote");
|
|
616
|
+
}
|
|
617
|
+
}, [connectionType]);
|
|
618
|
+
useEffect(() => {
|
|
619
|
+
if (nodeType === "remote") {
|
|
620
|
+
setIsValid(isValidUrl(nodeUrl));
|
|
621
|
+
} else {
|
|
622
|
+
setIsValid(true);
|
|
623
|
+
}
|
|
624
|
+
}, [nodeUrl, nodeType]);
|
|
625
|
+
const handleConnect = useCallback(async () => {
|
|
626
|
+
if (!isValid) return;
|
|
627
|
+
setLoading(true);
|
|
628
|
+
setError(null);
|
|
629
|
+
const baseUrl = nodeType === "local" ? "http://node1.127.0.0.1.nip.io" : nodeUrl;
|
|
630
|
+
try {
|
|
631
|
+
const response = await fetch(
|
|
632
|
+
new URL("admin-api/is-authed", baseUrl).toString()
|
|
633
|
+
);
|
|
634
|
+
if (response.ok || response.status === 401) {
|
|
635
|
+
setLoading(false);
|
|
636
|
+
const normalizedUrl = baseUrl.replace(/\/+$/, "");
|
|
637
|
+
onConnect(normalizedUrl);
|
|
638
|
+
} else {
|
|
639
|
+
throw new Error(`Connection failed: ${response.statusText}`);
|
|
640
|
+
}
|
|
641
|
+
} catch (err) {
|
|
642
|
+
console.error("Connection failed:", err);
|
|
643
|
+
setError("Failed to connect. Please check the URL and try again.");
|
|
644
|
+
setLoading(false);
|
|
645
|
+
}
|
|
646
|
+
}, [isValid, nodeType, nodeUrl, onConnect]);
|
|
647
|
+
if (!isOpen) {
|
|
648
|
+
return null;
|
|
649
|
+
}
|
|
650
|
+
const modalContent = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
651
|
+
/* @__PURE__ */ jsx("style", { children: `
|
|
652
|
+
@keyframes spin {
|
|
653
|
+
to { transform: rotate(360deg); }
|
|
654
|
+
}
|
|
655
|
+
` }),
|
|
656
|
+
/* @__PURE__ */ jsx("div", { style: styles.overlay, onClick: onClose, children: /* @__PURE__ */ jsxs("div", { style: styles.content, onClick: (e) => e.stopPropagation(), children: [
|
|
657
|
+
/* @__PURE__ */ jsx("button", { style: styles.closeButton, onClick: onClose, children: "\xD7" }),
|
|
658
|
+
/* @__PURE__ */ jsxs("div", { style: styles.header, children: [
|
|
659
|
+
/* @__PURE__ */ jsx(MeroLogo, {}),
|
|
660
|
+
/* @__PURE__ */ jsx("h1", { style: styles.title, children: "Connect to Calimero" })
|
|
661
|
+
] }),
|
|
662
|
+
loading ? /* @__PURE__ */ jsxs("div", { style: styles.loading, children: [
|
|
663
|
+
/* @__PURE__ */ jsx("p", { children: "Connecting to node..." }),
|
|
664
|
+
/* @__PURE__ */ jsx("div", { style: styles.spinner })
|
|
665
|
+
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
666
|
+
/* @__PURE__ */ jsx("p", { style: styles.info, children: shouldShowRadioGroup ? "Select your Calimero node type to continue." : connectionType === "local" /* Local */ ? "Connect to your local Calimero node." : "Enter your remote Calimero node URL." }),
|
|
667
|
+
error && /* @__PURE__ */ jsx("p", { style: styles.error, children: error }),
|
|
668
|
+
shouldShowRadioGroup && /* @__PURE__ */ jsxs("div", { style: styles.radioGroup, children: [
|
|
669
|
+
/* @__PURE__ */ jsxs(
|
|
670
|
+
"label",
|
|
671
|
+
{
|
|
672
|
+
style: {
|
|
673
|
+
...styles.radioLabel,
|
|
674
|
+
...nodeType === "local" ? styles.radioLabelActive : {}
|
|
675
|
+
},
|
|
676
|
+
onClick: () => setNodeType("local"),
|
|
677
|
+
children: [
|
|
678
|
+
/* @__PURE__ */ jsx(
|
|
679
|
+
"input",
|
|
680
|
+
{
|
|
681
|
+
type: "radio",
|
|
682
|
+
value: "local",
|
|
683
|
+
checked: nodeType === "local",
|
|
684
|
+
onChange: () => setNodeType("local"),
|
|
685
|
+
style: { display: "none" }
|
|
686
|
+
}
|
|
687
|
+
),
|
|
688
|
+
"\u{1F3E0} Local"
|
|
689
|
+
]
|
|
690
|
+
}
|
|
691
|
+
),
|
|
692
|
+
/* @__PURE__ */ jsxs(
|
|
693
|
+
"label",
|
|
694
|
+
{
|
|
695
|
+
style: {
|
|
696
|
+
...styles.radioLabel,
|
|
697
|
+
...nodeType === "remote" ? styles.radioLabelActive : {}
|
|
698
|
+
},
|
|
699
|
+
onClick: () => setNodeType("remote"),
|
|
700
|
+
children: [
|
|
701
|
+
/* @__PURE__ */ jsx(
|
|
702
|
+
"input",
|
|
703
|
+
{
|
|
704
|
+
type: "radio",
|
|
705
|
+
value: "remote",
|
|
706
|
+
checked: nodeType === "remote",
|
|
707
|
+
onChange: () => setNodeType("remote"),
|
|
708
|
+
style: { display: "none" }
|
|
709
|
+
}
|
|
710
|
+
),
|
|
711
|
+
"\u{1F310} Remote"
|
|
712
|
+
]
|
|
713
|
+
}
|
|
714
|
+
)
|
|
715
|
+
] }),
|
|
716
|
+
/* @__PURE__ */ jsx("div", { children: shouldShowRemote && nodeType === "remote" ? /* @__PURE__ */ jsx(
|
|
717
|
+
"input",
|
|
718
|
+
{
|
|
719
|
+
type: "text",
|
|
720
|
+
value: nodeUrl,
|
|
721
|
+
onChange: (e) => setNodeUrl2(e.target.value),
|
|
722
|
+
placeholder: "https://your-node-url.calimero.network",
|
|
723
|
+
style: styles.input,
|
|
724
|
+
onKeyDown: (e) => {
|
|
725
|
+
if (e.key === "Enter" && isValid) {
|
|
726
|
+
handleConnect();
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
) : shouldShowLocal ? /* @__PURE__ */ jsxs("p", { style: styles.localInfo, children: [
|
|
731
|
+
"Using default local node: ",
|
|
732
|
+
/* @__PURE__ */ jsx("br", {}),
|
|
733
|
+
/* @__PURE__ */ jsx("code", { style: { color: "#60a5fa" }, children: "http://node1.127.0.0.1.nip.io" })
|
|
734
|
+
] }) : null }),
|
|
735
|
+
/* @__PURE__ */ jsx("div", { style: styles.buttonGroup, children: /* @__PURE__ */ jsx(
|
|
736
|
+
"button",
|
|
737
|
+
{
|
|
738
|
+
onClick: handleConnect,
|
|
739
|
+
disabled: !isValid || loading,
|
|
740
|
+
style: {
|
|
741
|
+
...styles.button,
|
|
742
|
+
...!isValid || loading ? styles.buttonDisabled : {}
|
|
743
|
+
},
|
|
744
|
+
children: "Connect"
|
|
745
|
+
}
|
|
746
|
+
) })
|
|
747
|
+
] })
|
|
748
|
+
] }) })
|
|
749
|
+
] });
|
|
750
|
+
return createPortal(modalContent, document.body);
|
|
751
|
+
}
|
|
752
|
+
function MeroLogo() {
|
|
753
|
+
return /* @__PURE__ */ jsx(
|
|
754
|
+
"svg",
|
|
755
|
+
{
|
|
756
|
+
width: "40",
|
|
757
|
+
height: "40",
|
|
758
|
+
viewBox: "0 0 24 24",
|
|
759
|
+
fill: "#3b82f6",
|
|
760
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
761
|
+
children: /* @__PURE__ */ jsx("path", { d: "M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8zm-1-13h2v6h-2zm0 8h2v2h-2z" })
|
|
762
|
+
}
|
|
763
|
+
);
|
|
764
|
+
}
|
|
765
|
+
function ConnectButton({
|
|
766
|
+
connectionType = "remote-and-local" /* RemoteAndLocal */,
|
|
767
|
+
className,
|
|
768
|
+
style
|
|
769
|
+
}) {
|
|
770
|
+
const { isAuthenticated, connectToNode, logout, nodeUrl, isOnline } = useMero();
|
|
771
|
+
const [isDropdownOpen, setIsDropdownOpen] = useState(false);
|
|
772
|
+
const [isModalOpen, setIsModalOpen] = useState(false);
|
|
773
|
+
const dropdownRef = useRef(null);
|
|
774
|
+
useEffect(() => {
|
|
775
|
+
const handleClickOutside = (event) => {
|
|
776
|
+
if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
|
|
777
|
+
setIsDropdownOpen(false);
|
|
778
|
+
}
|
|
779
|
+
};
|
|
780
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
781
|
+
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
782
|
+
}, []);
|
|
783
|
+
const dashboardUrl = useMemo(() => {
|
|
784
|
+
if (!isAuthenticated || !nodeUrl) return "#";
|
|
785
|
+
return new URL("admin-dashboard/", nodeUrl).toString();
|
|
786
|
+
}, [isAuthenticated, nodeUrl]);
|
|
787
|
+
const handleConnect = () => {
|
|
788
|
+
if (typeof connectionType === "object" && connectionType.type === "custom" /* Custom */) {
|
|
789
|
+
connectToNode(connectionType.url);
|
|
790
|
+
return;
|
|
791
|
+
}
|
|
792
|
+
setIsModalOpen(true);
|
|
793
|
+
};
|
|
794
|
+
const handleModalConnect = (url) => {
|
|
795
|
+
setIsModalOpen(false);
|
|
796
|
+
connectToNode(url);
|
|
797
|
+
};
|
|
798
|
+
if (isAuthenticated && !isOnline) {
|
|
799
|
+
return /* @__PURE__ */ jsxs(
|
|
800
|
+
"button",
|
|
801
|
+
{
|
|
802
|
+
className: `mero-connect-button mero-reconnecting ${className || ""}`,
|
|
803
|
+
style,
|
|
804
|
+
disabled: true,
|
|
805
|
+
children: [
|
|
806
|
+
/* @__PURE__ */ jsx(MeroLogo2, {}),
|
|
807
|
+
"Reconnecting..."
|
|
808
|
+
]
|
|
809
|
+
}
|
|
810
|
+
);
|
|
811
|
+
}
|
|
812
|
+
if (isAuthenticated) {
|
|
813
|
+
return /* @__PURE__ */ jsxs("div", { ref: dropdownRef, className: "mero-connect-container", style: { position: "relative", display: "inline-block" }, children: [
|
|
814
|
+
/* @__PURE__ */ jsxs(
|
|
815
|
+
"button",
|
|
816
|
+
{
|
|
817
|
+
className: `mero-connect-button mero-connected ${className || ""}`,
|
|
818
|
+
style,
|
|
819
|
+
onClick: () => setIsDropdownOpen((prev) => !prev),
|
|
820
|
+
children: [
|
|
821
|
+
/* @__PURE__ */ jsx(MeroLogo2, {}),
|
|
822
|
+
"Connected"
|
|
823
|
+
]
|
|
824
|
+
}
|
|
825
|
+
),
|
|
826
|
+
isDropdownOpen && /* @__PURE__ */ jsxs("div", { className: "mero-dropdown", children: [
|
|
827
|
+
/* @__PURE__ */ jsx("div", { className: "mero-dropdown-info", title: nodeUrl || "", children: nodeUrl }),
|
|
828
|
+
/* @__PURE__ */ jsx(
|
|
829
|
+
"a",
|
|
830
|
+
{
|
|
831
|
+
href: dashboardUrl,
|
|
832
|
+
target: "_blank",
|
|
833
|
+
rel: "noopener noreferrer",
|
|
834
|
+
className: "mero-dropdown-item",
|
|
835
|
+
children: "Dashboard"
|
|
836
|
+
}
|
|
837
|
+
),
|
|
838
|
+
/* @__PURE__ */ jsx(
|
|
839
|
+
"button",
|
|
840
|
+
{
|
|
841
|
+
className: "mero-dropdown-item",
|
|
842
|
+
onClick: () => {
|
|
843
|
+
setIsDropdownOpen(false);
|
|
844
|
+
logout();
|
|
845
|
+
},
|
|
846
|
+
children: "Log out"
|
|
847
|
+
}
|
|
848
|
+
)
|
|
849
|
+
] })
|
|
850
|
+
] });
|
|
851
|
+
}
|
|
852
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
853
|
+
/* @__PURE__ */ jsxs(
|
|
854
|
+
"button",
|
|
855
|
+
{
|
|
856
|
+
className: `mero-connect-button ${className || ""}`,
|
|
857
|
+
style,
|
|
858
|
+
onClick: handleConnect,
|
|
859
|
+
children: [
|
|
860
|
+
/* @__PURE__ */ jsx(MeroLogo2, {}),
|
|
861
|
+
"Connect"
|
|
862
|
+
]
|
|
863
|
+
}
|
|
864
|
+
),
|
|
865
|
+
/* @__PURE__ */ jsx(
|
|
866
|
+
LoginModal,
|
|
867
|
+
{
|
|
868
|
+
isOpen: isModalOpen,
|
|
869
|
+
onConnect: handleModalConnect,
|
|
870
|
+
onClose: () => setIsModalOpen(false),
|
|
871
|
+
connectionType: typeof connectionType === "object" ? "remote-and-local" /* RemoteAndLocal */ : connectionType
|
|
872
|
+
}
|
|
873
|
+
)
|
|
874
|
+
] });
|
|
875
|
+
}
|
|
876
|
+
function MeroLogo2() {
|
|
877
|
+
return /* @__PURE__ */ jsx(
|
|
878
|
+
"svg",
|
|
879
|
+
{
|
|
880
|
+
className: "mero-logo",
|
|
881
|
+
width: "24",
|
|
882
|
+
height: "24",
|
|
883
|
+
viewBox: "0 0 24 24",
|
|
884
|
+
fill: "currentColor",
|
|
885
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
886
|
+
children: /* @__PURE__ */ jsx("path", { d: "M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8zm-1-13h2v6h-2zm0 8h2v2h-2z" })
|
|
887
|
+
}
|
|
888
|
+
);
|
|
889
|
+
}
|
|
890
|
+
|
|
891
|
+
export { AppMode, ConnectButton, ConnectionType, EventStreamMode, LoginModal, MeroContext, MeroProvider, clearAllStorage, clearApplicationId, clearNodeUrl, getApplicationId, getNodeUrl, localStorageTokenStorage, setApplicationId, setNodeUrl, useMero };
|
|
892
|
+
//# sourceMappingURL=index.js.map
|
|
893
|
+
//# sourceMappingURL=index.js.map
|