From b4444e7bd2fe9eeae3f4c3e83eb9630aa68f0aa3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5kon=20St=C3=B8rdal?= <30749741+hakon55@users.noreply.github.com> Date: Tue, 2 Sep 2025 22:51:17 +0200 Subject: [PATCH] Working example --- .prettierrc | 16 -- package-lock.json | 186 ++++++++++++++++++ package.json | 5 + prettier.config.ts | 20 ++ src/hooks.client.ts | 21 +++ src/hooks.server.ts | 35 ++++ src/lib/WorkoutDisplay.svelte | 148 +++++++++++++++ src/lib/WorkoutLogger.svelte | 271 +++++++++++++++++++++++++++ src/lib/db.ts | 81 ++++++++ src/routes/+page.svelte | 35 +++- src/routes/DbConnection.svelte | 12 ++ src/routes/db.remote.js | 6 + src/routes/workout.remote.ts | 109 +++++++++++ svelte.config.js => svelte.config.ts | 12 +- 14 files changed, 935 insertions(+), 22 deletions(-) delete mode 100644 .prettierrc create mode 100644 prettier.config.ts create mode 100644 src/hooks.client.ts create mode 100644 src/hooks.server.ts create mode 100644 src/lib/WorkoutDisplay.svelte create mode 100644 src/lib/WorkoutLogger.svelte create mode 100644 src/lib/db.ts create mode 100644 src/routes/DbConnection.svelte create mode 100644 src/routes/db.remote.js create mode 100644 src/routes/workout.remote.ts rename svelte.config.js => svelte.config.ts (56%) diff --git a/.prettierrc b/.prettierrc deleted file mode 100644 index 8103a0b..0000000 --- a/.prettierrc +++ /dev/null @@ -1,16 +0,0 @@ -{ - "useTabs": true, - "singleQuote": true, - "trailingComma": "none", - "printWidth": 100, - "plugins": ["prettier-plugin-svelte", "prettier-plugin-tailwindcss"], - "overrides": [ - { - "files": "*.svelte", - "options": { - "parser": "svelte" - } - } - ], - "tailwindStylesheet": "./src/app.css" -} diff --git a/package-lock.json b/package-lock.json index a5dd651..f5ae55c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7,6 +7,11 @@ "": { "name": "egentrening", "version": "0.0.1", + "dependencies": { + "@types/pg": "^8.15.5", + "pg": "^8.16.3", + "zod": "^4.1.5" + }, "devDependencies": { "@sveltejs/adapter-auto": "^6.0.0", "@sveltejs/kit": "^2.22.0", @@ -1225,6 +1230,26 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/node": { + "version": "24.3.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.3.0.tgz", + "integrity": "sha512-aPTXCrfwnDLj4VvXrm+UUCQjNEvJgNA8s5F1cvwQU+3KNltTOkBm1j30uNLyqqPNe7gE3KFzImYoZEfLhp4Yow==", + "license": "MIT", + "dependencies": { + "undici-types": "~7.10.0" + } + }, + "node_modules/@types/pg": { + "version": "8.15.5", + "resolved": "https://registry.npmjs.org/@types/pg/-/pg-8.15.5.tgz", + "integrity": "sha512-LF7lF6zWEKxuT3/OR8wAZGzkg4ENGXFNyiV/JeOt9z5B+0ZVwbql9McqX5c/WStFq1GaGso7H1AzP/qSzmlCKQ==", + "license": "MIT", + "dependencies": { + "@types/node": "*", + "pg-protocol": "*", + "pg-types": "^2.2.0" + } + }, "node_modules/acorn": { "version": "8.15.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", @@ -1833,6 +1858,95 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, + "node_modules/pg": { + "version": "8.16.3", + "resolved": "https://registry.npmjs.org/pg/-/pg-8.16.3.tgz", + "integrity": "sha512-enxc1h0jA/aq5oSDMvqyW3q89ra6XIIDZgCX9vkMrnz5DFTw/Ny3Li2lFQ+pt3L6MCgm/5o2o8HW9hiJji+xvw==", + "license": "MIT", + "dependencies": { + "pg-connection-string": "^2.9.1", + "pg-pool": "^3.10.1", + "pg-protocol": "^1.10.3", + "pg-types": "2.2.0", + "pgpass": "1.0.5" + }, + "engines": { + "node": ">= 16.0.0" + }, + "optionalDependencies": { + "pg-cloudflare": "^1.2.7" + }, + "peerDependencies": { + "pg-native": ">=3.0.1" + }, + "peerDependenciesMeta": { + "pg-native": { + "optional": true + } + } + }, + "node_modules/pg-cloudflare": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.2.7.tgz", + "integrity": "sha512-YgCtzMH0ptvZJslLM1ffsY4EuGaU0cx4XSdXLRFae8bPP4dS5xL1tNB3k2o/N64cHJpwU7dxKli/nZ2lUa5fLg==", + "license": "MIT", + "optional": true + }, + "node_modules/pg-connection-string": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.9.1.tgz", + "integrity": "sha512-nkc6NpDcvPVpZXxrreI/FOtX3XemeLl8E0qFr6F2Lrm/I8WOnaWNhIPK2Z7OHpw7gh5XJThi6j6ppgNoaT1w4w==", + "license": "MIT" + }, + "node_modules/pg-int8": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", + "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==", + "license": "ISC", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/pg-pool": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.10.1.tgz", + "integrity": "sha512-Tu8jMlcX+9d8+QVzKIvM/uJtp07PKr82IUOYEphaWcoBhIYkoHpLXN3qO59nAI11ripznDsEzEv8nUxBVWajGg==", + "license": "MIT", + "peerDependencies": { + "pg": ">=8.0" + } + }, + "node_modules/pg-protocol": { + "version": "1.10.3", + "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.10.3.tgz", + "integrity": "sha512-6DIBgBQaTKDJyxnXaLiLR8wBpQQcGWuAESkRBX/t6OwA8YsqP+iVSiond2EDy6Y/dsGk8rh/jtax3js5NeV7JQ==", + "license": "MIT" + }, + "node_modules/pg-types": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", + "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", + "license": "MIT", + "dependencies": { + "pg-int8": "1.0.1", + "postgres-array": "~2.0.0", + "postgres-bytea": "~1.0.0", + "postgres-date": "~1.0.4", + "postgres-interval": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pgpass": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz", + "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==", + "license": "MIT", + "dependencies": { + "split2": "^4.1.0" + } + }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", @@ -1882,6 +1996,45 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/postgres-array": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", + "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/postgres-bytea": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz", + "integrity": "sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-date": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz", + "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-interval": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", + "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", + "license": "MIT", + "dependencies": { + "xtend": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/prettier": { "version": "3.6.2", "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz", @@ -2096,6 +2249,15 @@ "node": ">=0.10.0" } }, + "node_modules/split2": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", + "license": "ISC", + "engines": { + "node": ">= 10.x" + } + }, "node_modules/svelte": { "version": "5.38.6", "resolved": "https://registry.npmjs.org/svelte/-/svelte-5.38.6.tgz", @@ -2226,6 +2388,12 @@ "node": ">=14.17" } }, + "node_modules/undici-types": { + "version": "7.10.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.10.0.tgz", + "integrity": "sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag==", + "license": "MIT" + }, "node_modules/vite": { "version": "7.1.4", "resolved": "https://registry.npmjs.org/vite/-/vite-7.1.4.tgz", @@ -2321,6 +2489,15 @@ } } }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "license": "MIT", + "engines": { + "node": ">=0.4" + } + }, "node_modules/yallist": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", @@ -2337,6 +2514,15 @@ "integrity": "sha512-rAbqEGa8ovJy4pyBxZM70hg4pE6gDgaQ0Sl9M3enG3I0d6H4XSAM3GeNGLKnsBpuijUow064sf7ww1nutC5/3w==", "dev": true, "license": "MIT" + }, + "node_modules/zod": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.1.5.tgz", + "integrity": "sha512-rcUUZqlLJgBC33IT3PNMgsCq6TzLQEG/Ei/KTCU0PedSWRMAXoOUN+4t/0H+Q8bdnLPdqUYnvboJT0bn/229qg==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } } } } diff --git a/package.json b/package.json index 05ae257..9c16393 100644 --- a/package.json +++ b/package.json @@ -26,5 +26,10 @@ "tailwindcss": "^4.0.0", "typescript": "^5.0.0", "vite": "^7.0.4" + }, + "dependencies": { + "@types/pg": "^8.15.5", + "pg": "^8.16.3", + "zod": "^4.1.5" } } diff --git a/prettier.config.ts b/prettier.config.ts new file mode 100644 index 0000000..3eb33d8 --- /dev/null +++ b/prettier.config.ts @@ -0,0 +1,20 @@ +import type { Config } from 'prettier'; + +const config: Config = { + useTabs: true, + singleQuote: true, + trailingComma: 'none', + printWidth: 100, + plugins: ['prettier-plugin-svelte', 'prettier-plugin-tailwindcss'], + overrides: [ + { + files: '*.svelte', + options: { + parser: 'svelte' + } + } + ], + tailwindStylesheet: './src/app.css' +}; + +export default config; diff --git a/src/hooks.client.ts b/src/hooks.client.ts new file mode 100644 index 0000000..b3af44e --- /dev/null +++ b/src/hooks.client.ts @@ -0,0 +1,21 @@ +import type { HandleClientError } from '@sveltejs/kit'; +import { dev } from '$app/environment'; + +// Handle client-side errors +export const handleError: HandleClientError = ({ error, event }) => { + console.error('Client error:', error); + + // Log additional context in development + if (dev) { + console.error('Event details:', { + url: event.url, + route: event.route?.id + }); + } + + // Return user-friendly error message + return { + message: dev ? String(error) : 'Something went wrong', + code: 'CLIENT_ERROR' + }; +}; diff --git a/src/hooks.server.ts b/src/hooks.server.ts new file mode 100644 index 0000000..e91472a --- /dev/null +++ b/src/hooks.server.ts @@ -0,0 +1,35 @@ +import type { Handle, ServerInit } from '@sveltejs/kit'; +import { dev } from '$app/environment'; +import { db } from '$lib/db'; + +export const init: ServerInit = async () => { + db.createTables(); + console.log('Tables created'); +}; + +// The handle function runs on every request +export const handle: Handle = async ({ event, resolve }) => { + // Initialize on first request (lazy initialization) + + // Add custom headers or modify request/response if needed + const response = await resolve(event); + + // Optional: Add security headers + if (!dev) { + response.headers.set('X-Content-Type-Options', 'nosniff'); + response.headers.set('X-Frame-Options', 'DENY'); + response.headers.set('X-XSS-Protection', '1; mode=block'); + } + + return response; +}; + +// Optional: Handle server errors +export const handleError = ({ error, event }) => { + console.error('Server error:', error); + + // Don't expose sensitive error details in production + return { + message: dev ? String(error) : 'Internal server error' + }; +}; diff --git a/src/lib/WorkoutDisplay.svelte b/src/lib/WorkoutDisplay.svelte new file mode 100644 index 0000000..fcc7e7b --- /dev/null +++ b/src/lib/WorkoutDisplay.svelte @@ -0,0 +1,148 @@ + + +
Here by text
-Visit svelte.dev/docs/kit to read the documentation
+ + +Track your daily fitness progress
+ +Here be connection: {await testConnection().current}
+ + + {#snippet pending()} +loading...
+ {/snippet} +