diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index 4660078..0000000 --- a/Dockerfile +++ /dev/null @@ -1,11 +0,0 @@ -FROM oven/bun:latest - -WORKDIR /app -COPY package.json package.json -RUN bun install - -COPY . . -RUN bun run build - -EXPOSE 3000 -CMD ["bun", "--bun", "build/index.js"] \ No newline at end of file diff --git a/app.Dockerfile b/app.Dockerfile new file mode 100644 index 0000000..6da6e85 --- /dev/null +++ b/app.Dockerfile @@ -0,0 +1,34 @@ +FROM oven/bun:latest as builder + +WORKDIR /app + +# Copy package files +COPY package.json bun.lockb ./ + +# Install dependencies +RUN bun install + +# Copy all source files +COPY . . + +# Build the application +RUN bun run build + +# Production stage +FROM oven/bun:latest + +WORKDIR /app + +# Copy only the built files and necessary runtime files +COPY --from=builder /app/build ./build +COPY --from=builder /app/package.json ./package.json +COPY --from=builder /app/bun.lockb ./bun.lockb + +# Install only production dependencies +RUN bun install --production + +# Expose the port +EXPOSE 3000 + +# Start the application +CMD ["bun", "build/index.js"] \ No newline at end of file diff --git a/cms/pb_migrations/1733582513_created_docs.js b/cms/pb_migrations/1733582513_created_docs.js new file mode 100644 index 0000000..013ef9f --- /dev/null +++ b/cms/pb_migrations/1733582513_created_docs.js @@ -0,0 +1,125 @@ +/// +migrate((db) => { + const collection = new Collection({ + "id": "n9aqwacwoy4stzs", + "created": "2024-12-07 14:41:53.612Z", + "updated": "2024-12-07 14:41:53.612Z", + "name": "docs", + "type": "base", + "system": false, + "schema": [ + { + "system": false, + "id": "r8barbx0", + "name": "slug", + "type": "text", + "required": false, + "presentable": false, + "unique": false, + "options": { + "min": null, + "max": null, + "pattern": "" + } + }, + { + "system": false, + "id": "wjyjywhk", + "name": "title", + "type": "text", + "required": false, + "presentable": false, + "unique": false, + "options": { + "min": null, + "max": null, + "pattern": "" + } + }, + { + "system": false, + "id": "wnxus5oj", + "name": "description", + "type": "text", + "required": false, + "presentable": false, + "unique": false, + "options": { + "min": null, + "max": null, + "pattern": "" + } + }, + { + "system": false, + "id": "if2blvvp", + "name": "content", + "type": "editor", + "required": false, + "presentable": false, + "unique": false, + "options": { + "convertUrls": false + } + }, + { + "system": false, + "id": "cypldga8", + "name": "tags", + "type": "select", + "required": false, + "presentable": false, + "unique": false, + "options": { + "maxSelect": 2, + "values": [ + "self–hosting", + "docker", + "setup", + "fli.so" + ] + } + }, + { + "system": false, + "id": "zwblvrwy", + "name": "author", + "type": "relation", + "required": false, + "presentable": false, + "unique": false, + "options": { + "collectionId": "_pb_users_auth_", + "cascadeDelete": false, + "minSelect": null, + "maxSelect": 1, + "displayFields": null + } + }, + { + "system": false, + "id": "xdwxo0if", + "name": "status", + "type": "bool", + "required": false, + "presentable": false, + "unique": false, + "options": {} + } + ], + "indexes": [], + "listRule": null, + "viewRule": null, + "createRule": null, + "updateRule": null, + "deleteRule": null, + "options": {} + }); + + return Dao(db).saveCollection(collection); +}, (db) => { + const dao = new Dao(db); + const collection = dao.findCollectionByNameOrId("n9aqwacwoy4stzs"); + + return dao.deleteCollection(collection); +}) diff --git a/pocketbase/pb_migrations/1732955394_created_domains.js b/cms/pb_migrations/1733582837_created_authors.js similarity index 61% rename from pocketbase/pb_migrations/1732955394_created_domains.js rename to cms/pb_migrations/1733582837_created_authors.js index 3c1115d..103f6c6 100644 --- a/pocketbase/pb_migrations/1732955394_created_domains.js +++ b/cms/pb_migrations/1733582837_created_authors.js @@ -1,17 +1,17 @@ /// migrate((db) => { const collection = new Collection({ - "id": "469ndywsep8ecvn", - "created": "2024-11-30 08:29:54.301Z", - "updated": "2024-11-30 08:29:54.301Z", - "name": "domains", + "id": "bqnprvdsyv14cmi", + "created": "2024-12-07 14:47:17.289Z", + "updated": "2024-12-07 14:47:17.289Z", + "name": "authors", "type": "base", "system": false, "schema": [ { "system": false, - "id": "vxevfkyy", - "name": "domain", + "id": "pqx1adlk", + "name": "name", "type": "text", "required": false, "presentable": false, @@ -24,64 +24,57 @@ migrate((db) => { }, { "system": false, - "id": "aeh0hbkr", - "name": "user_id", - "type": "relation", + "id": "q8bh7ydq", + "name": "email", + "type": "email", "required": false, "presentable": false, "unique": false, "options": { - "collectionId": "_pb_users_auth_", - "cascadeDelete": false, - "minSelect": null, - "maxSelect": 1, - "displayFields": null + "exceptDomains": null, + "onlyDomains": null } }, { "system": false, - "id": "oxvonyoq", - "name": "status", - "type": "select", + "id": "zmyitrxf", + "name": "bio", + "type": "text", "required": false, "presentable": false, "unique": false, "options": { - "maxSelect": 1, - "values": [ - "pending", - "verified" - ] + "min": null, + "max": null, + "pattern": "" } }, { "system": false, - "id": "vntyprgm", - "name": "verification_token", - "type": "text", + "id": "3ro1gcog", + "name": "avatar", + "type": "file", "required": false, "presentable": false, "unique": false, "options": { - "min": null, - "max": null, - "pattern": "" + "mimeTypes": [], + "thumbs": [], + "maxSelect": 1, + "maxSize": 5242880, + "protected": false } }, { "system": false, - "id": "dyvcs7x6", - "name": "verification_method", - "type": "select", + "id": "ezv96p4c", + "name": "social_links", + "type": "json", "required": false, "presentable": false, "unique": false, "options": { - "maxSelect": 1, - "values": [ - "dns", - "file" - ] + "maxSize": 2000000 } } ], @@ -97,7 +90,7 @@ migrate((db) => { return Dao(db).saveCollection(collection); }, (db) => { const dao = new Dao(db); - const collection = dao.findCollectionByNameOrId("469ndywsep8ecvn"); + const collection = dao.findCollectionByNameOrId("bqnprvdsyv14cmi"); return dao.deleteCollection(collection); }) diff --git a/cms/pb_migrations/1733583100_updated_users.js b/cms/pb_migrations/1733583100_updated_users.js new file mode 100644 index 0000000..e2e8126 --- /dev/null +++ b/cms/pb_migrations/1733583100_updated_users.js @@ -0,0 +1,48 @@ +/// +migrate((db) => { + const dao = new Dao(db) + const collection = dao.findCollectionByNameOrId("_pb_users_auth_") + + // add + collection.schema.addField(new SchemaField({ + "system": false, + "id": "uu943hxz", + "name": "bio", + "type": "text", + "required": false, + "presentable": false, + "unique": false, + "options": { + "min": null, + "max": null, + "pattern": "" + } + })) + + // add + collection.schema.addField(new SchemaField({ + "system": false, + "id": "npn2vwkz", + "name": "social_links", + "type": "json", + "required": false, + "presentable": false, + "unique": false, + "options": { + "maxSize": 2000000 + } + })) + + return dao.saveCollection(collection) +}, (db) => { + const dao = new Dao(db) + const collection = dao.findCollectionByNameOrId("_pb_users_auth_") + + // remove + collection.schema.removeField("uu943hxz") + + // remove + collection.schema.removeField("npn2vwkz") + + return dao.saveCollection(collection) +}) diff --git a/cms/pb_migrations/1733583162_deleted_authors.js b/cms/pb_migrations/1733583162_deleted_authors.js new file mode 100644 index 0000000..60d3a85 --- /dev/null +++ b/cms/pb_migrations/1733583162_deleted_authors.js @@ -0,0 +1,96 @@ +/// +migrate((db) => { + const dao = new Dao(db); + const collection = dao.findCollectionByNameOrId("bqnprvdsyv14cmi"); + + return dao.deleteCollection(collection); +}, (db) => { + const collection = new Collection({ + "id": "bqnprvdsyv14cmi", + "created": "2024-12-07 14:47:17.289Z", + "updated": "2024-12-07 14:47:17.289Z", + "name": "authors", + "type": "base", + "system": false, + "schema": [ + { + "system": false, + "id": "pqx1adlk", + "name": "name", + "type": "text", + "required": false, + "presentable": false, + "unique": false, + "options": { + "min": null, + "max": null, + "pattern": "" + } + }, + { + "system": false, + "id": "q8bh7ydq", + "name": "email", + "type": "email", + "required": false, + "presentable": false, + "unique": false, + "options": { + "exceptDomains": null, + "onlyDomains": null + } + }, + { + "system": false, + "id": "zmyitrxf", + "name": "bio", + "type": "text", + "required": false, + "presentable": false, + "unique": false, + "options": { + "min": null, + "max": null, + "pattern": "" + } + }, + { + "system": false, + "id": "3ro1gcog", + "name": "avatar", + "type": "file", + "required": false, + "presentable": false, + "unique": false, + "options": { + "mimeTypes": [], + "thumbs": [], + "maxSelect": 1, + "maxSize": 5242880, + "protected": false + } + }, + { + "system": false, + "id": "ezv96p4c", + "name": "social_links", + "type": "json", + "required": false, + "presentable": false, + "unique": false, + "options": { + "maxSize": 2000000 + } + } + ], + "indexes": [], + "listRule": null, + "viewRule": null, + "createRule": null, + "updateRule": null, + "deleteRule": null, + "options": {} + }); + + return Dao(db).saveCollection(collection); +}) diff --git a/cms/pb_migrations/1733583222_updated_docs.js b/cms/pb_migrations/1733583222_updated_docs.js new file mode 100644 index 0000000..704b344 --- /dev/null +++ b/cms/pb_migrations/1733583222_updated_docs.js @@ -0,0 +1,36 @@ +/// +migrate((db) => { + const dao = new Dao(db) + const collection = dao.findCollectionByNameOrId("n9aqwacwoy4stzs") + + // update + collection.schema.addField(new SchemaField({ + "system": false, + "id": "xdwxo0if", + "name": "published", + "type": "bool", + "required": false, + "presentable": false, + "unique": false, + "options": {} + })) + + return dao.saveCollection(collection) +}, (db) => { + const dao = new Dao(db) + const collection = dao.findCollectionByNameOrId("n9aqwacwoy4stzs") + + // update + collection.schema.addField(new SchemaField({ + "system": false, + "id": "xdwxo0if", + "name": "status", + "type": "bool", + "required": false, + "presentable": false, + "unique": false, + "options": {} + })) + + return dao.saveCollection(collection) +}) diff --git a/cms/pb_migrations/1733583307_updated_docs.js b/cms/pb_migrations/1733583307_updated_docs.js new file mode 100644 index 0000000..38ef326 --- /dev/null +++ b/cms/pb_migrations/1733583307_updated_docs.js @@ -0,0 +1,36 @@ +/// +migrate((db) => { + const dao = new Dao(db) + const collection = dao.findCollectionByNameOrId("n9aqwacwoy4stzs") + + // add + collection.schema.addField(new SchemaField({ + "system": false, + "id": "slqrtrqd", + "name": "category", + "type": "select", + "required": false, + "presentable": false, + "unique": false, + "options": { + "maxSelect": 1, + "values": [ + "Getting Started", + "Features", + "API Documentation", + "Troubleshooting", + "FAQs" + ] + } + })) + + return dao.saveCollection(collection) +}, (db) => { + const dao = new Dao(db) + const collection = dao.findCollectionByNameOrId("n9aqwacwoy4stzs") + + // remove + collection.schema.removeField("slqrtrqd") + + return dao.saveCollection(collection) +}) diff --git a/cms/pb_migrations/1733584117_created_blogs.js b/cms/pb_migrations/1733584117_created_blogs.js new file mode 100644 index 0000000..4cce92a --- /dev/null +++ b/cms/pb_migrations/1733584117_created_blogs.js @@ -0,0 +1,157 @@ +/// +migrate((db) => { + const collection = new Collection({ + "id": "3mjc7om79ldoiu5", + "created": "2024-12-07 15:08:37.620Z", + "updated": "2024-12-07 15:08:37.620Z", + "name": "blogs", + "type": "base", + "system": false, + "schema": [ + { + "system": false, + "id": "cqlip1bv", + "name": "slug", + "type": "text", + "required": false, + "presentable": false, + "unique": false, + "options": { + "min": null, + "max": null, + "pattern": "" + } + }, + { + "system": false, + "id": "7qakq1fc", + "name": "title", + "type": "text", + "required": false, + "presentable": false, + "unique": false, + "options": { + "min": null, + "max": null, + "pattern": "" + } + }, + { + "system": false, + "id": "ibgca345", + "name": "description", + "type": "text", + "required": false, + "presentable": false, + "unique": false, + "options": { + "min": null, + "max": null, + "pattern": "" + } + }, + { + "system": false, + "id": "lnxn4exu", + "name": "content", + "type": "editor", + "required": false, + "presentable": false, + "unique": false, + "options": { + "convertUrls": false + } + }, + { + "system": false, + "id": "06crocuf", + "name": "tags", + "type": "text", + "required": false, + "presentable": false, + "unique": false, + "options": { + "min": null, + "max": null, + "pattern": "" + } + }, + { + "system": false, + "id": "dkhjkerb", + "name": "author_id", + "type": "relation", + "required": false, + "presentable": false, + "unique": false, + "options": { + "collectionId": "_pb_users_auth_", + "cascadeDelete": false, + "minSelect": null, + "maxSelect": null, + "displayFields": null + } + }, + { + "system": false, + "id": "ib038pli", + "name": "status", + "type": "select", + "required": false, + "presentable": false, + "unique": false, + "options": { + "maxSelect": 1, + "values": [ + "draft", + "published", + "archived" + ] + } + }, + { + "system": false, + "id": "8mgw6t5l", + "name": "published_at", + "type": "date", + "required": false, + "presentable": false, + "unique": false, + "options": { + "min": "", + "max": "" + } + }, + { + "system": false, + "id": "ikxz28su", + "name": "featured_image", + "type": "file", + "required": false, + "presentable": false, + "unique": false, + "options": { + "mimeTypes": [], + "thumbs": [], + "maxSelect": 1, + "maxSize": 5242880, + "protected": false + } + } + ], + "indexes": [], + "listRule": null, + "viewRule": null, + "createRule": null, + "updateRule": null, + "deleteRule": null, + "options": {} + }); + + return Dao(db).saveCollection(collection); +}, (db) => { + const dao = new Dao(db); + const collection = dao.findCollectionByNameOrId("3mjc7om79ldoiu5"); + + return dao.deleteCollection(collection); +}) diff --git a/pocketbase/pb_migrations/1732803633_updated_subscriptions.js b/cms/pb_migrations/1733588991_updated_docs.js similarity index 52% rename from pocketbase/pb_migrations/1732803633_updated_subscriptions.js rename to cms/pb_migrations/1733588991_updated_docs.js index 339c7fd..c1362e1 100644 --- a/pocketbase/pb_migrations/1732803633_updated_subscriptions.js +++ b/cms/pb_migrations/1733588991_updated_docs.js @@ -1,16 +1,18 @@ /// migrate((db) => { const dao = new Dao(db) - const collection = dao.findCollectionByNameOrId("4zjs84zpsai0wu4") + const collection = dao.findCollectionByNameOrId("n9aqwacwoy4stzs") - collection.listRule = null + collection.listRule = "" + collection.viewRule = "" return dao.saveCollection(collection) }, (db) => { const dao = new Dao(db) - const collection = dao.findCollectionByNameOrId("4zjs84zpsai0wu4") + const collection = dao.findCollectionByNameOrId("n9aqwacwoy4stzs") - collection.listRule = "user_id = @request.auth.id" + collection.listRule = null + collection.viewRule = null return dao.saveCollection(collection) }) diff --git a/cms/pocketbase b/cms/pocketbase new file mode 100755 index 0000000..b44af64 Binary files /dev/null and b/cms/pocketbase differ diff --git a/docker-compose.yml b/docker-compose.yml index 2786c68..86519bc 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,26 +1,46 @@ version: "3.8" +networks: + app_network: + driver: bridge + +volumes: + pb_data: + pb_public: + pb_hooks: + pb_migrations: + node_modules: + services: pocketbase: - image: ghcr.io/muchobien/pocketbase:0.22.27 container_name: pocketbase + build: + context: . + dockerfile: pocketbase.Dockerfile restart: unless-stopped ports: - - "8090:8090" + - "8092:8092" volumes: - - ./pocketbase/pb_data:/pb_data - - ./pocketbase/pb_public:/pb_public - - ./pocketbase/pb_hooks:/pb_hooks + - pb_data:/pb/pb_data + - pb_public:/pb/pb_public + - pb_hooks:/pb/pb_hooks + - pb_migrations:/pb/pb_migrations networks: - app_network + healthcheck: + test: + ["CMD", "wget", "-q", "--spider", "http://localhost:8092/api/health"] + interval: 10s + timeout: 5s + retries: 5 environment: - - ORIGIN=http://localhost:3000 # Allow CORS requests from SvelteKit during development + - DISABLE_GZIP=true - sveltekit-app: + app: + container_name: app build: context: . - dockerfile: Dockerfile - container_name: sveltekit-app + dockerfile: app.Dockerfile ports: - "3000:3000" depends_on: @@ -28,7 +48,7 @@ services: env_file: - .env environment: - - PUBLIC_POCKETBASE_URL=http://pocketbase:8090 # Use Docker network service name + - PUBLIC_POCKETBASE_URL=${PUBLIC_POCKETBASE_URL} - PUBLIC_APPLICATION_NAME=${PUBLIC_APPLICATION_NAME} - PUBLIC_APPLICATION_URL=${PUBLIC_APPLICATION_URL} - ENCRYPTION=${ENCRYPTION} @@ -43,13 +63,9 @@ services: - STRIPE_ENTERPRISE_PRICE_ID=${STRIPE_ENTERPRISE_PRICE_ID} - PUBLIC_SITE_URL=${PUBLIC_SITE_URL} - STRIPE_PRODUCT_ID=${STRIPE_PRODUCT_ID} - - ORIGIN=http://localhost:3000 + networks: - app_network volumes: - .:/app - - /app/node_modules - -networks: - app_network: - driver: bridge + - node_modules:/app/node_modules diff --git a/package.json b/package.json index 46af6bd..b24a88c 100644 --- a/package.json +++ b/package.json @@ -34,11 +34,13 @@ "dev": "vite dev", "build": "vite build", "preview": "vite preview", - "pocketbase": "pocketbase/pocketbase serve", - "pocketbase:dev": "pocketbase/pocketbase serve --http=127.0.0.1:8090 --dir=pocketbase/pocketbase/pb_data", - "pocketbase:export": "pocketbase schema export pb_schema.json", - "typegen": "pocketbase-typegen --db pocketbase/pb_data/data.db --out ./src/lib/types/generated-types.ts", - "start": "bun run pocketbase & bun run dev", + "app:pocketbase": "pocketbase/pocketbase serve --http=127.0.0.1:8090 --dir=pocketbase/pb_data", + "cms:pocketbase": "cms/pocketbase serve --http=127.0.0.1:8091 --dir=cms/pb_data", + "app:pocketbase:export": "pocketbase/pocketbase schema export pb_schema.json", + "cms:pocketbase:export": "cms/pocketbase schema export pb_schema.json", + "app:typegen": "pocketbase-typegen --db pocketbase/pb_data/data.db --out ./src/lib/types/generated-types.ts", + "cms:typegen": "pocketbase-typegen --db cms/pb_data/data.db --out ./src/lib/types/cms-generated-types.ts", + "start": "bun run app:pocketbase & bun run dev", "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", "test:e2e": "playwright test", diff --git a/pocketbase.Dockerfile b/pocketbase.Dockerfile new file mode 100644 index 0000000..fd7dc09 --- /dev/null +++ b/pocketbase.Dockerfile @@ -0,0 +1,32 @@ +FROM alpine:latest + +ARG PB_VERSION=0.22.27 + +# Install required tools +RUN apk add --no-cache \ + ca-certificates \ + unzip \ + wget \ + bash + +# Download and unzip PocketBase +ADD https://github.com/pocketbase/pocketbase/releases/download/v${PB_VERSION}/pocketbase_${PB_VERSION}_linux_amd64.zip /tmp/pb.zip +RUN unzip /tmp/pb.zip -d /pb/ + +# Create required directories +WORKDIR /pb +RUN mkdir -p /pb/pb_data /pb/pb_migrations /pb/pb_hooks + +# Copy migrations +COPY ./pocketbase/pb_migrations /pb/pb_migrations/ + +# Set correct permissions +RUN chmod 755 /pb/pocketbase && \ + chown -R nobody:nobody /pb + +USER nobody + +EXPOSE 8092 + +# Start PocketBase with automigrate and CORS enabled +CMD ["/pb/pocketbase", "serve", "--http=0.0.0.0:8092", "--automigrate"] \ No newline at end of file diff --git a/pocketbase/pb_migrations/1732803643_updated_subscriptions.js b/pocketbase/pb_migrations/1732803643_updated_subscriptions.js deleted file mode 100644 index 50fe5e3..0000000 --- a/pocketbase/pb_migrations/1732803643_updated_subscriptions.js +++ /dev/null @@ -1,16 +0,0 @@ -/// -migrate((db) => { - const dao = new Dao(db) - const collection = dao.findCollectionByNameOrId("4zjs84zpsai0wu4") - - collection.listRule = "user_id = @request.auth.id" - - return dao.saveCollection(collection) -}, (db) => { - const dao = new Dao(db) - const collection = dao.findCollectionByNameOrId("4zjs84zpsai0wu4") - - collection.listRule = null - - return dao.saveCollection(collection) -}) diff --git a/pocketbase/pb_migrations/1732858379_updated_users.js b/pocketbase/pb_migrations/1732858379_updated_users.js deleted file mode 100644 index 7801e74..0000000 --- a/pocketbase/pb_migrations/1732858379_updated_users.js +++ /dev/null @@ -1,36 +0,0 @@ -/// -migrate((db) => { - const dao = new Dao(db) - const collection = dao.findCollectionByNameOrId("_pb_users_auth_") - - collection.options = { - "allowEmailAuth": true, - "allowOAuth2Auth": true, - "allowUsernameAuth": true, - "exceptEmailDomains": null, - "manageRule": null, - "minPasswordLength": 8, - "onlyEmailDomains": null, - "onlyVerified": false, - "requireEmail": false - } - - return dao.saveCollection(collection) -}, (db) => { - const dao = new Dao(db) - const collection = dao.findCollectionByNameOrId("_pb_users_auth_") - - collection.options = { - "allowEmailAuth": true, - "allowOAuth2Auth": true, - "allowUsernameAuth": true, - "exceptEmailDomains": null, - "manageRule": null, - "minPasswordLength": 8, - "onlyEmailDomains": null, - "onlyVerified": true, - "requireEmail": true - } - - return dao.saveCollection(collection) -}) diff --git a/pocketbase/pb_migrations/1732955580_updated_domains.js b/pocketbase/pb_migrations/1732955580_updated_domains.js deleted file mode 100644 index fa6a259..0000000 --- a/pocketbase/pb_migrations/1732955580_updated_domains.js +++ /dev/null @@ -1,24 +0,0 @@ -/// -migrate((db) => { - const dao = new Dao(db) - const collection = dao.findCollectionByNameOrId("469ndywsep8ecvn") - - collection.listRule = "user_id = @request.auth.id" - collection.viewRule = "user_id = @request.auth.id" - collection.createRule = "user_id = @request.auth.id" - collection.updateRule = "user_id = @request.auth.id" - collection.deleteRule = "user_id = @request.auth.id" - - return dao.saveCollection(collection) -}, (db) => { - const dao = new Dao(db) - const collection = dao.findCollectionByNameOrId("469ndywsep8ecvn") - - collection.listRule = null - collection.viewRule = null - collection.createRule = null - collection.updateRule = null - collection.deleteRule = null - - return dao.saveCollection(collection) -}) diff --git a/pocketbase/pb_migrations/1732955602_updated_domains.js b/pocketbase/pb_migrations/1732955602_updated_domains.js deleted file mode 100644 index 8a54781..0000000 --- a/pocketbase/pb_migrations/1732955602_updated_domains.js +++ /dev/null @@ -1,16 +0,0 @@ -/// -migrate((db) => { - const dao = new Dao(db) - const collection = dao.findCollectionByNameOrId("469ndywsep8ecvn") - - collection.createRule = "@request.auth.id != ''" - - return dao.saveCollection(collection) -}, (db) => { - const dao = new Dao(db) - const collection = dao.findCollectionByNameOrId("469ndywsep8ecvn") - - collection.createRule = "user_id = @request.auth.id" - - return dao.saveCollection(collection) -}) diff --git a/pocketbase/pb_migrations/1732803670_updated_users.js b/pocketbase/pb_migrations/1733826839_updated_users.js similarity index 100% rename from pocketbase/pb_migrations/1732803670_updated_users.js rename to pocketbase/pb_migrations/1733826839_updated_users.js diff --git a/pocketbase/pb_migrations/1732961407_updated_urls.js b/pocketbase/pb_migrations/1733826874_updated_urls.js similarity index 56% rename from pocketbase/pb_migrations/1732961407_updated_urls.js rename to pocketbase/pb_migrations/1733826874_updated_urls.js index c90ebf9..ed527f1 100644 --- a/pocketbase/pb_migrations/1732961407_updated_urls.js +++ b/pocketbase/pb_migrations/1733826874_updated_urls.js @@ -3,18 +3,18 @@ migrate((db) => { const dao = new Dao(db) const collection = dao.findCollectionByNameOrId("yq7y9q93v9mlxmq") - // add + // update collection.schema.addField(new SchemaField({ "system": false, - "id": "ddtxaev3", - "name": "domain_id", + "id": "oqmxf691", + "name": "created_by", "type": "relation", "required": false, "presentable": false, "unique": false, "options": { - "collectionId": "469ndywsep8ecvn", - "cascadeDelete": false, + "collectionId": "_pb_users_auth_", + "cascadeDelete": true, "minSelect": null, "maxSelect": 1, "displayFields": null @@ -26,8 +26,23 @@ migrate((db) => { const dao = new Dao(db) const collection = dao.findCollectionByNameOrId("yq7y9q93v9mlxmq") - // remove - collection.schema.removeField("ddtxaev3") + // update + collection.schema.addField(new SchemaField({ + "system": false, + "id": "oqmxf691", + "name": "created_by", + "type": "relation", + "required": false, + "presentable": false, + "unique": false, + "options": { + "collectionId": "_pb_users_auth_", + "cascadeDelete": false, + "minSelect": null, + "maxSelect": 1, + "displayFields": null + } + })) return dao.saveCollection(collection) }) diff --git a/pocketbase/pb_migrations/1733826887_updated_customers.js b/pocketbase/pb_migrations/1733826887_updated_customers.js new file mode 100644 index 0000000..3270923 --- /dev/null +++ b/pocketbase/pb_migrations/1733826887_updated_customers.js @@ -0,0 +1,48 @@ +/// +migrate((db) => { + const dao = new Dao(db) + const collection = dao.findCollectionByNameOrId("qxxr33ci9lj5ub1") + + // update + collection.schema.addField(new SchemaField({ + "system": false, + "id": "n3mc4xme", + "name": "user_id", + "type": "relation", + "required": false, + "presentable": false, + "unique": false, + "options": { + "collectionId": "_pb_users_auth_", + "cascadeDelete": true, + "minSelect": null, + "maxSelect": 1, + "displayFields": null + } + })) + + return dao.saveCollection(collection) +}, (db) => { + const dao = new Dao(db) + const collection = dao.findCollectionByNameOrId("qxxr33ci9lj5ub1") + + // update + collection.schema.addField(new SchemaField({ + "system": false, + "id": "n3mc4xme", + "name": "user_id", + "type": "relation", + "required": false, + "presentable": false, + "unique": false, + "options": { + "collectionId": "_pb_users_auth_", + "cascadeDelete": false, + "minSelect": null, + "maxSelect": 1, + "displayFields": null + } + })) + + return dao.saveCollection(collection) +}) diff --git a/pocketbase/pb_migrations/1733826899_updated_domains.js b/pocketbase/pb_migrations/1733826899_updated_domains.js new file mode 100644 index 0000000..f75d396 --- /dev/null +++ b/pocketbase/pb_migrations/1733826899_updated_domains.js @@ -0,0 +1,48 @@ +/// +migrate((db) => { + const dao = new Dao(db) + const collection = dao.findCollectionByNameOrId("469ndywsep8ecvn") + + // update + collection.schema.addField(new SchemaField({ + "system": false, + "id": "aeh0hbkr", + "name": "user_id", + "type": "relation", + "required": false, + "presentable": false, + "unique": false, + "options": { + "collectionId": "_pb_users_auth_", + "cascadeDelete": true, + "minSelect": null, + "maxSelect": 1, + "displayFields": null + } + })) + + return dao.saveCollection(collection) +}, (db) => { + const dao = new Dao(db) + const collection = dao.findCollectionByNameOrId("469ndywsep8ecvn") + + // update + collection.schema.addField(new SchemaField({ + "system": false, + "id": "aeh0hbkr", + "name": "user_id", + "type": "relation", + "required": false, + "presentable": false, + "unique": false, + "options": { + "collectionId": "_pb_users_auth_", + "cascadeDelete": false, + "minSelect": null, + "maxSelect": 1, + "displayFields": null + } + })) + + return dao.saveCollection(collection) +}) diff --git a/pocketbase/pb_migrations/1733826908_deleted_payment_methods.js b/pocketbase/pb_migrations/1733826908_deleted_payment_methods.js new file mode 100644 index 0000000..35d434e --- /dev/null +++ b/pocketbase/pb_migrations/1733826908_deleted_payment_methods.js @@ -0,0 +1,127 @@ +/// +migrate((db) => { + const dao = new Dao(db); + const collection = dao.findCollectionByNameOrId("x7wrm7o336mkewh"); + + return dao.deleteCollection(collection); +}, (db) => { + const collection = new Collection({ + "id": "x7wrm7o336mkewh", + "created": "2024-11-26 07:01:25.288Z", + "updated": "2024-11-29 05:32:59.439Z", + "name": "payment_methods", + "type": "base", + "system": false, + "schema": [ + { + "system": false, + "id": "p4ryjmxg", + "name": "stripe_payment_method_id", + "type": "text", + "required": false, + "presentable": false, + "unique": false, + "options": { + "min": null, + "max": null, + "pattern": "" + } + }, + { + "system": false, + "id": "rm365mrw", + "name": "card_brand", + "type": "text", + "required": false, + "presentable": false, + "unique": false, + "options": { + "min": null, + "max": null, + "pattern": "" + } + }, + { + "system": false, + "id": "4eqxjol6", + "name": "card_last4", + "type": "text", + "required": false, + "presentable": false, + "unique": false, + "options": { + "min": null, + "max": null, + "pattern": "" + } + }, + { + "system": false, + "id": "bjlj8suv", + "name": "card_exp_month", + "type": "text", + "required": false, + "presentable": false, + "unique": false, + "options": { + "min": null, + "max": null, + "pattern": "" + } + }, + { + "system": false, + "id": "nvzibrot", + "name": "card_exp_year", + "type": "text", + "required": false, + "presentable": false, + "unique": false, + "options": { + "min": null, + "max": null, + "pattern": "" + } + }, + { + "system": false, + "id": "5vihftrv", + "name": "is_default", + "type": "text", + "required": false, + "presentable": false, + "unique": false, + "options": { + "min": null, + "max": null, + "pattern": "" + } + }, + { + "system": false, + "id": "a3air834", + "name": "customer_id", + "type": "relation", + "required": false, + "presentable": false, + "unique": false, + "options": { + "collectionId": "qxxr33ci9lj5ub1", + "cascadeDelete": false, + "minSelect": null, + "maxSelect": 1, + "displayFields": null + } + } + ], + "indexes": [], + "listRule": "customer_id.user_id = @request.auth.id", + "viewRule": "customer_id.user_id = @request.auth.id", + "createRule": "customer_id.user_id = @request.auth.id", + "updateRule": "customer_id.user_id = @request.auth.id", + "deleteRule": "customer_id.user_id = @request.auth.id", + "options": {} + }); + + return Dao(db).saveCollection(collection); +}) diff --git a/pocketbase/pb_migrations/1733826918_updated_subscriptions.js b/pocketbase/pb_migrations/1733826918_updated_subscriptions.js new file mode 100644 index 0000000..50b8ad0 --- /dev/null +++ b/pocketbase/pb_migrations/1733826918_updated_subscriptions.js @@ -0,0 +1,48 @@ +/// +migrate((db) => { + const dao = new Dao(db) + const collection = dao.findCollectionByNameOrId("4zjs84zpsai0wu4") + + // update + collection.schema.addField(new SchemaField({ + "system": false, + "id": "rs4t3bd8", + "name": "user_id", + "type": "relation", + "required": false, + "presentable": false, + "unique": false, + "options": { + "collectionId": "_pb_users_auth_", + "cascadeDelete": true, + "minSelect": null, + "maxSelect": 1, + "displayFields": null + } + })) + + return dao.saveCollection(collection) +}, (db) => { + const dao = new Dao(db) + const collection = dao.findCollectionByNameOrId("4zjs84zpsai0wu4") + + // update + collection.schema.addField(new SchemaField({ + "system": false, + "id": "rs4t3bd8", + "name": "user_id", + "type": "relation", + "required": false, + "presentable": false, + "unique": false, + "options": { + "collectionId": "_pb_users_auth_", + "cascadeDelete": false, + "minSelect": null, + "maxSelect": 1, + "displayFields": null + } + })) + + return dao.saveCollection(collection) +}) diff --git a/pocketbase/pb_migrations/1733826927_updated_tags.js b/pocketbase/pb_migrations/1733826927_updated_tags.js new file mode 100644 index 0000000..5e8e1c8 --- /dev/null +++ b/pocketbase/pb_migrations/1733826927_updated_tags.js @@ -0,0 +1,48 @@ +/// +migrate((db) => { + const dao = new Dao(db) + const collection = dao.findCollectionByNameOrId("6156foct15u4yk8") + + // update + collection.schema.addField(new SchemaField({ + "system": false, + "id": "r1rj0tde", + "name": "created_by", + "type": "relation", + "required": false, + "presentable": false, + "unique": false, + "options": { + "collectionId": "_pb_users_auth_", + "cascadeDelete": true, + "minSelect": null, + "maxSelect": 1, + "displayFields": null + } + })) + + return dao.saveCollection(collection) +}, (db) => { + const dao = new Dao(db) + const collection = dao.findCollectionByNameOrId("6156foct15u4yk8") + + // update + collection.schema.addField(new SchemaField({ + "system": false, + "id": "r1rj0tde", + "name": "created_by", + "type": "relation", + "required": false, + "presentable": false, + "unique": false, + "options": { + "collectionId": "_pb_users_auth_", + "cascadeDelete": false, + "minSelect": null, + "maxSelect": 1, + "displayFields": null + } + })) + + return dao.saveCollection(collection) +}) diff --git a/src/app.css b/src/app.css index d1e7eb2..1644d68 100644 --- a/src/app.css +++ b/src/app.css @@ -71,6 +71,14 @@ --ring: 24 5.7% 82.9%; } + + html { + font-family: Satoshi, system-ui, sans-serif; + } + + body { + @apply bg-background font-medium text-foreground; + } } @layer base { @@ -80,4 +88,20 @@ body { @apply bg-background text-foreground; } + + @font-face { + font-family: "Satoshi"; + src: url("/fonts/satoshi/Satoshi-Variable.woff2") format("woff2"); + font-weight: 300 900; + font-display: swap; + font-style: normal; + } + + @font-face { + font-family: "Satoshi"; + src: url("/fonts/satoshi/Satoshi-VariableItalic.woff2") format("woff2"); + font-weight: 300 900; + font-display: swap; + font-style: italic; + } } diff --git a/src/app.d.ts b/src/app.d.ts index 10fbbcf..255bffa 100644 --- a/src/app.d.ts +++ b/src/app.d.ts @@ -7,7 +7,7 @@ declare global { namespace App { // interface Error {} interface Locals { - pb: TypedPocketBase + pb: TypedPocketBase; user: import("pocketbase").default["authStore"]["model"]; } // interface PageData {} diff --git a/src/hooks.client.ts b/src/hooks.client.ts index 1429387..bc0abf7 100644 --- a/src/hooks.client.ts +++ b/src/hooks.client.ts @@ -1,12 +1,9 @@ import type { Handle, HandleClientError } from "@sveltejs/kit"; import PocketBase from "pocketbase"; -import { dev } from "$app/environment"; import { env } from "$env/dynamic/public"; // Create a singleton instance -export const pbClient = new PocketBase( - dev ? "http://localhost:8090" : env.PUBLIC_POCKETBASE_URL, -); +export const pbClient = new PocketBase(env.PUBLIC_POCKETBASE_URL); export const handleError: HandleClientError = async ({ error }) => { // Handle client-side errors here diff --git a/src/hooks.server.ts b/src/hooks.server.ts index 8a11e8a..8b8bd26 100644 --- a/src/hooks.server.ts +++ b/src/hooks.server.ts @@ -2,7 +2,7 @@ export let requestIp: string; import { type Handle } from "@sveltejs/kit"; import { dev } from "$app/environment"; -import { createInstance } from "$lib/pocketbase"; +import { createInstance } from "./lib/pocketbase"; export const handle: Handle = async ({ event, resolve }) => { event.locals.pb = createInstance(); diff --git a/src/lib/pocketbase.ts b/src/lib/pocketbase.ts index 9397e49..8e54c91 100644 --- a/src/lib/pocketbase.ts +++ b/src/lib/pocketbase.ts @@ -1,36 +1,33 @@ import { env } from "$env/dynamic/public"; import PocketBase, { ClientResponseError } from "pocketbase"; -import { dev } from "$app/environment"; import type { TypedPocketBase } from "./types"; export function createInstance() { - return new PocketBase( - dev ? "http://0.0.0.0:8090" : env.PUBLIC_POCKETBASE_URL, - ) as TypedPocketBase; + return new PocketBase(env.PUBLIC_POCKETBASE_URL) as TypedPocketBase; } export const pb = createInstance() as TypedPocketBase; export function handlePocketBaseError(error: unknown) { - if (error instanceof ClientResponseError) { - // Connection refused - if (error.originalError?.cause?.message?.includes('ECONNREFUSED')) { - console.error('Cannot connect to PocketBase server'); - return new Error('Database connection failed'); - } - - // Auto-cancelled request - if (error.isAbort) { - console.error('Request was auto-cancelled'); - return new Error('Request timeout'); - } + if (error instanceof ClientResponseError) { + // Connection refused + if (error.originalError?.cause?.message?.includes("ECONNREFUSED")) { + console.error("Cannot connect to PocketBase server"); + return new Error("Database connection failed"); + } - // Other PocketBase errors - console.error(`PocketBase error ${error.status}: ${error.message}`); - return error; + // Auto-cancelled request + if (error.isAbort) { + console.error("Request was auto-cancelled"); + return new Error("Request timeout"); } - // Unknown errors - console.error('Unknown error:', error); - return new Error('An unexpected error occurred'); + // Other PocketBase errors + console.error(`PocketBase error ${error.status}: ${error.message}`); + return error; + } + + // Unknown errors + console.error("Unknown error:", error); + return new Error("An unexpected error occurred"); } diff --git a/src/lib/server/stripe-utils.ts b/src/lib/server/stripe-utils.ts index a14ad6b..9173da7 100644 --- a/src/lib/server/stripe-utils.ts +++ b/src/lib/server/stripe-utils.ts @@ -1,9 +1,11 @@ import { stripe } from "./stripe"; import type { UsersResponse } from "$lib/types"; import { env } from "$env/dynamic/private"; -import { createInstance } from "$lib/pocketbase"; -export async function createOrRetrieveStripeCustomer(user: UsersResponse) { +export async function createOrRetrieveStripeCustomer( + user: UsersResponse, + locals: any, +) { try { console.log( "Attempting to create or retrieve Stripe customer for user:", @@ -11,16 +13,14 @@ export async function createOrRetrieveStripeCustomer(user: UsersResponse) { ); // Create new pocketbase client as admin - const pb = createInstance(); - // Authenticate as admin - await pb.admins.authWithPassword( + await locals.pb.admins.authWithPassword( env.POCKETBASE_ADMIN_EMAIL!, env.POCKETBASE_ADMIN_PASSWORD!, ); // Check if customer already exists in PocketBase - const existingCustomer = await pb + const existingCustomer = await locals.pb .collection("customers") .getFirstListItem(`user_id="${user.id}"`) .catch(() => { @@ -45,7 +45,7 @@ export async function createOrRetrieveStripeCustomer(user: UsersResponse) { console.log("Stripe customer created successfully:", stripeCustomer.id); // Create customer record in PocketBase using authenticated client - const customer = await pb.collection("customers").create({ + const customer = await locals.pb.collection("customers").create({ user_id: user.id, stripe_customer_id: stripeCustomer.id, }); diff --git a/src/lib/types/cms-extented-types.ts b/src/lib/types/cms-extented-types.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/lib/types/cms-generated-types.ts b/src/lib/types/cms-generated-types.ts new file mode 100644 index 0000000..229da51 --- /dev/null +++ b/src/lib/types/cms-generated-types.ts @@ -0,0 +1,113 @@ +/** +* This file was @generated using pocketbase-typegen +*/ + +import type PocketBase from 'pocketbase' +import type { RecordService } from 'pocketbase' + +export enum Collections { + Blogs = "blogs", + Docs = "docs", + Users = "users", +} + +// Alias types for improved usability +export type IsoDateString = string +export type RecordIdString = string +export type HTMLString = string + +// System fields +export type BaseSystemFields = { + id: RecordIdString + created: IsoDateString + updated: IsoDateString + collectionId: string + collectionName: Collections + expand?: T +} + +export type AuthSystemFields = { + email: string + emailVisibility: boolean + username: string + verified: boolean +} & BaseSystemFields + +// Record types for each collection + +export enum BlogsStatusOptions { + "draft" = "draft", + "published" = "published", + "archived" = "archived", +} +export type BlogsRecord = { + author_id?: RecordIdString[] + content?: HTMLString + description?: string + featured_image?: string + published_at?: IsoDateString + slug?: string + status?: BlogsStatusOptions + tags?: string + title?: string +} + +export enum DocsTagsOptions { + "self–hosting" = "self–hosting", + "docker" = "docker", + "setup" = "setup", + "fli.so" = "fli.so", +} + +export enum DocsCategoryOptions { + "Getting Started" = "Getting Started", + "Features" = "Features", + "API Documentation" = "API Documentation", + "Troubleshooting" = "Troubleshooting", + "FAQs" = "FAQs", +} +export type DocsRecord = { + author?: RecordIdString + category?: DocsCategoryOptions + content?: HTMLString + description?: string + published?: boolean + slug?: string + tags?: DocsTagsOptions[] + title?: string +} + +export type UsersRecord = { + avatar?: string + bio?: string + name?: string + social_links?: null | Tsocial_links +} + +// Response types include system fields and match responses from the PocketBase API +export type BlogsResponse = Required & BaseSystemFields +export type DocsResponse = Required & BaseSystemFields +export type UsersResponse = Required> & AuthSystemFields + +// Types containing all Records and Responses, useful for creating typing helper functions + +export type CollectionRecords = { + blogs: BlogsRecord + docs: DocsRecord + users: UsersRecord +} + +export type CollectionResponses = { + blogs: BlogsResponse + docs: DocsResponse + users: UsersResponse +} + +// Type for usage with type asserted PocketBase instance +// https://github.com/pocketbase/js-sdk#specify-typescript-definitions + +export type TypedPocketBase = PocketBase & { + collection(idOrName: 'blogs'): RecordService + collection(idOrName: 'docs'): RecordService + collection(idOrName: 'users'): RecordService +} diff --git a/src/routes/+page.server.ts b/src/routes/+page.server.ts deleted file mode 100644 index 613f24a..0000000 --- a/src/routes/+page.server.ts +++ /dev/null @@ -1,5 +0,0 @@ -import type { PageServerLoad } from "./$types"; - -export const load = (async () => { - return {}; -}) satisfies PageServerLoad; diff --git a/src/routes/[slug]/+page.server.ts b/src/routes/[slug]/+page.server.ts index 2c8938a..2a3ee64 100644 --- a/src/routes/[slug]/+page.server.ts +++ b/src/routes/[slug]/+page.server.ts @@ -2,91 +2,107 @@ import { error, fail, redirect, type Actions } from "@sveltejs/kit"; import type { PageServerLoad } from "./$types"; import { env } from "$env/dynamic/private"; import type { UrlsResponse } from "$lib/types"; -import { createInstance } from "$lib/pocketbase"; import { hashPassword } from "$lib/utils/hash-password"; +import { createInstance } from "../../lib/pocketbase"; const HASH_SECRET = env.HASH_SECRET || "your-fallback-secret-key"; -export const load: PageServerLoad = async ({ params }) => { - // Authenticate as admin because we have api rules that prevent unauthenticated access +export const load: PageServerLoad = async ({ params, locals }) => { console.log("Starting load function with params:", params); - const pb = createInstance(); - await pb.admins.authWithPassword( - env.POCKETBASE_ADMIN_EMAIL!, - env.POCKETBASE_ADMIN_PASSWORD!, - ); - console.log("Successfully authenticated with PocketBase"); - - if (!params.slug) { - console.log("No slug provided in params"); - throw error(400, "Slug is required"); - } - console.log("Attempting to fetch URL with slug:", params.slug); - const url = await pb - .collection("urls") - .getFirstListItem(`slug = "${params.slug}"`) - .catch(() => { - console.log("URL not found for slug:", params.slug); - return null; + try { + // Authenticate as admin + await locals.pb.admins + .authWithPassword( + env.POCKETBASE_ADMIN_EMAIL!, + env.POCKETBASE_ADMIN_PASSWORD!, + ) + .catch((e) => { + console.error("Failed to authenticate as admin:", e); + throw error(500, "Failed to authenticate with PocketBase"); + }); + + if (!params.slug) { + console.log("No slug provided in params"); + throw error(400, "Slug is required"); + } + + if (params.slug.match(/\.(ico|png|jpg|jpeg|svg)$/i)) { + return { isStaticAsset: true }; + } + + const url = await locals.pb + .collection("urls") + .getFirstListItem(`slug = "${params.slug}"`) + .catch(() => { + console.log("URL not found for slug:", params.slug); + return null; + }); + + if (!url) { + throw error(404, "Not found"); + } + console.log("Found URL:", url); + + // Increment clicks + console.log("Incrementing clicks for URL ID:", url.id); + await locals.pb.collection("urls").update(url.id, { + clicks: url.clicks + 1, }); - if (!url) { - throw error(404, "Not found"); - } - console.log("Found URL:", url); - - // Increment clicks - console.log("Incrementing clicks for URL ID:", url.id); - await pb.collection("urls").update(url.id, { - clicks: url.clicks + 1, - }); - - // Check if the url is expired and redirect to expiration URL if needed - if (url.expiration && new Date(url.expiration) < new Date()) { - console.log("URL is expired. Expiration date:", url.expiration); - if (url.expiration_url) { - console.log("Redirecting to expiration URL:", url.expiration_url); - throw redirect(302, url.expiration_url); + // Check if the url is expired and redirect to expiration URL if needed + if (url.expiration && new Date(url.expiration) < new Date()) { + console.log("URL is expired. Expiration date:", url.expiration); + if (url.expiration_url) { + console.log("Redirecting to expiration URL:", url.expiration_url); + throw redirect(302, url.expiration_url); + } + throw error(410, "This link has expired"); } - throw error(410, "This link has expired"); - } - // If URL has password - if (url.password_hash) { - console.log("URL is password protected"); - return { - isProtected: true, - url_id: url.id, - }; - } + // If URL has password + if (url.password_hash) { + console.log("URL is password protected"); + return { + isProtected: true, + url_id: url.id, + }; + } - // If URL has meta data, return for brief display - if (url.meta_title || url.meta_description || url.meta_image_url) { - console.log("URL has meta data, returning meta information"); - return { - meta: { - title: url.meta_title, - description: url.meta_description || "not working", - image: url.meta_image_url, - url: url.url, - }, - }; - } + // If URL has meta data, return for brief display + if (url.meta_title || url.meta_description || url.meta_image_url) { + console.log("URL has meta data, returning meta information"); + return { + meta: { + title: url.meta_title, + description: url.meta_description || "not working", + image: url.meta_image_url, + url: url.url, + }, + }; + } - // No meta or password - direct redirect - console.log("Redirecting to URL:", url.url); - throw redirect(302, url.url); + // No meta or password - direct redirect + console.log("Redirecting to URL:", url.url); + throw redirect(302, url.url); + } catch (e) { + console.error("Error in load function:", e); + throw error(500, "Failed to load URL"); + } }; export const actions: Actions = { verify_password: async ({ request }) => { - const pb = createInstance(); - await pb.admins.authWithPassword( + const pb = createInstance(env.PUBLIC_POCKETBASE_URL!); + const authdata = await pb.admins.authWithPassword( env.POCKETBASE_ADMIN_EMAIL!, env.POCKETBASE_ADMIN_PASSWORD!, ); + if (!authdata.record) { + throw error(401, "Unauthorized"); + } + // Get form data from request const formData = await request.formData(); const url_id = formData.get("url_id") as string; diff --git a/src/routes/app/login/+page.server.ts b/src/routes/app/login/+page.server.ts index c945f76..546f04a 100644 --- a/src/routes/app/login/+page.server.ts +++ b/src/routes/app/login/+page.server.ts @@ -34,13 +34,14 @@ export const actions: Actions = { if (!authData.record.verified) { // Clear auth store since we don't want unverified users to remain logged in locals.pb.authStore.clear(); - + // Send another verification email await locals.pb.collection("users").requestVerification(email); - + return fail(403, { - message: "Please verify your email address. A new verification email has been sent.", - unverified: true + message: + "Please verify your email address. A new verification email has been sent.", + unverified: true, }); } } catch (err) { diff --git a/static/fonts/satoshi/Satoshi-Variable.woff b/static/fonts/satoshi/Satoshi-Variable.woff new file mode 100644 index 0000000..f8dcd1d Binary files /dev/null and b/static/fonts/satoshi/Satoshi-Variable.woff differ diff --git a/static/fonts/satoshi/Satoshi-Variable.woff2 b/static/fonts/satoshi/Satoshi-Variable.woff2 new file mode 100644 index 0000000..b00e833 Binary files /dev/null and b/static/fonts/satoshi/Satoshi-Variable.woff2 differ diff --git a/static/fonts/satoshi/Satoshi-VariableItalic.woff b/static/fonts/satoshi/Satoshi-VariableItalic.woff new file mode 100644 index 0000000..3fe029e Binary files /dev/null and b/static/fonts/satoshi/Satoshi-VariableItalic.woff differ diff --git a/static/fonts/satoshi/Satoshi-VariableItalic.woff2 b/static/fonts/satoshi/Satoshi-VariableItalic.woff2 new file mode 100644 index 0000000..e7ab3a0 Binary files /dev/null and b/static/fonts/satoshi/Satoshi-VariableItalic.woff2 differ diff --git a/tailwind.config.ts b/tailwind.config.ts index eac77dd..61ac924 100644 --- a/tailwind.config.ts +++ b/tailwind.config.ts @@ -63,7 +63,7 @@ const config: Config = { sm: "calc(var(--radius) - 4px)", }, fontFamily: { - sans: [...fontFamily.sans], + sans: ["Satoshi", ...fontFamily.sans], }, boxShadow: { right: "24px 0px 20px 0px rgba(0, 0, 0, 0.04)", diff --git a/tsconfig.json b/tsconfig.json index f4d0a0e..e671b90 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -9,11 +9,11 @@ "skipLibCheck": true, "sourceMap": true, "strict": true, - "moduleResolution": "bundler" + "moduleResolution": "bundler", } // Path aliases are handled by https://svelte.dev/docs/kit/configuration#alias // except $lib which is handled by https://svelte.dev/docs/kit/configuration#files // // If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes // from the referenced tsconfig.json - TypeScript does not merge them in -} +} \ No newline at end of file diff --git a/vite.config.ts b/vite.config.ts index 8e08994..a71188b 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -3,6 +3,12 @@ import { sveltekit } from "@sveltejs/kit/vite"; export default defineConfig({ plugins: [sveltekit()], + server: { + cors: { + origin: true, + credentials: true, + }, + }, test: { include: ["src/**/*.{test,spec}.{js,ts}"], },