mirror of
https://github.com/seanmorley15/AdventureLog.git
synced 2025-08-05 13:15:18 +02:00
commit
c210c655af
22 changed files with 892 additions and 117 deletions
|
@ -10,5 +10,7 @@ _**⚠️ AdventureLog is in early development and is not recommended for produc
|
|||
2. Edit the `docker-compose.yml` file and change the database password
|
||||
3. Run `docker compose up -d` to build the image and start the container
|
||||
4. Wait for the app to start up and migrate then visit the port and enjoy!
|
||||
5. After navigating to the app, fill out the form to create the admin user.
|
||||
|
||||
**Note**: The `ORIGIN` variable is required for CSRF protection. It can be omitted if using a reverse proxy or other HTTPS service.
|
||||
|
||||
|
|
15
compose-dev.yml
Normal file
15
compose-dev.yml
Normal file
|
@ -0,0 +1,15 @@
|
|||
services:
|
||||
web:
|
||||
build: .
|
||||
ports:
|
||||
- "3000:3000"
|
||||
environment:
|
||||
- DATABASE_URL=
|
||||
# ORIGIN is only necessary when not using a reverse proxy or hosting that includes https
|
||||
- ORIGIN=http://localhost:3000
|
||||
- SKIP_DB_WAIT=true
|
||||
# Only necessary for externaly hosted databases such as NeonDB
|
||||
volumes:
|
||||
- ./sql:/sql
|
||||
|
||||
# docker compose -f ./compose-dev.yml up --build
|
|
@ -7,6 +7,8 @@ services:
|
|||
- DATABASE_URL=postgres://adventurelog:PO24VjITwGgk@db:5432/adventurelog
|
||||
# ORIGIN is only necessary when not using a reverse proxy or hosting that includes https
|
||||
- ORIGIN=http://localhost:3000
|
||||
- SKIP_DB_WAIT=false
|
||||
# Only necessary for externaly hosted databases such as NeonDB
|
||||
depends_on:
|
||||
- db
|
||||
volumes:
|
||||
|
|
3
migrations/0003_easy_iron_monger.sql
Normal file
3
migrations/0003_easy_iron_monger.sql
Normal file
|
@ -0,0 +1,3 @@
|
|||
ALTER TABLE "user" ADD COLUMN "signup_date" timestamp with time zone NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE "user" ADD COLUMN "last_login" timestamp with time zone;--> statement-breakpoint
|
||||
ALTER TABLE "user" ADD COLUMN "role" text NOT NULL;
|
409
migrations/meta/0003_snapshot.json
Normal file
409
migrations/meta/0003_snapshot.json
Normal file
|
@ -0,0 +1,409 @@
|
|||
{
|
||||
"id": "72cc9a9a-a12e-4ca2-b644-b704673af4d7",
|
||||
"prevId": "91692e84-91ec-4411-ad9d-7b8b14f67dda",
|
||||
"version": "5",
|
||||
"dialect": "pg",
|
||||
"tables": {
|
||||
"featuredAdventures": {
|
||||
"name": "featuredAdventures",
|
||||
"schema": "",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "serial",
|
||||
"primaryKey": true,
|
||||
"notNull": true
|
||||
},
|
||||
"name": {
|
||||
"name": "name",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"location": {
|
||||
"name": "location",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {
|
||||
"featuredAdventures_name_unique": {
|
||||
"name": "featuredAdventures_name_unique",
|
||||
"nullsNotDistinct": false,
|
||||
"columns": [
|
||||
"name"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"session": {
|
||||
"name": "session",
|
||||
"schema": "",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "text",
|
||||
"primaryKey": true,
|
||||
"notNull": true
|
||||
},
|
||||
"user_id": {
|
||||
"name": "user_id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"expires_at": {
|
||||
"name": "expires_at",
|
||||
"type": "timestamp with time zone",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"session_user_id_user_id_fk": {
|
||||
"name": "session_user_id_user_id_fk",
|
||||
"tableFrom": "session",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "no action",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {}
|
||||
},
|
||||
"sharedAdventures": {
|
||||
"name": "sharedAdventures",
|
||||
"schema": "",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "text",
|
||||
"primaryKey": true,
|
||||
"notNull": true
|
||||
},
|
||||
"data": {
|
||||
"name": "data",
|
||||
"type": "json",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"name": {
|
||||
"name": "name",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"date": {
|
||||
"name": "date",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {}
|
||||
},
|
||||
"user": {
|
||||
"name": "user",
|
||||
"schema": "",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "text",
|
||||
"primaryKey": true,
|
||||
"notNull": true
|
||||
},
|
||||
"username": {
|
||||
"name": "username",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"first_name": {
|
||||
"name": "first_name",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"last_name": {
|
||||
"name": "last_name",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"icon": {
|
||||
"name": "icon",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"hashed_password": {
|
||||
"name": "hashed_password",
|
||||
"type": "varchar",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"signup_date": {
|
||||
"name": "signup_date",
|
||||
"type": "timestamp with time zone",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"last_login": {
|
||||
"name": "last_login",
|
||||
"type": "timestamp with time zone",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"role": {
|
||||
"name": "role",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {}
|
||||
},
|
||||
"userVisitedAdventures": {
|
||||
"name": "userVisitedAdventures",
|
||||
"schema": "",
|
||||
"columns": {
|
||||
"adventure_id": {
|
||||
"name": "adventure_id",
|
||||
"type": "serial",
|
||||
"primaryKey": true,
|
||||
"notNull": true
|
||||
},
|
||||
"user_id": {
|
||||
"name": "user_id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"adventure_name": {
|
||||
"name": "adventure_name",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"location": {
|
||||
"name": "location",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"visited_date": {
|
||||
"name": "visited_date",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"userVisitedAdventures_user_id_user_id_fk": {
|
||||
"name": "userVisitedAdventures_user_id_user_id_fk",
|
||||
"tableFrom": "userVisitedAdventures",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "no action",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {}
|
||||
},
|
||||
"userVisitedWorldTravel": {
|
||||
"name": "userVisitedWorldTravel",
|
||||
"schema": "",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "serial",
|
||||
"primaryKey": true,
|
||||
"notNull": true
|
||||
},
|
||||
"country_code": {
|
||||
"name": "country_code",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"user_id": {
|
||||
"name": "user_id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"region_id": {
|
||||
"name": "region_id",
|
||||
"type": "varchar",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"userVisitedWorldTravel_country_code_worldTravelCountries_country_code_fk": {
|
||||
"name": "userVisitedWorldTravel_country_code_worldTravelCountries_country_code_fk",
|
||||
"tableFrom": "userVisitedWorldTravel",
|
||||
"tableTo": "worldTravelCountries",
|
||||
"columnsFrom": [
|
||||
"country_code"
|
||||
],
|
||||
"columnsTo": [
|
||||
"country_code"
|
||||
],
|
||||
"onDelete": "no action",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
"userVisitedWorldTravel_user_id_user_id_fk": {
|
||||
"name": "userVisitedWorldTravel_user_id_user_id_fk",
|
||||
"tableFrom": "userVisitedWorldTravel",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "no action",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
"userVisitedWorldTravel_region_id_worldTravelCountryRegions_id_fk": {
|
||||
"name": "userVisitedWorldTravel_region_id_worldTravelCountryRegions_id_fk",
|
||||
"tableFrom": "userVisitedWorldTravel",
|
||||
"tableTo": "worldTravelCountryRegions",
|
||||
"columnsFrom": [
|
||||
"region_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "no action",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {}
|
||||
},
|
||||
"worldTravelCountries": {
|
||||
"name": "worldTravelCountries",
|
||||
"schema": "",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "serial",
|
||||
"primaryKey": true,
|
||||
"notNull": true
|
||||
},
|
||||
"name": {
|
||||
"name": "name",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"country_code": {
|
||||
"name": "country_code",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"continent": {
|
||||
"name": "continent",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {
|
||||
"worldTravelCountries_country_code_unique": {
|
||||
"name": "worldTravelCountries_country_code_unique",
|
||||
"nullsNotDistinct": false,
|
||||
"columns": [
|
||||
"country_code"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"worldTravelCountryRegions": {
|
||||
"name": "worldTravelCountryRegions",
|
||||
"schema": "",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "varchar",
|
||||
"primaryKey": true,
|
||||
"notNull": true
|
||||
},
|
||||
"name": {
|
||||
"name": "name",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"country_code": {
|
||||
"name": "country_code",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"info": {
|
||||
"name": "info",
|
||||
"type": "json",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"worldTravelCountryRegions_country_code_worldTravelCountries_country_code_fk": {
|
||||
"name": "worldTravelCountryRegions_country_code_worldTravelCountries_country_code_fk",
|
||||
"tableFrom": "worldTravelCountryRegions",
|
||||
"tableTo": "worldTravelCountries",
|
||||
"columnsFrom": [
|
||||
"country_code"
|
||||
],
|
||||
"columnsTo": [
|
||||
"country_code"
|
||||
],
|
||||
"onDelete": "no action",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {}
|
||||
}
|
||||
},
|
||||
"enums": {},
|
||||
"schemas": {},
|
||||
"_meta": {
|
||||
"columns": {},
|
||||
"schemas": {},
|
||||
"tables": {}
|
||||
}
|
||||
}
|
|
@ -22,6 +22,13 @@
|
|||
"when": 1713125110816,
|
||||
"tag": "0002_far_mephistopheles",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 3,
|
||||
"version": "5",
|
||||
"when": 1713402092365,
|
||||
"tag": "0003_easy_iron_monger",
|
||||
"breakpoints": true
|
||||
}
|
||||
]
|
||||
}
|
167
package-lock.json
generated
167
package-lock.json
generated
|
@ -1,14 +1,16 @@
|
|||
{
|
||||
"name": "adventurelog",
|
||||
"version": "0.0.1",
|
||||
"version": "0.1.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "adventurelog",
|
||||
"version": "0.0.1",
|
||||
"version": "0.1.0",
|
||||
"dependencies": {
|
||||
"@lucia-auth/adapter-drizzle": "^1.0.7",
|
||||
"@vercel/analytics": "^1.2.2",
|
||||
"@vercel/speed-insights": "^1.0.10",
|
||||
"drizzle-orm": "^0.30.6",
|
||||
"oslo": "^1.2.0",
|
||||
"postgres": "^3.4.4"
|
||||
|
@ -52,7 +54,7 @@
|
|||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz",
|
||||
"integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"dependencies": {
|
||||
"@jridgewell/gen-mapping": "^0.3.5",
|
||||
"@jridgewell/trace-mapping": "^0.3.24"
|
||||
|
@ -886,7 +888,7 @@
|
|||
"version": "0.3.5",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz",
|
||||
"integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"dependencies": {
|
||||
"@jridgewell/set-array": "^1.2.1",
|
||||
"@jridgewell/sourcemap-codec": "^1.4.10",
|
||||
|
@ -900,7 +902,7 @@
|
|||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
|
||||
"integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"engines": {
|
||||
"node": ">=6.0.0"
|
||||
}
|
||||
|
@ -909,7 +911,7 @@
|
|||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz",
|
||||
"integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"engines": {
|
||||
"node": ">=6.0.0"
|
||||
}
|
||||
|
@ -918,13 +920,13 @@
|
|||
"version": "1.4.15",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz",
|
||||
"integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==",
|
||||
"dev": true
|
||||
"devOptional": true
|
||||
},
|
||||
"node_modules/@jridgewell/trace-mapping": {
|
||||
"version": "0.3.25",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz",
|
||||
"integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"dependencies": {
|
||||
"@jridgewell/resolve-uri": "^3.1.0",
|
||||
"@jridgewell/sourcemap-codec": "^1.4.14"
|
||||
|
@ -1529,7 +1531,7 @@
|
|||
"version": "1.0.0-next.25",
|
||||
"resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.25.tgz",
|
||||
"integrity": "sha512-j7P6Rgr3mmtdkeDGTe0E/aYyWEWVtc5yFXtHCRHs28/jptDEWfaVOc5T7cblqy1XKPPfCxJc/8DwQ5YgLOZOVQ==",
|
||||
"dev": true
|
||||
"devOptional": true
|
||||
},
|
||||
"node_modules/@rollup/plugin-commonjs": {
|
||||
"version": "25.0.7",
|
||||
|
@ -2329,7 +2331,7 @@
|
|||
"version": "2.5.5",
|
||||
"resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-2.5.5.tgz",
|
||||
"integrity": "sha512-ULe3PB00q4+wYRL+IS5FDPsCEVnhEITofm7b9Yz8malcH3r1SAnW/JJ6T13hIMeu8QNRIuVQWo+P4+2VklbnLQ==",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"@types/cookie": "^0.6.0",
|
||||
|
@ -2361,7 +2363,7 @@
|
|||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-3.0.2.tgz",
|
||||
"integrity": "sha512-MpmF/cju2HqUls50WyTHQBZUV3ovV/Uk8k66AN2gwHogNAG8wnW8xtZDhzNBsFJJuvmq1qnzA5kE7YfMJNFv2Q==",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"dependencies": {
|
||||
"@sveltejs/vite-plugin-svelte-inspector": "^2.0.0",
|
||||
"debug": "^4.3.4",
|
||||
|
@ -2383,7 +2385,7 @@
|
|||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte-inspector/-/vite-plugin-svelte-inspector-2.0.0.tgz",
|
||||
"integrity": "sha512-gjr9ZFg1BSlIpfZ4PRewigrvYmHWbDrq2uvvPB1AmTWKuM+dI1JXQSUu2pIrYLb/QncyiIGkFDFKTwJ0XqQZZg==",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"dependencies": {
|
||||
"debug": "^4.3.4"
|
||||
},
|
||||
|
@ -2437,13 +2439,13 @@
|
|||
"version": "0.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz",
|
||||
"integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==",
|
||||
"dev": true
|
||||
"devOptional": true
|
||||
},
|
||||
"node_modules/@types/estree": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz",
|
||||
"integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==",
|
||||
"dev": true
|
||||
"devOptional": true
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "20.12.3",
|
||||
|
@ -2534,6 +2536,26 @@
|
|||
"integrity": "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@vercel/analytics": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@vercel/analytics/-/analytics-1.2.2.tgz",
|
||||
"integrity": "sha512-X0rctVWkQV1e5Y300ehVNqpOfSOufo7ieA5PIdna8yX/U7Vjz0GFsGf4qvAhxV02uQ2CVt7GYcrFfddXXK2Y4A==",
|
||||
"dependencies": {
|
||||
"server-only": "^0.0.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"next": ">= 13",
|
||||
"react": "^18 || ^19"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"next": {
|
||||
"optional": true
|
||||
},
|
||||
"react": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@vercel/nft": {
|
||||
"version": "0.26.4",
|
||||
"resolved": "https://registry.npmjs.org/@vercel/nft/-/nft-0.26.4.tgz",
|
||||
|
@ -2588,6 +2610,40 @@
|
|||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/@vercel/speed-insights": {
|
||||
"version": "1.0.10",
|
||||
"resolved": "https://registry.npmjs.org/@vercel/speed-insights/-/speed-insights-1.0.10.tgz",
|
||||
"integrity": "sha512-4uzdKB0RW6Ff2FkzshzjZ+RlJfLPxgm/00i0XXgxfMPhwnnsk92YgtqsxT9OcPLdJUyVU1DqFlSWWjIQMPkh0g==",
|
||||
"hasInstallScript": true,
|
||||
"peerDependencies": {
|
||||
"@sveltejs/kit": "^1 || ^2",
|
||||
"next": ">= 13",
|
||||
"react": "^18 || ^19",
|
||||
"svelte": "^4",
|
||||
"vue": "^3",
|
||||
"vue-router": "^4"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@sveltejs/kit": {
|
||||
"optional": true
|
||||
},
|
||||
"next": {
|
||||
"optional": true
|
||||
},
|
||||
"react": {
|
||||
"optional": true
|
||||
},
|
||||
"svelte": {
|
||||
"optional": true
|
||||
},
|
||||
"vue": {
|
||||
"optional": true
|
||||
},
|
||||
"vue-router": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/abbrev": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
|
||||
|
@ -2598,7 +2654,7 @@
|
|||
"version": "8.11.3",
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz",
|
||||
"integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"bin": {
|
||||
"acorn": "bin/acorn"
|
||||
},
|
||||
|
@ -2699,7 +2755,7 @@
|
|||
"version": "5.3.0",
|
||||
"resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz",
|
||||
"integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"dependencies": {
|
||||
"dequal": "^2.0.3"
|
||||
}
|
||||
|
@ -2751,7 +2807,7 @@
|
|||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.0.0.tgz",
|
||||
"integrity": "sha512-+60uv1hiVFhHZeO+Lz0RYzsVHy5Wr1ayX0mwda9KPDVLNJgZ1T9Ny7VmFbLDzxsH0D87I86vgj3gFrjTJUYznw==",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"dependencies": {
|
||||
"dequal": "^2.0.3"
|
||||
}
|
||||
|
@ -2979,7 +3035,7 @@
|
|||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/code-red/-/code-red-1.0.4.tgz",
|
||||
"integrity": "sha512-7qJWqItLA8/VPVlKJlFXU+NBlo/qyfs39aJcuMT/2ere32ZqvF5OSxgdM5xOfJJ7O429gg2HM47y8v9P+9wrNw==",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"dependencies": {
|
||||
"@jridgewell/sourcemap-codec": "^1.4.15",
|
||||
"@types/estree": "^1.0.1",
|
||||
|
@ -3046,7 +3102,7 @@
|
|||
"version": "0.6.0",
|
||||
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz",
|
||||
"integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
|
@ -3094,7 +3150,7 @@
|
|||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz",
|
||||
"integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"dependencies": {
|
||||
"mdn-data": "2.0.30",
|
||||
"source-map-js": "^1.0.1"
|
||||
|
@ -3160,7 +3216,7 @@
|
|||
"version": "4.3.4",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
||||
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"dependencies": {
|
||||
"ms": "2.1.2"
|
||||
},
|
||||
|
@ -3177,7 +3233,7 @@
|
|||
"version": "4.3.1",
|
||||
"resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz",
|
||||
"integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
|
@ -3192,7 +3248,7 @@
|
|||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz",
|
||||
"integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
|
@ -3219,7 +3275,7 @@
|
|||
"version": "4.3.2",
|
||||
"resolved": "https://registry.npmjs.org/devalue/-/devalue-4.3.2.tgz",
|
||||
"integrity": "sha512-KqFl6pOgOW+Y6wJgu80rHpo2/3H07vr8ntR9rkkFIRETewbf5GaYYcakYfiKz89K+sLsuPkQIZaXDMjUObZwWg==",
|
||||
"dev": true
|
||||
"devOptional": true
|
||||
},
|
||||
"node_modules/didyoumean": {
|
||||
"version": "1.2.2",
|
||||
|
@ -3965,7 +4021,7 @@
|
|||
"version": "0.20.2",
|
||||
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.20.2.tgz",
|
||||
"integrity": "sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"hasInstallScript": true,
|
||||
"bin": {
|
||||
"esbuild": "bin/esbuild"
|
||||
|
@ -4024,7 +4080,7 @@
|
|||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/esm-env/-/esm-env-1.0.0.tgz",
|
||||
"integrity": "sha512-Cf6VksWPsTuW01vU9Mk/3vRue91Zevka5SjyNf3nEpokFRuqt/KjUQoGAwq9qMmhpLTHmXzSIrFRw8zxWzmFBA==",
|
||||
"dev": true
|
||||
"devOptional": true
|
||||
},
|
||||
"node_modules/esniff": {
|
||||
"version": "2.0.1",
|
||||
|
@ -4045,7 +4101,7 @@
|
|||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz",
|
||||
"integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"dependencies": {
|
||||
"@types/estree": "^1.0.0"
|
||||
}
|
||||
|
@ -4321,13 +4377,13 @@
|
|||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/globalyzer/-/globalyzer-0.1.0.tgz",
|
||||
"integrity": "sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q==",
|
||||
"dev": true
|
||||
"devOptional": true
|
||||
},
|
||||
"node_modules/globrex": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz",
|
||||
"integrity": "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==",
|
||||
"dev": true
|
||||
"devOptional": true
|
||||
},
|
||||
"node_modules/graceful-fs": {
|
||||
"version": "4.2.11",
|
||||
|
@ -4402,7 +4458,7 @@
|
|||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.0.0.tgz",
|
||||
"integrity": "sha512-okYUR7ZQPH+efeuMJGlq4f8ubUgO50kByRPyt/Cy1Io4PSRsPjxME+YlVaCOx+NIToW7hCsZNFJyTPFFKepRSA==",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/wooorm"
|
||||
|
@ -4518,7 +4574,7 @@
|
|||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.2.tgz",
|
||||
"integrity": "sha512-v3rht/LgVcsdZa3O2Nqs+NMowLOxeOm7Ay9+/ARQ2F+qEoANRcqrjAZKGN0v8ymUetZGgkp26LTnGT7H0Qo9Pg==",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"dependencies": {
|
||||
"@types/estree": "*"
|
||||
}
|
||||
|
@ -4589,7 +4645,7 @@
|
|||
"version": "4.1.5",
|
||||
"resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz",
|
||||
"integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
|
@ -4613,7 +4669,7 @@
|
|||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/locate-character/-/locate-character-3.0.0.tgz",
|
||||
"integrity": "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==",
|
||||
"dev": true
|
||||
"devOptional": true
|
||||
},
|
||||
"node_modules/lodash.castarray": {
|
||||
"version": "4.4.0",
|
||||
|
@ -5150,7 +5206,7 @@
|
|||
"version": "0.30.8",
|
||||
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.8.tgz",
|
||||
"integrity": "sha512-ISQTe55T2ao7XtlAStud6qwYPZjE4GK1S/BeVPus4jrq6JuOnQ00YKQC581RWhR122W7msZV263KzVeLoqidyQ==",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"dependencies": {
|
||||
"@jridgewell/sourcemap-codec": "^1.4.15"
|
||||
},
|
||||
|
@ -5186,7 +5242,7 @@
|
|||
"version": "2.0.30",
|
||||
"resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz",
|
||||
"integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==",
|
||||
"dev": true
|
||||
"devOptional": true
|
||||
},
|
||||
"node_modules/memfs": {
|
||||
"version": "3.5.3",
|
||||
|
@ -5327,7 +5383,7 @@
|
|||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz",
|
||||
"integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
|
@ -5336,7 +5392,7 @@
|
|||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.0.tgz",
|
||||
"integrity": "sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw==",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
|
@ -5345,7 +5401,7 @@
|
|||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
|
||||
"dev": true
|
||||
"devOptional": true
|
||||
},
|
||||
"node_modules/mz": {
|
||||
"version": "2.7.0",
|
||||
|
@ -5362,7 +5418,7 @@
|
|||
"version": "3.3.7",
|
||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz",
|
||||
"integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
|
@ -5562,7 +5618,7 @@
|
|||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/periscopic/-/periscopic-3.1.0.tgz",
|
||||
"integrity": "sha512-vKiQ8RRtkl9P+r/+oefh25C3fhybptkHKCZSPlcXiJux2tJF55GnEj3BVn4A5gKfq9NWWXXrxkHBwVPUfH0opw==",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"dependencies": {
|
||||
"@types/estree": "^1.0.0",
|
||||
"estree-walker": "^3.0.0",
|
||||
|
@ -5671,7 +5727,7 @@
|
|||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
|
||||
"integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==",
|
||||
"dev": true
|
||||
"devOptional": true
|
||||
},
|
||||
"node_modules/picomatch": {
|
||||
"version": "2.3.1",
|
||||
|
@ -5707,7 +5763,7 @@
|
|||
"version": "8.4.38",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz",
|
||||
"integrity": "sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "opencollective",
|
||||
|
@ -6025,7 +6081,7 @@
|
|||
"version": "4.13.2",
|
||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.13.2.tgz",
|
||||
"integrity": "sha512-MIlLgsdMprDBXC+4hsPgzWUasLO9CE4zOkj/u6j+Z6j5A4zRY+CtiXAdJyPtgCsc42g658Aeh1DlrdVEJhsL2g==",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"dependencies": {
|
||||
"@types/estree": "1.0.5"
|
||||
},
|
||||
|
@ -6082,7 +6138,7 @@
|
|||
"version": "1.8.1",
|
||||
"resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz",
|
||||
"integrity": "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"dependencies": {
|
||||
"mri": "^1.1.0"
|
||||
},
|
||||
|
@ -6149,6 +6205,11 @@
|
|||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/server-only": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/server-only/-/server-only-0.0.1.tgz",
|
||||
"integrity": "sha512-qepMx2JxAa5jjfzxG79yPPq+8BuFToHd1hm7kI+Z4zAq1ftQiP7HcxMhDDItrbtwVeLg/cY2JnKnrcFkmiswNA=="
|
||||
},
|
||||
"node_modules/set-blocking": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
|
||||
|
@ -6159,7 +6220,7 @@
|
|||
"version": "2.6.0",
|
||||
"resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.6.0.tgz",
|
||||
"integrity": "sha512-RVnVQxTXuerk653XfuliOxBP81Sf0+qfQE73LIYKcyMYHG94AuH0kgrQpRDuTZnSmjpysHmzxJXKNfa6PjFhyQ==",
|
||||
"dev": true
|
||||
"devOptional": true
|
||||
},
|
||||
"node_modules/shebang-command": {
|
||||
"version": "2.0.0",
|
||||
|
@ -6198,7 +6259,7 @@
|
|||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/sirv/-/sirv-2.0.4.tgz",
|
||||
"integrity": "sha512-94Bdh3cC2PKrbgSOUqTiGPWVZeSiXfKOVZNJniWoqrWrRkB1CJzBU3NEbiTsPcYy1lDsANA/THzS+9WBiy5nfQ==",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"dependencies": {
|
||||
"@polka/url": "^1.0.0-next.24",
|
||||
"mrmime": "^2.0.0",
|
||||
|
@ -6242,7 +6303,7 @@
|
|||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz",
|
||||
"integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
|
@ -6479,7 +6540,7 @@
|
|||
"version": "4.2.12",
|
||||
"resolved": "https://registry.npmjs.org/svelte/-/svelte-4.2.12.tgz",
|
||||
"integrity": "sha512-d8+wsh5TfPwqVzbm4/HCXC783/KPHV60NvwitJnyTA5lWn1elhXMNWhXGCJ7PwPa8qFUnyJNIyuIRt2mT0WMug==",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"dependencies": {
|
||||
"@ampproject/remapping": "^2.2.1",
|
||||
"@jridgewell/sourcemap-codec": "^1.4.15",
|
||||
|
@ -6526,7 +6587,7 @@
|
|||
"version": "0.15.3",
|
||||
"resolved": "https://registry.npmjs.org/svelte-hmr/-/svelte-hmr-0.15.3.tgz",
|
||||
"integrity": "sha512-41snaPswvSf8TJUhlkoJBekRrABDXDMdpNpT2tfHIv4JuhgvHqLMhEPGtaQn0BmbNSTkuz2Ed20DF2eHw0SmBQ==",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"engines": {
|
||||
"node": "^12.20 || ^14.13.1 || >= 16"
|
||||
},
|
||||
|
@ -6719,7 +6780,7 @@
|
|||
"version": "0.2.9",
|
||||
"resolved": "https://registry.npmjs.org/tiny-glob/-/tiny-glob-0.2.9.tgz",
|
||||
"integrity": "sha512-g/55ssRPUjShh+xkfx9UPDXqhckHEsHr4Vd9zX55oSdGZc/MD0m3sferOkwWtp98bv+kcVfEHtRJgBVJzelrzg==",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"dependencies": {
|
||||
"globalyzer": "0.1.0",
|
||||
"globrex": "^0.1.2"
|
||||
|
@ -6741,7 +6802,7 @@
|
|||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz",
|
||||
"integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
|
@ -6829,7 +6890,7 @@
|
|||
"version": "5.2.7",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-5.2.7.tgz",
|
||||
"integrity": "sha512-k14PWOKLI6pMaSzAuGtT+Cf0YmIx12z9YGon39onaJNy8DLBfBJrzg9FQEmkAM5lpHBZs9wksWAsyF/HkpEwJA==",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"dependencies": {
|
||||
"esbuild": "^0.20.1",
|
||||
"postcss": "^8.4.38",
|
||||
|
@ -6884,7 +6945,7 @@
|
|||
"version": "0.2.5",
|
||||
"resolved": "https://registry.npmjs.org/vitefu/-/vitefu-0.2.5.tgz",
|
||||
"integrity": "sha512-SgHtMLoqaeeGnd2evZ849ZbACbnwQCIwRH57t18FxcXoZop0uQu0uzlIhJBlF/eWVzuce0sHeqPcDo+evVcg8Q==",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"peerDependencies": {
|
||||
"vite": "^3.0.0 || ^4.0.0 || ^5.0.0"
|
||||
},
|
||||
|
|
|
@ -39,6 +39,8 @@
|
|||
"type": "module",
|
||||
"dependencies": {
|
||||
"@lucia-auth/adapter-drizzle": "^1.0.7",
|
||||
"@vercel/analytics": "^1.2.2",
|
||||
"@vercel/speed-insights": "^1.0.10",
|
||||
"drizzle-orm": "^0.30.6",
|
||||
"oslo": "^1.2.0",
|
||||
"postgres": "^3.4.4"
|
||||
|
|
1
src/app.d.ts
vendored
1
src/app.d.ts
vendored
|
@ -3,6 +3,7 @@ declare global {
|
|||
interface Locals {
|
||||
user: import("lucia").User | null;
|
||||
session: import("lucia").Session | null;
|
||||
isServerSetup: boolean | null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
import { lucia } from "$lib/server/auth";
|
||||
import type { Handle } from "@sveltejs/kit";
|
||||
import { redirect, type Handle } from "@sveltejs/kit";
|
||||
import { sequence } from '@sveltejs/kit/hooks';
|
||||
import { db } from "$lib/db/db.server";
|
||||
import { userTable } from "$lib/db/schema";
|
||||
import { eq } from "drizzle-orm";
|
||||
|
||||
export const authHook: Handle = async ({ event, resolve }) => {
|
||||
const sessionId = event.cookies.get(lucia.sessionCookieName);
|
||||
|
@ -53,4 +56,27 @@ export const themeHook: Handle = async ({ event, resolve }) => {
|
|||
return await resolve(event);
|
||||
}
|
||||
|
||||
export const handle = sequence(authHook, themeHook);
|
||||
export const setupAdminUser: Handle = async ({ event, resolve }) => {
|
||||
// Check if an admin user exists
|
||||
/* let result = await db
|
||||
.select()
|
||||
.from(userVisitedAdventures)
|
||||
.where(eq(userVisitedAdventures.userId, event.locals.user.id))
|
||||
.execute();*/
|
||||
let adminUser = await db
|
||||
.select()
|
||||
.from(userTable)
|
||||
.where(eq(userTable.role, 'admin'))
|
||||
.execute();
|
||||
// If an admin user exists, return the resolved event
|
||||
if (adminUser != null && adminUser.length > 0) {
|
||||
event.locals.isServerSetup = true;
|
||||
return await resolve(event);
|
||||
}
|
||||
|
||||
console.log("No admin user found");
|
||||
event.locals.isServerSetup = false;
|
||||
return await resolve(event);
|
||||
};
|
||||
|
||||
export const handle = sequence(setupAdminUser, authHook, themeHook);
|
||||
|
|
|
@ -36,7 +36,12 @@
|
|||
<p class="text-lg ml-4 font-bold">Hi, {user.first_name} {user.last_name}</p>
|
||||
<li><a>Profile</a></li>
|
||||
<li><button on:click={navToLog}>My Log</button></li>
|
||||
<li><button on:click={navToSettings}>Settings</button></li>
|
||||
<li><button on:click={navToSettings}>User Settings</button></li>
|
||||
{#if user.role == "admin"}
|
||||
<li>
|
||||
<button on:click={() => goto("/settings/admin")}>Admin Settings</button>
|
||||
</li>
|
||||
{/if}
|
||||
<form method="post">
|
||||
<li><button formaction="/?/logout">Logout</button></li>
|
||||
</form>
|
||||
|
|
|
@ -28,6 +28,15 @@ export const userTable = pgTable("user", {
|
|||
last_name: text("last_name").notNull(),
|
||||
icon: text("icon"),
|
||||
hashed_password: varchar("hashed_password").notNull(),
|
||||
signup_date: timestamp("signup_date", {
|
||||
withTimezone: true,
|
||||
mode: "date",
|
||||
}).notNull(),
|
||||
last_login: timestamp("last_login", {
|
||||
withTimezone: true,
|
||||
mode: "date",
|
||||
}),
|
||||
role: text("role").notNull(),
|
||||
});
|
||||
|
||||
// export type SelectUser = typeof userTable.$inferSelect;
|
||||
|
|
|
@ -20,6 +20,9 @@ export const lucia = new Lucia(adapter, {
|
|||
first_name: attributes.first_name,
|
||||
last_name: attributes.last_name,
|
||||
icon: attributes.icon,
|
||||
signup_date: attributes.signup_date,
|
||||
last_login: attributes.last_login,
|
||||
role: attributes.role,
|
||||
};
|
||||
},
|
||||
});
|
||||
|
@ -38,4 +41,7 @@ export interface DatabaseUser {
|
|||
last_name: string;
|
||||
icon: string;
|
||||
hashed_password: string;
|
||||
signup_date: Date;
|
||||
last_login: Date;
|
||||
role: string;
|
||||
}
|
||||
|
|
|
@ -1,12 +1,21 @@
|
|||
import type { LayoutServerLoad, PageServerLoad } from "./$types";
|
||||
import { inject } from "@vercel/analytics";
|
||||
import { injectSpeedInsights } from "@vercel/speed-insights/sveltekit";
|
||||
|
||||
if (process.env.USING_VERCEL === "true") {
|
||||
inject();
|
||||
injectSpeedInsights();
|
||||
}
|
||||
|
||||
export const load: LayoutServerLoad = async (event) => {
|
||||
if (event.locals.user) {
|
||||
return {
|
||||
user: event.locals.user,
|
||||
isServerSetup: event.locals.isServerSetup,
|
||||
};
|
||||
}
|
||||
return {
|
||||
user: null,
|
||||
isServerSetup: event.locals.isServerSetup,
|
||||
};
|
||||
};
|
|
@ -4,6 +4,21 @@
|
|||
import Navbar from "$lib/components/Navbar.svelte";
|
||||
import type { SubmitFunction } from "@sveltejs/kit";
|
||||
import "../app.css";
|
||||
import { goto } from "$app/navigation";
|
||||
import { onMount } from "svelte";
|
||||
import { page } from "$app/stores";
|
||||
|
||||
let isServerSetup = data.isServerSetup;
|
||||
|
||||
onMount(() => {
|
||||
console.log("isServerSetup", isServerSetup);
|
||||
if (!isServerSetup && $page.url.pathname !== "/setup") {
|
||||
goto("/setup");
|
||||
}
|
||||
if (isServerSetup && $page.url.pathname == "/setup") {
|
||||
goto("/");
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<!-- passes the user object to the navbar component -->
|
||||
|
|
|
@ -47,7 +47,7 @@ export const actions: Actions = {
|
|||
});
|
||||
}
|
||||
|
||||
const existingUser = await db
|
||||
const existingUser:any = await db
|
||||
.select()
|
||||
.from(userTable)
|
||||
.where(eq(userTable.username, username))
|
||||
|
@ -70,6 +70,14 @@ export const actions: Actions = {
|
|||
});
|
||||
}
|
||||
|
||||
await db
|
||||
.update(userTable)
|
||||
.set({
|
||||
last_login: new Date(),
|
||||
})
|
||||
.where(eq(userTable.id, existingUser.id))
|
||||
.execute();
|
||||
|
||||
const session = await lucia.createSession(existingUser.id, {});
|
||||
const sessionCookie = lucia.createSessionCookie(session.id);
|
||||
event.cookies.set(sessionCookie.name, sessionCookie.value, {
|
||||
|
|
|
@ -4,6 +4,7 @@ import { db } from "$lib/db/db.server";
|
|||
import { userTable } from "$lib/db/schema";
|
||||
import { eq } from "drizzle-orm";
|
||||
import { Argon2id } from "oslo/password";
|
||||
import type { DatabaseUser } from "$lib/server/auth";
|
||||
|
||||
export const load: PageServerLoad = async (event) => {
|
||||
if (event.locals.user)
|
||||
|
@ -42,6 +43,22 @@ export const actions: Actions = {
|
|||
};
|
||||
}
|
||||
|
||||
const usernameTaken = await db
|
||||
.select()
|
||||
.from(userTable)
|
||||
.where(eq(userTable.username, username))
|
||||
.limit(1)
|
||||
.then((results) => results[0] as unknown as DatabaseUser | undefined);
|
||||
|
||||
if (usernameTaken) {
|
||||
return {
|
||||
status: 400,
|
||||
body: {
|
||||
message: "Username taken!"
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
if (password) {
|
||||
let hashedPassword = await new Argon2id().hash(password);
|
||||
console.log(hashedPassword)
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
<script>
|
||||
import { enhance } from "$app/forms";
|
||||
import AdventureCard from "$lib/components/AdventureCard.svelte";
|
||||
|
||||
export let data;
|
||||
let username = data.user?.username;
|
||||
|
@ -7,12 +8,13 @@
|
|||
let last_name = data.user?.last_name;
|
||||
let user_id = data.user?.id;
|
||||
let icon = data.user?.icon;
|
||||
let signup_date = data.user?.signup_date;
|
||||
let role = data.user?.role;
|
||||
</script>
|
||||
|
||||
<h1 class="text-center font-extrabold text-4xl mb-6">Settings Page</h1>
|
||||
|
||||
<h1 class="text-center font-extrabold text-xl">User Account Settings</h1>
|
||||
|
||||
<div class="flex justify-center">
|
||||
<form method="post" use:enhance class="w-full max-w-xs">
|
||||
<label for="username">Username</label>
|
||||
|
@ -65,4 +67,6 @@
|
|||
</form>
|
||||
</div>
|
||||
|
||||
<small class="text-center">For Debug Use: UUID={user_id}</small>
|
||||
<small class="text-center"
|
||||
><b>For Debug Use:</b> UUID={user_id} Signup Date={signup_date} Role={role}</small
|
||||
>
|
||||
|
|
121
src/routes/setup/+page.server.ts
Normal file
121
src/routes/setup/+page.server.ts
Normal file
|
@ -0,0 +1,121 @@
|
|||
// routes/signup/+page.server.ts
|
||||
import { lucia } from "$lib/server/auth";
|
||||
import { fail, redirect } from "@sveltejs/kit";
|
||||
import { generateId } from "lucia";
|
||||
import { Argon2id } from "oslo/password";
|
||||
import { db } from "$lib/db/db.server";
|
||||
import type { DatabaseUser } from "$lib/server/auth";
|
||||
|
||||
import type { Actions } from "./$types";
|
||||
import { userTable } from "$lib/db/schema";
|
||||
import { eq } from "drizzle-orm";
|
||||
|
||||
export const actions: Actions = {
|
||||
default: async (event) => {
|
||||
const formData = await event.request.formData();
|
||||
const username = formData.get("username");
|
||||
const password = formData.get("password");
|
||||
const firstName = formData.get("first_name");
|
||||
const lastName = formData.get("last_name");
|
||||
// username must be between 4 ~ 31 characters, and only consists of lowercase letters, 0-9, -, and _
|
||||
// keep in mind some database (e.g. mysql) are case insensitive
|
||||
|
||||
// check all to make sure all fields are provided
|
||||
if (!username || !password || !firstName || !lastName) {
|
||||
return fail(400, {
|
||||
message: "All fields are required",
|
||||
});
|
||||
}
|
||||
|
||||
if (
|
||||
typeof username !== "string" ||
|
||||
username.length < 3 ||
|
||||
username.length > 31 ||
|
||||
!/^[a-z0-9_-]+$/.test(username)
|
||||
) {
|
||||
return fail(400, {
|
||||
message: "Invalid username",
|
||||
});
|
||||
}
|
||||
if (
|
||||
typeof password !== "string" ||
|
||||
password.length < 6 ||
|
||||
password.length > 255
|
||||
) {
|
||||
return fail(400, {
|
||||
message: "Invalid password",
|
||||
});
|
||||
}
|
||||
|
||||
if (
|
||||
typeof firstName !== "string" ||
|
||||
firstName.length < 1 ||
|
||||
firstName.length > 255
|
||||
) {
|
||||
return fail(400, {
|
||||
message: "Invalid first name",
|
||||
});
|
||||
}
|
||||
|
||||
if (
|
||||
typeof lastName !== "string" ||
|
||||
lastName.length < 1 ||
|
||||
lastName.length > 255
|
||||
) {
|
||||
return fail(400, {
|
||||
message: "Invalid last name",
|
||||
});
|
||||
}
|
||||
|
||||
const userId = generateId(15);
|
||||
const hashedPassword = await new Argon2id().hash(password);
|
||||
|
||||
const usernameTaken = await db
|
||||
.select()
|
||||
.from(userTable)
|
||||
.where(eq(userTable.username, username))
|
||||
.limit(1)
|
||||
.then((results) => results[0] as unknown as DatabaseUser | undefined);
|
||||
|
||||
if (usernameTaken) {
|
||||
return fail(400, {
|
||||
message: "Username already taken",
|
||||
});
|
||||
}
|
||||
|
||||
let adminUser = await db
|
||||
.select()
|
||||
.from(userTable)
|
||||
.where(eq(userTable.role, 'admin'))
|
||||
.execute();
|
||||
|
||||
if (adminUser != null && adminUser.length > 0) {
|
||||
return fail(400, {
|
||||
message: "Admin user already exists",
|
||||
});
|
||||
}
|
||||
|
||||
await db
|
||||
.insert(userTable)
|
||||
.values({
|
||||
id: userId,
|
||||
username: username,
|
||||
first_name: firstName,
|
||||
last_name: lastName,
|
||||
hashed_password: hashedPassword,
|
||||
signup_date: new Date(),
|
||||
role: "admin",
|
||||
last_login: new Date(),
|
||||
} as DatabaseUser)
|
||||
.execute();
|
||||
|
||||
const session = await lucia.createSession(userId, {});
|
||||
const sessionCookie = lucia.createSessionCookie(session.id);
|
||||
event.cookies.set(sessionCookie.name, sessionCookie.value, {
|
||||
path: ".",
|
||||
...sessionCookie.attributes,
|
||||
});
|
||||
|
||||
redirect(302, "/");
|
||||
},
|
||||
};
|
44
src/routes/setup/+page.svelte
Normal file
44
src/routes/setup/+page.svelte
Normal file
|
@ -0,0 +1,44 @@
|
|||
<script lang="ts">
|
||||
import { enhance } from "$app/forms";
|
||||
</script>
|
||||
|
||||
<h1 class="text-center font-bold text-4xl">AdventureLog Setup</h1>
|
||||
|
||||
<!-- centered text descripton welcomeing the user -->
|
||||
<p class="text-center mt-4">
|
||||
Welcome to AdventureLog! Please follow the steps below to setup your server.
|
||||
</p>
|
||||
|
||||
<!-- step 1 create admin user -->
|
||||
<h2 class="text-center font-bold text-2xl mt-6">Create Admin User</h2>
|
||||
|
||||
<div class="flex justify-center">
|
||||
<form method="post" use:enhance class="w-full max-w-xs">
|
||||
<label for="username">Username</label>
|
||||
<input
|
||||
name="username"
|
||||
id="username"
|
||||
class="block mb-2 input input-bordered w-full max-w-xs"
|
||||
/><br />
|
||||
<label for="first_name">First Name</label>
|
||||
<input
|
||||
name="first_name"
|
||||
id="first_name"
|
||||
class="block mb-2 input input-bordered w-full max-w-xs"
|
||||
/><br />
|
||||
<label for="last_name">Last Name</label>
|
||||
<input
|
||||
name="last_name"
|
||||
id="last_name"
|
||||
class="block mb-2 input input-bordered w-full max-w-xs"
|
||||
/><br />
|
||||
<label for="password">Password</label>
|
||||
<input
|
||||
type="password"
|
||||
name="password"
|
||||
id="password"
|
||||
class="block mb-2 input input-bordered w-full max-w-xs"
|
||||
/><br />
|
||||
<button class="py-2 px-4 btn btn-primary">Signup</button>
|
||||
</form>
|
||||
</div>
|
|
@ -90,6 +90,9 @@ export const actions: Actions = {
|
|||
first_name: firstName,
|
||||
last_name: lastName,
|
||||
hashed_password: hashedPassword,
|
||||
signup_date: new Date(),
|
||||
role: "user",
|
||||
last_login: new Date(),
|
||||
} as DatabaseUser)
|
||||
.execute();
|
||||
|
||||
|
|
|
@ -24,12 +24,18 @@ run_sql_scripts() {
|
|||
echo "Finished running SQL scripts."
|
||||
}
|
||||
|
||||
|
||||
# Start your application here
|
||||
# Print message
|
||||
echo "Starting AdventureLog"
|
||||
|
||||
# Wait for the database to start up
|
||||
wait_for_db
|
||||
if [ -z "$SKIP_DB_WAIT" ] || [ "$SKIP_DB_WAIT" = "false" ]; then
|
||||
wait_for_db
|
||||
fi
|
||||
|
||||
# Wait for the database to start up
|
||||
|
||||
|
||||
# generate the schema
|
||||
# npm run generate
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue