@batijs/cli 0.0.242 → 0.0.244

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.
Files changed (58) hide show
  1. package/dist/boilerplates/@batijs/cloudflare/files/$package.json.js +2 -2
  2. package/dist/boilerplates/@batijs/drizzle/files/$package.json.js +8 -8
  3. package/dist/boilerplates/@batijs/drizzle/files/database/{db.ts → drizzleDb.ts} +1 -2
  4. package/dist/boilerplates/@batijs/drizzle/files/database/seed.ts +4 -3
  5. package/dist/boilerplates/@batijs/drizzle/files/drizzle.config.ts +1 -1
  6. package/dist/boilerplates/@batijs/drizzle/types/database/drizzleDb.d.ts +1 -0
  7. package/dist/boilerplates/@batijs/eslint/files/$package.json.js +2 -2
  8. package/dist/boilerplates/@batijs/express/files/$package.json.js +1 -0
  9. package/dist/boilerplates/@batijs/express/files/express-entry.ts +20 -0
  10. package/dist/boilerplates/@batijs/fastify/files/$package.json.js +1 -0
  11. package/dist/boilerplates/@batijs/fastify/files/fastify-entry.ts +20 -0
  12. package/dist/boilerplates/@batijs/h3/files/$package.json.js +2 -1
  13. package/dist/boilerplates/@batijs/h3/files/h3-entry.ts +20 -0
  14. package/dist/boilerplates/@batijs/hattip/files/$package.json.js +6 -5
  15. package/dist/boilerplates/@batijs/hattip/files/hattip-entry.ts +20 -0
  16. package/dist/boilerplates/@batijs/hono/files/$package.json.js +3 -2
  17. package/dist/boilerplates/@batijs/hono/files/hono-entry.ts +20 -0
  18. package/dist/boilerplates/@batijs/lucia-auth/files/$.env.js +23 -0
  19. package/dist/boilerplates/@batijs/lucia-auth/files/$README.md.js +29 -0
  20. package/dist/boilerplates/@batijs/lucia-auth/files/$package.json.js +133 -0
  21. package/dist/boilerplates/@batijs/lucia-auth/files/database/auth-actions.ts +54 -0
  22. package/dist/boilerplates/@batijs/lucia-auth/files/database/schema/auth.ts +41 -0
  23. package/dist/boilerplates/@batijs/lucia-auth/files/database/sqliteDb.ts +30 -0
  24. package/dist/boilerplates/@batijs/lucia-auth/files/lib/lucia-auth.ts +96 -0
  25. package/dist/boilerplates/@batijs/lucia-auth/files/pages/login/+guard.ts +11 -0
  26. package/dist/boilerplates/@batijs/lucia-auth/files/pages/login/style.css +94 -0
  27. package/dist/boilerplates/@batijs/lucia-auth/files/server/lucia-auth-handlers.ts +344 -0
  28. package/dist/boilerplates/@batijs/lucia-auth/files/vike.d.ts +11 -0
  29. package/dist/boilerplates/@batijs/lucia-auth/types/database/auth-actions.d.ts +9 -0
  30. package/dist/boilerplates/@batijs/lucia-auth/types/database/schema/auth.d.ts +167 -0
  31. package/dist/boilerplates/@batijs/lucia-auth/types/database/sqliteDb.d.ts +2 -0
  32. package/dist/boilerplates/@batijs/lucia-auth/types/lib/lucia-auth.d.ts +43 -0
  33. package/dist/boilerplates/@batijs/lucia-auth/types/pages/login/+guard.d.ts +3 -0
  34. package/dist/boilerplates/@batijs/lucia-auth/types/server/lucia-auth-handlers.d.ts +46 -0
  35. package/dist/boilerplates/@batijs/react/files/layouts/LayoutDefault.tsx +1 -0
  36. package/dist/boilerplates/@batijs/react/files/pages/+config.ts +1 -1
  37. package/dist/boilerplates/@batijs/react-lucia-auth/files/pages/login/+Page.tsx +96 -0
  38. package/dist/boilerplates/@batijs/react-lucia-auth/types/pages/login/+Page.d.ts +2 -0
  39. package/dist/boilerplates/@batijs/shared-server/files/server/create-todo-handler.ts +3 -3
  40. package/dist/boilerplates/@batijs/shared-todo/files/pages/todo/+data.ts +3 -3
  41. package/dist/boilerplates/@batijs/solid/files/$package.json.js +1 -1
  42. package/dist/boilerplates/@batijs/solid/files/layouts/LayoutDefault.tsx +1 -0
  43. package/dist/boilerplates/@batijs/solid/files/pages/+config.ts +1 -1
  44. package/dist/boilerplates/@batijs/solid-lucia-auth/files/pages/login/+Page.tsx +96 -0
  45. package/dist/boilerplates/@batijs/solid-lucia-auth/types/pages/login/+Page.d.ts +2 -0
  46. package/dist/boilerplates/@batijs/telefunc/files/pages/todo/TodoList.telefunc.ts +3 -3
  47. package/dist/boilerplates/@batijs/trpc/files/trpc/server.ts +3 -3
  48. package/dist/boilerplates/@batijs/ts-rest/files/server/ts-rest-handler.ts +3 -3
  49. package/dist/boilerplates/@batijs/vercel/files/$package.json.js +2 -2
  50. package/dist/boilerplates/@batijs/vue/files/layouts/LayoutDefault.vue +2 -0
  51. package/dist/boilerplates/@batijs/vue/files/pages/+config.ts +1 -1
  52. package/dist/boilerplates/@batijs/vue-lucia-auth/files/pages/login/+Page.vue +87 -0
  53. package/dist/boilerplates/boilerplates.json +59 -0
  54. package/dist/index.js +2 -2
  55. package/package.json +5 -5
  56. package/dist/boilerplates/@batijs/drizzle/types/database/db.d.ts +0 -2
  57. /package/dist/boilerplates/@batijs/drizzle/files/database/{schema.ts → schema/todos.ts} +0 -0
  58. /package/dist/boilerplates/@batijs/drizzle/types/database/{schema.d.ts → schema/todos.d.ts} +0 -0
