Răsfoiți Sursa

Fix about 10k fuckups from grok

Lee Morgan 1 lună în urmă
părinte
comite
c93c955ed2

+ 1 - 1
src/lib/Header.svelte

@@ -5,7 +5,7 @@
 
 
     let {loggedIn} = $props();
     let {loggedIn} = $props();
     let notifications = getNotifications();
     let notifications = getNotifications();
-    let path = $derived(page.url.pathname);
+    let path = $derived(page.url?.pathname ?? "");
 </script>
 </script>
 
 
 {#if !path.endsWith("/print")}
 {#if !path.endsWith("/print")}

+ 0 - 8
src/lib/IngredientSearch.svelte

@@ -13,14 +13,6 @@
     let name = $state("");
     let name = $state("");
     let ingredients = $state(untrack(()=>startingIngredients ? [...startingIngredients] : []));
     let ingredients = $state(untrack(()=>startingIngredients ? [...startingIngredients] : []));
 
 
-    $effect(()=>{
-        if(!startingIngredients) return;
-        const next = [...startingIngredients];
-        untrack(()=>{
-            ingredients = next;
-        });
-    });
-
     const addIngredient = (event)=>{
     const addIngredient = (event)=>{
         event.preventDefault();
         event.preventDefault();
         const value = name.trim();
         const value = name.trim();

+ 8 - 0
src/lib/server/auth.js

@@ -25,5 +25,13 @@ export default async function userAuth(cookies, rdrct = true){
         }
         }
     }
     }
 
 
+    if(!user){
+        if(rdrct){
+            redirect(303, "/");
+        }else{
+            error(401, "Unauthorized");
+        }
+    }
+
     return user;
     return user;
 }
 }

+ 2 - 1
src/routes/+error.svelte

@@ -21,7 +21,8 @@
         justify-content: center;
         justify-content: center;
         align-items: center;
         align-items: center;
         width: 100%;
         width: 100%;
-        height: calc(100% - 75px);
+        min-height: calc(100% - 75px);
+        min-height: calc(100dvh - 75px);
         text-align: center;
         text-align: center;
     }
     }
 
 

+ 44 - 24
src/routes/+layout.svelte

@@ -1,35 +1,55 @@
 <script>
 <script>
     import "$lib/global.css";
     import "$lib/global.css";
     import Header from "$lib/Header.svelte";
     import Header from "$lib/Header.svelte";
-	import { pwaInfo } from 'virtual:pwa-info';
-	import { initPwaInstall } from '$lib/pwaInstall.svelte.js';
-
-	let {data, children} = $props();
-	let webManifest = $derived(pwaInfo ? pwaInfo.webManifest.linkTag : '');
-
-	$effect(() => {
-		initPwaInstall();
-
-		// Register the service worker quietly (no update toast).
-		let cancelled = false;
-		if (pwaInfo) {
-			import('virtual:pwa-register').then(({ registerSW }) => {
-				if (!cancelled) registerSW({ immediate: true });
-			});
-		}
-		return () => {
-			cancelled = true;
-		};
-	});
+    import {browser, dev} from "$app/environment";
+    import {pwaInfo} from "virtual:pwa-info";
+    import {initPwaInstall} from "$lib/pwaInstall.svelte.js";
+
+    let {data, children} = $props();
+    let webManifest = $derived(pwaInfo ? pwaInfo.webManifest.linkTag : "");
+
+    $effect(() => {
+        if(!browser) return;
+
+        let cancelled = false;
+
+        (async ()=>{
+            if("serviceWorker" in navigator){
+                const registrations = await navigator.serviceWorker.getRegistrations();
+                await Promise.all(registrations.map((registration)=>registration.unregister()));
+            }
+            if("caches" in window){
+                const keys = await caches.keys();
+                await Promise.all(keys.map((key)=>caches.delete(key)));
+            }
+
+            if(cancelled || dev) return;
+
+            initPwaInstall();
+            if(pwaInfo){
+                const {registerSW} = await import("virtual:pwa-register");
+                if(!cancelled) registerSW({immediate: true});
+            }
+        })();
+
+        return ()=>{
+            cancelled = true;
+        };
+    });
 </script>
 </script>
 
 
 <svelte:head>
 <svelte:head>
     <title>Recipes</title>
     <title>Recipes</title>
-	{#if webManifest}
-		{@html webManifest}
-	{/if}
+    {#if webManifest}
+        {@html webManifest}
+    {/if}
 </svelte:head>
 </svelte:head>
 
 
 <Header loggedIn={data.loggedIn} />
 <Header loggedIn={data.loggedIn} />
-
 {@render children()}
 {@render children()}
+
+<style>
+    :global(html){
+        height: 100%;
+    }
+</style>

+ 3 - 3
src/routes/dashboard/+page.server.js

@@ -10,8 +10,8 @@ export async function load({cookies}){
             id: {$toString: "$_id"},
             id: {$toString: "$_id"},
             name: 1,
             name: 1,
             updatedAt: 1
             updatedAt: 1
-        }},
-        {$sort: {name: 1}}
-    ]).collation({locale: "en", strength: 2});
+        }}
+    ]);
+    recipes.sort((a, b)=>String(a.name || "").localeCompare(String(b.name || ""), "en", {sensitivity: "base"}));
     return {recipes};
     return {recipes};
 }
 }

