diff --git a/.env.example b/.env.example
index 25a0c494..d97f55e4 100644
--- a/.env.example
+++ b/.env.example
@@ -3,17 +3,15 @@
DATABASE_URL="postgresql://postgres.USERNAME:PASSWORD@LOCATION.pooler.supabase.com:PORT/postgres"
JWT_SECRET="AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+AAAAAAAAAAAAAAAAA=="
-# This section consists of simply splitting Section 1's DATABASE_URL
-DB_HOST="LOCATION.pooler.supabase.com"
-DB_USER="postgres.USERNAME"
-DB_PASSWORD="PASSWORD"
-DB_NAME="postgres"
-
# --------
-PUBLIC_SUPABASE_URL="https://AAAAAAAAAAAA.supabase.co"
-PUBLIC_SUPABASE_ANON_KEY="AAAAAAAAAA.AAAAAAAAA.AAAAAAAAAAAAAAA"
+PUBLIC_DISCORD_CLIENT_ID=""
+DISCORD_CLIENT_SECRET=""
# --------
+# Ratelimits
+UPSTASH_REDIS_REST_URL="https://AAAAAA-AAAAA-38294.upstash.io"
+UPSTASH_REDIS_REST_TOKEN="AAAAAAAAAAAAAAAAAA"
+
# MinIO
MINIO_ENDPOINT="localhost"
MINIO_ACCESS_KEY="AAAAAAAAAAAAAAAA"
@@ -28,4 +26,4 @@ DISCORD_CHANNEL_ID="9999999999999999" # Channel to send reports to
ADMIN_KEY="AAAAAAAAAAAAAAAAAAAAAA" # Key to communicate between the API and the bot. Required for endpoint /verify & /ban
API_BASE_URL="http://localhost:5173" # The API URL (usually port 5173)
SUDO_USER_ID="AAAAAAAAAAAAAAAAAAA" # The (valid) Lyntr user ID to use as an "agent" when fetching Lynt content for reporting. (since views must count regardless)
-DISCORD_ADMIN_ROLE="9999999999999999" # Only users with this role can use /verify or ban users.
\ No newline at end of file
+DISCORD_ADMIN_ROLE="9999999999999999" # Only users with this role can use /verify or ban users.
diff --git a/README.md b/README.md
index 82670336..88d64749 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,5 @@
+# Moved to [NeoLyntr](https://github.com/NeoLyntr/NeoLyntr)
+
Lyntr.com - the micro-blogging social media with an IQ test
[Privacy Policy](https://lyntr.com/privacy) | [Terms of Service](https://lyntr.com/tos) | [License](https://github.com/face-hh/lyntr/blob/master/LICENSE.md) | [YouTube video](https://youtu.be/-D2L3gHqcUA)
@@ -10,12 +12,17 @@ Light mode - Lyntr

+# Issues
+PLEASE before you make a issue read all the open and closed issues, use the search make sure a similar issue hasn't been posted by someone else before you make a new issue!
+
+If you have anything to add to a issue you can do so. Anymore information about a particular issue will be helpful!
+
# Self-host
First, we need to setup the `.env` file with the right secrets.
- Rename `.env.example` to `.env`
-## Supabase
-Firstly we have to setup the database. Head to https://supabase.com and **create an account.**
+## Database
+Firstly we have to setup the database we are going to use supabase here but you should be able to use any postgres database. Head to https://supabase.com and **create an account.**

@@ -33,15 +40,8 @@ Then click **Create new project**. It will take a few minutes, so in the meantim

On this page we can see the **Project API keys** and **Project configuration** sections.
-- Copy the `anon public` secret and put it in your `.env`:
-```python
-PUBLIC_SUPABASE_ANON_KEY="ey........................"
-```
-- Copy the `Project Configuration` > `URL`:
-```python
-PUBLIC_SUPABASE_URL="https://.....supabase.co"
-```
- Copy the `Project Configuration` > `JWT Secret`:
+- You could also generate one with password sites or `node -e "console.log(require('crypto').randomBytes(32).toString(hex));"`
```python
JWT_SECRET="..........x............x........."
```
@@ -56,13 +56,6 @@ DATABASE_URL="postgresql://postgres.USERNAME:PASSWORD/options"
If you clicked `Copy` on the Connect page, you should already have the `USERNAME`. Simply replace `PASSWORD` with the one you put at:
> For the **database password**, you could generate a random password or input yours. **Make sure to save it.**
-Now simply split the `DATABASE_URL` components:
-```python
-DB_HOST="LOCATION.pooler.supabase.com" # Change "LOCATION"
-DB_USER="postgres.USERNAME" # Change "USERNAME"
-DB_PASSWORD="PASSWORD" # Change "PASSWORD"
-DB_NAME="postgres" # Can be left like this
-```

Now run the following:
@@ -72,9 +65,20 @@ npx drizzle-kit migrate
npx drizzle-kit push
```
-And follow [this guide on how to enable the Discord auth in Supabase](https://supabase.com/docs/guides/auth/social-login/auth-discord), until the code part. It should look something like this.
-
+## Discord
+Now that the database is set up you will need to create a application on the [Discord Developer Portal](https://discord.com/developers/docs/intro)
+
+You can then copy the client id and client secrets into the corresponding lines of your env:
+```python
+PUBLIC_DISCORD_CLIENT_ID=""
+DISCORD_CLIENT_SECRET=""
+```
+
+## Ratelimits
+For ratelimits we use [upstash redis](https://upstash.com/).
+Create a redis and then copy these values into your env.
+
## MinIO
We need Min.io for images. This and the next step can be omitted if you don't need *Image support* / *reporting*.
diff --git a/drizzle.config.ts b/drizzle.config.ts
index c375972a..11502239 100644
--- a/drizzle.config.ts
+++ b/drizzle.config.ts
@@ -3,19 +3,12 @@ import type { Config } from 'drizzle-kit';
config({ path: '.env' })
-if (!process.env.DB_HOST || !process.env.DB_USER || !process.env.DB_PASSWORD || !process.env.DB_NAME) {
- throw new Error('Missing database credentials in environment variables');
-}
-
export default {
schema: './src/lib/server/schema.ts',
out: './drizzle',
dialect: 'postgresql', // 'postgresql' | 'mysql' | 'sqlite'
dbCredentials: {
- host: process.env.DB_HOST,
- user: process.env.DB_USER,
- password: process.env.DB_PASSWORD,
- database: process.env.DB_NAME,
- ssl: false
+ url: process.env.DATABASE_URL,
+ ssl: "prefer"
},
} satisfies Config;
diff --git a/drizzle/0002_goofy_prism.sql b/drizzle/0002_goofy_prism.sql
new file mode 100644
index 00000000..646c49e0
--- /dev/null
+++ b/drizzle/0002_goofy_prism.sql
@@ -0,0 +1,30 @@
+CREATE TABLE IF NOT EXISTS "messages" (
+ "id" bigserial PRIMARY KEY NOT NULL,
+ "sender_id" text,
+ "receiver_id" text,
+ "content" text NOT NULL,
+ "image" text,
+ "referenced_lynt_id" text,
+ "read" boolean DEFAULT false,
+ "created_at" timestamp DEFAULT now()
+);
+--> statement-breakpoint
+DO $$ BEGIN
+ ALTER TABLE "messages" ADD CONSTRAINT "messages_sender_id_users_id_fk" FOREIGN KEY ("sender_id") REFERENCES "public"."users"("id") ON DELETE no action ON UPDATE no action;
+EXCEPTION
+ WHEN duplicate_object THEN null;
+END $$;
+--> statement-breakpoint
+DO $$ BEGIN
+ ALTER TABLE "messages" ADD CONSTRAINT "messages_receiver_id_users_id_fk" FOREIGN KEY ("receiver_id") REFERENCES "public"."users"("id") ON DELETE no action ON UPDATE no action;
+EXCEPTION
+ WHEN duplicate_object THEN null;
+END $$;
+--> statement-breakpoint
+DO $$ BEGIN
+ ALTER TABLE "messages" ADD CONSTRAINT "messages_referenced_lynt_id_lynts_id_fk" FOREIGN KEY ("referenced_lynt_id") REFERENCES "public"."lynts"("id") ON DELETE no action ON UPDATE no action;
+EXCEPTION
+ WHEN duplicate_object THEN null;
+END $$;
+--> statement-breakpoint
+CREATE INDEX IF NOT EXISTS "created_at_idx" ON "messages" USING btree ("created_at");
\ No newline at end of file
diff --git a/drizzle/meta/0002_snapshot.json b/drizzle/meta/0002_snapshot.json
new file mode 100644
index 00000000..67df4133
--- /dev/null
+++ b/drizzle/meta/0002_snapshot.json
@@ -0,0 +1,617 @@
+{
+ "id": "e7adf0f7-93ff-45de-874b-0599733b1908",
+ "prevId": "b2855ae0-cf08-4251-ad0f-ea64d0cf1b7f",
+ "version": "7",
+ "dialect": "postgresql",
+ "tables": {
+ "public.followers": {
+ "name": "followers",
+ "schema": "",
+ "columns": {
+ "user_id": {
+ "name": "user_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "follower_id": {
+ "name": "follower_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {
+ "followers_user_id_users_id_fk": {
+ "name": "followers_user_id_users_id_fk",
+ "tableFrom": "followers",
+ "tableTo": "users",
+ "columnsFrom": [
+ "user_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ },
+ "followers_follower_id_users_id_fk": {
+ "name": "followers_follower_id_users_id_fk",
+ "tableFrom": "followers",
+ "tableTo": "users",
+ "columnsFrom": [
+ "follower_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {
+ "followers_pkey": {
+ "name": "followers_pkey",
+ "columns": [
+ "user_id",
+ "follower_id"
+ ]
+ }
+ },
+ "uniqueConstraints": {}
+ },
+ "public.history": {
+ "name": "history",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "user_id": {
+ "name": "user_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "lynt_id": {
+ "name": "lynt_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "unique_user_lynt": {
+ "name": "unique_user_lynt",
+ "columns": [
+ {
+ "expression": "user_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "lynt_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "history_user_id_users_id_fk": {
+ "name": "history_user_id_users_id_fk",
+ "tableFrom": "history",
+ "tableTo": "users",
+ "columnsFrom": [
+ "user_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ },
+ "history_lynt_id_lynts_id_fk": {
+ "name": "history_lynt_id_lynts_id_fk",
+ "tableFrom": "history",
+ "tableTo": "lynts",
+ "columnsFrom": [
+ "lynt_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {}
+ },
+ "public.likes": {
+ "name": "likes",
+ "schema": "",
+ "columns": {
+ "lynt_id": {
+ "name": "lynt_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "user_id": {
+ "name": "user_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "liked_at": {
+ "name": "liked_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false,
+ "default": "now()"
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {
+ "likes_lynt_id_lynts_id_fk": {
+ "name": "likes_lynt_id_lynts_id_fk",
+ "tableFrom": "likes",
+ "tableTo": "lynts",
+ "columnsFrom": [
+ "lynt_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ },
+ "likes_user_id_users_id_fk": {
+ "name": "likes_user_id_users_id_fk",
+ "tableFrom": "likes",
+ "tableTo": "users",
+ "columnsFrom": [
+ "user_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {
+ "likes_pkey": {
+ "name": "likes_pkey",
+ "columns": [
+ "lynt_id",
+ "user_id"
+ ]
+ }
+ },
+ "uniqueConstraints": {}
+ },
+ "public.lynts": {
+ "name": "lynts",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "user_id": {
+ "name": "user_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "content": {
+ "name": "content",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "views": {
+ "name": "views",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "default": 0
+ },
+ "shares": {
+ "name": "shares",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "default": 0
+ },
+ "has_link": {
+ "name": "has_link",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": false,
+ "default": false
+ },
+ "has_image": {
+ "name": "has_image",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": false,
+ "default": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false,
+ "default": "now()"
+ },
+ "reposted": {
+ "name": "reposted",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": false,
+ "default": false
+ },
+ "parent": {
+ "name": "parent",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {
+ "lynts_user_id_users_id_fk": {
+ "name": "lynts_user_id_users_id_fk",
+ "tableFrom": "lynts",
+ "tableTo": "users",
+ "columnsFrom": [
+ "user_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ },
+ "lynts_parent_lynts_id_fk": {
+ "name": "lynts_parent_lynts_id_fk",
+ "tableFrom": "lynts",
+ "tableTo": "lynts",
+ "columnsFrom": [
+ "parent"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {}
+ },
+ "public.messages": {
+ "name": "messages",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "bigserial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "sender_id": {
+ "name": "sender_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "receiver_id": {
+ "name": "receiver_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "content": {
+ "name": "content",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "image": {
+ "name": "image",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "referenced_lynt_id": {
+ "name": "referenced_lynt_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "read": {
+ "name": "read",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": false,
+ "default": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "created_at_idx": {
+ "name": "created_at_idx",
+ "columns": [
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "messages_sender_id_users_id_fk": {
+ "name": "messages_sender_id_users_id_fk",
+ "tableFrom": "messages",
+ "tableTo": "users",
+ "columnsFrom": [
+ "sender_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ },
+ "messages_receiver_id_users_id_fk": {
+ "name": "messages_receiver_id_users_id_fk",
+ "tableFrom": "messages",
+ "tableTo": "users",
+ "columnsFrom": [
+ "receiver_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ },
+ "messages_referenced_lynt_id_lynts_id_fk": {
+ "name": "messages_referenced_lynt_id_lynts_id_fk",
+ "tableFrom": "messages",
+ "tableTo": "lynts",
+ "columnsFrom": [
+ "referenced_lynt_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {}
+ },
+ "public.notifications": {
+ "name": "notifications",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "user_id": {
+ "name": "user_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "type": {
+ "name": "type",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "source_user_id": {
+ "name": "source_user_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "lynt_id": {
+ "name": "lynt_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "read": {
+ "name": "read",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": false,
+ "default": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false,
+ "default": "now()"
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {
+ "notifications_user_id_users_id_fk": {
+ "name": "notifications_user_id_users_id_fk",
+ "tableFrom": "notifications",
+ "tableTo": "users",
+ "columnsFrom": [
+ "user_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ },
+ "notifications_source_user_id_users_id_fk": {
+ "name": "notifications_source_user_id_users_id_fk",
+ "tableFrom": "notifications",
+ "tableTo": "users",
+ "columnsFrom": [
+ "source_user_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ },
+ "notifications_lynt_id_lynts_id_fk": {
+ "name": "notifications_lynt_id_lynts_id_fk",
+ "tableFrom": "notifications",
+ "tableTo": "lynts",
+ "columnsFrom": [
+ "lynt_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {}
+ },
+ "public.users": {
+ "name": "users",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "username": {
+ "name": "username",
+ "type": "varchar(60)",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "handle": {
+ "name": "handle",
+ "type": "varchar(32)",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "bio": {
+ "name": "bio",
+ "type": "varchar(256)",
+ "primaryKey": false,
+ "notNull": false,
+ "default": "'Nothing here yet...'"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false,
+ "default": "now()"
+ },
+ "banned": {
+ "name": "banned",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": false,
+ "default": false
+ },
+ "iq": {
+ "name": "iq",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "token": {
+ "name": "token",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "default": "'a'"
+ },
+ "email": {
+ "name": "email",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "verified": {
+ "name": "verified",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": false,
+ "default": false
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {
+ "users_handle_unique": {
+ "name": "users_handle_unique",
+ "nullsNotDistinct": false,
+ "columns": [
+ "handle"
+ ]
+ }
+ }
+ }
+ },
+ "enums": {},
+ "schemas": {},
+ "_meta": {
+ "columns": {},
+ "schemas": {},
+ "tables": {}
+ }
+}
\ No newline at end of file
diff --git a/drizzle/meta/_journal.json b/drizzle/meta/_journal.json
index 0ae134a1..8d8dcdb0 100644
--- a/drizzle/meta/_journal.json
+++ b/drizzle/meta/_journal.json
@@ -15,6 +15,13 @@
"when": 1722220455698,
"tag": "0001_overrated_deadpool",
"breakpoints": true
+ },
+ {
+ "idx": 2,
+ "version": "7",
+ "when": 1722730351277,
+ "tag": "0002_goofy_prism",
+ "breakpoints": true
}
]
}
\ No newline at end of file
diff --git a/github-assets/redis.png b/github-assets/redis.png
new file mode 100755
index 00000000..f3abf436
Binary files /dev/null and b/github-assets/redis.png differ
diff --git a/package-lock.json b/package-lock.json
index 426c3fd1..da8e6887 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -19,8 +19,9 @@
"@types/ws": "^8.5.11",
"@upstash/ratelimit": "^2.0.1",
"@upstash/redis": "^1.34.0",
- "bits-ui": "^0.21.12",
+ "bits-ui": "^0.21.13",
"clsx": "^2.1.1",
+ "dayjs": "^1.11.12",
"discord.js": "^14.15.3",
"dompurify": "^3.1.6",
"dotenv": "^16.4.5",
@@ -69,6 +70,7 @@
"svelte": "^4.2.7",
"svelte-check": "^3.6.0",
"svelte-magnifier": "^0.0.1",
+ "svelte-virtual-scroll-list": "^1.3.0",
"sveltekit-sse": "^0.13.2",
"tailwindcss": "^3.4.4",
"ts-node": "^10.9.2",
@@ -3116,9 +3118,9 @@
}
},
"node_modules/bits-ui": {
- "version": "0.21.12",
- "resolved": "https://registry.npmjs.org/bits-ui/-/bits-ui-0.21.12.tgz",
- "integrity": "sha512-Cf0iB+ZKwA0ZjkpixrhrZK9PC6pGPFleW/65Xc/z0lpGvWaFtdOhiYEntCHHxZ0VihP3aJaG0OBhUBIbmAePaA==",
+ "version": "0.21.13",
+ "resolved": "https://registry.npmjs.org/bits-ui/-/bits-ui-0.21.13.tgz",
+ "integrity": "sha512-7nmOh6Ig7ND4DXZHv1FhNsY9yUGrad0+mf3tc4YN//3MgnJT1LnHtk4HZAKgmxCOe7txSX7/39LtYHbkrXokAQ==",
"dependencies": {
"@internationalized/date": "^3.5.1",
"@melt-ui/svelte": "0.76.2",
@@ -3683,10 +3685,9 @@
}
},
"node_modules/dayjs": {
- "version": "1.11.11",
- "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.11.tgz",
- "integrity": "sha512-okzr3f11N6WuqYtZSvm+F776mB41wRZMhKP+hc34YdW+KmtYYK9iqvHSwo2k9FEH3fhGXvOPV6yz2IcSrfRUDg==",
- "optional": true
+ "version": "1.11.12",
+ "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.12.tgz",
+ "integrity": "sha512-Rt2g+nTbLlDWZTwwrIXjy9MeiZmSDI375FvZs72ngxx8PDC6YXOeR3q5LAuPzjZQxhiWdRKac7RKV+YyQYfYIg=="
},
"node_modules/debug": {
"version": "4.3.5",
@@ -4725,9 +4726,9 @@
}
},
"node_modules/fast-xml-parser": {
- "version": "4.4.0",
- "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.4.0.tgz",
- "integrity": "sha512-kLY3jFlwIYwBNDojclKsNAC12sfD6NwW74QB2CoNGPvtVxjliYehVunB3HYyNi+n4Tt1dAcgwYvmKF/Z18flqg==",
+ "version": "4.4.1",
+ "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.4.1.tgz",
+ "integrity": "sha512-xkjOecfnKGkSsOwtZ5Pz7Us/T6mrbPQrq0nh+aCO5V9nk5NLWmasAHumTKjiPJPWANe+kAZ84Jc8ooJkzZ88Sw==",
"funding": [
{
"type": "github",
@@ -7630,6 +7631,15 @@
"svelte": "^3.0.0 || ^4.0.0 || ^5.0.0-next.1"
}
},
+ "node_modules/svelte-virtual-scroll-list": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/svelte-virtual-scroll-list/-/svelte-virtual-scroll-list-1.3.0.tgz",
+ "integrity": "sha512-rkU993mMsTboFRlygExhYeLJwysaFxyzfTsAfOtDklGIyd0wB31eZtYSAHAcz/WaZCEwjn+GKXfx5jM1xUv3GQ==",
+ "dev": true,
+ "peerDependencies": {
+ "svelte": ">=3.5.0"
+ }
+ },
"node_modules/sveltekit-sse": {
"version": "0.13.2",
"resolved": "https://registry.npmjs.org/sveltekit-sse/-/sveltekit-sse-0.13.2.tgz",
diff --git a/package.json b/package.json
index 548c8937..f66cebc0 100644
--- a/package.json
+++ b/package.json
@@ -35,6 +35,7 @@
"svelte": "^4.2.7",
"svelte-check": "^3.6.0",
"svelte-magnifier": "^0.0.1",
+ "svelte-virtual-scroll-list": "^1.3.0",
"sveltekit-sse": "^0.13.2",
"tailwindcss": "^3.4.4",
"ts-node": "^10.9.2",
@@ -54,8 +55,9 @@
"@types/ws": "^8.5.11",
"@upstash/ratelimit": "^2.0.1",
"@upstash/redis": "^1.34.0",
- "bits-ui": "^0.21.12",
+ "bits-ui": "^0.21.13",
"clsx": "^2.1.1",
+ "dayjs": "^1.11.12",
"discord.js": "^14.15.3",
"dompurify": "^3.1.6",
"dotenv": "^16.4.5",
diff --git a/src/app.html b/src/app.html
index 7bad6484..d22cf034 100644
--- a/src/app.html
+++ b/src/app.html
@@ -13,9 +13,7 @@
-
-
-
+
%sveltekit.head%
@@ -23,4 +21,3 @@
%sveltekit.body%