diff --git a/astro.config.mjs b/astro.config.mjs
index 2200e93..a7248d8 100644
--- a/astro.config.mjs
+++ b/astro.config.mjs
@@ -6,20 +6,25 @@ import remarkMath from 'remark-math'
import yaml from '@rollup/plugin-yaml'
+import node from '@astrojs/node'
+
// https://astro.build/config
export default defineConfig({
vite: {
plugins: [yaml()],
},
+
server: {
port: 3000,
},
+
markdown: {
remarkPlugins: [remarkMath],
shikiConfig: {
theme: 'github-light',
},
},
+
integrations: [
preact({
compat: true,
@@ -28,5 +33,10 @@ export default defineConfig({
remarkPlugins: [remarkMath],
}),
],
- output: 'static',
+
+ output: 'server',
+
+ adapter: node({
+ mode: 'standalone',
+ }),
})
diff --git a/bun.lockb b/bun.lockb
index a74191b..507ac3e 100755
Binary files a/bun.lockb and b/bun.lockb differ
diff --git a/drizzle.config.ts b/drizzle.config.ts
new file mode 100644
index 0000000..cc9c855
--- /dev/null
+++ b/drizzle.config.ts
@@ -0,0 +1,11 @@
+import 'dotenv/config'
+import { defineConfig } from 'drizzle-kit'
+
+export default defineConfig({
+ out: './drizzle',
+ schema: './src/db/schema.ts',
+ dialect: 'sqlite',
+ dbCredentials: {
+ url: process.env.DB_FILE_NAME!,
+ },
+})
diff --git a/drizzle/0000_violet_agent_zero.sql b/drizzle/0000_violet_agent_zero.sql
new file mode 100644
index 0000000..86e0ba6
--- /dev/null
+++ b/drizzle/0000_violet_agent_zero.sql
@@ -0,0 +1,82 @@
+CREATE TABLE `accounts` (
+ `user_id` text,
+ `provider` text NOT NULL,
+ `username` text NOT NULL,
+ FOREIGN KEY (`user_id`) REFERENCES `user`(`id`) ON UPDATE no action ON DELETE no action
+);
+--> statement-breakpoint
+CREATE TABLE `appunti` (
+ `user_id` text,
+ `hash` text NOT NULL,
+ `link` text,
+ `visibility` text NOT NULL,
+ `title` text NOT NULL,
+ `description` text,
+ `tags` text NOT NULL,
+ FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON UPDATE no action ON DELETE no action
+);
+--> statement-breakpoint
+CREATE TABLE `poisson_requests` (
+ `user_id` text,
+ `request_type` text NOT NULL,
+ `comments` text,
+ FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON UPDATE no action ON DELETE no action
+);
+--> statement-breakpoint
+CREATE TABLE `users` (
+ `id` text,
+ `username` text NOT NULL,
+ `full_name` text,
+ `email` text,
+ FOREIGN KEY (`id`) REFERENCES `user`(`id`) ON UPDATE no action ON DELETE no action
+);
+--> statement-breakpoint
+CREATE TABLE `account` (
+ `id` text PRIMARY KEY NOT NULL,
+ `account_id` text NOT NULL,
+ `provider_id` text NOT NULL,
+ `user_id` text NOT NULL,
+ `access_token` text,
+ `refresh_token` text,
+ `id_token` text,
+ `access_token_expires_at` integer,
+ `refresh_token_expires_at` integer,
+ `scope` text,
+ `password` text,
+ `created_at` integer NOT NULL,
+ `updated_at` integer NOT NULL,
+ FOREIGN KEY (`user_id`) REFERENCES `user`(`id`) ON UPDATE no action ON DELETE cascade
+);
+--> statement-breakpoint
+CREATE TABLE `session` (
+ `id` text PRIMARY KEY NOT NULL,
+ `expires_at` integer NOT NULL,
+ `token` text NOT NULL,
+ `created_at` integer NOT NULL,
+ `updated_at` integer NOT NULL,
+ `ip_address` text,
+ `user_agent` text,
+ `user_id` text NOT NULL,
+ FOREIGN KEY (`user_id`) REFERENCES `user`(`id`) ON UPDATE no action ON DELETE cascade
+);
+--> statement-breakpoint
+CREATE UNIQUE INDEX `session_token_unique` ON `session` (`token`);--> statement-breakpoint
+CREATE TABLE `user` (
+ `id` text PRIMARY KEY NOT NULL,
+ `name` text NOT NULL,
+ `email` text NOT NULL,
+ `email_verified` integer NOT NULL,
+ `image` text,
+ `created_at` integer NOT NULL,
+ `updated_at` integer NOT NULL
+);
+--> statement-breakpoint
+CREATE UNIQUE INDEX `user_email_unique` ON `user` (`email`);--> statement-breakpoint
+CREATE TABLE `verification` (
+ `id` text PRIMARY KEY NOT NULL,
+ `identifier` text NOT NULL,
+ `value` text NOT NULL,
+ `expires_at` integer NOT NULL,
+ `created_at` integer,
+ `updated_at` integer
+);
diff --git a/drizzle/meta/0000_snapshot.json b/drizzle/meta/0000_snapshot.json
new file mode 100644
index 0000000..7c6944a
--- /dev/null
+++ b/drizzle/meta/0000_snapshot.json
@@ -0,0 +1,555 @@
+{
+ "version": "6",
+ "dialect": "sqlite",
+ "id": "84352768-6c24-4412-9d9e-8a3c756d31b1",
+ "prevId": "00000000-0000-0000-0000-000000000000",
+ "tables": {
+ "accounts": {
+ "name": "accounts",
+ "columns": {
+ "user_id": {
+ "name": "user_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "provider": {
+ "name": "provider",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "username": {
+ "name": "username",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {
+ "accounts_user_id_user_id_fk": {
+ "name": "accounts_user_id_user_id_fk",
+ "tableFrom": "accounts",
+ "tableTo": "user",
+ "columnsFrom": [
+ "user_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "appunti": {
+ "name": "appunti",
+ "columns": {
+ "user_id": {
+ "name": "user_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "hash": {
+ "name": "hash",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "link": {
+ "name": "link",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "visibility": {
+ "name": "visibility",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "title": {
+ "name": "title",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "description": {
+ "name": "description",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "tags": {
+ "name": "tags",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {
+ "appunti_user_id_users_id_fk": {
+ "name": "appunti_user_id_users_id_fk",
+ "tableFrom": "appunti",
+ "tableTo": "users",
+ "columnsFrom": [
+ "user_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "poisson_requests": {
+ "name": "poisson_requests",
+ "columns": {
+ "user_id": {
+ "name": "user_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "request_type": {
+ "name": "request_type",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "comments": {
+ "name": "comments",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {
+ "poisson_requests_user_id_users_id_fk": {
+ "name": "poisson_requests_user_id_users_id_fk",
+ "tableFrom": "poisson_requests",
+ "tableTo": "users",
+ "columnsFrom": [
+ "user_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "users": {
+ "name": "users",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "username": {
+ "name": "username",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "full_name": {
+ "name": "full_name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "email": {
+ "name": "email",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {
+ "users_id_user_id_fk": {
+ "name": "users_id_user_id_fk",
+ "tableFrom": "users",
+ "tableTo": "user",
+ "columnsFrom": [
+ "id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "account": {
+ "name": "account",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "account_id": {
+ "name": "account_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "provider_id": {
+ "name": "provider_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "user_id": {
+ "name": "user_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "access_token": {
+ "name": "access_token",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "refresh_token": {
+ "name": "refresh_token",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "id_token": {
+ "name": "id_token",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "access_token_expires_at": {
+ "name": "access_token_expires_at",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "refresh_token_expires_at": {
+ "name": "refresh_token_expires_at",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "scope": {
+ "name": "scope",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "password": {
+ "name": "password",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {
+ "account_user_id_user_id_fk": {
+ "name": "account_user_id_user_id_fk",
+ "tableFrom": "account",
+ "tableTo": "user",
+ "columnsFrom": [
+ "user_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "session": {
+ "name": "session",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "expires_at": {
+ "name": "expires_at",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "token": {
+ "name": "token",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "ip_address": {
+ "name": "ip_address",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "user_agent": {
+ "name": "user_agent",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "user_id": {
+ "name": "user_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ }
+ },
+ "indexes": {
+ "session_token_unique": {
+ "name": "session_token_unique",
+ "columns": [
+ "token"
+ ],
+ "isUnique": true
+ }
+ },
+ "foreignKeys": {
+ "session_user_id_user_id_fk": {
+ "name": "session_user_id_user_id_fk",
+ "tableFrom": "session",
+ "tableTo": "user",
+ "columnsFrom": [
+ "user_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "user": {
+ "name": "user",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "name": {
+ "name": "name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "email": {
+ "name": "email",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "email_verified": {
+ "name": "email_verified",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "image": {
+ "name": "image",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ }
+ },
+ "indexes": {
+ "user_email_unique": {
+ "name": "user_email_unique",
+ "columns": [
+ "email"
+ ],
+ "isUnique": true
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "verification": {
+ "name": "verification",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "identifier": {
+ "name": "identifier",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "value": {
+ "name": "value",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "expires_at": {
+ "name": "expires_at",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ }
+ },
+ "views": {},
+ "enums": {},
+ "_meta": {
+ "schemas": {},
+ "tables": {},
+ "columns": {}
+ },
+ "internal": {
+ "indexes": {}
+ }
+}
\ No newline at end of file
diff --git a/drizzle/meta/_journal.json b/drizzle/meta/_journal.json
new file mode 100644
index 0000000..913f43e
--- /dev/null
+++ b/drizzle/meta/_journal.json
@@ -0,0 +1,13 @@
+{
+ "version": "7",
+ "dialect": "sqlite",
+ "entries": [
+ {
+ "idx": 0,
+ "version": "6",
+ "when": 1749233567397,
+ "tag": "0000_violet_agent_zero",
+ "breakpoints": true
+ }
+ ]
+}
\ No newline at end of file
diff --git a/package.json b/package.json
index bf80598..8aa0c01 100644
--- a/package.json
+++ b/package.json
@@ -20,11 +20,16 @@
"@fontsource/source-code-pro": "^5.0.16",
"@fontsource/source-sans-pro": "^5.0.8",
"@fontsource/space-mono": "^5.0.20",
+ "@libsql/client": "^0.15.8",
"@phosphor-icons/core": "^2.1.1",
"@phosphor-icons/react": "^2.1.7",
"@preact/signals": "^1.3.0",
"@types/jsdom": "^21.1.7",
"astro": "5.1.0",
+ "better-auth": "^1.2.8",
+ "better-sqlite3": "^11.10.0",
+ "dotenv": "^16.5.0",
+ "drizzle-orm": "^0.44.2",
"fuse.js": "^7.0.0",
"katex": "^0.16.9",
"lucide-static": "^0.468.0",
@@ -36,6 +41,7 @@
"@astrojs/mdx": "4.0.2",
"@rollup/plugin-yaml": "^4.1.2",
"@types/katex": "^0.16.7",
+ "drizzle-kit": "^0.31.1",
"jsdom": "^24.1.1",
"linkedom": "^0.18.4",
"npm-run-all": "^4.1.5",
diff --git a/src/auth.ts b/src/auth.ts
new file mode 100644
index 0000000..bfde777
--- /dev/null
+++ b/src/auth.ts
@@ -0,0 +1,28 @@
+import { betterAuth } from 'better-auth'
+import { genericOAuth } from 'better-auth/plugins'
+import { drizzleAdapter } from 'better-auth/adapters/drizzle'
+import * as authSchema from '@/db/auth-schema'
+import db from '@/db'
+
+export const auth = betterAuth({
+ database: drizzleAdapter(db, {
+ provider: 'sqlite',
+ schema: authSchema,
+ }),
+ plugins: [
+ genericOAuth({
+ config: [
+ {
+ providerId: 'unipi',
+ clientId: process.env.OAUTH_CLIENT_ID!,
+ clientSecret: process.env.OAUTH_CLIENT_SECRET!,
+ scopes: process.env.OAUTH_SCOPES!.split(' '),
+ userInfoUrl: process.env.OAUTH_USER_INFO_URL!,
+ authorizationUrl: process.env.OAUTH_AUTH_URL!,
+ tokenUrl: `${process.env.OAUTH_TOKEN_HOST}${process.env.OAUTH_TOKEN_PATH}`,
+ redirectURI: process.env.OAUTH_REDIRECT_URL!,
+ },
+ ],
+ }),
+ ],
+})
diff --git a/src/client/auth-client.ts b/src/client/auth-client.ts
new file mode 100644
index 0000000..a134d33
--- /dev/null
+++ b/src/client/auth-client.ts
@@ -0,0 +1,5 @@
+import { createAuthClient } from 'better-auth/client'
+import { genericOAuthClient } from 'better-auth/client/plugins'
+export const authClient = createAuthClient({
+ plugins: [genericOAuthClient()],
+})
diff --git a/src/db/auth-schema.ts b/src/db/auth-schema.ts
new file mode 100644
index 0000000..f527aa8
--- /dev/null
+++ b/src/db/auth-schema.ts
@@ -0,0 +1,57 @@
+import { sqliteTable, text, integer } from 'drizzle-orm/sqlite-core'
+
+export const user = sqliteTable('user', {
+ id: text('id').primaryKey(),
+ name: text('name').notNull(),
+ email: text('email').notNull().unique(),
+ emailVerified: integer('email_verified', { mode: 'boolean' })
+ .$defaultFn(() => false)
+ .notNull(),
+ image: text('image'),
+ createdAt: integer('created_at', { mode: 'timestamp' })
+ .$defaultFn(() => /* @__PURE__ */ new Date())
+ .notNull(),
+ updatedAt: integer('updated_at', { mode: 'timestamp' })
+ .$defaultFn(() => /* @__PURE__ */ new Date())
+ .notNull(),
+})
+
+export const session = sqliteTable('session', {
+ id: text('id').primaryKey(),
+ expiresAt: integer('expires_at', { mode: 'timestamp' }).notNull(),
+ token: text('token').notNull().unique(),
+ createdAt: integer('created_at', { mode: 'timestamp' }).notNull(),
+ updatedAt: integer('updated_at', { mode: 'timestamp' }).notNull(),
+ ipAddress: text('ip_address'),
+ userAgent: text('user_agent'),
+ userId: text('user_id')
+ .notNull()
+ .references(() => user.id, { onDelete: 'cascade' }),
+})
+
+export const account = sqliteTable('account', {
+ id: text('id').primaryKey(),
+ accountId: text('account_id').notNull(),
+ providerId: text('provider_id').notNull(),
+ userId: text('user_id')
+ .notNull()
+ .references(() => user.id, { onDelete: 'cascade' }),
+ accessToken: text('access_token'),
+ refreshToken: text('refresh_token'),
+ idToken: text('id_token'),
+ accessTokenExpiresAt: integer('access_token_expires_at', { mode: 'timestamp' }),
+ refreshTokenExpiresAt: integer('refresh_token_expires_at', { mode: 'timestamp' }),
+ scope: text('scope'),
+ password: text('password'),
+ createdAt: integer('created_at', { mode: 'timestamp' }).notNull(),
+ updatedAt: integer('updated_at', { mode: 'timestamp' }).notNull(),
+})
+
+export const verification = sqliteTable('verification', {
+ id: text('id').primaryKey(),
+ identifier: text('identifier').notNull(),
+ value: text('value').notNull(),
+ expiresAt: integer('expires_at', { mode: 'timestamp' }).notNull(),
+ createdAt: integer('created_at', { mode: 'timestamp' }).$defaultFn(() => /* @__PURE__ */ new Date()),
+ updatedAt: integer('updated_at', { mode: 'timestamp' }).$defaultFn(() => /* @__PURE__ */ new Date()),
+})
diff --git a/src/db/index.ts b/src/db/index.ts
new file mode 100644
index 0000000..a3ce19f
--- /dev/null
+++ b/src/db/index.ts
@@ -0,0 +1,4 @@
+import 'dotenv/config'
+import { drizzle } from 'drizzle-orm/libsql'
+
+export default drizzle(process.env.DB_FILE_NAME!)
diff --git a/src/db/schema.ts b/src/db/schema.ts
new file mode 100644
index 0000000..c5315bf
--- /dev/null
+++ b/src/db/schema.ts
@@ -0,0 +1,33 @@
+import { sqliteTable, text } from 'drizzle-orm/sqlite-core'
+export * from './auth-schema'
+
+import { user } from './auth-schema'
+
+export const usersTable = sqliteTable('users', {
+ id: text('id').references(() => user.id),
+ username: text('username').notNull(),
+ fullName: text('full_name'),
+ email: text('email'),
+})
+
+export const accountsTable = sqliteTable('accounts', {
+ userId: text('user_id').references(() => user.id),
+ provider: text('provider').notNull(),
+ username: text('username').notNull(),
+})
+
+export const poissonRequestsTable = sqliteTable('poisson_requests', {
+ userId: text('user_id').references(() => usersTable.id),
+ requestType: text('request_type').notNull(), // "link" or "create"
+ comments: text('comments'), // contains username suggestions
+})
+
+export const appuntiTable = sqliteTable('appunti', {
+ userId: text('user_id').references(() => usersTable.id),
+ hash: text('hash').notNull(),
+ link: text('link'),
+ visibility: text('visibility').notNull(), // "public", "internal", "private"
+ title: text('title').notNull(),
+ description: text('description'),
+ tags: text('tags').notNull(), // Array of strings, e.g. ["#geometria-2", "#511aa", "#2017-18", "#frigerio"]
+})
diff --git a/src/env.d.ts b/src/env.d.ts
index acef35f..7691f9f 100644
--- a/src/env.d.ts
+++ b/src/env.d.ts
@@ -1,2 +1,10 @@
///
///
+
+declare namespace App {
+ // Note: 'import {} from ""' syntax does not work in .d.ts files.
+ interface Locals {
+ user: import('better-auth').User | null
+ session: import('better-auth').Session | null
+ }
+}
diff --git a/src/middleware.ts b/src/middleware.ts
new file mode 100644
index 0000000..e5f1b1f
--- /dev/null
+++ b/src/middleware.ts
@@ -0,0 +1,18 @@
+import { auth } from '@/auth'
+import { defineMiddleware } from 'astro:middleware'
+
+export const onRequest = defineMiddleware(async (context, next) => {
+ const isAuthed = await auth.api.getSession({
+ headers: context.request.headers,
+ })
+
+ if (isAuthed) {
+ context.locals.user = isAuthed.user
+ context.locals.session = isAuthed.session
+ } else {
+ context.locals.user = null
+ context.locals.session = null
+ }
+
+ return next()
+})
diff --git a/src/pages/api/auth/[...all].ts b/src/pages/api/auth/[...all].ts
new file mode 100644
index 0000000..04b18eb
--- /dev/null
+++ b/src/pages/api/auth/[...all].ts
@@ -0,0 +1,8 @@
+import { auth } from '@/auth'
+import type { APIRoute } from 'astro'
+
+export const ALL: APIRoute = async ctx => {
+ // If you want to use rate limiting, make sure to set the 'x-forwarded-for' header to the request headers from the context
+ // ctx.request.headers.set("x-forwarded-for", ctx.clientAddress);
+ return auth.handler(ctx.request)
+}
diff --git a/src/pages/login.astro b/src/pages/login.astro
index 7a2a4a0..fbbf60a 100644
--- a/src/pages/login.astro
+++ b/src/pages/login.astro
@@ -19,4 +19,13 @@ import PageLayout from '../layouts/PageLayout.astro'
Login
+
+
diff --git a/src/pages/profilo.astro b/src/pages/profilo.astro
new file mode 100644
index 0000000..55bc529
--- /dev/null
+++ b/src/pages/profilo.astro
@@ -0,0 +1,12 @@
+---
+const session = () => {
+ if (Astro.locals.session) {
+ return Astro.locals.session
+ } else {
+ // Redirect to login page if the user is not authenticated
+ return Astro.redirect('/login')
+ }
+}
+---
+
+Ciao prova profilo {JSON.stringify(Astro.locals.user)}