passkey-magic 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/README.md +302 -0
- package/dist/adapters/memory.d.mts +10 -0
- package/dist/adapters/memory.mjs +142 -0
- package/dist/adapters/unstorage.d.mts +30 -0
- package/dist/adapters/unstorage.mjs +238 -0
- package/dist/better-auth/client.d.mts +9 -0
- package/dist/better-auth/client.mjs +7 -0
- package/dist/better-auth/index.d.mts +2 -0
- package/dist/better-auth/index.mjs +4044 -0
- package/dist/client/index.d.mts +167 -0
- package/dist/client/index.mjs +166 -0
- package/dist/crypto-KHRNe6EL.mjs +45 -0
- package/dist/index-BoHvgaqz.d.mts +2816 -0
- package/dist/index-Cqqpr_uS.d.mts +176 -0
- package/dist/nitro/index.d.mts +89 -0
- package/dist/nitro/index.mjs +117 -0
- package/dist/server/index.d.mts +3 -0
- package/dist/server/index.mjs +3 -0
- package/dist/server-BXkm8lU0.mjs +823 -0
- package/dist/types-BjM1f6uu.d.mts +249 -0
- package/package.json +74 -0
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
//#region src/adapters/unstorage.ts
|
|
2
|
+
/**
|
|
3
|
+
* Storage adapter backed by [unstorage](https://unstorage.unjs.io).
|
|
4
|
+
* Works with any unstorage driver (memory, redis, fs, cloudflare-kv, etc.).
|
|
5
|
+
*
|
|
6
|
+
* Key schema:
|
|
7
|
+
* ```
|
|
8
|
+
* {base}:user:{id} → User
|
|
9
|
+
* {base}:user-email:{email} → userId (secondary index)
|
|
10
|
+
* {base}:cred:{id} → Credential
|
|
11
|
+
* {base}:user-creds:{userId} → credentialId[] (index)
|
|
12
|
+
* {base}:session:{id} → Session
|
|
13
|
+
* {base}:session-token:{token} → sessionId (secondary index)
|
|
14
|
+
* {base}:user-sessions:{userId} → sessionId[] (index)
|
|
15
|
+
* {base}:challenge:{key} → { challenge, expiresAt }
|
|
16
|
+
* {base}:magic-link:{token} → { email, expiresAt }
|
|
17
|
+
* {base}:qr:{id} → QRSession
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
function unstorageAdapter(storage, options = {}) {
|
|
21
|
+
const base = options.base ?? "auth";
|
|
22
|
+
const k = (key) => `${base}:${key}`;
|
|
23
|
+
function serialize(obj) {
|
|
24
|
+
return JSON.parse(JSON.stringify(obj));
|
|
25
|
+
}
|
|
26
|
+
function deserializeUser(raw) {
|
|
27
|
+
if (!raw) return null;
|
|
28
|
+
return {
|
|
29
|
+
...raw,
|
|
30
|
+
createdAt: new Date(raw.createdAt)
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
function deserializeCredential(raw) {
|
|
34
|
+
if (!raw) return null;
|
|
35
|
+
const pk = raw.publicKey;
|
|
36
|
+
return {
|
|
37
|
+
...raw,
|
|
38
|
+
publicKey: new Uint8Array(Object.values(pk)),
|
|
39
|
+
createdAt: new Date(raw.createdAt)
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
function deserializeSession(raw) {
|
|
43
|
+
if (!raw) return null;
|
|
44
|
+
return {
|
|
45
|
+
...raw,
|
|
46
|
+
expiresAt: new Date(raw.expiresAt),
|
|
47
|
+
createdAt: new Date(raw.createdAt)
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
function deserializeQRSession(raw) {
|
|
51
|
+
if (!raw) return null;
|
|
52
|
+
return {
|
|
53
|
+
...raw,
|
|
54
|
+
expiresAt: new Date(raw.expiresAt),
|
|
55
|
+
createdAt: new Date(raw.createdAt)
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
const adapter = {
|
|
59
|
+
async createUser(user) {
|
|
60
|
+
await storage.setItem(k(`user:${user.id}`), serialize(user));
|
|
61
|
+
if (user.email) await storage.setItem(k(`user-email:${user.email}`), user.id);
|
|
62
|
+
return { ...user };
|
|
63
|
+
},
|
|
64
|
+
async getUserById(id) {
|
|
65
|
+
return deserializeUser(await storage.getItem(k(`user:${id}`)));
|
|
66
|
+
},
|
|
67
|
+
async getUserByEmail(email) {
|
|
68
|
+
const userId = await storage.getItem(k(`user-email:${email}`));
|
|
69
|
+
if (!userId) return null;
|
|
70
|
+
return adapter.getUserById(userId);
|
|
71
|
+
},
|
|
72
|
+
async updateUser(id, update) {
|
|
73
|
+
const raw = await storage.getItem(k(`user:${id}`));
|
|
74
|
+
if (!raw) throw new Error(`User not found: ${id}`);
|
|
75
|
+
const user = deserializeUser(raw);
|
|
76
|
+
const oldEmail = user.email;
|
|
77
|
+
const updated = {
|
|
78
|
+
...user,
|
|
79
|
+
...update
|
|
80
|
+
};
|
|
81
|
+
await storage.setItem(k(`user:${id}`), serialize(updated));
|
|
82
|
+
if (update.email !== void 0 && update.email !== oldEmail) {
|
|
83
|
+
if (oldEmail) await storage.removeItem(k(`user-email:${oldEmail}`));
|
|
84
|
+
if (update.email) await storage.setItem(k(`user-email:${update.email}`), id);
|
|
85
|
+
}
|
|
86
|
+
return { ...updated };
|
|
87
|
+
},
|
|
88
|
+
async deleteUser(id) {
|
|
89
|
+
const raw = await storage.getItem(k(`user:${id}`));
|
|
90
|
+
if (!raw) return;
|
|
91
|
+
const user = deserializeUser(raw);
|
|
92
|
+
if (user.email) await storage.removeItem(k(`user-email:${user.email}`));
|
|
93
|
+
await storage.removeItem(k(`user:${id}`));
|
|
94
|
+
},
|
|
95
|
+
async createCredential(cred) {
|
|
96
|
+
await storage.setItem(k(`cred:${cred.id}`), serialize(cred));
|
|
97
|
+
const indexKey = k(`user-creds:${cred.userId}`);
|
|
98
|
+
const existing = await storage.getItem(indexKey) ?? [];
|
|
99
|
+
existing.push(cred.id);
|
|
100
|
+
await storage.setItem(indexKey, existing);
|
|
101
|
+
return { ...cred };
|
|
102
|
+
},
|
|
103
|
+
async getCredentialById(id) {
|
|
104
|
+
return deserializeCredential(await storage.getItem(k(`cred:${id}`)));
|
|
105
|
+
},
|
|
106
|
+
async getCredentialsByUserId(userId) {
|
|
107
|
+
const credIds = await storage.getItem(k(`user-creds:${userId}`)) ?? [];
|
|
108
|
+
const creds = [];
|
|
109
|
+
for (const id of credIds) {
|
|
110
|
+
const cred = await adapter.getCredentialById(id);
|
|
111
|
+
if (cred) creds.push(cred);
|
|
112
|
+
}
|
|
113
|
+
return creds;
|
|
114
|
+
},
|
|
115
|
+
async updateCredential(id, update) {
|
|
116
|
+
const raw = await storage.getItem(k(`cred:${id}`));
|
|
117
|
+
if (!raw) throw new Error(`Credential not found: ${id}`);
|
|
118
|
+
if (update.counter !== void 0) raw.counter = update.counter;
|
|
119
|
+
if (update.label !== void 0) raw.label = update.label;
|
|
120
|
+
await storage.setItem(k(`cred:${id}`), raw);
|
|
121
|
+
},
|
|
122
|
+
async deleteCredential(id) {
|
|
123
|
+
const raw = await storage.getItem(k(`cred:${id}`));
|
|
124
|
+
if (!raw) return;
|
|
125
|
+
const cred = deserializeCredential(raw);
|
|
126
|
+
await storage.removeItem(k(`cred:${id}`));
|
|
127
|
+
const indexKey = k(`user-creds:${cred.userId}`);
|
|
128
|
+
const existing = await storage.getItem(indexKey) ?? [];
|
|
129
|
+
await storage.setItem(indexKey, existing.filter((c) => c !== id));
|
|
130
|
+
},
|
|
131
|
+
async createSession(session) {
|
|
132
|
+
await storage.setItem(k(`session:${session.id}`), serialize(session));
|
|
133
|
+
await storage.setItem(k(`session-token:${session.token}`), session.id);
|
|
134
|
+
const indexKey = k(`user-sessions:${session.userId}`);
|
|
135
|
+
const existing = await storage.getItem(indexKey) ?? [];
|
|
136
|
+
existing.push(session.id);
|
|
137
|
+
await storage.setItem(indexKey, existing);
|
|
138
|
+
return { ...session };
|
|
139
|
+
},
|
|
140
|
+
async getSessionByToken(token) {
|
|
141
|
+
const sessionId = await storage.getItem(k(`session-token:${token}`));
|
|
142
|
+
if (!sessionId) return null;
|
|
143
|
+
const session = deserializeSession(await storage.getItem(k(`session:${sessionId}`)));
|
|
144
|
+
if (!session) return null;
|
|
145
|
+
if (/* @__PURE__ */ new Date() > session.expiresAt) {
|
|
146
|
+
await adapter.deleteSession(session.id);
|
|
147
|
+
return null;
|
|
148
|
+
}
|
|
149
|
+
return session;
|
|
150
|
+
},
|
|
151
|
+
async getSessionsByUserId(userId) {
|
|
152
|
+
const sessionIds = await storage.getItem(k(`user-sessions:${userId}`)) ?? [];
|
|
153
|
+
const result = [];
|
|
154
|
+
for (const id of sessionIds) {
|
|
155
|
+
const session = deserializeSession(await storage.getItem(k(`session:${id}`)));
|
|
156
|
+
if (session && /* @__PURE__ */ new Date() <= session.expiresAt) result.push(session);
|
|
157
|
+
}
|
|
158
|
+
return result;
|
|
159
|
+
},
|
|
160
|
+
async deleteSession(id) {
|
|
161
|
+
const raw = await storage.getItem(k(`session:${id}`));
|
|
162
|
+
if (!raw) return;
|
|
163
|
+
const session = deserializeSession(raw);
|
|
164
|
+
await storage.removeItem(k(`session:${id}`));
|
|
165
|
+
await storage.removeItem(k(`session-token:${session.token}`));
|
|
166
|
+
const indexKey = k(`user-sessions:${session.userId}`);
|
|
167
|
+
const existing = await storage.getItem(indexKey) ?? [];
|
|
168
|
+
await storage.setItem(indexKey, existing.filter((s) => s !== id));
|
|
169
|
+
},
|
|
170
|
+
async deleteSessionsByUserId(userId) {
|
|
171
|
+
const sessionIds = await storage.getItem(k(`user-sessions:${userId}`)) ?? [];
|
|
172
|
+
for (const id of sessionIds) {
|
|
173
|
+
const raw = await storage.getItem(k(`session:${id}`));
|
|
174
|
+
if (raw) {
|
|
175
|
+
const session = deserializeSession(raw);
|
|
176
|
+
await storage.removeItem(k(`session:${id}`));
|
|
177
|
+
await storage.removeItem(k(`session-token:${session.token}`));
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
await storage.setItem(k(`user-sessions:${userId}`), []);
|
|
181
|
+
},
|
|
182
|
+
async storeChallenge(key, challenge, ttlMs) {
|
|
183
|
+
await storage.setItem(k(`challenge:${key}`), {
|
|
184
|
+
challenge,
|
|
185
|
+
expiresAt: Date.now() + ttlMs
|
|
186
|
+
});
|
|
187
|
+
},
|
|
188
|
+
async getChallenge(key) {
|
|
189
|
+
const raw = await storage.getItem(k(`challenge:${key}`));
|
|
190
|
+
if (!raw) return null;
|
|
191
|
+
if (Date.now() > raw.expiresAt) {
|
|
192
|
+
await storage.removeItem(k(`challenge:${key}`));
|
|
193
|
+
return null;
|
|
194
|
+
}
|
|
195
|
+
return raw.challenge;
|
|
196
|
+
},
|
|
197
|
+
async deleteChallenge(key) {
|
|
198
|
+
await storage.removeItem(k(`challenge:${key}`));
|
|
199
|
+
},
|
|
200
|
+
async storeMagicLink(token, email, ttlMs) {
|
|
201
|
+
await storage.setItem(k(`magic-link:${token}`), {
|
|
202
|
+
email,
|
|
203
|
+
expiresAt: Date.now() + ttlMs
|
|
204
|
+
});
|
|
205
|
+
},
|
|
206
|
+
async getMagicLink(token) {
|
|
207
|
+
const raw = await storage.getItem(k(`magic-link:${token}`));
|
|
208
|
+
if (!raw) return null;
|
|
209
|
+
if (Date.now() > raw.expiresAt) {
|
|
210
|
+
await storage.removeItem(k(`magic-link:${token}`));
|
|
211
|
+
return null;
|
|
212
|
+
}
|
|
213
|
+
return { email: raw.email };
|
|
214
|
+
},
|
|
215
|
+
async deleteMagicLink(token) {
|
|
216
|
+
await storage.removeItem(k(`magic-link:${token}`));
|
|
217
|
+
},
|
|
218
|
+
async createQRSession(session) {
|
|
219
|
+
await storage.setItem(k(`qr:${session.id}`), serialize(session));
|
|
220
|
+
return { ...session };
|
|
221
|
+
},
|
|
222
|
+
async getQRSession(id) {
|
|
223
|
+
const session = deserializeQRSession(await storage.getItem(k(`qr:${id}`)));
|
|
224
|
+
if (!session) return null;
|
|
225
|
+
if (/* @__PURE__ */ new Date() > session.expiresAt && session.state === "pending") session.state = "expired";
|
|
226
|
+
return session;
|
|
227
|
+
},
|
|
228
|
+
async updateQRSession(id, update) {
|
|
229
|
+
const raw = await storage.getItem(k(`qr:${id}`));
|
|
230
|
+
if (!raw) return;
|
|
231
|
+
Object.assign(raw, serialize(update));
|
|
232
|
+
await storage.setItem(k(`qr:${id}`), raw);
|
|
233
|
+
}
|
|
234
|
+
};
|
|
235
|
+
return adapter;
|
|
236
|
+
}
|
|
237
|
+
//#endregion
|
|
238
|
+
export { unstorageAdapter };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { n as passkeyMagicPlugin } from "../index-BoHvgaqz.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/better-auth/client.d.ts
|
|
4
|
+
declare const passkeyMagicClientPlugin: () => {
|
|
5
|
+
id: "passkey-magic";
|
|
6
|
+
$InferServerPlugin: ReturnType<typeof passkeyMagicPlugin>;
|
|
7
|
+
};
|
|
8
|
+
//#endregion
|
|
9
|
+
export { passkeyMagicClientPlugin };
|