@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/index.js ADDED
@@ -0,0 +1,189 @@
1
+ import {
2
+ deserializeOutput,
3
+ serializeOutput
4
+ } from "./chunk-AUDIM6MZ.js";
5
+ import {
6
+ generateNonce,
7
+ verifySIWS
8
+ } from "./chunk-Q7TSFSYW.js";
9
+
10
+ // src/index.ts
11
+ import { createAuthEndpoint, APIError } from "better-auth/api";
12
+ import { setSessionCookie } from "better-auth/cookies";
13
+ import { z } from "zod";
14
+ var siws = (options) => ({
15
+ id: "siws",
16
+ endpoints: {
17
+ getSiwsNonce: createAuthEndpoint(
18
+ "/siws/nonce",
19
+ {
20
+ method: "POST",
21
+ body: z.object({
22
+ walletAddress: z.string().min(32).max(44)
23
+ })
24
+ },
25
+ async (ctx) => {
26
+ const { walletAddress } = ctx.body;
27
+ const nonce = generateNonce();
28
+ const expiryMs = options?.nonceExpiryMs ?? 5 * 60 * 1e3;
29
+ await ctx.context.internalAdapter.createVerificationValue({
30
+ identifier: `siws:${walletAddress}`,
31
+ value: nonce,
32
+ expiresAt: new Date(Date.now() + expiryMs)
33
+ });
34
+ const host = ctx.headers?.get("host") || "localhost:3000";
35
+ const protocol = host.includes("localhost") ? "http" : "https";
36
+ const domain = host;
37
+ const uri = `${protocol}://${host}`;
38
+ return ctx.json({
39
+ nonce,
40
+ domain,
41
+ uri,
42
+ statement: options?.statement ?? "Sign in with your Solana wallet. This will not trigger a blockchain transaction or cost any gas fee.",
43
+ chainId: options?.chainId ?? "mainnet",
44
+ issuedAt: (/* @__PURE__ */ new Date()).toISOString()
45
+ });
46
+ }
47
+ ),
48
+ verifySiwsSignature: createAuthEndpoint(
49
+ "/siws/verify",
50
+ {
51
+ method: "POST",
52
+ body: z.object({
53
+ output: z.object({
54
+ account: z.object({
55
+ address: z.string(),
56
+ publicKey: z.array(z.number())
57
+ }),
58
+ signature: z.array(z.number()),
59
+ signedMessage: z.array(z.number())
60
+ }),
61
+ input: z.object({
62
+ domain: z.string(),
63
+ address: z.string().optional(),
64
+ statement: z.string().optional(),
65
+ uri: z.string().optional(),
66
+ version: z.string().optional(),
67
+ chainId: z.string().optional(),
68
+ nonce: z.string().optional(),
69
+ issuedAt: z.string().optional(),
70
+ expirationTime: z.string().optional(),
71
+ notBefore: z.string().optional(),
72
+ requestId: z.string().optional(),
73
+ resources: z.array(z.string()).optional()
74
+ })
75
+ }),
76
+ requireRequest: true
77
+ },
78
+ async (ctx) => {
79
+ const { output, input } = ctx.body;
80
+ const walletAddress = output.account.address;
81
+ const verification = await ctx.context.internalAdapter.findVerificationValue(
82
+ `siws:${walletAddress}`
83
+ );
84
+ if (!verification || /* @__PURE__ */ new Date() > verification.expiresAt) {
85
+ throw new APIError("UNAUTHORIZED", {
86
+ message: "Invalid or expired nonce"
87
+ });
88
+ }
89
+ const solanaOutput = deserializeOutput(output);
90
+ const isValid = verifySIWS(input, solanaOutput);
91
+ if (!isValid) {
92
+ throw new APIError("UNAUTHORIZED", {
93
+ message: "Invalid signature"
94
+ });
95
+ }
96
+ await ctx.context.internalAdapter.deleteVerificationValue(
97
+ verification.id
98
+ );
99
+ const linkedAccount = await ctx.context.adapter.findOne({
100
+ model: "account",
101
+ where: [
102
+ { field: "providerId", operator: "eq", value: "solana" },
103
+ { field: "accountId", operator: "eq", value: walletAddress }
104
+ ]
105
+ });
106
+ if (!linkedAccount) {
107
+ if (options?.anonymous) {
108
+ const user2 = await ctx.context.internalAdapter.createUser({
109
+ name: walletAddress,
110
+ email: `${walletAddress}@solana.wallet`,
111
+ image: ""
112
+ });
113
+ await ctx.context.internalAdapter.createAccount({
114
+ userId: user2.id,
115
+ providerId: "solana",
116
+ accountId: walletAddress,
117
+ createdAt: /* @__PURE__ */ new Date(),
118
+ updatedAt: /* @__PURE__ */ new Date()
119
+ });
120
+ const session2 = await ctx.context.internalAdapter.createSession(
121
+ user2.id,
122
+ ctx
123
+ );
124
+ if (!session2) {
125
+ throw new APIError("INTERNAL_SERVER_ERROR", {
126
+ message: "Failed to create session"
127
+ });
128
+ }
129
+ await setSessionCookie(ctx, { session: session2, user: user2 });
130
+ return ctx.json({
131
+ success: true,
132
+ user: {
133
+ id: user2.id,
134
+ name: user2.name,
135
+ email: user2.email
136
+ }
137
+ });
138
+ }
139
+ throw new APIError("UNAUTHORIZED", {
140
+ message: "No account linked to this wallet. Please sign in with email first and link your wallet.",
141
+ code: "WALLET_NOT_LINKED"
142
+ });
143
+ }
144
+ const user = await ctx.context.adapter.findOne({
145
+ model: "user",
146
+ where: [
147
+ { field: "id", operator: "eq", value: linkedAccount.userId }
148
+ ]
149
+ });
150
+ if (!user) {
151
+ throw new APIError("UNAUTHORIZED", {
152
+ message: "User not found"
153
+ });
154
+ }
155
+ if (user.banned) {
156
+ throw new APIError("FORBIDDEN", {
157
+ message: "Your account has been banned"
158
+ });
159
+ }
160
+ const session = await ctx.context.internalAdapter.createSession(
161
+ user.id,
162
+ ctx
163
+ );
164
+ if (!session) {
165
+ throw new APIError("INTERNAL_SERVER_ERROR", {
166
+ message: "Failed to create session"
167
+ });
168
+ }
169
+ await setSessionCookie(ctx, { session, user });
170
+ return ctx.json({
171
+ success: true,
172
+ user: {
173
+ id: user.id,
174
+ name: user.name,
175
+ email: user.email
176
+ }
177
+ });
178
+ }
179
+ )
180
+ }
181
+ });
182
+ export {
183
+ deserializeOutput,
184
+ generateNonce,
185
+ serializeOutput,
186
+ siws,
187
+ verifySIWS
188
+ };
189
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["import { createAuthEndpoint, APIError } from \"better-auth/api\";\nimport { setSessionCookie } from \"better-auth/cookies\";\nimport { z } from \"zod\";\nimport { generateNonce, verifySIWS } from \"./crypto\";\nimport { deserializeOutput } from \"./types\";\nimport type { SiwsPluginOptions } from \"./types\";\n\nexport type { SiwsPluginOptions };\nexport { generateNonce, verifySIWS } from \"./crypto\";\nexport { serializeOutput, deserializeOutput } from \"./types\";\nexport type {\n SiwsNonceResponse,\n SiwsVerifyRequest,\n SiwsVerifyResponse,\n SiwsLinkedWallet,\n SerializedSolanaOutput,\n} from \"./types\";\n\nexport const siws = (options?: SiwsPluginOptions) => ({\n id: \"siws\" as const,\n endpoints: {\n getSiwsNonce: createAuthEndpoint(\n \"/siws/nonce\",\n {\n method: \"POST\",\n body: z.object({\n walletAddress: z.string().min(32).max(44),\n }),\n },\n async (ctx) => {\n const { walletAddress } = ctx.body;\n const nonce = generateNonce();\n const expiryMs = options?.nonceExpiryMs ?? 5 * 60 * 1000;\n\n await ctx.context.internalAdapter.createVerificationValue({\n identifier: `siws:${walletAddress}`,\n value: nonce,\n expiresAt: new Date(Date.now() + expiryMs),\n });\n\n const host = ctx.headers?.get(\"host\") || \"localhost:3000\";\n const protocol = host.includes(\"localhost\") ? \"http\" : \"https\";\n const domain = host;\n const uri = `${protocol}://${host}`;\n\n return ctx.json({\n nonce,\n domain,\n uri,\n statement:\n options?.statement ??\n \"Sign in with your Solana wallet. This will not trigger a blockchain transaction or cost any gas fee.\",\n chainId: options?.chainId ?? \"mainnet\",\n issuedAt: new Date().toISOString(),\n });\n }\n ),\n\n verifySiwsSignature: createAuthEndpoint(\n \"/siws/verify\",\n {\n method: \"POST\",\n body: z.object({\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 input: z.object({\n domain: z.string(),\n address: z.string().optional(),\n statement: z.string().optional(),\n uri: z.string().optional(),\n version: z.string().optional(),\n chainId: z.string().optional(),\n nonce: z.string().optional(),\n issuedAt: z.string().optional(),\n expirationTime: z.string().optional(),\n notBefore: z.string().optional(),\n requestId: z.string().optional(),\n resources: z.array(z.string()).optional(),\n }),\n }),\n requireRequest: true,\n },\n async (ctx: any) => {\n const { output, input } = ctx.body;\n const walletAddress = output.account.address;\n\n const verification =\n await ctx.context.internalAdapter.findVerificationValue(\n `siws:${walletAddress}`\n );\n\n if (!verification || new Date() > verification.expiresAt) {\n throw new APIError(\"UNAUTHORIZED\", {\n message: \"Invalid or expired nonce\",\n });\n }\n\n const solanaOutput = deserializeOutput(output);\n const isValid = verifySIWS(input, solanaOutput);\n\n if (!isValid) {\n throw new APIError(\"UNAUTHORIZED\", {\n message: \"Invalid signature\",\n });\n }\n\n await ctx.context.internalAdapter.deleteVerificationValue(\n verification.id\n );\n\n const linkedAccount = (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 })) as { userId: string } | null;\n\n if (!linkedAccount) {\n if (options?.anonymous) {\n const user = await ctx.context.internalAdapter.createUser({\n name: walletAddress,\n email: `${walletAddress}@solana.wallet`,\n image: \"\",\n });\n\n await ctx.context.internalAdapter.createAccount({\n userId: user.id,\n providerId: \"solana\",\n accountId: walletAddress,\n createdAt: new Date(),\n updatedAt: new Date(),\n });\n\n const session = await ctx.context.internalAdapter.createSession(\n user.id,\n ctx\n );\n\n if (!session) {\n throw new APIError(\"INTERNAL_SERVER_ERROR\", {\n message: \"Failed to create session\",\n });\n }\n\n await setSessionCookie(ctx, { session, user });\n\n return ctx.json({\n success: true,\n user: {\n id: user.id,\n name: user.name,\n email: user.email,\n },\n });\n }\n\n throw new APIError(\"UNAUTHORIZED\", {\n message:\n \"No account linked to this wallet. Please sign in with email first and link your wallet.\",\n code: \"WALLET_NOT_LINKED\",\n });\n }\n\n const user = (await ctx.context.adapter.findOne({\n model: \"user\",\n where: [\n { field: \"id\", operator: \"eq\", value: linkedAccount.userId },\n ],\n })) as {\n id: string;\n name: string;\n email: string;\n emailVerified: boolean;\n image?: string | null;\n banned?: boolean;\n createdAt: Date;\n updatedAt: Date;\n } | null;\n\n if (!user) {\n throw new APIError(\"UNAUTHORIZED\", {\n message: \"User not found\",\n });\n }\n\n if (user.banned) {\n throw new APIError(\"FORBIDDEN\", {\n message: \"Your account has been banned\",\n });\n }\n\n const session = await ctx.context.internalAdapter.createSession(\n user.id,\n ctx\n );\n\n if (!session) {\n throw new APIError(\"INTERNAL_SERVER_ERROR\", {\n message: \"Failed to create session\",\n });\n }\n\n await setSessionCookie(ctx, { session, user });\n\n return ctx.json({\n success: true,\n user: {\n id: user.id,\n name: user.name,\n email: user.email,\n },\n });\n }\n ),\n },\n});\n"],"mappings":"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","names":["user","session"]}
package/dist/link.cjs ADDED
@@ -0,0 +1,208 @@
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/link.ts
21
+ var link_exports = {};
22
+ __export(link_exports, {
23
+ createSignInInput: () => createSignInInput,
24
+ generateNonce: () => generateNonce,
25
+ siwsLink: () => siwsLink,
26
+ verifySIWS: () => verifySIWS
27
+ });
28
+ module.exports = __toCommonJS(link_exports);
29
+ var import_api = require("better-auth/api");
30
+ var import_api2 = require("better-auth/api");
31
+ var import_zod = require("zod");
32
+
33
+ // src/crypto.ts
34
+ var import_wallet_standard_util = require("@solana/wallet-standard-util");
35
+ function generateNonce() {
36
+ const array = new Uint8Array(16);
37
+ crypto.getRandomValues(array);
38
+ return Array.from(array, (byte) => byte.toString(16).padStart(2, "0")).join("");
39
+ }
40
+ function createSignInInput(domain, nonce, options) {
41
+ return {
42
+ domain,
43
+ statement: options?.statement ?? "Sign in with your Solana wallet. This will not trigger a blockchain transaction or cost any gas fee.",
44
+ version: "1",
45
+ nonce,
46
+ chainId: options?.chainId ?? "mainnet",
47
+ issuedAt: (/* @__PURE__ */ new Date()).toISOString()
48
+ };
49
+ }
50
+ function verifySIWS(input, output) {
51
+ try {
52
+ const reconstructed = {
53
+ account: {
54
+ ...output.account,
55
+ publicKey: output.account.publicKey instanceof Uint8Array ? output.account.publicKey : new Uint8Array(output.account.publicKey),
56
+ chains: output.account.chains ?? [],
57
+ features: output.account.features ?? []
58
+ },
59
+ signature: output.signature instanceof Uint8Array ? output.signature : new Uint8Array(output.signature),
60
+ signedMessage: output.signedMessage instanceof Uint8Array ? output.signedMessage : new Uint8Array(output.signedMessage)
61
+ };
62
+ return (0, import_wallet_standard_util.verifySignIn)(input, reconstructed);
63
+ } catch (error) {
64
+ console.error("SIWS verification error:", error);
65
+ return false;
66
+ }
67
+ }
68
+
69
+ // src/link.ts
70
+ var siwsLink = (_options) => ({
71
+ id: "siws-link",
72
+ endpoints: {
73
+ linkSolanaWallet: (0, import_api.createAuthEndpoint)(
74
+ "/siws/link",
75
+ {
76
+ method: "POST",
77
+ body: import_zod.z.object({
78
+ input: import_zod.z.object({
79
+ domain: import_zod.z.string(),
80
+ statement: import_zod.z.string().optional(),
81
+ version: import_zod.z.string().optional(),
82
+ nonce: import_zod.z.string().optional(),
83
+ chainId: import_zod.z.string().optional(),
84
+ issuedAt: import_zod.z.string().optional()
85
+ }),
86
+ output: import_zod.z.object({
87
+ account: import_zod.z.object({
88
+ address: import_zod.z.string(),
89
+ publicKey: import_zod.z.array(import_zod.z.number())
90
+ }),
91
+ signature: import_zod.z.array(import_zod.z.number()),
92
+ signedMessage: import_zod.z.array(import_zod.z.number())
93
+ })
94
+ }),
95
+ requireRequest: true
96
+ },
97
+ async (ctx) => {
98
+ const session = await (0, import_api2.getSessionFromCtx)(ctx);
99
+ if (!session?.user) {
100
+ throw new import_api.APIError("UNAUTHORIZED", { message: "Not authenticated" });
101
+ }
102
+ const { input, output } = ctx.body;
103
+ const walletAddress = output.account.address;
104
+ const isValid = verifySIWS(input, output);
105
+ if (!isValid) {
106
+ throw new import_api.APIError("BAD_REQUEST", {
107
+ message: "Invalid signature"
108
+ });
109
+ }
110
+ const existing = await ctx.context.adapter.findOne({
111
+ model: "account",
112
+ where: [
113
+ { field: "providerId", operator: "eq", value: "solana" },
114
+ { field: "accountId", operator: "eq", value: walletAddress }
115
+ ]
116
+ });
117
+ if (existing) {
118
+ if (existing.userId === session.user.id) {
119
+ throw new import_api.APIError("BAD_REQUEST", {
120
+ message: "This wallet is already linked to your account"
121
+ });
122
+ }
123
+ throw new import_api.APIError("BAD_REQUEST", {
124
+ message: "This wallet is already linked to another account"
125
+ });
126
+ }
127
+ await ctx.context.internalAdapter.createAccount({
128
+ userId: session.user.id,
129
+ providerId: "solana",
130
+ accountId: walletAddress,
131
+ createdAt: /* @__PURE__ */ new Date(),
132
+ updatedAt: /* @__PURE__ */ new Date()
133
+ });
134
+ return ctx.json({ success: true, walletAddress });
135
+ }
136
+ ),
137
+ unlinkSolanaWallet: (0, import_api.createAuthEndpoint)(
138
+ "/siws/unlink",
139
+ {
140
+ method: "POST",
141
+ body: import_zod.z.object({
142
+ walletAddress: import_zod.z.string().min(32).max(44)
143
+ }),
144
+ requireRequest: true
145
+ },
146
+ async (ctx) => {
147
+ const session = await (0, import_api2.getSessionFromCtx)(ctx);
148
+ if (!session?.user) {
149
+ throw new import_api.APIError("UNAUTHORIZED", { message: "Not authenticated" });
150
+ }
151
+ const { walletAddress } = ctx.body;
152
+ const account = await ctx.context.adapter.findOne({
153
+ model: "account",
154
+ where: [
155
+ { field: "providerId", operator: "eq", value: "solana" },
156
+ { field: "accountId", operator: "eq", value: walletAddress },
157
+ { field: "userId", operator: "eq", value: session.user.id }
158
+ ]
159
+ });
160
+ if (!account) {
161
+ throw new import_api.APIError("NOT_FOUND", {
162
+ message: "Wallet not found on your account"
163
+ });
164
+ }
165
+ await ctx.context.adapter.delete({
166
+ model: "account",
167
+ where: [
168
+ { field: "id", operator: "eq", value: account.id }
169
+ ]
170
+ });
171
+ return ctx.json({ success: true });
172
+ }
173
+ ),
174
+ getLinkedSolanaWallets: (0, import_api.createAuthEndpoint)(
175
+ "/siws/wallets",
176
+ {
177
+ method: "GET",
178
+ requireRequest: true
179
+ },
180
+ async (ctx) => {
181
+ const session = await (0, import_api2.getSessionFromCtx)(ctx);
182
+ if (!session?.user) {
183
+ throw new import_api.APIError("UNAUTHORIZED", { message: "Not authenticated" });
184
+ }
185
+ const accounts = await ctx.context.adapter.findMany({
186
+ model: "account",
187
+ where: [
188
+ { field: "providerId", operator: "eq", value: "solana" },
189
+ { field: "userId", operator: "eq", value: session.user.id }
190
+ ]
191
+ });
192
+ const wallets = accounts.map((a) => ({
193
+ walletAddress: a.accountId,
194
+ createdAt: a.createdAt
195
+ }));
196
+ return ctx.json({ wallets });
197
+ }
198
+ )
199
+ }
200
+ });
201
+ // Annotate the CommonJS export names for ESM import in node:
202
+ 0 && (module.exports = {
203
+ createSignInInput,
204
+ generateNonce,
205
+ siwsLink,
206
+ verifySIWS
207
+ });
208
+ //# sourceMappingURL=link.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/link.ts","../src/crypto.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","import type { SolanaSignInInput, SolanaSignInOutput } from \"@solana/wallet-standard-features\";\nimport { verifySignIn } from \"@solana/wallet-standard-util\";\n\nexport function generateNonce(): string {\n const array = new Uint8Array(16);\n crypto.getRandomValues(array);\n return Array.from(array, (byte) => byte.toString(16).padStart(2, \"0\")).join(\"\");\n}\n\nexport function createSignInInput(\n domain: string,\n nonce: string,\n options?: { statement?: string; chainId?: string }\n): SolanaSignInInput {\n return {\n domain,\n statement:\n options?.statement ??\n \"Sign in with your Solana wallet. This will not trigger a blockchain transaction or cost any gas fee.\",\n version: \"1\",\n nonce,\n chainId: options?.chainId ?? \"mainnet\",\n issuedAt: new Date().toISOString(),\n };\n}\n\nexport function verifySIWS(\n input: SolanaSignInInput,\n output: SolanaSignInOutput | { account: { publicKey: number[] | Uint8Array; address: string }; signature: number[] | Uint8Array; signedMessage: number[] | Uint8Array }\n): boolean {\n try {\n const reconstructed: SolanaSignInOutput = {\n account: {\n ...output.account,\n publicKey:\n output.account.publicKey instanceof Uint8Array\n ? output.account.publicKey\n : new Uint8Array(output.account.publicKey),\n chains: (output.account as any).chains ?? [],\n features: (output.account as any).features ?? [],\n },\n signature:\n output.signature instanceof Uint8Array\n ? output.signature\n : new Uint8Array(output.signature),\n signedMessage:\n output.signedMessage instanceof Uint8Array\n ? output.signedMessage\n : new Uint8Array(output.signedMessage),\n };\n return verifySignIn(input, reconstructed);\n } catch (error) {\n console.error(\"SIWS verification error:\", error);\n return false;\n }\n}\n"],"mappings":"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","names":["import_api"]}
@@ -0,0 +1,46 @@
1
+ import * as better_call from 'better-call';
2
+ import { z } from 'zod';
3
+ import { b as SiwsPluginOptions } from './crypto-BQgenqov.cjs';
4
+ export { h as SiwsLinkRequest, c as SiwsLinkedWallet, i as createSignInInput, g as generateNonce, v as verifySIWS } from './crypto-BQgenqov.cjs';
5
+ import '@solana/wallet-standard-features';
6
+
7
+ declare const siwsLink: (_options?: Pick<SiwsPluginOptions, "chainId">) => {
8
+ id: "siws-link";
9
+ endpoints: {
10
+ linkSolanaWallet: better_call.StrictEndpoint<"/siws/link", {
11
+ method: "POST";
12
+ body: z.ZodObject<{
13
+ input: z.ZodObject<{
14
+ domain: z.ZodString;
15
+ statement: z.ZodOptional<z.ZodString>;
16
+ version: z.ZodOptional<z.ZodString>;
17
+ nonce: z.ZodOptional<z.ZodString>;
18
+ chainId: z.ZodOptional<z.ZodString>;
19
+ issuedAt: z.ZodOptional<z.ZodString>;
20
+ }, z.core.$strip>;
21
+ output: z.ZodObject<{
22
+ account: z.ZodObject<{
23
+ address: z.ZodString;
24
+ publicKey: z.ZodArray<z.ZodNumber>;
25
+ }, z.core.$strip>;
26
+ signature: z.ZodArray<z.ZodNumber>;
27
+ signedMessage: z.ZodArray<z.ZodNumber>;
28
+ }, z.core.$strip>;
29
+ }, z.core.$strip>;
30
+ requireRequest: true;
31
+ }, any>;
32
+ unlinkSolanaWallet: better_call.StrictEndpoint<"/siws/unlink", {
33
+ method: "POST";
34
+ body: z.ZodObject<{
35
+ walletAddress: z.ZodString;
36
+ }, z.core.$strip>;
37
+ requireRequest: true;
38
+ }, any>;
39
+ getLinkedSolanaWallets: better_call.StrictEndpoint<"/siws/wallets", {
40
+ method: "GET";
41
+ requireRequest: true;
42
+ }, any>;
43
+ };
44
+ };
45
+
46
+ export { siwsLink };
package/dist/link.d.ts ADDED
@@ -0,0 +1,46 @@
1
+ import * as better_call from 'better-call';
2
+ import { z } from 'zod';
3
+ import { b as SiwsPluginOptions } from './crypto-BQgenqov.js';
4
+ export { h as SiwsLinkRequest, c as SiwsLinkedWallet, i as createSignInInput, g as generateNonce, v as verifySIWS } from './crypto-BQgenqov.js';
5
+ import '@solana/wallet-standard-features';
6
+
7
+ declare const siwsLink: (_options?: Pick<SiwsPluginOptions, "chainId">) => {
8
+ id: "siws-link";
9
+ endpoints: {
10
+ linkSolanaWallet: better_call.StrictEndpoint<"/siws/link", {
11
+ method: "POST";
12
+ body: z.ZodObject<{
13
+ input: z.ZodObject<{
14
+ domain: z.ZodString;
15
+ statement: z.ZodOptional<z.ZodString>;
16
+ version: z.ZodOptional<z.ZodString>;
17
+ nonce: z.ZodOptional<z.ZodString>;
18
+ chainId: z.ZodOptional<z.ZodString>;
19
+ issuedAt: z.ZodOptional<z.ZodString>;
20
+ }, z.core.$strip>;
21
+ output: z.ZodObject<{
22
+ account: z.ZodObject<{
23
+ address: z.ZodString;
24
+ publicKey: z.ZodArray<z.ZodNumber>;
25
+ }, z.core.$strip>;
26
+ signature: z.ZodArray<z.ZodNumber>;
27
+ signedMessage: z.ZodArray<z.ZodNumber>;
28
+ }, z.core.$strip>;
29
+ }, z.core.$strip>;
30
+ requireRequest: true;
31
+ }, any>;
32
+ unlinkSolanaWallet: better_call.StrictEndpoint<"/siws/unlink", {
33
+ method: "POST";
34
+ body: z.ZodObject<{
35
+ walletAddress: z.ZodString;
36
+ }, z.core.$strip>;
37
+ requireRequest: true;
38
+ }, any>;
39
+ getLinkedSolanaWallets: better_call.StrictEndpoint<"/siws/wallets", {
40
+ method: "GET";
41
+ requireRequest: true;
42
+ }, any>;
43
+ };
44
+ };
45
+
46
+ export { siwsLink };