@@ -0,0 +1,30 @@
1
+ /*# BATI include-if-imported #*/
2
+ import sqlite, { type Database } from "better-sqlite3";
3
+
4
+ export const sqliteDb: Database = sqlite(":memory:");
5
+
6
+ /**
7
+ * SQLite Schema
8
+ *
9
+ * @link {@see https://lucia-auth.com/database/sqlite#schema}
10
+ */
11
+ sqliteDb.exec(`CREATE TABLE IF NOT EXISTS users (
12
+ id TEXT NOT NULL PRIMARY KEY,
13
+ username TEXT NOT NULL UNIQUE,
14
+ password TEXT
15
+ )`);
16
+
17
+ sqliteDb.exec(`CREATE TABLE IF NOT EXISTS oauth_accounts (
18
+ provider_id TEXT NOT NULL,
19
+ provider_user_id INTEGER NOT NULL,
20
+ user_id TEXT NOT NULL,
21
+ PRIMARY KEY (provider_id, provider_user_id),
22
+ FOREIGN KEY (user_id) REFERENCES users(id) ON UPDATE cascade ON DELETE cascade
23
+ )`);
24
+
25
+ sqliteDb.exec(`CREATE TABLE IF NOT EXISTS sessions (
26
+ id TEXT NOT NULL PRIMARY KEY,
27
+ expires_at INTEGER NOT NULL,
28
+ user_id TEXT NOT NULL,
29
+ FOREIGN KEY (user_id) REFERENCES users(id) ON UPDATE cascade ON DELETE cascade
30
+ )`);
@@ -0,0 +1,96 @@
1
+ import "dotenv/config";
2
+ import { Lucia } from "lucia";
3
+ import { BetterSqlite3Adapter } from "@lucia-auth/adapter-sqlite";
4
+ import { GitHub } from "arctic";
5
+ import { sqliteDb } from "../database/sqliteDb";
6
+ import { DrizzleSQLiteAdapter } from "@lucia-auth/adapter-drizzle";
7
+ import { drizzleDb } from "@batijs/drizzle/database/drizzleDb";
8
+ import { sessionTable, userTable } from "../database/schema/auth";
9
+
10
+ /**
11
+ * Polyfill needed if you're using Node.js 18 or below
12
+ *
13
+ * @link {@see https://lucia-auth.com/getting-started/#polyfill}
14
+ */
15
+ if (!globalThis.crypto) {
16
+ Object.defineProperty(globalThis, "crypto", {
17
+ value: await import("node:crypto").then((crypto) => crypto.webcrypto as Crypto),
18
+ writable: false,
19
+ configurable: true,
20
+ });
21
+ }
22
+
23
+ /**
24
+ * Database setup
25
+ *
26
+ * @link {@see https://lucia-auth.com/database/#database-setup}
27
+ **/
28
+ const adapter = BATI.has("drizzle")
29
+ ? new DrizzleSQLiteAdapter(drizzleDb, sessionTable, userTable)
30
+ : new BetterSqlite3Adapter(sqliteDb, {
31
+ user: "users",
32
+ session: "sessions",
33
+ });
34
+
35
+ /**
36
+ * Initialize Lucia
37
+ *
38
+ * @link {@see https://lucia-auth.com/getting-started/#initialize-lucia}
39
+ */
40
+ export const lucia = new Lucia(adapter, {
41
+ /**
42
+ * Lucia Configuration
43
+ *
44
+ * @link {@see https://lucia-auth.com/basics/configuration}
45
+ */
46
+ sessionCookie: {
47
+ attributes: {
48
+ secure: process.env.NODE_ENV === "production",
49
+ },
50
+ },
51
+ getUserAttributes: (attributes) => {
52
+ return {
53
+ username: attributes.username,
54
+ };
55
+ },
56
+ });
57
+
58
+ /**
59
+ * Initialize OAuth provider
60
+ *
61
+ * @link {@see https://lucia-auth.com/guides/oauth/basics#initialize-oauth-provider}
62
+ */
63
+ export const github = new GitHub(process.env.GITHUB_CLIENT_ID as string, process.env.GITHUB_CLIENT_SECRET as string);
64
+
65
+ /**
66
+ * Define user attributes
67
+ *
68
+ * @link {@see https://lucia-auth.com/basics/users#define-user-attributes}
69
+ */
70
+ declare module "lucia" {
71
+ interface Register {
72
+ Lucia: typeof lucia;
73
+ DatabaseUserAttributes: Omit<DatabaseUser, "id">;
74
+ }
75
+ }
76
+
77
+ export interface DatabaseUser {
78
+ id: string;
79
+ username: string;
80
+ password?: string;
81
+ }
82
+
83
+ export interface DatabaseOAuthAccount {
84
+ provider_id: string;
85
+ provider_user_id: string;
86
+ /*{ @if (it.BATI.has("drizzle")) }*/
87
+ userId: string;
88
+ /*{ #else }*/
89
+ user_id: string;
90
+ /*{ /if }*/
91
+ }
92
+
93
+ export interface GitHubUser {
94
+ id: number;
95
+ login: string; // username
96
+ }
@@ -0,0 +1,11 @@
1
+ // https://vike.dev/guard
2
+ import { redirect } from "vike/abort";
3
+ import type { GuardAsync } from "vike/types";
4
+
5
+ const guard: GuardAsync = async (pageContext): ReturnType<GuardAsync> => {
6
+ if (pageContext.user) {
7
+ throw redirect("/");
8
+ }
9
+ };
10
+
11
+ export { guard };
@@ -0,0 +1,94 @@
1
+ header {
2
+ font-size: 28px;
3
+ font-weight: 600;
4
+ text-align: center;
5
+ }
6
+ .form {
7
+ position: absolute;
8
+ max-width: 430px;
9
+ width: 100%;
10
+ }
11
+ .form .field {
12
+ position: relative;
13
+ height: 50px;
14
+ width: 100%;
15
+ margin-top: 20px;
16
+ border-radius: 6px;
17
+ }
18
+ .field input,
19
+ .button-field {
20
+ height: 100%;
21
+ width: 100%;
22
+ border: none;
23
+ font-size: 16px;
24
+ font-weight: 400;
25
+ border-radius: 6px;
26
+ }
27
+ .button-group {
28
+ display: flex;
29
+ }
30
+ .login-button {
31
+ background-color: #0171d3e8;
32
+ }
33
+ .login-button:hover {
34
+ background-color: #016dcb;
35
+ }
36
+ .signup-button {
37
+ background-color: #d30101f6;
38
+ }
39
+ .signup-button:hover {
40
+ background-color: #cb010b;
41
+ }
42
+ .field input {
43
+ outline: none;
44
+ padding: 0 15px;
45
+ border: 1px solid#CACACA;
46
+ }
47
+ .field input:focus {
48
+ border-bottom-width: 2px;
49
+ }
50
+ .field button {
51
+ color: #fff;
52
+ margin: 0 2px;
53
+ transition: all 0.3s ease;
54
+ cursor: pointer;
55
+ }
56
+ .field-error {
57
+ display: block;
58
+ width: 100%;
59
+ margin-top: 0.25rem;
60
+ font-size: 85%;
61
+ color: #dc3545;
62
+ }
63
+ .media-options a {
64
+ display: flex;
65
+ align-items: center;
66
+ justify-content: center;
67
+ }
68
+ a.github {
69
+ color: #fff;
70
+ background-color: #000;
71
+ }
72
+ a.github .github-icon {
73
+ height: 28px;
74
+ width: 28px;
75
+ color: #000;
76
+ font-size: 20px;
77
+ border-radius: 50%;
78
+ display: flex;
79
+ align-items: center;
80
+ justify-content: center;
81
+ background-color: #fff;
82
+ }
83
+ .github-icon {
84
+ position: absolute;
85
+ top: 50%;
86
+ left: 15px;
87
+ transform: translateY(-50%);
88
+ }
89
+
90
+ @media screen and (max-width: 400px) {
91
+ .form {
92
+ padding: 20px 10px;
93
+ }
94
+ }
@@ -0,0 +1,344 @@
1
+ import type { Session, User } from "lucia";
2
+ import { generateId, Scrypt, verifyRequestOrigin } from "lucia";
3
+ import type { DatabaseOAuthAccount, DatabaseUser, GitHubUser } from "../lib/lucia-auth";
4
+ import { github, lucia } from "../lib/lucia-auth";
5
+ import { SqliteError } from "better-sqlite3";
6
+ import { sqliteDb } from "../database/sqliteDb";
7
+ import { generateState, OAuth2RequestError } from "arctic";
8
+ import { parse, serialize } from "cookie";
9
+ import { drizzleDb } from "@batijs/drizzle/database/drizzleDb";
10
+ import { oauthAccountTable, userTable } from "../database/schema/auth";
11
+ import { getExistingAccount, getExistingUser, validateInput } from "../database/auth-actions";
12
+
13
+ /**
14
+ * CSRF protection middleware
15
+ *
16
+ * @link {@see https://lucia-auth.com/guides/validate-session-cookies/}
17
+ */
18
+ export function luciaCsrfMiddleware<Context extends Record<string | number | symbol, unknown>>(
19
+ request: Request,
20
+ _context?: Context,
21
+ ): Response | undefined {
22
+ if (request.method === "GET") {
23
+ return;
24
+ }
25
+ if (!BATI_TEST) {
26
+ const originHeader = request.headers.get("Origin") ?? null;
27
+ const hostHeader = request.headers.get("Host") ?? null;
28
+
29
+ if (!originHeader || !hostHeader || !verifyRequestOrigin(originHeader, [hostHeader])) {
30
+ return new Response("Forbidden Request", {
31
+ status: 403,
32
+ });
33
+ }
34
+ }
35
+ }
36
+
37
+ /**
38
+ * Validate session cookies middleware
39
+ *
40
+ * @link {@see https://lucia-auth.com/guides/validate-session-cookies/}
41
+ */
42
+ export async function luciaAuthMiddleware<Context extends Record<string | number | symbol, unknown>>(
43
+ request: Request,
44
+ context: Context & { session?: Session | null; user?: User | null },
45
+ ): Promise<void> {
46
+ const sessionId = lucia.readSessionCookie(request.headers.get("cookie") ?? "");
47
+
48
+ if (!sessionId) {
49
+ context.user = null;
50
+ context.session = null;
51
+ } else {
52
+ const { session, user } = await lucia.validateSession(sessionId);
53
+
54
+ if (session?.fresh) {
55
+ request.headers.append("Set-Cookie", lucia.createSessionCookie(session.id).serialize());
56
+ }
57
+ if (!session) {
58
+ request.headers.append("Set-Cookie", lucia.createBlankSessionCookie().serialize());
59
+ }
60
+
61
+ context.session = session;
62
+ context.user = user;
63
+ }
64
+ }
65
+
66
+ /**
67
+ * Register user handler
68
+ *
69
+ * @link {@see https://lucia-auth.com/guides/email-and-password/basics#register-user}
70
+ */
71
+ export async function luciaAuthSignupHandler<Context extends Record<string | number | symbol, unknown>>(
72
+ request: Request,
73
+ _context?: Context,
74
+ ): Promise<Response> {
75
+ const body = (await request.json()) as { username: string; password: string };
76
+ const username = body.username ?? "";
77
+ const password = body.password ?? "";
78
+
79
+ const validated = validateInput(username, password);
80
+
81
+ if (!validated.success) {
82
+ return new Response(JSON.stringify({ error: validated.error }), {
83
+ status: 422,
84
+ headers: {
85
+ "content-type": "application/json",
86
+ },
87
+ });
88
+ }
89
+
90
+ /**
91
+ * A pure JS implementation of Scrypt.
92
+ * It's portable but slower than implementations based on native code.
93
+ *
94
+ * @link {@see https://lucia-auth.com/reference/main/Scrypt}
95
+ * @link {@see https://lucia-auth.com/guides/email-and-password/basics#hashing-passwords}
96
+ */
97
+ const scrypt = new Scrypt();
98
+ const passwordHash = await scrypt.hash(password);
99
+
100
+ const userId = generateId(15);
101
+
102
+ try {
103
+ if (BATI.has("drizzle")) {
104
+ drizzleDb.insert(userTable).values({ id: userId, username, password: passwordHash }).run();
105
+ } else {
106
+ sqliteDb
107
+ .prepare("INSERT INTO users (id, username, password) VALUES(?, ?, ?)")
108
+ .run(userId, username, passwordHash);
109
+ }
110
+
111
+ const session = await lucia.createSession(userId, {});
112
+
113
+ return new Response(JSON.stringify({ status: "success" }), {
114
+ status: 200,
115
+ headers: {
116
+ "content-type": "application/json",
117
+ "set-cookie": lucia.createSessionCookie(session.id).serialize(),
118
+ },
119
+ });
120
+ } catch (error) {
121
+ if (error instanceof SqliteError && error.code === "SQLITE_CONSTRAINT_UNIQUE") {
122
+ return new Response(JSON.stringify({ error: { username: "Username already in use" } }), {
123
+ status: 422,
124
+ headers: {
125
+ "content-type": "application/json",
126
+ },
127
+ });
128
+ }
129
+
130
+ return new Response(JSON.stringify({ error: { invalid: "An unknown error has occurred" } }), {
131
+ status: 500,
132
+ headers: {
133
+ "content-type": "application/json",
134
+ },
135
+ });
136
+ }
137
+ }
138
+
139
+ /**
140
+ * Sign in user handler
141
+ *
142
+ * @link {@see https://lucia-auth.com/guides/email-and-password/basics#sign-in-user}
143
+ */
144
+ export async function luciaAuthLoginHandler<Context extends Record<string | number | symbol, unknown>>(
145
+ request: Request,
146
+ _context?: Context,
147
+ ): Promise<Response> {
148
+ const body = (await request.json()) as { username: string; password: string };
149
+ const username = body.username ?? "";
150
+ const password = body.password ?? "";
151
+
152
+ const validated = validateInput(username, password);
153
+
154
+ if (!validated.success) {
155
+ return new Response(JSON.stringify({ error: validated.error }), {
156
+ status: 422,
157
+ headers: {
158
+ "content-type": "application/json",
159
+ },
160
+ });
161
+ }
162
+
163
+ const existingUser = getExistingUser(username) as DatabaseUser | undefined;
164
+ if (!existingUser) {
165
+ return new Response(JSON.stringify({ error: { invalid: "Incorrect username or password" } }), {
166
+ status: 422,
167
+ headers: {
168
+ "content-type": "application/json",
169
+ },
170
+ });
171
+ }
172
+
173
+ const scrypt = new Scrypt();
174
+ const validPassword = existingUser.password && (await scrypt.verify(existingUser.password, password));
175
+
176
+ if (!validPassword) {
177
+ return new Response(JSON.stringify({ error: { invalid: "Incorrect username or password" } }), {
178
+ status: 422,
179
+ headers: {
180
+ "content-type": "application/json",
181
+ },
182
+ });
183
+ }
184
+
185
+ const session = await lucia.createSession(existingUser.id, {});
186
+
187
+ return new Response(JSON.stringify({ status: "success" }), {
188
+ status: 200,
189
+ headers: {
190
+ "content-type": "application/json",
191
+ "set-cookie": lucia.createSessionCookie(session.id).serialize(),
192
+ },
193
+ });
194
+ }
195
+
196
+ /**
197
+ * Log out user handler
198
+ */
199
+ export async function luciaAuthLogoutHandler<Context extends Record<string | number | symbol, unknown>>(
200
+ _request: Request,
201
+ context: Context & { session?: Session | null },
202
+ ): Promise<Response> {
203
+ const session = context.session ?? null;
204
+
205
+ if (!session) {
206
+ return new Response("Unauthorized Request", {
207
+ status: 401,
208
+ });
209
+ }
210
+ /**
211
+ * Invalidate sessions
212
+ *
213
+ * @link {@see https://lucia-auth.com/basics/sessions#invalidate-sessions}
214
+ */
215
+ await lucia.invalidateSession(session.id);
216
+
217
+ /**
218
+ * Delete session cookie
219
+ *
220
+ * @link {@see https://lucia-auth.com/basics/sessions#delete-session-cookie}
221
+ */
222
+ return new Response(JSON.stringify({ status: "success" }), {
223
+ status: 200,
224
+ headers: {
225
+ "set-cookie": lucia.createBlankSessionCookie().serialize(),
226
+ },
227
+ });
228
+ }
229
+
230
+ /**
231
+ * Github OAuth authorization handler
232
+ *
233
+ * @link {@see https://lucia-auth.com/guides/oauth/basics#creating-authorization-url}
234
+ */
235
+ export async function luciaGithubLoginHandler<Context extends Record<string | number | symbol, unknown>>(
236
+ _request: Request,
237
+ _context?: Context,
238
+ ): Promise<Response> {
239
+ const state = generateState();
240
+ const url = await github.createAuthorizationURL(state);
241
+
242
+ return new Response(null, {
243
+ status: 302,
244
+ headers: {
245
+ Location: url.toString(),
246
+ "set-cookie": serialize("github_oauth_state", state, {
247
+ path: "/",
248
+ secure: process.env.NODE_ENV === "production",
249
+ httpOnly: true,
250
+ maxAge: 60 * 10,
251
+ sameSite: "lax",
252
+ }),
253
+ },
254
+ });
255
+ }
256
+
257
+ /**
258
+ * Github OAuth validate callback handler
259
+ *
260
+ * @link {@see https://lucia-auth.com/guides/oauth/basics#validate-callback}
261
+ */
262
+ export async function luciaGithubCallbackHandler<Context extends Record<string | number | symbol, unknown>>(
263
+ request: Request,
264
+ _context?: Context,
265
+ ): Promise<Response> {
266
+ const cookies = parse(request.headers.get("cookie") ?? "");
267
+ const params = new URL(request.url).searchParams;
268
+ const code = params.get("code");
269
+ const state = params.get("state");
270
+ const storedState = cookies.github_oauth_state ?? null;
271
+
272
+ if (!code || !state || !storedState || state !== storedState) {
273
+ return new Response("Unauthorized Request", {
274
+ status: 401,
275
+ });
276
+ }
277
+
278
+ try {
279
+ const tokens = await github.validateAuthorizationCode(code);
280
+ const githubUserResponse = await fetch("https://api.github.com/user", {
281
+ headers: {
282
+ Authorization: `Bearer ${tokens.accessToken}`,
283
+ },
284
+ });
285
+ const githubUser = (await githubUserResponse.json()) as GitHubUser;
286
+
287
+ const existingAccount = getExistingAccount("github", githubUser.id) as DatabaseOAuthAccount | undefined;
288
+
289
+ if (existingAccount) {
290
+ const session = await lucia.createSession(
291
+ BATI.has("drizzle") ? existingAccount.userId : existingAccount.user_id,
292
+ {},
293
+ );
294
+ return new Response(null, {
295
+ status: 302,
296
+ headers: {
297
+ Location: "/",
298
+ "set-cookie": lucia.createSessionCookie(session.id).serialize(),
299
+ },
300
+ });
301
+ }
302
+
303
+ const userId = generateId(15);
304
+
305
+ if (BATI.has("drizzle")) {
306
+ await drizzleDb.transaction(async (tx) => {
307
+ await tx.insert(userTable).values({ id: userId, username: githubUser.login });
308
+ await tx.insert(oauthAccountTable).values({ providerId: "github", providerUserId: githubUser.id, userId });
309
+ });
310
+ } else {
311
+ sqliteDb.transaction(() => {
312
+ sqliteDb.prepare("INSERT INTO users (id, username) VALUES (?, ?)").run(userId, githubUser.login);
313
+ sqliteDb
314
+ .prepare("INSERT INTO oauth_accounts (provider_id, provider_user_id, user_id) VALUES (?, ?, ?)")
315
+ .run("github", githubUser.id, userId);
316
+ });
317
+ }
318
+
319
+ const session = await lucia.createSession(userId, {});
320
+
321
+ return new Response(null, {
322
+ status: 302,
323
+ headers: {
324
+ Location: "/",
325
+ "set-cookie": lucia.createSessionCookie(session.id).serialize(),
326
+ },
327
+ });
328
+ } catch (error) {
329
+ if (error instanceof OAuth2RequestError && error.message === "bad_verification_code") {
330
+ return new Response(JSON.stringify({ error: error.message }), {
331
+ status: 400,
332
+ headers: {
333
+ "content-type": "application/json",
334
+ },
335
+ });
336
+ }
337
+ return new Response(JSON.stringify({ error: error }), {
338
+ status: 500,
339
+ headers: {
340
+ "content-type": "application/json",
341
+ },
342
+ });
343
+ }
344
+ }
@@ -0,0 +1,11 @@
1
+ import type { User } from "lucia";
2
+
3
+ declare global {
4
+ namespace Vike {
5
+ interface PageContext {
6
+ user?: User;
7
+ }
8
+ }
9
+ }
10
+
11
+ export {};
@@ -0,0 +1,9 @@
1
+ export declare function getExistingUser(username: string): unknown;
2
+ export declare function getExistingAccount(providerId: string, providerUserId: number): unknown;
3
+ export declare function validateInput(username: string | null, password: string | null): {
4
+ error: {
5
+ username: string | null;
6
+ password: string | null;
7
+ };
8
+ success: boolean;
9
+ };