+ 1 - 1
src/routes/dashboard/+page.svelte

@@ -69,7 +69,7 @@
 
 
     <div class="recipes">
     <div class="recipes">
         {#each recipes as r}
         {#each recipes as r}
-            <a href="/recipe/{r.id}" class="recipe">
+            <a href="/recipe/{r.id}" class="recipe" data-sveltekit-reload>
                 <p class="name">{r.name}</p>
                 <p class="name">{r.name}</p>
                 <p class="date">{r.updatedAt ? new Date(r.updatedAt).toLocaleDateString() : ""}</p>
                 <p class="date">{r.updatedAt ? new Date(r.updatedAt).toLocaleDateString() : ""}</p>
             </a>
             </a>

+ 7 - 7
src/routes/login/+page.server.js

@@ -3,6 +3,7 @@ import User from "$lib/server/models/User.js";
 import bcrypt from "bcrypt";
 import bcrypt from "bcrypt";
 import jwt from "jsonwebtoken";
 import jwt from "jsonwebtoken";
 import {JWT_SECRET} from "$env/static/private";
 import {JWT_SECRET} from "$env/static/private";
+import {dev} from "$app/environment";
 
 
 export const actions = {
 export const actions = {
     default: async ({request, cookies})=>{
     default: async ({request, cookies})=>{
@@ -11,10 +12,9 @@ export const actions = {
         const password = data.get("password");
         const password = data.get("password");
 
 
         const user = await User.findOne({email: email});
         const user = await User.findOne({email: email});
+        const valid = user ? await bcrypt.compare(password, user.password) : false;
 
 
-        if(!user) return fail(401, "Wrong email or password");
-        
-        if(!bcrypt.compare(password, user.password)) return fail(401, "Wrong email or password");
+        if(!user || !valid) return fail(401, {message: "Wrong email or password"});
 
 
         const tokenData = {
         const tokenData = {
             id: user._id,
             id: user._id,
@@ -25,11 +25,11 @@ export const actions = {
         cookies.set("user", token, {
         cookies.set("user", token, {
             path: "/",
             path: "/",
             httpOnly: true,
             httpOnly: true,
-            secure: true,
-            sameSite: "strict",
-            maxAge: 60 * 60 *24 * 7 * 30
+            secure: !dev,
+            sameSite: "lax",
+            maxAge: 60 * 60 * 24 * 7 * 30
         });
         });
 
 
-        redirect(303, "/dashboard")
+        redirect(303, "/dashboard");
     }
     }
 }
 }

+ 2 - 1
src/routes/login/+page.svelte

@@ -29,7 +29,8 @@
         display: flex;
         display: flex;
         justify-content: center;
         justify-content: center;
         align-items: center;
         align-items: center;
+        flex: 1;
         width: 100%;
         width: 100%;
-        height: calc(100% - 75px);
+        min-height: calc(100dvh - 75px);
     }
     }
 </style>
 </style>

+ 27 - 18
src/routes/recipe/[recipeId]/+page.server.js

@@ -1,38 +1,47 @@
-import auth from "$lib/server/auth.js";
+import mongoose from "mongoose";
 import Recipe from "$lib/server/models/Recipe.js";
 import Recipe from "$lib/server/models/Recipe.js";
 import User from "$lib/server/models/User.js";
 import User from "$lib/server/models/User.js";
 import {JWT_SECRET} from "$env/static/private";
 import {JWT_SECRET} from "$env/static/private";
 import jwt from "jsonwebtoken";
 import jwt from "jsonwebtoken";
 
 
 export async function load({cookies, params}){
 export async function load({cookies, params}){
-    let recipe;
+    let recipe = null;
     let user = null;
     let user = null;
     let isOwner = false;
     let isOwner = false;
     try{
     try{
         const userData = jwt.verify(cookies.get("user"), JWT_SECRET);
         const userData = jwt.verify(cookies.get("user"), JWT_SECRET);
         user = await User.findOne({_id: userData.id, token: userData.token});
         user = await User.findOne({_id: userData.id, token: userData.token});
     }catch{}
     }catch{}
-    
 
 
     try{
     try{
-        recipe = await Recipe.findOne({_id: params.recipeId}, {"ingredients._id": 0}).lean();
-        isOwner = user && user._id.toString() === recipe.user.toString();
+        if(!mongoose.isValidObjectId(params.recipeId)){
+            return {isOwner, recipe};
+        }
 
 
-        if(recipe.private && !isOwner){
-            recipe = null;
-        }else{
-            recipe = {
-                id: recipe._id.toString(),
-                name: recipe.name,
-                ingredients: recipe.ingredients,
-                steps: recipe.steps,
-                notes: recipe.notes,
-                createdAt: recipe.createdAt,
-                updatedAt: recipe.updatedAt
-            };
+        const doc = await Recipe.findById(params.recipeId, {"ingredients._id": 0}).lean();
+        if(!doc){
+            return {isOwner, recipe};
         }
         }
-    }catch(e){
+
+        isOwner = !!(user && user._id.toString() === doc.user.toString());
+
+        if(doc.private && !isOwner){
+            return {isOwner: false, recipe: null};
+        }
+
+        recipe = {
+            id: doc._id.toString(),
+            name: doc.name,
+            ingredients: doc.ingredients ?? [],
+            steps: doc.steps ?? [],
+            notes: doc.notes ?? "",
+            private: doc.private,
+            createdAt: doc.createdAt,
+            updatedAt: doc.updatedAt
+        };
+    }catch{
         recipe = null;
         recipe = null;
+        isOwner = false;
     }
     }
 
 
     return {
     return {

+ 2 - 1
src/routes/register/+page.svelte

@@ -44,7 +44,8 @@
         display: flex;
         display: flex;
         justify-content: center;
         justify-content: center;
         align-items: center;
         align-items: center;
+        flex: 1;
         width: 100%;
         width: 100%;
-        height: calc(100% - 75px);
+        min-height: calc(100dvh - 75px);
     }
     }
 </style>
 </style>

+ 1 - 1
src/routes/search/+page.svelte

@@ -13,7 +13,7 @@
 
 
     <div class="recipes">
     <div class="recipes">
         {#each data.recipes as r}
         {#each data.recipes as r}
-            <a href="/recipe/{r.id}" class="recipe">
+            <a href="/recipe/{r.id}" class="recipe" data-sveltekit-reload>
                 <p class="name">{r.name}</p>
                 <p class="name">{r.name}</p>
                 <p class="date">{r.updatedAt ? new Date(r.updatedAt).toLocaleDateString() : ""}</p>
                 <p class="date">{r.updatedAt ? new Date(r.updatedAt).toLocaleDateString() : ""}</p>
             </a>
             </a>

+ 16 - 0
svelte.config.js

@@ -0,0 +1,16 @@
+import adapter from '@sveltejs/adapter-auto';
+
+/** @type {import('@sveltejs/kit').Config} */
+const config = {
+	kit: {
+		adapter: adapter(),
+		serviceWorker: {
+			register: false
+		}
+	},
+	compilerOptions: {
+		runes: true
+	}
+};
+
+export default config;

+ 3 - 22
vite.config.js

@@ -1,27 +1,10 @@
-import adapter from '@sveltejs/adapter-auto';
 import { sveltekit } from '@sveltejs/kit/vite';
 import { sveltekit } from '@sveltejs/kit/vite';
 import { SvelteKitPWA } from '@vite-pwa/sveltekit';
 import { SvelteKitPWA } from '@vite-pwa/sveltekit';
 import { defineConfig } from 'vite';
 import { defineConfig } from 'vite';
 
 
 export default defineConfig({
 export default defineConfig({
 	plugins: [
 	plugins: [
-		sveltekit({
-			compilerOptions: {
-				// Force runes mode for the project, except for libraries. Can be removed in svelte 6.
-				runes: ({ filename }) =>
-					filename.split(/[/\\]/).includes('node_modules') ? undefined : true
-			},
-
-			// adapter-auto only supports some environments, see https://svelte.dev/docs/kit/adapter-auto for a list.
-			// If your environment is not supported, or you settled on a specific environment, switch out the adapter.
-			// See https://svelte.dev/docs/kit/adapters for more information about adapters.
-			adapter: adapter(),
-
-			// Registration is handled by vite-plugin-pwa virtual modules.
-			serviceWorker: {
-				register: false
-			}
-		}),
+		sveltekit(),
 		SvelteKitPWA({
 		SvelteKitPWA({
 			registerType: 'autoUpdate',
 			registerType: 'autoUpdate',
 			injectRegister: null,
 			injectRegister: null,
@@ -173,11 +156,9 @@ export default defineConfig({
 				]
 				]
 			},
 			},
 			devOptions: {
 			devOptions: {
-				// Keep SW available in `vite dev` so install prompts can appear while developing.
-				enabled: true,
+				enabled: false,
 				suppressWarnings: true,
 				suppressWarnings: true,
-				type: 'module',
-				navigateFallback: '/'
+				type: 'module'
 			},
 			},
 			kit: {
 			kit: {
 				includeVersionFile: true
 				includeVersionFile: true