@calimero-network/mero-react 1.0.0-beta.1 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +201 -125
- package/dist/index.cjs +248 -660
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +61 -57
- package/dist/index.d.ts +61 -57
- package/dist/index.js +237 -657
- package/dist/index.js.map +1 -1
- package/package.json +23 -10
package/dist/index.js
CHANGED
|
@@ -1,11 +1,25 @@
|
|
|
1
1
|
import { createContext, useState, useRef, useCallback, useEffect, useMemo, useContext } from 'react';
|
|
2
|
-
import { MeroJs } from '@calimero-network/mero-js';
|
|
3
|
-
export
|
|
4
|
-
import { jsx
|
|
5
|
-
import { createPortal } from 'react-dom';
|
|
2
|
+
import { parseAuthCallback, MeroJs, buildAuthLoginUrl, LocalStorageTokenStore } from '@calimero-network/mero-js';
|
|
3
|
+
export * from '@calimero-network/mero-js';
|
|
4
|
+
import { jsx } from 'react/jsx-runtime';
|
|
6
5
|
|
|
7
6
|
// src/context/MeroContext.tsx
|
|
8
7
|
|
|
8
|
+
// src/types.ts
|
|
9
|
+
var AppMode = /* @__PURE__ */ ((AppMode2) => {
|
|
10
|
+
AppMode2["SingleContext"] = "single-context";
|
|
11
|
+
AppMode2["MultiContext"] = "multi-context";
|
|
12
|
+
AppMode2["Admin"] = "admin";
|
|
13
|
+
return AppMode2;
|
|
14
|
+
})(AppMode || {});
|
|
15
|
+
var ConnectionType = /* @__PURE__ */ ((ConnectionType2) => {
|
|
16
|
+
ConnectionType2["RemoteAndLocal"] = "remote-and-local";
|
|
17
|
+
ConnectionType2["Remote"] = "remote";
|
|
18
|
+
ConnectionType2["Local"] = "local";
|
|
19
|
+
ConnectionType2["Custom"] = "custom";
|
|
20
|
+
return ConnectionType2;
|
|
21
|
+
})(ConnectionType || {});
|
|
22
|
+
|
|
9
23
|
// src/storage/index.ts
|
|
10
24
|
var STORAGE_KEYS = {
|
|
11
25
|
ACCESS_TOKEN: "mero:access_token",
|
|
@@ -13,20 +27,25 @@ var STORAGE_KEYS = {
|
|
|
13
27
|
EXPIRES_AT: "mero:expires_at",
|
|
14
28
|
NODE_URL: "mero:node_url",
|
|
15
29
|
APPLICATION_ID: "mero:application_id",
|
|
16
|
-
CONTEXT_ID: "mero:context_id"
|
|
30
|
+
CONTEXT_ID: "mero:context_id",
|
|
31
|
+
CONTEXT_IDENTITY: "mero:context_identity"
|
|
17
32
|
};
|
|
33
|
+
var _storageAvailable = null;
|
|
18
34
|
function isLocalStorageAvailable() {
|
|
35
|
+
if (_storageAvailable !== null) return _storageAvailable;
|
|
19
36
|
try {
|
|
20
37
|
if (typeof window === "undefined" || !window.localStorage) {
|
|
38
|
+
_storageAvailable = false;
|
|
21
39
|
return false;
|
|
22
40
|
}
|
|
23
41
|
const testKey = "__mero_test__";
|
|
24
42
|
localStorage.setItem(testKey, "test");
|
|
25
43
|
localStorage.removeItem(testKey);
|
|
26
|
-
|
|
44
|
+
_storageAvailable = true;
|
|
27
45
|
} catch {
|
|
28
|
-
|
|
46
|
+
_storageAvailable = false;
|
|
29
47
|
}
|
|
48
|
+
return _storageAvailable;
|
|
30
49
|
}
|
|
31
50
|
var localStorageTokenStorage = {
|
|
32
51
|
async get() {
|
|
@@ -107,46 +126,37 @@ function setContextId(id) {
|
|
|
107
126
|
if (!isLocalStorageAvailable()) return;
|
|
108
127
|
localStorage.setItem(STORAGE_KEYS.CONTEXT_ID, id);
|
|
109
128
|
}
|
|
129
|
+
function clearContextId() {
|
|
130
|
+
if (!isLocalStorageAvailable()) return;
|
|
131
|
+
localStorage.removeItem(STORAGE_KEYS.CONTEXT_ID);
|
|
132
|
+
}
|
|
133
|
+
function getContextIdentity() {
|
|
134
|
+
if (!isLocalStorageAvailable()) return null;
|
|
135
|
+
return localStorage.getItem(STORAGE_KEYS.CONTEXT_IDENTITY);
|
|
136
|
+
}
|
|
137
|
+
function setContextIdentity(id) {
|
|
138
|
+
if (!isLocalStorageAvailable()) return;
|
|
139
|
+
localStorage.setItem(STORAGE_KEYS.CONTEXT_IDENTITY, id);
|
|
140
|
+
}
|
|
141
|
+
function clearContextIdentity() {
|
|
142
|
+
if (!isLocalStorageAvailable()) return;
|
|
143
|
+
localStorage.removeItem(STORAGE_KEYS.CONTEXT_IDENTITY);
|
|
144
|
+
}
|
|
110
145
|
function clearAllStorage() {
|
|
111
146
|
if (!isLocalStorageAvailable()) return;
|
|
112
147
|
Object.values(STORAGE_KEYS).forEach((key) => {
|
|
113
148
|
localStorage.removeItem(key);
|
|
114
149
|
});
|
|
115
150
|
}
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
var
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
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);
|
|
151
|
+
var MeroContext = createContext(null);
|
|
152
|
+
var isBrowser = typeof window !== "undefined";
|
|
153
|
+
var _tokenStore = null;
|
|
154
|
+
function getTokenStore() {
|
|
155
|
+
if (!_tokenStore) {
|
|
156
|
+
_tokenStore = new LocalStorageTokenStore();
|
|
157
|
+
}
|
|
158
|
+
return _tokenStore;
|
|
159
|
+
}
|
|
150
160
|
function getPermissionsForMode(mode) {
|
|
151
161
|
switch (mode) {
|
|
152
162
|
case "single-context" /* SingleContext */:
|
|
@@ -159,27 +169,20 @@ function getPermissionsForMode(mode) {
|
|
|
159
169
|
throw new Error(`Unsupported application mode: ${mode}`);
|
|
160
170
|
}
|
|
161
171
|
}
|
|
162
|
-
function
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
if (params.registryUrl) {
|
|
173
|
-
authParams.append("registry-url", params.registryUrl);
|
|
172
|
+
function parseJwtExpiry(token) {
|
|
173
|
+
try {
|
|
174
|
+
const parts = token.split(".");
|
|
175
|
+
if (parts.length === 3) {
|
|
176
|
+
let b64 = parts[1].replace(/-/g, "+").replace(/_/g, "/");
|
|
177
|
+
while (b64.length % 4) b64 += "=";
|
|
178
|
+
const payload = JSON.parse(atob(b64));
|
|
179
|
+
if (payload.exp && payload.exp > 0) {
|
|
180
|
+
return payload.exp * 1e3;
|
|
181
|
+
}
|
|
174
182
|
}
|
|
175
|
-
}
|
|
176
|
-
authParams.append("application-id", params.applicationId);
|
|
177
|
-
}
|
|
178
|
-
if (params.applicationPath) {
|
|
179
|
-
authParams.append("application-path", params.applicationPath);
|
|
183
|
+
} catch {
|
|
180
184
|
}
|
|
181
|
-
|
|
182
|
-
window.location.href = `${params.nodeUrl}/auth/login?${authParams.toString()}`;
|
|
185
|
+
return Date.now() + 36e5;
|
|
183
186
|
}
|
|
184
187
|
function MeroProvider({
|
|
185
188
|
children,
|
|
@@ -187,8 +190,6 @@ function MeroProvider({
|
|
|
187
190
|
packageName,
|
|
188
191
|
packageVersion,
|
|
189
192
|
registryUrl,
|
|
190
|
-
applicationId: propApplicationId,
|
|
191
|
-
applicationPath,
|
|
192
193
|
timeoutMs = 3e4
|
|
193
194
|
}) {
|
|
194
195
|
const [mero, setMero] = useState(null);
|
|
@@ -197,15 +198,23 @@ function MeroProvider({
|
|
|
197
198
|
const [isLoading, setIsLoading] = useState(true);
|
|
198
199
|
const [nodeUrl, setNodeUrlState] = useState(() => getNodeUrl());
|
|
199
200
|
const [applicationId, setApplicationIdState] = useState(
|
|
200
|
-
() => getApplicationId() ||
|
|
201
|
+
() => getApplicationId() || null
|
|
201
202
|
);
|
|
202
203
|
const [contextId, setContextIdState] = useState(() => getContextId());
|
|
204
|
+
const [contextIdentity, setContextIdentityState] = useState(() => getContextIdentity());
|
|
203
205
|
const meroRef = useRef(null);
|
|
206
|
+
const callbackRef = useRef(void 0);
|
|
207
|
+
if (callbackRef.current === void 0 && isBrowser) {
|
|
208
|
+
callbackRef.current = parseAuthCallback(window.location.href);
|
|
209
|
+
}
|
|
204
210
|
const createMeroInstance = useCallback(
|
|
205
211
|
(url) => {
|
|
212
|
+
if (meroRef.current) {
|
|
213
|
+
meroRef.current.close();
|
|
214
|
+
}
|
|
206
215
|
const instance = new MeroJs({
|
|
207
216
|
baseUrl: url,
|
|
208
|
-
|
|
217
|
+
tokenStore: getTokenStore(),
|
|
209
218
|
timeoutMs
|
|
210
219
|
});
|
|
211
220
|
meroRef.current = instance;
|
|
@@ -215,127 +224,35 @@ function MeroProvider({
|
|
|
215
224
|
);
|
|
216
225
|
const checkAuth = useCallback(async (instance) => {
|
|
217
226
|
try {
|
|
218
|
-
await instance.admin.
|
|
227
|
+
await instance.admin.getContexts();
|
|
219
228
|
return true;
|
|
220
229
|
} catch {
|
|
221
230
|
return false;
|
|
222
231
|
}
|
|
223
232
|
}, []);
|
|
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
233
|
const connectToNode = useCallback(
|
|
310
234
|
(url) => {
|
|
235
|
+
if (!isBrowser) return;
|
|
311
236
|
setNodeUrl(url);
|
|
312
237
|
setNodeUrlState(url);
|
|
313
238
|
const callbackUrl = new URL(window.location.href);
|
|
314
|
-
|
|
315
|
-
|
|
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,
|
|
239
|
+
callbackUrl.hash = "";
|
|
240
|
+
const loginUrl = buildAuthLoginUrl(url, {
|
|
324
241
|
callbackUrl: callbackUrl.toString(),
|
|
325
|
-
permissions,
|
|
242
|
+
permissions: getPermissionsForMode(mode),
|
|
326
243
|
mode,
|
|
327
244
|
packageName,
|
|
328
245
|
packageVersion,
|
|
329
|
-
registryUrl
|
|
330
|
-
applicationId: propApplicationId,
|
|
331
|
-
applicationPath
|
|
246
|
+
registryUrl
|
|
332
247
|
});
|
|
248
|
+
window.location.href = loginUrl;
|
|
333
249
|
},
|
|
334
|
-
[mode, packageName, packageVersion, registryUrl
|
|
250
|
+
[mode, packageName, packageVersion, registryUrl]
|
|
335
251
|
);
|
|
336
|
-
const logout = useCallback(
|
|
252
|
+
const logout = useCallback(() => {
|
|
337
253
|
if (meroRef.current) {
|
|
338
|
-
|
|
254
|
+
meroRef.current.clearToken();
|
|
255
|
+
meroRef.current.close();
|
|
339
256
|
}
|
|
340
257
|
clearAllStorage();
|
|
341
258
|
setMero(null);
|
|
@@ -343,56 +260,90 @@ function MeroProvider({
|
|
|
343
260
|
setNodeUrlState(null);
|
|
344
261
|
setApplicationIdState(null);
|
|
345
262
|
setContextIdState(null);
|
|
263
|
+
setContextIdentityState(null);
|
|
346
264
|
meroRef.current = null;
|
|
347
265
|
}, []);
|
|
348
266
|
useEffect(() => {
|
|
267
|
+
let active = true;
|
|
349
268
|
const init = async () => {
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
269
|
+
const callback = callbackRef.current;
|
|
270
|
+
if (callback) {
|
|
271
|
+
getTokenStore().setTokens({
|
|
272
|
+
access_token: callback.accessToken,
|
|
273
|
+
refresh_token: callback.refreshToken,
|
|
274
|
+
expires_at: parseJwtExpiry(callback.accessToken)
|
|
275
|
+
});
|
|
276
|
+
if (callback.applicationId) {
|
|
277
|
+
setApplicationId(callback.applicationId);
|
|
278
|
+
if (active) setApplicationIdState(callback.applicationId);
|
|
279
|
+
}
|
|
280
|
+
if (callback.contextId) {
|
|
281
|
+
setContextId(callback.contextId);
|
|
282
|
+
if (active) setContextIdState(callback.contextId);
|
|
283
|
+
}
|
|
284
|
+
if (callback.contextIdentity) {
|
|
285
|
+
setContextIdentity(callback.contextIdentity);
|
|
286
|
+
if (active) setContextIdentityState(callback.contextIdentity);
|
|
287
|
+
}
|
|
288
|
+
if (callback.nodeUrl) {
|
|
289
|
+
setNodeUrl(callback.nodeUrl);
|
|
290
|
+
if (active) setNodeUrlState(callback.nodeUrl);
|
|
291
|
+
}
|
|
292
|
+
if (isBrowser) {
|
|
293
|
+
window.history.replaceState({}, "", window.location.pathname + window.location.search);
|
|
294
|
+
}
|
|
295
|
+
callbackRef.current = null;
|
|
296
|
+
}
|
|
297
|
+
const savedUrl = callback?.nodeUrl || getNodeUrl();
|
|
358
298
|
if (!savedUrl) {
|
|
359
|
-
setIsLoading(false);
|
|
299
|
+
if (active) setIsLoading(false);
|
|
360
300
|
return;
|
|
361
301
|
}
|
|
362
302
|
const instance = createMeroInstance(savedUrl);
|
|
363
|
-
await instance.init();
|
|
364
303
|
const authed = await checkAuth(instance);
|
|
304
|
+
if (!active) return;
|
|
365
305
|
if (authed) {
|
|
366
306
|
setMero(instance);
|
|
367
307
|
setIsAuthenticated(true);
|
|
368
308
|
setIsOnline(true);
|
|
369
|
-
} else if (
|
|
309
|
+
} else if (callback) {
|
|
370
310
|
setMero(instance);
|
|
371
|
-
setIsAuthenticated(false);
|
|
372
311
|
}
|
|
373
312
|
setIsLoading(false);
|
|
374
313
|
};
|
|
375
|
-
init()
|
|
376
|
-
|
|
314
|
+
init().catch((err) => {
|
|
315
|
+
console.error("[MeroProvider] Initialization failed:", err);
|
|
316
|
+
if (active) setIsLoading(false);
|
|
317
|
+
});
|
|
318
|
+
return () => {
|
|
319
|
+
active = false;
|
|
320
|
+
};
|
|
321
|
+
}, [createMeroInstance, checkAuth]);
|
|
377
322
|
useEffect(() => {
|
|
378
323
|
if (!isAuthenticated || !meroRef.current) return;
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
324
|
+
let active = true;
|
|
325
|
+
const sse = meroRef.current.events;
|
|
326
|
+
const onConnect = () => {
|
|
327
|
+
if (active) setIsOnline(true);
|
|
328
|
+
};
|
|
329
|
+
const onError = (err) => {
|
|
330
|
+
if (!active) return;
|
|
331
|
+
setIsOnline(false);
|
|
332
|
+
if (err.message.includes("401")) {
|
|
333
|
+
logout();
|
|
387
334
|
}
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
335
|
+
};
|
|
336
|
+
sse.on("connect", onConnect);
|
|
337
|
+
sse.on("error", onError);
|
|
338
|
+
sse.connect().catch(() => {
|
|
339
|
+
if (active) setIsOnline(false);
|
|
340
|
+
});
|
|
341
|
+
return () => {
|
|
342
|
+
active = false;
|
|
343
|
+
sse.off("connect", onConnect);
|
|
344
|
+
sse.off("error", onError);
|
|
345
|
+
};
|
|
346
|
+
}, [isAuthenticated, mero]);
|
|
396
347
|
const contextValue = useMemo(
|
|
397
348
|
() => ({
|
|
398
349
|
mero,
|
|
@@ -401,493 +352,122 @@ function MeroProvider({
|
|
|
401
352
|
nodeUrl,
|
|
402
353
|
applicationId,
|
|
403
354
|
contextId,
|
|
355
|
+
contextIdentity,
|
|
404
356
|
connectToNode,
|
|
405
357
|
logout,
|
|
406
358
|
isLoading
|
|
407
359
|
}),
|
|
408
|
-
[mero, isAuthenticated, isOnline, nodeUrl, applicationId, contextId, connectToNode, logout, isLoading]
|
|
360
|
+
[mero, isAuthenticated, isOnline, nodeUrl, applicationId, contextId, contextIdentity, connectToNode, logout, isLoading]
|
|
409
361
|
);
|
|
410
362
|
return /* @__PURE__ */ jsx(MeroContext.Provider, { value: contextValue, children });
|
|
411
363
|
}
|
|
412
364
|
function useMero() {
|
|
413
365
|
const context = useContext(MeroContext);
|
|
414
|
-
if (context
|
|
366
|
+
if (!context) {
|
|
415
367
|
throw new Error("useMero must be used within a MeroProvider");
|
|
416
368
|
}
|
|
417
369
|
return context;
|
|
418
370
|
}
|
|
419
|
-
function
|
|
420
|
-
|
|
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);
|
|
371
|
+
function useExecute(contextId, executorId) {
|
|
372
|
+
const { mero } = useMero();
|
|
600
373
|
const [loading, setLoading] = useState(false);
|
|
601
374
|
const [error, setError] = useState(null);
|
|
602
|
-
const
|
|
603
|
-
const shouldShowRemote = connectionType === "remote-and-local" /* RemoteAndLocal */ || connectionType === "remote" /* Remote */;
|
|
604
|
-
const shouldShowRadioGroup = shouldShowLocal && shouldShowRemote;
|
|
375
|
+
const mountedRef = useRef(true);
|
|
605
376
|
useEffect(() => {
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
}
|
|
377
|
+
mountedRef.current = true;
|
|
378
|
+
return () => {
|
|
379
|
+
mountedRef.current = false;
|
|
380
|
+
};
|
|
610
381
|
}, []);
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
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}`);
|
|
382
|
+
const execute = useCallback(
|
|
383
|
+
async (method, params) => {
|
|
384
|
+
if (!mero || !contextId || !executorId) {
|
|
385
|
+
if (mountedRef.current) setError(new Error("Not connected"));
|
|
386
|
+
return null;
|
|
640
387
|
}
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
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
|
-
}
|
|
388
|
+
if (mountedRef.current) {
|
|
389
|
+
setLoading(true);
|
|
390
|
+
setError(null);
|
|
391
|
+
}
|
|
392
|
+
try {
|
|
393
|
+
const result = await mero.rpc.execute({
|
|
394
|
+
contextId,
|
|
395
|
+
method,
|
|
396
|
+
argsJson: params,
|
|
397
|
+
executorPublicKey: executorId
|
|
398
|
+
});
|
|
399
|
+
return result;
|
|
400
|
+
} catch (err) {
|
|
401
|
+
const e = err instanceof Error ? err : new Error(String(err));
|
|
402
|
+
if (mountedRef.current) setError(e);
|
|
403
|
+
return null;
|
|
404
|
+
} finally {
|
|
405
|
+
if (mountedRef.current) setLoading(false);
|
|
406
|
+
}
|
|
407
|
+
},
|
|
408
|
+
[mero, contextId, executorId]
|
|
763
409
|
);
|
|
410
|
+
return { execute, loading, error };
|
|
764
411
|
}
|
|
765
|
-
function
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
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);
|
|
412
|
+
function useSubscription(contextIds, callback) {
|
|
413
|
+
const { mero } = useMero();
|
|
414
|
+
const callbackRef = useRef(callback);
|
|
415
|
+
callbackRef.current = callback;
|
|
416
|
+
const contextIdsKey = JSON.stringify(contextIds);
|
|
774
417
|
useEffect(() => {
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
418
|
+
if (!mero || contextIds.length === 0) return;
|
|
419
|
+
const sse = mero.events;
|
|
420
|
+
const handler = (event) => {
|
|
421
|
+
callbackRef.current(event);
|
|
422
|
+
};
|
|
423
|
+
sse.on("event", handler);
|
|
424
|
+
sse.connect().catch(() => {
|
|
425
|
+
});
|
|
426
|
+
sse.subscribe(contextIds).catch(() => {
|
|
427
|
+
});
|
|
428
|
+
return () => {
|
|
429
|
+
sse.off("event", handler);
|
|
430
|
+
};
|
|
431
|
+
}, [mero, contextIdsKey]);
|
|
432
|
+
}
|
|
433
|
+
function useContexts(applicationId) {
|
|
434
|
+
const { mero } = useMero();
|
|
435
|
+
const [contexts, setContexts] = useState([]);
|
|
436
|
+
const [loading, setLoading] = useState(false);
|
|
437
|
+
const [error, setError] = useState(null);
|
|
438
|
+
const mountedRef = useRef(true);
|
|
439
|
+
useEffect(() => {
|
|
440
|
+
mountedRef.current = true;
|
|
441
|
+
return () => {
|
|
442
|
+
mountedRef.current = false;
|
|
779
443
|
};
|
|
780
|
-
document.addEventListener("mousedown", handleClickOutside);
|
|
781
|
-
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
782
444
|
}, []);
|
|
783
|
-
const
|
|
784
|
-
if (!
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
if (typeof connectionType === "object" && connectionType.type === "custom" /* Custom */) {
|
|
789
|
-
connectToNode(connectionType.url);
|
|
790
|
-
return;
|
|
445
|
+
const refetch = useCallback(async () => {
|
|
446
|
+
if (!mero) return;
|
|
447
|
+
if (mountedRef.current) {
|
|
448
|
+
setLoading(true);
|
|
449
|
+
setError(null);
|
|
791
450
|
}
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
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
|
|
451
|
+
try {
|
|
452
|
+
const response = await mero.admin.getContexts();
|
|
453
|
+
let list = (response.contexts ?? []).map((c) => ({ contextId: c.id, applicationId: c.applicationId }));
|
|
454
|
+
if (applicationId) {
|
|
455
|
+
list = list.filter((c) => c.applicationId === applicationId);
|
|
872
456
|
}
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
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" })
|
|
457
|
+
if (mountedRef.current) setContexts(list);
|
|
458
|
+
} catch (err) {
|
|
459
|
+
const e = err instanceof Error ? err : new Error(String(err));
|
|
460
|
+
if (mountedRef.current) setError(e);
|
|
461
|
+
} finally {
|
|
462
|
+
if (mountedRef.current) setLoading(false);
|
|
887
463
|
}
|
|
888
|
-
);
|
|
464
|
+
}, [mero, applicationId]);
|
|
465
|
+
useEffect(() => {
|
|
466
|
+
void refetch();
|
|
467
|
+
}, [refetch]);
|
|
468
|
+
return { contexts, loading, error, refetch };
|
|
889
469
|
}
|
|
890
470
|
|
|
891
|
-
export { AppMode,
|
|
471
|
+
export { AppMode, ConnectionType, MeroContext, MeroProvider, clearAllStorage, clearApplicationId, clearContextId, clearContextIdentity, clearNodeUrl, getApplicationId, getContextId, getContextIdentity, getNodeUrl, localStorageTokenStorage, setApplicationId, setContextId, setContextIdentity, setNodeUrl, useContexts, useExecute, useMero, useSubscription };
|
|
892
472
|
//# sourceMappingURL=index.js.map
|
|
893
473
|
//# sourceMappingURL=index.js.map
|