cilantro-react 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs ADDED
@@ -0,0 +1,2837 @@
1
+ 'use client';
2
+
3
+ // src/providers/CilantroProvider.tsx
4
+ import { useEffect as useEffect3 } from "react";
5
+
6
+ // src/providers/CilantroAuthProvider.tsx
7
+ import { createContext, useContext, useEffect, useState } from "react";
8
+ import { clearAuth } from "cilantro-sdk";
9
+ import { login as cilantroLogin } from "cilantro-sdk/auth";
10
+ import { create as createUser } from "cilantro-sdk/user";
11
+
12
+ // src/core/auth.ts
13
+ import { setAuth } from "cilantro-sdk";
14
+ var platformApiKey = "";
15
+ var apiUrl;
16
+ function setAuthConfig(config) {
17
+ platformApiKey = config.platformApiKey;
18
+ apiUrl = config.apiUrl;
19
+ const authPayload = {};
20
+ if (config.jwt) {
21
+ authPayload.jwt = config.jwt;
22
+ }
23
+ if (platformApiKey) {
24
+ authPayload.platformApiKey = platformApiKey;
25
+ }
26
+ if (apiUrl) {
27
+ authPayload.apiUrl = apiUrl;
28
+ }
29
+ setAuth(authPayload);
30
+ }
31
+ function setSdkAuth(jwt) {
32
+ const authConfig = {};
33
+ if (jwt) {
34
+ authConfig.jwt = jwt;
35
+ }
36
+ if (platformApiKey) {
37
+ authConfig.platformApiKey = platformApiKey;
38
+ }
39
+ if (apiUrl) {
40
+ authConfig.apiUrl = apiUrl;
41
+ }
42
+ setAuth(authConfig);
43
+ }
44
+ function getPlatformApiKey() {
45
+ return platformApiKey;
46
+ }
47
+
48
+ // src/core/types.ts
49
+ function extractResponseData(response) {
50
+ if (!response) return null;
51
+ if (typeof response !== "object" || response === null) {
52
+ return response;
53
+ }
54
+ if ("data" in response) {
55
+ const data = response.data;
56
+ if (data && typeof data === "object" && !Array.isArray(data)) {
57
+ const dataObj = data;
58
+ if ("authenticationSigners" in dataObj || "onChainSigners" in dataObj) {
59
+ const authSigners = Array.isArray(dataObj.authenticationSigners) ? dataObj.authenticationSigners : [];
60
+ const onChainSigners = Array.isArray(dataObj.onChainSigners) ? dataObj.onChainSigners : [];
61
+ return [...authSigners, ...onChainSigners];
62
+ }
63
+ }
64
+ return data;
65
+ }
66
+ if ("success" in response && "data" in response) {
67
+ const data = response.data;
68
+ if (data && typeof data === "object" && !Array.isArray(data)) {
69
+ const dataObj = data;
70
+ if ("authenticationSigners" in dataObj || "onChainSigners" in dataObj) {
71
+ const authSigners = Array.isArray(dataObj.authenticationSigners) ? dataObj.authenticationSigners : [];
72
+ const onChainSigners = Array.isArray(dataObj.onChainSigners) ? dataObj.onChainSigners : [];
73
+ return [...authSigners, ...onChainSigners];
74
+ }
75
+ }
76
+ return data;
77
+ }
78
+ if ("authenticationSigners" in response || "onChainSigners" in response) {
79
+ const responseObj = response;
80
+ const authSigners = Array.isArray(responseObj.authenticationSigners) ? responseObj.authenticationSigners : [];
81
+ const onChainSigners = Array.isArray(responseObj.onChainSigners) ? responseObj.onChainSigners : [];
82
+ return [...authSigners, ...onChainSigners];
83
+ }
84
+ return response;
85
+ }
86
+ function extractOnChainSigners(response) {
87
+ if (!response || typeof response !== "object" || response === null) return [];
88
+ let signersObj = null;
89
+ if ("data" in response) {
90
+ const data = response.data;
91
+ if (data && typeof data === "object" && !Array.isArray(data)) {
92
+ const dataObj = data;
93
+ if ("authenticationSigners" in dataObj || "onChainSigners" in dataObj) signersObj = dataObj;
94
+ }
95
+ }
96
+ if (!signersObj && "success" in response && "data" in response) {
97
+ const data = response.data;
98
+ if (data && typeof data === "object" && !Array.isArray(data)) {
99
+ const dataObj = data;
100
+ if ("authenticationSigners" in dataObj || "onChainSigners" in dataObj) signersObj = dataObj;
101
+ }
102
+ }
103
+ if (!signersObj && ("authenticationSigners" in response || "onChainSigners" in response)) {
104
+ signersObj = response;
105
+ }
106
+ if (signersObj) {
107
+ return Array.isArray(signersObj.onChainSigners) ? signersObj.onChainSigners : [];
108
+ }
109
+ if (Array.isArray(response)) return response;
110
+ return [];
111
+ }
112
+ function extractAuthenticationSigners(response) {
113
+ if (!response || typeof response !== "object" || response === null) return [];
114
+ let signersObj = null;
115
+ if ("data" in response) {
116
+ const data = response.data;
117
+ if (data && typeof data === "object" && !Array.isArray(data)) {
118
+ const dataObj = data;
119
+ if ("authenticationSigners" in dataObj || "onChainSigners" in dataObj) signersObj = dataObj;
120
+ }
121
+ }
122
+ if (!signersObj && "success" in response && "data" in response) {
123
+ const data = response.data;
124
+ if (data && typeof data === "object" && !Array.isArray(data)) {
125
+ const dataObj = data;
126
+ if ("authenticationSigners" in dataObj || "onChainSigners" in dataObj) signersObj = dataObj;
127
+ }
128
+ }
129
+ if (!signersObj && ("authenticationSigners" in response || "onChainSigners" in response)) {
130
+ signersObj = response;
131
+ }
132
+ if (signersObj) {
133
+ return Array.isArray(signersObj.authenticationSigners) ? signersObj.authenticationSigners : [];
134
+ }
135
+ return [];
136
+ }
137
+ function isErrorWithResponse(error) {
138
+ return typeof error === "object" && error !== null && "response" in error;
139
+ }
140
+ function isErrorWithMessage(error) {
141
+ return typeof error === "object" && error !== null && "message" in error;
142
+ }
143
+
144
+ // src/core/error-utils.ts
145
+ function extractErrorMessage(error) {
146
+ if (!error) return "An unknown error occurred";
147
+ if (error instanceof Error) return error.message;
148
+ if (isErrorWithResponse(error)) {
149
+ if (error.response?.data?.message) return String(error.response.data.message);
150
+ if (error.response?.data?.error) return String(error.response.data.error);
151
+ }
152
+ if (isErrorWithMessage(error)) return String(error.message);
153
+ if (typeof error === "object" && error !== null && "error" in error) {
154
+ return String(error.error);
155
+ }
156
+ return String(error);
157
+ }
158
+
159
+ // src/providers/CilantroAuthProvider.tsx
160
+ import { jsx } from "react/jsx-runtime";
161
+ var AuthContext = createContext(void 0);
162
+ var DEFAULT_JWT_STORAGE_KEY = "cilantro_jwt";
163
+ function CilantroAuthProvider({
164
+ children,
165
+ platformApiKey: platformApiKey2,
166
+ apiUrl: apiUrl2,
167
+ jwtStorageKey = DEFAULT_JWT_STORAGE_KEY,
168
+ onLoginSuccess,
169
+ onLogout,
170
+ onRegisterSuccess
171
+ }) {
172
+ const [user, setUser] = useState(null);
173
+ const [token, setToken] = useState(null);
174
+ const [isLoading, setIsLoading] = useState(true);
175
+ useEffect(() => {
176
+ setAuthConfig({ platformApiKey: platformApiKey2, apiUrl: apiUrl2 });
177
+ setSdkAuth(null);
178
+ const storedToken = typeof window !== "undefined" ? localStorage.getItem(jwtStorageKey) : null;
179
+ if (storedToken) {
180
+ setToken(storedToken);
181
+ setSdkAuth(storedToken);
182
+ try {
183
+ const payload = JSON.parse(atob(storedToken.split(".")[1]));
184
+ setUser({
185
+ username: payload.username,
186
+ email: payload.email,
187
+ userType: payload.userType
188
+ });
189
+ } catch {
190
+ }
191
+ }
192
+ setIsLoading(false);
193
+ }, [platformApiKey2, apiUrl2, jwtStorageKey]);
194
+ const login = async (usernameOrEmail, password) => {
195
+ try {
196
+ const result = await cilantroLogin({ usernameOrEmail, password });
197
+ const responseData = extractResponseData(result);
198
+ if (!responseData?.jwt) throw new Error("No JWT token received from server");
199
+ const jwt = responseData.jwt;
200
+ const userType = responseData.userType;
201
+ setToken(jwt);
202
+ setSdkAuth(jwt);
203
+ if (typeof window !== "undefined") {
204
+ localStorage.setItem(jwtStorageKey, jwt);
205
+ document.cookie = `cilantro_jwt=${jwt}; path=/; max-age=${60 * 60 * 24 * 7}`;
206
+ }
207
+ try {
208
+ const payload = JSON.parse(atob(jwt.split(".")[1]));
209
+ setUser({
210
+ username: payload.username,
211
+ email: payload.email,
212
+ userType: userType ?? payload.userType
213
+ });
214
+ } catch {
215
+ setUser({ userType });
216
+ }
217
+ onLoginSuccess?.();
218
+ } catch (error) {
219
+ throw new Error(extractErrorMessage(error));
220
+ }
221
+ };
222
+ const register = async (username, email, password, isActive = true) => {
223
+ try {
224
+ setSdkAuth(null);
225
+ const platformKey = getPlatformApiKey();
226
+ const userData = { username, email, password, isActive };
227
+ if (platformKey) userData.platformApiKey = platformKey;
228
+ await createUser(userData);
229
+ await login(username, password);
230
+ onRegisterSuccess?.();
231
+ } catch (error) {
232
+ throw new Error(extractErrorMessage(error));
233
+ }
234
+ };
235
+ const logout = () => {
236
+ setUser(null);
237
+ setToken(null);
238
+ clearAuth();
239
+ if (typeof window !== "undefined") {
240
+ localStorage.removeItem(jwtStorageKey);
241
+ const keys = Object.keys(localStorage);
242
+ keys.forEach((key) => {
243
+ if (key.startsWith("delegated-key-")) localStorage.removeItem(key);
244
+ });
245
+ document.cookie = "cilantro_jwt=; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT";
246
+ }
247
+ setSdkAuth(null);
248
+ onLogout?.();
249
+ };
250
+ const value = {
251
+ user,
252
+ token,
253
+ isAuthenticated: !!token,
254
+ login,
255
+ register,
256
+ logout,
257
+ isLoading
258
+ };
259
+ return /* @__PURE__ */ jsx(AuthContext.Provider, { value, children });
260
+ }
261
+ function useCilantroAuth() {
262
+ const context = useContext(AuthContext);
263
+ if (context === void 0) {
264
+ throw new Error("useCilantroAuth must be used within a CilantroAuthProvider");
265
+ }
266
+ return context;
267
+ }
268
+
269
+ // src/providers/WalletProvider.tsx
270
+ import { createContext as createContext2, useContext as useContext2, useEffect as useEffect2, useState as useState2 } from "react";
271
+ import { findAll as findAllWallets } from "cilantro-sdk/wallet";
272
+ import { jsx as jsx2 } from "react/jsx-runtime";
273
+ var WalletContext = createContext2(void 0);
274
+ var DEFAULT_STORAGE_KEY = "cilantro_selected_wallet_id";
275
+ function WalletProvider({ children, storageKey = DEFAULT_STORAGE_KEY }) {
276
+ const { token } = useCilantroAuth();
277
+ const [wallets, setWallets] = useState2([]);
278
+ const [selectedWallet, setSelectedWallet] = useState2(null);
279
+ const [isLoading, setIsLoading] = useState2(true);
280
+ useEffect2(() => {
281
+ if (token) {
282
+ loadWallets();
283
+ } else {
284
+ setWallets([]);
285
+ setSelectedWallet(null);
286
+ setIsLoading(false);
287
+ }
288
+ }, [token]);
289
+ useEffect2(() => {
290
+ if (wallets.length > 0 && !selectedWallet) {
291
+ const storedWalletId = typeof window !== "undefined" ? localStorage.getItem(storageKey) : null;
292
+ if (storedWalletId) {
293
+ const wallet = wallets.find((w) => w.id === storedWalletId || w.walletId === storedWalletId);
294
+ if (wallet) {
295
+ setSelectedWallet(wallet);
296
+ } else {
297
+ setSelectedWallet(wallets[0]);
298
+ if (typeof window !== "undefined") localStorage.setItem(storageKey, wallets[0].id);
299
+ }
300
+ } else {
301
+ if (wallets.length > 0) {
302
+ setSelectedWallet(wallets[0]);
303
+ if (typeof window !== "undefined") localStorage.setItem(storageKey, wallets[0].id);
304
+ }
305
+ }
306
+ } else if (wallets.length === 0) {
307
+ setSelectedWallet(null);
308
+ if (typeof window !== "undefined") localStorage.removeItem(storageKey);
309
+ }
310
+ }, [wallets, storageKey]);
311
+ const loadWallets = async () => {
312
+ try {
313
+ setIsLoading(true);
314
+ if (token) setSdkAuth(token);
315
+ const result = await findAllWallets();
316
+ const walletsList = extractResponseData(result) ?? [];
317
+ const formattedWallets = Array.isArray(walletsList) ? walletsList.map((wallet) => {
318
+ const w = wallet;
319
+ return {
320
+ id: String(w.walletId ?? w.id ?? ""),
321
+ walletId: String(w.walletId ?? w.id ?? ""),
322
+ walletName: w.walletName ?? "",
323
+ address: w.walletAddress ?? w.address ?? "",
324
+ walletAddress: w.walletAddress ?? w.address ?? "",
325
+ chain: w.chain ?? "solana",
326
+ active: w.active !== false,
327
+ ...w
328
+ };
329
+ }) : [];
330
+ setWallets(formattedWallets);
331
+ } catch (error) {
332
+ console.error("Failed to load wallets:", error);
333
+ setWallets([]);
334
+ } finally {
335
+ setIsLoading(false);
336
+ }
337
+ };
338
+ const selectWallet = (walletId) => {
339
+ const wallet = wallets.find((w) => w.id === walletId || w.walletId === walletId);
340
+ if (wallet) {
341
+ setSelectedWallet(wallet);
342
+ if (typeof window !== "undefined") localStorage.setItem(storageKey, wallet.id);
343
+ }
344
+ };
345
+ const refreshWallets = async () => {
346
+ await loadWallets();
347
+ };
348
+ const value = {
349
+ selectedWallet,
350
+ wallets,
351
+ selectWallet,
352
+ refreshWallets,
353
+ isLoading
354
+ };
355
+ return /* @__PURE__ */ jsx2(WalletContext.Provider, { value, children });
356
+ }
357
+ function useWallets() {
358
+ const context = useContext2(WalletContext);
359
+ if (context === void 0) {
360
+ throw new Error("useWallets must be used within a WalletProvider");
361
+ }
362
+ return context;
363
+ }
364
+
365
+ // src/core/storage-adapter.ts
366
+ import { createIndexedDBAdapter } from "cilantro-sdk/helpers";
367
+ var storageAdapterInstance = null;
368
+ var initializationPromise = null;
369
+ async function initializeStorageAdapter() {
370
+ if (storageAdapterInstance) return storageAdapterInstance;
371
+ if (initializationPromise) return initializationPromise;
372
+ if (typeof window === "undefined") {
373
+ throw new Error("Storage adapter can only be initialized in browser environment.");
374
+ }
375
+ initializationPromise = (async () => {
376
+ try {
377
+ storageAdapterInstance = createIndexedDBAdapter();
378
+ return storageAdapterInstance;
379
+ } catch (error) {
380
+ initializationPromise = null;
381
+ throw error;
382
+ }
383
+ })();
384
+ return initializationPromise;
385
+ }
386
+ function getStorageAdapter() {
387
+ if (storageAdapterInstance) return storageAdapterInstance;
388
+ if (typeof window === "undefined") {
389
+ throw new Error("Storage adapter can only be initialized in browser environment.");
390
+ }
391
+ storageAdapterInstance = createIndexedDBAdapter();
392
+ return storageAdapterInstance;
393
+ }
394
+
395
+ // src/providers/CilantroProvider.tsx
396
+ import { jsx as jsx3 } from "react/jsx-runtime";
397
+ function CilantroProvider({
398
+ children,
399
+ platformApiKey: platformApiKey2,
400
+ apiUrl: apiUrl2,
401
+ jwtStorageKey,
402
+ walletStorageKey,
403
+ onLoginSuccess,
404
+ onLogout,
405
+ onRegisterSuccess
406
+ }) {
407
+ useEffect3(() => {
408
+ initializeStorageAdapter().catch((err) => {
409
+ console.error("[CilantroProvider] Failed to initialize storage adapter:", err);
410
+ });
411
+ }, []);
412
+ return /* @__PURE__ */ jsx3(
413
+ CilantroAuthProvider,
414
+ {
415
+ platformApiKey: platformApiKey2,
416
+ apiUrl: apiUrl2,
417
+ jwtStorageKey,
418
+ onLoginSuccess,
419
+ onLogout,
420
+ onRegisterSuccess,
421
+ children: /* @__PURE__ */ jsx3(WalletProvider, { storageKey: walletStorageKey, children })
422
+ }
423
+ );
424
+ }
425
+
426
+ // src/hooks/useSigners.ts
427
+ import { useState as useState3, useEffect as useEffect4, useCallback } from "react";
428
+
429
+ // src/core/signer-helpers.ts
430
+ import { getSigners, parseSignerResponse } from "cilantro-sdk/helpers";
431
+ import { listSigners } from "cilantro-sdk/wallet";
432
+ async function loadSigners(walletId) {
433
+ if (!walletId) return [];
434
+ try {
435
+ let signersResult = await getSigners(walletId);
436
+ let onChainSigners = extractOnChainSigners(signersResult);
437
+ let authSigners = extractAuthenticationSigners(signersResult);
438
+ if ((!onChainSigners || !Array.isArray(onChainSigners) || onChainSigners.length === 0) && (!authSigners || !Array.isArray(authSigners) || authSigners.length === 0)) {
439
+ const response = await listSigners(walletId);
440
+ onChainSigners = extractOnChainSigners(response);
441
+ authSigners = extractAuthenticationSigners(response);
442
+ }
443
+ const processedOnChain = onChainSigners.filter((s) => s && typeof s === "object").map((signer) => processSigner(signer, "onchain"));
444
+ const processedAuth = authSigners.filter((s) => s && typeof s === "object").map((signer) => processSigner(signer, "authenticationsigner"));
445
+ return [...processedOnChain, ...processedAuth].filter((s) => s.id && (s.type || s.signerType));
446
+ } catch (error) {
447
+ console.error("Failed to load signers:", error);
448
+ return [];
449
+ }
450
+ }
451
+ function processSigner(signer, category) {
452
+ const parsed = parseSignerResponse(signer);
453
+ const signerId = signer.id ?? signer.signerId ?? parsed.signerId;
454
+ const signerType = signer.signerType ?? signer.type ?? parsed.type;
455
+ const signerPubkey = signer.signerPubkey ?? signer.publicKey ?? parsed.publicKey ?? "";
456
+ const authId = signer.authId ?? parsed.email ?? parsed.phone;
457
+ const walletId = signer.walletId ?? parsed.walletId;
458
+ let email = signer.email ?? parsed.email;
459
+ let phone = signer.phone ?? parsed.phone;
460
+ if (!email && !phone && authId) {
461
+ if (signerType === "email") email = authId;
462
+ else if (signerType === "phone") phone = authId;
463
+ }
464
+ const signerConfig = signer.signerConfig;
465
+ if (signerConfig) {
466
+ if (!email && signerConfig.email) email = signerConfig.email;
467
+ if (!phone && signerConfig.phone) phone = signerConfig.phone;
468
+ }
469
+ const isActive = signer.isActive !== void 0 ? signer.isActive : parsed.isActive !== void 0 ? parsed.isActive : true;
470
+ return {
471
+ ...signer,
472
+ id: signerId,
473
+ signerId,
474
+ walletId: walletId ?? "",
475
+ type: signerType,
476
+ signerType,
477
+ publicKey: signerPubkey,
478
+ signerPubkey,
479
+ email,
480
+ phone,
481
+ isActive,
482
+ credentialId: signer.credentialId ?? (signerType === "passkey" ? authId : void 0),
483
+ authId,
484
+ deviceIdentities: signer.deviceIdentities,
485
+ signerConfig: signer.signerConfig,
486
+ permissions: signer.permissions,
487
+ signerCategory: category
488
+ };
489
+ }
490
+ function getSignerType(signer) {
491
+ return signer.type || signer.signerType || "";
492
+ }
493
+ function getSignerTypeLabel(type) {
494
+ if (!type) return "Unknown";
495
+ const t = type.toLowerCase();
496
+ if (t === "email") return "Email";
497
+ if (t === "phone") return "Phone";
498
+ if (t === "external" || t === "external-wallet") return "External Wallet";
499
+ if (t === "passkey") return "Passkey";
500
+ if (t === "api-key" || t === "apikey") return "API Key";
501
+ return type;
502
+ }
503
+ function getSignerDisplayName(signer) {
504
+ const signerType = getSignerType(signer);
505
+ const typeLabel = getSignerTypeLabel(signerType);
506
+ const shortId = signer.id.length > 8 ? `${signer.id.slice(0, 4)}...${signer.id.slice(-4)}` : signer.id;
507
+ if (signer.email) return `${typeLabel}: ${signer.email}`;
508
+ if (signer.phone) return `${typeLabel}: ${signer.phone}`;
509
+ if (signerType === "passkey") {
510
+ const credId = signer.credentialId ?? signer.authId ?? signer.signerConfig?.credentialId;
511
+ if (credId) {
512
+ const shortCredId = credId.length > 12 ? `${credId.slice(0, 6)}...${credId.slice(-6)}` : credId;
513
+ return `${typeLabel} (${shortCredId})`;
514
+ }
515
+ return `${typeLabel} (${shortId})`;
516
+ }
517
+ return `${typeLabel} (${shortId})`;
518
+ }
519
+ function getSignerUniqueId(signer) {
520
+ if (signer.id) return signer.id.length > 12 ? `${signer.id.slice(0, 6)}...${signer.id.slice(-6)}` : signer.id;
521
+ if (signer.publicKey) return `${signer.publicKey.slice(0, 6)}...${signer.publicKey.slice(-6)}`;
522
+ return "Unknown";
523
+ }
524
+ function extractSignerInfo(signer) {
525
+ const signerType = signer.type || signer.signerType;
526
+ const signerId = signer.id || signer.signerId;
527
+ if (!signerType) throw new Error(`Signer type is missing. Signer data: ${JSON.stringify(signer)}`);
528
+ if (!signerId) throw new Error(`Signer ID is missing. Signer data: ${JSON.stringify(signer)}`);
529
+ return { signerId, signerType };
530
+ }
531
+
532
+ // src/hooks/useSigners.ts
533
+ function useSigners(options = {}) {
534
+ const { walletId: walletIdOption } = options;
535
+ const { token } = useCilantroAuth();
536
+ const [signers, setSigners] = useState3([]);
537
+ const [isLoading, setIsLoading] = useState3(false);
538
+ const [error, setError] = useState3(null);
539
+ const load = useCallback(async (walletId) => {
540
+ if (!walletId) {
541
+ setSigners([]);
542
+ return;
543
+ }
544
+ setIsLoading(true);
545
+ setError(null);
546
+ try {
547
+ if (token) setSdkAuth(token);
548
+ const list = await loadSigners(walletId);
549
+ setSigners(list);
550
+ } catch (err) {
551
+ const message = err instanceof Error ? err.message : String(err);
552
+ setError(message);
553
+ setSigners([]);
554
+ } finally {
555
+ setIsLoading(false);
556
+ }
557
+ }, [token]);
558
+ useEffect4(() => {
559
+ const id = walletIdOption ?? void 0;
560
+ if (id) load(id);
561
+ else {
562
+ setSigners([]);
563
+ setError(null);
564
+ }
565
+ }, [walletIdOption, load]);
566
+ const refresh = useCallback(async () => {
567
+ const id = walletIdOption ?? void 0;
568
+ if (id) await load(id);
569
+ }, [walletIdOption, load]);
570
+ return { signers, isLoading, error, refresh };
571
+ }
572
+
573
+ // src/hooks/useSignerSelection.ts
574
+ import { useState as useState4, useEffect as useEffect5, useCallback as useCallback2 } from "react";
575
+ function useSignerSelection(options = {}) {
576
+ const { walletId: walletIdOverride, signingMethod = "sdk-signer" } = options;
577
+ const { selectedWallet } = useWallets();
578
+ const effectiveWalletId = walletIdOverride ?? selectedWallet?.id ?? selectedWallet?.walletId ?? "";
579
+ const { signers: availableSigners, isLoading: isLoadingSigners } = useSigners({
580
+ walletId: effectiveWalletId || null
581
+ });
582
+ const [selectedWalletId, setSelectedWalletId] = useState4(effectiveWalletId);
583
+ const [selectedSigner, setSelectedSigner] = useState4(null);
584
+ useEffect5(() => {
585
+ setSelectedWalletId(effectiveWalletId);
586
+ }, [effectiveWalletId]);
587
+ useEffect5(() => {
588
+ if (signingMethod !== "sdk-signer") {
589
+ setSelectedSigner(null);
590
+ }
591
+ }, [signingMethod]);
592
+ const reset = useCallback2(() => {
593
+ setSelectedWalletId("");
594
+ setSelectedSigner(null);
595
+ }, []);
596
+ return {
597
+ selectedWalletId: selectedWalletId || effectiveWalletId,
598
+ setSelectedWalletId,
599
+ availableSigners,
600
+ selectedSigner,
601
+ setSelectedSigner,
602
+ isLoadingSigners,
603
+ reset
604
+ };
605
+ }
606
+
607
+ // src/hooks/useMessageSigning.ts
608
+ import { useState as useState5 } from "react";
609
+
610
+ // src/core/signer-signing/core.ts
611
+ import { PublicKey } from "@solana/web3.js";
612
+ import {
613
+ deriveSignerKeypair,
614
+ getEmailSignerKeypair,
615
+ getPhoneSignerKeypair
616
+ } from "cilantro-sdk/helpers";
617
+
618
+ // src/core/signer-signing/constants.ts
619
+ var CACHE_CONFIG = { enabled: true, ttl: 3e5 };
620
+ var SIGNER_TYPES = {
621
+ EMAIL: "email",
622
+ PHONE: "phone",
623
+ PASSKEY: "passkey",
624
+ EXTERNAL: "external",
625
+ API_KEY: "apiKey"
626
+ };
627
+ function isValidSignerType(type) {
628
+ return Object.values(SIGNER_TYPES).includes(type);
629
+ }
630
+
631
+ // src/core/signer-signing/storage.ts
632
+ function getSignerStorage() {
633
+ return getStorageAdapter();
634
+ }
635
+ function getStorageOptions() {
636
+ return {
637
+ deviceKeyManager: getSignerStorage(),
638
+ cache: CACHE_CONFIG
639
+ };
640
+ }
641
+
642
+ // src/core/signer-signing/core.ts
643
+ async function getSignerPublicKey(walletId, signer, signerType, signerId) {
644
+ const existingPubkey = signer.signerPubkey || signer.publicKey;
645
+ if (existingPubkey && typeof existingPubkey === "string" && existingPubkey.trim()) {
646
+ return new PublicKey(existingPubkey.trim());
647
+ }
648
+ const storageOptions = getStorageOptions();
649
+ if (signerType === SIGNER_TYPES.EMAIL) {
650
+ const keypair = await getEmailSignerKeypair(walletId, signerId, storageOptions);
651
+ return new PublicKey(keypair.publicKey);
652
+ }
653
+ if (signerType === SIGNER_TYPES.PHONE) {
654
+ const keypair = await getPhoneSignerKeypair(walletId, signerId, storageOptions);
655
+ return new PublicKey(keypair.publicKey);
656
+ }
657
+ if (signerType === SIGNER_TYPES.EXTERNAL || signerType === SIGNER_TYPES.API_KEY) {
658
+ const keypair = await deriveSignerKeypair(walletId, signerId, signerType, storageOptions);
659
+ return new PublicKey(keypair.publicKey);
660
+ }
661
+ throw new Error(`Unsupported signer type: ${signerType}`);
662
+ }
663
+
664
+ // src/core/signer-signing/message-signing.ts
665
+ import {
666
+ deriveSignerKeypair as deriveSignerKeypair2,
667
+ signWithSigner,
668
+ signWithEmailSigner,
669
+ signWithPhoneSigner,
670
+ getEmailSignerKeypair as getEmailSignerKeypair2,
671
+ getPhoneSignerKeypair as getPhoneSignerKeypair2
672
+ } from "cilantro-sdk/helpers";
673
+
674
+ // src/core/signer-creation.ts
675
+ import { PublicKey as PublicKey2 } from "@solana/web3.js";
676
+ import {
677
+ createEmailSignerHelper as createEmailSignerSDK,
678
+ createPhoneSignerHelper as createPhoneSignerSDK,
679
+ isValidEmail,
680
+ isValidPhone,
681
+ authenticateWithPasskey,
682
+ findExistingPasskeySigner,
683
+ formatAuthenticationResponse,
684
+ isWebAuthnSupported,
685
+ registerPasskeyComplete,
686
+ signWithPasskeySigner
687
+ } from "cilantro-sdk/helpers";
688
+ import { sendRawPasskeyTransaction } from "cilantro-sdk/transactions";
689
+ import { createExternalWalletSigner, startPasskeyAuthentication } from "cilantro-sdk/wallet";
690
+ async function createEmailSignerHelper(walletId, email) {
691
+ const trimmedEmail = email.trim();
692
+ if (!trimmedEmail) throw new Error("Email address is required");
693
+ if (!isValidEmail(trimmedEmail)) throw new Error("Invalid email address format");
694
+ const deviceKeyManager = getStorageAdapter();
695
+ return await createEmailSignerSDK(walletId, { email: trimmedEmail, deviceKeyManager });
696
+ }
697
+ async function createPhoneSignerHelper(walletId, phone) {
698
+ const trimmedPhone = phone.trim();
699
+ if (!trimmedPhone) throw new Error("Phone number is required");
700
+ if (!isValidPhone(trimmedPhone)) throw new Error("Invalid phone number format");
701
+ const deviceKeyManager = getStorageAdapter();
702
+ return await createPhoneSignerSDK(walletId, { phone: trimmedPhone, deviceKeyManager });
703
+ }
704
+ async function createExternalSignerHelper(walletId, address) {
705
+ if (!address.trim()) throw new Error("Wallet address is required");
706
+ return await createExternalWalletSigner(walletId, { address: address.trim(), chain: "solana" });
707
+ }
708
+ async function registerPasskeySigner(walletId) {
709
+ if (!isWebAuthnSupported()) throw new Error("WebAuthn is not supported in this browser");
710
+ return await registerPasskeyComplete(walletId);
711
+ }
712
+ async function signWithPasskey(walletId, signerId, message, options) {
713
+ if (!isWebAuthnSupported()) throw new Error("WebAuthn is not supported in this browser");
714
+ const messageBytes = new TextEncoder().encode(message);
715
+ const signature = await signWithPasskeySigner(walletId, signerId, messageBytes, options);
716
+ return {
717
+ signature: Buffer.from(signature).toString("hex"),
718
+ signer: signerId
719
+ };
720
+ }
721
+ async function signAndSendPasskeyTransaction(walletId, signerId, transaction, options) {
722
+ if (!isWebAuthnSupported()) throw new Error("WebAuthn is not supported in this browser");
723
+ let credentialId = options?.credentialId;
724
+ if (!credentialId) {
725
+ const signers = await loadSigners(walletId);
726
+ const passkeySigner = signers.find((s) => s.id === signerId || s.signerId === signerId);
727
+ if (!passkeySigner) {
728
+ throw new Error(
729
+ `Passkey signer ${signerId} not found in wallet. Available signers: ${signers.map((s) => `${s.id} (${s.type})`).join(", ")}`
730
+ );
731
+ }
732
+ credentialId = passkeySigner.credentialId ?? passkeySigner.signerConfig?.credentialId ?? passkeySigner.authId;
733
+ if (!credentialId) {
734
+ throw new Error(`Credential ID not found for passkey signer ${signerId}.`);
735
+ }
736
+ }
737
+ let mintAddress = options?.mintAddress;
738
+ if (!mintAddress && transaction.instructions.length > 0) {
739
+ const systemProgramId = new PublicKey2("11111111111111111111111111111111");
740
+ const feePayer = transaction.feePayer || systemProgramId;
741
+ transaction.instructions.forEach((ix) => {
742
+ ix.keys.forEach((key) => {
743
+ if (key.isWritable && key.isSigner && !key.pubkey.equals(feePayer) && !mintAddress) {
744
+ mintAddress = key.pubkey.toString();
745
+ }
746
+ });
747
+ });
748
+ }
749
+ const unsignedTransaction = transaction.serialize({ verifySignatures: false }).toString("base64");
750
+ const authOptions = await startPasskeyAuthentication(walletId, {
751
+ credentialId: options?.credentialId
752
+ });
753
+ const authData = extractResponseData(authOptions);
754
+ if (!authData) throw new Error("Failed to get authentication options");
755
+ const authDataValue = authData && typeof authData === "object" && "data" in authData ? authData.data : authData;
756
+ const credential = await authenticateWithPasskey(
757
+ authDataValue,
758
+ { useBrowserAutofill: options?.useBrowserAutofill ?? false }
759
+ );
760
+ const formattedCredential = formatAuthenticationResponse(credential);
761
+ const dto = {
762
+ walletId,
763
+ credentialId,
764
+ unsignedTransaction,
765
+ signature: formattedCredential.response.signature,
766
+ authenticatorData: formattedCredential.response.authenticatorData,
767
+ clientDataJSON: formattedCredential.response.clientDataJSON
768
+ };
769
+ const result = await sendRawPasskeyTransaction(dto);
770
+ const resultData = extractResponseData(result);
771
+ return { signature: resultData?.signature ?? "", status: resultData?.status };
772
+ }
773
+
774
+ // src/core/signer-signing/errors.ts
775
+ import {
776
+ DeviceKeyNotFoundError,
777
+ DeviceKeyMismatchError,
778
+ SignerInactiveError,
779
+ SignerNotFoundError
780
+ } from "cilantro-sdk/helpers";
781
+ function handleDeviceKeyError(error, signerType) {
782
+ if (error instanceof DeviceKeyNotFoundError) {
783
+ throw new Error(
784
+ `Device key not found. Please create the ${signerType} signer first using the Signers page. The device key is generated when you create the signer.`
785
+ );
786
+ }
787
+ if (error instanceof DeviceKeyMismatchError) {
788
+ throw new Error(
789
+ "Device key mismatch. The stored device key doesn't match the server. You may need to create a new signer or update the device identity."
790
+ );
791
+ }
792
+ if (error instanceof SignerNotFoundError) {
793
+ throw new Error(`Signer not found. Please ensure the ${signerType} signer exists.`);
794
+ }
795
+ if (error instanceof SignerInactiveError) {
796
+ throw new Error(`${signerType} signer is not active. Please activate the signer first.`);
797
+ }
798
+ if (error instanceof Error) {
799
+ if (error.message.includes("Device key not found") || error.name === "DeviceKeyNotFoundError") {
800
+ throw new Error(
801
+ `Device key not found. Please create the ${signerType} signer first using the Signers page. The device key is generated when you create the signer.`
802
+ );
803
+ }
804
+ if (error.message.includes("Device key mismatch") || error.name === "DeviceKeyMismatchError") {
805
+ throw new Error(
806
+ "Device key mismatch. The stored device key doesn't match the server. You may need to create a new signer or update the device identity."
807
+ );
808
+ }
809
+ }
810
+ throw error;
811
+ }
812
+
813
+ // src/core/signer-signing/signer-types.ts
814
+ function extractSignerInfo2(signer) {
815
+ const signerType = signer.type || signer.signerType;
816
+ const signerId = signer.id || signer.signerId;
817
+ if (!signerType || !signerId) {
818
+ throw new Error(`Signer type or ID is missing. Signer data: ${JSON.stringify(signer)}`);
819
+ }
820
+ if (!isValidSignerType(signerType)) {
821
+ throw new Error(`Unsupported signer type: ${signerType}`);
822
+ }
823
+ return { signerType, signerId };
824
+ }
825
+ function requiresActiveStatus(signerType) {
826
+ return signerType === SIGNER_TYPES.EMAIL || signerType === SIGNER_TYPES.PHONE || signerType === SIGNER_TYPES.EXTERNAL || signerType === SIGNER_TYPES.API_KEY;
827
+ }
828
+ function validateSignerActive(signer, signerType) {
829
+ if (requiresActiveStatus(signerType) && !signer.isActive) {
830
+ throw new Error(`${signerType} signer is not active. Please activate the signer first.`);
831
+ }
832
+ }
833
+
834
+ // src/core/signer-signing/message-signing.ts
835
+ async function signMessageWithSigner(walletId, signer, messageText) {
836
+ const { signerType, signerId } = extractSignerInfo2(signer);
837
+ const message = new TextEncoder().encode(messageText);
838
+ if (signerType === SIGNER_TYPES.EMAIL) {
839
+ validateSignerActive(signer, signerType);
840
+ const storageOptions = getStorageOptions();
841
+ try {
842
+ const signature = await signWithEmailSigner(walletId, signerId, message, storageOptions);
843
+ const keypair = await getEmailSignerKeypair2(walletId, signerId, storageOptions);
844
+ return {
845
+ signature: Buffer.from(signature).toString("hex"),
846
+ publicKey: Buffer.from(keypair.publicKey).toString("hex"),
847
+ signerType: SIGNER_TYPES.EMAIL
848
+ };
849
+ } catch (error) {
850
+ throw handleDeviceKeyError(error, SIGNER_TYPES.EMAIL);
851
+ }
852
+ }
853
+ if (signerType === SIGNER_TYPES.PHONE) {
854
+ validateSignerActive(signer, signerType);
855
+ const storageOptions = getStorageOptions();
856
+ try {
857
+ const signature = await signWithPhoneSigner(walletId, signerId, message, storageOptions);
858
+ const keypair = await getPhoneSignerKeypair2(walletId, signerId, storageOptions);
859
+ return {
860
+ signature: Buffer.from(signature).toString("hex"),
861
+ publicKey: Buffer.from(keypair.publicKey).toString("hex"),
862
+ signerType: SIGNER_TYPES.PHONE
863
+ };
864
+ } catch (error) {
865
+ throw handleDeviceKeyError(error, SIGNER_TYPES.PHONE);
866
+ }
867
+ }
868
+ if (signerType === SIGNER_TYPES.PASSKEY) {
869
+ const signResult = await signWithPasskey(walletId, signerId, messageText, { useBrowserAutofill: false });
870
+ return {
871
+ signature: signResult.signature,
872
+ signerType: SIGNER_TYPES.PASSKEY,
873
+ signer: signResult.signer
874
+ };
875
+ }
876
+ if (signerType === SIGNER_TYPES.EXTERNAL || signerType === SIGNER_TYPES.API_KEY) {
877
+ validateSignerActive(signer, signerType);
878
+ const storageOptions = getStorageOptions();
879
+ const signature = await signWithSigner(walletId, signerId, signerType, message, storageOptions);
880
+ const keypair = await deriveSignerKeypair2(walletId, signerId, signerType, storageOptions);
881
+ return {
882
+ signature: Buffer.from(signature).toString("hex"),
883
+ publicKey: Buffer.from(keypair.publicKey).toString("base64"),
884
+ signerType
885
+ };
886
+ }
887
+ throw new Error(`Unsupported signer type: ${signerType}`);
888
+ }
889
+
890
+ // src/core/signer-signing/transaction-signing.ts
891
+ import {
892
+ signWithSigner as signWithSigner2,
893
+ signWithEmailSigner as signWithEmailSigner2,
894
+ signWithPhoneSigner as signWithPhoneSigner2,
895
+ signTransactionWithEmailSigner,
896
+ signTransactionWithPhoneSigner
897
+ } from "cilantro-sdk/helpers";
898
+ import { submitTransaction } from "cilantro-sdk/wallet";
899
+
900
+ // src/core/signer-signing/validation.ts
901
+ import { PublicKey as PublicKey3, Transaction } from "@solana/web3.js";
902
+ async function validateSignerInTransaction(signedTransactionBase64, expectedSignerPublicKey) {
903
+ const errors = [];
904
+ const warnings = [];
905
+ try {
906
+ const transactionBuffer = Buffer.from(signedTransactionBase64, "base64");
907
+ const transaction = Transaction.from(transactionBuffer);
908
+ let allSignaturesValid = true;
909
+ try {
910
+ transaction.verifySignatures();
911
+ } catch (error) {
912
+ allSignaturesValid = false;
913
+ errors.push(`Signature verification failed: ${extractErrorMessage(error)}`);
914
+ }
915
+ const signers = transaction.signatures.map((sig) => {
916
+ const publicKeyStr = sig.publicKey.toString();
917
+ const hasSignature = sig.signature !== null && sig.signature.length > 0;
918
+ const signatureLength = sig.signature !== null ? sig.signature.length : 0;
919
+ let matchesExpected = false;
920
+ if (expectedSignerPublicKey) {
921
+ const expectedPubkey = typeof expectedSignerPublicKey === "string" ? new PublicKey3(expectedSignerPublicKey) : expectedSignerPublicKey;
922
+ matchesExpected = sig.publicKey.equals(expectedPubkey);
923
+ }
924
+ if (!hasSignature) warnings.push(`Signer ${publicKeyStr} has no signature (unsigned)`);
925
+ return { publicKey: publicKeyStr, hasSignature, signatureLength, matchesExpected };
926
+ });
927
+ let expectedSignerFound = false;
928
+ if (expectedSignerPublicKey) {
929
+ const expectedPubkey = typeof expectedSignerPublicKey === "string" ? new PublicKey3(expectedSignerPublicKey) : expectedSignerPublicKey;
930
+ expectedSignerFound = signers.some((s) => s.matchesExpected);
931
+ if (!expectedSignerFound) {
932
+ errors.push(`Expected signer ${expectedPubkey.toString()} not found in transaction signers`);
933
+ }
934
+ }
935
+ if (expectedSignerFound && expectedSignerPublicKey) {
936
+ const expectedSigner = signers.find((s) => s.matchesExpected);
937
+ if (expectedSigner && !expectedSigner.hasSignature) {
938
+ errors.push(
939
+ `Expected signer ${typeof expectedSignerPublicKey === "string" ? expectedSignerPublicKey : expectedSignerPublicKey.toString()} is present but has no signature`
940
+ );
941
+ }
942
+ }
943
+ const isValid = allSignaturesValid && (expectedSignerPublicKey ? expectedSignerFound : true) && errors.length === 0;
944
+ return {
945
+ isValid,
946
+ transaction,
947
+ signers,
948
+ expectedSignerFound,
949
+ allSignaturesValid,
950
+ feePayer: transaction.feePayer?.toString(),
951
+ recentBlockhash: transaction.recentBlockhash ?? void 0,
952
+ errors,
953
+ warnings
954
+ };
955
+ } catch (error) {
956
+ errors.push(`Failed to deserialize transaction: ${extractErrorMessage(error)}`);
957
+ throw new Error(
958
+ `Transaction validation failed: ${errors.join("; ")}
959
+ Original error: ${extractErrorMessage(error)}`
960
+ );
961
+ }
962
+ }
963
+
964
+ // src/core/signer-signing/transaction-signing.ts
965
+ function prepareTransactionForSigning(transaction, signerPublicKey) {
966
+ const signerPubkeyStr = signerPublicKey.toString();
967
+ const hasSignerInSignatures = transaction.signatures.some(
968
+ (sig) => sig.publicKey.toString() === signerPubkeyStr
969
+ );
970
+ if (!hasSignerInSignatures) {
971
+ transaction.signatures.push({
972
+ publicKey: signerPublicKey,
973
+ signature: null
974
+ });
975
+ }
976
+ if (transaction.feePayer) {
977
+ const feePayerStr = transaction.feePayer.toString();
978
+ const hasFeePayerInSignatures = transaction.signatures.some(
979
+ (sig) => sig.publicKey.toString() === feePayerStr
980
+ );
981
+ if (!hasFeePayerInSignatures) {
982
+ transaction.signatures.push({ publicKey: transaction.feePayer, signature: null });
983
+ }
984
+ }
985
+ }
986
+ async function signTransactionWithEmailOrPhone(walletId, signerId, signerType, unsignedTransactionBase64) {
987
+ const storageOptions = getStorageOptions();
988
+ if (signerType === SIGNER_TYPES.EMAIL) {
989
+ return await signTransactionWithEmailSigner(
990
+ walletId,
991
+ signerId,
992
+ unsignedTransactionBase64,
993
+ storageOptions
994
+ );
995
+ }
996
+ return await signTransactionWithPhoneSigner(
997
+ walletId,
998
+ signerId,
999
+ unsignedTransactionBase64,
1000
+ storageOptions
1001
+ );
1002
+ }
1003
+ async function submitSignedTransaction(walletId, signedTransactionBase64) {
1004
+ const submitResult = await submitTransaction(walletId, {
1005
+ signedTransaction: signedTransactionBase64
1006
+ });
1007
+ const resultData = extractResponseData(submitResult);
1008
+ if (!resultData?.signature) throw new Error("Server did not return a transaction signature");
1009
+ return {
1010
+ signature: resultData.signature,
1011
+ confirmationStatus: resultData.status === "confirmed" ? "confirmed" : "pending"
1012
+ };
1013
+ }
1014
+ async function handlePasskeyTransaction(walletId, signerId, transaction, connection) {
1015
+ if (!connection) {
1016
+ throw new Error(
1017
+ "Connection is required for passkey sign-and-send. Pass the connection from your Solana config to useTransactionSigning / TransactionSigningForm."
1018
+ );
1019
+ }
1020
+ const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash("confirmed");
1021
+ const result = await signAndSendPasskeyTransaction(walletId, signerId, transaction, {
1022
+ useBrowserAutofill: false
1023
+ });
1024
+ let confirmationStatus = "confirmed";
1025
+ try {
1026
+ await connection.confirmTransaction({
1027
+ signature: result.signature,
1028
+ blockhash,
1029
+ lastValidBlockHeight
1030
+ });
1031
+ } catch (error) {
1032
+ const errorMsg = extractErrorMessage(error);
1033
+ if (errorMsg.includes("block height exceeded") || errorMsg.includes("expired") || errorMsg.includes("timeout")) {
1034
+ confirmationStatus = "pending";
1035
+ } else {
1036
+ throw new Error(`Transaction confirmation failed: ${errorMsg}. Signature: ${result.signature}`);
1037
+ }
1038
+ }
1039
+ return { signature: result.signature, confirmationStatus };
1040
+ }
1041
+ async function handleEmailOrPhoneTransaction(walletId, signer, signerType, signerId, transaction) {
1042
+ validateSignerActive(signer, signerType);
1043
+ const signerPublicKey = await getSignerPublicKey(walletId, signer, signerType, signerId);
1044
+ prepareTransactionForSigning(transaction, signerPublicKey);
1045
+ const unsignedTransactionBase64 = Buffer.from(
1046
+ transaction.serialize({ verifySignatures: false })
1047
+ ).toString("base64");
1048
+ let signedTransactionBase64;
1049
+ try {
1050
+ signedTransactionBase64 = await signTransactionWithEmailOrPhone(
1051
+ walletId,
1052
+ signerId,
1053
+ signerType,
1054
+ unsignedTransactionBase64
1055
+ );
1056
+ } catch (error) {
1057
+ handleDeviceKeyError(error, signerType);
1058
+ throw error;
1059
+ }
1060
+ try {
1061
+ const validationResult = await validateSignerInTransaction(
1062
+ signedTransactionBase64,
1063
+ signerPublicKey
1064
+ );
1065
+ if (!validationResult.isValid) {
1066
+ console.error("Transaction validation failed:", {
1067
+ errors: validationResult.errors,
1068
+ warnings: validationResult.warnings
1069
+ });
1070
+ }
1071
+ } catch (validationError) {
1072
+ console.error("Validation error (non-fatal):", extractErrorMessage(validationError));
1073
+ }
1074
+ return await submitSignedTransaction(walletId, signedTransactionBase64);
1075
+ }
1076
+ async function handleExternalOrApiKeyTransaction(walletId, signer, signerType, signerId, transaction) {
1077
+ validateSignerActive(signer, signerType);
1078
+ const messageBytes = transaction.serializeMessage();
1079
+ const storageOptions = getStorageOptions();
1080
+ const signatureBytes = await signWithSigner2(
1081
+ walletId,
1082
+ signerId,
1083
+ signerType,
1084
+ messageBytes,
1085
+ storageOptions
1086
+ );
1087
+ const signerPublicKey = await getSignerPublicKey(walletId, signer, signerType, signerId);
1088
+ const signatureBuffer = Buffer.from(signatureBytes);
1089
+ transaction.addSignature(signerPublicKey, signatureBuffer);
1090
+ const signedTransactionBytes = transaction.serialize();
1091
+ const signedTransactionBase64 = Buffer.from(signedTransactionBytes).toString("base64");
1092
+ return await submitSignedTransaction(walletId, signedTransactionBase64);
1093
+ }
1094
+ async function signTransactionWithSigner(walletId, signer, transactionBuffer) {
1095
+ const { signerType, signerId } = extractSignerInfo2(signer);
1096
+ const storageOptions = getStorageOptions();
1097
+ if (signerType === SIGNER_TYPES.EMAIL) {
1098
+ validateSignerActive(signer, signerType);
1099
+ try {
1100
+ const signature = await signWithEmailSigner2(walletId, signerId, transactionBuffer, storageOptions);
1101
+ return { signature: Buffer.from(signature).toString("hex"), signerType: SIGNER_TYPES.EMAIL };
1102
+ } catch (error) {
1103
+ throw handleDeviceKeyError(error, SIGNER_TYPES.EMAIL);
1104
+ }
1105
+ }
1106
+ if (signerType === SIGNER_TYPES.PHONE) {
1107
+ validateSignerActive(signer, signerType);
1108
+ try {
1109
+ const signature = await signWithPhoneSigner2(walletId, signerId, transactionBuffer, storageOptions);
1110
+ return { signature: Buffer.from(signature).toString("hex"), signerType: SIGNER_TYPES.PHONE };
1111
+ } catch (error) {
1112
+ throw handleDeviceKeyError(error, SIGNER_TYPES.PHONE);
1113
+ }
1114
+ }
1115
+ if (signerType === SIGNER_TYPES.PASSKEY) {
1116
+ const { signWithPasskeySigner: signWithPasskeySigner2 } = await import("cilantro-sdk/helpers");
1117
+ const signature = await signWithPasskeySigner2(walletId, signerId, transactionBuffer, {
1118
+ useBrowserAutofill: false
1119
+ });
1120
+ return { signature: Buffer.from(signature).toString("hex"), signerType: SIGNER_TYPES.PASSKEY };
1121
+ }
1122
+ if (signerType === SIGNER_TYPES.EXTERNAL || signerType === SIGNER_TYPES.API_KEY) {
1123
+ validateSignerActive(signer, signerType);
1124
+ const signature = await signWithSigner2(
1125
+ walletId,
1126
+ signerId,
1127
+ signerType,
1128
+ transactionBuffer,
1129
+ storageOptions
1130
+ );
1131
+ return { signature: Buffer.from(signature).toString("hex"), signerType };
1132
+ }
1133
+ throw new Error(`Unsupported signer type: ${signerType}`);
1134
+ }
1135
+ async function signAndSendTransactionWithSigner(walletId, signer, transaction, connection) {
1136
+ const { signerType, signerId } = extractSignerInfo2(signer);
1137
+ if (signerType === SIGNER_TYPES.PASSKEY) {
1138
+ return await handlePasskeyTransaction(walletId, signerId, transaction, connection);
1139
+ }
1140
+ if (signerType === SIGNER_TYPES.EMAIL || signerType === SIGNER_TYPES.PHONE) {
1141
+ return await handleEmailOrPhoneTransaction(walletId, signer, signerType, signerId, transaction);
1142
+ }
1143
+ if (signerType === SIGNER_TYPES.EXTERNAL || signerType === SIGNER_TYPES.API_KEY) {
1144
+ return await handleExternalOrApiKeyTransaction(walletId, signer, signerType, signerId, transaction);
1145
+ }
1146
+ throw new Error(`Unsupported signer type: ${signerType}`);
1147
+ }
1148
+
1149
+ // src/core/signer-signing/wallet-data.ts
1150
+ import { PublicKey as PublicKey4 } from "@solana/web3.js";
1151
+ import { findOne as findOneWallet } from "cilantro-sdk/wallet";
1152
+ async function getWalletData(walletId) {
1153
+ const walletDataResponse = await findOneWallet(walletId);
1154
+ const walletData = extractResponseData(walletDataResponse);
1155
+ if (!walletData) throw new Error("Wallet data is empty");
1156
+ const address = String(
1157
+ walletData.address ?? walletData.walletAddress ?? walletData.solanaAddress ?? walletData.publicKey ?? walletData.pubkey ?? ""
1158
+ ).trim();
1159
+ if (!address) throw new Error(`No wallet address found. Available fields: ${Object.keys(walletData).join(", ")}`);
1160
+ const walletPublicKey = new PublicKey4(address);
1161
+ const adminData = walletData.admin;
1162
+ const adminPubkey = String(
1163
+ walletData.adminSignerPubkey ?? walletData.adminSigner ?? adminData?.publicKey ?? ""
1164
+ ).trim();
1165
+ if (!adminPubkey) {
1166
+ throw new Error(
1167
+ `adminSignerPubkey not found in wallet data. Available fields: ${Object.keys(walletData).join(", ")}`
1168
+ );
1169
+ }
1170
+ const adminSignerPubkey = new PublicKey4(adminPubkey);
1171
+ return { walletPublicKey, adminSignerPubkey };
1172
+ }
1173
+
1174
+ // src/hooks/useMessageSigning.ts
1175
+ function useMessageSigning(options) {
1176
+ const {
1177
+ token,
1178
+ signingMethod,
1179
+ selectedSigner,
1180
+ selectedWalletId,
1181
+ walletAdapterSignMessage,
1182
+ walletAdapterPublicKey
1183
+ } = options;
1184
+ const [messageText, setMessageText] = useState5("Hello, Solana!");
1185
+ const [signResultState, setSignResultState] = useState5({ status: "idle" });
1186
+ const [isSigning, setIsSigning] = useState5(false);
1187
+ const handleSign = async () => {
1188
+ setIsSigning(true);
1189
+ setSignResultState({ status: "loading" });
1190
+ try {
1191
+ if (token) setSdkAuth(token);
1192
+ if (!messageText.trim()) throw new Error("Please enter a message to sign.");
1193
+ if (signingMethod === "wallet-adapter") {
1194
+ if (!walletAdapterSignMessage) {
1195
+ throw new Error("Wallet adapter signMessage not provided.");
1196
+ }
1197
+ const message = new TextEncoder().encode(messageText);
1198
+ const signature = await walletAdapterSignMessage(message);
1199
+ setSignResultState({
1200
+ status: "success",
1201
+ message: "Message signed successfully!",
1202
+ detail: {
1203
+ message: messageText,
1204
+ signature: Array.from(signature).map((b) => b.toString(16).padStart(2, "0")).join(""),
1205
+ publicKey: walletAdapterPublicKey ?? void 0
1206
+ }
1207
+ });
1208
+ return;
1209
+ }
1210
+ if (!selectedSigner || !selectedWalletId) throw new Error("Please select a signer.");
1211
+ const result = await signMessageWithSigner(selectedWalletId, selectedSigner, messageText);
1212
+ const { signerType } = extractSignerInfo(selectedSigner);
1213
+ setSignResultState({
1214
+ status: "success",
1215
+ message: `Message signed successfully with ${signerType} signer!`,
1216
+ detail: { message: messageText, ...result }
1217
+ });
1218
+ } catch (error) {
1219
+ const errorMsg = extractErrorMessage(error);
1220
+ const isCancelled = errorMsg.toLowerCase().includes("cancel") || errorMsg.toLowerCase().includes("notallowederror");
1221
+ setSignResultState({
1222
+ status: "error",
1223
+ message: isCancelled ? "User cancelled authentication" : errorMsg
1224
+ });
1225
+ } finally {
1226
+ setIsSigning(false);
1227
+ }
1228
+ };
1229
+ const reset = () => {
1230
+ setMessageText("Hello, Solana!");
1231
+ setSignResultState({ status: "idle" });
1232
+ };
1233
+ return {
1234
+ messageText,
1235
+ setMessageText,
1236
+ signResultState,
1237
+ isSigning,
1238
+ handleSign,
1239
+ reset
1240
+ };
1241
+ }
1242
+
1243
+ // src/hooks/useTransactionSigning.ts
1244
+ import { useState as useState6 } from "react";
1245
+ function useTransactionSigning(options) {
1246
+ const {
1247
+ token,
1248
+ signingMethod,
1249
+ selectedSigner,
1250
+ selectedWalletId,
1251
+ walletAdapterSignTransaction,
1252
+ walletAdapterPublicKey,
1253
+ connection
1254
+ } = options;
1255
+ const [transactionResultState, setTransactionResultState] = useState6({ status: "idle" });
1256
+ const [isSigningTransaction, setIsSigningTransaction] = useState6(false);
1257
+ const [isSendingTransaction, setIsSendingTransaction] = useState6(false);
1258
+ const signTransaction = async (transaction) => {
1259
+ setIsSigningTransaction(true);
1260
+ setTransactionResultState({ status: "loading" });
1261
+ try {
1262
+ if (token) setSdkAuth(token);
1263
+ if (signingMethod === "wallet-adapter") {
1264
+ if (!walletAdapterSignTransaction || !walletAdapterPublicKey) {
1265
+ throw new Error("Wallet adapter signTransaction or publicKey not provided.");
1266
+ }
1267
+ const signed = await walletAdapterSignTransaction(transaction);
1268
+ setTransactionResultState({
1269
+ status: "success",
1270
+ message: "Transaction signed successfully!",
1271
+ detail: { transaction: signed.serialize().toString("base64") }
1272
+ });
1273
+ return;
1274
+ }
1275
+ if (!selectedSigner || !selectedWalletId) throw new Error("Please select a signer.");
1276
+ const { signerId, signerType } = extractSignerInfo(selectedSigner);
1277
+ if (signerType === "passkey") {
1278
+ throw new Error("Passkey signers cannot be used for sign-only. Use sign-and-send instead.");
1279
+ }
1280
+ const transactionBuffer = transaction.serializeMessage();
1281
+ const result = await signTransactionWithSigner(
1282
+ selectedWalletId,
1283
+ selectedSigner,
1284
+ transactionBuffer
1285
+ );
1286
+ setTransactionResultState({
1287
+ status: "success",
1288
+ message: `Transaction signed with ${signerType} signer!`,
1289
+ detail: { ...result }
1290
+ });
1291
+ } catch (error) {
1292
+ const errorMsg = extractErrorMessage(error);
1293
+ const isCancelled = errorMsg.toLowerCase().includes("cancel") || errorMsg.toLowerCase().includes("notallowederror");
1294
+ setTransactionResultState({
1295
+ status: "error",
1296
+ message: isCancelled ? "User cancelled authentication" : errorMsg
1297
+ });
1298
+ } finally {
1299
+ setIsSigningTransaction(false);
1300
+ }
1301
+ };
1302
+ const signAndSendTransaction = async (transaction) => {
1303
+ setIsSendingTransaction(true);
1304
+ setTransactionResultState({ status: "loading" });
1305
+ try {
1306
+ if (token) setSdkAuth(token);
1307
+ if (signingMethod === "wallet-adapter") {
1308
+ if (!walletAdapterSignTransaction || !walletAdapterPublicKey || !connection) {
1309
+ throw new Error("Wallet adapter signTransaction, publicKey, or connection not provided.");
1310
+ }
1311
+ const signed = await walletAdapterSignTransaction(transaction);
1312
+ const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash();
1313
+ const signature = await connection.sendRawTransaction(Buffer.from(signed.serialize()));
1314
+ await connection.confirmTransaction({ signature, blockhash, lastValidBlockHeight });
1315
+ setTransactionResultState({
1316
+ status: "success",
1317
+ message: "Transaction sent successfully!",
1318
+ detail: { signature, explorerUrl: `https://solscan.io/tx/${signature}?cluster=devnet` }
1319
+ });
1320
+ return;
1321
+ }
1322
+ if (!selectedSigner || !selectedWalletId) throw new Error("Please select a signer.");
1323
+ const { signerType } = extractSignerInfo(selectedSigner);
1324
+ const result = await signAndSendTransactionWithSigner(
1325
+ selectedWalletId,
1326
+ selectedSigner,
1327
+ transaction,
1328
+ connection ?? void 0
1329
+ );
1330
+ setTransactionResultState({
1331
+ status: "success",
1332
+ message: `Transaction sent with ${signerType} signer!`,
1333
+ detail: {
1334
+ signature: result.signature,
1335
+ confirmationStatus: result.confirmationStatus,
1336
+ explorerUrl: `https://solscan.io/tx/${result.signature}?cluster=devnet`
1337
+ }
1338
+ });
1339
+ } catch (error) {
1340
+ const errorMsg = extractErrorMessage(error);
1341
+ const isCancelled = errorMsg.toLowerCase().includes("cancel") || errorMsg.toLowerCase().includes("notallowederror");
1342
+ setTransactionResultState({
1343
+ status: "error",
1344
+ message: isCancelled ? "User cancelled transaction" : errorMsg,
1345
+ detail: { error: errorMsg, walletId: selectedWalletId }
1346
+ });
1347
+ } finally {
1348
+ setIsSendingTransaction(false);
1349
+ }
1350
+ };
1351
+ const reset = () => {
1352
+ setTransactionResultState({ status: "idle" });
1353
+ };
1354
+ return {
1355
+ transactionResultState,
1356
+ isSigningTransaction,
1357
+ isSendingTransaction,
1358
+ signTransaction,
1359
+ signAndSendTransaction,
1360
+ reset
1361
+ };
1362
+ }
1363
+
1364
+ // src/ui/select.tsx
1365
+ import * as React from "react";
1366
+ import * as SelectPrimitive from "@radix-ui/react-select";
1367
+
1368
+ // src/ui/cn.ts
1369
+ import { clsx } from "clsx";
1370
+ import { twMerge } from "tailwind-merge";
1371
+ function cn(...inputs) {
1372
+ return twMerge(clsx(inputs));
1373
+ }
1374
+
1375
+ // src/ui/select.tsx
1376
+ import { jsx as jsx4, jsxs } from "react/jsx-runtime";
1377
+ var Select = SelectPrimitive.Root;
1378
+ var SelectValue = SelectPrimitive.Value;
1379
+ var SelectTrigger = React.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs(
1380
+ SelectPrimitive.Trigger,
1381
+ {
1382
+ ref,
1383
+ className: cn(
1384
+ "flex h-9 w-full items-center justify-between whitespace-nowrap rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-1 focus:ring-ring disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1",
1385
+ className
1386
+ ),
1387
+ ...props,
1388
+ children: [
1389
+ children,
1390
+ /* @__PURE__ */ jsx4(SelectPrimitive.Icon, { asChild: true, children: /* @__PURE__ */ jsx4("span", { className: "ml-2 h-4 w-4 shrink-0 opacity-50", children: "\u25BC" }) })
1391
+ ]
1392
+ }
1393
+ ));
1394
+ SelectTrigger.displayName = SelectPrimitive.Trigger.displayName;
1395
+ var SelectContent = React.forwardRef(({ className, children, position = "popper", ...props }, ref) => /* @__PURE__ */ jsx4(SelectPrimitive.Portal, { children: /* @__PURE__ */ jsx4(
1396
+ SelectPrimitive.Content,
1397
+ {
1398
+ ref,
1399
+ className: cn(
1400
+ "relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
1401
+ position === "popper" && "data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
1402
+ className
1403
+ ),
1404
+ position,
1405
+ ...props,
1406
+ children: /* @__PURE__ */ jsx4(
1407
+ SelectPrimitive.Viewport,
1408
+ {
1409
+ className: cn(
1410
+ "p-1",
1411
+ position === "popper" && "h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]"
1412
+ ),
1413
+ children
1414
+ }
1415
+ )
1416
+ }
1417
+ ) }));
1418
+ SelectContent.displayName = SelectPrimitive.Content.displayName;
1419
+ var SelectItem = React.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs(
1420
+ SelectPrimitive.Item,
1421
+ {
1422
+ ref,
1423
+ className: cn(
1424
+ "relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-2 pr-8 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
1425
+ className
1426
+ ),
1427
+ ...props,
1428
+ children: [
1429
+ /* @__PURE__ */ jsx4("span", { className: "absolute right-2 flex h-3.5 w-3.5 items-center justify-center", children: /* @__PURE__ */ jsx4(SelectPrimitive.ItemIndicator, { children: "\u2713" }) }),
1430
+ /* @__PURE__ */ jsx4(SelectPrimitive.ItemText, { children })
1431
+ ]
1432
+ }
1433
+ ));
1434
+ SelectItem.displayName = SelectPrimitive.Item.displayName;
1435
+
1436
+ // src/components/WalletSelector.tsx
1437
+ import { Fragment, jsx as jsx5, jsxs as jsxs2 } from "react/jsx-runtime";
1438
+ function WalletSelector(props) {
1439
+ const {
1440
+ value,
1441
+ onWalletChange,
1442
+ className,
1443
+ classNames,
1444
+ placeholder = "Select a wallet",
1445
+ renderTrigger,
1446
+ renderList,
1447
+ children
1448
+ } = props;
1449
+ const { wallets, selectedWallet, selectWallet, isLoading, refreshWallets } = useWallets();
1450
+ const effectiveValue = value ?? selectedWallet?.id ?? selectedWallet?.walletId ?? "";
1451
+ const selected = wallets.find((w) => w.id === effectiveValue || w.walletId === effectiveValue) ?? selectedWallet;
1452
+ const handleSelect = (wallet) => {
1453
+ selectWallet(wallet.id);
1454
+ onWalletChange?.(wallet.id, wallet);
1455
+ };
1456
+ const handleValueChange = (id) => {
1457
+ selectWallet(id);
1458
+ onWalletChange?.(id, wallets.find((w) => w.id === id || w.walletId === id) ?? null);
1459
+ };
1460
+ if (children) {
1461
+ return /* @__PURE__ */ jsx5(Fragment, { children: children({
1462
+ wallets,
1463
+ selectedWallet: selected,
1464
+ selectWallet: (id) => {
1465
+ selectWallet(id);
1466
+ onWalletChange?.(id, wallets.find((w) => w.id === id || w.walletId === id) ?? null);
1467
+ },
1468
+ isLoading,
1469
+ refreshWallets
1470
+ }) });
1471
+ }
1472
+ if (renderTrigger || renderList) {
1473
+ return /* @__PURE__ */ jsxs2("div", { className: cn(className, classNames?.root), "data-cilantro-wallet-selector": true, children: [
1474
+ renderTrigger?.({ selectedWallet: selected, wallets, isLoading, open: false, setOpen: () => {
1475
+ } }),
1476
+ renderList?.({ wallets, selectedWallet: selected, onSelect: handleSelect, isLoading })
1477
+ ] });
1478
+ }
1479
+ return /* @__PURE__ */ jsx5("div", { className: cn(className, classNames?.root), "data-cilantro-wallet-selector": true, children: /* @__PURE__ */ jsxs2(Select, { value: effectiveValue || void 0, onValueChange: handleValueChange, disabled: isLoading, children: [
1480
+ /* @__PURE__ */ jsx5(SelectTrigger, { className: classNames?.trigger, "aria-label": "Select wallet", children: /* @__PURE__ */ jsx5(SelectValue, { placeholder: isLoading ? "Loading..." : placeholder }) }),
1481
+ /* @__PURE__ */ jsx5(SelectContent, { className: classNames?.content, children: wallets.map((w) => /* @__PURE__ */ jsx5(SelectItem, { value: w.id, className: classNames?.item, children: w.walletName || w.id }, w.id)) })
1482
+ ] }) });
1483
+ }
1484
+
1485
+ // src/ui/button.tsx
1486
+ import * as React2 from "react";
1487
+ import { Slot } from "@radix-ui/react-slot";
1488
+ import { cva } from "class-variance-authority";
1489
+ import { jsx as jsx6 } from "react/jsx-runtime";
1490
+ var buttonVariants = cva(
1491
+ "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
1492
+ {
1493
+ variants: {
1494
+ variant: {
1495
+ default: "bg-primary text-primary-foreground hover:bg-primary/90",
1496
+ destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
1497
+ outline: "border border-input bg-background hover:bg-accent hover:text-accent-foreground",
1498
+ secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
1499
+ ghost: "hover:bg-accent hover:text-accent-foreground",
1500
+ link: "text-primary underline-offset-4 hover:underline"
1501
+ },
1502
+ size: {
1503
+ default: "h-10 px-4 py-2",
1504
+ sm: "h-9 rounded-md px-3",
1505
+ lg: "h-11 rounded-md px-8",
1506
+ icon: "h-10 w-10"
1507
+ }
1508
+ },
1509
+ defaultVariants: {
1510
+ variant: "default",
1511
+ size: "default"
1512
+ }
1513
+ }
1514
+ );
1515
+ var Button = React2.forwardRef(
1516
+ ({ className, variant, size, asChild = false, ...props }, ref) => {
1517
+ const Comp = asChild ? Slot : "button";
1518
+ return /* @__PURE__ */ jsx6(Comp, { className: cn(buttonVariants({ variant, size, className })), ref, ...props });
1519
+ }
1520
+ );
1521
+ Button.displayName = "Button";
1522
+
1523
+ // src/components/SignerSelector.tsx
1524
+ import { Fragment as Fragment2, jsx as jsx7, jsxs as jsxs3 } from "react/jsx-runtime";
1525
+ function SignerSelector({
1526
+ selectedWalletId,
1527
+ availableSigners,
1528
+ selectedSigner,
1529
+ isLoadingSigners = false,
1530
+ onSignerSelect,
1531
+ className,
1532
+ classNames,
1533
+ renderList,
1534
+ children
1535
+ }) {
1536
+ if (!selectedWalletId) return null;
1537
+ if (children) {
1538
+ return /* @__PURE__ */ jsx7(Fragment2, { children: children({ signers: availableSigners, selectedSigner, onSignerSelect, isLoading: isLoadingSigners }) });
1539
+ }
1540
+ if (renderList) {
1541
+ return /* @__PURE__ */ jsx7("div", { className: cn(className, classNames?.root), "data-cilantro-signer-selector": true, children: renderList({
1542
+ signers: availableSigners,
1543
+ selectedSigner,
1544
+ onSelect: onSignerSelect,
1545
+ isLoading: isLoadingSigners,
1546
+ getSignerDisplayName,
1547
+ getSignerTypeLabel,
1548
+ getSignerUniqueId
1549
+ }) });
1550
+ }
1551
+ return /* @__PURE__ */ jsx7("div", { className: cn(className, classNames?.root), "data-cilantro-signer-selector": true, role: "listbox", "aria-label": "Select signer", children: isLoadingSigners ? /* @__PURE__ */ jsx7("p", { className: cn("text-sm text-muted-foreground", classNames?.message), children: "Loading signers..." }) : availableSigners.length === 0 ? /* @__PURE__ */ jsx7("p", { className: cn("text-sm text-muted-foreground", classNames?.message), children: "No signers for this wallet." }) : /* @__PURE__ */ jsx7("ul", { className: cn("space-y-1", classNames?.list), children: availableSigners.map((signer) => /* @__PURE__ */ jsx7("li", { children: /* @__PURE__ */ jsxs3(
1552
+ Button,
1553
+ {
1554
+ type: "button",
1555
+ variant: selectedSigner?.id === signer.id ? "secondary" : "ghost",
1556
+ size: "sm",
1557
+ className: cn("w-full justify-start", classNames?.item),
1558
+ onClick: () => onSignerSelect(signer),
1559
+ "aria-pressed": selectedSigner?.id === signer.id,
1560
+ children: [
1561
+ getSignerDisplayName(signer),
1562
+ " (",
1563
+ getSignerTypeLabel(signer.type || signer.signerType || ""),
1564
+ ")"
1565
+ ]
1566
+ }
1567
+ ) }, signer.id)) }) });
1568
+ }
1569
+
1570
+ // src/components/DelegatedKeySelector.tsx
1571
+ import { useState as useState7, useEffect as useEffect6, useCallback as useCallback3 } from "react";
1572
+ import { findAll } from "cilantro-sdk/delegated-keys";
1573
+ import { Fragment as Fragment3, jsx as jsx8, jsxs as jsxs4 } from "react/jsx-runtime";
1574
+ function DelegatedKeySelector(props) {
1575
+ const {
1576
+ walletId,
1577
+ value,
1578
+ onChange,
1579
+ filterActive = true,
1580
+ className,
1581
+ classNames,
1582
+ placeholder = "Select a delegated key",
1583
+ children
1584
+ } = props;
1585
+ const { token } = useCilantroAuth();
1586
+ const [keys, setKeys] = useState7([]);
1587
+ const [isLoading, setIsLoading] = useState7(false);
1588
+ const [error, setError] = useState7(null);
1589
+ const loadKeys = useCallback3(async () => {
1590
+ if (!walletId) {
1591
+ setKeys([]);
1592
+ return;
1593
+ }
1594
+ setIsLoading(true);
1595
+ setError(null);
1596
+ try {
1597
+ if (token) setSdkAuth(token);
1598
+ const result = await findAll(walletId);
1599
+ const keysData = extractResponseData(result) ?? [];
1600
+ const list = Array.isArray(keysData) ? keysData : [];
1601
+ let loaded = list.filter((k) => k != null && typeof k === "object" && "id" in k).map((k) => ({
1602
+ id: String(k.id ?? ""),
1603
+ walletId: String(k.walletId ?? ""),
1604
+ name: k.name,
1605
+ publicKey: String(k.publicKey ?? ""),
1606
+ permissions: k.permissions ?? {},
1607
+ isActive: k.isActive !== false,
1608
+ createdAt: k.createdAt,
1609
+ expiresAt: k.expiresAt,
1610
+ ...k
1611
+ }));
1612
+ if (filterActive) {
1613
+ const now = Date.now();
1614
+ loaded = loaded.filter((key) => {
1615
+ if (!key.isActive) return false;
1616
+ const exp = key.expiresAt ? new Date(key.expiresAt).getTime() : null;
1617
+ return exp === null || exp > now;
1618
+ });
1619
+ }
1620
+ setKeys(loaded);
1621
+ } catch (err) {
1622
+ setError(err instanceof Error ? err.message : String(err));
1623
+ setKeys([]);
1624
+ } finally {
1625
+ setIsLoading(false);
1626
+ }
1627
+ }, [walletId, token, filterActive]);
1628
+ useEffect6(() => {
1629
+ loadKeys();
1630
+ }, [loadKeys]);
1631
+ const onSelect = (key) => {
1632
+ onChange?.(key.id, key);
1633
+ };
1634
+ const handleValueChange = (id) => {
1635
+ const key = keys.find((k) => k.id === id) ?? null;
1636
+ onChange?.(id, key);
1637
+ };
1638
+ if (children) {
1639
+ return /* @__PURE__ */ jsx8(Fragment3, { children: children({ keys, selectedKeyId: value, onSelect, isLoading, error, refresh: loadKeys }) });
1640
+ }
1641
+ if (!walletId) {
1642
+ return /* @__PURE__ */ jsx8("div", { className: cn(className, classNames?.root, "text-sm text-muted-foreground"), children: "Select a wallet first" });
1643
+ }
1644
+ return /* @__PURE__ */ jsx8("div", { className: cn(className, classNames?.root), "data-cilantro-delegated-key-selector": true, children: isLoading ? /* @__PURE__ */ jsx8("p", { className: cn("text-sm text-muted-foreground", classNames?.message), children: "Loading delegated keys..." }) : error ? /* @__PURE__ */ jsx8("p", { className: cn("text-sm text-destructive", classNames?.message), role: "alert", children: error }) : keys.length === 0 ? /* @__PURE__ */ jsx8("p", { className: cn("text-sm text-muted-foreground", classNames?.message), children: "No delegated keys found." }) : /* @__PURE__ */ jsxs4(Select, { value: (value ?? "") || void 0, onValueChange: handleValueChange, children: [
1645
+ /* @__PURE__ */ jsx8(SelectTrigger, { className: classNames?.trigger, "aria-label": "Select delegated key", children: /* @__PURE__ */ jsx8(SelectValue, { placeholder }) }),
1646
+ /* @__PURE__ */ jsx8(SelectContent, { className: classNames?.content, children: keys.map((k) => /* @__PURE__ */ jsx8(SelectItem, { value: k.id, className: classNames?.item, children: k.name || k.publicKey.slice(0, 8) + "..." }, k.id)) })
1647
+ ] }) });
1648
+ }
1649
+
1650
+ // src/ui/textarea.tsx
1651
+ import * as React3 from "react";
1652
+ import { jsx as jsx9 } from "react/jsx-runtime";
1653
+ var Textarea = React3.forwardRef(
1654
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsx9(
1655
+ "textarea",
1656
+ {
1657
+ className: cn(
1658
+ "flex min-h-[80px] w-full rounded-md border border-input bg-transparent px-3 py-2 text-base shadow-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
1659
+ className
1660
+ ),
1661
+ ref,
1662
+ ...props
1663
+ }
1664
+ )
1665
+ );
1666
+ Textarea.displayName = "Textarea";
1667
+
1668
+ // src/ui/label.tsx
1669
+ import * as React4 from "react";
1670
+ import * as LabelPrimitive from "@radix-ui/react-label";
1671
+ import { cva as cva2 } from "class-variance-authority";
1672
+ import { jsx as jsx10 } from "react/jsx-runtime";
1673
+ var labelVariants = cva2(
1674
+ "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
1675
+ );
1676
+ var Label = React4.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx10(LabelPrimitive.Root, { ref, className: cn(labelVariants(), className), ...props }));
1677
+ Label.displayName = LabelPrimitive.Root.displayName;
1678
+
1679
+ // src/ui/card.tsx
1680
+ import * as React5 from "react";
1681
+ import { jsx as jsx11 } from "react/jsx-runtime";
1682
+ var Card = React5.forwardRef(
1683
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsx11(
1684
+ "div",
1685
+ {
1686
+ ref,
1687
+ className: cn("rounded-xl border bg-card text-card-foreground shadow", className),
1688
+ ...props
1689
+ }
1690
+ )
1691
+ );
1692
+ Card.displayName = "Card";
1693
+ var CardHeader = React5.forwardRef(
1694
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsx11("div", { ref, className: cn("flex flex-col space-y-1.5 p-6", className), ...props })
1695
+ );
1696
+ CardHeader.displayName = "CardHeader";
1697
+ var CardTitle = React5.forwardRef(
1698
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsx11(
1699
+ "h3",
1700
+ {
1701
+ ref,
1702
+ className: cn("font-semibold leading-none tracking-tight", className),
1703
+ ...props
1704
+ }
1705
+ )
1706
+ );
1707
+ CardTitle.displayName = "CardTitle";
1708
+ var CardDescription = React5.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx11("p", { ref, className: cn("text-sm text-muted-foreground", className), ...props }));
1709
+ CardDescription.displayName = "CardDescription";
1710
+ var CardContent = React5.forwardRef(
1711
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsx11("div", { ref, className: cn("p-6 pt-0", className), ...props })
1712
+ );
1713
+ CardContent.displayName = "CardContent";
1714
+ var CardFooter = React5.forwardRef(
1715
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsx11("div", { ref, className: cn("flex items-center p-6 pt-0", className), ...props })
1716
+ );
1717
+ CardFooter.displayName = "CardFooter";
1718
+
1719
+ // src/components/MessageSigningForm.tsx
1720
+ import { jsx as jsx12, jsxs as jsxs5 } from "react/jsx-runtime";
1721
+ function MessageSigningForm({
1722
+ token: tokenOverride,
1723
+ selectedWalletId: walletIdOverride,
1724
+ selectedSigner: signerOverride,
1725
+ signingMethod: methodOverride,
1726
+ walletAdapterSignMessage,
1727
+ walletAdapterPublicKey,
1728
+ className,
1729
+ classNames,
1730
+ showContext = true,
1731
+ showCharCount = false,
1732
+ children
1733
+ }) {
1734
+ const { token: contextToken } = useCilantroAuth();
1735
+ const token = tokenOverride ?? contextToken;
1736
+ const selection = useSignerSelection({
1737
+ signingMethod: methodOverride ?? "sdk-signer",
1738
+ walletId: walletIdOverride
1739
+ });
1740
+ const selectedWalletId = walletIdOverride ?? selection.selectedWalletId;
1741
+ const selectedSigner = signerOverride ?? selection.selectedSigner;
1742
+ const signingMethod = methodOverride ?? "sdk-signer";
1743
+ const signing = useMessageSigning({
1744
+ token,
1745
+ signingMethod,
1746
+ selectedSigner,
1747
+ selectedWalletId,
1748
+ walletAdapterSignMessage,
1749
+ walletAdapterPublicKey
1750
+ });
1751
+ if (children) {
1752
+ return /* @__PURE__ */ jsx12("div", { className: cn(className, classNames?.root), "data-cilantro-message-signing-form": true, children: children({
1753
+ messageText: signing.messageText,
1754
+ setMessageText: signing.setMessageText,
1755
+ signResultState: signing.signResultState,
1756
+ isSigning: signing.isSigning,
1757
+ handleSign: signing.handleSign,
1758
+ reset: signing.reset
1759
+ }) });
1760
+ }
1761
+ const resultStatus = signing.signResultState.status;
1762
+ const isSuccess = resultStatus === "success";
1763
+ const isError = resultStatus === "error";
1764
+ return /* @__PURE__ */ jsxs5(Card, { className: cn(className, classNames?.root), "data-cilantro-message-signing-form": true, children: [
1765
+ /* @__PURE__ */ jsxs5(CardHeader, { className: classNames?.header, children: [
1766
+ /* @__PURE__ */ jsx12(CardTitle, { className: cn("text-lg", classNames?.title), children: "Sign message" }),
1767
+ /* @__PURE__ */ jsx12(CardDescription, { className: classNames?.description, children: "Sign a message with your selected wallet or signer. The signature proves you control the key." }),
1768
+ showContext && (selectedWalletId || selectedSigner) && /* @__PURE__ */ jsxs5("p", { className: cn("mt-1 text-xs text-muted-foreground", classNames?.context), children: [
1769
+ selectedWalletId && /* @__PURE__ */ jsxs5("span", { children: [
1770
+ "Wallet: ",
1771
+ selectedWalletId.slice(0, 8),
1772
+ "\u2026"
1773
+ ] }),
1774
+ selectedSigner && /* @__PURE__ */ jsxs5("span", { className: selectedWalletId ? " ml-2" : "", children: [
1775
+ "Signer: ",
1776
+ getSignerDisplayName(selectedSigner),
1777
+ " (",
1778
+ getSignerTypeLabel(selectedSigner.type || selectedSigner.signerType || ""),
1779
+ ")"
1780
+ ] })
1781
+ ] })
1782
+ ] }),
1783
+ /* @__PURE__ */ jsxs5(CardContent, { className: "space-y-4", children: [
1784
+ /* @__PURE__ */ jsxs5("div", { className: "space-y-2", children: [
1785
+ /* @__PURE__ */ jsx12(Label, { htmlFor: "cilantro-message-text", className: classNames?.label, children: "Message" }),
1786
+ /* @__PURE__ */ jsx12(
1787
+ Textarea,
1788
+ {
1789
+ id: "cilantro-message-text",
1790
+ className: classNames?.textarea,
1791
+ value: signing.messageText,
1792
+ onChange: (e) => signing.setMessageText(e.target.value),
1793
+ placeholder: "Enter the message you want to sign...",
1794
+ rows: 4
1795
+ }
1796
+ ),
1797
+ showCharCount && /* @__PURE__ */ jsxs5("p", { className: cn("text-right text-xs text-muted-foreground", classNames?.charCount), children: [
1798
+ signing.messageText.length,
1799
+ " character",
1800
+ signing.messageText.length !== 1 ? "s" : ""
1801
+ ] })
1802
+ ] }),
1803
+ /* @__PURE__ */ jsxs5("div", { className: "flex flex-col gap-2 sm:flex-row sm:items-center", children: [
1804
+ /* @__PURE__ */ jsx12(
1805
+ Button,
1806
+ {
1807
+ type: "button",
1808
+ className: cn("w-full sm:w-auto", classNames?.button),
1809
+ onClick: signing.handleSign,
1810
+ disabled: signing.isSigning || !signing.messageText.trim(),
1811
+ children: signing.isSigning ? "Signing..." : "Sign message"
1812
+ }
1813
+ ),
1814
+ /* @__PURE__ */ jsx12(
1815
+ Button,
1816
+ {
1817
+ type: "button",
1818
+ variant: "outline",
1819
+ className: cn("w-full sm:w-auto", classNames?.resetButton),
1820
+ onClick: signing.reset,
1821
+ disabled: signing.isSigning,
1822
+ children: "Clear"
1823
+ }
1824
+ )
1825
+ ] }),
1826
+ resultStatus !== "idle" && /* @__PURE__ */ jsxs5(
1827
+ "div",
1828
+ {
1829
+ className: cn(
1830
+ "rounded-lg border px-3 py-2 text-sm",
1831
+ isSuccess && cn("border-green-500/50 bg-green-500/10 text-green-700 dark:text-green-400", classNames?.resultSuccess),
1832
+ isError && cn("border-destructive/50 bg-destructive/10 text-destructive", classNames?.resultError),
1833
+ resultStatus === "loading" && "border-muted bg-muted/50 text-muted-foreground",
1834
+ classNames?.result
1835
+ ),
1836
+ "data-status": resultStatus,
1837
+ children: [
1838
+ signing.signResultState.message,
1839
+ signing.signResultState.detail != null && /* @__PURE__ */ jsx12("pre", { className: cn("mt-2 overflow-auto rounded-md bg-muted/80 p-2 text-xs", classNames?.resultPre), children: JSON.stringify(signing.signResultState.detail, null, 2) })
1840
+ ]
1841
+ }
1842
+ )
1843
+ ] })
1844
+ ] });
1845
+ }
1846
+
1847
+ // src/components/TransactionSigningForm.tsx
1848
+ import { jsx as jsx13, jsxs as jsxs6 } from "react/jsx-runtime";
1849
+ function TransactionSigningForm({
1850
+ token: tokenOverride,
1851
+ selectedWalletId: walletIdOverride,
1852
+ selectedSigner: signerOverride,
1853
+ signingMethod: methodOverride,
1854
+ walletAdapterSignTransaction,
1855
+ walletAdapterPublicKey,
1856
+ connection,
1857
+ className,
1858
+ classNames,
1859
+ showContext = true,
1860
+ children
1861
+ }) {
1862
+ const { token: contextToken } = useCilantroAuth();
1863
+ const token = tokenOverride ?? contextToken;
1864
+ const selection = useSignerSelection({
1865
+ signingMethod: methodOverride ?? "sdk-signer",
1866
+ walletId: walletIdOverride
1867
+ });
1868
+ const selectedWalletId = walletIdOverride ?? selection.selectedWalletId;
1869
+ const selectedSigner = signerOverride ?? selection.selectedSigner;
1870
+ const signingMethod = methodOverride ?? "sdk-signer";
1871
+ const signing = useTransactionSigning({
1872
+ token,
1873
+ signingMethod,
1874
+ selectedSigner,
1875
+ selectedWalletId,
1876
+ walletAdapterSignTransaction,
1877
+ walletAdapterPublicKey,
1878
+ connection
1879
+ });
1880
+ if (children) {
1881
+ return /* @__PURE__ */ jsx13("div", { className: cn(className, classNames?.root), "data-cilantro-transaction-signing-form": true, children: children({
1882
+ transactionResultState: signing.transactionResultState,
1883
+ isSigningTransaction: signing.isSigningTransaction,
1884
+ isSendingTransaction: signing.isSendingTransaction,
1885
+ signTransaction: signing.signTransaction,
1886
+ signAndSendTransaction: signing.signAndSendTransaction,
1887
+ reset: signing.reset
1888
+ }) });
1889
+ }
1890
+ const resultStatus = signing.transactionResultState.status;
1891
+ const isSuccess = resultStatus === "success";
1892
+ const isError = resultStatus === "error";
1893
+ return /* @__PURE__ */ jsxs6(Card, { className: cn(className, classNames?.root), "data-cilantro-transaction-signing-form": true, children: [
1894
+ /* @__PURE__ */ jsxs6(CardHeader, { className: classNames?.header, children: [
1895
+ /* @__PURE__ */ jsx13(CardTitle, { className: cn("text-lg", classNames?.title), children: "Sign transaction" }),
1896
+ /* @__PURE__ */ jsxs6(CardDescription, { className: classNames?.description, children: [
1897
+ "Build a transaction in your app, then pass it to ",
1898
+ /* @__PURE__ */ jsx13("code", { className: "text-xs", children: "signTransaction(tx)" }),
1899
+ " to sign only, or ",
1900
+ /* @__PURE__ */ jsx13("code", { className: "text-xs", children: "signAndSendTransaction(tx)" }),
1901
+ " to sign and send. Use the render props (children) to wire your own UI."
1902
+ ] }),
1903
+ showContext && (selectedWalletId || selectedSigner) && /* @__PURE__ */ jsxs6("p", { className: cn("mt-1 text-xs text-muted-foreground", classNames?.context), children: [
1904
+ selectedWalletId && /* @__PURE__ */ jsxs6("span", { children: [
1905
+ "Wallet: ",
1906
+ selectedWalletId.slice(0, 8),
1907
+ "\u2026"
1908
+ ] }),
1909
+ selectedSigner && /* @__PURE__ */ jsxs6("span", { className: selectedWalletId ? " ml-2" : "", children: [
1910
+ "Signer: ",
1911
+ getSignerDisplayName(selectedSigner),
1912
+ " (",
1913
+ getSignerTypeLabel(selectedSigner.type || selectedSigner.signerType || ""),
1914
+ ")"
1915
+ ] })
1916
+ ] })
1917
+ ] }),
1918
+ /* @__PURE__ */ jsxs6(CardContent, { className: "space-y-4", children: [
1919
+ /* @__PURE__ */ jsx13(
1920
+ Button,
1921
+ {
1922
+ type: "button",
1923
+ variant: "outline",
1924
+ className: classNames?.button,
1925
+ onClick: signing.reset,
1926
+ disabled: signing.isSigningTransaction || signing.isSendingTransaction,
1927
+ children: "Reset status"
1928
+ }
1929
+ ),
1930
+ resultStatus !== "idle" && /* @__PURE__ */ jsxs6(
1931
+ "div",
1932
+ {
1933
+ className: cn(
1934
+ "rounded-lg border px-3 py-2 text-sm",
1935
+ isSuccess && cn("border-green-500/50 bg-green-500/10 text-green-700 dark:text-green-400", classNames?.resultSuccess),
1936
+ isError && cn("border-destructive/50 bg-destructive/10 text-destructive", classNames?.resultError),
1937
+ resultStatus === "loading" && "border-muted bg-muted/50 text-muted-foreground",
1938
+ classNames?.result
1939
+ ),
1940
+ "data-status": resultStatus,
1941
+ children: [
1942
+ signing.transactionResultState.message,
1943
+ signing.transactionResultState.detail != null && /* @__PURE__ */ jsx13("pre", { className: cn("mt-2 overflow-auto rounded-md bg-muted/80 p-2 text-xs", classNames?.resultPre), children: JSON.stringify(signing.transactionResultState.detail, null, 2) })
1944
+ ]
1945
+ }
1946
+ )
1947
+ ] })
1948
+ ] });
1949
+ }
1950
+
1951
+ // src/components/LoginForm.tsx
1952
+ import { useState as useState8 } from "react";
1953
+
1954
+ // src/ui/input.tsx
1955
+ import * as React6 from "react";
1956
+ import { jsx as jsx14 } from "react/jsx-runtime";
1957
+ var Input = React6.forwardRef(
1958
+ ({ className, type, ...props }, ref) => {
1959
+ return /* @__PURE__ */ jsx14(
1960
+ "input",
1961
+ {
1962
+ type,
1963
+ className: cn(
1964
+ "flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-base shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
1965
+ className
1966
+ ),
1967
+ ref,
1968
+ ...props
1969
+ }
1970
+ );
1971
+ }
1972
+ );
1973
+ Input.displayName = "Input";
1974
+
1975
+ // src/components/LoginForm.tsx
1976
+ import { jsx as jsx15, jsxs as jsxs7 } from "react/jsx-runtime";
1977
+ function LoginForm({
1978
+ className,
1979
+ classNames,
1980
+ onSuccess,
1981
+ onError,
1982
+ submitLabel = "Sign in",
1983
+ title = "Sign in",
1984
+ description,
1985
+ renderSwitchToRegister
1986
+ }) {
1987
+ const { login, isLoading } = useCilantroAuth();
1988
+ const [usernameOrEmail, setUsernameOrEmail] = useState8("");
1989
+ const [password, setPassword] = useState8("");
1990
+ const [error, setError] = useState8(null);
1991
+ const handleSubmit = async (e) => {
1992
+ e.preventDefault();
1993
+ setError(null);
1994
+ try {
1995
+ await login(usernameOrEmail.trim(), password);
1996
+ onSuccess?.();
1997
+ } catch (err) {
1998
+ const message = err instanceof Error ? err.message : String(err);
1999
+ setError(message);
2000
+ onError?.(message);
2001
+ }
2002
+ };
2003
+ return /* @__PURE__ */ jsxs7(Card, { className: cn(className, classNames?.root), "data-cilantro-login-form": true, children: [
2004
+ /* @__PURE__ */ jsxs7(CardHeader, { className: classNames?.header, children: [
2005
+ /* @__PURE__ */ jsx15(CardTitle, { className: classNames?.title, children: title }),
2006
+ description != null && /* @__PURE__ */ jsx15(CardDescription, { className: classNames?.description, children: description })
2007
+ ] }),
2008
+ /* @__PURE__ */ jsx15(CardContent, { children: /* @__PURE__ */ jsxs7("form", { onSubmit: handleSubmit, className: cn("space-y-4", classNames?.form), children: [
2009
+ /* @__PURE__ */ jsxs7("div", { className: "space-y-2", children: [
2010
+ /* @__PURE__ */ jsx15(Label, { htmlFor: "cilantro-login-username", className: classNames?.label, children: "Username or email" }),
2011
+ /* @__PURE__ */ jsx15(
2012
+ Input,
2013
+ {
2014
+ id: "cilantro-login-username",
2015
+ type: "text",
2016
+ autoComplete: "username",
2017
+ className: classNames?.input,
2018
+ value: usernameOrEmail,
2019
+ onChange: (e) => setUsernameOrEmail(e.target.value),
2020
+ placeholder: "Username or email",
2021
+ required: true,
2022
+ disabled: isLoading
2023
+ }
2024
+ )
2025
+ ] }),
2026
+ /* @__PURE__ */ jsxs7("div", { className: "space-y-2", children: [
2027
+ /* @__PURE__ */ jsx15(Label, { htmlFor: "cilantro-login-password", className: classNames?.label, children: "Password" }),
2028
+ /* @__PURE__ */ jsx15(
2029
+ Input,
2030
+ {
2031
+ id: "cilantro-login-password",
2032
+ type: "password",
2033
+ autoComplete: "current-password",
2034
+ className: classNames?.input,
2035
+ value: password,
2036
+ onChange: (e) => setPassword(e.target.value),
2037
+ placeholder: "Password",
2038
+ required: true,
2039
+ disabled: isLoading
2040
+ }
2041
+ )
2042
+ ] }),
2043
+ error && /* @__PURE__ */ jsx15(
2044
+ "div",
2045
+ {
2046
+ className: cn(
2047
+ "rounded-md border border-destructive/50 bg-destructive/10 px-3 py-2 text-sm text-destructive",
2048
+ classNames?.error
2049
+ ),
2050
+ role: "alert",
2051
+ children: error
2052
+ }
2053
+ ),
2054
+ /* @__PURE__ */ jsx15(
2055
+ Button,
2056
+ {
2057
+ type: "submit",
2058
+ className: cn("w-full", classNames?.submitButton),
2059
+ disabled: isLoading || !usernameOrEmail.trim() || !password,
2060
+ children: isLoading ? "Signing in..." : submitLabel
2061
+ }
2062
+ ),
2063
+ renderSwitchToRegister && /* @__PURE__ */ jsx15("div", { className: "text-center text-sm text-muted-foreground", children: renderSwitchToRegister() })
2064
+ ] }) })
2065
+ ] });
2066
+ }
2067
+
2068
+ // src/components/RegisterForm.tsx
2069
+ import { useState as useState9 } from "react";
2070
+ import { jsx as jsx16, jsxs as jsxs8 } from "react/jsx-runtime";
2071
+ function RegisterForm({
2072
+ className,
2073
+ classNames,
2074
+ onSuccess,
2075
+ onError,
2076
+ submitLabel = "Create account",
2077
+ title = "Create an account",
2078
+ description,
2079
+ isActive = true,
2080
+ renderSwitchToLogin
2081
+ }) {
2082
+ const { register, isLoading } = useCilantroAuth();
2083
+ const [username, setUsername] = useState9("");
2084
+ const [email, setEmail] = useState9("");
2085
+ const [password, setPassword] = useState9("");
2086
+ const [error, setError] = useState9(null);
2087
+ const handleSubmit = async (e) => {
2088
+ e.preventDefault();
2089
+ setError(null);
2090
+ try {
2091
+ await register(username.trim(), email.trim(), password, isActive);
2092
+ onSuccess?.();
2093
+ } catch (err) {
2094
+ const message = err instanceof Error ? err.message : String(err);
2095
+ setError(message);
2096
+ onError?.(message);
2097
+ }
2098
+ };
2099
+ return /* @__PURE__ */ jsxs8(Card, { className: cn(className, classNames?.root), "data-cilantro-register-form": true, children: [
2100
+ /* @__PURE__ */ jsxs8(CardHeader, { className: classNames?.header, children: [
2101
+ /* @__PURE__ */ jsx16(CardTitle, { className: classNames?.title, children: title }),
2102
+ description != null && /* @__PURE__ */ jsx16(CardDescription, { className: classNames?.description, children: description })
2103
+ ] }),
2104
+ /* @__PURE__ */ jsx16(CardContent, { children: /* @__PURE__ */ jsxs8("form", { onSubmit: handleSubmit, className: cn("space-y-4", classNames?.form), children: [
2105
+ /* @__PURE__ */ jsxs8("div", { className: "space-y-2", children: [
2106
+ /* @__PURE__ */ jsx16(Label, { htmlFor: "cilantro-register-username", className: classNames?.label, children: "Username" }),
2107
+ /* @__PURE__ */ jsx16(
2108
+ Input,
2109
+ {
2110
+ id: "cilantro-register-username",
2111
+ type: "text",
2112
+ autoComplete: "username",
2113
+ className: classNames?.input,
2114
+ value: username,
2115
+ onChange: (e) => setUsername(e.target.value),
2116
+ placeholder: "Username",
2117
+ required: true,
2118
+ disabled: isLoading
2119
+ }
2120
+ )
2121
+ ] }),
2122
+ /* @__PURE__ */ jsxs8("div", { className: "space-y-2", children: [
2123
+ /* @__PURE__ */ jsx16(Label, { htmlFor: "cilantro-register-email", className: classNames?.label, children: "Email" }),
2124
+ /* @__PURE__ */ jsx16(
2125
+ Input,
2126
+ {
2127
+ id: "cilantro-register-email",
2128
+ type: "email",
2129
+ autoComplete: "email",
2130
+ className: classNames?.input,
2131
+ value: email,
2132
+ onChange: (e) => setEmail(e.target.value),
2133
+ placeholder: "Email",
2134
+ required: true,
2135
+ disabled: isLoading
2136
+ }
2137
+ )
2138
+ ] }),
2139
+ /* @__PURE__ */ jsxs8("div", { className: "space-y-2", children: [
2140
+ /* @__PURE__ */ jsx16(Label, { htmlFor: "cilantro-register-password", className: classNames?.label, children: "Password" }),
2141
+ /* @__PURE__ */ jsx16(
2142
+ Input,
2143
+ {
2144
+ id: "cilantro-register-password",
2145
+ type: "password",
2146
+ autoComplete: "new-password",
2147
+ className: classNames?.input,
2148
+ value: password,
2149
+ onChange: (e) => setPassword(e.target.value),
2150
+ placeholder: "Password",
2151
+ required: true,
2152
+ disabled: isLoading
2153
+ }
2154
+ )
2155
+ ] }),
2156
+ error && /* @__PURE__ */ jsx16(
2157
+ "div",
2158
+ {
2159
+ className: cn(
2160
+ "rounded-md border border-destructive/50 bg-destructive/10 px-3 py-2 text-sm text-destructive",
2161
+ classNames?.error
2162
+ ),
2163
+ role: "alert",
2164
+ children: error
2165
+ }
2166
+ ),
2167
+ /* @__PURE__ */ jsx16(
2168
+ Button,
2169
+ {
2170
+ type: "submit",
2171
+ className: cn("w-full", classNames?.submitButton),
2172
+ disabled: isLoading || !username.trim() || !email.trim() || !password,
2173
+ children: isLoading ? "Creating account..." : submitLabel
2174
+ }
2175
+ ),
2176
+ renderSwitchToLogin && /* @__PURE__ */ jsx16("div", { className: "text-center text-sm text-muted-foreground", children: renderSwitchToLogin() })
2177
+ ] }) })
2178
+ ] });
2179
+ }
2180
+
2181
+ // src/components/AuthForm.tsx
2182
+ import { useState as useState10 } from "react";
2183
+ import { Fragment as Fragment4, jsx as jsx17, jsxs as jsxs9 } from "react/jsx-runtime";
2184
+ function AuthForm({
2185
+ defaultMode = "login",
2186
+ className,
2187
+ classNames,
2188
+ onSuccess,
2189
+ onError,
2190
+ loginSubmitLabel = "Sign in",
2191
+ registerSubmitLabel = "Create account",
2192
+ loginTitle = "Welcome back",
2193
+ registerTitle = "Create an account",
2194
+ loginDescription = "Sign in with your username or email.",
2195
+ registerDescription = "Enter your details to get started.",
2196
+ switchToRegisterText = "Don't have an account? Create one",
2197
+ switchToLoginText = "Already have an account? Sign in",
2198
+ isActive = true
2199
+ }) {
2200
+ const { login, register, isLoading } = useCilantroAuth();
2201
+ const [mode, setMode] = useState10(defaultMode);
2202
+ const [usernameOrEmail, setUsernameOrEmail] = useState10("");
2203
+ const [username, setUsername] = useState10("");
2204
+ const [email, setEmail] = useState10("");
2205
+ const [password, setPassword] = useState10("");
2206
+ const [error, setError] = useState10(null);
2207
+ const isLogin = mode === "login";
2208
+ const handleSubmit = async (e) => {
2209
+ e.preventDefault();
2210
+ setError(null);
2211
+ try {
2212
+ if (isLogin) {
2213
+ await login(usernameOrEmail.trim(), password);
2214
+ } else {
2215
+ await register(username.trim(), email.trim(), password, isActive);
2216
+ }
2217
+ onSuccess?.();
2218
+ } catch (err) {
2219
+ const message = err instanceof Error ? err.message : String(err);
2220
+ setError(message);
2221
+ onError?.(message);
2222
+ }
2223
+ };
2224
+ const switchMode = () => {
2225
+ setMode(isLogin ? "register" : "login");
2226
+ setError(null);
2227
+ };
2228
+ const canSubmit = isLogin ? usernameOrEmail.trim().length > 0 && password.length > 0 : username.trim().length > 0 && email.trim().length > 0 && password.length > 0;
2229
+ return /* @__PURE__ */ jsxs9(Card, { className: cn("w-full max-w-sm", className, classNames?.root), "data-cilantro-auth-form": true, children: [
2230
+ /* @__PURE__ */ jsxs9(CardHeader, { className: cn("space-y-1 text-center sm:text-left", classNames?.header), children: [
2231
+ /* @__PURE__ */ jsx17(CardTitle, { className: cn("text-xl", classNames?.title), children: isLogin ? loginTitle : registerTitle }),
2232
+ /* @__PURE__ */ jsx17(CardDescription, { className: classNames?.description, children: isLogin ? loginDescription : registerDescription })
2233
+ ] }),
2234
+ /* @__PURE__ */ jsx17(CardContent, { children: /* @__PURE__ */ jsxs9("form", { onSubmit: handleSubmit, className: cn("space-y-4", classNames?.form), children: [
2235
+ isLogin ? /* @__PURE__ */ jsxs9(Fragment4, { children: [
2236
+ /* @__PURE__ */ jsxs9("div", { className: "space-y-2", children: [
2237
+ /* @__PURE__ */ jsx17(Label, { htmlFor: "cilantro-auth-username", className: classNames?.label, children: "Username or email" }),
2238
+ /* @__PURE__ */ jsx17(
2239
+ Input,
2240
+ {
2241
+ id: "cilantro-auth-username",
2242
+ type: "text",
2243
+ autoComplete: "username",
2244
+ className: classNames?.input,
2245
+ value: usernameOrEmail,
2246
+ onChange: (e) => setUsernameOrEmail(e.target.value),
2247
+ placeholder: "you@example.com",
2248
+ required: true,
2249
+ disabled: isLoading
2250
+ }
2251
+ )
2252
+ ] }),
2253
+ /* @__PURE__ */ jsxs9("div", { className: "space-y-2", children: [
2254
+ /* @__PURE__ */ jsx17(Label, { htmlFor: "cilantro-auth-password", className: classNames?.label, children: "Password" }),
2255
+ /* @__PURE__ */ jsx17(
2256
+ Input,
2257
+ {
2258
+ id: "cilantro-auth-password",
2259
+ type: "password",
2260
+ autoComplete: "current-password",
2261
+ className: classNames?.input,
2262
+ value: password,
2263
+ onChange: (e) => setPassword(e.target.value),
2264
+ placeholder: "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022",
2265
+ required: true,
2266
+ disabled: isLoading
2267
+ }
2268
+ )
2269
+ ] })
2270
+ ] }) : /* @__PURE__ */ jsxs9(Fragment4, { children: [
2271
+ /* @__PURE__ */ jsxs9("div", { className: "space-y-2", children: [
2272
+ /* @__PURE__ */ jsx17(Label, { htmlFor: "cilantro-auth-reg-username", className: classNames?.label, children: "Username" }),
2273
+ /* @__PURE__ */ jsx17(
2274
+ Input,
2275
+ {
2276
+ id: "cilantro-auth-reg-username",
2277
+ type: "text",
2278
+ autoComplete: "username",
2279
+ className: classNames?.input,
2280
+ value: username,
2281
+ onChange: (e) => setUsername(e.target.value),
2282
+ placeholder: "johndoe",
2283
+ required: true,
2284
+ disabled: isLoading
2285
+ }
2286
+ )
2287
+ ] }),
2288
+ /* @__PURE__ */ jsxs9("div", { className: "space-y-2", children: [
2289
+ /* @__PURE__ */ jsx17(Label, { htmlFor: "cilantro-auth-reg-email", className: classNames?.label, children: "Email" }),
2290
+ /* @__PURE__ */ jsx17(
2291
+ Input,
2292
+ {
2293
+ id: "cilantro-auth-reg-email",
2294
+ type: "email",
2295
+ autoComplete: "email",
2296
+ className: classNames?.input,
2297
+ value: email,
2298
+ onChange: (e) => setEmail(e.target.value),
2299
+ placeholder: "you@example.com",
2300
+ required: true,
2301
+ disabled: isLoading
2302
+ }
2303
+ )
2304
+ ] }),
2305
+ /* @__PURE__ */ jsxs9("div", { className: "space-y-2", children: [
2306
+ /* @__PURE__ */ jsx17(Label, { htmlFor: "cilantro-auth-reg-password", className: classNames?.label, children: "Password" }),
2307
+ /* @__PURE__ */ jsx17(
2308
+ Input,
2309
+ {
2310
+ id: "cilantro-auth-reg-password",
2311
+ type: "password",
2312
+ autoComplete: "new-password",
2313
+ className: classNames?.input,
2314
+ value: password,
2315
+ onChange: (e) => setPassword(e.target.value),
2316
+ placeholder: "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022",
2317
+ required: true,
2318
+ disabled: isLoading
2319
+ }
2320
+ )
2321
+ ] })
2322
+ ] }),
2323
+ error && /* @__PURE__ */ jsx17(
2324
+ "div",
2325
+ {
2326
+ className: cn(
2327
+ "rounded-md border border-destructive/50 bg-destructive/10 px-3 py-2 text-sm text-destructive",
2328
+ classNames?.error
2329
+ ),
2330
+ role: "alert",
2331
+ children: error
2332
+ }
2333
+ ),
2334
+ /* @__PURE__ */ jsx17(
2335
+ Button,
2336
+ {
2337
+ type: "submit",
2338
+ className: cn("w-full", classNames?.submitButton),
2339
+ disabled: isLoading || !canSubmit,
2340
+ children: isLoading ? isLogin ? "Signing in..." : "Creating account..." : isLogin ? loginSubmitLabel : registerSubmitLabel
2341
+ }
2342
+ ),
2343
+ /* @__PURE__ */ jsx17("p", { className: cn("text-center text-sm text-muted-foreground", classNames?.toggle), children: /* @__PURE__ */ jsx17(
2344
+ "button",
2345
+ {
2346
+ type: "button",
2347
+ className: cn("underline underline-offset-2 hover:text-foreground", classNames?.toggleLink),
2348
+ onClick: switchMode,
2349
+ disabled: isLoading,
2350
+ children: isLogin ? switchToRegisterText : switchToLoginText
2351
+ }
2352
+ ) })
2353
+ ] }) })
2354
+ ] });
2355
+ }
2356
+
2357
+ // src/components/AuthGuard.tsx
2358
+ import { Fragment as Fragment5, jsx as jsx18 } from "react/jsx-runtime";
2359
+ function AuthGuard({
2360
+ children,
2361
+ fallback,
2362
+ className,
2363
+ classNames,
2364
+ showFallback = true
2365
+ }) {
2366
+ const { isAuthenticated, isLoading } = useCilantroAuth();
2367
+ if (isLoading) {
2368
+ return /* @__PURE__ */ jsx18("div", { className: cn(className, classNames?.root), "data-cilantro-auth-guard": true, children: /* @__PURE__ */ jsx18("div", { className: cn("text-sm text-muted-foreground", classNames?.fallback), children: "Loading..." }) });
2369
+ }
2370
+ if (!isAuthenticated) {
2371
+ if (!showFallback) return null;
2372
+ return /* @__PURE__ */ jsx18("div", { className: cn(className, classNames?.root), "data-cilantro-auth-guard": true, children: fallback ?? /* @__PURE__ */ jsx18(LoginForm, { className: classNames?.fallback }) });
2373
+ }
2374
+ return /* @__PURE__ */ jsx18(Fragment5, { children });
2375
+ }
2376
+
2377
+ // src/components/AddSignerForm.tsx
2378
+ import { useState as useState11 } from "react";
2379
+
2380
+ // src/ui/dialog.tsx
2381
+ import * as React7 from "react";
2382
+ import * as DialogPrimitive from "@radix-ui/react-dialog";
2383
+ import { jsx as jsx19, jsxs as jsxs10 } from "react/jsx-runtime";
2384
+ var Dialog = DialogPrimitive.Root;
2385
+ var DialogPortal = DialogPrimitive.Portal;
2386
+ var DialogOverlay = React7.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx19(
2387
+ DialogPrimitive.Overlay,
2388
+ {
2389
+ ref,
2390
+ className: cn(
2391
+ "fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
2392
+ className
2393
+ ),
2394
+ ...props
2395
+ }
2396
+ ));
2397
+ DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
2398
+ var DialogContent = React7.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs10(DialogPortal, { children: [
2399
+ /* @__PURE__ */ jsx19(DialogOverlay, {}),
2400
+ /* @__PURE__ */ jsx19(
2401
+ DialogPrimitive.Content,
2402
+ {
2403
+ ref,
2404
+ className: cn(
2405
+ "fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg",
2406
+ className
2407
+ ),
2408
+ ...props,
2409
+ children
2410
+ }
2411
+ )
2412
+ ] }));
2413
+ DialogContent.displayName = DialogPrimitive.Content.displayName;
2414
+ var DialogHeader = ({ className, ...props }) => /* @__PURE__ */ jsx19("div", { className: cn("flex flex-col space-y-1.5 text-center sm:text-left", className), ...props });
2415
+ DialogHeader.displayName = "DialogHeader";
2416
+ var DialogFooter = ({ className, ...props }) => /* @__PURE__ */ jsx19(
2417
+ "div",
2418
+ {
2419
+ className: cn("flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2", className),
2420
+ ...props
2421
+ }
2422
+ );
2423
+ DialogFooter.displayName = "DialogFooter";
2424
+ var DialogTitle = React7.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx19(
2425
+ DialogPrimitive.Title,
2426
+ {
2427
+ ref,
2428
+ className: cn("text-lg font-semibold leading-none tracking-tight", className),
2429
+ ...props
2430
+ }
2431
+ ));
2432
+ DialogTitle.displayName = DialogPrimitive.Title.displayName;
2433
+ var DialogDescription = React7.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx19(
2434
+ DialogPrimitive.Description,
2435
+ {
2436
+ ref,
2437
+ className: cn("text-sm text-muted-foreground", className),
2438
+ ...props
2439
+ }
2440
+ ));
2441
+ DialogDescription.displayName = DialogPrimitive.Description.displayName;
2442
+
2443
+ // src/components/AddSignerForm.tsx
2444
+ import { Fragment as Fragment6, jsx as jsx20, jsxs as jsxs11 } from "react/jsx-runtime";
2445
+ function AddSignerForm({
2446
+ walletId,
2447
+ open = true,
2448
+ onOpenChange,
2449
+ onSuccess,
2450
+ onCancel,
2451
+ onError,
2452
+ className,
2453
+ classNames,
2454
+ asDialog = true
2455
+ }) {
2456
+ const [signerType, setSignerType] = useState11(null);
2457
+ const [email, setEmail] = useState11("");
2458
+ const [phone, setPhone] = useState11("");
2459
+ const [address, setAddress] = useState11("");
2460
+ const [isSubmitting, setIsSubmitting] = useState11(false);
2461
+ const [error, setError] = useState11(null);
2462
+ const resetForm = () => {
2463
+ setSignerType(null);
2464
+ setEmail("");
2465
+ setPhone("");
2466
+ setAddress("");
2467
+ setError(null);
2468
+ };
2469
+ const handleClose = (open2) => {
2470
+ if (!open2) {
2471
+ resetForm();
2472
+ onCancel?.();
2473
+ }
2474
+ onOpenChange?.(open2);
2475
+ };
2476
+ const handleSubmit = async (e) => {
2477
+ e.preventDefault();
2478
+ if (!signerType) return;
2479
+ setError(null);
2480
+ setIsSubmitting(true);
2481
+ try {
2482
+ if (signerType === "email") {
2483
+ await createEmailSignerHelper(walletId, email);
2484
+ } else if (signerType === "phone") {
2485
+ await createPhoneSignerHelper(walletId, phone);
2486
+ } else if (signerType === "passkey") {
2487
+ await registerPasskeySigner(walletId);
2488
+ } else if (signerType === "external") {
2489
+ await createExternalSignerHelper(walletId, address);
2490
+ }
2491
+ resetForm();
2492
+ onSuccess?.();
2493
+ handleClose(false);
2494
+ } catch (err) {
2495
+ const message = err instanceof Error ? err.message : String(err);
2496
+ setError(message);
2497
+ onError?.(message);
2498
+ } finally {
2499
+ setIsSubmitting(false);
2500
+ }
2501
+ };
2502
+ const handlePasskeyClick = () => {
2503
+ setSignerType("passkey");
2504
+ setError(null);
2505
+ setIsSubmitting(true);
2506
+ registerPasskeySigner(walletId).then(() => {
2507
+ resetForm();
2508
+ onSuccess?.();
2509
+ handleClose(false);
2510
+ }).catch((err) => {
2511
+ const message = err instanceof Error ? err.message : String(err);
2512
+ setError(message);
2513
+ onError?.(message);
2514
+ }).finally(() => setIsSubmitting(false));
2515
+ };
2516
+ const formContent = /* @__PURE__ */ jsxs11("form", { onSubmit: handleSubmit, className: cn("space-y-4", classNames?.form), children: [
2517
+ !signerType ? /* @__PURE__ */ jsxs11(Fragment6, { children: [
2518
+ /* @__PURE__ */ jsxs11("div", { className: "space-y-2", children: [
2519
+ /* @__PURE__ */ jsx20(Label, { className: classNames?.label, children: "Signer type" }),
2520
+ /* @__PURE__ */ jsxs11("div", { className: "flex flex-wrap gap-2", children: [
2521
+ /* @__PURE__ */ jsx20(
2522
+ Button,
2523
+ {
2524
+ type: "button",
2525
+ variant: "outline",
2526
+ size: "sm",
2527
+ onClick: () => setSignerType("email"),
2528
+ disabled: isSubmitting,
2529
+ children: "Email"
2530
+ }
2531
+ ),
2532
+ /* @__PURE__ */ jsx20(
2533
+ Button,
2534
+ {
2535
+ type: "button",
2536
+ variant: "outline",
2537
+ size: "sm",
2538
+ onClick: () => setSignerType("phone"),
2539
+ disabled: isSubmitting,
2540
+ children: "Phone"
2541
+ }
2542
+ ),
2543
+ /* @__PURE__ */ jsx20(
2544
+ Button,
2545
+ {
2546
+ type: "button",
2547
+ variant: "outline",
2548
+ size: "sm",
2549
+ onClick: handlePasskeyClick,
2550
+ disabled: isSubmitting,
2551
+ children: "Passkey"
2552
+ }
2553
+ ),
2554
+ /* @__PURE__ */ jsx20(
2555
+ Button,
2556
+ {
2557
+ type: "button",
2558
+ variant: "outline",
2559
+ size: "sm",
2560
+ onClick: () => setSignerType("external"),
2561
+ disabled: isSubmitting,
2562
+ children: "External wallet"
2563
+ }
2564
+ )
2565
+ ] })
2566
+ ] }),
2567
+ asDialog && /* @__PURE__ */ jsx20(DialogFooter, { className: "gap-2 sm:gap-0", children: /* @__PURE__ */ jsx20(
2568
+ Button,
2569
+ {
2570
+ type: "button",
2571
+ variant: "outline",
2572
+ className: classNames?.cancelButton,
2573
+ onClick: () => handleClose(false),
2574
+ disabled: isSubmitting,
2575
+ children: "Cancel"
2576
+ }
2577
+ ) })
2578
+ ] }) : signerType === "email" ? /* @__PURE__ */ jsxs11(Fragment6, { children: [
2579
+ /* @__PURE__ */ jsxs11("div", { className: "space-y-2", children: [
2580
+ /* @__PURE__ */ jsx20(Label, { htmlFor: "add-signer-email", className: classNames?.label, children: "Email" }),
2581
+ /* @__PURE__ */ jsx20(
2582
+ Input,
2583
+ {
2584
+ id: "add-signer-email",
2585
+ type: "email",
2586
+ autoComplete: "email",
2587
+ className: classNames?.input,
2588
+ value: email,
2589
+ onChange: (e) => setEmail(e.target.value),
2590
+ placeholder: "email@example.com",
2591
+ required: true,
2592
+ disabled: isSubmitting
2593
+ }
2594
+ )
2595
+ ] }),
2596
+ asDialog && /* @__PURE__ */ jsxs11(DialogFooter, { className: "gap-2 sm:gap-0", children: [
2597
+ /* @__PURE__ */ jsx20(
2598
+ Button,
2599
+ {
2600
+ type: "button",
2601
+ variant: "outline",
2602
+ className: classNames?.cancelButton,
2603
+ onClick: () => setSignerType(null),
2604
+ disabled: isSubmitting,
2605
+ children: "Back"
2606
+ }
2607
+ ),
2608
+ /* @__PURE__ */ jsx20(Button, { type: "submit", className: classNames?.submitButton, disabled: isSubmitting, children: isSubmitting ? "Adding..." : "Add signer" })
2609
+ ] }),
2610
+ !asDialog && /* @__PURE__ */ jsxs11("div", { className: "flex gap-2", children: [
2611
+ /* @__PURE__ */ jsx20(
2612
+ Button,
2613
+ {
2614
+ type: "button",
2615
+ variant: "outline",
2616
+ className: classNames?.cancelButton,
2617
+ onClick: () => setSignerType(null),
2618
+ disabled: isSubmitting,
2619
+ children: "Back"
2620
+ }
2621
+ ),
2622
+ /* @__PURE__ */ jsx20(Button, { type: "submit", className: classNames?.submitButton, disabled: isSubmitting, children: isSubmitting ? "Adding..." : "Add signer" })
2623
+ ] })
2624
+ ] }) : signerType === "phone" ? /* @__PURE__ */ jsxs11(Fragment6, { children: [
2625
+ /* @__PURE__ */ jsxs11("div", { className: "space-y-2", children: [
2626
+ /* @__PURE__ */ jsx20(Label, { htmlFor: "add-signer-phone", className: classNames?.label, children: "Phone number" }),
2627
+ /* @__PURE__ */ jsx20(
2628
+ Input,
2629
+ {
2630
+ id: "add-signer-phone",
2631
+ type: "tel",
2632
+ autoComplete: "tel",
2633
+ className: classNames?.input,
2634
+ value: phone,
2635
+ onChange: (e) => setPhone(e.target.value),
2636
+ placeholder: "+1234567890",
2637
+ required: true,
2638
+ disabled: isSubmitting
2639
+ }
2640
+ )
2641
+ ] }),
2642
+ asDialog && /* @__PURE__ */ jsxs11(DialogFooter, { className: "gap-2 sm:gap-0", children: [
2643
+ /* @__PURE__ */ jsx20(
2644
+ Button,
2645
+ {
2646
+ type: "button",
2647
+ variant: "outline",
2648
+ className: classNames?.cancelButton,
2649
+ onClick: () => setSignerType(null),
2650
+ disabled: isSubmitting,
2651
+ children: "Back"
2652
+ }
2653
+ ),
2654
+ /* @__PURE__ */ jsx20(Button, { type: "submit", className: classNames?.submitButton, disabled: isSubmitting, children: isSubmitting ? "Adding..." : "Add signer" })
2655
+ ] }),
2656
+ !asDialog && /* @__PURE__ */ jsxs11("div", { className: "flex gap-2", children: [
2657
+ /* @__PURE__ */ jsx20(
2658
+ Button,
2659
+ {
2660
+ type: "button",
2661
+ variant: "outline",
2662
+ className: classNames?.cancelButton,
2663
+ onClick: () => setSignerType(null),
2664
+ disabled: isSubmitting,
2665
+ children: "Back"
2666
+ }
2667
+ ),
2668
+ /* @__PURE__ */ jsx20(Button, { type: "submit", className: classNames?.submitButton, disabled: isSubmitting, children: isSubmitting ? "Adding..." : "Add signer" })
2669
+ ] })
2670
+ ] }) : signerType === "external" ? /* @__PURE__ */ jsxs11(Fragment6, { children: [
2671
+ /* @__PURE__ */ jsxs11("div", { className: "space-y-2", children: [
2672
+ /* @__PURE__ */ jsx20(Label, { htmlFor: "add-signer-address", className: classNames?.label, children: "Wallet address" }),
2673
+ /* @__PURE__ */ jsx20(
2674
+ Input,
2675
+ {
2676
+ id: "add-signer-address",
2677
+ type: "text",
2678
+ className: classNames?.input,
2679
+ value: address,
2680
+ onChange: (e) => setAddress(e.target.value),
2681
+ placeholder: "Solana address",
2682
+ required: true,
2683
+ disabled: isSubmitting
2684
+ }
2685
+ )
2686
+ ] }),
2687
+ asDialog && /* @__PURE__ */ jsxs11(DialogFooter, { className: "gap-2 sm:gap-0", children: [
2688
+ /* @__PURE__ */ jsx20(
2689
+ Button,
2690
+ {
2691
+ type: "button",
2692
+ variant: "outline",
2693
+ className: classNames?.cancelButton,
2694
+ onClick: () => setSignerType(null),
2695
+ disabled: isSubmitting,
2696
+ children: "Back"
2697
+ }
2698
+ ),
2699
+ /* @__PURE__ */ jsx20(Button, { type: "submit", className: classNames?.submitButton, disabled: isSubmitting, children: isSubmitting ? "Adding..." : "Add signer" })
2700
+ ] }),
2701
+ !asDialog && /* @__PURE__ */ jsxs11("div", { className: "flex gap-2", children: [
2702
+ /* @__PURE__ */ jsx20(
2703
+ Button,
2704
+ {
2705
+ type: "button",
2706
+ variant: "outline",
2707
+ className: classNames?.cancelButton,
2708
+ onClick: () => setSignerType(null),
2709
+ disabled: isSubmitting,
2710
+ children: "Back"
2711
+ }
2712
+ ),
2713
+ /* @__PURE__ */ jsx20(Button, { type: "submit", className: classNames?.submitButton, disabled: isSubmitting, children: isSubmitting ? "Adding..." : "Add signer" })
2714
+ ] })
2715
+ ] }) : null,
2716
+ error && /* @__PURE__ */ jsx20("p", { className: cn("text-sm text-destructive", classNames?.error), role: "alert", children: error })
2717
+ ] });
2718
+ if (asDialog) {
2719
+ return /* @__PURE__ */ jsx20(Dialog, { open, onOpenChange: handleClose, children: /* @__PURE__ */ jsxs11(DialogContent, { className: cn(classNames?.dialog), children: [
2720
+ /* @__PURE__ */ jsxs11(DialogHeader, { children: [
2721
+ /* @__PURE__ */ jsx20(DialogTitle, { children: "Add signer" }),
2722
+ /* @__PURE__ */ jsx20(DialogDescription, { children: "Add a new signer to this wallet." })
2723
+ ] }),
2724
+ formContent
2725
+ ] }) });
2726
+ }
2727
+ return /* @__PURE__ */ jsxs11("div", { className: cn(className, classNames?.root), "data-cilantro-add-signer-form": true, children: [
2728
+ /* @__PURE__ */ jsx20("h3", { className: "text-sm font-medium mb-2", children: "Add signer" }),
2729
+ formContent
2730
+ ] });
2731
+ }
2732
+
2733
+ // src/components/SignerList.tsx
2734
+ import { useState as useState12 } from "react";
2735
+ import { Fragment as Fragment7, jsx as jsx21, jsxs as jsxs12 } from "react/jsx-runtime";
2736
+ function SignerList({
2737
+ walletId,
2738
+ className,
2739
+ classNames,
2740
+ onSignerAdded,
2741
+ children
2742
+ }) {
2743
+ const { signers, isLoading, error, refresh } = useSigners({ walletId });
2744
+ const [addSignerOpen, setAddSignerOpen] = useState12(false);
2745
+ const handleAddSuccess = () => {
2746
+ refresh();
2747
+ onSignerAdded?.();
2748
+ };
2749
+ if (children) {
2750
+ return /* @__PURE__ */ jsxs12(Fragment7, { children: [
2751
+ children({
2752
+ signers,
2753
+ isLoading,
2754
+ error,
2755
+ refresh,
2756
+ openAddSigner: () => setAddSignerOpen(true)
2757
+ }),
2758
+ /* @__PURE__ */ jsx21(
2759
+ AddSignerForm,
2760
+ {
2761
+ walletId,
2762
+ open: addSignerOpen,
2763
+ onOpenChange: setAddSignerOpen,
2764
+ onSuccess: handleAddSuccess,
2765
+ asDialog: true
2766
+ }
2767
+ )
2768
+ ] });
2769
+ }
2770
+ if (!walletId) {
2771
+ return /* @__PURE__ */ jsx21("div", { className: cn(className, classNames?.root), "data-cilantro-signer-list": true, children: /* @__PURE__ */ jsx21("p", { className: cn("text-sm text-muted-foreground", classNames?.message), children: "Select a wallet first." }) });
2772
+ }
2773
+ return /* @__PURE__ */ jsxs12("div", { className: cn(className, classNames?.root), "data-cilantro-signer-list": true, children: [
2774
+ /* @__PURE__ */ jsxs12("div", { className: cn("flex items-center justify-between gap-2 mb-2", classNames?.header), children: [
2775
+ /* @__PURE__ */ jsx21("span", { className: "text-sm font-medium", children: "Signers" }),
2776
+ /* @__PURE__ */ jsx21(
2777
+ Button,
2778
+ {
2779
+ type: "button",
2780
+ size: "sm",
2781
+ variant: "outline",
2782
+ className: classNames?.addButton,
2783
+ onClick: () => setAddSignerOpen(true),
2784
+ disabled: isLoading,
2785
+ children: "Add signer"
2786
+ }
2787
+ )
2788
+ ] }),
2789
+ isLoading ? /* @__PURE__ */ jsx21("p", { className: cn("text-sm text-muted-foreground", classNames?.message), children: "Loading signers..." }) : error ? /* @__PURE__ */ jsx21("p", { className: cn("text-sm text-destructive", classNames?.message), role: "alert", children: error }) : signers.length === 0 ? /* @__PURE__ */ jsx21("p", { className: cn("text-sm text-muted-foreground", classNames?.message), children: "No signers. Add one to get started." }) : /* @__PURE__ */ jsx21("ul", { className: cn("space-y-1", classNames?.list), role: "list", children: signers.map((signer) => /* @__PURE__ */ jsxs12("li", { className: cn("text-sm", classNames?.item), children: [
2790
+ getSignerDisplayName(signer),
2791
+ " (",
2792
+ getSignerTypeLabel(signer.type || signer.signerType || ""),
2793
+ ")"
2794
+ ] }, signer.id)) }),
2795
+ /* @__PURE__ */ jsx21(
2796
+ AddSignerForm,
2797
+ {
2798
+ walletId,
2799
+ open: addSignerOpen,
2800
+ onOpenChange: setAddSignerOpen,
2801
+ onSuccess: handleAddSuccess,
2802
+ asDialog: true
2803
+ }
2804
+ )
2805
+ ] });
2806
+ }
2807
+ export {
2808
+ AddSignerForm,
2809
+ AuthForm,
2810
+ AuthGuard,
2811
+ CilantroAuthProvider,
2812
+ CilantroProvider,
2813
+ DelegatedKeySelector,
2814
+ LoginForm,
2815
+ MessageSigningForm,
2816
+ RegisterForm,
2817
+ SIGNER_TYPES,
2818
+ SignerList,
2819
+ SignerSelector,
2820
+ TransactionSigningForm,
2821
+ WalletProvider,
2822
+ WalletSelector,
2823
+ extractErrorMessage,
2824
+ extractResponseData,
2825
+ getSignerPublicKey,
2826
+ getWalletData,
2827
+ signAndSendTransactionWithSigner,
2828
+ signMessageWithSigner,
2829
+ signTransactionWithSigner,
2830
+ useCilantroAuth,
2831
+ useMessageSigning,
2832
+ useSignerSelection,
2833
+ useSigners,
2834
+ useTransactionSigning,
2835
+ useWallets
2836
+ };
2837
+ //# sourceMappingURL=index.mjs.map