@pinklemon8/better-auth-siws 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/link.js ADDED
@@ -0,0 +1,148 @@
1
+ import {
2
+ createSignInInput,
3
+ generateNonce,
4
+ verifySIWS
5
+ } from "./chunk-Q7TSFSYW.js";
6
+
7
+ // src/link.ts
8
+ import { createAuthEndpoint, APIError } from "better-auth/api";
9
+ import { getSessionFromCtx } from "better-auth/api";
10
+ import { z } from "zod";
11
+ var siwsLink = (_options) => ({
12
+ id: "siws-link",
13
+ endpoints: {
14
+ linkSolanaWallet: createAuthEndpoint(
15
+ "/siws/link",
16
+ {
17
+ method: "POST",
18
+ body: z.object({
19
+ input: z.object({
20
+ domain: z.string(),
21
+ statement: z.string().optional(),
22
+ version: z.string().optional(),
23
+ nonce: z.string().optional(),
24
+ chainId: z.string().optional(),
25
+ issuedAt: z.string().optional()
26
+ }),
27
+ output: z.object({
28
+ account: z.object({
29
+ address: z.string(),
30
+ publicKey: z.array(z.number())
31
+ }),
32
+ signature: z.array(z.number()),
33
+ signedMessage: z.array(z.number())
34
+ })
35
+ }),
36
+ requireRequest: true
37
+ },
38
+ async (ctx) => {
39
+ const session = await getSessionFromCtx(ctx);
40
+ if (!session?.user) {
41
+ throw new APIError("UNAUTHORIZED", { message: "Not authenticated" });
42
+ }
43
+ const { input, output } = ctx.body;
44
+ const walletAddress = output.account.address;
45
+ const isValid = verifySIWS(input, output);
46
+ if (!isValid) {
47
+ throw new APIError("BAD_REQUEST", {
48
+ message: "Invalid signature"
49
+ });
50
+ }
51
+ const existing = await ctx.context.adapter.findOne({
52
+ model: "account",
53
+ where: [
54
+ { field: "providerId", operator: "eq", value: "solana" },
55
+ { field: "accountId", operator: "eq", value: walletAddress }
56
+ ]
57
+ });
58
+ if (existing) {
59
+ if (existing.userId === session.user.id) {
60
+ throw new APIError("BAD_REQUEST", {
61
+ message: "This wallet is already linked to your account"
62
+ });
63
+ }
64
+ throw new APIError("BAD_REQUEST", {
65
+ message: "This wallet is already linked to another account"
66
+ });
67
+ }
68
+ await ctx.context.internalAdapter.createAccount({
69
+ userId: session.user.id,
70
+ providerId: "solana",
71
+ accountId: walletAddress,
72
+ createdAt: /* @__PURE__ */ new Date(),
73
+ updatedAt: /* @__PURE__ */ new Date()
74
+ });
75
+ return ctx.json({ success: true, walletAddress });
76
+ }
77
+ ),
78
+ unlinkSolanaWallet: createAuthEndpoint(
79
+ "/siws/unlink",
80
+ {
81
+ method: "POST",
82
+ body: z.object({
83
+ walletAddress: z.string().min(32).max(44)
84
+ }),
85
+ requireRequest: true
86
+ },
87
+ async (ctx) => {
88
+ const session = await getSessionFromCtx(ctx);
89
+ if (!session?.user) {
90
+ throw new APIError("UNAUTHORIZED", { message: "Not authenticated" });
91
+ }
92
+ const { walletAddress } = ctx.body;
93
+ const account = await ctx.context.adapter.findOne({
94
+ model: "account",
95
+ where: [
96
+ { field: "providerId", operator: "eq", value: "solana" },
97
+ { field: "accountId", operator: "eq", value: walletAddress },
98
+ { field: "userId", operator: "eq", value: session.user.id }
99
+ ]
100
+ });
101
+ if (!account) {
102
+ throw new APIError("NOT_FOUND", {
103
+ message: "Wallet not found on your account"
104
+ });
105
+ }
106
+ await ctx.context.adapter.delete({
107
+ model: "account",
108
+ where: [
109
+ { field: "id", operator: "eq", value: account.id }
110
+ ]
111
+ });
112
+ return ctx.json({ success: true });
113
+ }
114
+ ),
115
+ getLinkedSolanaWallets: createAuthEndpoint(
116
+ "/siws/wallets",
117
+ {
118
+ method: "GET",
119
+ requireRequest: true
120
+ },
121
+ async (ctx) => {
122
+ const session = await getSessionFromCtx(ctx);
123
+ if (!session?.user) {
124
+ throw new APIError("UNAUTHORIZED", { message: "Not authenticated" });
125
+ }
126
+ const accounts = await ctx.context.adapter.findMany({
127
+ model: "account",
128
+ where: [
129
+ { field: "providerId", operator: "eq", value: "solana" },
130
+ { field: "userId", operator: "eq", value: session.user.id }
131
+ ]
132
+ });
133
+ const wallets = accounts.map((a) => ({
134
+ walletAddress: a.accountId,
135
+ createdAt: a.createdAt
136
+ }));
137
+ return ctx.json({ wallets });
138
+ }
139
+ )
140
+ }
141
+ });
142
+ export {
143
+ createSignInInput,
144
+ generateNonce,
145
+ siwsLink,
146
+ verifySIWS
147
+ };
148
+ //# sourceMappingURL=link.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/link.ts"],"sourcesContent":["import { createAuthEndpoint, APIError } from \"better-auth/api\";\nimport { getSessionFromCtx } from \"better-auth/api\";\nimport { z } from \"zod\";\nimport { verifySIWS } from \"./crypto\";\nimport type { SiwsPluginOptions } from \"./types\";\n\nexport { verifySIWS } from \"./crypto\";\nexport { generateNonce, createSignInInput } from \"./crypto\";\nexport type { SiwsLinkedWallet, SiwsLinkRequest } from \"./types\";\n\nexport const siwsLink = (_options?: Pick<SiwsPluginOptions, \"chainId\">) => ({\n id: \"siws-link\" as const,\n endpoints: {\n linkSolanaWallet: createAuthEndpoint(\n \"/siws/link\",\n {\n method: \"POST\",\n body: z.object({\n input: z.object({\n domain: z.string(),\n statement: z.string().optional(),\n version: z.string().optional(),\n nonce: z.string().optional(),\n chainId: z.string().optional(),\n issuedAt: z.string().optional(),\n }),\n output: z.object({\n account: z.object({\n address: z.string(),\n publicKey: z.array(z.number()),\n }),\n signature: z.array(z.number()),\n signedMessage: z.array(z.number()),\n }),\n }),\n requireRequest: true,\n },\n async (ctx: any) => {\n const session = await getSessionFromCtx(ctx);\n if (!session?.user) {\n throw new APIError(\"UNAUTHORIZED\", { message: \"Not authenticated\" });\n }\n\n const { input, output } = ctx.body;\n const walletAddress = output.account.address;\n\n const isValid = verifySIWS(input, output);\n if (!isValid) {\n throw new APIError(\"BAD_REQUEST\", {\n message: \"Invalid signature\",\n });\n }\n\n const existing = await ctx.context.adapter.findOne({\n model: \"account\",\n where: [\n { field: \"providerId\", operator: \"eq\", value: \"solana\" },\n { field: \"accountId\", operator: \"eq\", value: walletAddress },\n ],\n });\n\n if (existing) {\n if ((existing as any).userId === session.user.id) {\n throw new APIError(\"BAD_REQUEST\", {\n message: \"This wallet is already linked to your account\",\n });\n }\n throw new APIError(\"BAD_REQUEST\", {\n message: \"This wallet is already linked to another account\",\n });\n }\n\n await ctx.context.internalAdapter.createAccount({\n userId: session.user.id,\n providerId: \"solana\",\n accountId: walletAddress,\n createdAt: new Date(),\n updatedAt: new Date(),\n });\n\n return ctx.json({ success: true, walletAddress });\n }\n ),\n\n unlinkSolanaWallet: createAuthEndpoint(\n \"/siws/unlink\",\n {\n method: \"POST\",\n body: z.object({\n walletAddress: z.string().min(32).max(44),\n }),\n requireRequest: true,\n },\n async (ctx: any) => {\n const session = await getSessionFromCtx(ctx);\n if (!session?.user) {\n throw new APIError(\"UNAUTHORIZED\", { message: \"Not authenticated\" });\n }\n\n const { walletAddress } = ctx.body;\n\n const account = await ctx.context.adapter.findOne({\n model: \"account\",\n where: [\n { field: \"providerId\", operator: \"eq\", value: \"solana\" },\n { field: \"accountId\", operator: \"eq\", value: walletAddress },\n { field: \"userId\", operator: \"eq\", value: session.user.id },\n ],\n });\n\n if (!account) {\n throw new APIError(\"NOT_FOUND\", {\n message: \"Wallet not found on your account\",\n });\n }\n\n await ctx.context.adapter.delete({\n model: \"account\",\n where: [\n { field: \"id\", operator: \"eq\", value: (account as any).id },\n ],\n });\n\n return ctx.json({ success: true });\n }\n ),\n\n getLinkedSolanaWallets: createAuthEndpoint(\n \"/siws/wallets\",\n {\n method: \"GET\",\n requireRequest: true,\n },\n async (ctx: any) => {\n const session = await getSessionFromCtx(ctx);\n if (!session?.user) {\n throw new APIError(\"UNAUTHORIZED\", { message: \"Not authenticated\" });\n }\n\n const accounts = await ctx.context.adapter.findMany({\n model: \"account\",\n where: [\n { field: \"providerId\", operator: \"eq\", value: \"solana\" },\n { field: \"userId\", operator: \"eq\", value: session.user.id },\n ],\n });\n\n const wallets = (accounts as any[]).map((a) => ({\n walletAddress: a.accountId,\n createdAt: a.createdAt,\n }));\n\n return ctx.json({ wallets });\n }\n ),\n },\n});\n"],"mappings":"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","names":[]}
@@ -0,0 +1,361 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/react/index.ts
21
+ var react_exports = {};
22
+ __export(react_exports, {
23
+ SolanaLinkWallet: () => SolanaLinkWallet,
24
+ SolanaProvider: () => SolanaProvider,
25
+ SolanaSignInButton: () => SolanaSignInButton
26
+ });
27
+ module.exports = __toCommonJS(react_exports);
28
+
29
+ // src/react/provider.tsx
30
+ var import_react = require("react");
31
+ var import_wallet_adapter_react = require("@solana/wallet-adapter-react");
32
+ var import_wallet_adapter_react_ui = require("@solana/wallet-adapter-react-ui");
33
+ var import_web3 = require("@solana/web3.js");
34
+ var import_styles = require("@solana/wallet-adapter-react-ui/styles.css");
35
+ var import_jsx_runtime = require("react/jsx-runtime");
36
+ var SolanaProvider = ({
37
+ children,
38
+ cluster = "mainnet-beta",
39
+ endpoint,
40
+ autoConnect = false
41
+ }) => {
42
+ const rpcEndpoint = (0, import_react.useMemo)(
43
+ () => endpoint ?? (0, import_web3.clusterApiUrl)(cluster),
44
+ [endpoint, cluster]
45
+ );
46
+ const wallets = (0, import_react.useMemo)(() => [], []);
47
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_wallet_adapter_react.ConnectionProvider, { endpoint: rpcEndpoint, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_wallet_adapter_react.WalletProvider, { wallets, autoConnect, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_wallet_adapter_react_ui.WalletModalProvider, { children }) }) });
48
+ };
49
+
50
+ // src/react/sign-in.tsx
51
+ var import_react2 = require("react");
52
+ var import_wallet_adapter_react2 = require("@solana/wallet-adapter-react");
53
+ var import_wallet_adapter_react_ui2 = require("@solana/wallet-adapter-react-ui");
54
+
55
+ // src/types.ts
56
+ function serializeOutput(output) {
57
+ return {
58
+ account: {
59
+ address: output.account.address,
60
+ publicKey: Array.from(output.account.publicKey)
61
+ },
62
+ signature: Array.from(output.signature),
63
+ signedMessage: Array.from(output.signedMessage),
64
+ signatureType: output.signatureType
65
+ };
66
+ }
67
+
68
+ // src/react/sign-in.tsx
69
+ var import_jsx_runtime2 = require("react/jsx-runtime");
70
+ function SolanaSignInInner({
71
+ baseURL = "",
72
+ onSuccess,
73
+ onError,
74
+ className,
75
+ children
76
+ }) {
77
+ const { publicKey, connected, disconnect, wallet, connecting, connect } = (0, import_wallet_adapter_react2.useWallet)();
78
+ const { setVisible, visible } = (0, import_wallet_adapter_react_ui2.useWalletModal)();
79
+ const [loading, setLoading] = (0, import_react2.useState)(false);
80
+ const [signingIn, setSigningIn] = (0, import_react2.useState)(false);
81
+ const [hasTriggered, setHasTriggered] = (0, import_react2.useState)(false);
82
+ (0, import_react2.useEffect)(() => {
83
+ if (connected && publicKey && signingIn && !hasTriggered) {
84
+ setHasTriggered(true);
85
+ setVisible(false);
86
+ handleSignIn();
87
+ }
88
+ }, [connected, publicKey, signingIn, wallet, hasTriggered]);
89
+ (0, import_react2.useEffect)(() => {
90
+ if (wallet && !connected && !connecting && signingIn) {
91
+ connect().catch(console.error);
92
+ }
93
+ }, [wallet, connected, connecting, signingIn, connect]);
94
+ (0, import_react2.useEffect)(() => {
95
+ if (!visible && signingIn && !connected && !connecting && !wallet) {
96
+ setSigningIn(false);
97
+ setHasTriggered(false);
98
+ }
99
+ }, [visible, signingIn, connected, connecting, wallet]);
100
+ const handleClick = async () => {
101
+ setSigningIn(true);
102
+ if (wallet && !connected) {
103
+ try {
104
+ await connect();
105
+ } catch {
106
+ setVisible(true);
107
+ }
108
+ } else if (!wallet) {
109
+ setVisible(true);
110
+ }
111
+ };
112
+ const handleSignIn = async () => {
113
+ if (!publicKey || !wallet?.adapter) {
114
+ setSigningIn(false);
115
+ return;
116
+ }
117
+ const adapter = wallet.adapter;
118
+ if (!("signIn" in adapter) || typeof adapter.signIn !== "function") {
119
+ onError?.(
120
+ "Your wallet does not support Sign In With Solana. Please use Phantom v23.11.0 or later."
121
+ );
122
+ setSigningIn(false);
123
+ disconnect();
124
+ return;
125
+ }
126
+ setLoading(true);
127
+ try {
128
+ const nonceRes = await fetch(`${baseURL}/api/auth/siws/nonce`, {
129
+ method: "POST",
130
+ headers: { "Content-Type": "application/json" },
131
+ body: JSON.stringify({ walletAddress: publicKey.toBase58() })
132
+ });
133
+ const nonceData = await nonceRes.json();
134
+ const input = {
135
+ domain: nonceData.domain,
136
+ statement: nonceData.statement,
137
+ uri: nonceData.uri,
138
+ nonce: nonceData.nonce,
139
+ chainId: nonceData.chainId,
140
+ issuedAt: nonceData.issuedAt
141
+ };
142
+ const output = await adapter.signIn(input);
143
+ const serialized = serializeOutput(output);
144
+ const verifyRes = await fetch(`${baseURL}/api/auth/siws/verify`, {
145
+ method: "POST",
146
+ headers: { "Content-Type": "application/json" },
147
+ body: JSON.stringify({ input, output: serialized })
148
+ });
149
+ const data = await verifyRes.json();
150
+ if (!verifyRes.ok) {
151
+ onError?.(data.message || data.error || "Failed to sign in with Solana");
152
+ } else {
153
+ onSuccess?.(data.user);
154
+ }
155
+ } catch (error) {
156
+ if (error?.message !== "User rejected the request.") {
157
+ onError?.(error?.message || "Failed to sign in with Solana wallet");
158
+ }
159
+ } finally {
160
+ setLoading(false);
161
+ setSigningIn(false);
162
+ setHasTriggered(false);
163
+ disconnect();
164
+ }
165
+ };
166
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
167
+ "button",
168
+ {
169
+ onClick: handleClick,
170
+ disabled: loading,
171
+ className,
172
+ type: "button",
173
+ children: children ?? (loading ? "Authenticating..." : "Sign In with Solana")
174
+ }
175
+ );
176
+ }
177
+ var SolanaSignInButton = ({
178
+ cluster,
179
+ endpoint,
180
+ ...props
181
+ }) => {
182
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(SolanaProvider, { cluster, endpoint, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(SolanaSignInInner, { ...props }) });
183
+ };
184
+
185
+ // src/react/link-wallet.tsx
186
+ var import_react3 = require("react");
187
+ var import_wallet_adapter_react3 = require("@solana/wallet-adapter-react");
188
+ var import_wallet_adapter_react_ui3 = require("@solana/wallet-adapter-react-ui");
189
+ var import_jsx_runtime3 = require("react/jsx-runtime");
190
+ function LinkWalletInner({
191
+ baseURL = "",
192
+ onLink,
193
+ onUnlink,
194
+ onError,
195
+ className,
196
+ unlinkClassName,
197
+ renderLinked,
198
+ children
199
+ }) {
200
+ const { publicKey, connected, disconnect, wallet, connecting, connect } = (0, import_wallet_adapter_react3.useWallet)();
201
+ const { setVisible, visible } = (0, import_wallet_adapter_react_ui3.useWalletModal)();
202
+ const [linkedWallet, setLinkedWallet] = (0, import_react3.useState)(null);
203
+ const [loading, setLoading] = (0, import_react3.useState)(true);
204
+ const [linking, setLinking] = (0, import_react3.useState)(false);
205
+ const [hasTriggered, setHasTriggered] = (0, import_react3.useState)(false);
206
+ const fetchWallets = async () => {
207
+ try {
208
+ const res = await fetch(`${baseURL}/api/auth/siws/wallets`);
209
+ const data = await res.json();
210
+ if (data.wallets?.[0]) {
211
+ setLinkedWallet(data.wallets[0].walletAddress);
212
+ }
213
+ } catch {
214
+ }
215
+ setLoading(false);
216
+ };
217
+ (0, import_react3.useEffect)(() => {
218
+ fetchWallets();
219
+ }, []);
220
+ (0, import_react3.useEffect)(() => {
221
+ if (connected && publicKey && linking && !hasTriggered) {
222
+ setHasTriggered(true);
223
+ setVisible(false);
224
+ handleLink();
225
+ }
226
+ }, [connected, publicKey, linking, wallet, hasTriggered]);
227
+ (0, import_react3.useEffect)(() => {
228
+ if (wallet && !connected && !connecting && linking) {
229
+ connect().catch(console.error);
230
+ }
231
+ }, [wallet, connected, connecting, linking, connect]);
232
+ (0, import_react3.useEffect)(() => {
233
+ if (!visible && linking && !connected && !connecting && !wallet) {
234
+ setLinking(false);
235
+ setHasTriggered(false);
236
+ }
237
+ }, [visible, linking, connected, connecting, wallet]);
238
+ const handleLinkClick = async () => {
239
+ setLinking(true);
240
+ if (wallet && !connected) {
241
+ try {
242
+ await connect();
243
+ } catch {
244
+ setVisible(true);
245
+ }
246
+ } else if (!wallet) {
247
+ setVisible(true);
248
+ }
249
+ };
250
+ const handleLink = async () => {
251
+ if (!wallet?.adapter) return;
252
+ const adapter = wallet.adapter;
253
+ if (!("signIn" in adapter)) {
254
+ onError?.("Wallet doesn't support SIWS");
255
+ setLinking(false);
256
+ disconnect();
257
+ return;
258
+ }
259
+ try {
260
+ const createRes = await fetch(`${baseURL}/api/auth/siws/nonce`, {
261
+ method: "POST",
262
+ headers: { "Content-Type": "application/json" },
263
+ body: JSON.stringify({
264
+ walletAddress: publicKey.toBase58()
265
+ })
266
+ });
267
+ const nonceData = await createRes.json();
268
+ const input = {
269
+ domain: nonceData.domain,
270
+ statement: nonceData.statement,
271
+ uri: nonceData.uri,
272
+ nonce: nonceData.nonce,
273
+ chainId: nonceData.chainId,
274
+ issuedAt: nonceData.issuedAt
275
+ };
276
+ const output = await adapter.signIn(input);
277
+ const serializedOutput = {
278
+ account: {
279
+ address: output.account.address,
280
+ publicKey: Array.from(output.account.publicKey)
281
+ },
282
+ signature: Array.from(output.signature),
283
+ signedMessage: Array.from(output.signedMessage)
284
+ };
285
+ const linkRes = await fetch(`${baseURL}/api/auth/siws/link`, {
286
+ method: "POST",
287
+ headers: { "Content-Type": "application/json" },
288
+ body: JSON.stringify({ input, output: serializedOutput })
289
+ });
290
+ if (linkRes.ok) {
291
+ const data = await linkRes.json();
292
+ setLinkedWallet(data.walletAddress);
293
+ onLink?.(data.walletAddress);
294
+ } else {
295
+ const err = await linkRes.json();
296
+ onError?.(err.message || "Failed to link wallet");
297
+ }
298
+ } catch (e) {
299
+ if (!e?.message?.includes("rejected")) {
300
+ onError?.("Failed to link wallet");
301
+ }
302
+ } finally {
303
+ setLinking(false);
304
+ setHasTriggered(false);
305
+ disconnect();
306
+ }
307
+ };
308
+ const handleUnlink = async () => {
309
+ if (!linkedWallet) return;
310
+ try {
311
+ const res = await fetch(`${baseURL}/api/auth/siws/unlink`, {
312
+ method: "POST",
313
+ headers: { "Content-Type": "application/json" },
314
+ body: JSON.stringify({ walletAddress: linkedWallet })
315
+ });
316
+ if (res.ok) {
317
+ setLinkedWallet(null);
318
+ onUnlink?.();
319
+ }
320
+ } catch {
321
+ onError?.("Failed to unlink wallet");
322
+ }
323
+ };
324
+ if (loading) {
325
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { disabled: true, className, children: "Loading..." });
326
+ }
327
+ if (linkedWallet) {
328
+ if (renderLinked) {
329
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_jsx_runtime3.Fragment, { children: renderLinked({ address: linkedWallet, onUnlink: handleUnlink }) });
330
+ }
331
+ const truncated = `${linkedWallet.slice(0, 4)}...${linkedWallet.slice(-4)}`;
332
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: "0.5rem" }, children: [
333
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { style: { fontFamily: "monospace", fontSize: "0.875rem" }, children: truncated }),
334
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { onClick: handleUnlink, className: unlinkClassName, type: "button", children: "Unlink" })
335
+ ] });
336
+ }
337
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
338
+ "button",
339
+ {
340
+ onClick: handleLinkClick,
341
+ disabled: linking,
342
+ className,
343
+ type: "button",
344
+ children: children ?? (linking ? "Linking..." : "Link Solana Wallet")
345
+ }
346
+ );
347
+ }
348
+ var SolanaLinkWallet = ({
349
+ cluster,
350
+ endpoint,
351
+ ...props
352
+ }) => {
353
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(SolanaProvider, { cluster, endpoint, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(LinkWalletInner, { ...props }) });
354
+ };
355
+ // Annotate the CommonJS export names for ESM import in node:
356
+ 0 && (module.exports = {
357
+ SolanaLinkWallet,
358
+ SolanaProvider,
359
+ SolanaSignInButton
360
+ });
361
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/react/index.ts","../../src/react/provider.tsx","../../src/react/sign-in.tsx","../../src/types.ts","../../src/react/link-wallet.tsx"],"sourcesContent":["export { SolanaProvider } from \"./provider\";\nexport type { SolanaProviderProps } from \"./provider\";\n\nexport { SolanaSignInButton } from \"./sign-in\";\nexport type { SolanaSignInButtonProps } from \"./sign-in\";\n\nexport { SolanaLinkWallet } from \"./link-wallet\";\nexport type { SolanaLinkWalletProps } from \"./link-wallet\";\n","\"use client\";\n\nimport { type FC, type ReactNode, useMemo } from \"react\";\nimport {\n ConnectionProvider,\n WalletProvider,\n} from \"@solana/wallet-adapter-react\";\nimport { WalletModalProvider } from \"@solana/wallet-adapter-react-ui\";\nimport { clusterApiUrl } from \"@solana/web3.js\";\n\nimport \"@solana/wallet-adapter-react-ui/styles.css\";\n\nexport type SolanaProviderProps = {\n children: ReactNode;\n cluster?: \"mainnet-beta\" | \"devnet\" | \"testnet\";\n endpoint?: string;\n autoConnect?: boolean;\n};\n\nexport const SolanaProvider: FC<SolanaProviderProps> = ({\n children,\n cluster = \"mainnet-beta\",\n endpoint,\n autoConnect = false,\n}) => {\n const rpcEndpoint = useMemo(\n () => endpoint ?? clusterApiUrl(cluster),\n [endpoint, cluster]\n );\n const wallets = useMemo(() => [], []);\n\n return (\n <ConnectionProvider endpoint={rpcEndpoint}>\n <WalletProvider wallets={wallets} autoConnect={autoConnect}>\n <WalletModalProvider>{children}</WalletModalProvider>\n </WalletProvider>\n </ConnectionProvider>\n );\n};\n","\"use client\";\n\nimport { useEffect, useState, type FC } from \"react\";\nimport { useWallet } from \"@solana/wallet-adapter-react\";\nimport { useWalletModal } from \"@solana/wallet-adapter-react-ui\";\nimport type { SolanaSignInInput } from \"@solana/wallet-standard-features\";\nimport { serializeOutput } from \"../types\";\nimport { SolanaProvider, type SolanaProviderProps } from \"./provider\";\n\nexport type SolanaSignInButtonProps = {\n baseURL?: string;\n onSuccess?: (user: { id: string; name: string; email: string }) => void;\n onError?: (error: string) => void;\n className?: string;\n children?: React.ReactNode;\n cluster?: SolanaProviderProps[\"cluster\"];\n endpoint?: SolanaProviderProps[\"endpoint\"];\n};\n\nfunction SolanaSignInInner({\n baseURL = \"\",\n onSuccess,\n onError,\n className,\n children,\n}: Omit<SolanaSignInButtonProps, \"cluster\" | \"endpoint\">) {\n const { publicKey, connected, disconnect, wallet, connecting, connect } =\n useWallet();\n const { setVisible, visible } = useWalletModal();\n const [loading, setLoading] = useState(false);\n const [signingIn, setSigningIn] = useState(false);\n const [hasTriggered, setHasTriggered] = useState(false);\n\n useEffect(() => {\n if (connected && publicKey && signingIn && !hasTriggered) {\n setHasTriggered(true);\n setVisible(false);\n handleSignIn();\n }\n }, [connected, publicKey, signingIn, wallet, hasTriggered]);\n\n useEffect(() => {\n if (wallet && !connected && !connecting && signingIn) {\n connect().catch(console.error);\n }\n }, [wallet, connected, connecting, signingIn, connect]);\n\n useEffect(() => {\n if (!visible && signingIn && !connected && !connecting && !wallet) {\n setSigningIn(false);\n setHasTriggered(false);\n }\n }, [visible, signingIn, connected, connecting, wallet]);\n\n const handleClick = async () => {\n setSigningIn(true);\n if (wallet && !connected) {\n try {\n await connect();\n } catch {\n setVisible(true);\n }\n } else if (!wallet) {\n setVisible(true);\n }\n };\n\n const handleSignIn = async () => {\n if (!publicKey || !wallet?.adapter) {\n setSigningIn(false);\n return;\n }\n\n const adapter = wallet.adapter as any;\n if (!(\"signIn\" in adapter) || typeof adapter.signIn !== \"function\") {\n onError?.(\n \"Your wallet does not support Sign In With Solana. Please use Phantom v23.11.0 or later.\"\n );\n setSigningIn(false);\n disconnect();\n return;\n }\n\n setLoading(true);\n\n try {\n const nonceRes = await fetch(`${baseURL}/api/auth/siws/nonce`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ walletAddress: publicKey.toBase58() }),\n });\n const nonceData = await nonceRes.json();\n\n const input: SolanaSignInInput = {\n domain: nonceData.domain,\n statement: nonceData.statement,\n uri: nonceData.uri,\n nonce: nonceData.nonce,\n chainId: nonceData.chainId,\n issuedAt: nonceData.issuedAt,\n };\n\n const output = await adapter.signIn(input);\n const serialized = serializeOutput(output);\n\n const verifyRes = await fetch(`${baseURL}/api/auth/siws/verify`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ input, output: serialized }),\n });\n\n const data = await verifyRes.json();\n\n if (!verifyRes.ok) {\n onError?.(data.message || data.error || \"Failed to sign in with Solana\");\n } else {\n onSuccess?.(data.user);\n }\n } catch (error: any) {\n if (error?.message !== \"User rejected the request.\") {\n onError?.(error?.message || \"Failed to sign in with Solana wallet\");\n }\n } finally {\n setLoading(false);\n setSigningIn(false);\n setHasTriggered(false);\n disconnect();\n }\n };\n\n return (\n <button\n onClick={handleClick}\n disabled={loading}\n className={className}\n type=\"button\"\n >\n {children ?? (loading ? \"Authenticating...\" : \"Sign In with Solana\")}\n </button>\n );\n}\n\nexport const SolanaSignInButton: FC<SolanaSignInButtonProps> = ({\n cluster,\n endpoint,\n ...props\n}) => {\n return (\n <SolanaProvider cluster={cluster} endpoint={endpoint}>\n <SolanaSignInInner {...props} />\n </SolanaProvider>\n );\n};\n","import type { SolanaSignInInput, SolanaSignInOutput } from \"@solana/wallet-standard-features\";\n\nexport type { SolanaSignInInput, SolanaSignInOutput };\n\nexport interface SiwsPluginOptions {\n statement?: string;\n chainId?: string;\n nonceExpiryMs?: number;\n anonymous?: boolean;\n}\n\nexport interface SiwsNonceResponse {\n nonce: string;\n domain: string;\n uri: string;\n statement: string;\n chainId: string;\n issuedAt: string;\n}\n\nexport interface SiwsVerifyRequest {\n output: {\n account: {\n address: string;\n publicKey: number[];\n };\n signature: number[];\n signedMessage: number[];\n };\n input: {\n domain: string;\n address?: string;\n statement?: string;\n uri?: string;\n version?: string;\n chainId?: string;\n nonce?: string;\n issuedAt?: string;\n expirationTime?: string;\n notBefore?: string;\n requestId?: string;\n resources?: string[];\n };\n}\n\nexport interface SiwsVerifyResponse {\n success: boolean;\n user: {\n id: string;\n name: string;\n email: string;\n };\n}\n\nexport interface SiwsLinkRequest {\n input: SolanaSignInInput;\n output: {\n account: {\n address: string;\n publicKey: number[];\n };\n signature: number[];\n signedMessage: number[];\n };\n}\n\nexport interface SiwsLinkedWallet {\n walletAddress: string;\n createdAt: Date;\n}\n\nexport interface SerializedSolanaOutput {\n account: {\n address: string;\n publicKey: number[];\n };\n signature: number[];\n signedMessage: number[];\n signatureType?: string;\n}\n\nexport function serializeOutput(output: SolanaSignInOutput): SerializedSolanaOutput {\n return {\n account: {\n address: output.account.address,\n publicKey: Array.from(output.account.publicKey),\n },\n signature: Array.from(output.signature),\n signedMessage: Array.from(output.signedMessage),\n signatureType: (output as any).signatureType,\n };\n}\n\nexport function deserializeOutput(data: SerializedSolanaOutput): SolanaSignInOutput {\n return {\n account: {\n address: data.account.address,\n publicKey: new Uint8Array(data.account.publicKey),\n chains: [],\n features: [],\n },\n signature: new Uint8Array(data.signature),\n signedMessage: new Uint8Array(data.signedMessage),\n };\n}\n","\"use client\";\n\nimport { useEffect, useState, type FC } from \"react\";\nimport { useWallet } from \"@solana/wallet-adapter-react\";\nimport { useWalletModal } from \"@solana/wallet-adapter-react-ui\";\nimport type { SolanaSignInInput, SolanaSignInOutput } from \"@solana/wallet-standard-features\";\nimport { SolanaProvider, type SolanaProviderProps } from \"./provider\";\n\nexport type SolanaLinkWalletProps = {\n baseURL?: string;\n onLink?: (walletAddress: string) => void;\n onUnlink?: () => void;\n onError?: (error: string) => void;\n className?: string;\n unlinkClassName?: string;\n cluster?: SolanaProviderProps[\"cluster\"];\n endpoint?: SolanaProviderProps[\"endpoint\"];\n renderLinked?: (wallet: { address: string; onUnlink: () => void }) => React.ReactNode;\n children?: React.ReactNode;\n};\n\nfunction LinkWalletInner({\n baseURL = \"\",\n onLink,\n onUnlink,\n onError,\n className,\n unlinkClassName,\n renderLinked,\n children,\n}: Omit<SolanaLinkWalletProps, \"cluster\" | \"endpoint\">) {\n const { publicKey, connected, disconnect, wallet, connecting, connect } =\n useWallet();\n const { setVisible, visible } = useWalletModal();\n const [linkedWallet, setLinkedWallet] = useState<string | null>(null);\n const [loading, setLoading] = useState(true);\n const [linking, setLinking] = useState(false);\n const [hasTriggered, setHasTriggered] = useState(false);\n\n const fetchWallets = async () => {\n try {\n const res = await fetch(`${baseURL}/api/auth/siws/wallets`);\n const data = await res.json();\n if (data.wallets?.[0]) {\n setLinkedWallet(data.wallets[0].walletAddress);\n }\n } catch {}\n setLoading(false);\n };\n\n useEffect(() => {\n fetchWallets();\n }, []);\n\n useEffect(() => {\n if (connected && publicKey && linking && !hasTriggered) {\n setHasTriggered(true);\n setVisible(false);\n handleLink();\n }\n }, [connected, publicKey, linking, wallet, hasTriggered]);\n\n useEffect(() => {\n if (wallet && !connected && !connecting && linking) {\n connect().catch(console.error);\n }\n }, [wallet, connected, connecting, linking, connect]);\n\n useEffect(() => {\n if (!visible && linking && !connected && !connecting && !wallet) {\n setLinking(false);\n setHasTriggered(false);\n }\n }, [visible, linking, connected, connecting, wallet]);\n\n const handleLinkClick = async () => {\n setLinking(true);\n if (wallet && !connected) {\n try {\n await connect();\n } catch {\n setVisible(true);\n }\n } else if (!wallet) {\n setVisible(true);\n }\n };\n\n const handleLink = async () => {\n if (!wallet?.adapter) return;\n\n const adapter = wallet.adapter as any;\n if (!(\"signIn\" in adapter)) {\n onError?.(\"Wallet doesn't support SIWS\");\n setLinking(false);\n disconnect();\n return;\n }\n\n try {\n const createRes = await fetch(`${baseURL}/api/auth/siws/nonce`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n walletAddress: publicKey!.toBase58(),\n }),\n });\n const nonceData = await createRes.json();\n\n const input: SolanaSignInInput = {\n domain: nonceData.domain,\n statement: nonceData.statement,\n uri: nonceData.uri,\n nonce: nonceData.nonce,\n chainId: nonceData.chainId,\n issuedAt: nonceData.issuedAt,\n };\n\n const output: SolanaSignInOutput = await adapter.signIn(input);\n\n const serializedOutput = {\n account: {\n address: output.account.address,\n publicKey: Array.from(output.account.publicKey),\n },\n signature: Array.from(output.signature),\n signedMessage: Array.from(output.signedMessage),\n };\n\n const linkRes = await fetch(`${baseURL}/api/auth/siws/link`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ input, output: serializedOutput }),\n });\n\n if (linkRes.ok) {\n const data = await linkRes.json();\n setLinkedWallet(data.walletAddress);\n onLink?.(data.walletAddress);\n } else {\n const err = await linkRes.json();\n onError?.(err.message || \"Failed to link wallet\");\n }\n } catch (e: any) {\n if (!e?.message?.includes(\"rejected\")) {\n onError?.(\"Failed to link wallet\");\n }\n } finally {\n setLinking(false);\n setHasTriggered(false);\n disconnect();\n }\n };\n\n const handleUnlink = async () => {\n if (!linkedWallet) return;\n try {\n const res = await fetch(`${baseURL}/api/auth/siws/unlink`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ walletAddress: linkedWallet }),\n });\n if (res.ok) {\n setLinkedWallet(null);\n onUnlink?.();\n }\n } catch {\n onError?.(\"Failed to unlink wallet\");\n }\n };\n\n if (loading) {\n return (\n <button disabled className={className}>\n Loading...\n </button>\n );\n }\n\n if (linkedWallet) {\n if (renderLinked) {\n return <>{renderLinked({ address: linkedWallet, onUnlink: handleUnlink })}</>;\n }\n const truncated = `${linkedWallet.slice(0, 4)}...${linkedWallet.slice(-4)}`;\n return (\n <div style={{ display: \"flex\", alignItems: \"center\", gap: \"0.5rem\" }}>\n <span style={{ fontFamily: \"monospace\", fontSize: \"0.875rem\" }}>\n {truncated}\n </span>\n <button onClick={handleUnlink} className={unlinkClassName} type=\"button\">\n Unlink\n </button>\n </div>\n );\n }\n\n return (\n <button\n onClick={handleLinkClick}\n disabled={linking}\n className={className}\n type=\"button\"\n >\n {children ?? (linking ? \"Linking...\" : \"Link Solana Wallet\")}\n </button>\n );\n}\n\nexport const SolanaLinkWallet: FC<SolanaLinkWalletProps> = ({\n cluster,\n endpoint,\n ...props\n}) => {\n return (\n <SolanaProvider cluster={cluster} endpoint={endpoint}>\n <LinkWalletInner {...props} />\n </SolanaProvider>\n );\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACEA,mBAAiD;AACjD,kCAGO;AACP,qCAAoC;AACpC,kBAA8B;AAE9B,oBAAO;AAwBC;AAfD,IAAM,iBAA0C,CAAC;AAAA,EACtD;AAAA,EACA,UAAU;AAAA,EACV;AAAA,EACA,cAAc;AAChB,MAAM;AACJ,QAAM,kBAAc;AAAA,IAClB,MAAM,gBAAY,2BAAc,OAAO;AAAA,IACvC,CAAC,UAAU,OAAO;AAAA,EACpB;AACA,QAAM,cAAU,sBAAQ,MAAM,CAAC,GAAG,CAAC,CAAC;AAEpC,SACE,4CAAC,kDAAmB,UAAU,aAC5B,sDAAC,8CAAe,SAAkB,aAChC,sDAAC,sDAAqB,UAAS,GACjC,GACF;AAEJ;;;ACpCA,IAAAA,gBAA6C;AAC7C,IAAAC,+BAA0B;AAC1B,IAAAC,kCAA+B;;;AC6ExB,SAAS,gBAAgB,QAAoD;AAClF,SAAO;AAAA,IACL,SAAS;AAAA,MACP,SAAS,OAAO,QAAQ;AAAA,MACxB,WAAW,MAAM,KAAK,OAAO,QAAQ,SAAS;AAAA,IAChD;AAAA,IACA,WAAW,MAAM,KAAK,OAAO,SAAS;AAAA,IACtC,eAAe,MAAM,KAAK,OAAO,aAAa;AAAA,IAC9C,eAAgB,OAAe;AAAA,EACjC;AACF;;;ADwCI,IAAAC,sBAAA;AAhHJ,SAAS,kBAAkB;AAAA,EACzB,UAAU;AAAA,EACV;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAA0D;AACxD,QAAM,EAAE,WAAW,WAAW,YAAY,QAAQ,YAAY,QAAQ,QACpE,wCAAU;AACZ,QAAM,EAAE,YAAY,QAAQ,QAAI,gDAAe;AAC/C,QAAM,CAAC,SAAS,UAAU,QAAI,wBAAS,KAAK;AAC5C,QAAM,CAAC,WAAW,YAAY,QAAI,wBAAS,KAAK;AAChD,QAAM,CAAC,cAAc,eAAe,QAAI,wBAAS,KAAK;AAEtD,+BAAU,MAAM;AACd,QAAI,aAAa,aAAa,aAAa,CAAC,cAAc;AACxD,sBAAgB,IAAI;AACpB,iBAAW,KAAK;AAChB,mBAAa;AAAA,IACf;AAAA,EACF,GAAG,CAAC,WAAW,WAAW,WAAW,QAAQ,YAAY,CAAC;AAE1D,+BAAU,MAAM;AACd,QAAI,UAAU,CAAC,aAAa,CAAC,cAAc,WAAW;AACpD,cAAQ,EAAE,MAAM,QAAQ,KAAK;AAAA,IAC/B;AAAA,EACF,GAAG,CAAC,QAAQ,WAAW,YAAY,WAAW,OAAO,CAAC;AAEtD,+BAAU,MAAM;AACd,QAAI,CAAC,WAAW,aAAa,CAAC,aAAa,CAAC,cAAc,CAAC,QAAQ;AACjE,mBAAa,KAAK;AAClB,sBAAgB,KAAK;AAAA,IACvB;AAAA,EACF,GAAG,CAAC,SAAS,WAAW,WAAW,YAAY,MAAM,CAAC;AAEtD,QAAM,cAAc,YAAY;AAC9B,iBAAa,IAAI;AACjB,QAAI,UAAU,CAAC,WAAW;AACxB,UAAI;AACF,cAAM,QAAQ;AAAA,MAChB,QAAQ;AACN,mBAAW,IAAI;AAAA,MACjB;AAAA,IACF,WAAW,CAAC,QAAQ;AAClB,iBAAW,IAAI;AAAA,IACjB;AAAA,EACF;AAEA,QAAM,eAAe,YAAY;AAC/B,QAAI,CAAC,aAAa,CAAC,QAAQ,SAAS;AAClC,mBAAa,KAAK;AAClB;AAAA,IACF;AAEA,UAAM,UAAU,OAAO;AACvB,QAAI,EAAE,YAAY,YAAY,OAAO,QAAQ,WAAW,YAAY;AAClE;AAAA,QACE;AAAA,MACF;AACA,mBAAa,KAAK;AAClB,iBAAW;AACX;AAAA,IACF;AAEA,eAAW,IAAI;AAEf,QAAI;AACF,YAAM,WAAW,MAAM,MAAM,GAAG,OAAO,wBAAwB;AAAA,QAC7D,QAAQ;AAAA,QACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,QAC9C,MAAM,KAAK,UAAU,EAAE,eAAe,UAAU,SAAS,EAAE,CAAC;AAAA,MAC9D,CAAC;AACD,YAAM,YAAY,MAAM,SAAS,KAAK;AAEtC,YAAM,QAA2B;AAAA,QAC/B,QAAQ,UAAU;AAAA,QAClB,WAAW,UAAU;AAAA,QACrB,KAAK,UAAU;AAAA,QACf,OAAO,UAAU;AAAA,QACjB,SAAS,UAAU;AAAA,QACnB,UAAU,UAAU;AAAA,MACtB;AAEA,YAAM,SAAS,MAAM,QAAQ,OAAO,KAAK;AACzC,YAAM,aAAa,gBAAgB,MAAM;AAEzC,YAAM,YAAY,MAAM,MAAM,GAAG,OAAO,yBAAyB;AAAA,QAC/D,QAAQ;AAAA,QACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,QAC9C,MAAM,KAAK,UAAU,EAAE,OAAO,QAAQ,WAAW,CAAC;AAAA,MACpD,CAAC;AAED,YAAM,OAAO,MAAM,UAAU,KAAK;AAElC,UAAI,CAAC,UAAU,IAAI;AACjB,kBAAU,KAAK,WAAW,KAAK,SAAS,+BAA+B;AAAA,MACzE,OAAO;AACL,oBAAY,KAAK,IAAI;AAAA,MACvB;AAAA,IACF,SAAS,OAAY;AACnB,UAAI,OAAO,YAAY,8BAA8B;AACnD,kBAAU,OAAO,WAAW,sCAAsC;AAAA,MACpE;AAAA,IACF,UAAE;AACA,iBAAW,KAAK;AAChB,mBAAa,KAAK;AAClB,sBAAgB,KAAK;AACrB,iBAAW;AAAA,IACb;AAAA,EACF;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACC,SAAS;AAAA,MACT,UAAU;AAAA,MACV;AAAA,MACA,MAAK;AAAA,MAEJ,uBAAa,UAAU,sBAAsB;AAAA;AAAA,EAChD;AAEJ;AAEO,IAAM,qBAAkD,CAAC;AAAA,EAC9D;AAAA,EACA;AAAA,EACA,GAAG;AACL,MAAM;AACJ,SACE,6CAAC,kBAAe,SAAkB,UAChC,uDAAC,qBAAmB,GAAG,OAAO,GAChC;AAEJ;;;AEtJA,IAAAC,gBAA6C;AAC7C,IAAAC,+BAA0B;AAC1B,IAAAC,kCAA+B;AAyKzB,IAAAC,sBAAA;AAxJN,SAAS,gBAAgB;AAAA,EACvB,UAAU;AAAA,EACV;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAwD;AACtD,QAAM,EAAE,WAAW,WAAW,YAAY,QAAQ,YAAY,QAAQ,QACpE,wCAAU;AACZ,QAAM,EAAE,YAAY,QAAQ,QAAI,gDAAe;AAC/C,QAAM,CAAC,cAAc,eAAe,QAAI,wBAAwB,IAAI;AACpE,QAAM,CAAC,SAAS,UAAU,QAAI,wBAAS,IAAI;AAC3C,QAAM,CAAC,SAAS,UAAU,QAAI,wBAAS,KAAK;AAC5C,QAAM,CAAC,cAAc,eAAe,QAAI,wBAAS,KAAK;AAEtD,QAAM,eAAe,YAAY;AAC/B,QAAI;AACF,YAAM,MAAM,MAAM,MAAM,GAAG,OAAO,wBAAwB;AAC1D,YAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,UAAI,KAAK,UAAU,CAAC,GAAG;AACrB,wBAAgB,KAAK,QAAQ,CAAC,EAAE,aAAa;AAAA,MAC/C;AAAA,IACF,QAAQ;AAAA,IAAC;AACT,eAAW,KAAK;AAAA,EAClB;AAEA,+BAAU,MAAM;AACd,iBAAa;AAAA,EACf,GAAG,CAAC,CAAC;AAEL,+BAAU,MAAM;AACd,QAAI,aAAa,aAAa,WAAW,CAAC,cAAc;AACtD,sBAAgB,IAAI;AACpB,iBAAW,KAAK;AAChB,iBAAW;AAAA,IACb;AAAA,EACF,GAAG,CAAC,WAAW,WAAW,SAAS,QAAQ,YAAY,CAAC;AAExD,+BAAU,MAAM;AACd,QAAI,UAAU,CAAC,aAAa,CAAC,cAAc,SAAS;AAClD,cAAQ,EAAE,MAAM,QAAQ,KAAK;AAAA,IAC/B;AAAA,EACF,GAAG,CAAC,QAAQ,WAAW,YAAY,SAAS,OAAO,CAAC;AAEpD,+BAAU,MAAM;AACd,QAAI,CAAC,WAAW,WAAW,CAAC,aAAa,CAAC,cAAc,CAAC,QAAQ;AAC/D,iBAAW,KAAK;AAChB,sBAAgB,KAAK;AAAA,IACvB;AAAA,EACF,GAAG,CAAC,SAAS,SAAS,WAAW,YAAY,MAAM,CAAC;AAEpD,QAAM,kBAAkB,YAAY;AAClC,eAAW,IAAI;AACf,QAAI,UAAU,CAAC,WAAW;AACxB,UAAI;AACF,cAAM,QAAQ;AAAA,MAChB,QAAQ;AACN,mBAAW,IAAI;AAAA,MACjB;AAAA,IACF,WAAW,CAAC,QAAQ;AAClB,iBAAW,IAAI;AAAA,IACjB;AAAA,EACF;AAEA,QAAM,aAAa,YAAY;AAC7B,QAAI,CAAC,QAAQ,QAAS;AAEtB,UAAM,UAAU,OAAO;AACvB,QAAI,EAAE,YAAY,UAAU;AAC1B,gBAAU,6BAA6B;AACvC,iBAAW,KAAK;AAChB,iBAAW;AACX;AAAA,IACF;AAEA,QAAI;AACF,YAAM,YAAY,MAAM,MAAM,GAAG,OAAO,wBAAwB;AAAA,QAC9D,QAAQ;AAAA,QACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,QAC9C,MAAM,KAAK,UAAU;AAAA,UACnB,eAAe,UAAW,SAAS;AAAA,QACrC,CAAC;AAAA,MACH,CAAC;AACD,YAAM,YAAY,MAAM,UAAU,KAAK;AAEvC,YAAM,QAA2B;AAAA,QAC/B,QAAQ,UAAU;AAAA,QAClB,WAAW,UAAU;AAAA,QACrB,KAAK,UAAU;AAAA,QACf,OAAO,UAAU;AAAA,QACjB,SAAS,UAAU;AAAA,QACnB,UAAU,UAAU;AAAA,MACtB;AAEA,YAAM,SAA6B,MAAM,QAAQ,OAAO,KAAK;AAE7D,YAAM,mBAAmB;AAAA,QACvB,SAAS;AAAA,UACP,SAAS,OAAO,QAAQ;AAAA,UACxB,WAAW,MAAM,KAAK,OAAO,QAAQ,SAAS;AAAA,QAChD;AAAA,QACA,WAAW,MAAM,KAAK,OAAO,SAAS;AAAA,QACtC,eAAe,MAAM,KAAK,OAAO,aAAa;AAAA,MAChD;AAEA,YAAM,UAAU,MAAM,MAAM,GAAG,OAAO,uBAAuB;AAAA,QAC3D,QAAQ;AAAA,QACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,QAC9C,MAAM,KAAK,UAAU,EAAE,OAAO,QAAQ,iBAAiB,CAAC;AAAA,MAC1D,CAAC;AAED,UAAI,QAAQ,IAAI;AACd,cAAM,OAAO,MAAM,QAAQ,KAAK;AAChC,wBAAgB,KAAK,aAAa;AAClC,iBAAS,KAAK,aAAa;AAAA,MAC7B,OAAO;AACL,cAAM,MAAM,MAAM,QAAQ,KAAK;AAC/B,kBAAU,IAAI,WAAW,uBAAuB;AAAA,MAClD;AAAA,IACF,SAAS,GAAQ;AACf,UAAI,CAAC,GAAG,SAAS,SAAS,UAAU,GAAG;AACrC,kBAAU,uBAAuB;AAAA,MACnC;AAAA,IACF,UAAE;AACA,iBAAW,KAAK;AAChB,sBAAgB,KAAK;AACrB,iBAAW;AAAA,IACb;AAAA,EACF;AAEA,QAAM,eAAe,YAAY;AAC/B,QAAI,CAAC,aAAc;AACnB,QAAI;AACF,YAAM,MAAM,MAAM,MAAM,GAAG,OAAO,yBAAyB;AAAA,QACzD,QAAQ;AAAA,QACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,QAC9C,MAAM,KAAK,UAAU,EAAE,eAAe,aAAa,CAAC;AAAA,MACtD,CAAC;AACD,UAAI,IAAI,IAAI;AACV,wBAAgB,IAAI;AACpB,mBAAW;AAAA,MACb;AAAA,IACF,QAAQ;AACN,gBAAU,yBAAyB;AAAA,IACrC;AAAA,EACF;AAEA,MAAI,SAAS;AACX,WACE,6CAAC,YAAO,UAAQ,MAAC,WAAsB,wBAEvC;AAAA,EAEJ;AAEA,MAAI,cAAc;AAChB,QAAI,cAAc;AAChB,aAAO,6EAAG,uBAAa,EAAE,SAAS,cAAc,UAAU,aAAa,CAAC,GAAE;AAAA,IAC5E;AACA,UAAM,YAAY,GAAG,aAAa,MAAM,GAAG,CAAC,CAAC,MAAM,aAAa,MAAM,EAAE,CAAC;AACzE,WACE,8CAAC,SAAI,OAAO,EAAE,SAAS,QAAQ,YAAY,UAAU,KAAK,SAAS,GACjE;AAAA,mDAAC,UAAK,OAAO,EAAE,YAAY,aAAa,UAAU,WAAW,GAC1D,qBACH;AAAA,MACA,6CAAC,YAAO,SAAS,cAAc,WAAW,iBAAiB,MAAK,UAAS,oBAEzE;AAAA,OACF;AAAA,EAEJ;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACC,SAAS;AAAA,MACT,UAAU;AAAA,MACV;AAAA,MACA,MAAK;AAAA,MAEJ,uBAAa,UAAU,eAAe;AAAA;AAAA,EACzC;AAEJ;AAEO,IAAM,mBAA8C,CAAC;AAAA,EAC1D;AAAA,EACA;AAAA,EACA,GAAG;AACL,MAAM;AACJ,SACE,6CAAC,kBAAe,SAAkB,UAChC,uDAAC,mBAAiB,GAAG,OAAO,GAC9B;AAEJ;","names":["import_react","import_wallet_adapter_react","import_wallet_adapter_react_ui","import_jsx_runtime","import_react","import_wallet_adapter_react","import_wallet_adapter_react_ui","import_jsx_runtime"]}