diff --git a/Les01-Introductie-AI/lesbestanden/les1-v0-workflow.zip b/Les01-Introductie-AI/lesbestanden/les1-v0-workflow.zip new file mode 100644 index 0000000..ce7218c Binary files /dev/null and b/Les01-Introductie-AI/lesbestanden/les1-v0-workflow.zip differ diff --git a/Les02-OpenCode/lesbestanden/opencode-ui-finished.zip b/Les02-OpenCode/lesbestanden/opencode-ui-finished.zip new file mode 100644 index 0000000..b30954f Binary files /dev/null and b/Les02-OpenCode/lesbestanden/opencode-ui-finished.zip differ diff --git a/Les02-OpenCode/lesbestanden/opencode-ui-starter.zip b/Les02-OpenCode/lesbestanden/opencode-ui-starter.zip new file mode 100644 index 0000000..4a12093 Binary files /dev/null and b/Les02-OpenCode/lesbestanden/opencode-ui-starter.zip differ diff --git a/Les03-Cursor-Basics/lesbestanden/cursor-rules-template.zip b/Les03-Cursor-Basics/lesbestanden/cursor-rules-template.zip new file mode 100644 index 0000000..113eba3 Binary files /dev/null and b/Les03-Cursor-Basics/lesbestanden/cursor-rules-template.zip differ diff --git a/Les03-Cursor-Basics/les3-debug-challenge-hard.zip b/Les03-Cursor-Basics/lesbestanden/les3-debug-challenge-hard.zip similarity index 100% rename from Les03-Cursor-Basics/les3-debug-challenge-hard.zip rename to Les03-Cursor-Basics/lesbestanden/les3-debug-challenge-hard.zip diff --git a/Les03-Cursor-Basics/les3-debug-challenge-super-hard.zip b/Les03-Cursor-Basics/lesbestanden/les3-debug-challenge-super-hard.zip similarity index 100% rename from Les03-Cursor-Basics/les3-debug-challenge-super-hard.zip rename to Les03-Cursor-Basics/lesbestanden/les3-debug-challenge-super-hard.zip diff --git a/Les03-Cursor-Basics/les3-debug-challenge.zip b/Les03-Cursor-Basics/lesbestanden/les3-debug-challenge.zip similarity index 100% rename from Les03-Cursor-Basics/les3-debug-challenge.zip rename to Les03-Cursor-Basics/lesbestanden/les3-debug-challenge.zip diff --git a/Les04-TypeScript-Fundamentals/les4-huiswerk-js-converter.zip b/Les04-TypeScript-Fundamentals/lesbestanden/les4-huiswerk-js-converter.zip similarity index 100% rename from Les04-TypeScript-Fundamentals/les4-huiswerk-js-converter.zip rename to Les04-TypeScript-Fundamentals/lesbestanden/les4-huiswerk-js-converter.zip diff --git a/Les04-TypeScript-Fundamentals/les4-typescript-escaperoom-v2.zip b/Les04-TypeScript-Fundamentals/lesbestanden/les4-typescript-escaperoom-v2.zip similarity index 100% rename from Les04-TypeScript-Fundamentals/les4-typescript-escaperoom-v2.zip rename to Les04-TypeScript-Fundamentals/lesbestanden/les4-typescript-escaperoom-v2.zip diff --git a/Les04-TypeScript-Fundamentals/les4-typescript-escaperoom.zip b/Les04-TypeScript-Fundamentals/lesbestanden/les4-typescript-escaperoom.zip similarity index 100% rename from Les04-TypeScript-Fundamentals/les4-typescript-escaperoom.zip rename to Les04-TypeScript-Fundamentals/lesbestanden/les4-typescript-escaperoom.zip diff --git a/Les05-NextJS-Basics/lesbestanden/quickpoll-finished.zip b/Les05-NextJS-Basics/lesbestanden/quickpoll-finished.zip new file mode 100644 index 0000000..0a42794 Binary files /dev/null and b/Les05-NextJS-Basics/lesbestanden/quickpoll-finished.zip differ diff --git a/Les05-NextJS-Basics/les5-quickpoll-starter.zip b/Les05-NextJS-Basics/lesbestanden/quickpoll-starter.zip similarity index 100% rename from Les05-NextJS-Basics/les5-quickpoll-starter.zip rename to Les05-NextJS-Basics/lesbestanden/quickpoll-starter.zip diff --git a/Les05-NextJS-Basics/quickpoll-starter.zip b/Les05-NextJS-Basics/quickpoll-starter.zip deleted file mode 100644 index 33f8e13..0000000 Binary files a/Les05-NextJS-Basics/quickpoll-starter.zip and /dev/null differ diff --git a/Les05-NextJS-Basics/quickpoll-starter/.cursorrules b/Les05-NextJS-Basics/quickpoll-starter/.cursorrules deleted file mode 100644 index 7de9420..0000000 --- a/Les05-NextJS-Basics/quickpoll-starter/.cursorrules +++ /dev/null @@ -1,6 +0,0 @@ -You are a Next.js 15 expert using App Router with TypeScript. -Use server components by default. -Use "use client" only when needed for interactivity. -Always define TypeScript interfaces for props, params, and API bodies. -Use Tailwind CSS for styling. -Use the @/ import alias for all local imports. diff --git a/Les05-NextJS-Basics/quickpoll-starter/.gitignore b/Les05-NextJS-Basics/quickpoll-starter/.gitignore deleted file mode 100644 index 5ef6a52..0000000 --- a/Les05-NextJS-Basics/quickpoll-starter/.gitignore +++ /dev/null @@ -1,41 +0,0 @@ -# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. - -# dependencies -/node_modules -/.pnp -.pnp.* -.yarn/* -!.yarn/patches -!.yarn/plugins -!.yarn/releases -!.yarn/versions - -# testing -/coverage - -# next.js -/.next/ -/out/ - -# production -/build - -# misc -.DS_Store -*.pem - -# debug -npm-debug.log* -yarn-debug.log* -yarn-error.log* -.pnpm-debug.log* - -# env files (can opt-in for committing if needed) -.env* - -# vercel -.vercel - -# typescript -*.tsbuildinfo -next-env.d.ts diff --git a/Les05-NextJS-Basics/quickpoll-starter/README.md b/Les05-NextJS-Basics/quickpoll-starter/README.md deleted file mode 100644 index e215bc4..0000000 --- a/Les05-NextJS-Basics/quickpoll-starter/README.md +++ /dev/null @@ -1,36 +0,0 @@ -This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app). - -## Getting Started - -First, run the development server: - -```bash -npm run dev -# or -yarn dev -# or -pnpm dev -# or -bun dev -``` - -Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. - -You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file. - -This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel. - -## Learn More - -To learn more about Next.js, take a look at the following resources: - -- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. -- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. - -You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome! - -## Deploy on Vercel - -The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. - -Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details. diff --git a/Les05-NextJS-Basics/quickpoll-starter/next.config.ts b/Les05-NextJS-Basics/quickpoll-starter/next.config.ts deleted file mode 100644 index e9ffa30..0000000 --- a/Les05-NextJS-Basics/quickpoll-starter/next.config.ts +++ /dev/null @@ -1,7 +0,0 @@ -import type { NextConfig } from "next"; - -const nextConfig: NextConfig = { - /* config options here */ -}; - -export default nextConfig; diff --git a/Les05-NextJS-Basics/quickpoll-starter/package-lock.json b/Les05-NextJS-Basics/quickpoll-starter/package-lock.json deleted file mode 100644 index 480ab5e..0000000 --- a/Les05-NextJS-Basics/quickpoll-starter/package-lock.json +++ /dev/null @@ -1,1664 +0,0 @@ -{ - "name": "quickpoll", - "version": "0.1.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "quickpoll", - "version": "0.1.0", - "dependencies": { - "next": "16.1.6", - "react": "19.2.3", - "react-dom": "19.2.3" - }, - "devDependencies": { - "@tailwindcss/postcss": "^4", - "@types/node": "^20", - "@types/react": "^19", - "@types/react-dom": "^19", - "tailwindcss": "^4", - "typescript": "^5" - } - }, - "node_modules/@alloc/quick-lru": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", - "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@emnapi/runtime": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.8.1.tgz", - "integrity": "sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg==", - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@img/colour": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.1.0.tgz", - "integrity": "sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==", - "license": "MIT", - "optional": true, - "engines": { - "node": ">=18" - } - }, - "node_modules/@img/sharp-darwin-arm64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.5.tgz", - "integrity": "sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==", - "cpu": [ - "arm64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-darwin-arm64": "1.2.4" - } - }, - "node_modules/@img/sharp-darwin-x64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.5.tgz", - "integrity": "sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==", - "cpu": [ - "x64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-darwin-x64": "1.2.4" - } - }, - "node_modules/@img/sharp-libvips-darwin-arm64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.4.tgz", - "integrity": "sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==", - "cpu": [ - "arm64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "darwin" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-darwin-x64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.4.tgz", - "integrity": "sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==", - "cpu": [ - "x64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "darwin" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-arm": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.4.tgz", - "integrity": "sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==", - "cpu": [ - "arm" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-arm64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.4.tgz", - "integrity": "sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==", - "cpu": [ - "arm64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-ppc64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.4.tgz", - "integrity": "sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==", - "cpu": [ - "ppc64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-riscv64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.2.4.tgz", - "integrity": "sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==", - "cpu": [ - "riscv64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-s390x": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.4.tgz", - "integrity": "sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==", - "cpu": [ - "s390x" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-x64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.4.tgz", - "integrity": "sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==", - "cpu": [ - "x64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linuxmusl-arm64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.4.tgz", - "integrity": "sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==", - "cpu": [ - "arm64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linuxmusl-x64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.4.tgz", - "integrity": "sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==", - "cpu": [ - "x64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-linux-arm": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.5.tgz", - "integrity": "sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==", - "cpu": [ - "arm" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-arm": "1.2.4" - } - }, - "node_modules/@img/sharp-linux-arm64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.5.tgz", - "integrity": "sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==", - "cpu": [ - "arm64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-arm64": "1.2.4" - } - }, - "node_modules/@img/sharp-linux-ppc64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.5.tgz", - "integrity": "sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==", - "cpu": [ - "ppc64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-ppc64": "1.2.4" - } - }, - "node_modules/@img/sharp-linux-riscv64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.34.5.tgz", - "integrity": "sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==", - "cpu": [ - "riscv64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-riscv64": "1.2.4" - } - }, - "node_modules/@img/sharp-linux-s390x": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.5.tgz", - "integrity": "sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==", - "cpu": [ - "s390x" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-s390x": "1.2.4" - } - }, - "node_modules/@img/sharp-linux-x64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.5.tgz", - "integrity": "sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==", - "cpu": [ - "x64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-x64": "1.2.4" - } - }, - "node_modules/@img/sharp-linuxmusl-arm64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.5.tgz", - "integrity": "sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==", - "cpu": [ - "arm64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-arm64": "1.2.4" - } - }, - "node_modules/@img/sharp-linuxmusl-x64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.5.tgz", - "integrity": "sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==", - "cpu": [ - "x64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-x64": "1.2.4" - } - }, - "node_modules/@img/sharp-wasm32": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.5.tgz", - "integrity": "sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==", - "cpu": [ - "wasm32" - ], - "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", - "optional": true, - "dependencies": { - "@emnapi/runtime": "^1.7.0" - }, - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-win32-arm64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.5.tgz", - "integrity": "sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==", - "cpu": [ - "arm64" - ], - "license": "Apache-2.0 AND LGPL-3.0-or-later", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-win32-ia32": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.5.tgz", - "integrity": "sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==", - "cpu": [ - "ia32" - ], - "license": "Apache-2.0 AND LGPL-3.0-or-later", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-win32-x64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.5.tgz", - "integrity": "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==", - "cpu": [ - "x64" - ], - "license": "Apache-2.0 AND LGPL-3.0-or-later", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.13", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", - "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.0", - "@jridgewell/trace-mapping": "^0.3.24" - } - }, - "node_modules/@jridgewell/remapping": { - "version": "2.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", - "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "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, - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", - "dev": true, - "license": "MIT" - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.31", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", - "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "node_modules/@next/env": { - "version": "16.1.6", - "resolved": "https://registry.npmjs.org/@next/env/-/env-16.1.6.tgz", - "integrity": "sha512-N1ySLuZjnAtN3kFnwhAwPvZah8RJxKasD7x1f8shFqhncnWZn4JMfg37diLNuoHsLAlrDfM3g4mawVdtAG8XLQ==", - "license": "MIT" - }, - "node_modules/@next/swc-darwin-arm64": { - "version": "16.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.1.6.tgz", - "integrity": "sha512-wTzYulosJr/6nFnqGW7FrG3jfUUlEf8UjGA0/pyypJl42ExdVgC6xJgcXQ+V8QFn6niSG2Pb8+MIG1mZr2vczw==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-darwin-x64": { - "version": "16.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.1.6.tgz", - "integrity": "sha512-BLFPYPDO+MNJsiDWbeVzqvYd4NyuRrEYVB5k2N3JfWncuHAy2IVwMAOlVQDFjj+krkWzhY2apvmekMkfQR0CUQ==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-linux-arm64-gnu": { - "version": "16.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.1.6.tgz", - "integrity": "sha512-OJYkCd5pj/QloBvoEcJ2XiMnlJkRv9idWA/j0ugSuA34gMT6f5b7vOiCQHVRpvStoZUknhl6/UxOXL4OwtdaBw==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-linux-arm64-musl": { - "version": "16.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.1.6.tgz", - "integrity": "sha512-S4J2v+8tT3NIO9u2q+S0G5KdvNDjXfAv06OhfOzNDaBn5rw84DGXWndOEB7d5/x852A20sW1M56vhC/tRVbccQ==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-linux-x64-gnu": { - "version": "16.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.1.6.tgz", - "integrity": "sha512-2eEBDkFlMMNQnkTyPBhQOAyn2qMxyG2eE7GPH2WIDGEpEILcBPI/jdSv4t6xupSP+ot/jkfrCShLAa7+ZUPcJQ==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-linux-x64-musl": { - "version": "16.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.1.6.tgz", - "integrity": "sha512-oicJwRlyOoZXVlxmIMaTq7f8pN9QNbdes0q2FXfRsPhfCi8n8JmOZJm5oo1pwDaFbnnD421rVU409M3evFbIqg==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-win32-arm64-msvc": { - "version": "16.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.1.6.tgz", - "integrity": "sha512-gQmm8izDTPgs+DCWH22kcDmuUp7NyiJgEl18bcr8irXA5N2m2O+JQIr6f3ct42GOs9c0h8QF3L5SzIxcYAAXXw==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-win32-x64-msvc": { - "version": "16.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.1.6.tgz", - "integrity": "sha512-NRfO39AIrzBnixKbjuo2YiYhB6o9d8v/ymU9m/Xk8cyVk+k7XylniXkHwjs4s70wedVffc6bQNbufk5v0xEm0A==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@swc/helpers": { - "version": "0.5.15", - "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz", - "integrity": "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==", - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.8.0" - } - }, - "node_modules/@tailwindcss/node": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.2.1.tgz", - "integrity": "sha512-jlx6sLk4EOwO6hHe1oCGm1Q4AN/s0rSrTTPBGPM0/RQ6Uylwq17FuU8IeJJKEjtc6K6O07zsvP+gDO6MMWo7pg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/remapping": "^2.3.5", - "enhanced-resolve": "^5.19.0", - "jiti": "^2.6.1", - "lightningcss": "1.31.1", - "magic-string": "^0.30.21", - "source-map-js": "^1.2.1", - "tailwindcss": "4.2.1" - } - }, - "node_modules/@tailwindcss/oxide": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.2.1.tgz", - "integrity": "sha512-yv9jeEFWnjKCI6/T3Oq50yQEOqmpmpfzG1hcZsAOaXFQPfzWprWrlHSdGPEF3WQTi8zu8ohC9Mh9J470nT5pUw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 20" - }, - "optionalDependencies": { - "@tailwindcss/oxide-android-arm64": "4.2.1", - "@tailwindcss/oxide-darwin-arm64": "4.2.1", - "@tailwindcss/oxide-darwin-x64": "4.2.1", - "@tailwindcss/oxide-freebsd-x64": "4.2.1", - "@tailwindcss/oxide-linux-arm-gnueabihf": "4.2.1", - "@tailwindcss/oxide-linux-arm64-gnu": "4.2.1", - "@tailwindcss/oxide-linux-arm64-musl": "4.2.1", - "@tailwindcss/oxide-linux-x64-gnu": "4.2.1", - "@tailwindcss/oxide-linux-x64-musl": "4.2.1", - "@tailwindcss/oxide-wasm32-wasi": "4.2.1", - "@tailwindcss/oxide-win32-arm64-msvc": "4.2.1", - "@tailwindcss/oxide-win32-x64-msvc": "4.2.1" - } - }, - "node_modules/@tailwindcss/oxide-android-arm64": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.2.1.tgz", - "integrity": "sha512-eZ7G1Zm5EC8OOKaesIKuw77jw++QJ2lL9N+dDpdQiAB/c/B2wDh0QPFHbkBVrXnwNugvrbJFk1gK2SsVjwWReg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">= 20" - } - }, - "node_modules/@tailwindcss/oxide-darwin-arm64": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.2.1.tgz", - "integrity": "sha512-q/LHkOstoJ7pI1J0q6djesLzRvQSIfEto148ppAd+BVQK0JYjQIFSK3JgYZJa+Yzi0DDa52ZsQx2rqytBnf8Hw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 20" - } - }, - "node_modules/@tailwindcss/oxide-darwin-x64": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.2.1.tgz", - "integrity": "sha512-/f/ozlaXGY6QLbpvd/kFTro2l18f7dHKpB+ieXz+Cijl4Mt9AI2rTrpq7V+t04nK+j9XBQHnSMdeQRhbGyt6fw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 20" - } - }, - "node_modules/@tailwindcss/oxide-freebsd-x64": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.2.1.tgz", - "integrity": "sha512-5e/AkgYJT/cpbkys/OU2Ei2jdETCLlifwm7ogMC7/hksI2fC3iiq6OcXwjibcIjPung0kRtR3TxEITkqgn0TcA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">= 20" - } - }, - "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.2.1.tgz", - "integrity": "sha512-Uny1EcVTTmerCKt/1ZuKTkb0x8ZaiuYucg2/kImO5A5Y/kBz41/+j0gxUZl+hTF3xkWpDmHX+TaWhOtba2Fyuw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 20" - } - }, - "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.2.1.tgz", - "integrity": "sha512-CTrwomI+c7n6aSSQlsPL0roRiNMDQ/YzMD9EjcR+H4f0I1SQ8QqIuPnsVp7QgMkC1Qi8rtkekLkOFjo7OlEFRQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 20" - } - }, - "node_modules/@tailwindcss/oxide-linux-arm64-musl": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.2.1.tgz", - "integrity": "sha512-WZA0CHRL/SP1TRbA5mp9htsppSEkWuQ4KsSUumYQnyl8ZdT39ntwqmz4IUHGN6p4XdSlYfJwM4rRzZLShHsGAQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 20" - } - }, - "node_modules/@tailwindcss/oxide-linux-x64-gnu": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.2.1.tgz", - "integrity": "sha512-qMFzxI2YlBOLW5PhblzuSWlWfwLHaneBE0xHzLrBgNtqN6mWfs+qYbhryGSXQjFYB1Dzf5w+LN5qbUTPhW7Y5g==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 20" - } - }, - "node_modules/@tailwindcss/oxide-linux-x64-musl": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.2.1.tgz", - "integrity": "sha512-5r1X2FKnCMUPlXTWRYpHdPYUY6a1Ar/t7P24OuiEdEOmms5lyqjDRvVY1yy9Rmioh+AunQ0rWiOTPE8F9A3v5g==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 20" - } - }, - "node_modules/@tailwindcss/oxide-wasm32-wasi": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.2.1.tgz", - "integrity": "sha512-MGFB5cVPvshR85MTJkEvqDUnuNoysrsRxd6vnk1Lf2tbiqNlXpHYZqkqOQalydienEWOHHFyyuTSYRsLfxFJ2Q==", - "bundleDependencies": [ - "@napi-rs/wasm-runtime", - "@emnapi/core", - "@emnapi/runtime", - "@tybys/wasm-util", - "@emnapi/wasi-threads", - "tslib" - ], - "cpu": [ - "wasm32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@emnapi/core": "^1.8.1", - "@emnapi/runtime": "^1.8.1", - "@emnapi/wasi-threads": "^1.1.0", - "@napi-rs/wasm-runtime": "^1.1.1", - "@tybys/wasm-util": "^0.10.1", - "tslib": "^2.8.1" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.2.1.tgz", - "integrity": "sha512-YlUEHRHBGnCMh4Nj4GnqQyBtsshUPdiNroZj8VPkvTZSoHsilRCwXcVKnG9kyi0ZFAS/3u+qKHBdDc81SADTRA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 20" - } - }, - "node_modules/@tailwindcss/oxide-win32-x64-msvc": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.2.1.tgz", - "integrity": "sha512-rbO34G5sMWWyrN/idLeVxAZgAKWrn5LiR3/I90Q9MkA67s6T1oB0xtTe+0heoBvHSpbU9Mk7i6uwJnpo4u21XQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 20" - } - }, - "node_modules/@tailwindcss/postcss": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/postcss/-/postcss-4.2.1.tgz", - "integrity": "sha512-OEwGIBnXnj7zJeonOh6ZG9woofIjGrd2BORfvE5p9USYKDCZoQmfqLcfNiRWoJlRWLdNPn2IgVZuWAOM4iTYMw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@alloc/quick-lru": "^5.2.0", - "@tailwindcss/node": "4.2.1", - "@tailwindcss/oxide": "4.2.1", - "postcss": "^8.5.6", - "tailwindcss": "4.2.1" - } - }, - "node_modules/@types/node": { - "version": "20.19.37", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.37.tgz", - "integrity": "sha512-8kzdPJ3FsNsVIurqBs7oodNnCEVbni9yUEkaHbgptDACOPW04jimGagZ51E6+lXUwJjgnBw+hyko/lkFWCldqw==", - "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": "~6.21.0" - } - }, - "node_modules/@types/react": { - "version": "19.2.14", - "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.14.tgz", - "integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==", - "dev": true, - "license": "MIT", - "dependencies": { - "csstype": "^3.2.2" - } - }, - "node_modules/@types/react-dom": { - "version": "19.2.3", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", - "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "@types/react": "^19.2.0" - } - }, - "node_modules/baseline-browser-mapping": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.0.tgz", - "integrity": "sha512-lIyg0szRfYbiy67j9KN8IyeD7q7hcmqnJ1ddWmNt19ItGpNN64mnllmxUNFIOdOm6by97jlL6wfpTTJrmnjWAA==", - "license": "Apache-2.0", - "bin": { - "baseline-browser-mapping": "dist/cli.cjs" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001777", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001777.tgz", - "integrity": "sha512-tmN+fJxroPndC74efCdp12j+0rk0RHwV5Jwa1zWaFVyw2ZxAuPeG8ZgWC3Wz7uSjT3qMRQ5XHZ4COgQmsCMJAQ==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "CC-BY-4.0" - }, - "node_modules/client-only": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", - "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==", - "license": "MIT" - }, - "node_modules/csstype": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", - "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/detect-libc": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", - "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", - "devOptional": true, - "license": "Apache-2.0", - "engines": { - "node": ">=8" - } - }, - "node_modules/enhanced-resolve": { - "version": "5.20.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.20.0.tgz", - "integrity": "sha512-/ce7+jQ1PQ6rVXwe+jKEg5hW5ciicHwIQUagZkp6IufBoY3YDgdTTY1azVs0qoRgVmvsNB+rbjLJxDAeHHtwsQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.2.4", - "tapable": "^2.3.0" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/jiti": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", - "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", - "dev": true, - "license": "MIT", - "bin": { - "jiti": "lib/jiti-cli.mjs" - } - }, - "node_modules/lightningcss": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.31.1.tgz", - "integrity": "sha512-l51N2r93WmGUye3WuFoN5k10zyvrVs0qfKBhyC5ogUQ6Ew6JUSswh78mbSO+IU3nTWsyOArqPCcShdQSadghBQ==", - "dev": true, - "license": "MPL-2.0", - "dependencies": { - "detect-libc": "^2.0.3" - }, - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - }, - "optionalDependencies": { - "lightningcss-android-arm64": "1.31.1", - "lightningcss-darwin-arm64": "1.31.1", - "lightningcss-darwin-x64": "1.31.1", - "lightningcss-freebsd-x64": "1.31.1", - "lightningcss-linux-arm-gnueabihf": "1.31.1", - "lightningcss-linux-arm64-gnu": "1.31.1", - "lightningcss-linux-arm64-musl": "1.31.1", - "lightningcss-linux-x64-gnu": "1.31.1", - "lightningcss-linux-x64-musl": "1.31.1", - "lightningcss-win32-arm64-msvc": "1.31.1", - "lightningcss-win32-x64-msvc": "1.31.1" - } - }, - "node_modules/lightningcss-android-arm64": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.31.1.tgz", - "integrity": "sha512-HXJF3x8w9nQ4jbXRiNppBCqeZPIAfUo8zE/kOEGbW5NZvGc/K7nMxbhIr+YlFlHW5mpbg/YFPdbnCh1wAXCKFg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-darwin-arm64": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.31.1.tgz", - "integrity": "sha512-02uTEqf3vIfNMq3h/z2cJfcOXnQ0GRwQrkmPafhueLb2h7mqEidiCzkE4gBMEH65abHRiQvhdcQ+aP0D0g67sg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-darwin-x64": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.31.1.tgz", - "integrity": "sha512-1ObhyoCY+tGxtsz1lSx5NXCj3nirk0Y0kB/g8B8DT+sSx4G9djitg9ejFnjb3gJNWo7qXH4DIy2SUHvpoFwfTA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-freebsd-x64": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.31.1.tgz", - "integrity": "sha512-1RINmQKAItO6ISxYgPwszQE1BrsVU5aB45ho6O42mu96UiZBxEXsuQ7cJW4zs4CEodPUioj/QrXW1r9pLUM74A==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-arm-gnueabihf": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.31.1.tgz", - "integrity": "sha512-OOCm2//MZJ87CdDK62rZIu+aw9gBv4azMJuA8/KB74wmfS3lnC4yoPHm0uXZ/dvNNHmnZnB8XLAZzObeG0nS1g==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-arm64-gnu": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.31.1.tgz", - "integrity": "sha512-WKyLWztD71rTnou4xAD5kQT+982wvca7E6QoLpoawZ1gP9JM0GJj4Tp5jMUh9B3AitHbRZ2/H3W5xQmdEOUlLg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-arm64-musl": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.31.1.tgz", - "integrity": "sha512-mVZ7Pg2zIbe3XlNbZJdjs86YViQFoJSpc41CbVmKBPiGmC4YrfeOyz65ms2qpAobVd7WQsbW4PdsSJEMymyIMg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-x64-gnu": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.31.1.tgz", - "integrity": "sha512-xGlFWRMl+0KvUhgySdIaReQdB4FNudfUTARn7q0hh/V67PVGCs3ADFjw+6++kG1RNd0zdGRlEKa+T13/tQjPMA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-x64-musl": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.31.1.tgz", - "integrity": "sha512-eowF8PrKHw9LpoZii5tdZwnBcYDxRw2rRCyvAXLi34iyeYfqCQNA9rmUM0ce62NlPhCvof1+9ivRaTY6pSKDaA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-win32-arm64-msvc": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.31.1.tgz", - "integrity": "sha512-aJReEbSEQzx1uBlQizAOBSjcmr9dCdL3XuC/6HLXAxmtErsj2ICo5yYggg1qOODQMtnjNQv2UHb9NpOuFtYe4w==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-win32-x64-msvc": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.31.1.tgz", - "integrity": "sha512-I9aiFrbd7oYHwlnQDqr1Roz+fTz61oDDJX7n9tYF9FJymH1cIN1DtKw3iYt6b8WZgEjoNwVSncwF4wx/ZedMhw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/magic-string": { - "version": "0.30.21", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", - "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.5" - } - }, - "node_modules/nanoid": { - "version": "3.3.11", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", - "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/next": { - "version": "16.1.6", - "resolved": "https://registry.npmjs.org/next/-/next-16.1.6.tgz", - "integrity": "sha512-hkyRkcu5x/41KoqnROkfTm2pZVbKxvbZRuNvKXLRXxs3VfyO0WhY50TQS40EuKO9SW3rBj/sF3WbVwDACeMZyw==", - "license": "MIT", - "dependencies": { - "@next/env": "16.1.6", - "@swc/helpers": "0.5.15", - "baseline-browser-mapping": "^2.8.3", - "caniuse-lite": "^1.0.30001579", - "postcss": "8.4.31", - "styled-jsx": "5.1.6" - }, - "bin": { - "next": "dist/bin/next" - }, - "engines": { - "node": ">=20.9.0" - }, - "optionalDependencies": { - "@next/swc-darwin-arm64": "16.1.6", - "@next/swc-darwin-x64": "16.1.6", - "@next/swc-linux-arm64-gnu": "16.1.6", - "@next/swc-linux-arm64-musl": "16.1.6", - "@next/swc-linux-x64-gnu": "16.1.6", - "@next/swc-linux-x64-musl": "16.1.6", - "@next/swc-win32-arm64-msvc": "16.1.6", - "@next/swc-win32-x64-msvc": "16.1.6", - "sharp": "^0.34.4" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.1.0", - "@playwright/test": "^1.51.1", - "babel-plugin-react-compiler": "*", - "react": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", - "react-dom": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", - "sass": "^1.3.0" - }, - "peerDependenciesMeta": { - "@opentelemetry/api": { - "optional": true - }, - "@playwright/test": { - "optional": true - }, - "babel-plugin-react-compiler": { - "optional": true - }, - "sass": { - "optional": true - } - } - }, - "node_modules/next/node_modules/postcss": { - "version": "8.4.31", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", - "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "nanoid": "^3.3.6", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/picocolors": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "license": "ISC" - }, - "node_modules/postcss": { - "version": "8.5.8", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.8.tgz", - "integrity": "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "nanoid": "^3.3.11", - "picocolors": "^1.1.1", - "source-map-js": "^1.2.1" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/react": { - "version": "19.2.3", - "resolved": "https://registry.npmjs.org/react/-/react-19.2.3.tgz", - "integrity": "sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/react-dom": { - "version": "19.2.3", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.3.tgz", - "integrity": "sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg==", - "license": "MIT", - "dependencies": { - "scheduler": "^0.27.0" - }, - "peerDependencies": { - "react": "^19.2.3" - } - }, - "node_modules/scheduler": { - "version": "0.27.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", - "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", - "license": "MIT" - }, - "node_modules/semver": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", - "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", - "license": "ISC", - "optional": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/sharp": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.5.tgz", - "integrity": "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==", - "hasInstallScript": true, - "license": "Apache-2.0", - "optional": true, - "dependencies": { - "@img/colour": "^1.0.0", - "detect-libc": "^2.1.2", - "semver": "^7.7.3" - }, - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-darwin-arm64": "0.34.5", - "@img/sharp-darwin-x64": "0.34.5", - "@img/sharp-libvips-darwin-arm64": "1.2.4", - "@img/sharp-libvips-darwin-x64": "1.2.4", - "@img/sharp-libvips-linux-arm": "1.2.4", - "@img/sharp-libvips-linux-arm64": "1.2.4", - "@img/sharp-libvips-linux-ppc64": "1.2.4", - "@img/sharp-libvips-linux-riscv64": "1.2.4", - "@img/sharp-libvips-linux-s390x": "1.2.4", - "@img/sharp-libvips-linux-x64": "1.2.4", - "@img/sharp-libvips-linuxmusl-arm64": "1.2.4", - "@img/sharp-libvips-linuxmusl-x64": "1.2.4", - "@img/sharp-linux-arm": "0.34.5", - "@img/sharp-linux-arm64": "0.34.5", - "@img/sharp-linux-ppc64": "0.34.5", - "@img/sharp-linux-riscv64": "0.34.5", - "@img/sharp-linux-s390x": "0.34.5", - "@img/sharp-linux-x64": "0.34.5", - "@img/sharp-linuxmusl-arm64": "0.34.5", - "@img/sharp-linuxmusl-x64": "0.34.5", - "@img/sharp-wasm32": "0.34.5", - "@img/sharp-win32-arm64": "0.34.5", - "@img/sharp-win32-ia32": "0.34.5", - "@img/sharp-win32-x64": "0.34.5" - } - }, - "node_modules/source-map-js": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", - "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/styled-jsx": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.6.tgz", - "integrity": "sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==", - "license": "MIT", - "dependencies": { - "client-only": "0.0.1" - }, - "engines": { - "node": ">= 12.0.0" - }, - "peerDependencies": { - "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0" - }, - "peerDependenciesMeta": { - "@babel/core": { - "optional": true - }, - "babel-plugin-macros": { - "optional": true - } - } - }, - "node_modules/tailwindcss": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.2.1.tgz", - "integrity": "sha512-/tBrSQ36vCleJkAOsy9kbNTgaxvGbyOamC30PRePTQe/o1MFwEKHQk4Cn7BNGaPtjp+PuUrByJehM1hgxfq4sw==", - "dev": true, - "license": "MIT" - }, - "node_modules/tapable": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz", - "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/tslib": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "license": "0BSD" - }, - "node_modules/typescript": { - "version": "5.9.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", - "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/undici-types": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", - "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", - "dev": true, - "license": "MIT" - } - } -} diff --git a/Les05-NextJS-Basics/quickpoll-starter/package.json b/Les05-NextJS-Basics/quickpoll-starter/package.json deleted file mode 100644 index 031dcdd..0000000 --- a/Les05-NextJS-Basics/quickpoll-starter/package.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "name": "quickpoll", - "version": "0.1.0", - "private": true, - "scripts": { - "dev": "next dev", - "build": "next build", - "start": "next start" - }, - "dependencies": { - "next": "16.1.6", - "react": "19.2.3", - "react-dom": "19.2.3" - }, - "devDependencies": { - "@tailwindcss/postcss": "^4", - "@types/node": "^20", - "@types/react": "^19", - "@types/react-dom": "^19", - "tailwindcss": "^4", - "typescript": "^5" - } -} diff --git a/Les05-NextJS-Basics/quickpoll-starter/postcss.config.mjs b/Les05-NextJS-Basics/quickpoll-starter/postcss.config.mjs deleted file mode 100644 index 61e3684..0000000 --- a/Les05-NextJS-Basics/quickpoll-starter/postcss.config.mjs +++ /dev/null @@ -1,7 +0,0 @@ -const config = { - plugins: { - "@tailwindcss/postcss": {}, - }, -}; - -export default config; diff --git a/Les05-NextJS-Basics/quickpoll-starter/public/file.svg b/Les05-NextJS-Basics/quickpoll-starter/public/file.svg deleted file mode 100644 index 004145c..0000000 --- a/Les05-NextJS-Basics/quickpoll-starter/public/file.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/Les05-NextJS-Basics/quickpoll-starter/public/globe.svg b/Les05-NextJS-Basics/quickpoll-starter/public/globe.svg deleted file mode 100644 index 567f17b..0000000 --- a/Les05-NextJS-Basics/quickpoll-starter/public/globe.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/Les05-NextJS-Basics/quickpoll-starter/public/next.svg b/Les05-NextJS-Basics/quickpoll-starter/public/next.svg deleted file mode 100644 index 5174b28..0000000 --- a/Les05-NextJS-Basics/quickpoll-starter/public/next.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/Les05-NextJS-Basics/quickpoll-starter/public/vercel.svg b/Les05-NextJS-Basics/quickpoll-starter/public/vercel.svg deleted file mode 100644 index 7705396..0000000 --- a/Les05-NextJS-Basics/quickpoll-starter/public/vercel.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/Les05-NextJS-Basics/quickpoll-starter/public/window.svg b/Les05-NextJS-Basics/quickpoll-starter/public/window.svg deleted file mode 100644 index b2b2a44..0000000 --- a/Les05-NextJS-Basics/quickpoll-starter/public/window.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/Les05-NextJS-Basics/quickpoll-starter/src/app/api/polls/[id]/route.ts b/Les05-NextJS-Basics/quickpoll-starter/src/app/api/polls/[id]/route.ts deleted file mode 100644 index 23d2baa..0000000 --- a/Les05-NextJS-Basics/quickpoll-starter/src/app/api/polls/[id]/route.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { NextResponse } from "next/server"; -import { getPollById } from "@/lib/data"; - -interface RouteParams { - params: Promise<{ id: string }>; -} - -// STAP 3: GET /api/polls/[id] — enkele poll ophalen -// -// Wat moet je doen? -// 1. Haal het id op uit params (let op: params is een Promise!) -// 2. Zoek de poll met getPollById(id) -// 3. Als de poll niet bestaat, return een 404 JSON response -// 4. Als de poll wel bestaat, return de poll als JSON -// -// Hint: kijk naar /api/polls/route.ts voor een voorbeeld van NextResponse.json() - -export async function GET( - request: Request, - { params }: RouteParams -): Promise { - // Jouw code hier... - return NextResponse.json({ error: "Nog niet geimplementeerd" }, { status: 501 }); -} diff --git a/Les05-NextJS-Basics/quickpoll-starter/src/app/api/polls/[id]/vote/route.ts b/Les05-NextJS-Basics/quickpoll-starter/src/app/api/polls/[id]/vote/route.ts deleted file mode 100644 index fc10810..0000000 --- a/Les05-NextJS-Basics/quickpoll-starter/src/app/api/polls/[id]/vote/route.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { NextResponse } from "next/server"; -import { votePoll } from "@/lib/data"; - -interface RouteParams { - params: Promise<{ id: string }>; -} - -interface VoteBody { - optionIndex: number; -} - -// STAP 4: POST /api/polls/[id]/vote — stem uitbrengen -// -// Wat moet je doen? -// 1. Haal het id op uit params -// 2. Lees de request body (request.json()) en cast naar VoteBody -// 3. Valideer: is optionIndex een number? -// 4. Roep votePoll(id, body.optionIndex) aan -// 5. Als het resultaat undefined is: return 404 -// 6. Anders: return de geüpdatete poll als JSON - -export async function POST( - request: Request, - { params }: RouteParams -): Promise { - // Jouw code hier... - return NextResponse.json({ error: "Nog niet geimplementeerd" }, { status: 501 }); -} diff --git a/Les05-NextJS-Basics/quickpoll-starter/src/app/api/polls/route.ts b/Les05-NextJS-Basics/quickpoll-starter/src/app/api/polls/route.ts deleted file mode 100644 index 0f647ef..0000000 --- a/Les05-NextJS-Basics/quickpoll-starter/src/app/api/polls/route.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { NextResponse } from "next/server"; -import { getPolls, createPoll } from "@/lib/data"; -import type { Poll, CreatePollBody } from "@/types"; - -// GET /api/polls — alle polls ophalen -export async function GET(): Promise> { - const polls = getPolls(); - return NextResponse.json(polls); -} - -// POST /api/polls — nieuwe poll aanmaken -export async function POST(request: Request): Promise { - const body: CreatePollBody = await request.json(); - - if (!body.question || !body.options || body.options.length < 2) { - return NextResponse.json( - { error: "Vraag en minstens 2 opties zijn verplicht" }, - { status: 400 } - ); - } - - const newPoll = createPoll(body.question, body.options); - return NextResponse.json(newPoll, { status: 201 }); -} diff --git a/Les05-NextJS-Basics/quickpoll-starter/src/app/create/page.tsx b/Les05-NextJS-Basics/quickpoll-starter/src/app/create/page.tsx deleted file mode 100644 index f27f872..0000000 --- a/Les05-NextJS-Basics/quickpoll-starter/src/app/create/page.tsx +++ /dev/null @@ -1,32 +0,0 @@ -"use client"; - -import { useState } from "react"; -import { useRouter } from "next/navigation"; - -// BONUS: Maak een formulier om een nieuwe poll aan te maken -// -// Benodigde state: -// - question: string -// - options: string[] (start met ["", ""]) -// - isSubmitting: boolean -// - error: string | null -// -// Wat moet je bouwen? -// 1. Een input voor de vraag -// 2. Inputs voor de opties (minimaal 2, maximaal 6) -// 3. Knoppen om opties toe te voegen/verwijderen -// 4. Een submit knop die POST naar /api/polls -// 5. Na success: redirect naar / met router.push("/") - -export default function CreatePollPage() { - return ( -
-

- Nieuwe Poll Aanmaken -

-

- Bonus: bouw hier het create formulier -

-
- ); -} diff --git a/Les05-NextJS-Basics/quickpoll-starter/src/app/error.tsx b/Les05-NextJS-Basics/quickpoll-starter/src/app/error.tsx deleted file mode 100644 index 8d17fc4..0000000 --- a/Les05-NextJS-Basics/quickpoll-starter/src/app/error.tsx +++ /dev/null @@ -1,30 +0,0 @@ -"use client"; - -// STAP 7: Error boundary -// -// Dit bestand vangt fouten op in de route. -// MOET een client component zijn ("use client" staat al bovenaan). -// -// Props die je krijgt: -// - error: Error — het error object met .message -// - reset: () => void — functie om de pagina opnieuw te proberen -// -// Bouw een nette error pagina met: -// - Een titel "Er ging iets mis!" -// - De error message -// - Een "Probeer opnieuw" knop die reset() aanroept - -export default function Error({ - error, - reset, -}: { - error: Error; - reset: () => void; -}) { - return ( -
-

Er ging iets mis: {error.message}

- -
- ); -} diff --git a/Les05-NextJS-Basics/quickpoll-starter/src/app/favicon.ico b/Les05-NextJS-Basics/quickpoll-starter/src/app/favicon.ico deleted file mode 100644 index 718d6fe..0000000 Binary files a/Les05-NextJS-Basics/quickpoll-starter/src/app/favicon.ico and /dev/null differ diff --git a/Les05-NextJS-Basics/quickpoll-starter/src/app/globals.css b/Les05-NextJS-Basics/quickpoll-starter/src/app/globals.css deleted file mode 100644 index f1d8c73..0000000 --- a/Les05-NextJS-Basics/quickpoll-starter/src/app/globals.css +++ /dev/null @@ -1 +0,0 @@ -@import "tailwindcss"; diff --git a/Les05-NextJS-Basics/quickpoll-starter/src/app/layout.tsx b/Les05-NextJS-Basics/quickpoll-starter/src/app/layout.tsx deleted file mode 100644 index 3252dda..0000000 --- a/Les05-NextJS-Basics/quickpoll-starter/src/app/layout.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import type { Metadata } from "next"; -import Link from "next/link"; -import "./globals.css"; - -export const metadata: Metadata = { - title: "QuickPoll — Stem op alles", - description: "Maak en deel polls met je vrienden", -}; - -export default function RootLayout({ - children, -}: { - children: React.ReactNode; -}) { - return ( - - - {/* - STAP 1: Bouw hier een navigatiebalk met: - - Logo/titel "QuickPoll" (links) die linkt naar / - - Een link naar / ("Polls") - - Een link naar /create ("Nieuwe Poll") - - Tip: gebruik van "next/link", niet - Tip: gebruik Tailwind classes voor styling - */} - -
{children}
- -
- © 2025 QuickPoll — NOVI Hogeschool Les 5 -
- - - ); -} diff --git a/Les05-NextJS-Basics/quickpoll-starter/src/app/loading.tsx b/Les05-NextJS-Basics/quickpoll-starter/src/app/loading.tsx deleted file mode 100644 index b70a23c..0000000 --- a/Les05-NextJS-Basics/quickpoll-starter/src/app/loading.tsx +++ /dev/null @@ -1,17 +0,0 @@ -// STAP 7: Loading state -// -// Dit bestand wordt automatisch getoond terwijl een pagina laadt. -// Bouw een skeleton loader met Tailwind's animate-pulse class. -// -// Voorbeeld: -//
-//
-//
- -export default function Loading() { - return ( -
-

Laden...

-
- ); -} diff --git a/Les05-NextJS-Basics/quickpoll-starter/src/app/not-found.tsx b/Les05-NextJS-Basics/quickpoll-starter/src/app/not-found.tsx deleted file mode 100644 index bd09789..0000000 --- a/Les05-NextJS-Basics/quickpoll-starter/src/app/not-found.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import Link from "next/link"; - -// STAP 7: Not found pagina -// -// Wordt getoond als een pagina niet bestaat. -// Bouw een nette 404 pagina met een link terug naar home. - -export default function NotFound() { - return ( -
-

404

-

Deze pagina bestaat niet.

- - Terug naar home - -
- ); -} diff --git a/Les05-NextJS-Basics/quickpoll-starter/src/app/page.tsx b/Les05-NextJS-Basics/quickpoll-starter/src/app/page.tsx deleted file mode 100644 index 9ddc506..0000000 --- a/Les05-NextJS-Basics/quickpoll-starter/src/app/page.tsx +++ /dev/null @@ -1,31 +0,0 @@ -import Link from "next/link"; -import { getPolls } from "@/lib/data"; -import type { Poll } from "@/types"; - -export const dynamic = "force-dynamic"; - -export default function HomePage() { - // STAP 2: Haal alle polls op met getPolls() - // Dit is een Server Component — je kunt gewoon functies aanroepen! - - return ( -
-

Actieve Polls

-

Klik op een poll om te stemmen

- -
- {/* - STAP 2: Map over de polls en toon voor elke poll: - - De vraag (poll.question) - - Het aantal opties en stemmen - - De opties als tags/badges - - Wrap het in een naar /poll/{poll.id} - - Tip: maak een helper functie voor het totaal aantal stemmen: - const totalVotes = (poll: Poll): number => - poll.votes.reduce((sum, v) => sum + v, 0); - */} -
-
- ); -} diff --git a/Les05-NextJS-Basics/quickpoll-starter/src/app/poll/[id]/not-found.tsx b/Les05-NextJS-Basics/quickpoll-starter/src/app/poll/[id]/not-found.tsx deleted file mode 100644 index 35e5934..0000000 --- a/Les05-NextJS-Basics/quickpoll-starter/src/app/poll/[id]/not-found.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import Link from "next/link"; - -export default function PollNotFound() { - return ( -
-

- Poll niet gevonden -

-

- Deze poll bestaat niet of is verwijderd. -

- - Bekijk alle polls - -
- ); -} diff --git a/Les05-NextJS-Basics/quickpoll-starter/src/app/poll/[id]/page.tsx b/Les05-NextJS-Basics/quickpoll-starter/src/app/poll/[id]/page.tsx deleted file mode 100644 index fb909e7..0000000 --- a/Les05-NextJS-Basics/quickpoll-starter/src/app/poll/[id]/page.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import { notFound } from "next/navigation"; -import { getPollById } from "@/lib/data"; -import VoteForm from "@/components/VoteForm"; -import type { Metadata } from "next"; - -interface PageProps { - params: Promise<{ id: string }>; -} - -// STAP 5: generateMetadata — dynamische pagina titel -// -// Deze functie genereert de tag voor SEO. -// Haal de poll op en return de vraag als titel. -// Als de poll niet bestaat, return "Poll niet gevonden". - -export async function generateMetadata({ params }: PageProps): Promise<Metadata> { - const { id } = await params; - const poll = getPollById(id); - - return { - title: poll ? `${poll.question} — QuickPoll` : "Poll niet gevonden", - }; -} - -// STAP 5: PollPage — de poll detail pagina -// -// Wat moet je doen? -// 1. Haal het id op uit params -// 2. Zoek de poll met getPollById(id) -// 3. Als de poll niet bestaat: roep notFound() aan -// 4. Render de poll vraag als <h1> -// 5. Render de <VoteForm poll={poll} /> component - -export default async function PollPage({ params }: PageProps) { - // Jouw code hier... - return ( - <div className="max-w-2xl mx-auto"> - <p>Implementeer deze pagina (zie stap 5 in de opdracht)</p> - </div> - ); -} diff --git a/Les05-NextJS-Basics/quickpoll-starter/src/components/VoteForm.tsx b/Les05-NextJS-Basics/quickpoll-starter/src/components/VoteForm.tsx deleted file mode 100644 index c5e0a1e..0000000 --- a/Les05-NextJS-Basics/quickpoll-starter/src/components/VoteForm.tsx +++ /dev/null @@ -1,89 +0,0 @@ -"use client"; - -import { useState } from "react"; -import { useRouter } from "next/navigation"; -import type { Poll } from "@/types"; - -interface VoteFormProps { - poll: Poll; -} - -// STAP 6: VoteForm — de stem interface -// -// Dit is een CLIENT component ("use client" staat bovenaan). -// Hier mag je wel useState en onClick gebruiken! -// -// Benodigde state: -// - selectedOption: number | null (welke optie is geselecteerd) -// - hasVoted: boolean (heeft de gebruiker al gestemd) -// - isSubmitting: boolean (wordt het formulier verstuurd) -// - currentPoll: Poll (de huidige poll data, update na stemmen) -// -// Wat moet je bouwen? -// 1. Toon alle opties als klikbare knoppen -// 2. Highlight de geselecteerde optie -// 3. Een "Stem!" knop die een POST doet naar /api/polls/{id}/vote -// 4. Na het stemmen: toon de resultaten met percentages -// -// De fetch call voor stemmen: -// const response = await fetch(`/api/polls/${currentPoll.id}/vote`, { -// method: "POST", -// headers: { "Content-Type": "application/json" }, -// body: JSON.stringify({ optionIndex: selectedOption }), -// }); -// if (response.ok) { -// const updatedPoll: Poll = await response.json(); -// setCurrentPoll(updatedPoll); -// setHasVoted(true); -// } - -export default function VoteForm({ poll }: VoteFormProps) { - const [selectedOption, setSelectedOption] = useState<number | null>(null); - const [hasVoted, setHasVoted] = useState<boolean>(false); - const [isSubmitting, setIsSubmitting] = useState<boolean>(false); - const [currentPoll, setCurrentPoll] = useState<Poll>(poll); - const router = useRouter(); - - const totalVotes: number = currentPoll.votes.reduce( - (sum, v) => sum + v, - 0 - ); - - function getPercentage(votes: number): number { - if (totalVotes === 0) return 0; - return Math.round((votes / totalVotes) * 100); - } - - async function handleVote(): Promise<void> { - if (selectedOption === null || isSubmitting) return; - setIsSubmitting(true); - - // STAP 6: Doe hier de fetch call naar de vote API - // Zie de beschrijving hierboven voor de code - - setIsSubmitting(false); - } - - return ( - <div className="space-y-3"> - {/* - STAP 6: Bouw hier de voting interface - - ALS de gebruiker nog NIET gestemd heeft: - - Toon elke optie als een klikbare button - - Highlight de geselecteerde optie (purple border) - - Toon een radio-achtige indicator (gevuld/leeg rondje) - - Toon een "Stem!" knop onderaan - - ALS de gebruiker WEL gestemd heeft: - - Toon elke optie met een percentage balk - - Toon het percentage en aantal stemmen - - Toon "Bedankt voor je stem!" - - Toon een "Terug" link naar / - */} - <p className="text-gray-400 italic"> - Bouw hier de voting interface (zie stap 6) - </p> - </div> - ); -} diff --git a/Les05-NextJS-Basics/quickpoll-starter/src/lib/data.ts b/Les05-NextJS-Basics/quickpoll-starter/src/lib/data.ts deleted file mode 100644 index 3e36f41..0000000 --- a/Les05-NextJS-Basics/quickpoll-starter/src/lib/data.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { Poll } from "@/types"; - -export const polls: Poll[] = [ - { - id: "1", - question: "Wat is de beste code editor?", - options: ["VS Code", "Cursor", "Vim", "WebStorm"], - votes: [12, 25, 5, 3], - }, - { - id: "2", - question: "Wat is de beste programmeertaal?", - options: ["TypeScript", "Python", "Rust", "Go"], - votes: [18, 15, 8, 4], - }, - { - id: "3", - question: "Welk framework heeft de toekomst?", - options: ["Next.js", "Remix", "Astro", "SvelteKit"], - votes: [22, 6, 10, 7], - }, -]; - -let nextId = 4; - -export function getPolls(): Poll[] { - return polls; -} - -export function getPollById(id: string): Poll | undefined { - return polls.find((poll) => poll.id === id); -} - -export function createPoll(question: string, options: string[]): Poll { - const newPoll: Poll = { - id: String(nextId++), - question, - options, - votes: new Array(options.length).fill(0), - }; - polls.push(newPoll); - return newPoll; -} - -export function votePoll( - pollId: string, - optionIndex: number -): Poll | undefined { - const poll = polls.find((p) => p.id === pollId); - if (!poll || optionIndex < 0 || optionIndex >= poll.options.length) { - return undefined; - } - poll.votes[optionIndex]++; - return poll; -} diff --git a/Les05-NextJS-Basics/quickpoll-starter/src/middleware.ts b/Les05-NextJS-Basics/quickpoll-starter/src/middleware.ts deleted file mode 100644 index 76bbfab..0000000 --- a/Les05-NextJS-Basics/quickpoll-starter/src/middleware.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { NextResponse } from "next/server"; -import type { NextRequest } from "next/server"; - -export function middleware(request: NextRequest): NextResponse { - const start = Date.now(); - - console.log(`[${request.method}] ${request.nextUrl.pathname}`); - - const response = NextResponse.next(); - response.headers.set("x-request-time", String(Date.now() - start)); - - return response; -} - -export const config = { - matcher: ["/api/:path*", "/poll/:path*"], -}; diff --git a/Les05-NextJS-Basics/quickpoll-starter/src/types/index.ts b/Les05-NextJS-Basics/quickpoll-starter/src/types/index.ts deleted file mode 100644 index 73f152f..0000000 --- a/Les05-NextJS-Basics/quickpoll-starter/src/types/index.ts +++ /dev/null @@ -1,11 +0,0 @@ -export interface Poll { - id: string; - question: string; - options: string[]; - votes: number[]; -} - -export interface CreatePollBody { - question: string; - options: string[]; -} diff --git a/Les05-NextJS-Basics/quickpoll-starter/tsconfig.json b/Les05-NextJS-Basics/quickpoll-starter/tsconfig.json deleted file mode 100644 index cf9c65d..0000000 --- a/Les05-NextJS-Basics/quickpoll-starter/tsconfig.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2017", - "lib": ["dom", "dom.iterable", "esnext"], - "allowJs": true, - "skipLibCheck": true, - "strict": true, - "noEmit": true, - "esModuleInterop": true, - "module": "esnext", - "moduleResolution": "bundler", - "resolveJsonModule": true, - "isolatedModules": true, - "jsx": "react-jsx", - "incremental": true, - "plugins": [ - { - "name": "next" - } - ], - "paths": { - "@/*": ["./src/*"] - } - }, - "include": [ - "next-env.d.ts", - "**/*.ts", - "**/*.tsx", - ".next/types/**/*.ts", - ".next/dev/types/**/*.ts", - "**/*.mts" - ], - "exclude": ["node_modules"] -} diff --git a/Les06-NextJS-QuickPoll-Part2/demo-zips/INDEX.md b/Les06-NextJS-QuickPoll-Part2/demo-zips/INDEX.md deleted file mode 100644 index b885ac2..0000000 --- a/Les06-NextJS-QuickPoll-Part2/demo-zips/INDEX.md +++ /dev/null @@ -1,336 +0,0 @@ -# QuickPoll Next.js Demo - Complete File Index - -## 📍 START HERE - -1. **For Tim (Teacher)**: Read `QUICK-START.md` first -2. **For Understanding the Project**: Read `README.md` -3. **For Complete Teaching Guide**: Read `TEACHER-GUIDE.md` -4. **For Technical Details**: Read `PROJECT-SUMMARY.md` - ---- - -## 📦 Project Files - -### Complete Project with Git History -``` -quickpoll-demo-complete.zip ~160 KB -└─ Full project with all 10 git tags - Extract this and use git checkout to jump between steps -``` - -### Individual Step Archives -``` -stap-0.zip ~32 KB Project setup + types + data -stap-1.zip ~32 KB Layout & Navigation -stap-2.zip ~33 KB Homepage with poll cards -stap-3.zip ~34 KB API routes (GET/POST) -stap-4.zip ~37 KB Vote API + demo form ⭐ -stap-5.zip ~39 KB Poll detail page -stap-6.zip ~40 KB VoteForm component -stap-7.zip ~43 KB Error handling pages -stap-8.zip ~43 KB Middleware -bonus.zip ~44 KB Create poll page -``` - -**Total Project Size**: ~588 KB (all files) - ---- - -## 📚 Documentation - -### Quick Start (3 pages, 7.1 KB) -File: `QUICK-START.md` -- For Tim before class -- Setup instructions -- Key demo points -- Troubleshooting -- Recommended read time: 10 minutes - -### Main README (3 pages, 7.2 KB) -File: `README.md` -- Project overview -- Getting started -- Key features -- Technology stack -- Common questions - -### Complete Teacher Guide (5 pages, 8.5 KB) -File: `TEACHER-GUIDE.md` -- Complete lesson breakdown -- What to show in each step -- DevTools demonstration strategy -- Key concepts to teach -- Tips for live coding - -### Project Summary (4 pages, 7.9 KB) -File: `PROJECT-SUMMARY.md` -- Technical architecture -- Git tag progression -- Teaching points -- Sample data -- Build information - ---- - -## 🎓 Learning Path - -### Beginner Path (Individual Zips) -If you want to start from scratch for each step: -``` -1. Extract stap-0.zip -2. npm install && npm run dev -3. Do the live-coding -4. Extract stap-1.zip (new terminal) -5. Repeat... -``` - -**Pros**: Each step is fresh, you can code along -**Cons**: More setup, can't jump back easily - -### Advanced Path (Complete Project) -If you want flexible jumping between steps: -``` -1. Extract quickpoll-demo-complete.zip -2. npm install -3. npm run dev -4. git checkout stap-0 (or any step) -5. Browser auto-refreshes -6. git checkout stap-5 (jump forward) -``` - -**Pros**: One setup, jump anywhere, see git history -**Cons**: Less live-coding from scratch - -**Recommended**: Use Complete Project with git checkout - ---- - -## 📋 File Structure in Zips - -Each zip contains a Next.js project with this structure: - -``` -quickpoll-demo/ -├── src/ -│ ├── app/ # Next.js App Router -│ │ ├── page.tsx # Homepage -│ │ ├── layout.tsx # Root layout with navbar -│ │ ├── globals.css # Tailwind imports -│ │ ├── loading.tsx # Loading skeleton -│ │ ├── error.tsx # Error boundary -│ │ ├── not-found.tsx # 404 page -│ │ ├── api/ -│ │ │ └── polls/ -│ │ │ ├── route.ts # GET all, POST create -│ │ │ └── [id]/ -│ │ │ ├── route.ts # GET single poll -│ │ │ ├── vote/route.ts # POST vote ⭐ -│ │ │ └── not-found.tsx -│ │ ├── poll/[id]/ -│ │ │ ├── page.tsx # Dynamic detail page -│ │ │ └── not-found.tsx -│ │ └── create/ -│ │ └── page.tsx # Create poll form (bonus) -│ ├── components/ -│ │ └── VoteForm.tsx # Voting component -│ ├── lib/ -│ │ └── data.ts # Mock data & functions -│ ├── types/ -│ │ └── index.ts # TypeScript interfaces -│ └── middleware.ts # Request logging -├── .cursorrules # Code style guidelines -├── package.json -├── tsconfig.json -├── tailwind.config.ts -└── .gitignore -``` - ---- - -## ⭐ Key Files to Show Students - -### Data & Types -- `src/types/index.ts` - Poll interface, VoteBody interface -- `src/lib/data.ts` - Sample polls, getPolls(), votePoll() - -### API Routes -- `src/app/api/polls/route.ts` - GET all, POST create -- `src/app/api/polls/[id]/route.ts` - GET single -- `src/app/api/polls/[id]/vote/route.ts` - POST vote (Key demo point!) - -### Pages -- `src/app/page.tsx` - Homepage with poll cards -- `src/app/poll/[id]/page.tsx` - Poll detail page with voting - -### Components -- `src/components/VoteForm.tsx` - Client component with voting logic - -### Layout & Styling -- `src/app/layout.tsx` - Navbar and global structure -- `src/app/globals.css` - Tailwind imports (minimal) - ---- - -## 🔧 System Requirements - -- **Node.js**: 18 or higher -- **npm**: 9 or higher -- **Disk Space**: ~500 MB for node_modules (generated during npm install) -- **Browser**: Any modern browser with DevTools (for demos) -- **Projector**: Recommended for classroom (test beforehand!) - ---- - -## 🚀 Quick Commands Reference - -### Setup -```bash -unzip quickpoll-demo-complete.zip -cd quickpoll-demo -npm install -npm run dev -``` - -### During Class -```bash -git tag -l # List all tags -git checkout stap-4 # Jump to step 4 -git diff stap-2 stap-3 # See what changed -git log --oneline # Show commits -``` - -### Build & Test -```bash -npm run build # Production build -npm run dev -- -p 3001 # Different port -``` - -### Browser -``` -http://localhost:3000 # Homepage -http://localhost:3000/poll/1 # Poll detail -http://localhost:3000/create # Create form (bonus) -http://localhost:3000/demo # Demo form (stap-4 only) -``` - -### DevTools (F12) -- Console: See console.log statements -- Network: See API requests -- Elements: Inspect HTML/CSS - ---- - -## 📊 Project Statistics - -| Metric | Value | -|--------|-------| -| Git Commits | 10 | -| Git Tags | 9 (stap-0 through stap-8, plus bonus) | -| TypeScript Files | 11 | -| Components | 2 (VoteForm + pages) | -| API Routes | 4 | -| Total Lines of Code | ~1,200 | -| Build Time | ~1.3 seconds | -| Estimated Teaching Time | 60-75 minutes | - ---- - -## ✅ Verification Checklist - -Before teaching, verify: - -- [ ] All 10 zip files present and readable -- [ ] quickpoll-demo-complete.zip contains .git folder -- [ ] All 4 markdown documentation files present -- [ ] npm version 9+ installed -- [ ] Node 18+ installed -- [ ] Can extract and npm install without errors -- [ ] npm run dev starts without errors -- [ ] Homepage loads at http://localhost:3000 -- [ ] All git tags present (`git tag -l`) -- [ ] Can checkout different tags without errors -- [ ] DevTools work correctly (F12) -- [ ] Network tab shows API requests -- [ ] Console.log appears in DevTools console - ---- - -## 🎯 Recommended Usage - -### For First-Time Teachers -1. Read QUICK-START.md (10 min) -2. Follow setup instructions -3. Test each step beforehand -4. Use git checkout to jump between steps -5. Use projector for display - -### For Experienced Teachers -1. Extract complete project -2. Review TEACHER-GUIDE.md for key points -3. Customize as needed -4. Focus on stap-4 demo form - -### For Students (After Class) -1. Extract any zip file -2. Run npm install && npm run dev -3. Explore the code -4. Try modifying things -5. See changes in real-time - ---- - -## 🆘 Common Issues - -| Problem | Solution | -|---------|----------| -| "npm: command not found" | Install Node.js from nodejs.org | -| "Port 3000 in use" | Use `npm run dev -- -p 3001` | -| Git tags not showing | You extracted individual zip, not complete | -| Changes not showing | Hard refresh browser: Ctrl+Shift+R | -| node_modules missing | Run `npm install` | -| TypeScript errors | All should build successfully | - ---- - -## 📞 File Organization - -All files are in one directory: -``` -/demo-output/ -├── (4 markdown files - documentation) -├── (10 zip files - project archives) -└── (this index file) -``` - -For best organization, create this structure: -``` -QuickPoll-Demo/ -├── Zips/ -│ ├── stap-0.zip through stap-8.zip -│ ├── bonus.zip -│ └── quickpoll-demo-complete.zip -├── Documentation/ -│ ├── QUICK-START.md -│ ├── TEACHER-GUIDE.md -│ ├── PROJECT-SUMMARY.md -│ ├── README.md -│ └── INDEX.md -└── Projects/ - └── (extract zips here as needed) -``` - ---- - -## 🎉 You're Ready! - -Everything is prepared for live-coding demonstrations. Start with QUICK-START.md and you'll have a successful classroom session. - -Good luck teaching Next.js! 🚀 - ---- - -**Created**: March 17, 2026 -**Files**: 15 total (4 docs + 11 zips) -**Total Size**: 588 KB -**Format**: Standard zip archives + Markdown -**Compatibility**: All platforms (Windows, Mac, Linux) diff --git a/Les06-NextJS-QuickPoll-Part2/demo-zips/PROJECT-SUMMARY.md b/Les06-NextJS-QuickPoll-Part2/demo-zips/PROJECT-SUMMARY.md deleted file mode 100644 index 0c3cc18..0000000 --- a/Les06-NextJS-QuickPoll-Part2/demo-zips/PROJECT-SUMMARY.md +++ /dev/null @@ -1,264 +0,0 @@ -# QuickPoll Next.js 15 Demo Project - Summary - -## Project Description - -QuickPoll is a complete polling application built with **Next.js 15**, **TypeScript**, and **Tailwind CSS**. Designed specifically for live-coding classroom demonstrations, it includes git tags at each development step. - -## Technology Stack - -- **Next.js 15** - React framework with App Router -- **TypeScript** - Fully typed JavaScript -- **Tailwind CSS** - Utility-first CSS framework -- **In-Memory Data** - Mock "database" for demo purposes -- **React Hooks** - useState for client-side state management - -## Project Structure - -``` -quickpoll-demo/ -├── src/ -│ ├── app/ # Next.js App Router -│ │ ├── page.tsx # Homepage with poll list -│ │ ├── layout.tsx # Root layout with navbar -│ │ ├── globals.css # Global Tailwind styles -│ │ ├── loading.tsx # Loading skeleton -│ │ ├── error.tsx # Error boundary -│ │ ├── not-found.tsx # 404 page -│ │ ├── api/ # API route handlers -│ │ │ └── polls/ -│ │ │ ├── route.ts # GET all, POST create -│ │ │ ├── [id]/ -│ │ │ │ ├── route.ts # GET single poll -│ │ │ │ ├── vote/route.ts # POST vote -│ │ │ │ └── not-found.tsx -│ │ ├── poll/[id]/ # Dynamic poll detail page -│ │ │ └── page.tsx -│ │ └── create/ # Create new poll page -│ │ └── page.tsx -│ ├── components/ # Reusable components -│ │ └── VoteForm.tsx # Voting component -│ ├── lib/ # Utilities and data -│ │ └── data.ts # Mock poll data & functions -│ ├── types/ # TypeScript interfaces -│ │ └── index.ts # Poll, VoteBody, CreatePollBody -│ └── middleware.ts # Request logging middleware -├── .cursorrules # Code style guidelines -├── package.json -├── tsconfig.json -└── tailwind.config.ts -``` - -## Core Features - -### 1. **Display Polls** (Homepage) -- Show all available polls as cards -- Display question, option count, total votes -- Click to navigate to poll detail page - -### 2. **Poll Details** (Dynamic Page) -- Show full poll question and options -- Real-time voting results with percentage bars -- Server-rendered for SEO - -### 3. **Vote on Polls** (VoteForm Component) -- Select an option -- Submit vote via POST API -- See results immediately after voting -- Purple theme with gradient progress bars - -### 4. **Create Polls** (Bonus Step) -- Form to create new polls -- Input validation -- Dynamic option fields (add/remove) -- Automatic redirect to new poll - -### 5. **API Routes** -- `GET /api/polls` - Get all polls -- `GET /api/polls/[id]` - Get single poll -- `POST /api/polls` - Create new poll -- `POST /api/polls/[id]/vote` - Vote on poll - -### 6. **Middleware** -- Log all requests with timing -- Track API and poll page access - -### 7. **Error Handling** -- Loading skeleton (Suspense) -- Error boundary component -- 404 pages (global and poll-specific) - -## Git Tags for Progression - -| Tag | Step | What's Added | -|-----|------|-------------| -| `stap-0` | Project Setup | Types, data, file structure, .cursorrules | -| `stap-1` | Layout & Navigation | Navbar, layout, metadata | -| `stap-2` | Homepage | Poll cards grid, Links | -| `stap-3` | API Routes | GET all, GET single, POST create | -| `stap-4` | Vote API & Demo | POST vote, Demo form at /demo | -| `stap-5` | Poll Detail Page | Dynamic [id] route, metadata | -| `stap-6` | VoteForm Component | Client component with voting logic | -| `stap-7` | Error Handling | loading.tsx, error.tsx, not-found.tsx | -| `stap-8` | Middleware | Request logging middleware | -| `bonus` | Create Poll | Full form, navbar link, remove demo | - -## How to Use in Class - -### Before Class -```bash -unzip quickpoll-demo-complete.zip -cd quickpoll-demo -npm install -npm run dev -``` - -### During Class -```bash -# Jump to any step -git checkout stap-3 - -# View what changed -git diff stap-2 stap-3 - -# Go to final version -git checkout bonus -``` - -### Demo the Voting API (stap-4) -1. Navigate to http://localhost:3000/demo -2. Show the form (projector) -3. Open DevTools Console to show logging -4. Open DevTools Network tab to show POST request -5. Display the fetch code example - -## Teaching Points - -### TypeScript & Types -- Define interfaces for data structures -- Export from `src/types/index.ts` -- Use types in function parameters - -### Next.js Features -- App Router with file-based routing -- Dynamic routes: `[id]` creates `/poll/1`, `/poll/2`, etc. -- Server Components by default -- Client Components with "use client" directive -- API routes in `/app/api` -- Special files: `layout.tsx`, `not-found.tsx`, `error.tsx`, `loading.tsx` - -### React Patterns -- Server Components (default, no interactivity) -- Client Components with useState -- Component composition (VoteForm in PollDetailPage) -- Fetch API for server communication - -### Tailwind CSS -- Utility-first approach -- Responsive design (md:, lg: prefixes) -- Color system (purple-500, purple-600, purple-700) -- Hover states and transitions - -### Form Handling -- Controlled inputs with useState -- Validation before submit -- Loading states during submission -- Error handling and feedback - -## Sample Data - -Three pre-loaded polls: - -1. **"Wat is je favoriete programmeer taal?"** - - JavaScript, Python, TypeScript, Rust - - Sample votes: 45, 32, 28, 15 - -2. **"Hoe veel uur slaap krijg je per nacht?"** - - < 6 uur, 6-8 uur, 8+ uur - - Sample votes: 12, 68, 35 - -3. **"Welke framework gebruik je het meest?"** - - React, Vue, Svelte, Angular - - Sample votes: 89, 34, 12, 8 - -## Color Scheme - -**Purple Theme for QuickPoll:** -- `#7c3aed` - purple-500 (main color) -- `#a855f7` - purple-600 (hover) -- `#9333ea` - purple-700 (pressed) - -**Neutral Colors:** -- Gray-50 to Gray-900 for text and backgrounds -- White for cards and backgrounds -- Red-600 for error states -- Blue-50 for information - -## Building & Deployment - -### Build for Production -```bash -npm run build -npm start -``` - -### Build Verification -```bash -npm run build -``` - -Output shows: -- Static pages: `/`, `/create` -- Dynamic pages: `/poll/[id]` -- API routes: `/api/polls`, `/api/polls/[id]`, etc. -- Middleware (Proxy) - -## Files Per Step - -Each zip file contains the complete project at that step: -- All source code -- package.json with dependencies -- Configuration files -- **Excludes:** `node_modules/`, `.next/`, `.git/` - -The `quickpoll-demo-complete.zip` includes: -- Full git history -- All commits and tags -- Ability to `git checkout` any step - -## Typical Class Flow - -1. **stap-0 to stap-2** - Show basic structure and homepage (15 min) -2. **stap-3** - Explain API routes (10 min) -3. **stap-4** - Demo the voting API in action (15 min) ⭐ Key demo point -4. **stap-5 to stap-6** - Build the voting interface (15 min) -5. **stap-7 to stap-8** - Error handling and middleware (10 min) -6. **bonus** - Create poll feature (optional, 10 min) - -## Key Takeaways for Students - -- Next.js makes building full-stack apps easy -- Server Components are the default (simpler, faster) -- API routes live alongside your pages -- TypeScript catches errors early -- Tailwind makes styling fast and consistent -- Git tags let you track feature development - -## Common Questions - -**Q: Is this production-ready?** -A: No - it uses in-memory data. For production, add a real database like PostgreSQL or MongoDB. - -**Q: Can I add authentication?** -A: Yes - add NextAuth.js or similar. Future lesson! - -**Q: How do I deploy this?** -A: Deploy to Vercel (created by Next.js team) or any Node.js hosting. See https://nextjs.org/docs/app/building-your-application/deploying - -**Q: Can students modify the code?** -A: Absolutely! Use it as a starting point for assignments. - ---- - -**Created:** March 2026 -**Next.js Version:** 15.x -**Node Version:** 18+ recommended diff --git a/Les06-NextJS-QuickPoll-Part2/demo-zips/QUICK-START.md b/Les06-NextJS-QuickPoll-Part2/demo-zips/QUICK-START.md deleted file mode 100644 index 12a83b4..0000000 --- a/Les06-NextJS-QuickPoll-Part2/demo-zips/QUICK-START.md +++ /dev/null @@ -1,304 +0,0 @@ -# QuickPoll Demo - Quick Start Guide - -## For Tim - Before Your Class - -### 1️⃣ Prepare Your Setup (30 minutes before class) - -```bash -# Extract the complete project -unzip quickpoll-demo-complete.zip - -# Enter directory -cd quickpoll-demo - -# Install dependencies -npm install - -# Test that it runs -npm run dev -``` - -Should see: -``` -- ready started server on 0.0.0.0:3000, url: http://localhost:3000 -``` - -### 2️⃣ Check All Git Tags Are Present - -```bash -git tag -l -``` - -You should see: -``` -bonus -stap-0 -stap-1 -stap-2 -stap-3 -stap-4 -stap-5 -stap-6 -stap-7 -stap-8 -``` - -### 3️⃣ Test Jumping Between Steps - -```bash -# Go to step 2 -git checkout stap-2 - -# Refresh browser - should show just poll cards -# Look at src/app/page.tsx - should be simple - -# Go to final version -git checkout bonus - -# Refresh browser - should show full app with "Nieuwe Poll" link -# Look at src/app/create/page.tsx - should exist -``` - -### 4️⃣ Check Your Display Setup - -- Open browser with http://localhost:3000 -- Test font size on projector (should be easily readable) -- Test network tab in DevTools (for stap-4 demo) -- Test VS Code has good contrast - ---- - -## During Your Class - -### Starting the Session - -```bash -# Make sure you're at the beginning -git checkout stap-0 -npm run dev -``` - -Then open http://localhost:3000 in your browser. - -### Jumping Between Steps - -When you want to show a new step: - -```bash -# Stop the dev server (Ctrl+C) -git checkout stap-3 - -# Restart dev server -npm run dev - -# Browser should hot-reload automatically -# If not, refresh manually (Ctrl+R or Cmd+R) -``` - -### Key Demo Points - -#### ⭐ Step 4 - The Voting API Demo (Most Important) - -1. Navigate to http://localhost:3000/demo -2. Open DevTools (F12) -3. Go to Console tab - show logging -4. Go to Network tab -5. Fill the form with: - - Poll ID: `1` - - Option Index: `0` -6. Click "Stem" button -7. Watch the Network tab to show POST request -8. Show the JSON response -9. Show console logs - -This is your most visual demonstration! - -#### Step 1 - Layout - -Show the navbar: -- Point out the "QuickPoll" branding (purple) -- Show the links being added - -#### Step 2 - Homepage - -Show poll cards appearing: -- Click one to navigate to detail page -- Show responsive grid - -#### Step 3 - API Routes - -Show file structure in VS Code: -- `src/app/api/polls/route.ts` - GET all, POST create -- `src/app/api/polls/[id]/route.ts` - GET single -- Point out `params: Promise<{ id: string }>` - Next.js 15 pattern - -#### Step 5-6 - Poll Detail & Voting - -Show the full flow: -1. Homepage → Click a poll -2. Vote on the poll -3. See results appear -4. Show purple gradient progress bars - -#### Step 7-8 - Error Handling & Middleware - -Show what happens when things break: -- Try navigating to non-existent poll (404 page) -- Point out loading skeleton briefly -- Show middleware logging in terminal - -### Stopping the Dev Server - -```bash -Ctrl+C -``` - ---- - -## Troubleshooting During Class - -| Problem | Solution | -|---------|----------| -| Port 3000 in use | `npm run dev -- -p 3001` | -| Browser shows old code | Hard refresh: `Ctrl+Shift+R` or `Cmd+Shift+R` | -| Git checkout fails | Run `git status` to check for uncommitted changes, then `git stash` | -| DevTools won't show Network tab | Close and reopen DevTools (F12) | -| Terminal shows errors | Try: `npm install` then `npm run dev` again | -| Can't see projector clearly | Zoom in: `Ctrl/Cmd + +` in browser | - ---- - -## File Locations You'll Reference - -``` -quickpoll-demo/ -├── src/types/index.ts ← Show for TypeScript interfaces -├── src/lib/data.ts ← Show for sample data -├── src/app/layout.tsx ← Show for navbar -├── src/app/page.tsx ← Show for homepage -├── src/app/api/polls/ ← Show for API routes -├── src/app/poll/[id]/page.tsx ← Show for dynamic routing -├── src/components/VoteForm.tsx ← Show for client component -├── src/app/create/page.tsx ← Show for form handling -└── src/middleware.ts ← Show for middleware concept -``` - ---- - -## Live-Coding Tips - -### Before You Type -- Take a screenshot for reference -- Know where you're going -- Have keyboard shortcuts ready - -### While You Type -- Type **slowly** - let students follow -- **Talk through** what you're doing -- **Pause** at key lines to explain -- **Ask questions** - make it interactive - -### Show Results -- Run frequently -- Show in browser on projector -- Use DevTools to demonstrate -- Let students ask questions - ---- - -## Sample Dialog When Showing Step 4 - -> "Okay, we have our API route that accepts votes. But how does it work? Let me show you with this demo form." -> -> *Navigate to /demo* -> -> "Here we have a simple form. Let me open DevTools to show what happens behind the scenes." -> -> *Open DevTools, go to Console tab* -> -> "When I click 'Stem', two things happen: -> 1. The browser makes a request to our API -> 2. We get back the updated poll with new vote counts" -> -> *Click "Stem" button* -> -> "Look at the Console - you can see exactly what happened. Now let me show you in the Network tab..." -> -> *Go to Network tab* -> -> "Here's our POST request. The body shows we sent the option index (0), and the response shows the entire poll with updated vote counts." - ---- - -## After Class - -### Save Your Progress -The project uses git, so all your changes are tracked. If you made modifications, you can: - -```bash -# See what you changed -git status - -# Commit your changes -git add . -git commit -m "My live-coding edits" -``` - -### For Student Assignments -You can: -1. Share the `stap-5.zip` as a starting point -2. Have students add the VoteForm (stap-6 solution) -3. Or start with complete project and have them add features - -### Deploy (Optional) -To deploy this app: -```bash -# Sign up at vercel.com -# Install Vercel CLI -npm i -g vercel - -# Deploy -vercel -``` - ---- - -## Key Concepts to Emphasize - -✅ **Server Components** - Default in Next.js, simpler, faster -✅ **Client Components** - Use "use client" only when needed -✅ **API Routes** - Backend code in `/api` folder -✅ **Dynamic Routes** - `[id]` creates flexible routing -✅ **TypeScript** - Catch errors before they happen -✅ **Tailwind CSS** - Write styles in HTML with utility classes -✅ **Fetch API** - How frontend talks to backend - ---- - -## Questions Students Will Ask - -**"Why use Next.js instead of just React?"** -> Next.js gives you Server Components, API routes, better file structure, and automatic optimization. React is just the UI library - Next.js is the complete framework. - -**"Can we use a database instead of in-memory data?"** -> Yes! Add PostgreSQL or MongoDB. That's another lesson though. - -**"How long would this take to build from scratch?"** -> About 1-2 hours for a developer. We're doing it in steps so you can understand each concept. - -**"Can we deploy this?"** -> Absolutely - to Vercel in 1 command. That's our bonus if we have time. - ---- - -## You've Got This! 🎉 - -The project is ready. You have: -- ✅ Complete, working Next.js 15 app -- ✅ Git tags at every step -- ✅ Demo form for showing APIs -- ✅ Clear progression from basic to advanced -- ✅ Purple theme ready for classroom -- ✅ Console logs for debugging - -Just follow this guide, and your students will love seeing a real app built step-by-step! diff --git a/Les06-NextJS-QuickPoll-Part2/demo-zips/README.md b/Les06-NextJS-QuickPoll-Part2/demo-zips/README.md deleted file mode 100644 index 1d26e7e..0000000 --- a/Les06-NextJS-QuickPoll-Part2/demo-zips/README.md +++ /dev/null @@ -1,278 +0,0 @@ -# QuickPoll Next.js 15 Demo Project - -A complete, step-by-step Next.js 15 polling application built for live-coding classroom demonstrations. Includes git tags at each development step for easy navigation during teaching. - -## 📦 What's Included - -### Zip Files (Individual Steps) -- `stap-0.zip` - Project setup + types + data -- `stap-1.zip` - Layout & Navigation -- `stap-2.zip` - Homepage with poll cards -- `stap-3.zip` - API routes (GET, POST) -- `stap-4.zip` - Vote API + demo form ⭐ -- `stap-5.zip` - Poll detail page -- `stap-6.zip` - VoteForm component -- `stap-7.zip` - Error handling & loading states -- `stap-8.zip` - Middleware -- `bonus.zip` - Create poll page - -### Complete Project -- `quickpoll-demo-complete.zip` - Full project with complete git history - -### Documentation -- `QUICK-START.md` - Instructions for Tim (start here!) -- `TEACHER-GUIDE.md` - Comprehensive teaching guide -- `PROJECT-SUMMARY.md` - Technical overview -- `README.md` - This file - -## 🚀 Getting Started - -### Step 1: Extract & Setup -```bash -unzip quickpoll-demo-complete.zip -cd quickpoll-demo -npm install -npm run dev -``` - -### Step 2: Navigate to App -Open http://localhost:3000 in your browser - -### Step 3: Jump Between Steps (During Teaching) -```bash -# View all available steps -git tag -l - -# Jump to any step -git checkout stap-3 - -# See what changed in this step -git diff stap-2 stap-3 - -# Go to final version -git checkout bonus -``` - -## ✨ Key Features - -- **9 Development Steps** - Logical progression from setup to full app -- **API Routes** - Backend routes in `/app/api` -- **Dynamic Routing** - `/poll/[id]` for individual poll pages -- **Real-Time Voting** - Vote and see results update instantly -- **Server Components** - Default Next.js 15 pattern -- **Client Components** - Interactive VoteForm with state -- **Error Handling** - Loading skeletons, error boundaries, 404 pages -- **TypeScript** - Fully typed throughout -- **Tailwind CSS** - Purple-themed responsive design -- **Middleware** - Request logging and timing -- **Demo Form** - Testing interface for API endpoints (stap-4) - -## 📚 Documentation - -### For Teachers -Start with **QUICK-START.md** - has everything you need before class - -### For Understanding the Project -Read **PROJECT-SUMMARY.md** - complete technical overview - -### For Teaching Details -See **TEACHER-GUIDE.md** - tips, key concepts, troubleshooting - -## 🎯 Typical Class Flow - -| Step | Duration | Focus | -|------|----------|-------| -| stap-0 to stap-2 | 15 min | File structure, homepage, cards | -| stap-3 | 10 min | API routes concept | -| stap-4 | 15 min | ⭐ Vote API demo (show DevTools!) | -| stap-5 to stap-6 | 15 min | Dynamic pages, voting interface | -| stap-7 to stap-8 | 10 min | Error handling, middleware | -| bonus | 10 min | Form handling, creating polls | - -**Total: ~75 minutes for complete lesson** - -## 💡 Key Teaching Moments - -### stap-4: The Demo Form -This is your star moment! Show: -1. Demo form at http://localhost:3000/demo -2. Open DevTools Console - show logging -3. Switch to Network tab - show POST request -4. Click "Stem" and watch the request happen -5. Show the JSON response with updated votes - -### stap-6: VoteForm Component -Explain: -- Why "use client" is needed (state management) -- How useState tracks selected option -- How fetch() sends vote to API -- How component updates when response comes back - -### All Steps -Keep showing the running app - live feedback is key! - -## 📋 What's in Each Step - -### stap-0: Project Setup -- Create Next.js with TypeScript + Tailwind -- Define Poll interfaces -- Create mock data (3 sample polls) -- Set up folder structure - -### stap-1: Layout & Navigation -- Add navbar with branding -- Set up global layout -- Add metadata - -### stap-2: Homepage -- Display all polls as cards -- Show poll stats (option count, vote count) -- Add links to individual polls - -### stap-3: API Routes -- `GET /api/polls` - fetch all polls -- `GET /api/polls/[id]` - fetch single poll -- `POST /api/polls` - create new poll - -### stap-4: Vote API + Demo -- `POST /api/polls/[id]/vote` - record a vote -- Demo form at `/demo` for testing - -### stap-5: Poll Detail Page -- Dynamic route `/poll/[id]` -- Dynamic metadata for SEO -- Show poll questions and options - -### stap-6: VoteForm Component -- Client component with voting logic -- Real-time results with percentage bars -- Purple gradient progress bars - -### stap-7: Error Handling -- Loading skeleton (Suspense) -- Error boundary component -- 404 pages - -### stap-8: Middleware -- Request logging -- Timing middleware -- Route matching - -### bonus: Create Poll -- Form to create new polls -- Dynamic option inputs -- Form validation -- Navigation after creation - -## 🛠 Technology Stack - -- **Next.js 15** - React framework -- **TypeScript** - Type-safe JavaScript -- **Tailwind CSS** - Utility-first CSS -- **React Hooks** - useState for interactivity -- **Fetch API** - For API calls -- **Git** - Version control with tags - -## 🎨 Design System - -**Purple Theme:** -- Primary: `#7c3aed` (purple-500) -- Hover: `#a855f7` (purple-600) -- Active: `#9333ea` (purple-700) - -**Neutral:** -- Light backgrounds: Gray-50 -- Text: Gray-900 -- Borders: Gray-200 -- Errors: Red-600 - -## ✅ Build & Deployment - -### Verify Build -```bash -npm run build -``` - -### Deploy to Vercel -```bash -npm i -g vercel -vercel -``` - -One command deployment! (You need a Vercel account) - -## 📌 Important Notes - -### In-Memory Data -This project uses in-memory JavaScript arrays for data. In production, you'd use: -- PostgreSQL -- MongoDB -- Supabase -- Firebase - -### No Authentication -This project doesn't have user accounts. Real apps would have: -- User authentication -- User-specific voting history -- Admin panels - -### No Database -Each time you restart the app, votes reset. That's fine for demos! - -## 🤔 Common Questions - -**Q: Is this production-ready?** -A: No - it's designed for learning. Add a database for production. - -**Q: Can I modify it for my class?** -A: Yes! Use it as a starting point for assignments. - -**Q: How do I extend it?** -A: Add a real database (PostgreSQL with Prisma is popular), add authentication, add user accounts, etc. - -**Q: Where can students learn more?** -A: https://nextjs.org/learn - official Next.js tutorial - -## 📞 Support - -Each zip file is independent and self-contained. You can: -1. Extract any `stap-X.zip` individually -2. Run `npm install` and `npm run dev` -3. See the app at that stage of development - -The `quickpoll-demo-complete.zip` has git history, so you can: -1. `git log --oneline` - see all commits -2. `git checkout stap-3` - jump to any step -3. `git diff stap-2 stap-3` - see what changed - -## 🎓 For Students - -After the lesson, students can: -1. Clone the repo and explore the code -2. Modify styling with Tailwind -3. Add new features (poll deletion, editing, etc.) -4. Connect to a real database -5. Deploy to Vercel - -This is a great foundation for learning full-stack web development! - -## 📝 Notes - -- All code in English (variable names, comments) -- UI text in Dutch (button labels, messages) -- Fully typed TypeScript throughout -- Comprehensive comments for teaching -- Clean, readable code style - -## 🎉 Ready to Teach! - -You have everything you need. Good luck with your live-coding demonstration! - -Start with **QUICK-START.md** for immediate instructions. - ---- - -**Version:** 1.0 -**Next.js:** 15.x -**Node:** 18+ recommended -**Date Created:** March 2026 diff --git a/Les06-NextJS-QuickPoll-Part2/demo-zips/TEACHER-GUIDE.md b/Les06-NextJS-QuickPoll-Part2/demo-zips/TEACHER-GUIDE.md deleted file mode 100644 index 162fbc6..0000000 --- a/Les06-NextJS-QuickPoll-Part2/demo-zips/TEACHER-GUIDE.md +++ /dev/null @@ -1,311 +0,0 @@ -# QuickPoll Next.js Demo - Live Coding Guide for Tim - -## Overview - -This is a complete, step-by-step Next.js 15 project built for live-coding demonstrations. Each step has a git tag, allowing you to jump between different stages of the application during class. - -## File Structure - -``` -demo-output/ -├── stap-0.zip # Project setup + types + data -├── stap-1.zip # Layout & Navigation -├── stap-2.zip # Homepage with poll cards -├── stap-3.zip # API routes (GET all, GET single, POST create) -├── stap-4.zip # POST vote route + demo form -├── stap-5.zip # Poll detail page -├── stap-6.zip # VoteForm component -├── stap-7.zip # Loading, error, not-found pages -├── stap-8.zip # Middleware -├── bonus.zip # Create poll page -└── quickpoll-demo-complete.zip # Full project with complete git history -``` - -## How to Use in Live-Coding Class - -### 1. **Setup Before Class** - -Extract `quickpoll-demo-complete.zip`: - -```bash -unzip quickpoll-demo-complete.zip -cd quickpoll-demo -npm install -``` - -### 2. **Jump Between Steps During Class** - -Use git checkout to jump to any step: - -```bash -# Go to beginning (step 0) -git checkout stap-0 - -# Progress to step 1 -git checkout stap-1 - -# Jump to step 4 to show the demo form -git checkout stap-4 - -# Go back to the final version -git checkout bonus -``` - -### 3. **Run the Application** - -```bash -npm run dev -``` - -Then open `http://localhost:3000` in your browser and use the projector to show students. - -### 4. **Show the Demo Form (stap-4)** - -When you checkout `stap-4`, a demo page is available at `http://localhost:3000/demo`: - -- Show students how to use the form to test the vote API -- Open DevTools (F12) → Network tab to show the POST request -- Open Console to show the console.log messages -- Display the fetch code example to teach how API calls work - -## What Each Step Covers - -### stap-0: Project Setup -- Create Next.js project with TypeScript and Tailwind -- Set up types and data structures -- Initial folder structure with in-memory "database" -- Includes `.cursorrules` for consistent code style - -**Files to show:** -- `src/types/index.ts` - Poll and VoteBody interfaces -- `src/lib/data.ts` - Sample polls data and functions - -### stap-1: Layout & Navigation -- Add navbar with QuickPoll branding -- Add navigation links (Home, Nieuwe Poll in bonus) -- Update metadata and HTML structure -- Global Tailwind styling - -**Files to show:** -- `src/app/layout.tsx` - Layout component with navbar - -### stap-2: Homepage -- Display all polls as cards -- Show poll question, number of options, total votes -- Add hover effects and links to poll detail pages - -**Files to show:** -- `src/app/page.tsx` - Homepage with poll cards grid -- Tailwind classes for responsive design - -### stap-3: API Routes -- Create `GET /api/polls` - fetch all polls -- Create `GET /api/polls/[id]` - fetch single poll -- Create `POST /api/polls` - create new poll -- Use Next.js 15 async params pattern - -**Files to show:** -- `src/app/api/polls/route.ts` -- `src/app/api/polls/[id]/route.ts` -- Point out `params: Promise<{ id: string }>` pattern - -### stap-4: Vote API Route + Demo Form -- Create `POST /api/polls/[id]/vote` - vote on a poll -- Input validation and error handling -- **Demo form at `/demo`** - interactive testing page -- Console.log statements for teaching -- Display fetch code example - -**Files to show:** -- `src/app/api/polls/[id]/vote/route.ts` -- `src/app/demo/page.tsx` - the demo form (use projector!) -- DevTools Console to show logging -- DevTools Network tab to show POST requests - -### stap-5: Poll Detail Page -- Create `src/app/poll/[id]/page.tsx` (Server Component) -- Add `generateMetadata()` for dynamic SEO -- Use `notFound()` for missing polls -- Placeholder for VoteForm (comes next) - -**Files to show:** -- `src/app/poll/[id]/page.tsx` -- Point out that this is a Server Component (no "use client") - -### stap-6: VoteForm Component -- Create `src/components/VoteForm.tsx` ("use client") -- Implement voting with state management -- Show results after voting with percentage bars -- Purple theme (#7c3aed) with gradient progress bars -- Real-time vote count updates - -**Files to show:** -- `src/components/VoteForm.tsx` -- Explain useState and fetch inside a component -- Show console.log for vote submissions -- Update to `src/app/poll/[id]/page.tsx` to use VoteForm - -### stap-7: Error Handling Pages -- Create `src/app/loading.tsx` - skeleton loader -- Create `src/app/error.tsx` - error boundary -- Create `src/app/not-found.tsx` - global 404 page -- Create `src/app/poll/[id]/not-found.tsx` - poll-specific 404 - -**Files to show:** -- Explain Suspense boundaries and error handling -- Show how Next.js automatically uses these files - -### stap-8: Middleware -- Create `src/middleware.ts` - request logging -- Log request timing and paths -- Use matcher for selective routes - -**Files to show:** -- `src/middleware.ts` -- Point out the matcher configuration - -### bonus: Create Poll Page -- Create `src/app/create/page.tsx` - full form with validation -- Dynamic option inputs (add/remove) -- POST to `/api/polls` and redirect -- Remove demo page (was temporary for stap-4) -- Add "Nieuwe Poll" link to navbar - -**Files to show:** -- `src/app/create/page.tsx` - form implementation -- Error handling and validation - -## Teaching Tips - -### Code Highlighting -- Use VS Code theme with good contrast on projector -- Increase font size (at least 16-18pt) -- Use "Zen Mode" or "Fullscreen" for less distraction - -### Live Coding Strategy -1. **Type slowly** - Let students follow along -2. **Explain as you type** - Narrate what you're doing -3. **Run often** - Show working results frequently -4. **Use DevTools** - Show Network and Console tabs -5. **Ask questions** - Make it interactive - -### DevTools Demonstrations - -**When showing stap-4 demo:** -1. Open http://localhost:3000/demo -2. Open DevTools (F12) -3. Go to Console tab - show console.log messages -4. Go to Network tab -5. Fill the form and click "Stem" -6. Show the POST request in Network tab -7. Show the JSON response -8. Check the Console for detailed logging - -### Key Concepts to Teach - -- **Server Components vs Client Components** - explain when to use "use client" -- **Dynamic Routes** - show how `[id]` creates dynamic pages -- **API Routes** - show how `/api` routes handle requests -- **Middleware** - show how to run code before requests -- **Tailwind CSS** - explain utility-first CSS -- **State Management** - useState in VoteForm -- **Fetch API** - how components communicate with API - -### Projector Tips -- Test the layout on a real projector before class -- Use a light theme for better visibility -- Zoom in on code snippets (Ctrl/Cmd + in browser) -- Keep demos simple - don't try to build everything from scratch - -## File Sizes -- `stap-0.zip` to `stap-8.zip`: ~32-43 KB each -- `bonus.zip`: ~44 KB -- `quickpoll-demo-complete.zip`: ~160 KB (includes full git history) - -## Git Commands for Students - -After you show them the steps, students can explore: - -```bash -# See all commits -git log --oneline - -# See all tags -git tag -l - -# Jump to a specific step -git checkout stap-3 - -# See what changed in this step -git diff stap-2 stap-3 - -# Go back to latest -git checkout bonus -``` - -## Troubleshooting - -### Port 3000 already in use -```bash -npm run dev -- -p 3001 -``` - -### Changes not showing -```bash -# Hard refresh in browser -Ctrl+Shift+R (Windows/Linux) -Cmd+Shift+R (Mac) -``` - -### Git checkout doesn't work -```bash -# Make sure you're in the project directory -cd quickpoll-demo - -# See current status -git status - -# If you have uncommitted changes -git stash - -# Then try checkout again -git checkout stap-5 -``` - -### Build errors -```bash -# Clear Next.js cache -rm -rf .next - -# Reinstall dependencies -npm install - -# Try building -npm run build -``` - -## Project Structure Notes - -- **src/app/** - Next.js App Router pages and layouts -- **src/components/** - Reusable React components -- **src/lib/** - Utility functions and mock data -- **src/types/** - TypeScript interfaces -- **src/middleware.ts** - Request middleware -- **public/** - Static assets - -## Additional Resources - -- Next.js 15 docs: https://nextjs.org/docs -- Tailwind CSS: https://tailwindcss.com/docs -- React: https://react.dev - -## Next Steps After the Demo - -Students can: -1. Modify poll questions and options -2. Add new features (e.g., poll deletion, editing) -3. Connect to a real database (PostgreSQL, MongoDB, etc.) -4. Add authentication -5. Deploy to Vercel - -Good luck with your live-coding demonstration! 🎉 diff --git a/Les06-NextJS-QuickPoll-Part2/demo-zips/bonus.zip b/Les06-NextJS-QuickPoll-Part2/demo-zips/bonus.zip deleted file mode 100644 index 489f7f0..0000000 Binary files a/Les06-NextJS-QuickPoll-Part2/demo-zips/bonus.zip and /dev/null differ diff --git a/Les06-NextJS-QuickPoll-Part2/demo-zips/quickpoll-demo-complete.zip b/Les06-NextJS-QuickPoll-Part2/demo-zips/quickpoll-demo-complete.zip deleted file mode 100644 index 9395caa..0000000 Binary files a/Les06-NextJS-QuickPoll-Part2/demo-zips/quickpoll-demo-complete.zip and /dev/null differ diff --git a/Les06-NextJS-QuickPoll-Part2/demo-zips/stap-0.zip b/Les06-NextJS-QuickPoll-Part2/demo-zips/stap-0.zip deleted file mode 100644 index 69852fd..0000000 Binary files a/Les06-NextJS-QuickPoll-Part2/demo-zips/stap-0.zip and /dev/null differ diff --git a/Les06-NextJS-QuickPoll-Part2/demo-zips/stap-1.zip b/Les06-NextJS-QuickPoll-Part2/demo-zips/stap-1.zip deleted file mode 100644 index f7b3892..0000000 Binary files a/Les06-NextJS-QuickPoll-Part2/demo-zips/stap-1.zip and /dev/null differ diff --git a/Les06-NextJS-QuickPoll-Part2/demo-zips/stap-2.zip b/Les06-NextJS-QuickPoll-Part2/demo-zips/stap-2.zip deleted file mode 100644 index af20edb..0000000 Binary files a/Les06-NextJS-QuickPoll-Part2/demo-zips/stap-2.zip and /dev/null differ diff --git a/Les06-NextJS-QuickPoll-Part2/demo-zips/stap-3.zip b/Les06-NextJS-QuickPoll-Part2/demo-zips/stap-3.zip deleted file mode 100644 index 738da91..0000000 Binary files a/Les06-NextJS-QuickPoll-Part2/demo-zips/stap-3.zip and /dev/null differ diff --git a/Les06-NextJS-QuickPoll-Part2/demo-zips/stap-4.zip b/Les06-NextJS-QuickPoll-Part2/demo-zips/stap-4.zip deleted file mode 100644 index 0ce7241..0000000 Binary files a/Les06-NextJS-QuickPoll-Part2/demo-zips/stap-4.zip and /dev/null differ diff --git a/Les06-NextJS-QuickPoll-Part2/demo-zips/stap-5.zip b/Les06-NextJS-QuickPoll-Part2/demo-zips/stap-5.zip deleted file mode 100644 index 25e5e09..0000000 Binary files a/Les06-NextJS-QuickPoll-Part2/demo-zips/stap-5.zip and /dev/null differ diff --git a/Les06-NextJS-QuickPoll-Part2/demo-zips/stap-6.zip b/Les06-NextJS-QuickPoll-Part2/demo-zips/stap-6.zip deleted file mode 100644 index c46f5b6..0000000 Binary files a/Les06-NextJS-QuickPoll-Part2/demo-zips/stap-6.zip and /dev/null differ diff --git a/Les06-NextJS-QuickPoll-Part2/demo-zips/stap-7.zip b/Les06-NextJS-QuickPoll-Part2/demo-zips/stap-7.zip deleted file mode 100644 index b9edaa0..0000000 Binary files a/Les06-NextJS-QuickPoll-Part2/demo-zips/stap-7.zip and /dev/null differ diff --git a/Les06-NextJS-QuickPoll-Part2/demo-zips/stap-8.zip b/Les06-NextJS-QuickPoll-Part2/demo-zips/stap-8.zip deleted file mode 100644 index 0ccdc0a..0000000 Binary files a/Les06-NextJS-QuickPoll-Part2/demo-zips/stap-8.zip and /dev/null differ diff --git a/Les06-NextJS-QuickPoll-Part2/demo-zips/zi1XoQtN b/Les06-NextJS-QuickPoll-Part2/demo-zips/zi1XoQtN deleted file mode 100644 index b075266..0000000 Binary files a/Les06-NextJS-QuickPoll-Part2/demo-zips/zi1XoQtN and /dev/null differ diff --git a/Les06-NextJS-QuickPoll-Part2/demo-zips/zi4mPzTQ b/Les06-NextJS-QuickPoll-Part2/demo-zips/zi4mPzTQ deleted file mode 100644 index 6682bd8..0000000 Binary files a/Les06-NextJS-QuickPoll-Part2/demo-zips/zi4mPzTQ and /dev/null differ diff --git a/Les06-NextJS-QuickPoll-Part2/demo-zips/zi7KvzJN b/Les06-NextJS-QuickPoll-Part2/demo-zips/zi7KvzJN deleted file mode 100644 index c7bad0a..0000000 Binary files a/Les06-NextJS-QuickPoll-Part2/demo-zips/zi7KvzJN and /dev/null differ diff --git a/Les06-NextJS-QuickPoll-Part2/demo-zips/ziMHBssm b/Les06-NextJS-QuickPoll-Part2/demo-zips/ziMHBssm deleted file mode 100644 index 477fde2..0000000 Binary files a/Les06-NextJS-QuickPoll-Part2/demo-zips/ziMHBssm and /dev/null differ diff --git a/Les06-NextJS-QuickPoll-Part2/demo-zips/ziPStmfI b/Les06-NextJS-QuickPoll-Part2/demo-zips/ziPStmfI deleted file mode 100644 index 915ca3c..0000000 Binary files a/Les06-NextJS-QuickPoll-Part2/demo-zips/ziPStmfI and /dev/null differ diff --git a/Les06-NextJS-QuickPoll-Part2/demo-zips/ziReGaBK b/Les06-NextJS-QuickPoll-Part2/demo-zips/ziReGaBK deleted file mode 100644 index d796b9e..0000000 Binary files a/Les06-NextJS-QuickPoll-Part2/demo-zips/ziReGaBK and /dev/null differ diff --git a/Les06-NextJS-QuickPoll-Part2/demo-zips/ziauujj7 b/Les06-NextJS-QuickPoll-Part2/demo-zips/ziauujj7 deleted file mode 100644 index 32e8e93..0000000 Binary files a/Les06-NextJS-QuickPoll-Part2/demo-zips/ziauujj7 and /dev/null differ diff --git a/Les06-NextJS-QuickPoll-Part2/demo-zips/zigANmHW b/Les06-NextJS-QuickPoll-Part2/demo-zips/zigANmHW deleted file mode 100644 index d9bfdaf..0000000 Binary files a/Les06-NextJS-QuickPoll-Part2/demo-zips/zigANmHW and /dev/null differ diff --git a/Les06-NextJS-QuickPoll-Part2/demo-zips/zitZdV9D b/Les06-NextJS-QuickPoll-Part2/demo-zips/zitZdV9D deleted file mode 100644 index 9ca200d..0000000 Binary files a/Les06-NextJS-QuickPoll-Part2/demo-zips/zitZdV9D and /dev/null differ diff --git a/Les06-NextJS-QuickPoll-Part2/demo-zips/zivUja03 b/Les06-NextJS-QuickPoll-Part2/demo-zips/zivUja03 deleted file mode 100644 index f7a6ddc..0000000 Binary files a/Les06-NextJS-QuickPoll-Part2/demo-zips/zivUja03 and /dev/null differ diff --git a/Les06-NextJS-QuickPoll-Part2/demo-zips/ziz6IP7H b/Les06-NextJS-QuickPoll-Part2/demo-zips/ziz6IP7H deleted file mode 100644 index f15559b..0000000 Binary files a/Les06-NextJS-QuickPoll-Part2/demo-zips/ziz6IP7H and /dev/null differ diff --git a/Les06-NextJS-QuickPoll-Part2/les6-quickpoll-starter.zip b/Les06-NextJS-QuickPoll-Part2/les6-quickpoll-starter.zip deleted file mode 100644 index 6f94d0f..0000000 Binary files a/Les06-NextJS-QuickPoll-Part2/les6-quickpoll-starter.zip and /dev/null differ diff --git a/Les06-NextJS-QuickPoll-Part2/lesbestanden/quickpoll-finished.zip b/Les06-NextJS-QuickPoll-Part2/lesbestanden/quickpoll-finished.zip new file mode 100644 index 0000000..c630345 Binary files /dev/null and b/Les06-NextJS-QuickPoll-Part2/lesbestanden/quickpoll-finished.zip differ diff --git a/Les06-NextJS-QuickPoll-Part2/quickpoll-les6-starter-bundle.zip b/Les06-NextJS-QuickPoll-Part2/lesbestanden/quickpoll-starter.zip similarity index 100% rename from Les06-NextJS-QuickPoll-Part2/quickpoll-les6-starter-bundle.zip rename to Les06-NextJS-QuickPoll-Part2/lesbestanden/quickpoll-starter.zip diff --git a/Les06-NextJS-QuickPoll-Part2/quickpoll-les6-starter.zip b/Les06-NextJS-QuickPoll-Part2/quickpoll-les6-starter.zip deleted file mode 100644 index e69de29..0000000 diff --git a/Les06-NextJS-QuickPoll-Part2/quickpoll-les6-starter/.cursorrules b/Les06-NextJS-QuickPoll-Part2/quickpoll-les6-starter/.cursorrules deleted file mode 100644 index 7de9420..0000000 --- a/Les06-NextJS-QuickPoll-Part2/quickpoll-les6-starter/.cursorrules +++ /dev/null @@ -1,6 +0,0 @@ -You are a Next.js 15 expert using App Router with TypeScript. -Use server components by default. -Use "use client" only when needed for interactivity. -Always define TypeScript interfaces for props, params, and API bodies. -Use Tailwind CSS for styling. -Use the @/ import alias for all local imports. diff --git a/Les06-NextJS-QuickPoll-Part2/quickpoll-les6-starter/.gitignore b/Les06-NextJS-QuickPoll-Part2/quickpoll-les6-starter/.gitignore deleted file mode 100644 index 5ef6a52..0000000 --- a/Les06-NextJS-QuickPoll-Part2/quickpoll-les6-starter/.gitignore +++ /dev/null @@ -1,41 +0,0 @@ -# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. - -# dependencies -/node_modules -/.pnp -.pnp.* -.yarn/* -!.yarn/patches -!.yarn/plugins -!.yarn/releases -!.yarn/versions - -# testing -/coverage - -# next.js -/.next/ -/out/ - -# production -/build - -# misc -.DS_Store -*.pem - -# debug -npm-debug.log* -yarn-debug.log* -yarn-error.log* -.pnpm-debug.log* - -# env files (can opt-in for committing if needed) -.env* - -# vercel -.vercel - -# typescript -*.tsbuildinfo -next-env.d.ts diff --git a/Les06-NextJS-QuickPoll-Part2/quickpoll-les6-starter/README.md b/Les06-NextJS-QuickPoll-Part2/quickpoll-les6-starter/README.md deleted file mode 100644 index e215bc4..0000000 --- a/Les06-NextJS-QuickPoll-Part2/quickpoll-les6-starter/README.md +++ /dev/null @@ -1,36 +0,0 @@ -This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app). - -## Getting Started - -First, run the development server: - -```bash -npm run dev -# or -yarn dev -# or -pnpm dev -# or -bun dev -``` - -Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. - -You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file. - -This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel. - -## Learn More - -To learn more about Next.js, take a look at the following resources: - -- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. -- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. - -You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome! - -## Deploy on Vercel - -The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. - -Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details. diff --git a/Les06-NextJS-QuickPoll-Part2/quickpoll-les6-starter/next.config.ts b/Les06-NextJS-QuickPoll-Part2/quickpoll-les6-starter/next.config.ts deleted file mode 100644 index e9ffa30..0000000 --- a/Les06-NextJS-QuickPoll-Part2/quickpoll-les6-starter/next.config.ts +++ /dev/null @@ -1,7 +0,0 @@ -import type { NextConfig } from "next"; - -const nextConfig: NextConfig = { - /* config options here */ -}; - -export default nextConfig; diff --git a/Les06-NextJS-QuickPoll-Part2/quickpoll-les6-starter/package-lock.json b/Les06-NextJS-QuickPoll-Part2/quickpoll-les6-starter/package-lock.json deleted file mode 100644 index 480ab5e..0000000 --- a/Les06-NextJS-QuickPoll-Part2/quickpoll-les6-starter/package-lock.json +++ /dev/null @@ -1,1664 +0,0 @@ -{ - "name": "quickpoll", - "version": "0.1.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "quickpoll", - "version": "0.1.0", - "dependencies": { - "next": "16.1.6", - "react": "19.2.3", - "react-dom": "19.2.3" - }, - "devDependencies": { - "@tailwindcss/postcss": "^4", - "@types/node": "^20", - "@types/react": "^19", - "@types/react-dom": "^19", - "tailwindcss": "^4", - "typescript": "^5" - } - }, - "node_modules/@alloc/quick-lru": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", - "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@emnapi/runtime": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.8.1.tgz", - "integrity": "sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg==", - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@img/colour": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.1.0.tgz", - "integrity": "sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==", - "license": "MIT", - "optional": true, - "engines": { - "node": ">=18" - } - }, - "node_modules/@img/sharp-darwin-arm64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.5.tgz", - "integrity": "sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==", - "cpu": [ - "arm64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-darwin-arm64": "1.2.4" - } - }, - "node_modules/@img/sharp-darwin-x64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.5.tgz", - "integrity": "sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==", - "cpu": [ - "x64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-darwin-x64": "1.2.4" - } - }, - "node_modules/@img/sharp-libvips-darwin-arm64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.4.tgz", - "integrity": "sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==", - "cpu": [ - "arm64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "darwin" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-darwin-x64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.4.tgz", - "integrity": "sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==", - "cpu": [ - "x64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "darwin" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-arm": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.4.tgz", - "integrity": "sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==", - "cpu": [ - "arm" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-arm64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.4.tgz", - "integrity": "sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==", - "cpu": [ - "arm64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-ppc64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.4.tgz", - "integrity": "sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==", - "cpu": [ - "ppc64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-riscv64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.2.4.tgz", - "integrity": "sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==", - "cpu": [ - "riscv64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-s390x": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.4.tgz", - "integrity": "sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==", - "cpu": [ - "s390x" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-x64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.4.tgz", - "integrity": "sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==", - "cpu": [ - "x64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linuxmusl-arm64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.4.tgz", - "integrity": "sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==", - "cpu": [ - "arm64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linuxmusl-x64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.4.tgz", - "integrity": "sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==", - "cpu": [ - "x64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-linux-arm": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.5.tgz", - "integrity": "sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==", - "cpu": [ - "arm" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-arm": "1.2.4" - } - }, - "node_modules/@img/sharp-linux-arm64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.5.tgz", - "integrity": "sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==", - "cpu": [ - "arm64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-arm64": "1.2.4" - } - }, - "node_modules/@img/sharp-linux-ppc64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.5.tgz", - "integrity": "sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==", - "cpu": [ - "ppc64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-ppc64": "1.2.4" - } - }, - "node_modules/@img/sharp-linux-riscv64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.34.5.tgz", - "integrity": "sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==", - "cpu": [ - "riscv64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-riscv64": "1.2.4" - } - }, - "node_modules/@img/sharp-linux-s390x": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.5.tgz", - "integrity": "sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==", - "cpu": [ - "s390x" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-s390x": "1.2.4" - } - }, - "node_modules/@img/sharp-linux-x64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.5.tgz", - "integrity": "sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==", - "cpu": [ - "x64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-x64": "1.2.4" - } - }, - "node_modules/@img/sharp-linuxmusl-arm64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.5.tgz", - "integrity": "sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==", - "cpu": [ - "arm64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-arm64": "1.2.4" - } - }, - "node_modules/@img/sharp-linuxmusl-x64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.5.tgz", - "integrity": "sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==", - "cpu": [ - "x64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-x64": "1.2.4" - } - }, - "node_modules/@img/sharp-wasm32": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.5.tgz", - "integrity": "sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==", - "cpu": [ - "wasm32" - ], - "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", - "optional": true, - "dependencies": { - "@emnapi/runtime": "^1.7.0" - }, - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-win32-arm64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.5.tgz", - "integrity": "sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==", - "cpu": [ - "arm64" - ], - "license": "Apache-2.0 AND LGPL-3.0-or-later", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-win32-ia32": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.5.tgz", - "integrity": "sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==", - "cpu": [ - "ia32" - ], - "license": "Apache-2.0 AND LGPL-3.0-or-later", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-win32-x64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.5.tgz", - "integrity": "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==", - "cpu": [ - "x64" - ], - "license": "Apache-2.0 AND LGPL-3.0-or-later", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.13", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", - "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.0", - "@jridgewell/trace-mapping": "^0.3.24" - } - }, - "node_modules/@jridgewell/remapping": { - "version": "2.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", - "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "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, - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", - "dev": true, - "license": "MIT" - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.31", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", - "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "node_modules/@next/env": { - "version": "16.1.6", - "resolved": "https://registry.npmjs.org/@next/env/-/env-16.1.6.tgz", - "integrity": "sha512-N1ySLuZjnAtN3kFnwhAwPvZah8RJxKasD7x1f8shFqhncnWZn4JMfg37diLNuoHsLAlrDfM3g4mawVdtAG8XLQ==", - "license": "MIT" - }, - "node_modules/@next/swc-darwin-arm64": { - "version": "16.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.1.6.tgz", - "integrity": "sha512-wTzYulosJr/6nFnqGW7FrG3jfUUlEf8UjGA0/pyypJl42ExdVgC6xJgcXQ+V8QFn6niSG2Pb8+MIG1mZr2vczw==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-darwin-x64": { - "version": "16.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.1.6.tgz", - "integrity": "sha512-BLFPYPDO+MNJsiDWbeVzqvYd4NyuRrEYVB5k2N3JfWncuHAy2IVwMAOlVQDFjj+krkWzhY2apvmekMkfQR0CUQ==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-linux-arm64-gnu": { - "version": "16.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.1.6.tgz", - "integrity": "sha512-OJYkCd5pj/QloBvoEcJ2XiMnlJkRv9idWA/j0ugSuA34gMT6f5b7vOiCQHVRpvStoZUknhl6/UxOXL4OwtdaBw==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-linux-arm64-musl": { - "version": "16.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.1.6.tgz", - "integrity": "sha512-S4J2v+8tT3NIO9u2q+S0G5KdvNDjXfAv06OhfOzNDaBn5rw84DGXWndOEB7d5/x852A20sW1M56vhC/tRVbccQ==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-linux-x64-gnu": { - "version": "16.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.1.6.tgz", - "integrity": "sha512-2eEBDkFlMMNQnkTyPBhQOAyn2qMxyG2eE7GPH2WIDGEpEILcBPI/jdSv4t6xupSP+ot/jkfrCShLAa7+ZUPcJQ==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-linux-x64-musl": { - "version": "16.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.1.6.tgz", - "integrity": "sha512-oicJwRlyOoZXVlxmIMaTq7f8pN9QNbdes0q2FXfRsPhfCi8n8JmOZJm5oo1pwDaFbnnD421rVU409M3evFbIqg==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-win32-arm64-msvc": { - "version": "16.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.1.6.tgz", - "integrity": "sha512-gQmm8izDTPgs+DCWH22kcDmuUp7NyiJgEl18bcr8irXA5N2m2O+JQIr6f3ct42GOs9c0h8QF3L5SzIxcYAAXXw==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-win32-x64-msvc": { - "version": "16.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.1.6.tgz", - "integrity": "sha512-NRfO39AIrzBnixKbjuo2YiYhB6o9d8v/ymU9m/Xk8cyVk+k7XylniXkHwjs4s70wedVffc6bQNbufk5v0xEm0A==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@swc/helpers": { - "version": "0.5.15", - "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz", - "integrity": "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==", - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.8.0" - } - }, - "node_modules/@tailwindcss/node": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.2.1.tgz", - "integrity": "sha512-jlx6sLk4EOwO6hHe1oCGm1Q4AN/s0rSrTTPBGPM0/RQ6Uylwq17FuU8IeJJKEjtc6K6O07zsvP+gDO6MMWo7pg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/remapping": "^2.3.5", - "enhanced-resolve": "^5.19.0", - "jiti": "^2.6.1", - "lightningcss": "1.31.1", - "magic-string": "^0.30.21", - "source-map-js": "^1.2.1", - "tailwindcss": "4.2.1" - } - }, - "node_modules/@tailwindcss/oxide": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.2.1.tgz", - "integrity": "sha512-yv9jeEFWnjKCI6/T3Oq50yQEOqmpmpfzG1hcZsAOaXFQPfzWprWrlHSdGPEF3WQTi8zu8ohC9Mh9J470nT5pUw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 20" - }, - "optionalDependencies": { - "@tailwindcss/oxide-android-arm64": "4.2.1", - "@tailwindcss/oxide-darwin-arm64": "4.2.1", - "@tailwindcss/oxide-darwin-x64": "4.2.1", - "@tailwindcss/oxide-freebsd-x64": "4.2.1", - "@tailwindcss/oxide-linux-arm-gnueabihf": "4.2.1", - "@tailwindcss/oxide-linux-arm64-gnu": "4.2.1", - "@tailwindcss/oxide-linux-arm64-musl": "4.2.1", - "@tailwindcss/oxide-linux-x64-gnu": "4.2.1", - "@tailwindcss/oxide-linux-x64-musl": "4.2.1", - "@tailwindcss/oxide-wasm32-wasi": "4.2.1", - "@tailwindcss/oxide-win32-arm64-msvc": "4.2.1", - "@tailwindcss/oxide-win32-x64-msvc": "4.2.1" - } - }, - "node_modules/@tailwindcss/oxide-android-arm64": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.2.1.tgz", - "integrity": "sha512-eZ7G1Zm5EC8OOKaesIKuw77jw++QJ2lL9N+dDpdQiAB/c/B2wDh0QPFHbkBVrXnwNugvrbJFk1gK2SsVjwWReg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">= 20" - } - }, - "node_modules/@tailwindcss/oxide-darwin-arm64": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.2.1.tgz", - "integrity": "sha512-q/LHkOstoJ7pI1J0q6djesLzRvQSIfEto148ppAd+BVQK0JYjQIFSK3JgYZJa+Yzi0DDa52ZsQx2rqytBnf8Hw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 20" - } - }, - "node_modules/@tailwindcss/oxide-darwin-x64": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.2.1.tgz", - "integrity": "sha512-/f/ozlaXGY6QLbpvd/kFTro2l18f7dHKpB+ieXz+Cijl4Mt9AI2rTrpq7V+t04nK+j9XBQHnSMdeQRhbGyt6fw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 20" - } - }, - "node_modules/@tailwindcss/oxide-freebsd-x64": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.2.1.tgz", - "integrity": "sha512-5e/AkgYJT/cpbkys/OU2Ei2jdETCLlifwm7ogMC7/hksI2fC3iiq6OcXwjibcIjPung0kRtR3TxEITkqgn0TcA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">= 20" - } - }, - "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.2.1.tgz", - "integrity": "sha512-Uny1EcVTTmerCKt/1ZuKTkb0x8ZaiuYucg2/kImO5A5Y/kBz41/+j0gxUZl+hTF3xkWpDmHX+TaWhOtba2Fyuw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 20" - } - }, - "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.2.1.tgz", - "integrity": "sha512-CTrwomI+c7n6aSSQlsPL0roRiNMDQ/YzMD9EjcR+H4f0I1SQ8QqIuPnsVp7QgMkC1Qi8rtkekLkOFjo7OlEFRQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 20" - } - }, - "node_modules/@tailwindcss/oxide-linux-arm64-musl": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.2.1.tgz", - "integrity": "sha512-WZA0CHRL/SP1TRbA5mp9htsppSEkWuQ4KsSUumYQnyl8ZdT39ntwqmz4IUHGN6p4XdSlYfJwM4rRzZLShHsGAQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 20" - } - }, - "node_modules/@tailwindcss/oxide-linux-x64-gnu": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.2.1.tgz", - "integrity": "sha512-qMFzxI2YlBOLW5PhblzuSWlWfwLHaneBE0xHzLrBgNtqN6mWfs+qYbhryGSXQjFYB1Dzf5w+LN5qbUTPhW7Y5g==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 20" - } - }, - "node_modules/@tailwindcss/oxide-linux-x64-musl": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.2.1.tgz", - "integrity": "sha512-5r1X2FKnCMUPlXTWRYpHdPYUY6a1Ar/t7P24OuiEdEOmms5lyqjDRvVY1yy9Rmioh+AunQ0rWiOTPE8F9A3v5g==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 20" - } - }, - "node_modules/@tailwindcss/oxide-wasm32-wasi": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.2.1.tgz", - "integrity": "sha512-MGFB5cVPvshR85MTJkEvqDUnuNoysrsRxd6vnk1Lf2tbiqNlXpHYZqkqOQalydienEWOHHFyyuTSYRsLfxFJ2Q==", - "bundleDependencies": [ - "@napi-rs/wasm-runtime", - "@emnapi/core", - "@emnapi/runtime", - "@tybys/wasm-util", - "@emnapi/wasi-threads", - "tslib" - ], - "cpu": [ - "wasm32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@emnapi/core": "^1.8.1", - "@emnapi/runtime": "^1.8.1", - "@emnapi/wasi-threads": "^1.1.0", - "@napi-rs/wasm-runtime": "^1.1.1", - "@tybys/wasm-util": "^0.10.1", - "tslib": "^2.8.1" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.2.1.tgz", - "integrity": "sha512-YlUEHRHBGnCMh4Nj4GnqQyBtsshUPdiNroZj8VPkvTZSoHsilRCwXcVKnG9kyi0ZFAS/3u+qKHBdDc81SADTRA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 20" - } - }, - "node_modules/@tailwindcss/oxide-win32-x64-msvc": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.2.1.tgz", - "integrity": "sha512-rbO34G5sMWWyrN/idLeVxAZgAKWrn5LiR3/I90Q9MkA67s6T1oB0xtTe+0heoBvHSpbU9Mk7i6uwJnpo4u21XQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 20" - } - }, - "node_modules/@tailwindcss/postcss": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/postcss/-/postcss-4.2.1.tgz", - "integrity": "sha512-OEwGIBnXnj7zJeonOh6ZG9woofIjGrd2BORfvE5p9USYKDCZoQmfqLcfNiRWoJlRWLdNPn2IgVZuWAOM4iTYMw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@alloc/quick-lru": "^5.2.0", - "@tailwindcss/node": "4.2.1", - "@tailwindcss/oxide": "4.2.1", - "postcss": "^8.5.6", - "tailwindcss": "4.2.1" - } - }, - "node_modules/@types/node": { - "version": "20.19.37", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.37.tgz", - "integrity": "sha512-8kzdPJ3FsNsVIurqBs7oodNnCEVbni9yUEkaHbgptDACOPW04jimGagZ51E6+lXUwJjgnBw+hyko/lkFWCldqw==", - "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": "~6.21.0" - } - }, - "node_modules/@types/react": { - "version": "19.2.14", - "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.14.tgz", - "integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==", - "dev": true, - "license": "MIT", - "dependencies": { - "csstype": "^3.2.2" - } - }, - "node_modules/@types/react-dom": { - "version": "19.2.3", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", - "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "@types/react": "^19.2.0" - } - }, - "node_modules/baseline-browser-mapping": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.0.tgz", - "integrity": "sha512-lIyg0szRfYbiy67j9KN8IyeD7q7hcmqnJ1ddWmNt19ItGpNN64mnllmxUNFIOdOm6by97jlL6wfpTTJrmnjWAA==", - "license": "Apache-2.0", - "bin": { - "baseline-browser-mapping": "dist/cli.cjs" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001777", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001777.tgz", - "integrity": "sha512-tmN+fJxroPndC74efCdp12j+0rk0RHwV5Jwa1zWaFVyw2ZxAuPeG8ZgWC3Wz7uSjT3qMRQ5XHZ4COgQmsCMJAQ==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "CC-BY-4.0" - }, - "node_modules/client-only": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", - "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==", - "license": "MIT" - }, - "node_modules/csstype": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", - "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/detect-libc": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", - "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", - "devOptional": true, - "license": "Apache-2.0", - "engines": { - "node": ">=8" - } - }, - "node_modules/enhanced-resolve": { - "version": "5.20.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.20.0.tgz", - "integrity": "sha512-/ce7+jQ1PQ6rVXwe+jKEg5hW5ciicHwIQUagZkp6IufBoY3YDgdTTY1azVs0qoRgVmvsNB+rbjLJxDAeHHtwsQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.2.4", - "tapable": "^2.3.0" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/jiti": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", - "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", - "dev": true, - "license": "MIT", - "bin": { - "jiti": "lib/jiti-cli.mjs" - } - }, - "node_modules/lightningcss": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.31.1.tgz", - "integrity": "sha512-l51N2r93WmGUye3WuFoN5k10zyvrVs0qfKBhyC5ogUQ6Ew6JUSswh78mbSO+IU3nTWsyOArqPCcShdQSadghBQ==", - "dev": true, - "license": "MPL-2.0", - "dependencies": { - "detect-libc": "^2.0.3" - }, - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - }, - "optionalDependencies": { - "lightningcss-android-arm64": "1.31.1", - "lightningcss-darwin-arm64": "1.31.1", - "lightningcss-darwin-x64": "1.31.1", - "lightningcss-freebsd-x64": "1.31.1", - "lightningcss-linux-arm-gnueabihf": "1.31.1", - "lightningcss-linux-arm64-gnu": "1.31.1", - "lightningcss-linux-arm64-musl": "1.31.1", - "lightningcss-linux-x64-gnu": "1.31.1", - "lightningcss-linux-x64-musl": "1.31.1", - "lightningcss-win32-arm64-msvc": "1.31.1", - "lightningcss-win32-x64-msvc": "1.31.1" - } - }, - "node_modules/lightningcss-android-arm64": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.31.1.tgz", - "integrity": "sha512-HXJF3x8w9nQ4jbXRiNppBCqeZPIAfUo8zE/kOEGbW5NZvGc/K7nMxbhIr+YlFlHW5mpbg/YFPdbnCh1wAXCKFg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-darwin-arm64": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.31.1.tgz", - "integrity": "sha512-02uTEqf3vIfNMq3h/z2cJfcOXnQ0GRwQrkmPafhueLb2h7mqEidiCzkE4gBMEH65abHRiQvhdcQ+aP0D0g67sg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-darwin-x64": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.31.1.tgz", - "integrity": "sha512-1ObhyoCY+tGxtsz1lSx5NXCj3nirk0Y0kB/g8B8DT+sSx4G9djitg9ejFnjb3gJNWo7qXH4DIy2SUHvpoFwfTA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-freebsd-x64": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.31.1.tgz", - "integrity": "sha512-1RINmQKAItO6ISxYgPwszQE1BrsVU5aB45ho6O42mu96UiZBxEXsuQ7cJW4zs4CEodPUioj/QrXW1r9pLUM74A==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-arm-gnueabihf": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.31.1.tgz", - "integrity": "sha512-OOCm2//MZJ87CdDK62rZIu+aw9gBv4azMJuA8/KB74wmfS3lnC4yoPHm0uXZ/dvNNHmnZnB8XLAZzObeG0nS1g==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-arm64-gnu": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.31.1.tgz", - "integrity": "sha512-WKyLWztD71rTnou4xAD5kQT+982wvca7E6QoLpoawZ1gP9JM0GJj4Tp5jMUh9B3AitHbRZ2/H3W5xQmdEOUlLg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-arm64-musl": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.31.1.tgz", - "integrity": "sha512-mVZ7Pg2zIbe3XlNbZJdjs86YViQFoJSpc41CbVmKBPiGmC4YrfeOyz65ms2qpAobVd7WQsbW4PdsSJEMymyIMg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-x64-gnu": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.31.1.tgz", - "integrity": "sha512-xGlFWRMl+0KvUhgySdIaReQdB4FNudfUTARn7q0hh/V67PVGCs3ADFjw+6++kG1RNd0zdGRlEKa+T13/tQjPMA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-x64-musl": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.31.1.tgz", - "integrity": "sha512-eowF8PrKHw9LpoZii5tdZwnBcYDxRw2rRCyvAXLi34iyeYfqCQNA9rmUM0ce62NlPhCvof1+9ivRaTY6pSKDaA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-win32-arm64-msvc": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.31.1.tgz", - "integrity": "sha512-aJReEbSEQzx1uBlQizAOBSjcmr9dCdL3XuC/6HLXAxmtErsj2ICo5yYggg1qOODQMtnjNQv2UHb9NpOuFtYe4w==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-win32-x64-msvc": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.31.1.tgz", - "integrity": "sha512-I9aiFrbd7oYHwlnQDqr1Roz+fTz61oDDJX7n9tYF9FJymH1cIN1DtKw3iYt6b8WZgEjoNwVSncwF4wx/ZedMhw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/magic-string": { - "version": "0.30.21", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", - "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.5" - } - }, - "node_modules/nanoid": { - "version": "3.3.11", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", - "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/next": { - "version": "16.1.6", - "resolved": "https://registry.npmjs.org/next/-/next-16.1.6.tgz", - "integrity": "sha512-hkyRkcu5x/41KoqnROkfTm2pZVbKxvbZRuNvKXLRXxs3VfyO0WhY50TQS40EuKO9SW3rBj/sF3WbVwDACeMZyw==", - "license": "MIT", - "dependencies": { - "@next/env": "16.1.6", - "@swc/helpers": "0.5.15", - "baseline-browser-mapping": "^2.8.3", - "caniuse-lite": "^1.0.30001579", - "postcss": "8.4.31", - "styled-jsx": "5.1.6" - }, - "bin": { - "next": "dist/bin/next" - }, - "engines": { - "node": ">=20.9.0" - }, - "optionalDependencies": { - "@next/swc-darwin-arm64": "16.1.6", - "@next/swc-darwin-x64": "16.1.6", - "@next/swc-linux-arm64-gnu": "16.1.6", - "@next/swc-linux-arm64-musl": "16.1.6", - "@next/swc-linux-x64-gnu": "16.1.6", - "@next/swc-linux-x64-musl": "16.1.6", - "@next/swc-win32-arm64-msvc": "16.1.6", - "@next/swc-win32-x64-msvc": "16.1.6", - "sharp": "^0.34.4" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.1.0", - "@playwright/test": "^1.51.1", - "babel-plugin-react-compiler": "*", - "react": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", - "react-dom": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", - "sass": "^1.3.0" - }, - "peerDependenciesMeta": { - "@opentelemetry/api": { - "optional": true - }, - "@playwright/test": { - "optional": true - }, - "babel-plugin-react-compiler": { - "optional": true - }, - "sass": { - "optional": true - } - } - }, - "node_modules/next/node_modules/postcss": { - "version": "8.4.31", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", - "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "nanoid": "^3.3.6", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/picocolors": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "license": "ISC" - }, - "node_modules/postcss": { - "version": "8.5.8", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.8.tgz", - "integrity": "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "nanoid": "^3.3.11", - "picocolors": "^1.1.1", - "source-map-js": "^1.2.1" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/react": { - "version": "19.2.3", - "resolved": "https://registry.npmjs.org/react/-/react-19.2.3.tgz", - "integrity": "sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/react-dom": { - "version": "19.2.3", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.3.tgz", - "integrity": "sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg==", - "license": "MIT", - "dependencies": { - "scheduler": "^0.27.0" - }, - "peerDependencies": { - "react": "^19.2.3" - } - }, - "node_modules/scheduler": { - "version": "0.27.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", - "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", - "license": "MIT" - }, - "node_modules/semver": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", - "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", - "license": "ISC", - "optional": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/sharp": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.5.tgz", - "integrity": "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==", - "hasInstallScript": true, - "license": "Apache-2.0", - "optional": true, - "dependencies": { - "@img/colour": "^1.0.0", - "detect-libc": "^2.1.2", - "semver": "^7.7.3" - }, - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-darwin-arm64": "0.34.5", - "@img/sharp-darwin-x64": "0.34.5", - "@img/sharp-libvips-darwin-arm64": "1.2.4", - "@img/sharp-libvips-darwin-x64": "1.2.4", - "@img/sharp-libvips-linux-arm": "1.2.4", - "@img/sharp-libvips-linux-arm64": "1.2.4", - "@img/sharp-libvips-linux-ppc64": "1.2.4", - "@img/sharp-libvips-linux-riscv64": "1.2.4", - "@img/sharp-libvips-linux-s390x": "1.2.4", - "@img/sharp-libvips-linux-x64": "1.2.4", - "@img/sharp-libvips-linuxmusl-arm64": "1.2.4", - "@img/sharp-libvips-linuxmusl-x64": "1.2.4", - "@img/sharp-linux-arm": "0.34.5", - "@img/sharp-linux-arm64": "0.34.5", - "@img/sharp-linux-ppc64": "0.34.5", - "@img/sharp-linux-riscv64": "0.34.5", - "@img/sharp-linux-s390x": "0.34.5", - "@img/sharp-linux-x64": "0.34.5", - "@img/sharp-linuxmusl-arm64": "0.34.5", - "@img/sharp-linuxmusl-x64": "0.34.5", - "@img/sharp-wasm32": "0.34.5", - "@img/sharp-win32-arm64": "0.34.5", - "@img/sharp-win32-ia32": "0.34.5", - "@img/sharp-win32-x64": "0.34.5" - } - }, - "node_modules/source-map-js": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", - "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/styled-jsx": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.6.tgz", - "integrity": "sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==", - "license": "MIT", - "dependencies": { - "client-only": "0.0.1" - }, - "engines": { - "node": ">= 12.0.0" - }, - "peerDependencies": { - "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0" - }, - "peerDependenciesMeta": { - "@babel/core": { - "optional": true - }, - "babel-plugin-macros": { - "optional": true - } - } - }, - "node_modules/tailwindcss": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.2.1.tgz", - "integrity": "sha512-/tBrSQ36vCleJkAOsy9kbNTgaxvGbyOamC30PRePTQe/o1MFwEKHQk4Cn7BNGaPtjp+PuUrByJehM1hgxfq4sw==", - "dev": true, - "license": "MIT" - }, - "node_modules/tapable": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz", - "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/tslib": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "license": "0BSD" - }, - "node_modules/typescript": { - "version": "5.9.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", - "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/undici-types": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", - "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", - "dev": true, - "license": "MIT" - } - } -} diff --git a/Les06-NextJS-QuickPoll-Part2/quickpoll-les6-starter/package.json b/Les06-NextJS-QuickPoll-Part2/quickpoll-les6-starter/package.json deleted file mode 100644 index 031dcdd..0000000 --- a/Les06-NextJS-QuickPoll-Part2/quickpoll-les6-starter/package.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "name": "quickpoll", - "version": "0.1.0", - "private": true, - "scripts": { - "dev": "next dev", - "build": "next build", - "start": "next start" - }, - "dependencies": { - "next": "16.1.6", - "react": "19.2.3", - "react-dom": "19.2.3" - }, - "devDependencies": { - "@tailwindcss/postcss": "^4", - "@types/node": "^20", - "@types/react": "^19", - "@types/react-dom": "^19", - "tailwindcss": "^4", - "typescript": "^5" - } -} diff --git a/Les06-NextJS-QuickPoll-Part2/quickpoll-les6-starter/postcss.config.mjs b/Les06-NextJS-QuickPoll-Part2/quickpoll-les6-starter/postcss.config.mjs deleted file mode 100644 index 61e3684..0000000 --- a/Les06-NextJS-QuickPoll-Part2/quickpoll-les6-starter/postcss.config.mjs +++ /dev/null @@ -1,7 +0,0 @@ -const config = { - plugins: { - "@tailwindcss/postcss": {}, - }, -}; - -export default config; diff --git a/Les06-NextJS-QuickPoll-Part2/quickpoll-les6-starter/public/file.svg b/Les06-NextJS-QuickPoll-Part2/quickpoll-les6-starter/public/file.svg deleted file mode 100644 index 004145c..0000000 --- a/Les06-NextJS-QuickPoll-Part2/quickpoll-les6-starter/public/file.svg +++ /dev/null @@ -1 +0,0 @@ -<svg fill="none" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="M14.5 13.5V5.41a1 1 0 0 0-.3-.7L9.8.29A1 1 0 0 0 9.08 0H1.5v13.5A2.5 2.5 0 0 0 4 16h8a2.5 2.5 0 0 0 2.5-2.5m-1.5 0v-7H8v-5H3v12a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1M9.5 5V2.12L12.38 5zM5.13 5h-.62v1.25h2.12V5zm-.62 3h7.12v1.25H4.5zm.62 3h-.62v1.25h7.12V11z" clip-rule="evenodd" fill="#666" fill-rule="evenodd"/></svg> \ No newline at end of file diff --git a/Les06-NextJS-QuickPoll-Part2/quickpoll-les6-starter/public/globe.svg b/Les06-NextJS-QuickPoll-Part2/quickpoll-les6-starter/public/globe.svg deleted file mode 100644 index 567f17b..0000000 --- a/Les06-NextJS-QuickPoll-Part2/quickpoll-les6-starter/public/globe.svg +++ /dev/null @@ -1 +0,0 @@ -<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><g clip-path="url(#a)"><path fill-rule="evenodd" clip-rule="evenodd" d="M10.27 14.1a6.5 6.5 0 0 0 3.67-3.45q-1.24.21-2.7.34-.31 1.83-.97 3.1M8 16A8 8 0 1 0 8 0a8 8 0 0 0 0 16m.48-1.52a7 7 0 0 1-.96 0H7.5a4 4 0 0 1-.84-1.32q-.38-.89-.63-2.08a40 40 0 0 0 3.92 0q-.25 1.2-.63 2.08a4 4 0 0 1-.84 1.31zm2.94-4.76q1.66-.15 2.95-.43a7 7 0 0 0 0-2.58q-1.3-.27-2.95-.43a18 18 0 0 1 0 3.44m-1.27-3.54a17 17 0 0 1 0 3.64 39 39 0 0 1-4.3 0 17 17 0 0 1 0-3.64 39 39 0 0 1 4.3 0m1.1-1.17q1.45.13 2.69.34a6.5 6.5 0 0 0-3.67-3.44q.65 1.26.98 3.1M8.48 1.5l.01.02q.41.37.84 1.31.38.89.63 2.08a40 40 0 0 0-3.92 0q.25-1.2.63-2.08a4 4 0 0 1 .85-1.32 7 7 0 0 1 .96 0m-2.75.4a6.5 6.5 0 0 0-3.67 3.44 29 29 0 0 1 2.7-.34q.31-1.83.97-3.1M4.58 6.28q-1.66.16-2.95.43a7 7 0 0 0 0 2.58q1.3.27 2.95.43a18 18 0 0 1 0-3.44m.17 4.71q-1.45-.12-2.69-.34a6.5 6.5 0 0 0 3.67 3.44q-.65-1.27-.98-3.1" fill="#666"/></g><defs><clipPath id="a"><path fill="#fff" d="M0 0h16v16H0z"/></clipPath></defs></svg> \ No newline at end of file diff --git a/Les06-NextJS-QuickPoll-Part2/quickpoll-les6-starter/public/next.svg b/Les06-NextJS-QuickPoll-Part2/quickpoll-les6-starter/public/next.svg deleted file mode 100644 index 5174b28..0000000 --- a/Les06-NextJS-QuickPoll-Part2/quickpoll-les6-starter/public/next.svg +++ /dev/null @@ -1 +0,0 @@ -<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 394 80"><path fill="#000" d="M262 0h68.5v12.7h-27.2v66.6h-13.6V12.7H262V0ZM149 0v12.7H94v20.4h44.3v12.6H94v21h55v12.6H80.5V0h68.7zm34.3 0h-17.8l63.8 79.4h17.9l-32-39.7 32-39.6h-17.9l-23 28.6-23-28.6zm18.3 56.7-9-11-27.1 33.7h17.8l18.3-22.7z"/><path fill="#000" d="M81 79.3 17 0H0v79.3h13.6V17l50.2 62.3H81Zm252.6-.4c-1 0-1.8-.4-2.5-1s-1.1-1.6-1.1-2.6.3-1.8 1-2.5 1.6-1 2.6-1 1.8.3 2.5 1a3.4 3.4 0 0 1 .6 4.3 3.7 3.7 0 0 1-3 1.8zm23.2-33.5h6v23.3c0 2.1-.4 4-1.3 5.5a9.1 9.1 0 0 1-3.8 3.5c-1.6.8-3.5 1.3-5.7 1.3-2 0-3.7-.4-5.3-1s-2.8-1.8-3.7-3.2c-.9-1.3-1.4-3-1.4-5h6c.1.8.3 1.6.7 2.2s1 1.2 1.6 1.5c.7.4 1.5.5 2.4.5 1 0 1.8-.2 2.4-.6a4 4 0 0 0 1.6-1.8c.3-.8.5-1.8.5-3V45.5zm30.9 9.1a4.4 4.4 0 0 0-2-3.3 7.5 7.5 0 0 0-4.3-1.1c-1.3 0-2.4.2-3.3.5-.9.4-1.6 1-2 1.6a3.5 3.5 0 0 0-.3 4c.3.5.7.9 1.3 1.2l1.8 1 2 .5 3.2.8c1.3.3 2.5.7 3.7 1.2a13 13 0 0 1 3.2 1.8 8.1 8.1 0 0 1 3 6.5c0 2-.5 3.7-1.5 5.1a10 10 0 0 1-4.4 3.5c-1.8.8-4.1 1.2-6.8 1.2-2.6 0-4.9-.4-6.8-1.2-2-.8-3.4-2-4.5-3.5a10 10 0 0 1-1.7-5.6h6a5 5 0 0 0 3.5 4.6c1 .4 2.2.6 3.4.6 1.3 0 2.5-.2 3.5-.6 1-.4 1.8-1 2.4-1.7a4 4 0 0 0 .8-2.4c0-.9-.2-1.6-.7-2.2a11 11 0 0 0-2.1-1.4l-3.2-1-3.8-1c-2.8-.7-5-1.7-6.6-3.2a7.2 7.2 0 0 1-2.4-5.7 8 8 0 0 1 1.7-5 10 10 0 0 1 4.3-3.5c2-.8 4-1.2 6.4-1.2 2.3 0 4.4.4 6.2 1.2 1.8.8 3.2 2 4.3 3.4 1 1.4 1.5 3 1.5 5h-5.8z"/></svg> \ No newline at end of file diff --git a/Les06-NextJS-QuickPoll-Part2/quickpoll-les6-starter/public/vercel.svg b/Les06-NextJS-QuickPoll-Part2/quickpoll-les6-starter/public/vercel.svg deleted file mode 100644 index 7705396..0000000 --- a/Les06-NextJS-QuickPoll-Part2/quickpoll-les6-starter/public/vercel.svg +++ /dev/null @@ -1 +0,0 @@ -<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1155 1000"><path d="m577.3 0 577.4 1000H0z" fill="#fff"/></svg> \ No newline at end of file diff --git a/Les06-NextJS-QuickPoll-Part2/quickpoll-les6-starter/public/window.svg b/Les06-NextJS-QuickPoll-Part2/quickpoll-les6-starter/public/window.svg deleted file mode 100644 index b2b2a44..0000000 --- a/Les06-NextJS-QuickPoll-Part2/quickpoll-les6-starter/public/window.svg +++ /dev/null @@ -1 +0,0 @@ -<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path fill-rule="evenodd" clip-rule="evenodd" d="M1.5 2.5h13v10a1 1 0 0 1-1 1h-11a1 1 0 0 1-1-1zM0 1h16v11.5a2.5 2.5 0 0 1-2.5 2.5h-11A2.5 2.5 0 0 1 0 12.5zm3.75 4.5a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5M7 4.75a.75.75 0 1 1-1.5 0 .75.75 0 0 1 1.5 0m1.75.75a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5" fill="#666"/></svg> \ No newline at end of file diff --git a/Les06-NextJS-QuickPoll-Part2/quickpoll-les6-starter/src/app/api/polls/[id]/route.ts b/Les06-NextJS-QuickPoll-Part2/quickpoll-les6-starter/src/app/api/polls/[id]/route.ts deleted file mode 100644 index 229a48a..0000000 --- a/Les06-NextJS-QuickPoll-Part2/quickpoll-les6-starter/src/app/api/polls/[id]/route.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { NextResponse } from "next/server"; -import { getPollById } from "@/lib/data"; -import type { Poll } from "@/types"; - -interface RouteParams { - params: Promise<{ id: string }>; -} - -// STAP 3: GET /api/polls/[id] — enkele poll ophalen -// (Dit bestand is COMPLEET van Les 5. Dit is stap 3 van Les 5.) - -export async function GET( - request: Request, - { params }: RouteParams -): Promise<NextResponse> { - const { id } = await params; - const poll = getPollById(id); - - if (!poll) { - return NextResponse.json( - { error: "Poll niet gevonden" }, - { status: 404 } - ); - } - - return NextResponse.json<Poll>(poll); -} diff --git a/Les06-NextJS-QuickPoll-Part2/quickpoll-les6-starter/src/app/api/polls/[id]/vote/route.ts b/Les06-NextJS-QuickPoll-Part2/quickpoll-les6-starter/src/app/api/polls/[id]/vote/route.ts deleted file mode 100644 index a68e040..0000000 --- a/Les06-NextJS-QuickPoll-Part2/quickpoll-les6-starter/src/app/api/polls/[id]/vote/route.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { NextResponse } from "next/server"; -import { votePoll } from "@/lib/data"; - -interface RouteParams { - params: Promise<{ id: string }>; -} - -interface VoteBody { - optionIndex: number; -} - -// STAP 4: POST /api/polls/[id]/vote — stem uitbrengen -// -// Wat moet je doen? -// 1. Haal het id op uit params (await!) -// 2. Lees de request body en cast naar VoteBody -// 3. Valideer: is optionIndex een number? -// 4. Roep votePoll(id, body.optionIndex) aan -// 5. Als het resultaat undefined is: return 404 -// 6. Anders: return de geüpdatete poll als JSON - -export async function POST( - request: Request, - { params }: RouteParams -): Promise<NextResponse> { - // Implementeer je POST handler hier - return NextResponse.json({ error: "Nog niet geimplementeerd" }, { status: 501 }); -} diff --git a/Les06-NextJS-QuickPoll-Part2/quickpoll-les6-starter/src/app/api/polls/route.ts b/Les06-NextJS-QuickPoll-Part2/quickpoll-les6-starter/src/app/api/polls/route.ts deleted file mode 100644 index 0f647ef..0000000 --- a/Les06-NextJS-QuickPoll-Part2/quickpoll-les6-starter/src/app/api/polls/route.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { NextResponse } from "next/server"; -import { getPolls, createPoll } from "@/lib/data"; -import type { Poll, CreatePollBody } from "@/types"; - -// GET /api/polls — alle polls ophalen -export async function GET(): Promise<NextResponse<Poll[]>> { - const polls = getPolls(); - return NextResponse.json(polls); -} - -// POST /api/polls — nieuwe poll aanmaken -export async function POST(request: Request): Promise<NextResponse> { - const body: CreatePollBody = await request.json(); - - if (!body.question || !body.options || body.options.length < 2) { - return NextResponse.json( - { error: "Vraag en minstens 2 opties zijn verplicht" }, - { status: 400 } - ); - } - - const newPoll = createPoll(body.question, body.options); - return NextResponse.json(newPoll, { status: 201 }); -} diff --git a/Les06-NextJS-QuickPoll-Part2/quickpoll-les6-starter/src/app/create/page.tsx b/Les06-NextJS-QuickPoll-Part2/quickpoll-les6-starter/src/app/create/page.tsx deleted file mode 100644 index f27f872..0000000 --- a/Les06-NextJS-QuickPoll-Part2/quickpoll-les6-starter/src/app/create/page.tsx +++ /dev/null @@ -1,32 +0,0 @@ -"use client"; - -import { useState } from "react"; -import { useRouter } from "next/navigation"; - -// BONUS: Maak een formulier om een nieuwe poll aan te maken -// -// Benodigde state: -// - question: string -// - options: string[] (start met ["", ""]) -// - isSubmitting: boolean -// - error: string | null -// -// Wat moet je bouwen? -// 1. Een input voor de vraag -// 2. Inputs voor de opties (minimaal 2, maximaal 6) -// 3. Knoppen om opties toe te voegen/verwijderen -// 4. Een submit knop die POST naar /api/polls -// 5. Na success: redirect naar / met router.push("/") - -export default function CreatePollPage() { - return ( - <div className="max-w-2xl mx-auto"> - <h1 className="text-2xl font-bold text-gray-900 mb-6"> - Nieuwe Poll Aanmaken - </h1> - <p className="text-gray-400 italic"> - Bonus: bouw hier het create formulier - </p> - </div> - ); -} diff --git a/Les06-NextJS-QuickPoll-Part2/quickpoll-les6-starter/src/app/error.tsx b/Les06-NextJS-QuickPoll-Part2/quickpoll-les6-starter/src/app/error.tsx deleted file mode 100644 index 8d17fc4..0000000 --- a/Les06-NextJS-QuickPoll-Part2/quickpoll-les6-starter/src/app/error.tsx +++ /dev/null @@ -1,30 +0,0 @@ -"use client"; - -// STAP 7: Error boundary -// -// Dit bestand vangt fouten op in de route. -// MOET een client component zijn ("use client" staat al bovenaan). -// -// Props die je krijgt: -// - error: Error — het error object met .message -// - reset: () => void — functie om de pagina opnieuw te proberen -// -// Bouw een nette error pagina met: -// - Een titel "Er ging iets mis!" -// - De error message -// - Een "Probeer opnieuw" knop die reset() aanroept - -export default function Error({ - error, - reset, -}: { - error: Error; - reset: () => void; -}) { - return ( - <div className="text-center py-16"> - <p>Er ging iets mis: {error.message}</p> - <button onClick={() => reset()}>Probeer opnieuw</button> - </div> - ); -} diff --git a/Les06-NextJS-QuickPoll-Part2/quickpoll-les6-starter/src/app/favicon.ico b/Les06-NextJS-QuickPoll-Part2/quickpoll-les6-starter/src/app/favicon.ico deleted file mode 100644 index 718d6fe..0000000 Binary files a/Les06-NextJS-QuickPoll-Part2/quickpoll-les6-starter/src/app/favicon.ico and /dev/null differ diff --git a/Les06-NextJS-QuickPoll-Part2/quickpoll-les6-starter/src/app/globals.css b/Les06-NextJS-QuickPoll-Part2/quickpoll-les6-starter/src/app/globals.css deleted file mode 100644 index f1d8c73..0000000 --- a/Les06-NextJS-QuickPoll-Part2/quickpoll-les6-starter/src/app/globals.css +++ /dev/null @@ -1 +0,0 @@ -@import "tailwindcss"; diff --git a/Les06-NextJS-QuickPoll-Part2/quickpoll-les6-starter/src/app/layout.tsx b/Les06-NextJS-QuickPoll-Part2/quickpoll-les6-starter/src/app/layout.tsx deleted file mode 100644 index 3252dda..0000000 --- a/Les06-NextJS-QuickPoll-Part2/quickpoll-les6-starter/src/app/layout.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import type { Metadata } from "next"; -import Link from "next/link"; -import "./globals.css"; - -export const metadata: Metadata = { - title: "QuickPoll — Stem op alles", - description: "Maak en deel polls met je vrienden", -}; - -export default function RootLayout({ - children, -}: { - children: React.ReactNode; -}) { - return ( - <html lang="nl"> - <body className="min-h-screen bg-gray-50 text-gray-900"> - {/* - STAP 1: Bouw hier een navigatiebalk met: - - Logo/titel "QuickPoll" (links) die linkt naar / - - Een link naar / ("Polls") - - Een link naar /create ("Nieuwe Poll") - - Tip: gebruik <Link> van "next/link", niet <a> - Tip: gebruik Tailwind classes voor styling - */} - - <main className="max-w-4xl mx-auto px-4 py-8">{children}</main> - - <footer className="text-center text-gray-400 text-sm py-8"> - © 2025 QuickPoll — NOVI Hogeschool Les 5 - </footer> - </body> - </html> - ); -} diff --git a/Les06-NextJS-QuickPoll-Part2/quickpoll-les6-starter/src/app/loading.tsx b/Les06-NextJS-QuickPoll-Part2/quickpoll-les6-starter/src/app/loading.tsx deleted file mode 100644 index b70a23c..0000000 --- a/Les06-NextJS-QuickPoll-Part2/quickpoll-les6-starter/src/app/loading.tsx +++ /dev/null @@ -1,17 +0,0 @@ -// STAP 7: Loading state -// -// Dit bestand wordt automatisch getoond terwijl een pagina laadt. -// Bouw een skeleton loader met Tailwind's animate-pulse class. -// -// Voorbeeld: -// <div className="animate-pulse"> -// <div className="h-8 bg-gray-200 rounded w-1/3 mb-4" /> -// </div> - -export default function Loading() { - return ( - <div> - <p>Laden...</p> - </div> - ); -} diff --git a/Les06-NextJS-QuickPoll-Part2/quickpoll-les6-starter/src/app/not-found.tsx b/Les06-NextJS-QuickPoll-Part2/quickpoll-les6-starter/src/app/not-found.tsx deleted file mode 100644 index bd09789..0000000 --- a/Les06-NextJS-QuickPoll-Part2/quickpoll-les6-starter/src/app/not-found.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import Link from "next/link"; - -// STAP 7: Not found pagina -// -// Wordt getoond als een pagina niet bestaat. -// Bouw een nette 404 pagina met een link terug naar home. - -export default function NotFound() { - return ( - <div className="text-center py-16"> - <h2 className="text-4xl font-bold text-gray-900 mb-4">404</h2> - <p className="text-gray-600 mb-6">Deze pagina bestaat niet.</p> - <Link href="/" className="text-purple-600 hover:underline"> - Terug naar home - </Link> - </div> - ); -} diff --git a/Les06-NextJS-QuickPoll-Part2/quickpoll-les6-starter/src/app/page.tsx b/Les06-NextJS-QuickPoll-Part2/quickpoll-les6-starter/src/app/page.tsx deleted file mode 100644 index 9ddc506..0000000 --- a/Les06-NextJS-QuickPoll-Part2/quickpoll-les6-starter/src/app/page.tsx +++ /dev/null @@ -1,31 +0,0 @@ -import Link from "next/link"; -import { getPolls } from "@/lib/data"; -import type { Poll } from "@/types"; - -export const dynamic = "force-dynamic"; - -export default function HomePage() { - // STAP 2: Haal alle polls op met getPolls() - // Dit is een Server Component — je kunt gewoon functies aanroepen! - - return ( - <div> - <h1 className="text-3xl font-bold text-gray-900 mb-2">Actieve Polls</h1> - <p className="text-gray-500 mb-8">Klik op een poll om te stemmen</p> - - <div className="grid gap-4"> - {/* - STAP 2: Map over de polls en toon voor elke poll: - - De vraag (poll.question) - - Het aantal opties en stemmen - - De opties als tags/badges - - Wrap het in een <Link> naar /poll/{poll.id} - - Tip: maak een helper functie voor het totaal aantal stemmen: - const totalVotes = (poll: Poll): number => - poll.votes.reduce((sum, v) => sum + v, 0); - */} - </div> - </div> - ); -} diff --git a/Les06-NextJS-QuickPoll-Part2/quickpoll-les6-starter/src/app/poll/[id]/error.tsx b/Les06-NextJS-QuickPoll-Part2/quickpoll-les6-starter/src/app/poll/[id]/error.tsx deleted file mode 100644 index f3a2d67..0000000 --- a/Les06-NextJS-QuickPoll-Part2/quickpoll-les6-starter/src/app/poll/[id]/error.tsx +++ /dev/null @@ -1,28 +0,0 @@ -"use client"; - -// STAP 7: Error boundary voor poll detail pagina -// -// Dit bestand vangt fouten op in deze route. - -export default function ErrorPoll({ - error, - reset, -}: { - error: Error & { digest?: string }; - reset: () => void; -}) { - return ( - <div className="max-w-2xl mx-auto text-center py-12"> - <h2 className="text-2xl font-bold text-red-600 mb-4"> - Oeps! Iets ging fout - </h2> - <p className="text-gray-600 mb-6">{error.message}</p> - <button - onClick={reset} - className="bg-red-600 text-white px-4 py-2 rounded-lg hover:bg-red-700" - > - Probeer opnieuw - </button> - </div> - ); -} diff --git a/Les06-NextJS-QuickPoll-Part2/quickpoll-les6-starter/src/app/poll/[id]/loading.tsx b/Les06-NextJS-QuickPoll-Part2/quickpoll-les6-starter/src/app/poll/[id]/loading.tsx deleted file mode 100644 index d1cb823..0000000 --- a/Les06-NextJS-QuickPoll-Part2/quickpoll-les6-starter/src/app/poll/[id]/loading.tsx +++ /dev/null @@ -1,20 +0,0 @@ -// STAP 7: Loading state voor poll detail pagina -// -// Dit bestand wordt automatisch getoond terwijl de poll detail pagina laadt. -// Bouw een skeleton loader die lijkt op de echte content. - -export default function LoadingPoll() { - return ( - <div className="max-w-2xl mx-auto animate-pulse"> - <div className="h-10 bg-gray-200 rounded w-3/4 mb-8" /> - <div className="space-y-4"> - {[1, 2, 3].map((i) => ( - <div - key={i} - className="bg-white rounded-lg border p-4 h-16" - /> - ))} - </div> - </div> - ); -} diff --git a/Les06-NextJS-QuickPoll-Part2/quickpoll-les6-starter/src/app/poll/[id]/not-found.tsx b/Les06-NextJS-QuickPoll-Part2/quickpoll-les6-starter/src/app/poll/[id]/not-found.tsx deleted file mode 100644 index 35e5934..0000000 --- a/Les06-NextJS-QuickPoll-Part2/quickpoll-les6-starter/src/app/poll/[id]/not-found.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import Link from "next/link"; - -export default function PollNotFound() { - return ( - <div className="text-center py-16"> - <h2 className="text-2xl font-bold text-gray-900 mb-4"> - Poll niet gevonden - </h2> - <p className="text-gray-600 mb-6"> - Deze poll bestaat niet of is verwijderd. - </p> - <Link href="/" className="text-purple-600 hover:underline"> - Bekijk alle polls - </Link> - </div> - ); -} diff --git a/Les06-NextJS-QuickPoll-Part2/quickpoll-les6-starter/src/app/poll/[id]/page.tsx b/Les06-NextJS-QuickPoll-Part2/quickpoll-les6-starter/src/app/poll/[id]/page.tsx deleted file mode 100644 index 75f46f9..0000000 --- a/Les06-NextJS-QuickPoll-Part2/quickpoll-les6-starter/src/app/poll/[id]/page.tsx +++ /dev/null @@ -1,40 +0,0 @@ -import { notFound } from "next/navigation"; -import { getPollById } from "@/lib/data"; -import { VoteForm } from "@/components/VoteForm"; -import type { Metadata } from "next"; - -interface PageProps { - params: Promise<{ id: string }>; -} - -// STAP 5: generateMetadata — dynamische pagina titel -// -// Deze functie genereert de <title> tag voor SEO. -// Haal de poll op en return de vraag als titel. - -export async function generateMetadata({ params }: PageProps): Promise<Metadata> { - const { id } = await params; - const poll = getPollById(id); - - return { - title: poll ? `${poll.question} — QuickPoll` : "Poll niet gevonden", - }; -} - -// STAP 5: PollPage — de poll detail pagina -// -// Wat moet je doen? -// 1. Haal het id op uit params (await!) -// 2. Zoek de poll met getPollById(id) -// 3. Als de poll niet bestaat: roep notFound() aan -// 4. Render de poll vraag als <h1> -// 5. Render de <VoteForm poll={poll} /> component - -export default async function PollPage({ params }: PageProps) { - // Implementeer je pagina hier - return ( - <div className="max-w-2xl mx-auto"> - <p>Implementeer deze pagina (zie stap 5 in de opdracht)</p> - </div> - ); -} diff --git a/Les06-NextJS-QuickPoll-Part2/quickpoll-les6-starter/src/components/VoteForm.tsx b/Les06-NextJS-QuickPoll-Part2/quickpoll-les6-starter/src/components/VoteForm.tsx deleted file mode 100644 index 9dfbc53..0000000 --- a/Les06-NextJS-QuickPoll-Part2/quickpoll-les6-starter/src/components/VoteForm.tsx +++ /dev/null @@ -1,129 +0,0 @@ -"use client"; - -import { useState } from "react"; -import Link from "next/link"; -import type { Poll } from "@/types"; - -interface VoteFormProps { - poll: Poll; -} - -// STAP 6: VoteForm — de stem interface -// -// Dit is een CLIENT component ("use client" staat bovenaan). -// Hier mag je wel useState en onClick gebruiken! -// -// Benodigde state: -// - selectedOption: number | null (welke optie is geselecteerd) -// - hasVoted: boolean (heeft de gebruiker al gestemd) -// - isLoading: boolean (wordt het formulier verstuurd) -// - currentPoll: Poll (de huidige poll data, update na stemmen) -// -// Wat moet je bouwen? -// 1. Toon alle opties als klikbare knoppen (voor het stemmen) -// 2. Highlight de geselecteerde optie met purple border -// 3. Een "Stem!" knop die een POST doet naar /api/polls/{id}/vote -// 4. Na het stemmen: toon de resultaten met progress bars en percentages -// 5. Toon een "Terug" link naar de homepage - -export function VoteForm({ poll }: VoteFormProps) { - const [selectedOption, setSelectedOption] = useState<number | null>(null); - const [hasVoted, setHasVoted] = useState<boolean>(false); - const [isLoading, setIsLoading] = useState<boolean>(false); - const [currentPoll, setCurrentPoll] = useState<Poll>(poll); - - const totalVotes: number = currentPoll.votes.reduce((sum, v) => sum + v, 0); - - function getPercentage(votes: number): number { - if (totalVotes === 0) return 0; - return Math.round((votes / totalVotes) * 100); - } - - async function handleVote(): Promise<void> { - if (selectedOption === null || isLoading) return; - setIsLoading(true); - - try { - const response = await fetch(`/api/polls/${currentPoll.id}/vote`, { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ optionIndex: selectedOption }), - }); - - if (response.ok) { - const updatedPoll: Poll = await response.json(); - setCurrentPoll(updatedPoll); - setHasVoted(true); - } - } finally { - setIsLoading(false); - } - } - - // Nog niet gestemd — toon opties - if (!hasVoted) { - return ( - <div className="space-y-4"> - {currentPoll.options.map((option, idx) => ( - <button - key={idx} - onClick={() => setSelectedOption(idx)} - disabled={isLoading} - className={`w-full text-left p-4 rounded-lg border-2 transition ${ - selectedOption === idx - ? "border-purple-500 bg-purple-50" - : "border-gray-200 hover:border-purple-300" - }`} - > - <span className="font-medium">{option}</span> - </button> - ))} - - <button - onClick={handleVote} - disabled={selectedOption === null || isLoading} - className="w-full bg-purple-600 text-white py-3 rounded-lg hover:bg-purple-700 disabled:opacity-50 disabled:cursor-not-allowed transition font-medium" - > - {isLoading ? "Aan het stemmen..." : "Stem!"} - </button> - </div> - ); - } - - // Wel gestemd — toon resultaten - return ( - <div className="space-y-6"> - <p className="text-green-600 font-medium text-lg"> - ✓ Bedankt voor je stem! - </p> - - <div className="space-y-4"> - {currentPoll.options.map((option, idx) => ( - <div key={idx}> - <div className="flex justify-between mb-2"> - <span className="font-medium">{option}</span> - <span className="text-sm text-gray-600"> - {currentPoll.votes[idx]} stemmen ({getPercentage(currentPoll.votes[idx])}%) - </span> - </div> - <div className="w-full bg-gray-200 rounded-full h-3"> - <div - className="bg-purple-600 h-3 rounded-full transition-all" - style={{ - width: `${getPercentage(currentPoll.votes[idx])}%`, - }} - /> - </div> - </div> - ))} - </div> - - <Link - href="/" - className="block text-center text-purple-600 hover:underline mt-6" - > - ← Terug naar polls - </Link> - </div> - ); -} diff --git a/Les06-NextJS-QuickPoll-Part2/quickpoll-les6-starter/src/lib/data.ts b/Les06-NextJS-QuickPoll-Part2/quickpoll-les6-starter/src/lib/data.ts deleted file mode 100644 index 3e36f41..0000000 --- a/Les06-NextJS-QuickPoll-Part2/quickpoll-les6-starter/src/lib/data.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { Poll } from "@/types"; - -export const polls: Poll[] = [ - { - id: "1", - question: "Wat is de beste code editor?", - options: ["VS Code", "Cursor", "Vim", "WebStorm"], - votes: [12, 25, 5, 3], - }, - { - id: "2", - question: "Wat is de beste programmeertaal?", - options: ["TypeScript", "Python", "Rust", "Go"], - votes: [18, 15, 8, 4], - }, - { - id: "3", - question: "Welk framework heeft de toekomst?", - options: ["Next.js", "Remix", "Astro", "SvelteKit"], - votes: [22, 6, 10, 7], - }, -]; - -let nextId = 4; - -export function getPolls(): Poll[] { - return polls; -} - -export function getPollById(id: string): Poll | undefined { - return polls.find((poll) => poll.id === id); -} - -export function createPoll(question: string, options: string[]): Poll { - const newPoll: Poll = { - id: String(nextId++), - question, - options, - votes: new Array(options.length).fill(0), - }; - polls.push(newPoll); - return newPoll; -} - -export function votePoll( - pollId: string, - optionIndex: number -): Poll | undefined { - const poll = polls.find((p) => p.id === pollId); - if (!poll || optionIndex < 0 || optionIndex >= poll.options.length) { - return undefined; - } - poll.votes[optionIndex]++; - return poll; -} diff --git a/Les06-NextJS-QuickPoll-Part2/quickpoll-les6-starter/src/middleware.ts b/Les06-NextJS-QuickPoll-Part2/quickpoll-les6-starter/src/middleware.ts deleted file mode 100644 index 76bbfab..0000000 --- a/Les06-NextJS-QuickPoll-Part2/quickpoll-les6-starter/src/middleware.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { NextResponse } from "next/server"; -import type { NextRequest } from "next/server"; - -export function middleware(request: NextRequest): NextResponse { - const start = Date.now(); - - console.log(`[${request.method}] ${request.nextUrl.pathname}`); - - const response = NextResponse.next(); - response.headers.set("x-request-time", String(Date.now() - start)); - - return response; -} - -export const config = { - matcher: ["/api/:path*", "/poll/:path*"], -}; diff --git a/Les06-NextJS-QuickPoll-Part2/quickpoll-les6-starter/src/types/index.ts b/Les06-NextJS-QuickPoll-Part2/quickpoll-les6-starter/src/types/index.ts deleted file mode 100644 index 73f152f..0000000 --- a/Les06-NextJS-QuickPoll-Part2/quickpoll-les6-starter/src/types/index.ts +++ /dev/null @@ -1,11 +0,0 @@ -export interface Poll { - id: string; - question: string; - options: string[]; - votes: number[]; -} - -export interface CreatePollBody { - question: string; - options: string[]; -} diff --git a/Les06-NextJS-QuickPoll-Part2/quickpoll-les6-starter/tsconfig.json b/Les06-NextJS-QuickPoll-Part2/quickpoll-les6-starter/tsconfig.json deleted file mode 100644 index cf9c65d..0000000 --- a/Les06-NextJS-QuickPoll-Part2/quickpoll-les6-starter/tsconfig.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2017", - "lib": ["dom", "dom.iterable", "esnext"], - "allowJs": true, - "skipLibCheck": true, - "strict": true, - "noEmit": true, - "esModuleInterop": true, - "module": "esnext", - "moduleResolution": "bundler", - "resolveJsonModule": true, - "isolatedModules": true, - "jsx": "react-jsx", - "incremental": true, - "plugins": [ - { - "name": "next" - } - ], - "paths": { - "@/*": ["./src/*"] - } - }, - "include": [ - "next-env.d.ts", - "**/*.ts", - "**/*.tsx", - ".next/types/**/*.ts", - ".next/dev/types/**/*.ts", - "**/*.mts" - ], - "exclude": ["node_modules"] -} diff --git a/Les07-Supabase/lesbestanden/quickpoll-starter.zip b/Les07-Supabase/lesbestanden/quickpoll-starter.zip new file mode 100644 index 0000000..c630345 Binary files /dev/null and b/Les07-Supabase/lesbestanden/quickpoll-starter.zip differ diff --git a/Les07-Supabase/lesbestanden/quickpoll-supabase-finished.zip b/Les07-Supabase/lesbestanden/quickpoll-supabase-finished.zip new file mode 100644 index 0000000..43997b2 Binary files /dev/null and b/Les07-Supabase/lesbestanden/quickpoll-supabase-finished.zip differ diff --git a/Les08-Van-InMemory-naar-Supabase/lesbestanden/quickpoll-realtime-finished.zip b/Les08-Van-InMemory-naar-Supabase/lesbestanden/quickpoll-realtime-finished.zip new file mode 100644 index 0000000..8565611 Binary files /dev/null and b/Les08-Van-InMemory-naar-Supabase/lesbestanden/quickpoll-realtime-finished.zip differ diff --git a/Les08-Van-InMemory-naar-Supabase/lesbestanden/quickpoll-starter.zip b/Les08-Van-InMemory-naar-Supabase/lesbestanden/quickpoll-starter.zip new file mode 100644 index 0000000..43997b2 Binary files /dev/null and b/Les08-Van-InMemory-naar-Supabase/lesbestanden/quickpoll-starter.zip differ diff --git a/Les09-Supabase-Auth/lesbestanden/quickpoll-auth-finished.zip b/Les09-Supabase-Auth/lesbestanden/quickpoll-auth-finished.zip new file mode 100644 index 0000000..d94f647 Binary files /dev/null and b/Les09-Supabase-Auth/lesbestanden/quickpoll-auth-finished.zip differ diff --git a/Les09-Supabase-Auth/lesbestanden/quickpoll-starter.zip b/Les09-Supabase-Auth/lesbestanden/quickpoll-starter.zip new file mode 100644 index 0000000..8565611 Binary files /dev/null and b/Les09-Supabase-Auth/lesbestanden/quickpoll-starter.zip differ diff --git a/Les10-Supabase-Auth/poll-app-starter.zip b/Les10-Supabase-Auth/lesbestanden/poll-app-starter.zip similarity index 100% rename from Les10-Supabase-Auth/poll-app-starter.zip rename to Les10-Supabase-Auth/lesbestanden/poll-app-starter.zip diff --git a/Les10-Supabase-Auth/lesbestanden/quickpoll-rls-finished.zip b/Les10-Supabase-Auth/lesbestanden/quickpoll-rls-finished.zip new file mode 100644 index 0000000..6c04041 Binary files /dev/null and b/Les10-Supabase-Auth/lesbestanden/quickpoll-rls-finished.zip differ diff --git a/Les11-AI-SDK/lesbestanden/code-snippets.zip b/Les11-AI-SDK/lesbestanden/code-snippets.zip new file mode 100644 index 0000000..0cc9b09 Binary files /dev/null and b/Les11-AI-SDK/lesbestanden/code-snippets.zip differ diff --git a/Les11-AI-SDK/lesbestanden/page.tsx b/Les11-AI-SDK/lesbestanden/page.tsx deleted file mode 100644 index 3be8ef3..0000000 --- a/Les11-AI-SDK/lesbestanden/page.tsx +++ /dev/null @@ -1,68 +0,0 @@ -/** - * Polderfest 2027 — chat pagina - * -------------------------------------------------- - * Les 11 — useChat hook + Tailwind chat UI. - * Plaats dit bestand op: app/chat/page.tsx - * - * Werking: - * - useChat() regelt messages, input, submit-handler, streaming - * - Praat met /api/chat (de route.ts) - * - Disabled tijdens streaming - * - * Vereist: - * - app/api/chat/route.ts (zie route.ts) - * - npm i ai - * - Tailwind aanwezig in project (standaard in create-next-app) - */ - -"use client"; - -import { useChat } from "ai/react"; - -export default function ChatPage() { - const { messages, input, handleInputChange, handleSubmit, status } = - useChat(); - - return ( - <main className="max-w-2xl mx-auto p-6 flex flex-col h-screen"> - <h1 className="text-2xl font-bold mb-4"> - Polderfest 2027 — vraag de AI - </h1> - - <div className="flex-1 overflow-y-auto space-y-4 mb-4"> - {messages.map((m) => ( - <div - key={m.id} - className={ - m.role === "user" - ? "bg-blue-50 p-3 rounded-lg ml-12" - : "bg-gray-50 p-3 rounded-lg mr-12" - } - > - <div className="font-medium text-sm text-gray-500 mb-1"> - {m.role === "user" ? "Jij" : "Festival AI"} - </div> - <div className="whitespace-pre-wrap">{m.content}</div> - </div> - ))} - </div> - - <form onSubmit={handleSubmit} className="flex gap-2"> - <input - value={input} - onChange={handleInputChange} - placeholder="Stel een vraag over de line-up..." - className="flex-1 p-3 border rounded-lg" - disabled={status !== "ready"} - /> - <button - type="submit" - disabled={status !== "ready"} - className="px-6 py-3 bg-blue-600 text-white rounded-lg disabled:opacity-50" - > - Stuur - </button> - </form> - </main> - ); -} diff --git a/Les11-AI-SDK/lesbestanden/polderfest-ai-finished.zip b/Les11-AI-SDK/lesbestanden/polderfest-ai-finished.zip new file mode 100644 index 0000000..e34f925 Binary files /dev/null and b/Les11-AI-SDK/lesbestanden/polderfest-ai-finished.zip differ diff --git a/Les11-AI-SDK/lesbestanden/polderfest-demo.zip b/Les11-AI-SDK/lesbestanden/polderfest-starter.zip similarity index 100% rename from Les11-AI-SDK/lesbestanden/polderfest-demo.zip rename to Les11-AI-SDK/lesbestanden/polderfest-starter.zip diff --git a/Les11-AI-SDK/lesbestanden/route.ts b/Les11-AI-SDK/lesbestanden/route.ts deleted file mode 100644 index 25f0670..0000000 --- a/Les11-AI-SDK/lesbestanden/route.ts +++ /dev/null @@ -1,61 +0,0 @@ -/** - * Polderfest 2027 — chat API route - * -------------------------------------------------- - * Les 11 — Vercel AI SDK + Supabase context. - * Plaats dit bestand op: app/api/chat/route.ts - * - * Werking: - * 1. Haal alle bands op uit Supabase - * 2. Formatteer als tekst-context - * 3. Stuur naar OpenAI via streamText + system prompt - * 4. Return een stream voor useChat - * - * Vereist: - * - NEXT_PUBLIC_SUPABASE_URL en NEXT_PUBLIC_SUPABASE_ANON_KEY in .env.local - * - OPENAI_API_KEY in .env.local - * - npm i ai @ai-sdk/openai @supabase/supabase-js - */ - -import { streamText } from "ai"; -import { openai } from "@ai-sdk/openai"; -import { createClient } from "@supabase/supabase-js"; - -const supabase = createClient( - process.env.NEXT_PUBLIC_SUPABASE_URL!, - process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!, -); - -export async function POST(req: Request) { - const { messages } = await req.json(); - - // 1. Haal alle bands op uit Supabase - const { data: bands, error } = await supabase.from("bands").select("*"); - if (error) throw error; - - // 2. Format bands als context-string - const context = bands! - .map( - (b) => - `- ${b.name} (${b.genre}, ${b.tier}, ${b.day} ${b.start_time} ` + - `op ${b.stage}, uit ${b.origin_city})`, - ) - .join("\n"); - - // 3. System prompt met context - const system = `Je bent een festival-assistent voor Polderfest 2027. -Hier zijn alle bands die op het festival spelen: - -${context} - -Beantwoord vragen van bezoekers over de line-up. Verzin niets — gebruik -alleen bovenstaande data. Antwoord in het Nederlands. Wees beknopt.`; - - // 4. Stream naar OpenAI - const result = streamText({ - model: openai("gpt-4o-mini"), - system, - messages, - }); - - return result.toDataStreamResponse(); -} diff --git a/Les11-AI-SDK/lesbestanden/schema.sql b/Les11-AI-SDK/lesbestanden/schema.sql deleted file mode 100644 index 0a3af2d..0000000 --- a/Les11-AI-SDK/lesbestanden/schema.sql +++ /dev/null @@ -1,42 +0,0 @@ --- Polderfest 2027 — Supabase schema --- Run dit in Supabase SQL Editor voor je het seed script gebruikt. - -create table if not exists bands ( - id bigserial primary key, - name text not null, - genre text not null, - sub_genre text, - stage text not null, - day text not null check (day in ('Vrijdag','Zaterdag','Zondag')), - start_time text not null, -- "21:30" - duration_min int not null default 60, - origin_city text, - members text[], - bio text, - tier text check (tier in ('headliner','mid','opener')), - popularity int check (popularity between 1 and 100), - ticket_impact numeric(6,2), -- bijdrage aan ticketprijs als extra - created_at timestamp default now() -); - --- Maak indexen voor de vragen die we vaak gaan stellen -create index if not exists idx_bands_day on bands(day); -create index if not exists idx_bands_stage on bands(stage); -create index if not exists idx_bands_genre on bands(genre); -create index if not exists idx_bands_tier on bands(tier); - --- RLS (we lezen public, geen edits voor anon) -alter table bands enable row level security; - -create policy "Bands zijn publiek leesbaar" - on bands for select - using (true); - --- Optioneel: tabel voor straks (tool calling demo in Les 12) -create table if not exists user_favorites ( - id bigserial primary key, - user_email text not null, - band_id bigint not null references bands(id) on delete cascade, - created_at timestamp default now(), - unique(user_email, band_id) -); diff --git a/Les11-AI-SDK/lesbestanden/seed-polderfest.ts b/Les11-AI-SDK/lesbestanden/seed-polderfest.ts deleted file mode 100644 index 0af987f..0000000 --- a/Les11-AI-SDK/lesbestanden/seed-polderfest.ts +++ /dev/null @@ -1,272 +0,0 @@ -/** - * Polderfest 2027 — seed script - * ---------------------------------------------------------- - * Genereert 500 fictieve bands en zet ze in je Supabase `bands` tabel. - * Run: - * 1. Zorg dat `bands` tabel bestaat (zie schema.sql) - * 2. Vul .env.local met: - * SUPABASE_URL=https://<project>.supabase.co - * SUPABASE_SERVICE_ROLE_KEY=<service role key> - * 3. npm i @supabase/supabase-js dotenv tsx --save-dev - * 4. npx tsx seed-polderfest.ts - * - * Service role key is bewust nodig — alleen voor lokaal seeden. - * NIET committen, NIET in client gebruiken. - */ - -import { createClient } from "@supabase/supabase-js"; -import dotenv from "dotenv"; - -// Laad .env.local (i.p.v. default .env) -dotenv.config({ path: ".env.local" }); - -const SUPABASE_URL = - process.env.NEXT_PUBLIC_SUPABASE_URL ?? process.env.SUPABASE_URL; -const SUPABASE_SERVICE_ROLE_KEY = process.env.SUPABASE_SERVICE_ROLE_KEY; - -if (!SUPABASE_URL || !SUPABASE_SERVICE_ROLE_KEY) { - console.error( - "Ontbrekende env vars. Check .env.local:\n" + - " NEXT_PUBLIC_SUPABASE_URL=https://<project>.supabase.co\n" + - " SUPABASE_SERVICE_ROLE_KEY=<service role key>" - ); - process.exit(1); -} - -const supabase = createClient(SUPABASE_URL, SUPABASE_SERVICE_ROLE_KEY, { - auth: { persistSession: false }, -}); - -// ──────────────────────────────────────────────────────────── -// Deterministische random (zodat seed reproduceerbaar is) -// ──────────────────────────────────────────────────────────── -let seed = 42; -function rand() { - seed = (seed * 9301 + 49297) % 233280; - return seed / 233280; -} -function pick<T>(arr: readonly T[]): T { - return arr[Math.floor(rand() * arr.length)]; -} -function pickN<T>(arr: readonly T[], n: number): T[] { - const copy = [...arr]; - const out: T[] = []; - for (let i = 0; i < n && copy.length; i++) { - out.push(copy.splice(Math.floor(rand() * copy.length), 1)[0]); - } - return out; -} -function range(min: number, max: number): number { - return Math.floor(rand() * (max - min + 1)) + min; -} - -// ──────────────────────────────────────────────────────────── -// Bouwstenen voor band-namen -// ──────────────────────────────────────────────────────────── -const adjectives = [ - "Lost", "Velvet", "Iron", "Neon", "Silent", "Wild", "Glass", "Paper", "Sleeping", - "Honest", "Crooked", "Bitter", "Sweet", "Drowsy", "Drowning", "Restless", "Sober", - "Midnight", "Morning", "Yellow", "Crimson", "Hollow", "Heavy", "Floating", "Slow", - "Burning", "Frozen", "Cardboard", "Plastic", "Analog", "Digital", "Forgotten", -] as const; - -const nouns = [ - "Tigers", "Wolves", "Horses", "Rabbits", "Mirrors", "Clouds", "Echoes", "Ghosts", - "Lights", "Roots", "Stones", "Foxes", "Riders", "Ships", "Tides", "Anchors", - "Maps", "Letters", "Postcards", "Radios", "Telegrams", "Diaries", "Highways", - "Cassettes", "Polaroids", "Cathedrals", "Stations", "Lanterns", "Compasses", - "Saturdays", "Tuesdays", "Mondays", -] as const; - -const dutchPrefixes = [ - "De", "Het", "Van der", "Polder", "Noord", "Zuid", -] as const; - -const soloNamesFirst = [ - "Sanne", "Joost", "Yara", "Lex", "Mila", "Tess", "Bram", "Lotte", "Ravi", "Imani", - "Marit", "Stijn", "Liva", "Noor", "Casper", "Anouk", "Mees", "Pien", "Daan", "Olivia", - "Niels", "Fenna", "Tygo", "Saar", "Cas", "Maud", "Roos", "Vince", "Lieke", "Floris", -] as const; - -const soloNamesLast = [ - "Van Dijk", "De Boer", "Visser", "Jansen", "Bakker", "Hendriks", "Mulder", "Smit", - "Peters", "De Vries", "Kuipers", "Brouwer", "Postma", "Hofman", "Van Loon", -] as const; - -// ──────────────────────────────────────────────────────────── -// Fest-velden -// ──────────────────────────────────────────────────────────── -const genres = [ - "Indie Rock", "Electronic", "Hip-Hop", "Jazz Fusion", "Folk", "Punk", "Soul", - "Ambient", "Disco-House", "Experimental", "Singer-Songwriter", "Synth-Pop", - "Garage Rock", "Neo-Soul", "Drum & Bass", "Afrobeat", "Dream Pop", "Post-Rock", -] as const; - -const subGenresByGenre: Record<string, string[]> = { - "Indie Rock": ["Shoegaze", "Lo-Fi", "Math Rock", "Slowcore"], - "Electronic": ["Techno", "House", "IDM", "Glitch", "Trance"], - "Hip-Hop": ["Boom Bap", "Trap", "Lo-Fi", "Conscious"], - "Jazz Fusion": ["Funk Jazz", "Cosmic Jazz", "Nu-Jazz"], - "Folk": ["Anti-Folk", "Sea Shanty", "Modern Folk"], - "Punk": ["Post-Punk", "Hardcore", "Surf Punk"], - "Soul": ["Neo-Soul", "Northern Soul", "Funk"], - "Ambient": ["Drone", "New Age", "Field Recording"], - "Disco-House": ["Italo Disco", "Nu-Disco", "French House"], - "Experimental": ["Noise", "Sound Art", "Avantgarde"], - "Singer-Songwriter": ["Confessional", "Storytelling"], - "Synth-Pop": ["Vaporwave", "Italo", "Darkwave"], - "Garage Rock": ["Surf", "Power Pop"], - "Neo-Soul": ["Alt R&B", "Jazz-influenced"], - "Drum & Bass": ["Liquid", "Jungle", "Neurofunk"], - "Afrobeat": ["Afro-Fusion", "Highlife"], - "Dream Pop": ["Bedroom Pop", "Ethereal"], - "Post-Rock": ["Cinematic", "Math-influenced"], -}; - -const stages = [ - "Main Stage", "Tent Stage", "Beach Stage", "Acoustic Bar", "Late Night Tent", -] as const; - -const days = ["Vrijdag", "Zaterdag", "Zondag"] as const; - -const timeSlots = [ - "14:00", "15:30", "17:00", "18:30", "20:00", "21:30", "23:00", "00:30", -] as const; - -const cities = [ - "Amsterdam", "Rotterdam", "Utrecht", "Groningen", "Eindhoven", "Den Haag", - "Tilburg", "Maastricht", "Nijmegen", "Leeuwarden", "Arnhem", "Breda", "Haarlem", - "Zwolle", "Enschede", "Delft", "Den Bosch", "Apeldoorn", -] as const; - -const tiers = ["headliner", "mid", "opener"] as const; - -// ──────────────────────────────────────────────────────────── -// Bio-fragmenten — combinatorisch zodat 500 bios uniek voelen -// ──────────────────────────────────────────────────────────── -const bioOpenings = [ - "Begonnen in een garage in", - "Ontstaan tijdens een blackout in", - "Een vriendengroep uit", - "Doorgebroken op het kleine podium van", - "Geboren uit een jam-sessie in", - "Een collectief van producers uit", -]; -const bioMiddle = [ - "experimenteert met analoge synths en gefluisterde lyrics", - "balanceert tussen melancholie en dansvloer-euforie", - "mixt traditionele samples met breakbeats", - "gebruikt veldopnames als ritmesectie", - "schrijft songs in Nederlands en Engels door elkaar", - "speelt instrumenten die ze grotendeels zelf hebben gebouwd", - "draait alleen optredens op locaties zonder Wi-Fi", -]; -const bioEnding = [ - "Debuut-EP verschijnt eind 2027.", - "Hun laatste album werd genomineerd voor de fictieve Edison Polder Award.", - "Polderfest is hun grootste festival tot nu toe.", - "Vorig jaar speelden ze nog in cafés, dit jaar op Stage B.", - "Spelen voor het eerst op een buitenpodium.", - "Beruchte live-show met 12 backing vocalists.", -]; - -// ──────────────────────────────────────────────────────────── -// Namen genereren -// ──────────────────────────────────────────────────────────── -function generateBandName(seedIdx: number): string { - const pattern = seedIdx % 4; - if (pattern === 0) { - return `${pick(adjectives)} ${pick(nouns)}`; - } - if (pattern === 1) { - return `${pick(dutchPrefixes)} ${pick(nouns)}`; - } - if (pattern === 2) { - return `${pick(soloNamesFirst)} ${pick(soloNamesLast)}`; - } - return `${pick(soloNamesFirst)} & The ${pick(nouns)}`; -} - -function generateMembers(): string[] { - const count = range(1, 5); - const out: string[] = []; - for (let i = 0; i < count; i++) { - out.push(`${pick(soloNamesFirst)} ${pick(soloNamesLast)}`); - } - return out; -} - -function generateBio(name: string): string { - return `${pick(bioOpenings)} ${pick(cities)}, ${name} ${pick(bioMiddle)}. ${pick(bioEnding)}`; -} - -// ──────────────────────────────────────────────────────────── -// Hoofdfunctie -// ──────────────────────────────────────────────────────────── -async function runSeed() { - console.log("Genereren van 500 Polderfest bands..."); - - // Wipe bestaande data (optioneel) - await supabase.from("bands").delete().neq("id", 0); - - const bands = []; - const usedNames = new Set<string>(); - - for (let i = 0; i < 500; i++) { - let name = generateBandName(i); - let attempts = 0; - while (usedNames.has(name) && attempts < 10) { - name = generateBandName(i + attempts * 7); - attempts++; - } - usedNames.add(name); - - const genre = pick(genres); - const sub_genre = pick(subGenresByGenre[genre]); - const tier = pick(tiers); - const popularity = tier === "headliner" ? range(80, 100) - : tier === "mid" ? range(40, 79) - : range(10, 39); - const ticket_impact = tier === "headliner" ? range(25, 60) - : tier === "mid" ? range(5, 25) - : 0; - - bands.push({ - name, - genre, - sub_genre, - stage: pick(stages), - day: pick(days), - start_time: pick(timeSlots), - duration_min: tier === "headliner" ? range(75, 120) - : tier === "mid" ? range(45, 75) - : range(30, 45), - origin_city: pick(cities), - members: generateMembers(), - bio: generateBio(name), - tier, - popularity, - ticket_impact, - }); - } - - console.log("Schrijven naar Supabase in batches van 100..."); - - // Supabase insert in batches (single call van 500 kan timeouten) - for (let i = 0; i < bands.length; i += 100) { - const batch = bands.slice(i, i + 100); - const { error } = await supabase.from("bands").insert(batch); - if (error) { - console.error("Insert error op batch", i / 100, ":", error.message); - process.exit(1); - } - console.log(` ✓ ${i + batch.length}/${bands.length}`); - } - - console.log("Klaar! 500 Polderfest bands staan in Supabase."); -} - -runSeed().catch((e) => { - console.error(e); - process.exit(1); -}); diff --git a/Les11-AI-SDK/polderfest-demo b/Les11-AI-SDK/polderfest-demo deleted file mode 160000 index ac06b4d..0000000 --- a/Les11-AI-SDK/polderfest-demo +++ /dev/null @@ -1 +0,0 @@ -Subproject commit ac06b4d59e9738cde12a1cb4ec3816318695a6df diff --git a/Les11-AI-SDK/polderfest-demo.zip b/Les11-AI-SDK/polderfest-demo.zip deleted file mode 100644 index 7c2a9e4..0000000 Binary files a/Les11-AI-SDK/polderfest-demo.zip and /dev/null differ diff --git a/Les12-Tool-Calling/lesbestanden/code-snippets.zip b/Les12-Tool-Calling/lesbestanden/code-snippets.zip new file mode 100644 index 0000000..d9b0c64 Binary files /dev/null and b/Les12-Tool-Calling/lesbestanden/code-snippets.zip differ diff --git a/Les12-Tool-Calling/lesbestanden/polderfest-starter.zip b/Les12-Tool-Calling/lesbestanden/polderfest-starter.zip new file mode 100644 index 0000000..e34f925 Binary files /dev/null and b/Les12-Tool-Calling/lesbestanden/polderfest-starter.zip differ diff --git a/Les12-Tool-Calling/lesbestanden/polderfest-tools-finished.zip b/Les12-Tool-Calling/lesbestanden/polderfest-tools-finished.zip new file mode 100644 index 0000000..86b5ee7 Binary files /dev/null and b/Les12-Tool-Calling/lesbestanden/polderfest-tools-finished.zip differ diff --git a/Les12-Tool-Calling/polderfest-demo/.gitignore b/Les12-Tool-Calling/polderfest-demo/.gitignore deleted file mode 100644 index 5ef6a52..0000000 --- a/Les12-Tool-Calling/polderfest-demo/.gitignore +++ /dev/null @@ -1,41 +0,0 @@ -# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. - -# dependencies -/node_modules -/.pnp -.pnp.* -.yarn/* -!.yarn/patches -!.yarn/plugins -!.yarn/releases -!.yarn/versions - -# testing -/coverage - -# next.js -/.next/ -/out/ - -# production -/build - -# misc -.DS_Store -*.pem - -# debug -npm-debug.log* -yarn-debug.log* -yarn-error.log* -.pnpm-debug.log* - -# env files (can opt-in for committing if needed) -.env* - -# vercel -.vercel - -# typescript -*.tsbuildinfo -next-env.d.ts diff --git a/Les12-Tool-Calling/polderfest-demo/AGENTS.md b/Les12-Tool-Calling/polderfest-demo/AGENTS.md deleted file mode 100644 index 8bd0e39..0000000 --- a/Les12-Tool-Calling/polderfest-demo/AGENTS.md +++ /dev/null @@ -1,5 +0,0 @@ -<!-- BEGIN:nextjs-agent-rules --> -# This is NOT the Next.js you know - -This version has breaking changes — APIs, conventions, and file structure may all differ from your training data. Read the relevant guide in `node_modules/next/dist/docs/` before writing any code. Heed deprecation notices. -<!-- END:nextjs-agent-rules --> diff --git a/Les12-Tool-Calling/polderfest-demo/CLAUDE.md b/Les12-Tool-Calling/polderfest-demo/CLAUDE.md deleted file mode 100644 index 43c994c..0000000 --- a/Les12-Tool-Calling/polderfest-demo/CLAUDE.md +++ /dev/null @@ -1 +0,0 @@ -@AGENTS.md diff --git a/Les12-Tool-Calling/polderfest-demo/README.md b/Les12-Tool-Calling/polderfest-demo/README.md deleted file mode 100644 index de6e0d5..0000000 --- a/Les12-Tool-Calling/polderfest-demo/README.md +++ /dev/null @@ -1,57 +0,0 @@ -# Polderfest demo — Les 12 startpunt - -Kopie van de werkende Les 11 demo. **Startpunt** voor Les 12 — Tool Calling. - -## Wat zit hier al in? - -- Next.js 16 + TypeScript + Tailwind -- Supabase client (`lib/supabase.ts` voor client, `lib/supabase-admin.ts` voor service-role) -- Chat-route met **context-all** aanpak (`app/api/chat/route.ts`): - - Haalt alle 500 bands op - - Stuurt mee als tekst in system prompt - - `streamText` → `toUIMessageStreamResponse()` -- Chat-pagina met `useChat` van `@ai-sdk/react` (`app/page.tsx`) -- Seed script (`scripts/seed-polderfest.ts`) -- `AGENTS.md` met project context - -## Wat doen we in Les 12? - -We refactoren `app/api/chat/route.ts` van **context-all** naar **Tool Calling**: - -- Weg met de hele context-string -- Tools definiëren — `searchBands`, `getStats`, `getBandByName`, ... -- `stopWhen: stepCountIs(5)` voor multi-step -- System prompt aanpassen: "gebruik tools, verzin niet" -- UI uitbreiden om tool-invocations te tonen - -## Setup - -```bash -# 1. Dependencies installeren -npm install - -# 2. .env.local maken -cp .env.local.example .env.local -# Vul je eigen Supabase + OpenAI keys in - -# 3. Supabase schema (als nog niet gedaan) -# Open Supabase → SQL Editor → run schema.sql uit Les 11 - -# 4. Seed (als nog niet gedaan) -npx tsx scripts/seed-polderfest.ts - -# 5. Dev server -npm run dev -``` - -Open `http://localhost:3000` voor de chat. - -## Stack-versies in dit project - -- `ai` v6 — gebruikt nieuwere API: - - `UIMessage` type - - `convertToModelMessages()` - - `toUIMessageStreamResponse()` -- `@ai-sdk/react` v3 — `useChat` returnt `{ messages, sendMessage, status }` -- `@ai-sdk/openai` v3 -- Tool API (v6): gebruikt `inputSchema` (was `parameters`) en `stopWhen` (was `maxSteps`) diff --git a/Les12-Tool-Calling/polderfest-demo/app/api/chat/route.ts b/Les12-Tool-Calling/polderfest-demo/app/api/chat/route.ts deleted file mode 100644 index fae429a..0000000 --- a/Les12-Tool-Calling/polderfest-demo/app/api/chat/route.ts +++ /dev/null @@ -1,97 +0,0 @@ -/** - * Polderfest 2027 — chat API route - * -------------------------------------------------- - * Les 11 — Vercel AI SDK + Supabase context. - * Plaats dit bestand op: app/api/chat/route.ts - * - * Werking: - * 1. Haal alle bands op uit Supabase - * 2. Formatteer als tekst-context - * 3. Stuur naar OpenAI via streamText + system prompt - * 4. Return een stream voor useChat - * - * Vereist: - * - NEXT_PUBLIC_SUPABASE_URL en NEXT_PUBLIC_SUPABASE_ANON_KEY in .env.local - * - OPENAI_API_KEY in .env.local - * - npm i ai @ai-sdk/openai @supabase/supabase-js - */ - -import { convertToModelMessages, streamText, type UIMessage } from "ai"; -import { openai } from "@ai-sdk/openai"; -import { createClient } from "@supabase/supabase-js"; - -const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL; -const supabaseKey = - process.env.SUPABASE_SERVICE_ROLE_KEY ?? - process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY; - -if (!supabaseUrl) { - throw new Error("Missing env: NEXT_PUBLIC_SUPABASE_URL"); -} -if (!supabaseKey) { - throw new Error( - "Missing env: SUPABASE_SERVICE_ROLE_KEY (preferred) or NEXT_PUBLIC_SUPABASE_ANON_KEY", - ); -} - -const supabase = createClient(supabaseUrl, supabaseKey); - -export async function POST(req: Request) { - try { - const { messages }: { messages: UIMessage[] } = await req.json(); - - // 1. Haal alle bands op uit Supabase - const { data: bands, error } = await supabase.from("bands").select("*"); - if (error) { - return Response.json( - { error: "Supabase query failed", details: error.message }, - { status: 500 }, - ); - } - - // 2. Format bands als context-string - const context = (bands ?? []) - .map( - (b) => - `- ${b.name} (${b.genre}, ${b.tier}, ${b.day} ${b.start_time} ` + - `op ${b.stage}, uit ${b.origin_city}), populariteit: ${b.popularity}`, - ) - .join("\n"); - - // 3. System prompt met context - const system = `Je bent een festival-assistent voor Polderfest 2027. -Hier zijn alle bands die op het festival spelen: - -${context} - -Beantwoord vragen van bezoekers over de line-up. Verzin niets — gebruik -alleen bovenstaande data. Antwoord in het Nederlands. Wees beknopt. Geef puur antwoord op de gestelde vraag en voeg geen extra informatie toe. - -Zodra iemand iets vraagt over het schema. Geef dan altijd een volledig schema terug met band, stage en start en eind tijd. Sorteer op start tijd. - -Wanneer een band speelt op bijvoorbeeld vrijdagavond, geef hem dan niet weer als iemand vraagt om de bands van zaterdag. - -Regels: -- Zaterdag start om 16:00 -`; - - // 4. Stream naar OpenAI - const result = streamText({ - model: openai('gpt-5.2'), - system, - messages: await convertToModelMessages(messages), - }); - - return result.toUIMessageStreamResponse({ - onError(error: unknown) { - if (error == null) return "unknown error"; - if (typeof error === "string") return error; - if (error instanceof Error) return error.message; - return JSON.stringify(error); - }, - }); - } catch (err) { - const message = err instanceof Error ? err.message : "Unknown error"; - return Response.json({ error: "Chat route failed", details: message }, { status: 500 }); - } -} diff --git a/Les12-Tool-Calling/polderfest-demo/app/favicon.ico b/Les12-Tool-Calling/polderfest-demo/app/favicon.ico deleted file mode 100644 index 718d6fe..0000000 Binary files a/Les12-Tool-Calling/polderfest-demo/app/favicon.ico and /dev/null differ diff --git a/Les12-Tool-Calling/polderfest-demo/app/globals.css b/Les12-Tool-Calling/polderfest-demo/app/globals.css deleted file mode 100644 index a2dc41e..0000000 --- a/Les12-Tool-Calling/polderfest-demo/app/globals.css +++ /dev/null @@ -1,26 +0,0 @@ -@import "tailwindcss"; - -:root { - --background: #ffffff; - --foreground: #171717; -} - -@theme inline { - --color-background: var(--background); - --color-foreground: var(--foreground); - --font-sans: var(--font-geist-sans); - --font-mono: var(--font-geist-mono); -} - -@media (prefers-color-scheme: dark) { - :root { - --background: #0a0a0a; - --foreground: #ededed; - } -} - -body { - background: var(--background); - color: var(--foreground); - font-family: Arial, Helvetica, sans-serif; -} diff --git a/Les12-Tool-Calling/polderfest-demo/app/layout.tsx b/Les12-Tool-Calling/polderfest-demo/app/layout.tsx deleted file mode 100644 index 976eb90..0000000 --- a/Les12-Tool-Calling/polderfest-demo/app/layout.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import type { Metadata } from "next"; -import { Geist, Geist_Mono } from "next/font/google"; -import "./globals.css"; - -const geistSans = Geist({ - variable: "--font-geist-sans", - subsets: ["latin"], -}); - -const geistMono = Geist_Mono({ - variable: "--font-geist-mono", - subsets: ["latin"], -}); - -export const metadata: Metadata = { - title: "Create Next App", - description: "Generated by create next app", -}; - -export default function RootLayout({ - children, -}: Readonly<{ - children: React.ReactNode; -}>) { - return ( - <html - lang="en" - className={`${geistSans.variable} ${geistMono.variable} h-full antialiased`} - > - <body className="min-h-full flex flex-col">{children}</body> - </html> - ); -} diff --git a/Les12-Tool-Calling/polderfest-demo/app/page.tsx b/Les12-Tool-Calling/polderfest-demo/app/page.tsx deleted file mode 100644 index 329a1b7..0000000 --- a/Les12-Tool-Calling/polderfest-demo/app/page.tsx +++ /dev/null @@ -1,89 +0,0 @@ -/** - * Polderfest 2027 — chat pagina - * -------------------------------------------------- - * Les 11 — useChat hook + Tailwind chat UI. - * Plaats dit bestand op: app/chat/page.tsx - * - * Werking: - * - useChat() regelt messages, input, submit-handler, streaming - * - Praat met /api/chat (de route.ts) - * - Disabled tijdens streaming - * - * Vereist: - * - app/api/chat/route.ts (zie route.ts) - * - npm i ai - * - Tailwind aanwezig in project (standaard in create-next-app) - */ - -"use client"; - -import { useState } from "react"; -import { useChat } from "@ai-sdk/react"; - -export default function ChatPage() { - const { messages, sendMessage, status } = useChat(); - const [input, setInput] = useState(""); - - return ( - <main className="max-w-2xl mx-auto p-6 flex flex-col h-screen"> - <div className="flex items-center justify-between gap-3 mb-4"> - <h1 className="text-2xl font-bold">Polderfest 2027 — vraag de AI</h1> - <a - href="/supabase" - className="text-sm px-3 py-2 rounded-lg border hover:bg-gray-50" - > - Supabase test - </a> - </div> - - <div className="flex-1 overflow-y-auto space-y-4 mb-4"> - {messages.map((m) => ( - <div - key={m.id} - className={ - m.role === "user" - ? "bg-blue-50 p-3 rounded-lg ml-12" - : "bg-gray-50 p-3 rounded-lg mr-12" - } - > - <div className="font-medium text-sm text-gray-500 mb-1"> - {m.role === "user" ? "Jij" : "Festival AI"} - </div> - <div className="whitespace-pre-wrap"> - {m.parts - .filter((p) => p.type === "text") - .map((p) => p.text) - .join("")} - </div> - </div> - ))} - </div> - - <form - onSubmit={(e) => { - e.preventDefault(); - const text = input.trim(); - if (!text || status !== "ready") return; - setInput(""); - void sendMessage({ text }); - }} - className="flex gap-2" - > - <input - value={input} - onChange={(e) => setInput(e.target.value)} - placeholder="Stel een vraag over de line-up..." - className="flex-1 p-3 border rounded-lg" - disabled={status !== "ready"} - /> - <button - type="submit" - disabled={status !== "ready"} - className="px-6 py-3 bg-blue-600 text-white rounded-lg disabled:opacity-50" - > - Stuur - </button> - </form> - </main> - ); -} diff --git a/Les12-Tool-Calling/polderfest-demo/app/supabase/page.tsx b/Les12-Tool-Calling/polderfest-demo/app/supabase/page.tsx deleted file mode 100644 index 48f1a1d..0000000 --- a/Les12-Tool-Calling/polderfest-demo/app/supabase/page.tsx +++ /dev/null @@ -1,61 +0,0 @@ -import { supabaseAdmin } from "@/lib/supabase-admin"; - -type Band = { - id: number; - name: string; - genre: string; - stage: string; - day: string; - start_time: string; -}; - -export default async function SupabasePage() { - const { data, error } = await supabaseAdmin - .from("bands") - .select("id,name,genre,stage,day,start_time") - .order("popularity", { ascending: false }) - .limit(10); - - return ( - <main className="max-w-3xl mx-auto p-6 space-y-6"> - <header className="space-y-1"> - <h1 className="text-2xl font-bold">Supabase verbinding</h1> - <p className="text-sm text-gray-600"> - Dit is een Server Component die met de service role key de top 10 bands - uit de <code className="px-1 py-0.5 bg-gray-100 rounded">bands</code>{" "} - tabel ophaalt. - </p> - </header> - - {error ? ( - <div className="p-4 border border-red-200 bg-red-50 rounded-lg"> - <div className="font-medium text-red-800"> - Query faalde: {error.message} - </div> - <div className="text-sm text-red-700 mt-2"> - Check of de <code className="px-1 py-0.5 bg-white/70 rounded">bands</code>{" "} - tabel bestaat en of je <code className="px-1 py-0.5 bg-white/70 rounded">SUPABASE_SERVICE_ROLE_KEY</code>{" "} - klopt. - </div> - </div> - ) : ( - <ul className="divide-y border rounded-lg overflow-hidden"> - {(data as Band[] | null)?.map((b) => ( - <li key={b.id} className="p-4 flex items-start justify-between gap-4"> - <div className="min-w-0"> - <div className="font-semibold truncate">{b.name}</div> - <div className="text-sm text-gray-600"> - {b.genre} • {b.stage} - </div> - </div> - <div className="shrink-0 text-sm text-gray-700"> - {b.day} {b.start_time} - </div> - </li> - ))} - </ul> - )} - </main> - ); -} - diff --git a/Les12-Tool-Calling/polderfest-demo/eslint.config.mjs b/Les12-Tool-Calling/polderfest-demo/eslint.config.mjs deleted file mode 100644 index 05e726d..0000000 --- a/Les12-Tool-Calling/polderfest-demo/eslint.config.mjs +++ /dev/null @@ -1,18 +0,0 @@ -import { defineConfig, globalIgnores } from "eslint/config"; -import nextVitals from "eslint-config-next/core-web-vitals"; -import nextTs from "eslint-config-next/typescript"; - -const eslintConfig = defineConfig([ - ...nextVitals, - ...nextTs, - // Override default ignores of eslint-config-next. - globalIgnores([ - // Default ignores of eslint-config-next: - ".next/**", - "out/**", - "build/**", - "next-env.d.ts", - ]), -]); - -export default eslintConfig; diff --git a/Les12-Tool-Calling/polderfest-demo/lib/supabase-admin.ts b/Les12-Tool-Calling/polderfest-demo/lib/supabase-admin.ts deleted file mode 100644 index 1dc197c..0000000 --- a/Les12-Tool-Calling/polderfest-demo/lib/supabase-admin.ts +++ /dev/null @@ -1,19 +0,0 @@ -import "server-only"; - -import { createClient } from "@supabase/supabase-js"; - -const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL; -const supabaseServiceRoleKey = process.env.SUPABASE_SERVICE_ROLE_KEY; - -if (!supabaseUrl) { - throw new Error("Missing env var: NEXT_PUBLIC_SUPABASE_URL"); -} - -if (!supabaseServiceRoleKey) { - throw new Error("Missing env var: SUPABASE_SERVICE_ROLE_KEY"); -} - -export const supabaseAdmin = createClient(supabaseUrl, supabaseServiceRoleKey, { - auth: { persistSession: false }, -}); - diff --git a/Les12-Tool-Calling/polderfest-demo/lib/supabase.ts b/Les12-Tool-Calling/polderfest-demo/lib/supabase.ts deleted file mode 100644 index 15a8e7e..0000000 --- a/Les12-Tool-Calling/polderfest-demo/lib/supabase.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { createClient } from '@supabase/supabase-js' - -const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL! -const supabaseAnonKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY! - -export const supabase = createClient(supabaseUrl, supabaseAnonKey) diff --git a/Les12-Tool-Calling/polderfest-demo/lib/supabase/client.ts b/Les12-Tool-Calling/polderfest-demo/lib/supabase/client.ts deleted file mode 100644 index d66e5ea..0000000 --- a/Les12-Tool-Calling/polderfest-demo/lib/supabase/client.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { createBrowserClient } from '@supabase/ssr' - -export function createClient() { - return createBrowserClient( - process.env.NEXT_PUBLIC_SUPABASE_URL!, - process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY! - ) -} \ No newline at end of file diff --git a/Les12-Tool-Calling/polderfest-demo/lib/supabase/server.ts b/Les12-Tool-Calling/polderfest-demo/lib/supabase/server.ts deleted file mode 100644 index 88c6b92..0000000 --- a/Les12-Tool-Calling/polderfest-demo/lib/supabase/server.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { createServerClient } from '@supabase/ssr' -import { cookies } from 'next/headers' - -export async function createClient() { - const cookieStore = await cookies() - - return createServerClient( - process.env.NEXT_PUBLIC_SUPABASE_URL!, - process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!, - { - cookies: { - getAll() { - return cookieStore.getAll() - }, - setAll(cookiesToSet) { - cookiesToSet.forEach(({ name, value, options }) => - cookieStore.set(name, value, options) - ) - }, - }, - } - ) -} \ No newline at end of file diff --git a/Les12-Tool-Calling/polderfest-demo/next.config.ts b/Les12-Tool-Calling/polderfest-demo/next.config.ts deleted file mode 100644 index e9ffa30..0000000 --- a/Les12-Tool-Calling/polderfest-demo/next.config.ts +++ /dev/null @@ -1,7 +0,0 @@ -import type { NextConfig } from "next"; - -const nextConfig: NextConfig = { - /* config options here */ -}; - -export default nextConfig; diff --git a/Les12-Tool-Calling/polderfest-demo/package-lock.json b/Les12-Tool-Calling/polderfest-demo/package-lock.json deleted file mode 100644 index 8b058e6..0000000 --- a/Les12-Tool-Calling/polderfest-demo/package-lock.json +++ /dev/null @@ -1,6963 +0,0 @@ -{ - "name": "polderfest-demo", - "version": "0.1.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "polderfest-demo", - "version": "0.1.0", - "dependencies": { - "@ai-sdk/openai": "^3.0.64", - "@ai-sdk/react": "^3.0.187", - "@supabase/supabase-js": "^2.106.0", - "ai": "^6.0.185", - "dotenv": "^17.4.2", - "next": "16.2.6", - "react": "19.2.4", - "react-dom": "19.2.4", - "zod": "^4.4.3" - }, - "devDependencies": { - "@tailwindcss/postcss": "^4", - "@types/node": "^20", - "@types/react": "^19", - "@types/react-dom": "^19", - "eslint": "^9", - "eslint-config-next": "16.2.6", - "tailwindcss": "^4", - "tsx": "^4.22.3", - "typescript": "^5" - } - }, - "node_modules/@ai-sdk/gateway": { - "version": "3.0.116", - "resolved": "https://registry.npmjs.org/@ai-sdk/gateway/-/gateway-3.0.116.tgz", - "integrity": "sha512-k8P17w7Eho5Y4l3tZrYxqQdffkI4xwtl8GCxkZs+JdMWZhyrLLlozqWkKLaWrCSlEYQOeIhEnQLhqQgYYU86Rw==", - "dependencies": { - "@ai-sdk/provider": "3.0.10", - "@ai-sdk/provider-utils": "4.0.27", - "@vercel/oidc": "3.2.0" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "zod": "^3.25.76 || ^4.1.8" - } - }, - "node_modules/@ai-sdk/openai": { - "version": "3.0.64", - "resolved": "https://registry.npmjs.org/@ai-sdk/openai/-/openai-3.0.64.tgz", - "integrity": "sha512-epO4iS6QwktaY2PF6uBcPnDTJ3BxPOfsGS7/OEtBe3GtNj7C8h8gMDVtIe5K8W16HNDbn0tbR4dcQfpfs+XVFg==", - "dependencies": { - "@ai-sdk/provider": "3.0.10", - "@ai-sdk/provider-utils": "4.0.27" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "zod": "^3.25.76 || ^4.1.8" - } - }, - "node_modules/@ai-sdk/provider": { - "version": "3.0.10", - "resolved": "https://registry.npmjs.org/@ai-sdk/provider/-/provider-3.0.10.tgz", - "integrity": "sha512-Q3BZ27qfpYqnCYGvE3vt+Qi6LGOF9R5Nmzn+9JoM1lCRsD9mYaIhfJLkSunN48nfGXJ6n+XNV0J/XVpqGQl7Dw==", - "dependencies": { - "json-schema": "^0.4.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@ai-sdk/provider-utils": { - "version": "4.0.27", - "resolved": "https://registry.npmjs.org/@ai-sdk/provider-utils/-/provider-utils-4.0.27.tgz", - "integrity": "sha512-ubkAJ+xODouwtmN1tYlvTPphH1hPOBfZaEQe8U7skGvFAnIRs9PPpsq57bC2+Ky/MB4yzhd6YOsxTAx9sGpazw==", - "dependencies": { - "@ai-sdk/provider": "3.0.10", - "@standard-schema/spec": "^1.1.0", - "eventsource-parser": "^3.0.8" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "zod": "^3.25.76 || ^4.1.8" - } - }, - "node_modules/@ai-sdk/react": { - "version": "3.0.187", - "resolved": "https://registry.npmjs.org/@ai-sdk/react/-/react-3.0.187.tgz", - "integrity": "sha512-TJBhR18F7BOLj/mBLYoZNZVkQgDc7DBVz2ZyQEecpKnO+EAhdx3QA2q8BnEVqwNlDfOKOa6dr7ka4hU0wy/wDw==", - "dependencies": { - "@ai-sdk/provider-utils": "4.0.27", - "ai": "6.0.185", - "swr": "^2.2.5", - "throttleit": "2.1.0" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "react": "^18 || ~19.0.1 || ~19.1.2 || ^19.2.1" - } - }, - "node_modules/@alloc/quick-lru": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", - "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@babel/code-frame": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", - "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", - "dev": true, - "dependencies": { - "@babel/helper-validator-identifier": "^7.28.5", - "js-tokens": "^4.0.0", - "picocolors": "^1.1.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/compat-data": { - "version": "7.29.3", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.3.tgz", - "integrity": "sha512-LIVqM46zQWZhj17qA8wb4nW/ixr2y1Nw+r1etiAWgRM6U1IqP+LNhL1yg440jYZR72jCWcWbLWzIosH+uP1fqg==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/core": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz", - "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.29.0", - "@babel/generator": "^7.29.0", - "@babel/helper-compilation-targets": "^7.28.6", - "@babel/helper-module-transforms": "^7.28.6", - "@babel/helpers": "^7.28.6", - "@babel/parser": "^7.29.0", - "@babel/template": "^7.28.6", - "@babel/traverse": "^7.29.0", - "@babel/types": "^7.29.0", - "@jridgewell/remapping": "^2.3.5", - "convert-source-map": "^2.0.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.3", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@babel/generator": { - "version": "7.29.1", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz", - "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", - "dev": true, - "dependencies": { - "@babel/parser": "^7.29.0", - "@babel/types": "^7.29.0", - "@jridgewell/gen-mapping": "^0.3.12", - "@jridgewell/trace-mapping": "^0.3.28", - "jsesc": "^3.0.2" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz", - "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==", - "dev": true, - "dependencies": { - "@babel/compat-data": "^7.28.6", - "@babel/helper-validator-option": "^7.27.1", - "browserslist": "^4.24.0", - "lru-cache": "^5.1.1", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-globals": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", - "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-imports": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz", - "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==", - "dev": true, - "dependencies": { - "@babel/traverse": "^7.28.6", - "@babel/types": "^7.28.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz", - "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==", - "dev": true, - "dependencies": { - "@babel/helper-module-imports": "^7.28.6", - "@babel/helper-validator-identifier": "^7.28.5", - "@babel/traverse": "^7.28.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-string-parser": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", - "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", - "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-option": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", - "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers": { - "version": "7.29.2", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.2.tgz", - "integrity": "sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw==", - "dev": true, - "dependencies": { - "@babel/template": "^7.28.6", - "@babel/types": "^7.29.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/parser": { - "version": "7.29.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.3.tgz", - "integrity": "sha512-b3ctpQwp+PROvU/cttc4OYl4MzfJUWy6FZg+PMXfzmt/+39iHVF0sDfqay8TQM3JA2EUOyKcFZt75jWriQijsA==", - "dev": true, - "dependencies": { - "@babel/types": "^7.29.0" - }, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/template": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", - "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.28.6", - "@babel/parser": "^7.28.6", - "@babel/types": "^7.28.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz", - "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.29.0", - "@babel/generator": "^7.29.0", - "@babel/helper-globals": "^7.28.0", - "@babel/parser": "^7.29.0", - "@babel/template": "^7.28.6", - "@babel/types": "^7.29.0", - "debug": "^4.3.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/types": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", - "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", - "dev": true, - "dependencies": { - "@babel/helper-string-parser": "^7.27.1", - "@babel/helper-validator-identifier": "^7.28.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@emnapi/core": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz", - "integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==", - "dev": true, - "optional": true, - "dependencies": { - "@emnapi/wasi-threads": "1.2.1", - "tslib": "^2.4.0" - } - }, - "node_modules/@emnapi/runtime": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz", - "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@emnapi/wasi-threads": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz", - "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==", - "dev": true, - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@esbuild/aix-ppc64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.0.tgz", - "integrity": "sha512-lhRUCeuOyJQURhTxl4WkpFTjIsbDayJHih5kZC1giwE+MhIzAb7mEsQMqMf18rHLsrb5qI1tafG20mLxEWcWlA==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-arm": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.0.tgz", - "integrity": "sha512-wqh0ByljabXLKHeWXYLqoJ5jKC4XBaw6Hk08OfMrCRd2nP2ZQ5eleDZC41XHyCNgktBGYMbqnrJKq/K/lzPMSQ==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-arm64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.0.tgz", - "integrity": "sha512-+WzIXQOSaGs33tLEgYPYe/yQHf0WTU0X42Jca3y8NWMbUVhp7rUnw+vAsRC/QiDrdD31IszMrZy+qwPOPjd+rw==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-x64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.0.tgz", - "integrity": "sha512-+VJggoaKhk2VNNqVL7f6S189UzShHC/mR9EE8rDdSkdpN0KflSwWY/gWjDrNxxisg8Fp1ZCD9jLMo4m0OUfeUA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.0.tgz", - "integrity": "sha512-0T+A9WZm+bZ84nZBtk1ckYsOvyA3x7e2Acj1KdVfV4/2tdG4fzUp91YHx+GArWLtwqp77pBXVCPn2We7Letr0Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.0.tgz", - "integrity": "sha512-fyzLm/DLDl/84OCfp2f/XQ4flmORsjU7VKt8HLjvIXChJoFFOIL6pLJPH4Yhd1n1gGFF9mPwtlN5Wf82DZs+LQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.0.tgz", - "integrity": "sha512-l9GeW5UZBT9k9brBYI+0WDffcRxgHQD8ShN2Ur4xWq/NFzUKm3k5lsH4PdaRgb2w7mI9u61nr2gI2mLI27Nh3Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.0.tgz", - "integrity": "sha512-BXoQai/A0wPO6Es3yFJ7APCiKGc1tdAEOgeTNy3SsB491S3aHn4S4r3e976eUnPdU+NbdtmBuLncYir2tMU9Nw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-arm": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.0.tgz", - "integrity": "sha512-CjaaREJagqJp7iTaNQjjidaNbCKYcd4IDkzbwwxtSvjI7NZm79qiHc8HqciMddQ6CKvJT6aBd8lO9kN/ZudLlw==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.0.tgz", - "integrity": "sha512-RVyzfb3FWsGA55n6WY0MEIEPURL1FcbhFE6BffZEMEekfCzCIMtB5yyDcFnVbTnwk+CLAgTujmV/Lgvih56W+A==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.0.tgz", - "integrity": "sha512-KBnSTt1kxl9x70q+ydterVdl+Cn0H18ngRMRCEQfrbqdUuntQQ0LoMZv47uB97NljZFzY6HcfqEZ2SAyIUTQBQ==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.0.tgz", - "integrity": "sha512-zpSlUce1mnxzgBADvxKXX5sl8aYQHo2ezvMNI8I0lbblJtp8V4odlm3Yzlj7gPyt3T8ReksE6bK+pT3WD+aJRg==", - "cpu": [ - "loong64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.0.tgz", - "integrity": "sha512-2jIfP6mmjkdmeTlsX/9vmdmhBmKADrWqN7zcdtHIeNSCH1SqIoNI63cYsjQR8J+wGa4Y5izRcSHSm8K3QWmk3w==", - "cpu": [ - "mips64el" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.0.tgz", - "integrity": "sha512-bc0FE9wWeC0WBm49IQMPSPILRocGTQt3j5KPCA8os6VprfuJ7KD+5PzESSrJ6GmPIPJK965ZJHTUlSA6GNYEhg==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.0.tgz", - "integrity": "sha512-SQPZOwoTTT/HXFXQJG/vBX8sOFagGqvZyXcgLA3NhIqcBv1BJU1d46c0rGcrij2B56Z2rNiSLaZOYW5cUk7yLQ==", - "cpu": [ - "riscv64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.0.tgz", - "integrity": "sha512-SCfR0HN8CEEjnYnySJTd2cw0k9OHB/YFzt5zgJEwa+wL/T/raGWYMBqwDNAC6dqFKmJYZoQBRfHjgwLHGSrn3Q==", - "cpu": [ - "s390x" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-x64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.0.tgz", - "integrity": "sha512-us0dSb9iFxIi8srnpl931Nvs65it/Jd2a2K3qs7fz2WfGPHqzfzZTfec7oxZJRNPXPnNYZtanmRc4AL/JwVzHQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-arm64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.0.tgz", - "integrity": "sha512-CR/RYotgtCKwtftMwJlUU7xCVNg3lMYZ0RzTmAHSfLCXw3NtZtNpswLEj/Kkf6kEL3Gw+BpOekRX0BYCtklhUw==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.0.tgz", - "integrity": "sha512-nU1yhmYutL+fQ71Kxnhg8uEOdC0pwEW9entHykTgEbna2pw2dkbFSMeqjjyHZoCmt8SBkOSvV+yNmm94aUrrqw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-arm64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.0.tgz", - "integrity": "sha512-cXb5vApOsRsxsEl4mcZ1XY3D4DzcoMxR/nnc4IyqYs0rTI8ZKmW6kyyg+11Z8yvgMfAEldKzP7AdP64HnSC/6g==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.0.tgz", - "integrity": "sha512-8wZM2qqtv9UP3mzy7HiGYNH/zjTA355mpeuA+859TyR+e+Tc08IHYpLJuMsfpDJwoLo1ikIJI8jC3GFjnRClzA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openharmony-arm64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.0.tgz", - "integrity": "sha512-FLGfyizszcef5C3YtoyQDACyg95+dndv79i2EekILBofh5wpCa1KuBqOWKrEHZg3zrL3t5ouE5jgr94vA+Wb2w==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "openharmony" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.0.tgz", - "integrity": "sha512-1ZgjUoEdHZZl/YlV76TSCz9Hqj9h9YmMGAgAPYd+q4SicWNX3G5GCyx9uhQWSLcbvPW8Ni7lj4gDa1T40akdlw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.0.tgz", - "integrity": "sha512-Q9StnDmQ/enxnpxCCLSg0oo4+34B9TdXpuyPeTedN/6+iXBJ4J+zwfQI28u/Jl40nOYAxGoNi7mFP40RUtkmUA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.0.tgz", - "integrity": "sha512-zF3ag/gfiCe6U2iczcRzSYJKH1DCI+ByzSENHlM2FcDbEeo5Zd2C86Aq0tKUYAJJ1obRP84ymxIAksZUcdztHA==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-x64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.0.tgz", - "integrity": "sha512-pEl1bO9mfAmIC+tW5btTmrKaujg3zGtUmWNdCw/xs70FBjwAL3o9OEKNHvNmnyylD6ubxUERiEhdsL0xBQ9efw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", - "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^3.4.3" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" - } - }, - "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint-community/regexpp": { - "version": "4.12.2", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", - "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", - "dev": true, - "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" - } - }, - "node_modules/@eslint/config-array": { - "version": "0.21.2", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.2.tgz", - "integrity": "sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw==", - "dev": true, - "dependencies": { - "@eslint/object-schema": "^2.1.7", - "debug": "^4.3.1", - "minimatch": "^3.1.5" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/config-helpers": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", - "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==", - "dev": true, - "dependencies": { - "@eslint/core": "^0.17.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/core": { - "version": "0.17.0", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz", - "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", - "dev": true, - "dependencies": { - "@types/json-schema": "^7.0.15" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/eslintrc": { - "version": "3.3.5", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.5.tgz", - "integrity": "sha512-4IlJx0X0qftVsN5E+/vGujTRIFtwuLbNsVUe7TO6zYPDR1O6nFwvwhIKEKSrl6dZchmYBITazxKoUYOjdtjlRg==", - "dev": true, - "dependencies": { - "ajv": "^6.14.0", - "debug": "^4.3.2", - "espree": "^10.0.1", - "globals": "^14.0.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.1", - "minimatch": "^3.1.5", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint/js": { - "version": "9.39.4", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.4.tgz", - "integrity": "sha512-nE7DEIchvtiFTwBw4Lfbu59PG+kCofhjsKaCWzxTpt4lfRjRMqG6uMBzKXuEcyXhOHoUp9riAm7/aWYGhXZ9cw==", - "dev": true, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://eslint.org/donate" - } - }, - "node_modules/@eslint/object-schema": { - "version": "2.1.7", - "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz", - "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", - "dev": true, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/plugin-kit": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz", - "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==", - "dev": true, - "dependencies": { - "@eslint/core": "^0.17.0", - "levn": "^0.4.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@humanfs/core": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.2.tgz", - "integrity": "sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==", - "dev": true, - "dependencies": { - "@humanfs/types": "^0.15.0" - }, - "engines": { - "node": ">=18.18.0" - } - }, - "node_modules/@humanfs/node": { - "version": "0.16.8", - "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.8.tgz", - "integrity": "sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==", - "dev": true, - "dependencies": { - "@humanfs/core": "^0.19.2", - "@humanfs/types": "^0.15.0", - "@humanwhocodes/retry": "^0.4.0" - }, - "engines": { - "node": ">=18.18.0" - } - }, - "node_modules/@humanfs/types": { - "version": "0.15.0", - "resolved": "https://registry.npmjs.org/@humanfs/types/-/types-0.15.0.tgz", - "integrity": "sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==", - "dev": true, - "engines": { - "node": ">=18.18.0" - } - }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true, - "engines": { - "node": ">=12.22" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@humanwhocodes/retry": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", - "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", - "dev": true, - "engines": { - "node": ">=18.18" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@img/colour": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.1.0.tgz", - "integrity": "sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==", - "optional": true, - "engines": { - "node": ">=18" - } - }, - "node_modules/@img/sharp-darwin-arm64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.5.tgz", - "integrity": "sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-darwin-arm64": "1.2.4" - } - }, - "node_modules/@img/sharp-darwin-x64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.5.tgz", - "integrity": "sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-darwin-x64": "1.2.4" - } - }, - "node_modules/@img/sharp-libvips-darwin-arm64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.4.tgz", - "integrity": "sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "darwin" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-darwin-x64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.4.tgz", - "integrity": "sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "darwin" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-arm": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.4.tgz", - "integrity": "sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==", - "cpu": [ - "arm" - ], - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-arm64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.4.tgz", - "integrity": "sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-ppc64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.4.tgz", - "integrity": "sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==", - "cpu": [ - "ppc64" - ], - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-riscv64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.2.4.tgz", - "integrity": "sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==", - "cpu": [ - "riscv64" - ], - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-s390x": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.4.tgz", - "integrity": "sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==", - "cpu": [ - "s390x" - ], - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-x64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.4.tgz", - "integrity": "sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linuxmusl-arm64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.4.tgz", - "integrity": "sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linuxmusl-x64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.4.tgz", - "integrity": "sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-linux-arm": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.5.tgz", - "integrity": "sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==", - "cpu": [ - "arm" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-arm": "1.2.4" - } - }, - "node_modules/@img/sharp-linux-arm64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.5.tgz", - "integrity": "sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-arm64": "1.2.4" - } - }, - "node_modules/@img/sharp-linux-ppc64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.5.tgz", - "integrity": "sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==", - "cpu": [ - "ppc64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-ppc64": "1.2.4" - } - }, - "node_modules/@img/sharp-linux-riscv64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.34.5.tgz", - "integrity": "sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==", - "cpu": [ - "riscv64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-riscv64": "1.2.4" - } - }, - "node_modules/@img/sharp-linux-s390x": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.5.tgz", - "integrity": "sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==", - "cpu": [ - "s390x" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-s390x": "1.2.4" - } - }, - "node_modules/@img/sharp-linux-x64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.5.tgz", - "integrity": "sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-x64": "1.2.4" - } - }, - "node_modules/@img/sharp-linuxmusl-arm64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.5.tgz", - "integrity": "sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-arm64": "1.2.4" - } - }, - "node_modules/@img/sharp-linuxmusl-x64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.5.tgz", - "integrity": "sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-x64": "1.2.4" - } - }, - "node_modules/@img/sharp-wasm32": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.5.tgz", - "integrity": "sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==", - "cpu": [ - "wasm32" - ], - "optional": true, - "dependencies": { - "@emnapi/runtime": "^1.7.0" - }, - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-win32-arm64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.5.tgz", - "integrity": "sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-win32-ia32": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.5.tgz", - "integrity": "sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==", - "cpu": [ - "ia32" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-win32-x64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.5.tgz", - "integrity": "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.13", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", - "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", - "dev": true, - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.0", - "@jridgewell/trace-mapping": "^0.3.24" - } - }, - "node_modules/@jridgewell/remapping": { - "version": "2.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", - "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", - "dev": true, - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "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, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", - "dev": true - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.31", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", - "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", - "dev": true, - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "node_modules/@napi-rs/wasm-runtime": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.4.tgz", - "integrity": "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==", - "dev": true, - "optional": true, - "dependencies": { - "@tybys/wasm-util": "^0.10.1" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Brooooooklyn" - }, - "peerDependencies": { - "@emnapi/core": "^1.7.1", - "@emnapi/runtime": "^1.7.1" - } - }, - "node_modules/@next/env": { - "version": "16.2.6", - "resolved": "https://registry.npmjs.org/@next/env/-/env-16.2.6.tgz", - "integrity": "sha512-gd8HoHN4ufj73WmR3JmVolrpJR47ILK6LouP5xElPglaVxir6e1a7VzvTvDWkOoPXT9rkkTzyCxBu4yeZfZwcw==" - }, - "node_modules/@next/eslint-plugin-next": { - "version": "16.2.6", - "resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-16.2.6.tgz", - "integrity": "sha512-Z8l6o4JWKUl755x4R+wogD86KPeU+Ckw4K+SYG4kHeOJtRenDeK+OSbGcqZpDtbwn9DsJVdir2UxmwXuinUbUw==", - "dev": true, - "dependencies": { - "fast-glob": "3.3.1" - } - }, - "node_modules/@next/swc-darwin-arm64": { - "version": "16.2.6", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.2.6.tgz", - "integrity": "sha512-ZJGkkcNfYgrrMkqOdZ7zoLa1TOy0qpcMfk/z4Mh/FKUz40gVO+HNQWqmLxf67Z5WB64DRp0dhEbyHfel+6sJUg==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-darwin-x64": { - "version": "16.2.6", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.2.6.tgz", - "integrity": "sha512-v/YLBHIY132Ced3puBJ7YJKw1lqsCrgcNo2aRJlCEyQrrCeRJlvGlnmxhPxNQI3KE3N1DN5r9TPNPvka3nq5RQ==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-linux-arm64-gnu": { - "version": "16.2.6", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.2.6.tgz", - "integrity": "sha512-RPOvqlYBbcQjkz9VQQDZ2T2bARIjXZV1KFlt+V2Mr6SW/e4I9fcKsaA0hdyf2FHoTlsV2xnBd5Y912rP/1Ce6w==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-linux-arm64-musl": { - "version": "16.2.6", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.2.6.tgz", - "integrity": "sha512-URUTu1+dMkxJsPFgm+OeEvq9wf5sujw0EvgYy80TDGHTSLTnIHeqb0Eu8A3sC95IRgjejQL+kC4mw+4yPxiAXA==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-linux-x64-gnu": { - "version": "16.2.6", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.2.6.tgz", - "integrity": "sha512-DOj182mPV8G3UkrayLoREM5YEYI+Dk5wv7Ox9xl1fFibAELEsFD0lDPfHIeILlutMMfdyhlzYPELG3peuKaurw==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-linux-x64-musl": { - "version": "16.2.6", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.2.6.tgz", - "integrity": "sha512-HKQ5SP/V/ub73UvF7n/zeJlxk2kLmtL7Wzrg4WfmkjmNos5onJ2tKu7yZOPdL18A6Svfn3max29ym+ry7NkK4g==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-win32-arm64-msvc": { - "version": "16.2.6", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.2.6.tgz", - "integrity": "sha512-LZXpTlPyS5v7HhSmnvsLGP3iIYgYOBnc8r8ArlT55sGHV89bR2HlDdBjWQ+PY6SJMmk8TuVGFuxalnP3k/0Dwg==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-win32-x64-msvc": { - "version": "16.2.6", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.2.6.tgz", - "integrity": "sha512-F0+4i0h9J6C4eE3EAPWsoCk7UW/dbzOjyzxY0qnDUOYFu6FFmdZ6l97/XdV3/Nz3VYyO7UWjyEJUXkGqcoXfMA==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nolyfill/is-core-module": { - "version": "1.0.39", - "resolved": "https://registry.npmjs.org/@nolyfill/is-core-module/-/is-core-module-1.0.39.tgz", - "integrity": "sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==", - "dev": true, - "engines": { - "node": ">=12.4.0" - } - }, - "node_modules/@opentelemetry/api": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.1.tgz", - "integrity": "sha512-gLyJlPHPZYdAk1JENA9LeHejZe1Ti77/pTeFm/nMXmQH/HFZlcS/O2XJB+L8fkbrNSqhdtlvjBVjxwUYanNH5Q==", - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/@rtsao/scc": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz", - "integrity": "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==", - "dev": true - }, - "node_modules/@standard-schema/spec": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", - "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==" - }, - "node_modules/@supabase/auth-js": { - "version": "2.106.0", - "resolved": "https://registry.npmjs.org/@supabase/auth-js/-/auth-js-2.106.0.tgz", - "integrity": "sha512-JY7602OvjK2l3BjsQkpePpxR+6P0iG37gCrZNWAMhAuNh1iFnhGRwj/y5EshUG0INMPGFrj0UA9MErQ/kOEKFg==", - "dependencies": { - "tslib": "2.8.1" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@supabase/functions-js": { - "version": "2.106.0", - "resolved": "https://registry.npmjs.org/@supabase/functions-js/-/functions-js-2.106.0.tgz", - "integrity": "sha512-ADIkJYH5w7HbnGVAAlCbyKoLF5QdfyezBLfYXpUqhxZOacK6YepOvnP/8p4p+50bhTPWp6VhDxu19KO7e/qU2g==", - "dependencies": { - "tslib": "2.8.1" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@supabase/phoenix": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/@supabase/phoenix/-/phoenix-0.4.2.tgz", - "integrity": "sha512-YSAGnmDAfuleFCVt3CeurQZAhxRfXWeZIIkwp7NhYzQ1UwW6ePSnzsFAiUm/mbCkfoCf70QQHKW/K6RKh52a4A==" - }, - "node_modules/@supabase/postgrest-js": { - "version": "2.106.0", - "resolved": "https://registry.npmjs.org/@supabase/postgrest-js/-/postgrest-js-2.106.0.tgz", - "integrity": "sha512-vNKFAXQrtmUn7J3LbN+uMlt0jciAwRIBpdy6Do4DKrpf1xj0kJhbqXTX4y8ziewWUEEx8G5GPnDmprXXaO9f3w==", - "dependencies": { - "tslib": "2.8.1" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@supabase/realtime-js": { - "version": "2.106.0", - "resolved": "https://registry.npmjs.org/@supabase/realtime-js/-/realtime-js-2.106.0.tgz", - "integrity": "sha512-mYZoaYpkyjlecixbvxCu0h3jw12uHfEcUqNdaRATNI8zQVI5arels+VJzAGcHwNiD+/Juv0OXIuk+M7SHsdI4A==", - "dependencies": { - "@supabase/phoenix": "^0.4.2", - "tslib": "2.8.1" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@supabase/storage-js": { - "version": "2.106.0", - "resolved": "https://registry.npmjs.org/@supabase/storage-js/-/storage-js-2.106.0.tgz", - "integrity": "sha512-BHc3nIjD3zfdDxBenphXrLJSoQ+qwo24VD96cVzmjBFbQVk5krvwRNUXrA5ozPplA3Vhlst2d/hy9R9ViqH2lg==", - "dependencies": { - "iceberg-js": "^0.8.1", - "tslib": "2.8.1" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@supabase/supabase-js": { - "version": "2.106.0", - "resolved": "https://registry.npmjs.org/@supabase/supabase-js/-/supabase-js-2.106.0.tgz", - "integrity": "sha512-OOoo3sLj9iVXNp6b+fkyOfFeQrvvNy7nQbaONNf72dOaictUeS39hFDS9argIRTag6M3ZxIypNWcrDAwLgUihQ==", - "dependencies": { - "@supabase/auth-js": "2.106.0", - "@supabase/functions-js": "2.106.0", - "@supabase/postgrest-js": "2.106.0", - "@supabase/realtime-js": "2.106.0", - "@supabase/storage-js": "2.106.0" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@swc/helpers": { - "version": "0.5.15", - "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz", - "integrity": "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==", - "dependencies": { - "tslib": "^2.8.0" - } - }, - "node_modules/@tailwindcss/node": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.3.0.tgz", - "integrity": "sha512-aFb4gUhFOgdh9AXo4IzBEOzBkkAxm9VigwDJnMIYv3lcfXCJVesNfbEaBl4BNgVRyid92AmdviqwBUBRKSeY3g==", - "dev": true, - "dependencies": { - "@jridgewell/remapping": "^2.3.5", - "enhanced-resolve": "^5.21.0", - "jiti": "^2.6.1", - "lightningcss": "1.32.0", - "magic-string": "^0.30.21", - "source-map-js": "^1.2.1", - "tailwindcss": "4.3.0" - } - }, - "node_modules/@tailwindcss/oxide": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.3.0.tgz", - "integrity": "sha512-F7HZGBeN9I0/AuuJS5PwcD8xayx5ri5GhjYUDBEVYUkexyA/giwbDNjRVrxSezE3T250OU2K/wp/ltWx3UOefg==", - "dev": true, - "engines": { - "node": ">= 20" - }, - "optionalDependencies": { - "@tailwindcss/oxide-android-arm64": "4.3.0", - "@tailwindcss/oxide-darwin-arm64": "4.3.0", - "@tailwindcss/oxide-darwin-x64": "4.3.0", - "@tailwindcss/oxide-freebsd-x64": "4.3.0", - "@tailwindcss/oxide-linux-arm-gnueabihf": "4.3.0", - "@tailwindcss/oxide-linux-arm64-gnu": "4.3.0", - "@tailwindcss/oxide-linux-arm64-musl": "4.3.0", - "@tailwindcss/oxide-linux-x64-gnu": "4.3.0", - "@tailwindcss/oxide-linux-x64-musl": "4.3.0", - "@tailwindcss/oxide-wasm32-wasi": "4.3.0", - "@tailwindcss/oxide-win32-arm64-msvc": "4.3.0", - "@tailwindcss/oxide-win32-x64-msvc": "4.3.0" - } - }, - "node_modules/@tailwindcss/oxide-android-arm64": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.3.0.tgz", - "integrity": "sha512-TJPiq67tKlLuObP6RkwvVGDoxCMBVtDgKkLfa/uyj7/FyxvQwHS+UOnVrXXgbEsfUaMgiVvC4KbJnRr26ho4Ng==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">= 20" - } - }, - "node_modules/@tailwindcss/oxide-darwin-arm64": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.3.0.tgz", - "integrity": "sha512-oMN/WZRb+SO37BmUElEgeEWuU8E/HXRkiODxJxLe1UTHVXLrdVSgfaJV7pSlhRGMSOiXLuxTIjfsF3wYvz8cgQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 20" - } - }, - "node_modules/@tailwindcss/oxide-darwin-x64": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.3.0.tgz", - "integrity": "sha512-N6CUmu4a6bKVADfw77p+iw6Yd9Q3OBhe0veaDX+QazfuVYlQsHfDgxBrsjQ/IW+zywL8mTrNd0SdJT/zgtvMdA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 20" - } - }, - "node_modules/@tailwindcss/oxide-freebsd-x64": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.3.0.tgz", - "integrity": "sha512-zDL5hBkQdH5C6MpqbK3gQAgP80tsMwSI26vjOzjJtNCMUo0lFgOItzHKBIupOZNQxt3ouPH7RPhvNhiTfCe5CQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">= 20" - } - }, - "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.3.0.tgz", - "integrity": "sha512-R06HdNi7A7OEoMsf6d4tjZ71RCWnZQPHj2mnotSFURjNLdBC+cIgXQ7l81CqeoiQftjf6OOblxXMInMgN2VzMA==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 20" - } - }, - "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.3.0.tgz", - "integrity": "sha512-qTJHELX8jetjhRQHCLilkVLmybpzNQAtaI/gaoVoidn/ufbNDbAo8KlK2J+yPoc8wQxvDxCmh/5lr8nC1+lTbg==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 20" - } - }, - "node_modules/@tailwindcss/oxide-linux-arm64-musl": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.3.0.tgz", - "integrity": "sha512-Z6sukiQsngnWO+l39X4pPbiWT81IC+PLKF+PHxIlyZbGNb9MODfYlXEVlFvej5BOZInWX01kVyzeLvHsXhfczQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 20" - } - }, - "node_modules/@tailwindcss/oxide-linux-x64-gnu": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.3.0.tgz", - "integrity": "sha512-DRNdQRpSGzRGfARVuVkxvM8Q12nh19l4BF/G7zGA1oe+9wcC6saFBHTISrpIcKzhiXtSrlSrluCfvMuledoCTQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 20" - } - }, - "node_modules/@tailwindcss/oxide-linux-x64-musl": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.3.0.tgz", - "integrity": "sha512-Z0IADbDo8bh6I7h2IQMx601AdXBLfFpEdUotft86evd/8ZPflZe9COPO8Q1vw+pfLWIUo9zN/JGZvwuAJqduqg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 20" - } - }, - "node_modules/@tailwindcss/oxide-wasm32-wasi": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.3.0.tgz", - "integrity": "sha512-HNZGOUxEmElksYR7S6sC5jTeNGpobAsy9u7Gu0AskJ8/20FR9GqebUyB+HBcU/ax6BHuiuJi+Oda4B+YX6H1yA==", - "bundleDependencies": [ - "@napi-rs/wasm-runtime", - "@emnapi/core", - "@emnapi/runtime", - "@tybys/wasm-util", - "@emnapi/wasi-threads", - "tslib" - ], - "cpu": [ - "wasm32" - ], - "dev": true, - "optional": true, - "dependencies": { - "@emnapi/core": "^1.10.0", - "@emnapi/runtime": "^1.10.0", - "@emnapi/wasi-threads": "^1.2.1", - "@napi-rs/wasm-runtime": "^1.1.4", - "@tybys/wasm-util": "^0.10.1", - "tslib": "^2.8.1" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.3.0.tgz", - "integrity": "sha512-Pe+RPVTi1T+qymuuRpcdvwSVZjnll/f7n8gBxMMh3xLTctMDKqpdfGimbMyioqtLhUYZxdJ9wGNhV7MKHvgZsQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 20" - } - }, - "node_modules/@tailwindcss/oxide-win32-x64-msvc": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.3.0.tgz", - "integrity": "sha512-Mvrf2kXW/yeW/OTezZlCGOirXRcUuLIBx/5Y12BaPM7wJoryG6dfS/NJL8aBPqtTEx/Vm4T4vKzFUcKDT+TKUA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 20" - } - }, - "node_modules/@tailwindcss/postcss": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/@tailwindcss/postcss/-/postcss-4.3.0.tgz", - "integrity": "sha512-Jm05Tjx+9yCLGv5qw1c+84Psds8MnyrEQYCB+FFk2lgGiUjlRqdxke4mVTuYrj2xnVZqKim2Apr5ySuQRYAw/w==", - "dev": true, - "dependencies": { - "@alloc/quick-lru": "^5.2.0", - "@tailwindcss/node": "4.3.0", - "@tailwindcss/oxide": "4.3.0", - "postcss": "^8.5.10", - "tailwindcss": "4.3.0" - } - }, - "node_modules/@tybys/wasm-util": { - "version": "0.10.2", - "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.2.tgz", - "integrity": "sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==", - "dev": true, - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@types/estree": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", - "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", - "dev": true - }, - "node_modules/@types/json-schema": { - "version": "7.0.15", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", - "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", - "dev": true - }, - "node_modules/@types/json5": { - "version": "0.0.29", - "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", - "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", - "dev": true - }, - "node_modules/@types/node": { - "version": "20.19.41", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.41.tgz", - "integrity": "sha512-ECymXOukMnOoVkC2bb1Vc/w/836DXncOg5m8Xj1RH7xSHZJWNYY6Zh7EH477vcnD5egKNNfy2RpNOmuChhFPgQ==", - "dev": true, - "dependencies": { - "undici-types": "~6.21.0" - } - }, - "node_modules/@types/react": { - "version": "19.2.15", - "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.15.tgz", - "integrity": "sha512-eRwcGNHve+E8qtEQSSRl6urh+rFop4v8gm6O8rGv25CodbvFdLjA1vVQ1KkiFE0w0UPOnb8tDiFKL5lp0rtY5Q==", - "dev": true, - "dependencies": { - "csstype": "^3.2.2" - } - }, - "node_modules/@types/react-dom": { - "version": "19.2.3", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", - "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", - "dev": true, - "peerDependencies": { - "@types/react": "^19.2.0" - } - }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.59.4", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.59.4.tgz", - "integrity": "sha512-PegsU+XfyJJNjd4+u/k6f9yTyp0lEXXiPopUNobZcIAUJFGICFLN+sP0Rb3JehVmiij1Ph0dFGYqODoRo/2+6A==", - "dev": true, - "dependencies": { - "@eslint-community/regexpp": "^4.12.2", - "@typescript-eslint/scope-manager": "8.59.4", - "@typescript-eslint/type-utils": "8.59.4", - "@typescript-eslint/utils": "8.59.4", - "@typescript-eslint/visitor-keys": "8.59.4", - "ignore": "^7.0.5", - "natural-compare": "^1.4.0", - "ts-api-utils": "^2.5.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^8.59.4", - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.1.0" - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", - "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/@typescript-eslint/parser": { - "version": "8.59.4", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.59.4.tgz", - "integrity": "sha512-zORHqO/tuhxY1zWuTvMUqddRxpiFJ72xVfcNoWpqdLjs6lfPbuQBJuW4pk+49/uBMy7Ssr4bzgjiKmmDB1UbZQ==", - "dev": true, - "dependencies": { - "@typescript-eslint/scope-manager": "8.59.4", - "@typescript-eslint/types": "8.59.4", - "@typescript-eslint/typescript-estree": "8.59.4", - "@typescript-eslint/visitor-keys": "8.59.4", - "debug": "^4.4.3" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.1.0" - } - }, - "node_modules/@typescript-eslint/project-service": { - "version": "8.59.4", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.59.4.tgz", - "integrity": "sha512-Ly00Vu4oAacfDeHp2Zg85ioNG6l8HG+tN1D7J+xTHSxu9y0awYKJ2zH1rFBn8ZSfuGK+7FxK3Cgl3uAz0aZZLg==", - "dev": true, - "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.59.4", - "@typescript-eslint/types": "^8.59.4", - "debug": "^4.4.3" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.1.0" - } - }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "8.59.4", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.59.4.tgz", - "integrity": "sha512-mUeR/3H1WrTAddJrwut8OoPjfauaztMQmRwV5fQTUyNVJCLiUXXe4lGEyYIL2oFDpP7UtgbGJXCt72wT0z2S3Q==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "8.59.4", - "@typescript-eslint/visitor-keys": "8.59.4" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.59.4", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.59.4.tgz", - "integrity": "sha512-DLCpnKgD4alVxTBSKulK+gU1KCqOgUXfDRDXh2mZgzokQKa/70ax93I2uVO3m/LLvIAtWZIFoiifudmIqAxpMA==", - "dev": true, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.1.0" - } - }, - "node_modules/@typescript-eslint/type-utils": { - "version": "8.59.4", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.59.4.tgz", - "integrity": "sha512-uonTuPAAKr9XaBGqJ3LjYTh72zy5DyGesljO9gtmk/eFW0W1fRHjnwVYKB35Lm8d5Q5CluEW3gPHjTvZTmgrfA==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "8.59.4", - "@typescript-eslint/typescript-estree": "8.59.4", - "@typescript-eslint/utils": "8.59.4", - "debug": "^4.4.3", - "ts-api-utils": "^2.5.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.1.0" - } - }, - "node_modules/@typescript-eslint/types": { - "version": "8.59.4", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.59.4.tgz", - "integrity": "sha512-F1o7WJcCq+bc8dwcO/YsSEOudAH8RDtaOhM6wcAQhcUsFhnWQl81JKy48q1hoxAU0qrzM89+31GYh1515Zde3Q==", - "dev": true, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.59.4", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.59.4.tgz", - "integrity": "sha512-F+RuOmcDXo4+TPdfd/TCLS3m2nw8gE9XXyZLrA3JBfaA5tz9TtdkyD3YJFmPxulyc2cKbEok/CvFE3MgSLWnag==", - "dev": true, - "dependencies": { - "@typescript-eslint/project-service": "8.59.4", - "@typescript-eslint/tsconfig-utils": "8.59.4", - "@typescript-eslint/types": "8.59.4", - "@typescript-eslint/visitor-keys": "8.59.4", - "debug": "^4.4.3", - "minimatch": "^10.2.2", - "semver": "^7.7.3", - "tinyglobby": "^0.2.15", - "ts-api-utils": "^2.5.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.1.0" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/balanced-match": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", - "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", - "dev": true, - "engines": { - "node": "18 || 20 || >=22" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { - "version": "5.0.6", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", - "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", - "dev": true, - "dependencies": { - "balanced-match": "^4.0.2" - }, - "engines": { - "node": "18 || 20 || >=22" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { - "version": "10.2.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", - "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", - "dev": true, - "dependencies": { - "brace-expansion": "^5.0.5" - }, - "engines": { - "node": "18 || 20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.0.tgz", - "integrity": "sha512-AcM7dV/5ul4EekoQ29Agm5vri8JNqRyj39o0qpX6vDF2GZrtutZl5RwgD1XnZjiTAfncsJhMI48QQH3sN87YNA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@typescript-eslint/utils": { - "version": "8.59.4", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.59.4.tgz", - "integrity": "sha512-cYXeNAUsG4lJo5dbc1FcKm+JwIWrj1/UpTORsC6tGMjEZ81DYcvIr9/ueikhMa/Y/gDQYGp+YX9/xQrXje5BJw==", - "dev": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.9.1", - "@typescript-eslint/scope-manager": "8.59.4", - "@typescript-eslint/types": "8.59.4", - "@typescript-eslint/typescript-estree": "8.59.4" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.1.0" - } - }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.59.4", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.59.4.tgz", - "integrity": "sha512-U3gxVaDVnuZKhSspW/MzMxE1kq7zOdc072FcSNoqA1I9p8HyKbBFfEHoWckBAMgNMph4MamwS5iTVzFmrnt8TQ==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "8.59.4", - "eslint-visitor-keys": "^5.0.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", - "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", - "dev": true, - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@unrs/resolver-binding-android-arm-eabi": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm-eabi/-/resolver-binding-android-arm-eabi-1.12.2.tgz", - "integrity": "sha512-g5T90pqg1bo/7mytQx6F4iBNC0Wsh9cu+z9veDbFjc7HjpesJFWD7QMS0NGStXM075+7dJPPVvBbpZlnrdpi/w==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@unrs/resolver-binding-android-arm64": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm64/-/resolver-binding-android-arm64-1.12.2.tgz", - "integrity": "sha512-YGCRZv/9GLhwmz6mYDeTsm/92BAyR28l6c2ReweVW5pWgfsitWLY8upvfRlGdoyD8HjeTHSYJWyZGD4KJA/nFQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@unrs/resolver-binding-darwin-arm64": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-arm64/-/resolver-binding-darwin-arm64-1.12.2.tgz", - "integrity": "sha512-u9DiNT1auQMO20A9SyTuG3wUgQWB9Z7KjAg0uFuCDR1FsAY8A0CG2S6JpHS1xwm/w1G08bjXZDcyOCjv1WAm2w==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@unrs/resolver-binding-darwin-x64": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-x64/-/resolver-binding-darwin-x64-1.12.2.tgz", - "integrity": "sha512-f7rPLi/T1HVKZu/u6t87lroib16n8vrSzcyxI7lg4BGO9UF26KhQL44sd9eOUgrTYhvRXtWOIZT5PejdPyJfUA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@unrs/resolver-binding-freebsd-x64": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-freebsd-x64/-/resolver-binding-freebsd-x64-1.12.2.tgz", - "integrity": "sha512-BpcOjWCJub6nRZUS2zA20pmLvjtqAtGejETaIyRLiZiQf++cbrjltLA5NN/xaXfqeOBOSlMFbemIl5/S5tljmg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ] - }, - "node_modules/@unrs/resolver-binding-linux-arm-gnueabihf": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-gnueabihf/-/resolver-binding-linux-arm-gnueabihf-1.12.2.tgz", - "integrity": "sha512-vZTDvdSISZjJx66OzJqtsOhzifbqRjbmI1Mnu49fQDwog5GtDI4QidRiEAYbZCRj9C8YZEW+3ZjqsyS9GR4k2A==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@unrs/resolver-binding-linux-arm-musleabihf": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-musleabihf/-/resolver-binding-linux-arm-musleabihf-1.12.2.tgz", - "integrity": "sha512-BiPI+IrIlwcW4nLLMM21+B1dFPzd55yAVgVGrdgDjNef+ch03GdxrcyaIz8X9SsQirh/kCQ7mviyWlMxdh2D7g==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@unrs/resolver-binding-linux-arm64-gnu": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-gnu/-/resolver-binding-linux-arm64-gnu-1.12.2.tgz", - "integrity": "sha512-zJc0H99FEPoFfSrNpa91HYfxzfAJCr502oxNK1cfdC9hlaFI43RT+JFCann9JUgZmLzzntChHyn13Sgn9ljHNg==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@unrs/resolver-binding-linux-arm64-musl": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-musl/-/resolver-binding-linux-arm64-musl-1.12.2.tgz", - "integrity": "sha512-KQ3Lki6l+Pz1k/eBipN41ES+YUK30beLGb9YqcB1O542cyLCNE6GaxrfcY3T6EezmGGk84wb5XyO9loTM9tkcA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@unrs/resolver-binding-linux-loong64-gnu": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-loong64-gnu/-/resolver-binding-linux-loong64-gnu-1.12.2.tgz", - "integrity": "sha512-3SJGEh1DborhG6pyxvhPzCT4bbSIVihsvgJc13P1bHG7KLdNDaF9T3gsTwFc7Jw/5Y5/iWOjkEx7Zy0NvCGX3Q==", - "cpu": [ - "loong64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@unrs/resolver-binding-linux-loong64-musl": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-loong64-musl/-/resolver-binding-linux-loong64-musl-1.12.2.tgz", - "integrity": "sha512-jiuG/Obbel7uw1PwHNFfrkiKhLAF6mnyZ6aWlOAVN9WqKm8v0OFGnciJIHu8+CMvXLQ8AD51LPzAoUfT21D5Ew==", - "cpu": [ - "loong64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@unrs/resolver-binding-linux-ppc64-gnu": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-ppc64-gnu/-/resolver-binding-linux-ppc64-gnu-1.12.2.tgz", - "integrity": "sha512-q7xRvVpmcfeL+LlZg8Pbbo6QaTZwDU5BaGZbwfhkEsXJn3Was8xYfE0RBH266xZt0rM6B7i8xAYIvjthuUIWHg==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@unrs/resolver-binding-linux-riscv64-gnu": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-gnu/-/resolver-binding-linux-riscv64-gnu-1.12.2.tgz", - "integrity": "sha512-0CVdx6lcnT3Q9inOH8tsMIOJ6ImndllMjqJHg8RLVdB7Vq4SfkEXl9mCSsVNuNA4MCYycRicCUxPCabVHJRr6A==", - "cpu": [ - "riscv64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@unrs/resolver-binding-linux-riscv64-musl": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-musl/-/resolver-binding-linux-riscv64-musl-1.12.2.tgz", - "integrity": "sha512-iOwlRo9vnp6R6ohHQS11n0NnfdXx/omhkocmIfaPRpQhKZ+3BDMkkdRVh53qjkFkpPddf+FETA28NwGN7l5l+w==", - "cpu": [ - "riscv64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@unrs/resolver-binding-linux-s390x-gnu": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-s390x-gnu/-/resolver-binding-linux-s390x-gnu-1.12.2.tgz", - "integrity": "sha512-HYJtLfXq94q8iZNFT1lknx258wlkkWhZeUXJRqzKBBUJ00CvZ+N33zgbCqimLjsyw5Va6uUxhVa12mI+kaveEw==", - "cpu": [ - "s390x" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@unrs/resolver-binding-linux-x64-gnu": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-gnu/-/resolver-binding-linux-x64-gnu-1.12.2.tgz", - "integrity": "sha512-mPsUhunKKDih5O96Y6enDQyHc1SqBPlY1E/SfMWDM3EdJ95Z9CArPeCVwCCqbP45ljvivdEk8Fxn+SIb1rDAJQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@unrs/resolver-binding-linux-x64-musl": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-musl/-/resolver-binding-linux-x64-musl-1.12.2.tgz", - "integrity": "sha512-azrt6+5ydLd8Vt210AAFis/lZevSfPw93EJRIJG+xPu4WCJ8K0kppCTpMyLPcKT7H15M4Jnt2tMp5bOvCkRC6A==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@unrs/resolver-binding-openharmony-arm64": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-openharmony-arm64/-/resolver-binding-openharmony-arm64-1.12.2.tgz", - "integrity": "sha512-YZ9hP4O0X9PQb8eO980qmLNGH4zT3I9+SZTdt0Pr0YyuGQhYKoOZkV02VzrzyOZJ5xIJ3UFIenKkUkGg8GjgWQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "openharmony" - ] - }, - "node_modules/@unrs/resolver-binding-wasm32-wasi": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-wasm32-wasi/-/resolver-binding-wasm32-wasi-1.12.2.tgz", - "integrity": "sha512-tYFDIkMxSflfEc/h92ZWNsZlHSwgimbNHSO3PL2JWQHfCuC2q316jMyYU9TIWZsFK2bQwyK5VAdYgn8ygPj69A==", - "cpu": [ - "wasm32" - ], - "dev": true, - "optional": true, - "dependencies": { - "@emnapi/core": "1.10.0", - "@emnapi/runtime": "1.10.0", - "@napi-rs/wasm-runtime": "^1.1.4" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@unrs/resolver-binding-win32-arm64-msvc": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-arm64-msvc/-/resolver-binding-win32-arm64-msvc-1.12.2.tgz", - "integrity": "sha512-qzNyg3xL0VPQmCaUh+N5jSitce6k+uCBfMDesWRnlULOZaqUkaJ0ybdT+UqlAWJoQjuqfIU/0Ptx9bteN4D82g==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@unrs/resolver-binding-win32-ia32-msvc": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-ia32-msvc/-/resolver-binding-win32-ia32-msvc-1.12.2.tgz", - "integrity": "sha512-WD9sY00OfpHVGfsnHZoA8jVT+esS/Bg8z8jzxp5BnDCjjwsuKsPQrzswwpFy4J1AUJbXPRfkpcX0mXrzeXW79g==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@unrs/resolver-binding-win32-x64-msvc": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-x64-msvc/-/resolver-binding-win32-x64-msvc-1.12.2.tgz", - "integrity": "sha512-nAB74NfSNKknqQ1RrYj6uz8FcXEomu/MATJZxh/x+BArzN2U3JbOYC0APYzUIGhVY3m5hRxA8VPNdPBoG8txlA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@vercel/oidc": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/@vercel/oidc/-/oidc-3.2.0.tgz", - "integrity": "sha512-UycprH3T6n3jH0k44NHMa7pnFHGu/N05MjojYr+Mc6I7obkoLIJujSWwin1pCvdy/eOxrI/l3uDLQsmcrOb4ug==", - "engines": { - "node": ">= 20" - } - }, - "node_modules/acorn": { - "version": "8.16.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", - "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/ai": { - "version": "6.0.185", - "resolved": "https://registry.npmjs.org/ai/-/ai-6.0.185.tgz", - "integrity": "sha512-oGsqscREaTlo75KHZLtwZxRyI+ZBwHV2wRX9B8smHjgOs13WwoCvUyr5aPUWpIBRz406wmIKy1RzoUEq0/WKJw==", - "dependencies": { - "@ai-sdk/gateway": "3.0.116", - "@ai-sdk/provider": "3.0.10", - "@ai-sdk/provider-utils": "4.0.27", - "@opentelemetry/api": "^1.9.0" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "zod": "^3.25.76 || ^4.1.8" - } - }, - "node_modules/ajv": { - "version": "6.15.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", - "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "node_modules/aria-query": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz", - "integrity": "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==", - "dev": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/array-buffer-byte-length": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz", - "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==", - "dev": true, - "dependencies": { - "call-bound": "^1.0.3", - "is-array-buffer": "^3.0.5" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array-includes": { - "version": "3.1.9", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.9.tgz", - "integrity": "sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.4", - "define-properties": "^1.2.1", - "es-abstract": "^1.24.0", - "es-object-atoms": "^1.1.1", - "get-intrinsic": "^1.3.0", - "is-string": "^1.1.1", - "math-intrinsics": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.findlast": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz", - "integrity": "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0", - "es-shim-unscopables": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.findlastindex": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.6.tgz", - "integrity": "sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.4", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.9", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.1.1", - "es-shim-unscopables": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.flat": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.3.tgz", - "integrity": "sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.8", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.5", - "es-shim-unscopables": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.flatmap": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.3.tgz", - "integrity": "sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.8", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.5", - "es-shim-unscopables": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.tosorted": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.4.tgz", - "integrity": "sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.3", - "es-errors": "^1.3.0", - "es-shim-unscopables": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/arraybuffer.prototype.slice": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz", - "integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==", - "dev": true, - "dependencies": { - "array-buffer-byte-length": "^1.0.1", - "call-bind": "^1.0.8", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.5", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.6", - "is-array-buffer": "^3.0.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/ast-types-flow": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.8.tgz", - "integrity": "sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==", - "dev": true - }, - "node_modules/async-function": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz", - "integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==", - "dev": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/available-typed-arrays": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", - "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", - "dev": true, - "dependencies": { - "possible-typed-array-names": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/axe-core": { - "version": "4.11.4", - "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.11.4.tgz", - "integrity": "sha512-KunSNx+TVpkAw/6ULfhnx+HWRecjqZGTOyquAoWHYLRSdK1tB5Ihce1ZW+UY3fj33bYAFWPu7W/GRSmmrCGuxA==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/axobject-query": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", - "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==", - "dev": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "node_modules/baseline-browser-mapping": { - "version": "2.10.31", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.31.tgz", - "integrity": "sha512-MujYO3eP72uvmSE0i4wltsodRfIpZATP3jvzRNRGGxgzId7aVocVJJV3nf01qnzzKFGxQVC9bpWxl5cjxTr/7Q==", - "bin": { - "baseline-browser-mapping": "dist/cli.cjs" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/brace-expansion": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz", - "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dev": true, - "dependencies": { - "fill-range": "^7.1.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/browserslist": { - "version": "4.28.2", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.2.tgz", - "integrity": "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "baseline-browser-mapping": "^2.10.12", - "caniuse-lite": "^1.0.30001782", - "electron-to-chromium": "^1.5.328", - "node-releases": "^2.0.36", - "update-browserslist-db": "^1.2.3" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, - "node_modules/call-bind": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.9.tgz", - "integrity": "sha512-a/hy+pNsFUTR+Iz8TCJvXudKVLAnz/DyeSUo10I5yvFDQJBFU2s9uqQpoSrJlroHUKoKqzg+epxyP9lqFdzfBQ==", - "dev": true, - "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "es-define-property": "^1.0.1", - "get-intrinsic": "^1.3.0", - "set-function-length": "^1.2.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/call-bind-apply-helpers": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", - "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", - "dev": true, - "dependencies": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/call-bound": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", - "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", - "dev": true, - "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "get-intrinsic": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001793", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001793.tgz", - "integrity": "sha512-iwSsYWaCOoh26cV8NwNRViHlrfUvYsHDfRVcbtmw0Kg6PJIZZXwMkj1442FYLBGkeUf1juAsU3DTfxW579mrPA==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ] - }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/client-only": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", - "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==" - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true - }, - "node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true - }, - "node_modules/cross-spawn": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", - "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", - "dev": true, - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/csstype": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", - "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", - "dev": true - }, - "node_modules/damerau-levenshtein": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", - "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==", - "dev": true - }, - "node_modules/data-view-buffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz", - "integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==", - "dev": true, - "dependencies": { - "call-bound": "^1.0.3", - "es-errors": "^1.3.0", - "is-data-view": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/data-view-byte-length": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz", - "integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==", - "dev": true, - "dependencies": { - "call-bound": "^1.0.3", - "es-errors": "^1.3.0", - "is-data-view": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/inspect-js" - } - }, - "node_modules/data-view-byte-offset": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz", - "integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==", - "dev": true, - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "is-data-view": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "dev": true, - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true - }, - "node_modules/define-data-property": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", - "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", - "dev": true, - "dependencies": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "gopd": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/define-properties": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", - "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", - "dev": true, - "dependencies": { - "define-data-property": "^1.0.1", - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/dequal": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", - "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", - "engines": { - "node": ">=6" - } - }, - "node_modules/detect-libc": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", - "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", - "devOptional": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/dotenv": { - "version": "17.4.2", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.4.2.tgz", - "integrity": "sha512-nI4U3TottKAcAD9LLud4Cb7b2QztQMUEfHbvhTH09bqXTxnSie8WnjPALV/WMCrJZ6UV/qHJ6L03OqO3LcdYZw==", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://dotenvx.com" - } - }, - "node_modules/dunder-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", - "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", - "dev": true, - "dependencies": { - "call-bind-apply-helpers": "^1.0.1", - "es-errors": "^1.3.0", - "gopd": "^1.2.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/electron-to-chromium": { - "version": "1.5.360", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.360.tgz", - "integrity": "sha512-GkcBt6YYAw9SxFWn+xVar4cLVGlXVuswwtRLBozi2zp0GjXs4ZnOrqV4zbXzg35n7w81hCkyJNYicgXlVHAmBA==", - "dev": true - }, - "node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true - }, - "node_modules/enhanced-resolve": { - "version": "5.21.5", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.21.5.tgz", - "integrity": "sha512-mLCNbrQli11K1ySUmuNt4ZUB3OpGIDq4q2vTBTf5cL2lpsRjI9QKqSD0ndjW8FyvcW/Jj46gMe9syyHAsvMa/A==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.2.4", - "tapable": "^2.3.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/es-abstract": { - "version": "1.24.2", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.2.tgz", - "integrity": "sha512-2FpH9Q5i2RRwyEP1AylXe6nYLR5OhaJTZwmlcP0dL/+JCbgg7yyEo/sEK6HeGZRf3dFpWwThaRHVApXSkW3xeg==", - "dev": true, - "dependencies": { - "array-buffer-byte-length": "^1.0.2", - "arraybuffer.prototype.slice": "^1.0.4", - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.8", - "call-bound": "^1.0.4", - "data-view-buffer": "^1.0.2", - "data-view-byte-length": "^1.0.2", - "data-view-byte-offset": "^1.0.1", - "es-define-property": "^1.0.1", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.1.1", - "es-set-tostringtag": "^2.1.0", - "es-to-primitive": "^1.3.0", - "function.prototype.name": "^1.1.8", - "get-intrinsic": "^1.3.0", - "get-proto": "^1.0.1", - "get-symbol-description": "^1.1.0", - "globalthis": "^1.0.4", - "gopd": "^1.2.0", - "has-property-descriptors": "^1.0.2", - "has-proto": "^1.2.0", - "has-symbols": "^1.1.0", - "hasown": "^2.0.2", - "internal-slot": "^1.1.0", - "is-array-buffer": "^3.0.5", - "is-callable": "^1.2.7", - "is-data-view": "^1.0.2", - "is-negative-zero": "^2.0.3", - "is-regex": "^1.2.1", - "is-set": "^2.0.3", - "is-shared-array-buffer": "^1.0.4", - "is-string": "^1.1.1", - "is-typed-array": "^1.1.15", - "is-weakref": "^1.1.1", - "math-intrinsics": "^1.1.0", - "object-inspect": "^1.13.4", - "object-keys": "^1.1.1", - "object.assign": "^4.1.7", - "own-keys": "^1.0.1", - "regexp.prototype.flags": "^1.5.4", - "safe-array-concat": "^1.1.3", - "safe-push-apply": "^1.0.0", - "safe-regex-test": "^1.1.0", - "set-proto": "^1.0.0", - "stop-iteration-iterator": "^1.1.0", - "string.prototype.trim": "^1.2.10", - "string.prototype.trimend": "^1.0.9", - "string.prototype.trimstart": "^1.0.8", - "typed-array-buffer": "^1.0.3", - "typed-array-byte-length": "^1.0.3", - "typed-array-byte-offset": "^1.0.4", - "typed-array-length": "^1.0.7", - "unbox-primitive": "^1.1.0", - "which-typed-array": "^1.1.19" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es-define-property": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", - "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", - "dev": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-errors": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "dev": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-iterator-helpers": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.3.2.tgz", - "integrity": "sha512-HVLACW1TppGYjJ8H6/jqH/pqOtKRw6wMlrB23xfExmFWxFquAIWCmwoLsOyN96K4a5KbmOf5At9ZUO3GZbetAw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.9", - "call-bound": "^1.0.4", - "define-properties": "^1.2.1", - "es-abstract": "^1.24.2", - "es-errors": "^1.3.0", - "es-set-tostringtag": "^2.1.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.3.0", - "globalthis": "^1.0.4", - "gopd": "^1.2.0", - "has-property-descriptors": "^1.0.2", - "has-proto": "^1.2.0", - "has-symbols": "^1.1.0", - "internal-slot": "^1.1.0", - "iterator.prototype": "^1.1.5", - "math-intrinsics": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-object-atoms": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", - "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", - "dev": true, - "dependencies": { - "es-errors": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-set-tostringtag": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", - "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", - "dev": true, - "dependencies": { - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.6", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-shim-unscopables": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.1.0.tgz", - "integrity": "sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==", - "dev": true, - "dependencies": { - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-to-primitive": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.0.tgz", - "integrity": "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==", - "dev": true, - "dependencies": { - "is-callable": "^1.2.7", - "is-date-object": "^1.0.5", - "is-symbol": "^1.0.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/esbuild": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.0.tgz", - "integrity": "sha512-sNR9MHpXSUV/XB4zmsFKN+QgVG82Cc7+/aaxJ8Adi8hyOac+EXptIp45QBPaVyX3N70664wRbTcLTOemCAnyqw==", - "dev": true, - "hasInstallScript": true, - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=18" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.28.0", - "@esbuild/android-arm": "0.28.0", - "@esbuild/android-arm64": "0.28.0", - "@esbuild/android-x64": "0.28.0", - "@esbuild/darwin-arm64": "0.28.0", - "@esbuild/darwin-x64": "0.28.0", - "@esbuild/freebsd-arm64": "0.28.0", - "@esbuild/freebsd-x64": "0.28.0", - "@esbuild/linux-arm": "0.28.0", - "@esbuild/linux-arm64": "0.28.0", - "@esbuild/linux-ia32": "0.28.0", - "@esbuild/linux-loong64": "0.28.0", - "@esbuild/linux-mips64el": "0.28.0", - "@esbuild/linux-ppc64": "0.28.0", - "@esbuild/linux-riscv64": "0.28.0", - "@esbuild/linux-s390x": "0.28.0", - "@esbuild/linux-x64": "0.28.0", - "@esbuild/netbsd-arm64": "0.28.0", - "@esbuild/netbsd-x64": "0.28.0", - "@esbuild/openbsd-arm64": "0.28.0", - "@esbuild/openbsd-x64": "0.28.0", - "@esbuild/openharmony-arm64": "0.28.0", - "@esbuild/sunos-x64": "0.28.0", - "@esbuild/win32-arm64": "0.28.0", - "@esbuild/win32-ia32": "0.28.0", - "@esbuild/win32-x64": "0.28.0" - } - }, - "node_modules/escalade": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", - "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint": { - "version": "9.39.4", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.4.tgz", - "integrity": "sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==", - "dev": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.8.0", - "@eslint-community/regexpp": "^4.12.1", - "@eslint/config-array": "^0.21.2", - "@eslint/config-helpers": "^0.4.2", - "@eslint/core": "^0.17.0", - "@eslint/eslintrc": "^3.3.5", - "@eslint/js": "9.39.4", - "@eslint/plugin-kit": "^0.4.1", - "@humanfs/node": "^0.16.6", - "@humanwhocodes/module-importer": "^1.0.1", - "@humanwhocodes/retry": "^0.4.2", - "@types/estree": "^1.0.6", - "ajv": "^6.14.0", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.6", - "debug": "^4.3.2", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^8.4.0", - "eslint-visitor-keys": "^4.2.1", - "espree": "^10.4.0", - "esquery": "^1.5.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^8.0.0", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "ignore": "^5.2.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.5", - "natural-compare": "^1.4.0", - "optionator": "^0.9.3" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://eslint.org/donate" - }, - "peerDependencies": { - "jiti": "*" - }, - "peerDependenciesMeta": { - "jiti": { - "optional": true - } - } - }, - "node_modules/eslint-config-next": { - "version": "16.2.6", - "resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-16.2.6.tgz", - "integrity": "sha512-z2ELYSkyrrJ6cuunTU8vhsT/RpouPkjaSah06nVW6Rg2Hpg0Vs8s497/e5s8G8qtdp4ccsiovz5P1rv+5VSW2Q==", - "dev": true, - "dependencies": { - "@next/eslint-plugin-next": "16.2.6", - "eslint-import-resolver-node": "^0.3.6", - "eslint-import-resolver-typescript": "^3.5.2", - "eslint-plugin-import": "^2.32.0", - "eslint-plugin-jsx-a11y": "^6.10.0", - "eslint-plugin-react": "^7.37.0", - "eslint-plugin-react-hooks": "^7.0.0", - "globals": "16.4.0", - "typescript-eslint": "^8.46.0" - }, - "peerDependencies": { - "eslint": ">=9.0.0", - "typescript": ">=3.3.1" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/eslint-config-next/node_modules/globals": { - "version": "16.4.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-16.4.0.tgz", - "integrity": "sha512-ob/2LcVVaVGCYN+r14cnwnoDPUufjiYgSqRhiFD0Q1iI4Odora5RE8Iv1D24hAz5oMophRGkGz+yuvQmmUMnMw==", - "dev": true, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint-import-resolver-node": { - "version": "0.3.10", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.10.tgz", - "integrity": "sha512-tRrKqFyCaKict5hOd244sL6EQFNycnMQnBe+j8uqGNXYzsImGbGUU4ibtoaBmv5FLwJwcFJNeg1GeVjQfbMrDQ==", - "dev": true, - "dependencies": { - "debug": "^3.2.7", - "is-core-module": "^2.16.1", - "resolve": "^2.0.0-next.6" - } - }, - "node_modules/eslint-import-resolver-node/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/eslint-import-resolver-typescript": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.10.1.tgz", - "integrity": "sha512-A1rHYb06zjMGAxdLSkN2fXPBwuSaQ0iO5M/hdyS0Ajj1VBaRp0sPD3dn1FhME3c/JluGFbwSxyCfqdSbtQLAHQ==", - "dev": true, - "dependencies": { - "@nolyfill/is-core-module": "1.0.39", - "debug": "^4.4.0", - "get-tsconfig": "^4.10.0", - "is-bun-module": "^2.0.0", - "stable-hash": "^0.0.5", - "tinyglobby": "^0.2.13", - "unrs-resolver": "^1.6.2" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint-import-resolver-typescript" - }, - "peerDependencies": { - "eslint": "*", - "eslint-plugin-import": "*", - "eslint-plugin-import-x": "*" - }, - "peerDependenciesMeta": { - "eslint-plugin-import": { - "optional": true - }, - "eslint-plugin-import-x": { - "optional": true - } - } - }, - "node_modules/eslint-module-utils": { - "version": "2.12.1", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.12.1.tgz", - "integrity": "sha512-L8jSWTze7K2mTg0vos/RuLRS5soomksDPoJLXIslC7c8Wmut3bx7CPpJijDcBZtxQ5lrbUdM+s0OlNbz0DCDNw==", - "dev": true, - "dependencies": { - "debug": "^3.2.7" - }, - "engines": { - "node": ">=4" - }, - "peerDependenciesMeta": { - "eslint": { - "optional": true - } - } - }, - "node_modules/eslint-module-utils/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/eslint-plugin-import": { - "version": "2.32.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.32.0.tgz", - "integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==", - "dev": true, - "dependencies": { - "@rtsao/scc": "^1.1.0", - "array-includes": "^3.1.9", - "array.prototype.findlastindex": "^1.2.6", - "array.prototype.flat": "^1.3.3", - "array.prototype.flatmap": "^1.3.3", - "debug": "^3.2.7", - "doctrine": "^2.1.0", - "eslint-import-resolver-node": "^0.3.9", - "eslint-module-utils": "^2.12.1", - "hasown": "^2.0.2", - "is-core-module": "^2.16.1", - "is-glob": "^4.0.3", - "minimatch": "^3.1.2", - "object.fromentries": "^2.0.8", - "object.groupby": "^1.0.3", - "object.values": "^1.2.1", - "semver": "^6.3.1", - "string.prototype.trimend": "^1.0.9", - "tsconfig-paths": "^3.15.0" - }, - "engines": { - "node": ">=4" - }, - "peerDependencies": { - "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9" - } - }, - "node_modules/eslint-plugin-import/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/eslint-plugin-jsx-a11y": { - "version": "6.10.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.10.2.tgz", - "integrity": "sha512-scB3nz4WmG75pV8+3eRUQOHZlNSUhFNq37xnpgRkCCELU3XMvXAxLk1eqWWyE22Ki4Q01Fnsw9BA3cJHDPgn2Q==", - "dev": true, - "dependencies": { - "aria-query": "^5.3.2", - "array-includes": "^3.1.8", - "array.prototype.flatmap": "^1.3.2", - "ast-types-flow": "^0.0.8", - "axe-core": "^4.10.0", - "axobject-query": "^4.1.0", - "damerau-levenshtein": "^1.0.8", - "emoji-regex": "^9.2.2", - "hasown": "^2.0.2", - "jsx-ast-utils": "^3.3.5", - "language-tags": "^1.0.9", - "minimatch": "^3.1.2", - "object.fromentries": "^2.0.8", - "safe-regex-test": "^1.0.3", - "string.prototype.includes": "^2.0.1" - }, - "engines": { - "node": ">=4.0" - }, - "peerDependencies": { - "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9" - } - }, - "node_modules/eslint-plugin-react": { - "version": "7.37.5", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.5.tgz", - "integrity": "sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==", - "dev": true, - "dependencies": { - "array-includes": "^3.1.8", - "array.prototype.findlast": "^1.2.5", - "array.prototype.flatmap": "^1.3.3", - "array.prototype.tosorted": "^1.1.4", - "doctrine": "^2.1.0", - "es-iterator-helpers": "^1.2.1", - "estraverse": "^5.3.0", - "hasown": "^2.0.2", - "jsx-ast-utils": "^2.4.1 || ^3.0.0", - "minimatch": "^3.1.2", - "object.entries": "^1.1.9", - "object.fromentries": "^2.0.8", - "object.values": "^1.2.1", - "prop-types": "^15.8.1", - "resolve": "^2.0.0-next.5", - "semver": "^6.3.1", - "string.prototype.matchall": "^4.0.12", - "string.prototype.repeat": "^1.0.0" - }, - "engines": { - "node": ">=4" - }, - "peerDependencies": { - "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7" - } - }, - "node_modules/eslint-plugin-react-hooks": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-7.1.1.tgz", - "integrity": "sha512-f2I7Gw6JbvCexzIInuSbZpfdQ44D7iqdWX01FKLvrPgqxoE7oMj8clOfto8U6vYiz4yd5oKu39rRSVOe1zRu0g==", - "dev": true, - "dependencies": { - "@babel/core": "^7.24.4", - "@babel/parser": "^7.24.4", - "hermes-parser": "^0.25.1", - "zod": "^3.25.0 || ^4.0.0", - "zod-validation-error": "^3.5.0 || ^4.0.0" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 || ^10.0.0" - } - }, - "node_modules/eslint-scope": { - "version": "8.4.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", - "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", - "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", - "dev": true, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/espree": { - "version": "10.4.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", - "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", - "dev": true, - "dependencies": { - "acorn": "^8.15.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^4.2.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/esquery": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", - "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", - "dev": true, - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eventsource-parser": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.0.8.tgz", - "integrity": "sha512-70QWGkr4snxr0OXLRWsFLeRBIRPuQOvt4s8QYjmUlmlkyTZkRqS7EDVRZtzU3TiyDbXSzaOeF0XUKy8PchzukQ==", - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "node_modules/fast-glob": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz", - "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fast-glob/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true - }, - "node_modules/fastq": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", - "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", - "dev": true, - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/file-entry-cache": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", - "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", - "dev": true, - "dependencies": { - "flat-cache": "^4.0.0" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "dev": true, - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/flat-cache": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", - "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", - "dev": true, - "dependencies": { - "flatted": "^3.2.9", - "keyv": "^4.5.4" - }, - "engines": { - "node": ">=16" - } - }, - "node_modules/flatted": { - "version": "3.4.2", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz", - "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==", - "dev": true - }, - "node_modules/for-each": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", - "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", - "dev": true, - "dependencies": { - "is-callable": "^1.2.7" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/function.prototype.name": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.8.tgz", - "integrity": "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.3", - "define-properties": "^1.2.1", - "functions-have-names": "^1.2.3", - "hasown": "^2.0.2", - "is-callable": "^1.2.7" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/functions-have-names": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", - "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/generator-function": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/generator-function/-/generator-function-2.0.1.tgz", - "integrity": "sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==", - "dev": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/get-intrinsic": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", - "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", - "dev": true, - "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "es-define-property": "^1.0.1", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.1.1", - "function-bind": "^1.1.2", - "get-proto": "^1.0.1", - "gopd": "^1.2.0", - "has-symbols": "^1.1.0", - "hasown": "^2.0.2", - "math-intrinsics": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", - "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", - "dev": true, - "dependencies": { - "dunder-proto": "^1.0.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/get-symbol-description": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz", - "integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==", - "dev": true, - "dependencies": { - "call-bound": "^1.0.3", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.6" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-tsconfig": { - "version": "4.14.0", - "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.14.0.tgz", - "integrity": "sha512-yTb+8DXzDREzgvYmh6s9vHsSVCHeC0G3PI5bEXNBHtmshPnO+S5O7qgLEOn0I5QvMy6kpZN8K1NKGyilLb93wA==", - "dev": true, - "dependencies": { - "resolve-pkg-maps": "^1.0.0" - }, - "funding": { - "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" - } - }, - "node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/globals": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", - "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", - "dev": true, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/globalthis": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", - "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", - "dev": true, - "dependencies": { - "define-properties": "^1.2.1", - "gopd": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/gopd": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", - "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true - }, - "node_modules/has-bigints": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz", - "integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/has-property-descriptors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", - "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", - "dev": true, - "dependencies": { - "es-define-property": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-proto": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz", - "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==", - "dev": true, - "dependencies": { - "dunder-proto": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-symbols": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", - "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-tostringtag": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", - "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", - "dev": true, - "dependencies": { - "has-symbols": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/hasown": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.3.tgz", - "integrity": "sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/hermes-estree": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.25.1.tgz", - "integrity": "sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==", - "dev": true - }, - "node_modules/hermes-parser": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.25.1.tgz", - "integrity": "sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==", - "dev": true, - "dependencies": { - "hermes-estree": "0.25.1" - } - }, - "node_modules/iceberg-js": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/iceberg-js/-/iceberg-js-0.8.1.tgz", - "integrity": "sha512-1dhVQZXhcHje7798IVM+xoo/1ZdVfzOMIc8/rgVSijRK38EDqOJoGula9N/8ZI5RD8QTxNQtK/Gozpr+qUqRRA==", - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/ignore": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", - "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/import-fresh": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", - "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", - "dev": true, - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/internal-slot": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", - "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==", - "dev": true, - "dependencies": { - "es-errors": "^1.3.0", - "hasown": "^2.0.2", - "side-channel": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/is-array-buffer": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz", - "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.3", - "get-intrinsic": "^1.2.6" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-async-function": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz", - "integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==", - "dev": true, - "dependencies": { - "async-function": "^1.0.0", - "call-bound": "^1.0.3", - "get-proto": "^1.0.1", - "has-tostringtag": "^1.0.2", - "safe-regex-test": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-bigint": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz", - "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==", - "dev": true, - "dependencies": { - "has-bigints": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-boolean-object": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz", - "integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==", - "dev": true, - "dependencies": { - "call-bound": "^1.0.3", - "has-tostringtag": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-bun-module": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-bun-module/-/is-bun-module-2.0.0.tgz", - "integrity": "sha512-gNCGbnnnnFAUGKeZ9PdbyeGYJqewpmc2aKHUEMO5nQPWU9lOmv7jcmQIv+qHD8fXW6W7qfuCwX4rY9LNRjXrkQ==", - "dev": true, - "dependencies": { - "semver": "^7.7.1" - } - }, - "node_modules/is-bun-module/node_modules/semver": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.0.tgz", - "integrity": "sha512-AcM7dV/5ul4EekoQ29Agm5vri8JNqRyj39o0qpX6vDF2GZrtutZl5RwgD1XnZjiTAfncsJhMI48QQH3sN87YNA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/is-callable": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", - "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-core-module": { - "version": "2.16.2", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.2.tgz", - "integrity": "sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==", - "dev": true, - "dependencies": { - "hasown": "^2.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-data-view": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz", - "integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==", - "dev": true, - "dependencies": { - "call-bound": "^1.0.2", - "get-intrinsic": "^1.2.6", - "is-typed-array": "^1.1.13" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-date-object": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz", - "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==", - "dev": true, - "dependencies": { - "call-bound": "^1.0.2", - "has-tostringtag": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-finalizationregistry": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz", - "integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==", - "dev": true, - "dependencies": { - "call-bound": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-generator-function": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.2.tgz", - "integrity": "sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==", - "dev": true, - "dependencies": { - "call-bound": "^1.0.4", - "generator-function": "^2.0.0", - "get-proto": "^1.0.1", - "has-tostringtag": "^1.0.2", - "safe-regex-test": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-map": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", - "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-negative-zero": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", - "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-number-object": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz", - "integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==", - "dev": true, - "dependencies": { - "call-bound": "^1.0.3", - "has-tostringtag": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-regex": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", - "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", - "dev": true, - "dependencies": { - "call-bound": "^1.0.2", - "gopd": "^1.2.0", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-set": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", - "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-shared-array-buffer": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz", - "integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==", - "dev": true, - "dependencies": { - "call-bound": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-string": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz", - "integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==", - "dev": true, - "dependencies": { - "call-bound": "^1.0.3", - "has-tostringtag": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-symbol": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz", - "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==", - "dev": true, - "dependencies": { - "call-bound": "^1.0.2", - "has-symbols": "^1.1.0", - "safe-regex-test": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-typed-array": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", - "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", - "dev": true, - "dependencies": { - "which-typed-array": "^1.1.16" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-weakmap": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", - "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-weakref": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.1.tgz", - "integrity": "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==", - "dev": true, - "dependencies": { - "call-bound": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-weakset": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz", - "integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==", - "dev": true, - "dependencies": { - "call-bound": "^1.0.3", - "get-intrinsic": "^1.2.6" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "dev": true - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true - }, - "node_modules/iterator.prototype": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.5.tgz", - "integrity": "sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==", - "dev": true, - "dependencies": { - "define-data-property": "^1.1.4", - "es-object-atoms": "^1.0.0", - "get-intrinsic": "^1.2.6", - "get-proto": "^1.0.0", - "has-symbols": "^1.1.0", - "set-function-name": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/jiti": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.7.0.tgz", - "integrity": "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==", - "dev": true, - "bin": { - "jiti": "lib/jiti-cli.mjs" - } - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "node_modules/js-yaml": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", - "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", - "dev": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/jsesc": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", - "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", - "dev": true, - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true - }, - "node_modules/json-schema": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", - "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==" - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true - }, - "node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true, - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/jsx-ast-utils": { - "version": "3.3.5", - "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", - "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==", - "dev": true, - "dependencies": { - "array-includes": "^3.1.6", - "array.prototype.flat": "^1.3.1", - "object.assign": "^4.1.4", - "object.values": "^1.1.6" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/keyv": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", - "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", - "dev": true, - "dependencies": { - "json-buffer": "3.0.1" - } - }, - "node_modules/language-subtag-registry": { - "version": "0.3.23", - "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.23.tgz", - "integrity": "sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==", - "dev": true - }, - "node_modules/language-tags": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.9.tgz", - "integrity": "sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==", - "dev": true, - "dependencies": { - "language-subtag-registry": "^0.3.20" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/lightningcss": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz", - "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==", - "dev": true, - "dependencies": { - "detect-libc": "^2.0.3" - }, - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - }, - "optionalDependencies": { - "lightningcss-android-arm64": "1.32.0", - "lightningcss-darwin-arm64": "1.32.0", - "lightningcss-darwin-x64": "1.32.0", - "lightningcss-freebsd-x64": "1.32.0", - "lightningcss-linux-arm-gnueabihf": "1.32.0", - "lightningcss-linux-arm64-gnu": "1.32.0", - "lightningcss-linux-arm64-musl": "1.32.0", - "lightningcss-linux-x64-gnu": "1.32.0", - "lightningcss-linux-x64-musl": "1.32.0", - "lightningcss-win32-arm64-msvc": "1.32.0", - "lightningcss-win32-x64-msvc": "1.32.0" - } - }, - "node_modules/lightningcss-android-arm64": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz", - "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-darwin-arm64": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz", - "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-darwin-x64": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz", - "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-freebsd-x64": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz", - "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-arm-gnueabihf": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz", - "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-arm64-gnu": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz", - "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-arm64-musl": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz", - "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-x64-gnu": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz", - "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-x64-musl": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz", - "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-win32-arm64-msvc": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz", - "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-win32-x64-msvc": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz", - "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true - }, - "node_modules/loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "dev": true, - "dependencies": { - "js-tokens": "^3.0.0 || ^4.0.0" - }, - "bin": { - "loose-envify": "cli.js" - } - }, - "node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, - "dependencies": { - "yallist": "^3.0.2" - } - }, - "node_modules/magic-string": { - "version": "0.30.21", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", - "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", - "dev": true, - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.5" - } - }, - "node_modules/math-intrinsics": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", - "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", - "dev": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/micromatch": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", - "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", - "dev": true, - "dependencies": { - "braces": "^3.0.3", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/minimatch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, - "node_modules/nanoid": { - "version": "3.3.12", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.12.tgz", - "integrity": "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/napi-postinstall": { - "version": "0.3.4", - "resolved": "https://registry.npmjs.org/napi-postinstall/-/napi-postinstall-0.3.4.tgz", - "integrity": "sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ==", - "dev": true, - "bin": { - "napi-postinstall": "lib/cli.js" - }, - "engines": { - "node": "^12.20.0 || ^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/napi-postinstall" - } - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true - }, - "node_modules/next": { - "version": "16.2.6", - "resolved": "https://registry.npmjs.org/next/-/next-16.2.6.tgz", - "integrity": "sha512-qOVgKJg1+At15NpeUP+eJgCHvTCgXsogweq87Ri/Ix7PkqQHg4sdaXmSFqKlgaIXE4kW0g25LE68W87UANlHtw==", - "dependencies": { - "@next/env": "16.2.6", - "@swc/helpers": "0.5.15", - "baseline-browser-mapping": "^2.9.19", - "caniuse-lite": "^1.0.30001579", - "postcss": "8.4.31", - "styled-jsx": "5.1.6" - }, - "bin": { - "next": "dist/bin/next" - }, - "engines": { - "node": ">=20.9.0" - }, - "optionalDependencies": { - "@next/swc-darwin-arm64": "16.2.6", - "@next/swc-darwin-x64": "16.2.6", - "@next/swc-linux-arm64-gnu": "16.2.6", - "@next/swc-linux-arm64-musl": "16.2.6", - "@next/swc-linux-x64-gnu": "16.2.6", - "@next/swc-linux-x64-musl": "16.2.6", - "@next/swc-win32-arm64-msvc": "16.2.6", - "@next/swc-win32-x64-msvc": "16.2.6", - "sharp": "^0.34.5" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.1.0", - "@playwright/test": "^1.51.1", - "babel-plugin-react-compiler": "*", - "react": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", - "react-dom": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", - "sass": "^1.3.0" - }, - "peerDependenciesMeta": { - "@opentelemetry/api": { - "optional": true - }, - "@playwright/test": { - "optional": true - }, - "babel-plugin-react-compiler": { - "optional": true - }, - "sass": { - "optional": true - } - } - }, - "node_modules/next/node_modules/postcss": { - "version": "8.4.31", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", - "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "nanoid": "^3.3.6", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/node-exports-info": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/node-exports-info/-/node-exports-info-1.6.0.tgz", - "integrity": "sha512-pyFS63ptit/P5WqUkt+UUfe+4oevH+bFeIiPPdfb0pFeYEu/1ELnJu5l+5EcTKYL5M7zaAa7S8ddywgXypqKCw==", - "dev": true, - "dependencies": { - "array.prototype.flatmap": "^1.3.3", - "es-errors": "^1.3.0", - "object.entries": "^1.1.9", - "semver": "^6.3.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/node-releases": { - "version": "2.0.44", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.44.tgz", - "integrity": "sha512-5WUyunoPMsvvEhS8AxHtRzP+oA8UCkJ7YRxatWKjngndhDGLiqEVAQKWjFAiAiuL8zMRGzGSJxFnLetoa43qGQ==", - "dev": true - }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-inspect": { - "version": "1.13.4", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", - "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.assign": { - "version": "4.1.7", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz", - "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.3", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0", - "has-symbols": "^1.1.0", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.entries": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.9.tgz", - "integrity": "sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.4", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.fromentries": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz", - "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.groupby": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz", - "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.values": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.1.tgz", - "integrity": "sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.3", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/optionator": { - "version": "0.9.4", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", - "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", - "dev": true, - "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.5" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/own-keys": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.1.tgz", - "integrity": "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.2.6", - "object-keys": "^1.1.1", - "safe-push-apply": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true - }, - "node_modules/picocolors": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==" - }, - "node_modules/picomatch": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", - "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", - "dev": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/possible-typed-array-names": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", - "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", - "dev": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/postcss": { - "version": "8.5.15", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.15.tgz", - "integrity": "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "nanoid": "^3.3.12", - "picocolors": "^1.1.1", - "source-map-js": "^1.2.1" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/prop-types": { - "version": "15.8.1", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", - "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", - "dev": true, - "dependencies": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.13.1" - } - }, - "node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/react": { - "version": "19.2.4", - "resolved": "https://registry.npmjs.org/react/-/react-19.2.4.tgz", - "integrity": "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/react-dom": { - "version": "19.2.4", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.4.tgz", - "integrity": "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==", - "dependencies": { - "scheduler": "^0.27.0" - }, - "peerDependencies": { - "react": "^19.2.4" - } - }, - "node_modules/react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "dev": true - }, - "node_modules/reflect.getprototypeof": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", - "integrity": "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.8", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.9", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0", - "get-intrinsic": "^1.2.7", - "get-proto": "^1.0.1", - "which-builtin-type": "^1.2.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/regexp.prototype.flags": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", - "integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.8", - "define-properties": "^1.2.1", - "es-errors": "^1.3.0", - "get-proto": "^1.0.1", - "gopd": "^1.2.0", - "set-function-name": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/resolve": { - "version": "2.0.0-next.7", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.7.tgz", - "integrity": "sha512-tqt+NBWwyaMgw3zDsnygx4CByWjQEJHOPMdslYhppaQSJUtL/D4JO9CcBBlhPoI8lz9oJIDXkwXfhF4aWqP8xQ==", - "dev": true, - "dependencies": { - "es-errors": "^1.3.0", - "is-core-module": "^2.16.2", - "node-exports-info": "^1.6.0", - "object-keys": "^1.1.1", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/resolve-pkg-maps": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", - "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", - "dev": true, - "funding": { - "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" - } - }, - "node_modules/reusify": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", - "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", - "dev": true, - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/safe-array-concat": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.4.tgz", - "integrity": "sha512-wtZlHyOje6OZTGqAoaDKxFkgRtkF9CnHAVnCHKfuj200wAgL+bSJhdsCD2l0Qx/2ekEXjPWcyKkfGb5CPboslg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.9", - "call-bound": "^1.0.4", - "get-intrinsic": "^1.3.0", - "has-symbols": "^1.1.0", - "isarray": "^2.0.5" - }, - "engines": { - "node": ">=0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/safe-push-apply": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz", - "integrity": "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==", - "dev": true, - "dependencies": { - "es-errors": "^1.3.0", - "isarray": "^2.0.5" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/safe-regex-test": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", - "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", - "dev": true, - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "is-regex": "^1.2.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/scheduler": { - "version": "0.27.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", - "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==" - }, - "node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/set-function-length": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", - "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", - "dev": true, - "dependencies": { - "define-data-property": "^1.1.4", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/set-function-name": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", - "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", - "dev": true, - "dependencies": { - "define-data-property": "^1.1.4", - "es-errors": "^1.3.0", - "functions-have-names": "^1.2.3", - "has-property-descriptors": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/set-proto": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/set-proto/-/set-proto-1.0.0.tgz", - "integrity": "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==", - "dev": true, - "dependencies": { - "dunder-proto": "^1.0.1", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/sharp": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.5.tgz", - "integrity": "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==", - "hasInstallScript": true, - "optional": true, - "dependencies": { - "@img/colour": "^1.0.0", - "detect-libc": "^2.1.2", - "semver": "^7.7.3" - }, - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-darwin-arm64": "0.34.5", - "@img/sharp-darwin-x64": "0.34.5", - "@img/sharp-libvips-darwin-arm64": "1.2.4", - "@img/sharp-libvips-darwin-x64": "1.2.4", - "@img/sharp-libvips-linux-arm": "1.2.4", - "@img/sharp-libvips-linux-arm64": "1.2.4", - "@img/sharp-libvips-linux-ppc64": "1.2.4", - "@img/sharp-libvips-linux-riscv64": "1.2.4", - "@img/sharp-libvips-linux-s390x": "1.2.4", - "@img/sharp-libvips-linux-x64": "1.2.4", - "@img/sharp-libvips-linuxmusl-arm64": "1.2.4", - "@img/sharp-libvips-linuxmusl-x64": "1.2.4", - "@img/sharp-linux-arm": "0.34.5", - "@img/sharp-linux-arm64": "0.34.5", - "@img/sharp-linux-ppc64": "0.34.5", - "@img/sharp-linux-riscv64": "0.34.5", - "@img/sharp-linux-s390x": "0.34.5", - "@img/sharp-linux-x64": "0.34.5", - "@img/sharp-linuxmusl-arm64": "0.34.5", - "@img/sharp-linuxmusl-x64": "0.34.5", - "@img/sharp-wasm32": "0.34.5", - "@img/sharp-win32-arm64": "0.34.5", - "@img/sharp-win32-ia32": "0.34.5", - "@img/sharp-win32-x64": "0.34.5" - } - }, - "node_modules/sharp/node_modules/semver": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.0.tgz", - "integrity": "sha512-AcM7dV/5ul4EekoQ29Agm5vri8JNqRyj39o0qpX6vDF2GZrtutZl5RwgD1XnZjiTAfncsJhMI48QQH3sN87YNA==", - "optional": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/side-channel": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", - "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", - "dev": true, - "dependencies": { - "es-errors": "^1.3.0", - "object-inspect": "^1.13.3", - "side-channel-list": "^1.0.0", - "side-channel-map": "^1.0.1", - "side-channel-weakmap": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel-list": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.1.tgz", - "integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==", - "dev": true, - "dependencies": { - "es-errors": "^1.3.0", - "object-inspect": "^1.13.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel-map": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", - "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", - "dev": true, - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.5", - "object-inspect": "^1.13.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel-weakmap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", - "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", - "dev": true, - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.5", - "object-inspect": "^1.13.3", - "side-channel-map": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/source-map-js": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", - "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/stable-hash": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/stable-hash/-/stable-hash-0.0.5.tgz", - "integrity": "sha512-+L3ccpzibovGXFK+Ap/f8LOS0ahMrHTf3xu7mMLSpEGU0EO9ucaysSylKo9eRDFNhWve/y275iPmIZ4z39a9iA==", - "dev": true - }, - "node_modules/stop-iteration-iterator": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz", - "integrity": "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==", - "dev": true, - "dependencies": { - "es-errors": "^1.3.0", - "internal-slot": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/string.prototype.includes": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/string.prototype.includes/-/string.prototype.includes-2.0.1.tgz", - "integrity": "sha512-o7+c9bW6zpAdJHTtujeePODAhkuicdAryFsfVKwA+wGw89wJ4GTY484WTucM9hLtDEOpOvI+aHnzqnC5lHp4Rg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.3" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/string.prototype.matchall": { - "version": "4.0.12", - "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.12.tgz", - "integrity": "sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.3", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.6", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0", - "get-intrinsic": "^1.2.6", - "gopd": "^1.2.0", - "has-symbols": "^1.1.0", - "internal-slot": "^1.1.0", - "regexp.prototype.flags": "^1.5.3", - "set-function-name": "^2.0.2", - "side-channel": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.repeat": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/string.prototype.repeat/-/string.prototype.repeat-1.0.0.tgz", - "integrity": "sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==", - "dev": true, - "dependencies": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.5" - } - }, - "node_modules/string.prototype.trim": { - "version": "1.2.10", - "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz", - "integrity": "sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.2", - "define-data-property": "^1.1.4", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.5", - "es-object-atoms": "^1.0.0", - "has-property-descriptors": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimend": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz", - "integrity": "sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.2", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimstart": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", - "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/styled-jsx": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.6.tgz", - "integrity": "sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==", - "dependencies": { - "client-only": "0.0.1" - }, - "engines": { - "node": ">= 12.0.0" - }, - "peerDependencies": { - "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0" - }, - "peerDependenciesMeta": { - "@babel/core": { - "optional": true - }, - "babel-plugin-macros": { - "optional": true - } - } - }, - "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/swr": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/swr/-/swr-2.4.1.tgz", - "integrity": "sha512-2CC6CiKQtEwaEeNiqWTAw9PGykW8SR5zZX8MZk6TeAvEAnVS7Visz8WzphqgtQ8v2xz/4Q5K+j+SeMaKXeeQIA==", - "dependencies": { - "dequal": "^2.0.3", - "use-sync-external-store": "^1.6.0" - }, - "peerDependencies": { - "react": "^16.11.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" - } - }, - "node_modules/tailwindcss": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.3.0.tgz", - "integrity": "sha512-y6nxMGB1nMW9R6k96e5gdIFzcfL/gTJRNaqGes1YvkLnPVXzWgbqFF2yLC0T8G774n24cx3Pe8XrKoniCOAH+Q==", - "dev": true - }, - "node_modules/tapable": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.3.tgz", - "integrity": "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==", - "dev": true, - "engines": { - "node": ">=6" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/throttleit": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-2.1.0.tgz", - "integrity": "sha512-nt6AMGKW1p/70DF/hGBdJB57B8Tspmbp5gfJ8ilhLnt7kkr2ye7hzD6NVG8GGErk2HWF34igrL2CXmNIkzKqKw==", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/tinyglobby": { - "version": "0.2.16", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.16.tgz", - "integrity": "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==", - "dev": true, - "dependencies": { - "fdir": "^6.5.0", - "picomatch": "^4.0.4" - }, - "engines": { - "node": ">=12.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/SuperchupuDev" - } - }, - "node_modules/tinyglobby/node_modules/fdir": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", - "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", - "dev": true, - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } - } - }, - "node_modules/tinyglobby/node_modules/picomatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", - "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/ts-api-utils": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.5.0.tgz", - "integrity": "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==", - "dev": true, - "engines": { - "node": ">=18.12" - }, - "peerDependencies": { - "typescript": ">=4.8.4" - } - }, - "node_modules/tsconfig-paths": { - "version": "3.15.0", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", - "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", - "dev": true, - "dependencies": { - "@types/json5": "^0.0.29", - "json5": "^1.0.2", - "minimist": "^1.2.6", - "strip-bom": "^3.0.0" - } - }, - "node_modules/tsconfig-paths/node_modules/json5": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", - "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", - "dev": true, - "dependencies": { - "minimist": "^1.2.0" - }, - "bin": { - "json5": "lib/cli.js" - } - }, - "node_modules/tslib": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==" - }, - "node_modules/tsx": { - "version": "4.22.3", - "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.22.3.tgz", - "integrity": "sha512-mdoNxBC/cSQObGGVQ5Bpn5i+yv7j68gk3Nfm3wFjcJg3Z0Mix9jzAFfP12prmm5eVGmDKtp0yyArrs0Q+8gZHg==", - "dev": true, - "dependencies": { - "esbuild": "~0.28.0" - }, - "bin": { - "tsx": "dist/cli.mjs" - }, - "engines": { - "node": ">=18.0.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.3" - } - }, - "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/typed-array-buffer": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", - "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", - "dev": true, - "dependencies": { - "call-bound": "^1.0.3", - "es-errors": "^1.3.0", - "is-typed-array": "^1.1.14" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/typed-array-byte-length": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz", - "integrity": "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.8", - "for-each": "^0.3.3", - "gopd": "^1.2.0", - "has-proto": "^1.2.0", - "is-typed-array": "^1.1.14" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/typed-array-byte-offset": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz", - "integrity": "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==", - "dev": true, - "dependencies": { - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.8", - "for-each": "^0.3.3", - "gopd": "^1.2.0", - "has-proto": "^1.2.0", - "is-typed-array": "^1.1.15", - "reflect.getprototypeof": "^1.0.9" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/typed-array-length": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.7.tgz", - "integrity": "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "is-typed-array": "^1.1.13", - "possible-typed-array-names": "^1.0.0", - "reflect.getprototypeof": "^1.0.6" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/typescript": { - "version": "5.9.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", - "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", - "dev": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/typescript-eslint": { - "version": "8.59.4", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.59.4.tgz", - "integrity": "sha512-Rw6+44QNFaXtgHSjPy+Kw8hrJniMYzR85E9yLmOLcfZ91/rz+JXQbDTCmc6ccxMPY6K6PgAq26f0JCBfR7LIPQ==", - "dev": true, - "dependencies": { - "@typescript-eslint/eslint-plugin": "8.59.4", - "@typescript-eslint/parser": "8.59.4", - "@typescript-eslint/typescript-estree": "8.59.4", - "@typescript-eslint/utils": "8.59.4" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.1.0" - } - }, - "node_modules/unbox-primitive": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz", - "integrity": "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==", - "dev": true, - "dependencies": { - "call-bound": "^1.0.3", - "has-bigints": "^1.0.2", - "has-symbols": "^1.1.0", - "which-boxed-primitive": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/undici-types": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", - "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", - "dev": true - }, - "node_modules/unrs-resolver": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/unrs-resolver/-/unrs-resolver-1.12.2.tgz", - "integrity": "sha512-dmlRxBJJayXjqTwC+JtF1HhJmgf3ftQ3YejFcZrf4+KKtJv0qDsK1pjqaaVjG7wJ5NJ6UVP1OqRMQ71Z4C3rxQ==", - "dev": true, - "hasInstallScript": true, - "dependencies": { - "napi-postinstall": "^0.3.4" - }, - "funding": { - "url": "https://opencollective.com/unrs-resolver" - }, - "optionalDependencies": { - "@unrs/resolver-binding-android-arm-eabi": "1.12.2", - "@unrs/resolver-binding-android-arm64": "1.12.2", - "@unrs/resolver-binding-darwin-arm64": "1.12.2", - "@unrs/resolver-binding-darwin-x64": "1.12.2", - "@unrs/resolver-binding-freebsd-x64": "1.12.2", - "@unrs/resolver-binding-linux-arm-gnueabihf": "1.12.2", - "@unrs/resolver-binding-linux-arm-musleabihf": "1.12.2", - "@unrs/resolver-binding-linux-arm64-gnu": "1.12.2", - "@unrs/resolver-binding-linux-arm64-musl": "1.12.2", - "@unrs/resolver-binding-linux-loong64-gnu": "1.12.2", - "@unrs/resolver-binding-linux-loong64-musl": "1.12.2", - "@unrs/resolver-binding-linux-ppc64-gnu": "1.12.2", - "@unrs/resolver-binding-linux-riscv64-gnu": "1.12.2", - "@unrs/resolver-binding-linux-riscv64-musl": "1.12.2", - "@unrs/resolver-binding-linux-s390x-gnu": "1.12.2", - "@unrs/resolver-binding-linux-x64-gnu": "1.12.2", - "@unrs/resolver-binding-linux-x64-musl": "1.12.2", - "@unrs/resolver-binding-openharmony-arm64": "1.12.2", - "@unrs/resolver-binding-wasm32-wasi": "1.12.2", - "@unrs/resolver-binding-win32-arm64-msvc": "1.12.2", - "@unrs/resolver-binding-win32-ia32-msvc": "1.12.2", - "@unrs/resolver-binding-win32-x64-msvc": "1.12.2" - } - }, - "node_modules/update-browserslist-db": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", - "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "escalade": "^3.2.0", - "picocolors": "^1.1.1" - }, - "bin": { - "update-browserslist-db": "cli.js" - }, - "peerDependencies": { - "browserslist": ">= 4.21.0" - } - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/use-sync-external-store": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz", - "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==", - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/which-boxed-primitive": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz", - "integrity": "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==", - "dev": true, - "dependencies": { - "is-bigint": "^1.1.0", - "is-boolean-object": "^1.2.1", - "is-number-object": "^1.1.1", - "is-string": "^1.1.1", - "is-symbol": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-builtin-type": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.2.1.tgz", - "integrity": "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==", - "dev": true, - "dependencies": { - "call-bound": "^1.0.2", - "function.prototype.name": "^1.1.6", - "has-tostringtag": "^1.0.2", - "is-async-function": "^2.0.0", - "is-date-object": "^1.1.0", - "is-finalizationregistry": "^1.1.0", - "is-generator-function": "^1.0.10", - "is-regex": "^1.2.1", - "is-weakref": "^1.0.2", - "isarray": "^2.0.5", - "which-boxed-primitive": "^1.1.0", - "which-collection": "^1.0.2", - "which-typed-array": "^1.1.16" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-collection": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", - "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", - "dev": true, - "dependencies": { - "is-map": "^2.0.3", - "is-set": "^2.0.3", - "is-weakmap": "^2.0.2", - "is-weakset": "^2.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-typed-array": { - "version": "1.1.20", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.20.tgz", - "integrity": "sha512-LYfpUkmqwl0h9A2HL09Mms427Q1RZWuOHsukfVcKRq9q95iQxdw0ix1JQrqbcDR9PH1QDwf5Qo8OZb5lksZ8Xg==", - "dev": true, - "dependencies": { - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.8", - "call-bound": "^1.0.4", - "for-each": "^0.3.5", - "get-proto": "^1.0.1", - "gopd": "^1.2.0", - "has-tostringtag": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/word-wrap": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", - "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/zod": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/zod/-/zod-4.4.3.tgz", - "integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==", - "funding": { - "url": "https://github.com/sponsors/colinhacks" - } - }, - "node_modules/zod-validation-error": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/zod-validation-error/-/zod-validation-error-4.0.2.tgz", - "integrity": "sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==", - "dev": true, - "engines": { - "node": ">=18.0.0" - }, - "peerDependencies": { - "zod": "^3.25.0 || ^4.0.0" - } - } - } -} diff --git a/Les12-Tool-Calling/polderfest-demo/package.json b/Les12-Tool-Calling/polderfest-demo/package.json deleted file mode 100644 index 2b8409f..0000000 --- a/Les12-Tool-Calling/polderfest-demo/package.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "name": "polderfest-demo", - "version": "0.1.0", - "private": true, - "scripts": { - "dev": "next dev", - "build": "next build", - "start": "next start", - "lint": "eslint" - }, - "dependencies": { - "@ai-sdk/openai": "^3.0.64", - "@ai-sdk/react": "^3.0.187", - "@supabase/supabase-js": "^2.106.0", - "ai": "^6.0.185", - "dotenv": "^17.4.2", - "next": "16.2.6", - "react": "19.2.4", - "react-dom": "19.2.4", - "zod": "^4.4.3" - }, - "devDependencies": { - "@tailwindcss/postcss": "^4", - "@types/node": "^20", - "@types/react": "^19", - "@types/react-dom": "^19", - "eslint": "^9", - "eslint-config-next": "16.2.6", - "tailwindcss": "^4", - "tsx": "^4.22.3", - "typescript": "^5" - } -} diff --git a/Les12-Tool-Calling/polderfest-demo/postcss.config.mjs b/Les12-Tool-Calling/polderfest-demo/postcss.config.mjs deleted file mode 100644 index 61e3684..0000000 --- a/Les12-Tool-Calling/polderfest-demo/postcss.config.mjs +++ /dev/null @@ -1,7 +0,0 @@ -const config = { - plugins: { - "@tailwindcss/postcss": {}, - }, -}; - -export default config; diff --git a/Les12-Tool-Calling/polderfest-demo/public/file.svg b/Les12-Tool-Calling/polderfest-demo/public/file.svg deleted file mode 100644 index 004145c..0000000 --- a/Les12-Tool-Calling/polderfest-demo/public/file.svg +++ /dev/null @@ -1 +0,0 @@ -<svg fill="none" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="M14.5 13.5V5.41a1 1 0 0 0-.3-.7L9.8.29A1 1 0 0 0 9.08 0H1.5v13.5A2.5 2.5 0 0 0 4 16h8a2.5 2.5 0 0 0 2.5-2.5m-1.5 0v-7H8v-5H3v12a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1M9.5 5V2.12L12.38 5zM5.13 5h-.62v1.25h2.12V5zm-.62 3h7.12v1.25H4.5zm.62 3h-.62v1.25h7.12V11z" clip-rule="evenodd" fill="#666" fill-rule="evenodd"/></svg> \ No newline at end of file diff --git a/Les12-Tool-Calling/polderfest-demo/public/globe.svg b/Les12-Tool-Calling/polderfest-demo/public/globe.svg deleted file mode 100644 index 567f17b..0000000 --- a/Les12-Tool-Calling/polderfest-demo/public/globe.svg +++ /dev/null @@ -1 +0,0 @@ -<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><g clip-path="url(#a)"><path fill-rule="evenodd" clip-rule="evenodd" d="M10.27 14.1a6.5 6.5 0 0 0 3.67-3.45q-1.24.21-2.7.34-.31 1.83-.97 3.1M8 16A8 8 0 1 0 8 0a8 8 0 0 0 0 16m.48-1.52a7 7 0 0 1-.96 0H7.5a4 4 0 0 1-.84-1.32q-.38-.89-.63-2.08a40 40 0 0 0 3.92 0q-.25 1.2-.63 2.08a4 4 0 0 1-.84 1.31zm2.94-4.76q1.66-.15 2.95-.43a7 7 0 0 0 0-2.58q-1.3-.27-2.95-.43a18 18 0 0 1 0 3.44m-1.27-3.54a17 17 0 0 1 0 3.64 39 39 0 0 1-4.3 0 17 17 0 0 1 0-3.64 39 39 0 0 1 4.3 0m1.1-1.17q1.45.13 2.69.34a6.5 6.5 0 0 0-3.67-3.44q.65 1.26.98 3.1M8.48 1.5l.01.02q.41.37.84 1.31.38.89.63 2.08a40 40 0 0 0-3.92 0q.25-1.2.63-2.08a4 4 0 0 1 .85-1.32 7 7 0 0 1 .96 0m-2.75.4a6.5 6.5 0 0 0-3.67 3.44 29 29 0 0 1 2.7-.34q.31-1.83.97-3.1M4.58 6.28q-1.66.16-2.95.43a7 7 0 0 0 0 2.58q1.3.27 2.95.43a18 18 0 0 1 0-3.44m.17 4.71q-1.45-.12-2.69-.34a6.5 6.5 0 0 0 3.67 3.44q-.65-1.27-.98-3.1" fill="#666"/></g><defs><clipPath id="a"><path fill="#fff" d="M0 0h16v16H0z"/></clipPath></defs></svg> \ No newline at end of file diff --git a/Les12-Tool-Calling/polderfest-demo/public/next.svg b/Les12-Tool-Calling/polderfest-demo/public/next.svg deleted file mode 100644 index 5174b28..0000000 --- a/Les12-Tool-Calling/polderfest-demo/public/next.svg +++ /dev/null @@ -1 +0,0 @@ -<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 394 80"><path fill="#000" d="M262 0h68.5v12.7h-27.2v66.6h-13.6V12.7H262V0ZM149 0v12.7H94v20.4h44.3v12.6H94v21h55v12.6H80.5V0h68.7zm34.3 0h-17.8l63.8 79.4h17.9l-32-39.7 32-39.6h-17.9l-23 28.6-23-28.6zm18.3 56.7-9-11-27.1 33.7h17.8l18.3-22.7z"/><path fill="#000" d="M81 79.3 17 0H0v79.3h13.6V17l50.2 62.3H81Zm252.6-.4c-1 0-1.8-.4-2.5-1s-1.1-1.6-1.1-2.6.3-1.8 1-2.5 1.6-1 2.6-1 1.8.3 2.5 1a3.4 3.4 0 0 1 .6 4.3 3.7 3.7 0 0 1-3 1.8zm23.2-33.5h6v23.3c0 2.1-.4 4-1.3 5.5a9.1 9.1 0 0 1-3.8 3.5c-1.6.8-3.5 1.3-5.7 1.3-2 0-3.7-.4-5.3-1s-2.8-1.8-3.7-3.2c-.9-1.3-1.4-3-1.4-5h6c.1.8.3 1.6.7 2.2s1 1.2 1.6 1.5c.7.4 1.5.5 2.4.5 1 0 1.8-.2 2.4-.6a4 4 0 0 0 1.6-1.8c.3-.8.5-1.8.5-3V45.5zm30.9 9.1a4.4 4.4 0 0 0-2-3.3 7.5 7.5 0 0 0-4.3-1.1c-1.3 0-2.4.2-3.3.5-.9.4-1.6 1-2 1.6a3.5 3.5 0 0 0-.3 4c.3.5.7.9 1.3 1.2l1.8 1 2 .5 3.2.8c1.3.3 2.5.7 3.7 1.2a13 13 0 0 1 3.2 1.8 8.1 8.1 0 0 1 3 6.5c0 2-.5 3.7-1.5 5.1a10 10 0 0 1-4.4 3.5c-1.8.8-4.1 1.2-6.8 1.2-2.6 0-4.9-.4-6.8-1.2-2-.8-3.4-2-4.5-3.5a10 10 0 0 1-1.7-5.6h6a5 5 0 0 0 3.5 4.6c1 .4 2.2.6 3.4.6 1.3 0 2.5-.2 3.5-.6 1-.4 1.8-1 2.4-1.7a4 4 0 0 0 .8-2.4c0-.9-.2-1.6-.7-2.2a11 11 0 0 0-2.1-1.4l-3.2-1-3.8-1c-2.8-.7-5-1.7-6.6-3.2a7.2 7.2 0 0 1-2.4-5.7 8 8 0 0 1 1.7-5 10 10 0 0 1 4.3-3.5c2-.8 4-1.2 6.4-1.2 2.3 0 4.4.4 6.2 1.2 1.8.8 3.2 2 4.3 3.4 1 1.4 1.5 3 1.5 5h-5.8z"/></svg> \ No newline at end of file diff --git a/Les12-Tool-Calling/polderfest-demo/public/vercel.svg b/Les12-Tool-Calling/polderfest-demo/public/vercel.svg deleted file mode 100644 index 7705396..0000000 --- a/Les12-Tool-Calling/polderfest-demo/public/vercel.svg +++ /dev/null @@ -1 +0,0 @@ -<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1155 1000"><path d="m577.3 0 577.4 1000H0z" fill="#fff"/></svg> \ No newline at end of file diff --git a/Les12-Tool-Calling/polderfest-demo/public/window.svg b/Les12-Tool-Calling/polderfest-demo/public/window.svg deleted file mode 100644 index b2b2a44..0000000 --- a/Les12-Tool-Calling/polderfest-demo/public/window.svg +++ /dev/null @@ -1 +0,0 @@ -<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path fill-rule="evenodd" clip-rule="evenodd" d="M1.5 2.5h13v10a1 1 0 0 1-1 1h-11a1 1 0 0 1-1-1zM0 1h16v11.5a2.5 2.5 0 0 1-2.5 2.5h-11A2.5 2.5 0 0 1 0 12.5zm3.75 4.5a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5M7 4.75a.75.75 0 1 1-1.5 0 .75.75 0 0 1 1.5 0m1.75.75a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5" fill="#666"/></svg> \ No newline at end of file diff --git a/Les12-Tool-Calling/polderfest-demo/scripts/seed-polderfest.ts b/Les12-Tool-Calling/polderfest-demo/scripts/seed-polderfest.ts deleted file mode 100644 index 0af987f..0000000 --- a/Les12-Tool-Calling/polderfest-demo/scripts/seed-polderfest.ts +++ /dev/null @@ -1,272 +0,0 @@ -/** - * Polderfest 2027 — seed script - * ---------------------------------------------------------- - * Genereert 500 fictieve bands en zet ze in je Supabase `bands` tabel. - * Run: - * 1. Zorg dat `bands` tabel bestaat (zie schema.sql) - * 2. Vul .env.local met: - * SUPABASE_URL=https://<project>.supabase.co - * SUPABASE_SERVICE_ROLE_KEY=<service role key> - * 3. npm i @supabase/supabase-js dotenv tsx --save-dev - * 4. npx tsx seed-polderfest.ts - * - * Service role key is bewust nodig — alleen voor lokaal seeden. - * NIET committen, NIET in client gebruiken. - */ - -import { createClient } from "@supabase/supabase-js"; -import dotenv from "dotenv"; - -// Laad .env.local (i.p.v. default .env) -dotenv.config({ path: ".env.local" }); - -const SUPABASE_URL = - process.env.NEXT_PUBLIC_SUPABASE_URL ?? process.env.SUPABASE_URL; -const SUPABASE_SERVICE_ROLE_KEY = process.env.SUPABASE_SERVICE_ROLE_KEY; - -if (!SUPABASE_URL || !SUPABASE_SERVICE_ROLE_KEY) { - console.error( - "Ontbrekende env vars. Check .env.local:\n" + - " NEXT_PUBLIC_SUPABASE_URL=https://<project>.supabase.co\n" + - " SUPABASE_SERVICE_ROLE_KEY=<service role key>" - ); - process.exit(1); -} - -const supabase = createClient(SUPABASE_URL, SUPABASE_SERVICE_ROLE_KEY, { - auth: { persistSession: false }, -}); - -// ──────────────────────────────────────────────────────────── -// Deterministische random (zodat seed reproduceerbaar is) -// ──────────────────────────────────────────────────────────── -let seed = 42; -function rand() { - seed = (seed * 9301 + 49297) % 233280; - return seed / 233280; -} -function pick<T>(arr: readonly T[]): T { - return arr[Math.floor(rand() * arr.length)]; -} -function pickN<T>(arr: readonly T[], n: number): T[] { - const copy = [...arr]; - const out: T[] = []; - for (let i = 0; i < n && copy.length; i++) { - out.push(copy.splice(Math.floor(rand() * copy.length), 1)[0]); - } - return out; -} -function range(min: number, max: number): number { - return Math.floor(rand() * (max - min + 1)) + min; -} - -// ──────────────────────────────────────────────────────────── -// Bouwstenen voor band-namen -// ──────────────────────────────────────────────────────────── -const adjectives = [ - "Lost", "Velvet", "Iron", "Neon", "Silent", "Wild", "Glass", "Paper", "Sleeping", - "Honest", "Crooked", "Bitter", "Sweet", "Drowsy", "Drowning", "Restless", "Sober", - "Midnight", "Morning", "Yellow", "Crimson", "Hollow", "Heavy", "Floating", "Slow", - "Burning", "Frozen", "Cardboard", "Plastic", "Analog", "Digital", "Forgotten", -] as const; - -const nouns = [ - "Tigers", "Wolves", "Horses", "Rabbits", "Mirrors", "Clouds", "Echoes", "Ghosts", - "Lights", "Roots", "Stones", "Foxes", "Riders", "Ships", "Tides", "Anchors", - "Maps", "Letters", "Postcards", "Radios", "Telegrams", "Diaries", "Highways", - "Cassettes", "Polaroids", "Cathedrals", "Stations", "Lanterns", "Compasses", - "Saturdays", "Tuesdays", "Mondays", -] as const; - -const dutchPrefixes = [ - "De", "Het", "Van der", "Polder", "Noord", "Zuid", -] as const; - -const soloNamesFirst = [ - "Sanne", "Joost", "Yara", "Lex", "Mila", "Tess", "Bram", "Lotte", "Ravi", "Imani", - "Marit", "Stijn", "Liva", "Noor", "Casper", "Anouk", "Mees", "Pien", "Daan", "Olivia", - "Niels", "Fenna", "Tygo", "Saar", "Cas", "Maud", "Roos", "Vince", "Lieke", "Floris", -] as const; - -const soloNamesLast = [ - "Van Dijk", "De Boer", "Visser", "Jansen", "Bakker", "Hendriks", "Mulder", "Smit", - "Peters", "De Vries", "Kuipers", "Brouwer", "Postma", "Hofman", "Van Loon", -] as const; - -// ──────────────────────────────────────────────────────────── -// Fest-velden -// ──────────────────────────────────────────────────────────── -const genres = [ - "Indie Rock", "Electronic", "Hip-Hop", "Jazz Fusion", "Folk", "Punk", "Soul", - "Ambient", "Disco-House", "Experimental", "Singer-Songwriter", "Synth-Pop", - "Garage Rock", "Neo-Soul", "Drum & Bass", "Afrobeat", "Dream Pop", "Post-Rock", -] as const; - -const subGenresByGenre: Record<string, string[]> = { - "Indie Rock": ["Shoegaze", "Lo-Fi", "Math Rock", "Slowcore"], - "Electronic": ["Techno", "House", "IDM", "Glitch", "Trance"], - "Hip-Hop": ["Boom Bap", "Trap", "Lo-Fi", "Conscious"], - "Jazz Fusion": ["Funk Jazz", "Cosmic Jazz", "Nu-Jazz"], - "Folk": ["Anti-Folk", "Sea Shanty", "Modern Folk"], - "Punk": ["Post-Punk", "Hardcore", "Surf Punk"], - "Soul": ["Neo-Soul", "Northern Soul", "Funk"], - "Ambient": ["Drone", "New Age", "Field Recording"], - "Disco-House": ["Italo Disco", "Nu-Disco", "French House"], - "Experimental": ["Noise", "Sound Art", "Avantgarde"], - "Singer-Songwriter": ["Confessional", "Storytelling"], - "Synth-Pop": ["Vaporwave", "Italo", "Darkwave"], - "Garage Rock": ["Surf", "Power Pop"], - "Neo-Soul": ["Alt R&B", "Jazz-influenced"], - "Drum & Bass": ["Liquid", "Jungle", "Neurofunk"], - "Afrobeat": ["Afro-Fusion", "Highlife"], - "Dream Pop": ["Bedroom Pop", "Ethereal"], - "Post-Rock": ["Cinematic", "Math-influenced"], -}; - -const stages = [ - "Main Stage", "Tent Stage", "Beach Stage", "Acoustic Bar", "Late Night Tent", -] as const; - -const days = ["Vrijdag", "Zaterdag", "Zondag"] as const; - -const timeSlots = [ - "14:00", "15:30", "17:00", "18:30", "20:00", "21:30", "23:00", "00:30", -] as const; - -const cities = [ - "Amsterdam", "Rotterdam", "Utrecht", "Groningen", "Eindhoven", "Den Haag", - "Tilburg", "Maastricht", "Nijmegen", "Leeuwarden", "Arnhem", "Breda", "Haarlem", - "Zwolle", "Enschede", "Delft", "Den Bosch", "Apeldoorn", -] as const; - -const tiers = ["headliner", "mid", "opener"] as const; - -// ──────────────────────────────────────────────────────────── -// Bio-fragmenten — combinatorisch zodat 500 bios uniek voelen -// ──────────────────────────────────────────────────────────── -const bioOpenings = [ - "Begonnen in een garage in", - "Ontstaan tijdens een blackout in", - "Een vriendengroep uit", - "Doorgebroken op het kleine podium van", - "Geboren uit een jam-sessie in", - "Een collectief van producers uit", -]; -const bioMiddle = [ - "experimenteert met analoge synths en gefluisterde lyrics", - "balanceert tussen melancholie en dansvloer-euforie", - "mixt traditionele samples met breakbeats", - "gebruikt veldopnames als ritmesectie", - "schrijft songs in Nederlands en Engels door elkaar", - "speelt instrumenten die ze grotendeels zelf hebben gebouwd", - "draait alleen optredens op locaties zonder Wi-Fi", -]; -const bioEnding = [ - "Debuut-EP verschijnt eind 2027.", - "Hun laatste album werd genomineerd voor de fictieve Edison Polder Award.", - "Polderfest is hun grootste festival tot nu toe.", - "Vorig jaar speelden ze nog in cafés, dit jaar op Stage B.", - "Spelen voor het eerst op een buitenpodium.", - "Beruchte live-show met 12 backing vocalists.", -]; - -// ──────────────────────────────────────────────────────────── -// Namen genereren -// ──────────────────────────────────────────────────────────── -function generateBandName(seedIdx: number): string { - const pattern = seedIdx % 4; - if (pattern === 0) { - return `${pick(adjectives)} ${pick(nouns)}`; - } - if (pattern === 1) { - return `${pick(dutchPrefixes)} ${pick(nouns)}`; - } - if (pattern === 2) { - return `${pick(soloNamesFirst)} ${pick(soloNamesLast)}`; - } - return `${pick(soloNamesFirst)} & The ${pick(nouns)}`; -} - -function generateMembers(): string[] { - const count = range(1, 5); - const out: string[] = []; - for (let i = 0; i < count; i++) { - out.push(`${pick(soloNamesFirst)} ${pick(soloNamesLast)}`); - } - return out; -} - -function generateBio(name: string): string { - return `${pick(bioOpenings)} ${pick(cities)}, ${name} ${pick(bioMiddle)}. ${pick(bioEnding)}`; -} - -// ──────────────────────────────────────────────────────────── -// Hoofdfunctie -// ──────────────────────────────────────────────────────────── -async function runSeed() { - console.log("Genereren van 500 Polderfest bands..."); - - // Wipe bestaande data (optioneel) - await supabase.from("bands").delete().neq("id", 0); - - const bands = []; - const usedNames = new Set<string>(); - - for (let i = 0; i < 500; i++) { - let name = generateBandName(i); - let attempts = 0; - while (usedNames.has(name) && attempts < 10) { - name = generateBandName(i + attempts * 7); - attempts++; - } - usedNames.add(name); - - const genre = pick(genres); - const sub_genre = pick(subGenresByGenre[genre]); - const tier = pick(tiers); - const popularity = tier === "headliner" ? range(80, 100) - : tier === "mid" ? range(40, 79) - : range(10, 39); - const ticket_impact = tier === "headliner" ? range(25, 60) - : tier === "mid" ? range(5, 25) - : 0; - - bands.push({ - name, - genre, - sub_genre, - stage: pick(stages), - day: pick(days), - start_time: pick(timeSlots), - duration_min: tier === "headliner" ? range(75, 120) - : tier === "mid" ? range(45, 75) - : range(30, 45), - origin_city: pick(cities), - members: generateMembers(), - bio: generateBio(name), - tier, - popularity, - ticket_impact, - }); - } - - console.log("Schrijven naar Supabase in batches van 100..."); - - // Supabase insert in batches (single call van 500 kan timeouten) - for (let i = 0; i < bands.length; i += 100) { - const batch = bands.slice(i, i + 100); - const { error } = await supabase.from("bands").insert(batch); - if (error) { - console.error("Insert error op batch", i / 100, ":", error.message); - process.exit(1); - } - console.log(` ✓ ${i + batch.length}/${bands.length}`); - } - - console.log("Klaar! 500 Polderfest bands staan in Supabase."); -} - -runSeed().catch((e) => { - console.error(e); - process.exit(1); -}); diff --git a/Les12-Tool-Calling/polderfest-demo/tsconfig.json b/Les12-Tool-Calling/polderfest-demo/tsconfig.json deleted file mode 100644 index 3a13f90..0000000 --- a/Les12-Tool-Calling/polderfest-demo/tsconfig.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2017", - "lib": ["dom", "dom.iterable", "esnext"], - "allowJs": true, - "skipLibCheck": true, - "strict": true, - "noEmit": true, - "esModuleInterop": true, - "module": "esnext", - "moduleResolution": "bundler", - "resolveJsonModule": true, - "isolatedModules": true, - "jsx": "react-jsx", - "incremental": true, - "plugins": [ - { - "name": "next" - } - ], - "paths": { - "@/*": ["./*"] - } - }, - "include": [ - "next-env.d.ts", - "**/*.ts", - "**/*.tsx", - ".next/types/**/*.ts", - ".next/dev/types/**/*.ts", - "**/*.mts" - ], - "exclude": ["node_modules"] -} diff --git a/Les12-Tool-Calling/tools-demo.ts b/Les12-Tool-Calling/tools-demo.ts deleted file mode 100644 index aa5459e..0000000 --- a/Les12-Tool-Calling/tools-demo.ts +++ /dev/null @@ -1,246 +0,0 @@ -/** - * Polderfest Tool-Calling demo — reference snippets (AI SDK v6) - * -------------------------------------------------- - * Dit zijn de tools die we live opbouwen tijdens Les 12. - * Matcht met de actuele stack van polderfest-demo: - * - ai@^6 - * - @ai-sdk/openai@^3 - * - @ai-sdk/react@^3 - * - * Gebruik dit als naslag — niet 1-op-1 kopiëren tijdens demo. - * Plek in project: app/api/chat/route.ts - */ - -import { - convertToModelMessages, - stepCountIs, - streamText, - tool, - type UIMessage, -} from "ai"; -import { openai } from "@ai-sdk/openai"; -import { createClient } from "@supabase/supabase-js"; -import { z } from "zod"; - -const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL!; -const supabaseKey = - process.env.SUPABASE_SERVICE_ROLE_KEY ?? - process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!; -const supabase = createClient(supabaseUrl, supabaseKey); - -// ──────────────────────────────────────────────────────────── -// Tool 1: searchBands — filter op velden -// ──────────────────────────────────────────────────────────── -const searchBands = tool({ - description: - "Zoek bands in de Polderfest line-up. Filter op dag, stage, genre of tier. " + - "Gebruik dit als de gebruiker iets zoekt op één of meerdere criteria.", - inputSchema: z.object({ - day: z - .enum(["Vrijdag", "Zaterdag", "Zondag"]) - .optional() - .describe("Festival-dag"), - stage: z - .string() - .optional() - .describe("Bv. Main Stage, Tent Stage, Beach Stage, Acoustic Bar, Late Night Tent"), - genre: z - .string() - .optional() - .describe("Bv. Indie Rock, Electronic, Hip-Hop, Jazz Fusion"), - tier: z.enum(["headliner", "mid", "opener"]).optional(), - minPopularity: z - .number() - .min(1) - .max(100) - .optional() - .describe("Minimale populariteit (1-100)"), - }), - execute: async ({ day, stage, genre, tier, minPopularity }) => { - let q = supabase - .from("bands") - .select( - "id, name, genre, sub_genre, stage, day, start_time, " + - "origin_city, tier, popularity, bio", - ); - if (day) q = q.eq("day", day); - if (stage) q = q.eq("stage", stage); - if (genre) q = q.eq("genre", genre); - if (tier) q = q.eq("tier", tier); - if (minPopularity) q = q.gte("popularity", minPopularity); - - const { data, error } = await q.limit(20); - if (error) return { error: error.message }; - return { count: data.length, bands: data }; - }, -}); - -// ──────────────────────────────────────────────────────────── -// Tool 2: getBandByName — exacte lookup -// ──────────────────────────────────────────────────────────── -const getBandByName = tool({ - description: - "Haal alle details op van één specifieke band, inclusief members en bio. " + - "Gebruik dit als de gebruiker naar een specifieke band vraagt.", - inputSchema: z.object({ - name: z.string().describe("Exacte band-naam"), - }), - execute: async ({ name }) => { - const { data, error } = await supabase - .from("bands") - .select("*") - .ilike("name", name) - .single(); - if (error) return { error: `Band '${name}' niet gevonden.` }; - return data; - }, -}); - -// ──────────────────────────────────────────────────────────── -// Tool 3: getStats — aggregate over alle bands -// ──────────────────────────────────────────────────────────── -const getStats = tool({ - description: - "Geef statistieken over de festival-line-up — totaal aantal bands, " + - "verdeling per genre, per dag, of per stage. Geen filters — overzicht.", - inputSchema: z.object({ - groupBy: z - .enum(["genre", "day", "stage", "tier"]) - .describe("Hoe te groeperen"), - }), - execute: async ({ groupBy }) => { - const { data, error } = await supabase.from("bands").select(groupBy); - if (error) return { error: error.message }; - - const counts: Record<string, number> = {}; - for (const row of data) { - const key = row[groupBy as keyof typeof row] as string; - counts[key] = (counts[key] ?? 0) + 1; - } - return { total: data.length, counts }; - }, -}); - -// ──────────────────────────────────────────────────────────── -// Tool 4: getScheduleByDay — slot-overzicht -// ──────────────────────────────────────────────────────────── -const getScheduleByDay = tool({ - description: - "Geef het volledige tijdschema voor één festival-dag. " + - "Bands gesorteerd op tijdslot. Handig voor 'wat speelt er om 22:00?'", - inputSchema: z.object({ - day: z.enum(["Vrijdag", "Zaterdag", "Zondag"]), - stage: z - .string() - .optional() - .describe("Optioneel filteren op specifieke stage"), - }), - execute: async ({ day, stage }) => { - let q = supabase - .from("bands") - .select("name, stage, start_time, duration_min, tier") - .eq("day", day); - if (stage) q = q.eq("stage", stage); - const { data, error } = await q.order("start_time", { ascending: true }); - if (error) return { error: error.message }; - return data; - }, -}); - -// ──────────────────────────────────────────────────────────── -// Tool 5 (write): addFavorite — user_favorites tabel -// ──────────────────────────────────────────────────────────── -const addFavorite = tool({ - description: - "Voeg een band toe aan de favorieten van de gebruiker. " + - "Gebruik alleen als de gebruiker expliciet vraagt 'voeg X toe aan mijn favorieten'.", - inputSchema: z.object({ - userEmail: z.string().email().describe("Email van de gebruiker"), - bandName: z.string().describe("Exacte band-naam"), - }), - execute: async ({ userEmail, bandName }) => { - const { data: band } = await supabase - .from("bands") - .select("id") - .ilike("name", bandName) - .single(); - if (!band) return { error: `Band '${bandName}' niet gevonden.` }; - - const { error } = await supabase - .from("user_favorites") - .insert({ user_email: userEmail, band_id: band.id }); - if (error) return { error: error.message }; - return { success: true, bandName, bandId: band.id }; - }, -}); - -// ──────────────────────────────────────────────────────────── -// Tool 6 (read): listFavorites -// ──────────────────────────────────────────────────────────── -const listFavorites = tool({ - description: "Geef de favoriete bands van de gebruiker.", - inputSchema: z.object({ - userEmail: z.string().email(), - }), - execute: async ({ userEmail }) => { - const { data, error } = await supabase - .from("user_favorites") - .select("bands(name, genre, day, start_time, stage)") - .eq("user_email", userEmail); - if (error) return { error: error.message }; - return data?.map((r) => r.bands) ?? []; - }, -}); - -// ──────────────────────────────────────────────────────────── -// De chat-route met alle tools -// ──────────────────────────────────────────────────────────── -export async function POST(req: Request) { - try { - const { messages }: { messages: UIMessage[] } = await req.json(); - - const system = `Je bent een festival-assistent voor Polderfest 2027. -Je hebt toegang tot tools om de bands-database te bevragen. Gebruik altijd -tools voor concrete vragen — verzin nooit data. Antwoord beknopt en in -het Nederlands. - -Tips: -- Voor "welke bands op X?" → searchBands -- Voor specifieke band → getBandByName -- Voor "hoeveel" / "verdeling" → getStats -- Voor tijdschema → getScheduleByDay -- Voor favorieten → addFavorite / listFavorites - -Als een tool een error returnt, leg dat netjes uit aan de gebruiker.`; - - const result = streamText({ - model: openai("gpt-4o-mini"), - system, - messages: await convertToModelMessages(messages), - tools: { - searchBands, - getBandByName, - getStats, - getScheduleByDay, - addFavorite, - listFavorites, - }, - stopWhen: stepCountIs(5), - }); - - return result.toUIMessageStreamResponse({ - onError(error: unknown) { - if (error == null) return "unknown error"; - if (typeof error === "string") return error; - if (error instanceof Error) return error.message; - return JSON.stringify(error); - }, - }); - } catch (err) { - const message = err instanceof Error ? err.message : "Unknown error"; - return Response.json( - { error: "Chat route failed", details: message }, - { status: 500 }, - ); - } -} diff --git a/Les13-Cursor-Vercel-Deploy/Les13-Docenttekst.md b/Les13-Cursor-Vercel-Deploy/Les13-Docenttekst.md index 0c64c27..4206f4e 100644 --- a/Les13-Cursor-Vercel-Deploy/Les13-Docenttekst.md +++ b/Les13-Cursor-Vercel-Deploy/Les13-Docenttekst.md @@ -1,539 +1,455 @@ -# Les 13 — Externe APIs + Cursor + Vercel -## Docenttekst (Klas A — 3 uur, fysiek, demo-driven) +# Les 13 — Docenttekst (Autocue) -**Les:** 14 van 18 -**Onderwerp:** Externe APIs + Cursor agents (Composer + Background) + Vercel preview deploys + GitHub Actions CI -**Duur:** 180 minuten -**Format:** Tim demonstreert klassikaal. Studenten kijken mee. Zelf bouwen = huiswerk. -**Demo-app:** Pokédex (PokéAPI, geen key, visueel) — nieuwe kleine app +**Online les — letterlijk voorleesbaar. Slide-nummers staan tussen `[SLIDE N]` zodat je weet wanneer door te klikken.** + +**Lesvorm:** online, demo-driven. Cursor + browser side-by-side delen. +**Duur:** 180 minuten met 1 pauze van 15 minuten. + +> **Voor de les klaarzetten:** +> - Cursor open in lege werkmap +> - Browser tabs open: github.com, vercel.com, pokeapi.co +> - Terminal klaar +> - Cursor Pro/Business actief (voor Background Agent) +> - GitHub + Vercel ingelogd +> - Webcam check + scherm delen ingericht --- -## Hoe deze tekst werkt - -- `[SLIDE X]` — klik naar slide X -- `[SCHERM: slides | cursor | terminal | browser | github | vercel]` — welk venster op de beamer -- **Vertel:** "..." — wat je zegt (mag eigen woorden) -- `*[stage direction]*` — instructie voor jezelf -- 💬 = verwachte studentenvraag - ---- - -## VÓÓR DE LES — Setup (60 min) - -### 1. Cursor versie checken - -- Cursor moet `>=0.45` zijn voor Background Agents -- Pro account aktief (Tim's eigen) — Background Agents zitten daar in -- Test: `Cmd+Shift+P` → "Open Background Agent" zichtbaar in command palette -- Login bij Cursor cloud — eenmalige flow - -### 2. Vercel + GitHub klaar - -- Vercel account (Tim's eigen) — gekoppeld aan GitHub -- Test repo: maak vooraf 1 dummy-repo aan (om snel te kunnen demonstreren als demo crasht) -- Bookmark: vercel.com/dashboard, github.com/USER - -### 3. Demo-app vooraf gemaakt (backup) - -- Werkende `pokedex-demo` lokaal + op GitHub + op Vercel -- Als live coding faalt: switch hier naartoe, vertel "dit is hoe het er eindelijk uitziet" - -### 4. Folder & terminal-tabs - -- Werk-folder: `~/novi/novi-lessons/Les13-Cursor-Vercel-Deploy/live` -- 3 terminal tabs: project root, git-watcher (`watch git status`), Vercel CLI -- Cursor open met empty folder klaar -- Browser tabs vooraf open: - - https://pokeapi.co/ - - https://vercel.com/dashboard - - https://github.com (jouw user) - - https://docs.cursor.com/background-agent (referentie) - -### 5. Internet check - -- Background Agents werken alleen met goede verbinding -- Vercel deploys ook -- Backup hotspot indien WiFi gisteren rare dingen deed - -### 6. Backup screenshots - -Heb klaar voor als demo faalt: -- Cursor Background Agent UI (run completed) -- GitHub PR met Vercel comment -- Vercel preview deploy -- GitHub Actions groene check -- Branch protection settings page - ---- - -# HET SCRIPT — Lees mee tijdens de les - ## BLOK 1 — Welkom + Terugblik (10 min) -`[SLIDE 1 — Title]` `[SCHERM: slides]` +`[SLIDE 1]` -**Vertel:** "Welkom bij les 14. Vandaag gaan we van localhost de wereld in. Externe APIs, Vercel, Cursor's coding agents, GitHub Actions CI. Heel hands-on." +Welkom bij Les 13. Vandaag is een belangrijke les, want we verlaten voor het eerst je laptop. -`[SLIDE 2 — Terugblik]` +Tot nu toe draaiden al jullie projecten op `localhost:3000`. Dat is prima om te leren, maar in de praktijk wil je dat anderen je werk kunnen zien. Klanten. Collega's. Werkgevers. Vandaag zetten we die stap. -**Vertel:** "Lessen 11 t/m 13 gingen over AI: SDK, tools, agents. Alles draaide op jouw laptop. Dat was prima om te leren, maar in het echt deploy je iets en wil je dat anderen het kunnen gebruiken. +We gaan drie dingen leren die je voor elk professioneel project nodig hebt. Eén: data ophalen van externe websites en APIs. Twee: je code automatisch online zetten via Vercel. Drie: efficiënt werken met Cursor agents. -Vandaag drie dingen tegelijk. Een — externe APIs aanroepen. Geen LLM, gewoon data ophalen. Twee — die app naar Vercel. Drie — Cursor's twee agent-modes leren kennen en daarmee feature branches openen die automatisch preview-URLs krijgen op Vercel." +Aan het einde van deze les heb je een live URL die je aan iedereen kunt delen. -`[SLIDE 3 — Planning]` +`[SLIDE 2]` -**Vertel:** "Drie uur. Eerst 45 minuten theorie verdeeld over de drie onderwerpen. Daarna vier demos. Pauze rond minuut 90. Tot slot lesopdracht en huiswerk." +Even kort terug. In de afgelopen lessen hebben we gewerkt aan AI-features. Les 11 was de Vercel AI SDK, Les 12 was Tool Calling. Allemaal mooi, maar steeds lokaal. + +Vandaag stappen we even uit dat AI-pad. Geen LLM's. Geen API keys voor AI. We gaan terug naar de basis: hoe ziet een professionele Next.js-workflow eruit van localhost tot productie? + +We gebruiken een eenvoudige Pokédex als demo-app. Waarom Pokémon? Omdat de PokéAPI gratis is, geen API key vraagt, en je krijgt direct visuele resultaten. Perfect om je te focussen op de workflow, niet op de data. + +`[SLIDE 3]` + +Dit is de planning voor vandaag. Honderdtachtig minuten. + +We beginnen met theorie. Drie blokken van een kwartier: externe APIs in Next.js, Vercel met preview-omgevingen, en Cursor agents. + +Dan vier live demo's. In demo één bouwen we de Pokédex met Composer. In demo twee deployen we naar Vercel en zetten we environment variables in. Na de pauze: demo drie met de Background Agent om een feature parallel te bouwen. Demo vier: GitHub Actions om CI in te richten. + +Na elke demo bouw je het zelf na in je eigen repo. Vragen tussendoor altijd welkom — typ ze in de chat. --- -## BLOK 2 — Theorie Externe APIs (15 min) +## BLOK 2 — Theorie: Externe APIs (15 min) -`[SLIDE 4 — Wat is een externe API]` +`[SLIDE 4]` -**Vertel:** "Een externe API is een HTTP-endpoint van iemand anders. Je doet `fetch()`, je krijgt JSON. Klaar. Dat is het idee. +Wat is een externe API. In simpele woorden: andere mensen of bedrijven hebben data of functionaliteit, en die stellen ze beschikbaar via HTTP. Jij doet een fetch-request, krijgt JSON terug, en kunt daar dingen mee doen. -Drie smaken qua authenticatie. Geen key — PokéAPI en Open-Meteo bijvoorbeeld. Met key — Tavily, TMDB, de meeste paid APIs. OAuth — Google, GitHub user-data, dat is complexer. +Een paar voorbeelden van APIs die je in projecten zult tegenkomen. -In Next.js fetch je op twee plekken. Server-side, in een Server Component of API route. Of client-side, met `useEffect`. Server-side is bijna altijd beter voor initial data. Je key blijft veilig, het is gecached, en sneller." +PokéAPI — onze demo van vandaag. Pokemon-data, geen key nodig. -`[SLIDE 5 — Code]` +Open-Meteo — gratis weerservice, ook geen key. -**Vertel:** "Code voorbeeld. Server Component is `async`. Doe `fetch`, parse als JSON, return. Met `next: { revalidate: 3600 }` zegt je tegen Next.js: cache dit een uur. Eerste user triggert de fetch, de volgende honderd users krijgen de gecachte versie. Schaalbaar zonder dat je iets hoeft te doen. +GitHub API — informatie over repositories, gebruikers, issues. -💬 *Vraag: 'Wanneer client-side?'* +Tavily — web search. Die heeft wél een API key nodig. -**Antwoord:** "Bij user-interactie. Een zoekbalk waar je live filtert — moet client-side, want de input verandert in de browser. Real-time updates, polling — client-side. Maar de eerste page-load: server-side." +Stripe — betalingen. Twee keys: een publishable en een secret. + +Voor APIs met een key onthoud je één regel: nooit, ooit, in je code committen. Altijd in environment variables. Hier komen we straks bij Vercel uitgebreid op terug. + +`[SLIDE 5]` + +Dit is misschien wel de belangrijkste slide van vandaag. Drie manieren om een API te fetchen in Next.js. Static, server, of client. Welke je kiest hangt af van je use case. + +Eerste optie: **static**. De fetch gebeurt tijdens `next build`. Eén keer, en daarna is het HTML. Snel, want geen server-werk per request. Goed voor data die zelden verandert: een blog-post, een marketing-pagina, een lijst van producten. + +Tweede optie: **server, oftewel dynamic**. De fetch gebeurt bij elke request opnieuw. Altijd vers, maar trager. Goed voor data die per gebruiker anders is, of die altijd up-to-date moet zijn. + +Derde optie: **ISR**, Incremental Static Regeneration. Een mix van de twee. Wordt gecached zoals static, maar elke X seconden mag Next.js de cache vervangen. Het beste van beide werelden. Voor onze Pokédex de juiste keuze voor de detail-pagina's: snel, maar elk uur kijkt Next.js of de PokéAPI iets nieuws heeft. + +Vierde optie: **client-side fetching**, met useEffect. Dit doe je alleen als de data live moet, of als je user-interactie nodig hebt. Belangrijk: bij client-side staat je API key in de browser. Dus alleen voor publieke APIs of voor data die geen geheim is. + +Kijk naar het code-blokje onderaan. Het verschil tussen die drie server-modes is letterlijk één optie in je fetch-call. Verder verandert je code helemaal niet. Dat is de kracht van Next.js: je kiest het render-gedrag per fetch. + +Vandaag gebruiken we static voor de Pokédex-lijst en ISR voor de detail-pages. --- -## BLOK 3 — Theorie Cursor Agents (15 min) +## BLOK 3 — Theorie: Vercel + Cursor + GitHub (15 min) -`[SLIDE 6 — Composer vs Background]` +`[SLIDE 6]` -**Vertel:** "Cursor heeft TWEE soorten agents. Niet hetzelfde. Niet uitwisselbaar. Vandaag gaan we beide doen. +Korte sidetrack — straks komen we terug op Vercel. Even Cursor: twee soorten agents. -Composer. `Cmd+I`. Lokaal in je editor. Jij wacht, agent werkt, je ziet de diffs verschijnen. Je accepteert per file. Synchroon — je bent erbij. Dit is pair programming. +Composer is de agent die je al kent. Cmd+I openen, prompt typen, hij maakt aanpassingen in je editor. Synchroon. Jij wacht, hij werkt, jij kijkt, je accepteert de diff. Pair programming. -Background Agent. `Cmd+Shift+P` → 'Open Background Agent'. Runt in Cursor's cloud, niet jouw machine. Je geeft een prompt, gaat iets anders doen, komt terug. De agent maakt een branch, doet commits, opent een PR op GitHub. Asynchroon — je hoeft er niet bij te zijn. +Background Agent is anders. Die draait in Cursor's cloud. Je geeft een opdracht, hij gaat aan de slag, hij maakt een branch, hij pusht naar GitHub, hij opent een Pull Request. Allemaal terwijl jij iets anders doet. Asynchroon dus. -Het verschil zit in waar je bent in je workflow. Composer voor exploreren, voor pair-programming, voor 'ik wil even meekijken'. Background Agent voor 'ik weet wat ik wil, voer maar uit terwijl ik vergader'." +Het verschil komt straks duidelijk in de demo. Voor nu: onthoud dat je twee modes hebt. Eén voor naast je, één voor namens je. -💬 *Vraag: 'Kost Background Agent geld?'* +`[SLIDE 7]` -**Antwoord:** "Ja, zit in Cursor Pro. Twintig dollar per maand. Hobby-tier — gratis Cursor — heeft alleen Composer. Voor de huiswerk-opdracht: trial van Pro werkt prima, of vraag credits via Cursor support voor studenten." +Nu Vercel. Dit is het hart van de les. Drie omgevingen, drie scopes — en het is cruciaal dat je dit begrijpt. -💬 *Vraag: 'Hoe vergelijkt dit met Claude Code of OpenCode?'* +Productie is de live versie. Wordt gedeployed elke keer dat je naar de `main` branch pusht. URL is `je-app.vercel.app`. Dit ziet iedereen. -**Antwoord:** "Allemaal coding agents, allemaal goed. Cursor's Background Agent is uniek in dat-ie autonoom een PR opent — Claude Code en OpenCode draaien lokaal en doen geen PR-flow zelf. Het hangt af van je workflow. We zien beide in deze les." +Preview is wat je krijgt voor élke andere branch. Push naar `feature/search` en je krijgt automatisch een URL terug. Iets als `je-app-git-feature-search-jouwnaam.vercel.app`. Ook publiek bereikbaar, maar alleen mensen met de link. + +Development is je lokale `pnpm dev` op localhost. Alleen jij ziet dat. + +Nu de belangrijke vraag: hoe ga je daar mee om als je verschillende databases, of verschillende API keys hebt per omgeving? Want dat wil je. Je wilt absoluut niet dat een experimentele preview-branch in je productie-database gaat schrijven. + +Bekijk de tabel met environment variables. In Vercel ga je naar Project, Settings, Environment Variables. En daar zet je per variabele drie keer een waarde. Voor productie. Voor preview. En voor development. + +Een paar voorbeelden. Je `DATABASE_URL` is voor productie je echte database. Voor preview een staging-database. Voor development je lokale Postgres. Drie totaal verschillende waarden, één variabele-naam. + +Je `OPENAI_API_KEY` is in productie de echte key met hoge limit. In preview een test-key zodat experimenten je niet failliet maken. In development je persoonlijke key. + +Voor Stripe heel concreet: productie is `sk_live_...`, preview en development zijn allebei `sk_test_...`. Een experiment dat per ongeluk een betaling doet komt nooit op een echte creditcard. + +Onderaan staat één killer-combo: Cursor Background Agent maakt een Pull Request, Vercel ziet die PR en bouwt automatisch een preview URL, die URL komt automatisch in een comment op de PR. Reviewer klikt, opent in de browser, test live. Geen lokale setup nodig. Dit is voor mij persoonlijk een van de redenen dat ik altijd met Vercel werk. + +`[SLIDE 8]` + +GitHub Actions, snel. Waarom: voordat je iets merget, weet je zeker dat de code lint en bouwt op een schone machine. Niet "het werkt op mijn laptop", maar "het werkt op een verse ubuntu". Belangrijk omdat Background Agents soms lint-errors maken — CI vangt dat op. + +Kijk naar het code-blok. Een minimale workflow. Bij elke pull request en bij elke push naar main: checkout, pnpm install, pnpm lint, pnpm build. Duurt ongeveer twee minuten op een kleine app. + +In demo vier gaan we dit bouwen. --- -## BLOK 4 — Theorie Vercel + CI (15 min) +## BLOK 4 — Wat we vandaag bouwen (5 min) -`[SLIDE 7 — Vercel preview deploys]` +`[SLIDE 9]` -**Vertel:** "Vercel is hosting platform van de Next.js-makers. Voor Next.js apps de simpelste deploy ter wereld. Push naar GitHub, een minuut later: live. +Dit is wat we vandaag bouwen. Een Pokédex. -Het magische zit in **preview deploys**. Elke branch krijgt automatisch een eigen URL. Niet alleen `main` — letterlijk elke. Push naar `feature/search` → `je-app-git-feature-search-user.vercel.app` is live. PR's krijgen een comment met de URL. +De stack: Next.js 16 met TypeScript en Tailwind. Geen Shadcn vandaag, we houden het simpel. PokéAPI als data-bron, geen API key. Cursor voor de code. GitHub voor de versie-controle. Vercel voor de deploys. -Waarom is dit zo krachtig? Background Agent maakt een PR — preview URL is direct klikbaar. Reviewer test de feature live, niet alleen code-diff. Stakeholders kunnen iets zien. Geen 'werkt op mijn laptop'-discussies meer. +Vier features die we bouwen. Een lijst met de eerste 151 Pokémon. Detail-pages per Pokémon. Een zoek-functie. Type-filter chips. -Environments — drie scopes. Production = main. Preview = alle andere branches. Development = lokaal. Per env-variabele kies je waar-ie beschikbaar is." +De eerste twee bouwen we met Composer, op de `main` branch. De andere twee met de Background Agent op feature-branches. -`[SLIDE 8 — GitHub Actions CI]` - -**Vertel:** "Last theory bit. GitHub Actions. Een script dat draait wanneer er iets gebeurt — push, PR, merge. - -Minimaal voor dit vak: lint en build per PR. Eerst tien regels YAML, daarna heb je voor elke PR: lint draait, TypeScript build slaagt, anders rode X. - -Waarom belangrijk? Background Agent kan typo's maken. CI vangt dat op voor je merget. Plus: 'werkte op mijn laptop' bestaat niet meer." +Aan het einde heb je: een productie-URL, twee preview-URL's, drie Pull Requests, een werkende CI-pipeline, en een geverifieerd begrip van static versus ISR. --- -## BLOK 5 — Demo 1: Pokédex met Composer (30 min) +## BLOK 5 — LIVE DEMO 1: Pokédex met Composer (30 min) -`[SLIDE 9 — Wat we bouwen]` +`[SLIDE 10]` -**Vertel:** "Tijd voor demo. We bouwen vandaag een Pokédex. PokéAPI heeft data van duizend Pokémon, geen key nodig, gratis. Vier features in totaal — twee met Composer nu, twee met Background Agent na de pauze." +Tijd voor de eerste demo. Open Cursor, lege werkmap, terminal openen. -`[SLIDE 10 — DEMO 1]` `[SCHERM: terminal + cursor]` - -**Vertel:** "Klas, kijk mee. Vragen tussendoor mogen." - -`*[Terminal:]*` +Eerste commando, typ mee: ```bash -cd ~/novi/novi-lessons/Les13-Cursor-Vercel-Deploy -pnpm create next-app@latest pokedex \ - --typescript --tailwind --app --no-src-dir --import-alias "@/*" -cd pokedex -cursor . +pnpm create next-app pokedex --typescript --tailwind --app ``` -`*[Cursor opens]*` +Beantwoord de vragen: geen src directory, gebruik Turbopack, default alias is prima. -**Vertel:** "Cursor open. Nu Composer. Op Mac: `Cmd+I`. Op Windows: `Ctrl+I`." +Stap in de map: `cd pokedex` en open in Cursor met `cursor .` of File → Open Folder. -`*[Cmd+I — Composer panel opens]*` +Nu het magische moment. Druk op Cmd+I — of Ctrl+I op Windows — voor Composer. Type deze prompt letterlijk over: -**Vertel:** "Composer is een tab in Cursor — niet hetzelfde als de gewone Chat. Composer kan meerdere files tegelijk wijzigen. Chat alleen één antwoord per keer." +> Bouw een lijst-pagina met de eerste 151 Pokémon van PokéAPI. URL is `https://pokeapi.co/api/v2/pokemon?limit=151`. Gebruik Tailwind cards in een grid met de naam en sprite van elke Pokémon. De sprite staat op `https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/{id}.png` waar {id} het index-nummer is. Gebruik een static fetch — dus géén revalidate optie meegeven. -`*[Type in Composer:]*` +Composer gaat aan de slag. Je ziet diffs verschijnen in `app/page.tsx`. Lees ze met me mee. Accepteer alle wijzigingen. -> Bouw een Pokédex-startpagina op `app/page.tsx`. Haal de eerste 151 Pokémon op van `https://pokeapi.co/api/v2/pokemon?limit=151` als async Server Component. Toon in een grid van cards (Tailwind, 4 kolommen op desktop, 2 op tablet, 1 op mobile). Elke card: naam (capitalized), sprite van `https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/{id}.png`, en het Pokemon nummer (#001). Hover effect: card lichtjes vergroten en schaduw. Gebruik `next/image`. Voeg PokéAPI's sprite domain toe aan `next.config.ts`. - -**Vertel:** "Klik 'Submit'. Composer denkt na. Je ziet diffs verschijnen — `app/page.tsx`, eventueel `next.config.ts`." - -`*[Accept all diffs]*` +Start lokaal: ```bash pnpm dev ``` -`*[Open browser → localhost:3000]*` +Open `localhost:3000`. Daar zou nu een grid van 151 Pokémon moeten staan. Werkt het? Mooi. -**Vertel:** "Daar staan onze 151 Pokémon. Werkt out of the box." +Tweede prompt in Composer: -💬 *Vraag: 'Hoe weet Composer welke files te wijzigen?'* +> Voeg een detail-pagina toe op `/pokemon/[id]`. Fetch van `https://pokeapi.co/api/v2/pokemon/{id}`. Toon de official artwork — die staat in `sprites.other["official-artwork"].front_default`. Toon ook de types als chips. Gebruik ISR met `revalidate: 3600`. Zorg dat de cards op de homepage linken naar `/pokemon/[id]`. -**Antwoord:** "Cursor heeft toegang tot je hele workspace. Composer ziet de file-structure, package.json, alles. Hij beslist zelf welke files relevant zijn voor de prompt. Soms vraagt hij om bevestiging — vooral bij nieuwe files." +Wacht op de diffs. Accepteer ze. Open een random Pokémon. Werkt? Goed. -`*[Tweede Composer prompt:]*` +Belangrijke uitleg terwijl studenten kijken: -> Voeg detail-pagina toe op `app/pokemon/[name]/page.tsx`. Toon: grote sprite van `https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/other/official-artwork/{id}.png`, de naam, types als gekleurde chips (gebruik officiële Pokemon type colors zoals fire = red, water = blue, etc), en stats (HP, Attack, Defense, Sp.Atk, Sp.Def, Speed) als progress bars die de waarde tonen. Voeg height + weight onderaan. Link de homepage-cards naar `/pokemon/{name}`. +Kijk naar het verschil tussen `app/page.tsx` en `app/pokemon/[id]/page.tsx`. De homepage gebruikt gewoon `fetch(URL)`. De detail-pagina gebruikt `fetch(URL, { next: { revalidate: 3600 } })`. Dat is het hele verschil tussen static en ISR. Eén optie. -`*[Accept diffs, refresh browser, klik op een card]*` +Open de browser Network tab — F12. Klik door wat detail-pages. Je ziet dat er geen calls vanuit de browser naar PokéAPI gaan. Alles is server-side. Dat betekent: als PokéAPI morgen omvalt, blijft jouw site werken tot de revalidate triggert. -**Vertel:** "Detail-pagina werkt. Stats als balkjes. Types met kleurtjes. Composer heeft type-colors zelf gevonden — die zitten in zijn training data." +Optioneel — en als de tijd het toelaat — voeg een derde route toe met `cache: "no-store"`. Bijvoorbeeld een "random pokemon" pagina. Zo zien studenten alle drie de modes naast elkaar. -`*[Optioneel — als tijd:]*` +Commit alles in de terminal: -> De stats balkjes zijn te dun en de kleur is wat saai. Maak ze dikker en gebruik een paarse gradient. - -**Vertel:** "Composer kan ook polish doen. Twee minuten later: betere UI. Dit is wat ik bedoelde met 'pair programming' — snel iteraten op visuals." +```bash +git add . && git commit -m "Initial Pokédex met Composer" +``` --- -## BLOK 6 — Demo 2: Vercel deploy (15 min) +## BLOK 6 — LIVE DEMO 2: Vercel deploy + env vars (20 min) -`[SLIDE 11 — DEMO 2]` `[SCHERM: terminal + github + vercel]` +`[SLIDE 11]` -**Vertel:** "App werkt lokaal. Nu de wereld in." +Tijd om dit live te zetten. -`*[Terminal:]*` +Open github.com in een nieuwe tab. Klik "New repository". Naam `pokedex`. Public. Geen README, geen gitignore, geen license — die hebben we al lokaal. + +Klik Create. GitHub laat een URL zien. Kopieer die. + +Terug in de terminal: ```bash -git init -git add . -git commit -m "Initial Pokédex with Composer" git branch -M main -``` - -`*[Browser → github.com/new]*` - -**Vertel:** "Nieuwe repo. Naam: pokedex. Public — geen secrets in onze code dus public mag. Géén README, géén license — Next.js heeft alles al." - -`*[Klik 'Create repository']*` - -```bash -git remote add origin https://github.com/JOUW-USER/pokedex.git +git remote add origin https://github.com/JOUWNAAM/pokedex.git git push -u origin main ``` -`*[Refresh GitHub — code is daar]*` +Refresh github.com. Daar staat je code. -`*[Browser → vercel.com/dashboard]*` `[SCHERM: vercel]` +Open vercel.com. Log in met GitHub. Klik "Add New" en kies "Project". Vercel toont een lijst met je repositories — kies `pokedex`. Klik "Deploy". -**Vertel:** "Vercel. Add New → Project. Import Git Repository. Kies pokedex." +Wacht zestig tot negentig seconden. Je ziet de build logs voorbij komen. Aan het einde: live URL. Klik. Daar staat je Pokédex op het internet. Live. -`*[Op import-screen — alle defaults laten staan]*` +Nu het belangrijkste stuk: environment variables. -**Vertel:** "Vercel detecteert Next.js automatisch. Build command: `pnpm build`. Output directory: `.next`. Niks aanpassen. Klik Deploy." +Open `app/page.tsx` lokaal in Cursor. Voeg ergens bovenaan in de return een regel toe: -`*[Wachten ~60-90s]*` - -**Vertel:** "Tijdens het builden: dit is wat er gebeurt. Vercel pulled je code van GitHub, install dependencies, runt `pnpm build`. Output gaat naar hun CDN. Klaar. - -`*[Build done — klik op URL]*` - -**Vertel:** "Daar staat-ie. Productie URL. Live." - -`*[Demonstreer: open URL op je telefoon — werkt]*` - -**Vertel:** "Werkt op telefoon. Werkt overal. Internet." - -`*[Terug naar Cursor — kleine wijziging:]*` - -`*[Composer:]*` "Verander de h1 van 'Pokédex' naar 'Mijn Pokédex (Live!)'" - -```bash -git add . && git commit -m "Update title" && git push +```tsx +<p className="mb-4 text-sm text-zinc-500"> + Omgeving: {process.env.NEXT_PUBLIC_APP_ENV ?? "onbekend"} +</p> ``` -`*[Browser → Vercel dashboard]*` +Push naar main: -**Vertel:** "Nieuwe deploy verschijnt direct. Wacht 30 seconden..." +```bash +git add . && git commit -m "Toon huidige omgeving" +git push +``` -`*[Refresh productie URL]*` +Vercel deployt automatisch opnieuw. Maar de regel toont "onbekend" — omdat we de variabele nog niet hebben ingesteld. -**Vertel:** "Nieuwe titel zichtbaar. Geen extra commando. Push naar main = deploy." +Ga in Vercel naar je project → Settings → Environment Variables. Klik "Add new". -💬 *Vraag: 'En als de build faalt?'* +Variable name: `NEXT_PUBLIC_APP_ENV`. Value: `production`. **Belangrijk:** vink ALLEEN Production aan. Klik Save. -**Antwoord:** "Productie blijft op de laatste werkende versie. Vercel deployt alleen als build slaagt. Je krijgt mail dat de build mislukte, productie blijft online. Geen downtime." +Tweede keer toevoegen. Zelfde naam, value `preview`, en vink ALLEEN Preview aan. Save. + +Ga naar de Deployments tab en redeploy de laatste deploy. Of push een kleine wijziging om automatisch te triggeren. Wacht. Open productie-URL — staat nu "production". + +Nu een feature-branch. Terug in Cursor terminal: + +```bash +git checkout -b chore/banner +# kleine wijziging — bv een spatie ergens +git add . && git commit -m "Banner aanpassing" +git push -u origin chore/banner +``` + +Open de Vercel deployments tab. Daar verschijnt een nieuwe deployment voor `chore/banner`. Klik de preview URL. Daar zie je "preview" staan, niet "production". Twee URL's, twee waarden, één variabele. + +Voor `.env.local` zou je `NEXT_PUBLIC_APP_ENV=development` zetten — dat doen ze in het huiswerk. + +Belangrijke regel: voor secrets — echte API keys, database passwords — vink je in Vercel **alleen** Production aan. In Preview gebruik je een aparte test-key. Dit voorkomt dat experimenten je productie-data raken. --- ## BLOK 7 — Pauze (15 min) -`[SLIDE 12 — Pauze]` +`[SLIDE 12]` -**Vertel:** "Pauze. Vijftien minuten." - -`*[Tijdens pauze: open Cursor Background Agent flow alvast — zorg dat repo geconnect is]*` +Vijftien minuten pauze. Ik mute mijn microfoon en zet de camera uit. Tot zo. --- -## BLOK 8 — Demo 3: Background Agent (25 min) +## BLOK 8 — LIVE DEMO 3: Background Agent + preview (25 min) -`[SLIDE 13 — DEMO 3]` `[SCHERM: cursor + github + vercel]` +`[SLIDE 13]` -**Vertel:** "Nu de Background Agent. Dit is écht anders. Geen pair-programming meer — we delegeren." +Welkom terug. Nu het stuk wat veel mensen voor het eerst zien: de Cursor Background Agent. -`*[Cursor: Cmd+Shift+P]*` +Open Cursor. Druk Cmd+Shift+P voor het command palette. Type "Background Agent". Eerste keer: Cursor vraagt of je je repository wilt verbinden aan de cloud. Accepteer in de browser, autoriseer GitHub. -**Vertel:** "Cmd+Shift+P opent command palette. Type 'Background Agent'." +Nu kun je een Background Agent starten. Type deze prompt — letterlijk over: -`*[Select 'Open Background Agent']*` +> Maak een nieuwe branch genaamd `feature/search`. Voeg bovenaan de homepage een zoekbalk toe. Wanneer iemand typt, filter dan de Pokémon-lijst op naam. Gebruik client-side state met useState. Push de branch naar GitHub en open een Pull Request met titel "Add search bar" en een korte beschrijving in de body. -**Vertel:** "Eerste keer: Cursor vraagt verbinding met je repo. Volg de flow — opent browser, OAuth met GitHub, Cursor mag in jouw cloud sandbox draaien." +Klik start. De agent gaat aan de slag. -`*[Connect flow]*` +Wat je nu kunt doen — en dit is het hele punt: iets anders doen. Een tweede Background Agent starten met een andere taak. -**Vertel:** "Klaar. Nu de prompt. Belangrijk: SPECIFIEK zijn. De agent ziet ons niet. Hij krijgt alleen de prompt." +Nieuwe Background Agent, prompt: -`*[Schrijf:]*` +> Maak branch `feature/type-filter`. Op de homepage, naast de zoekbalk: chips om te filteren op type. Type-data moet je per Pokémon fetchen via de detail-endpoint. Push de branch en open een PR. -> Maak een nieuwe branch `feature/search`. Voeg een controlled input toe bovenaan `app/page.tsx`. Wanneer gebruiker typt, filter de Pokémon-lijst case-insensitive op naam. Houd Tailwind-styling consistent met bestaande cards (rounded corners, padding p-4). Voeg een count toe rechtsboven: "X van 151 zichtbaar". Push de branch en open een PR met titel "Add search bar". PR body: korte beschrijving + screenshot suggestie. +Beide agents lopen nu parallel. Klik op de eerste in het Background panel — je ziet wat hij doet. Bij vragen kan hij je stoppen voor input. -`*[Submit]*` +Wacht drie tot vijf minuten. Pull-Requests verschijnen op GitHub. -**Vertel:** "Agent draait nu. Cursor toont je een panel waarin je kunt zien wat-ie doet — bestanden inlezen, edits maken, terminal commands." +Open de eerste PR — "Add search bar". Onderaan zie je een comment van Vercel met de preview URL. Klik. Test de zoekbalk live in de browser. Werkt? Goed. -`*[Wachten ~3-5 minuten. Tijdens wachten:]*` +Open de code-diff in de GitHub UI. Lees mee. De agent heeft toegevoegd: een useState voor de query, een input bovenaan, een filter op de lijst. Logisch. -**Vertel:** "Belangrijk om uit te leggen — terwijl deze agent draait, ben ik vrij om iets anders te doen. Lokaal coden, Composer gebruiken voor andere features, koffie halen. Dat is het voordeel. +Als de code goed is, klik "Merge pull request". Push gaat naar `main`. Vercel deployt naar productie. Binnen een minuut staat de zoekbalk live. -Andere relevante punten. Agent draait in Cursor's sandbox — niet jouw laptop. Hij heeft toegang tot je repo, kan `pnpm install` doen, kan tests draaien, kan PR's openen. Maar hij heeft GEEN toegang tot jouw productie-secrets of services. Sandbox is geïsoleerd." +Hetzelfde voor de tweede PR. Review, test op preview-URL, merge. -`*[Agent done — PR verschijnt op GitHub]*` `[SCHERM: github]` - -**Vertel:** "Pull request op GitHub. Klik." - -`*[PR open]*` - -**Vertel:** "Vercel heeft een comment achtergelaten — preview URL. Klik." - -`*[Browser → Vercel preview URL]*` - -**Vertel:** "Live, op een ANDERE URL dan productie. Test zoekbalk." - -`*[Type 'pika' — Pikachu blijft over]*` - -**Vertel:** "Werkt. Search live op preview URL. Productie ongewijzigd." - -`*[Terug naar GitHub PR — Files Changed tab]*` - -**Vertel:** "Code-review. Agent heeft `app/page.tsx` aangepast, eventueel een nieuwe component gemaakt. Lees diff, check of het ok is." - -`*[Eventueel: comment in PR]*` - -**Vertel:** "Stel ik wil een wijziging — bv. 'voeg ook een clear-button toe'. Twee opties. Een: open de branch lokaal, Composer fix. Twee: nieuwe Background Agent prompt op deze branch. Voor demo doen we optie twee." - -`*[Cursor → Background Agent → existing or new]*` - -> Op de bestaande branch feature/search: voeg een 'X' clear-button toe rechts in de zoekinput die de input leegmaakt. - -`*[Wacht 2-3 min, refresh PR, refresh preview URL]*` - -**Vertel:** "Update zichtbaar. Klik X — input leeg. Werkt." - -`*[Eventueel: merge]*` - -**Vertel:** "Tevreden? Merge PR. Vercel productie-deploy start automatisch. Een minuut later: search live op productie." - -💬 *Vraag: 'Wat als agent vastloopt?'* - -**Antwoord:** "Twee opties. Pakje sluiten en opnieuw beginnen met betere prompt. Of: open de branch lokaal, kijk wat agent gedaan heeft, fix met Composer. De agent is geen blackbox — hij commit echt op een branch, je kunt erin kijken." +Wat hier net gebeurde: in vijf minuten zijn er twee features autonoom gebouwd door agents, getest op aparte preview-URLs, en gemerged naar productie. Zonder dat ik één regel code zelf heb geschreven. --- -## BLOK 9 — Demo 4: GitHub Actions CI (15 min) +## BLOK 9 — LIVE DEMO 4: GitHub Actions CI (15 min) -`[SLIDE 14 — DEMO 4]` `[SCHERM: cursor + github]` +`[SLIDE 14]` -**Vertel:** "Laatste demo. CI. Eén check per PR — lint + build." +Laatste demo. We voegen CI toe. Lint en build moeten slagen voor elke PR. -`*[Cursor → Composer]*` +Open Composer in Cursor, Cmd+I, prompt: -> Voeg een GitHub Actions workflow toe: `.github/workflows/ci.yml`. Runt op pull_request en push naar main. Steps: checkout, install pnpm 9, setup node 20 met pnpm cache, install dependencies met frozen lockfile, run lint, run build. +> Voeg een GitHub Actions workflow toe op `.github/workflows/ci.yml`. Bij pull request én bij push naar main: checkout, setup pnpm met `pnpm/action-setup@v4`, setup node 22 met `actions/setup-node@v4` en `cache: pnpm`, install, run lint, run build. -`*[Accept diffs]*` +Composer maakt het bestand. Accepteer. -`*[Terminal:]*` +Push de wijziging: ```bash git checkout -b chore/add-ci -git add .github/workflows/ci.yml -git commit -m "Add CI workflow" +git add . && git commit -m "Add GitHub Actions CI" git push -u origin chore/add-ci ``` -`*[GitHub → openen PR]*` `[SCHERM: github]` +Open de PR op GitHub. Onder de PR zie je de "Checks" tab — de workflow draait. Wacht ongeveer twee minuten. Groene vinkjes — goed. -**Vertel:** "PR open. Klik tab 'Actions' — workflow draait. ~1-2 min." +Nu de demo van een falende CI. Introduceer een typo in de code. Open `app/page.tsx` lokaal, verander een opening tag in iets fouts — bijvoorbeeld `<dvi>` in plaats van `<div>`. Commit en push naar dezelfde branch. -`*[Wacht]*` +CI draait opnieuw, faalt. Rode X. Open de logs in GitHub — zie de TypeScript error. -**Vertel:** "Groene check verschijnt. Merge PR. CI is nu live op elke toekomstige PR." +Fix met Composer: -`*[Demo: failing CI]*` +> Repareer de TypeScript build error in `app/page.tsx`. -**Vertel:** "Laat ik laten zien wat er gebeurt bij een fout." +Composer fixt. Commit, push. CI draait. Groen. -`*[Cursor → Composer:]*` +Laatste stap: branch protection. Ga naar GitHub repo → Settings → Branches → Add rule. Branch name pattern: `main`. Vink aan: "Require status checks to pass before merging". Selecteer de CI-workflow. Save. -> Maak een TypeScript fout in app/page.tsx. Verwijder een belangrijke import. Push naar een nieuwe branch chore/test-ci-fail. +Vanaf nu mag niemand — ook jij niet — naar main mergen zonder groene CI. -```bash -git push -u origin chore/test-ci-fail -``` - -`*[GitHub → PR open → wait]*` - -**Vertel:** "Rode X. Build faalt. Klik op de details — daar staat letterlijk wat mis is." - -`*[Fix met Composer]*` - -> Repareer de TypeScript-fout in app/page.tsx (voeg de import terug). Commit. - -```bash -git push -``` - -`*[Wacht — groene check]*` - -**Vertel:** "Fixed. CI groen. Merge mag nu." - -`*[Branch protection toevoegen — kort]*` `[SCHERM: github settings]` - -**Vertel:** "Tot slot — branch protection. Settings → Branches → Add rule. Branch pattern: main. Vink aan: require PR before merging. Require status checks: select onze CI workflow. Save. - -Wat dit doet: niemand kan nog direct naar main pushen. Background Agents werken via PRs — dat blijft werken. PR moet groene CI hebben voor merge." - -`*[Demo: probeer direct push naar main]*` - -```bash -git checkout main && echo "test" >> README.md && git commit -am "direct" && git push -``` - -``` -! [remote rejected] main -> main (protected branch hook declined) -``` - -**Vertel:** "Geblokkeerd. Goed." +Merge de PR. Klaar. --- -## BLOK 10 — Composer vs Background reflectie (10 min) +## BLOK 10 — Composer vs Background (10 min) -`[SLIDE 15 — Wanneer welke]` +`[SLIDE 15]` -**Vertel:** "Twee tools, één keuze per taak. Wanneer welke? +Vandaag hebben we beide gebruikt. Wanneer kies je welke? -Composer voor pair-programming. Snel feedback, jij stuurt, agent voert uit, jij accepteert per diff. Goed voor: exploreren, leren, refactors waar je wilt meekijken. +Composer is je pair-programmer. Je zit erbij, hij maakt aanpassingen, je accepteert per file. Goed voor: snelle wijzigingen tijdens je werk, complex refactor waar je wilt meekijken, onbekend gebied waar je niet wilt dat een agent vastloopt. -Background Agent voor delegatie. Specifieke feature, kun je niet bij zijn, parallel werken aan andere taken. Goed voor: PR-prep, parallel werken aan 3 features, terwijl-je-vergadert. +Background Agent is je delegate. Je geeft een welomschreven taak, gaat iets anders doen, krijgt later een PR met preview URL. Goed voor: features met heldere specs, parallel werken aan meerdere features, tijdens een meeting iets voorbereiden. -Risico's bij Background. Vage prompts = vage PR's. Specifiek zijn helpt. Agent kost credits — voor solo-projecten geen issue, voor teams kan oplopen. +Mentaal model: Composer is "samen werken". Background Agent is "uitbesteden". -Wat ik zelf doe: 80% Composer, 20% Background. Background voor de écht goed-gedefinieerde features die ik dan parallel laat draaien." +Twee waarschuwingen voor Background Agent. Een: hij kan vastlopen op rare config — debuggen is moeilijker omdat je er niet bij was. Twee: hij verbruikt credits, dus Cursor Pro of Business is wel nodig. -💬 *Vraag: 'Welke is beter voor onze eindopdracht?'* - -**Antwoord:** "Beide. Ontwerpen + leren = Composer. Specifieke features uitwerken = Background. Voor de eindopdracht-pitch: laat zien dat je beide kunt — dat is een vaardigheid." +Praktische tip: te vage prompts geven matige PR's. Wees specifiek. Noem de bestanden, beschrijf de UX, geef voorbeelden van wat je wilt. Hoe meer context, hoe beter de output. --- ## BLOK 11 — Lesopdracht + Huiswerk (10 min) -`[SLIDE 16 — Lesopdracht + Huiswerk]` +`[SLIDE 16]` -**Vertel:** "Lesopdracht — in de les. Half uur. Je eigen Pokédex setuppen, één feature met Composer, push naar GitHub, deploy op Vercel. Aan het eind: jouw eigen productie-URL. +Tijd voor jullie eigen werk. Twee delen. -Huiswerk — voor volgende week. Vier dingen. +**Lesopdracht — doe je nu, dertig minuten:** -Een: feature toevoegen via Background Agent. Branch + PR + preview URL. +Een. Eigen Pokédex-repo opzetten met dezelfde stappen als de demo: `pnpm create next-app`, Composer prompt voor de lijst, Composer prompt voor de detail-page. -Twee: GitHub Actions CI workflow. Lint + build per PR. +Twee. Push naar GitHub. -Drie: branch protection op main. PR's verplicht, CI moet groen. +Drie. Verbind met Vercel, deploy. Open de productie-URL en stuur de URL in de chat — ik wil zien dat het werkt. -Vier: DEPLOY.md schrijven. URLs, prompt die je aan Background Agent gaf, reflectie over Composer vs Background, bewijs van CI (groen + rood voorbeeld), één observatie. +Vier. Voeg de `NEXT_PUBLIC_APP_ENV` environment variable toe met een aparte waarde voor production en preview. Verifieer dat het werkt op beide URLs. -Bonus: tweede externe API, environment scoping, parallelle Background Agents. +**Huiswerk — voor volgende les:** -Tien punten, voldoende is zes. Inleveren via Brightspace: repo URL + productie URL + DEPLOY.md." +A. Eén feature toevoegen met de Background Agent. Mijn voorstel: zoekbalk, type-filter, favorieten-systeem, of vergelijk-twee-pokemon. Open de PR, krijg de preview URL. + +B. GitHub Actions CI toevoegen met lint en build. + +C. Branch protection op `main` instellen. + +D. Schrijf een `DEPLOY.md` in de root van je repo met: productie-URL, één preview-URL, en een reflectie van ongeveer driehonderd woorden over Composer versus Background Agent. Wanneer werkte welke beter? Geef één voorbeeld waar Background verbluffend goed of juist slecht was. + +Bonus voor wie wil: vervang de Pokédex door een andere externe API. Open-Meteo voor weer, GitHub API voor jouw eigen repositories, of een free API naar keuze. + +Inleveren via Teams, voor volgende les. --- ## BLOK 12 — Afsluiting (5 min) -`[SLIDE 17 — Afsluiting]` +`[SLIDE 17]` -**Vertel:** "Wat hebben we vandaag gedaan. Externe APIs in Server Components. Cursor Composer voor synchrone werk. Cursor Background Agent voor async PR's. Vercel productie + preview per branch. GitHub Actions CI. Branch protection. +Vandaag hebben we veel gedaan. -Volgende les: RAG en embeddings. Vector search met pgvector. We bouwen een tool die semantic search doet — handig om in een agent te plakken. Combo van les 13 en 15. +We hebben externe APIs leren fetchen vanuit Server Components. We hebben drie rendering modes gezien: static voor de lijst, ISR voor detail-pages, en kort genoemd hoe je dynamic of client-side zou doen. Dat is een knop die je per fetch omdraait. -Daarna: performance + observability, eindopdracht-werkdagen, pitch. +We hebben Cursor Composer gebruikt voor synchrone wijzigingen, en Background Agent voor twee parallel-features. Verschillende tools voor verschillende momenten. -Vragen?" +We hebben naar Vercel gedeployed. Productie op main, preview per branch. En het belangrijkste: environment variables per omgeving. Een variabele kan drie totaal verschillende waarden hebben, één per scope. -`*[Vragenronde — minstens 5 min over laten]*` +En tenslotte GitHub Actions CI. Zekerheid dat je code lint en bouwt voor de merge. + +Volgende les is les 14: Agents. Nog een stap verder dan tool calling. LLM in een loop met tools, autonoom twintig tot vijftig stappen. We bouwen een research-agent from scratch met `ToolLoopAgent`, `stopWhen` en `prepareStep`. En we bespreken wanneer agents wel of niet de juiste keuze zijn. + +Dat was 'm. Bedankt voor jullie aandacht. Vragen? --- -## NA DE LES — Wrap-up +## VEELVOORKOMENDE FOUTEN — voor mezelf -- Push working `pokedex` repo naar GitHub als referentie voor studenten -- Brightspace: link naar referentie-repo + huiswerk-instructies -- Verzamel vragen die niet beantwoord — terug in Les 13 opening -- Voor Klas B (later): check of Cursor Pro licenties beschikbaar zijn voor studenten, anders Background Agent demo moeilijk +| Probleem | Oplossing | +|----------|-----------| +| Vercel deploy faalt op build | Check Build Logs — meestal type-error of missende env var | +| Background Agent doet niks | Repo niet gekoppeld aan Cursor cloud — Cmd+Shift+P → Repository Settings | +| Preview URL toont oude versie | Hard refresh (Cmd+Shift+R), of Vercel cache invalidate | +| Env var komt niet door | Redeploy na toevoegen var — bestaande build pakt 'm niet automatisch | +| `process.env.NEXT_PUBLIC_*` undefined | Moet beginnen met `NEXT_PUBLIC_` om in browser te werken | +| GitHub Actions faalt op pnpm | `actions/setup-node` MET `cache: pnpm` — anders geen lockfile-aware install | +| Branch protection blokkeert PR | Eerst CI groen zien voor je merge | +| Composer 'kan repo niet vinden' | Cursor verbinden met die specifieke repo via Cmd+Shift+P | --- -## Veelvoorkomende fouten tijdens live coding +## TIMING-CHECK -| Fout | Oplossing | -|------|-----------| -| `next/image` PokéAPI domain error | Composer: "voeg images.remotePatterns toe in next.config.ts" | -| Cursor Composer onresponsive | Cmd+I opnieuw, of restart Cursor | -| Background Agent verbinding faalt | Logout/login Cursor cloud, refresh repo connection | -| Vercel deploy faalt: missing dep | `pnpm install` lokaal, commit lockfile, push | -| GitHub Actions: pnpm not found | Check `pnpm/action-setup@v3` versie in yml | -| Branch protection: kan eigen PR niet mergen | Tijdens demo: voeg jezelf toe als bypass user | -| Preview URL 404 | Wachten — eerste build duurt soms 2 min | -| Background Agent fixt verkeerde files | Te vage prompt — specifiek met file paths volgende keer | +| Blok | Cumulatief | Duur | +|------|-----------|------| +| 1. Welkom + Terugblik | 0–10 | 10 min | +| 2. Theorie Externe APIs | 10–25 | 15 min | +| 3. Theorie Vercel + GH | 25–40 | 15 min | +| 4. Wat we bouwen | 40–45 | 5 min | +| 5. Demo 1 — Composer | 45–75 | 30 min | +| 6. Demo 2 — Vercel + env | 75–95 | 20 min | +| 7. Pauze | 95–110 | 15 min | +| 8. Demo 3 — Background Agent | 110–135 | 25 min | +| 9. Demo 4 — GitHub Actions | 135–150 | 15 min | +| 10. Composer vs Background | 150–160 | 10 min | +| 11. Lesopdracht + Huiswerk | 160–170 | 10 min | +| 12. Afsluiting | 170–175 | 5 min | +| Buffer voor vragen | 175–180 | 5 min | ---- - -## Mentale model voor de klas - -Als studenten verward zijn over de Cursor agent-modes: - -> **Composer** = jij pair-programt met AI. Synchroon. Cmd+I. Lokaal. -> -> **Background Agent** = jij delegeert aan AI. Async. Cmd+Shift+P. Cloud. Opent PR. - -Belangrijkste regel voor Background Agent: prompts moeten zo specifiek zijn alsof je het aan een nieuwe junior junior dev op afstand uitlegt. Geen context-cues, geen "je weet wel". +Totaal: 180 minuten. diff --git a/Les13-Cursor-Vercel-Deploy/Les13-Huiswerk.pdf b/Les13-Cursor-Vercel-Deploy/Les13-Huiswerk.pdf index 3753695..1f046d3 100644 --- a/Les13-Cursor-Vercel-Deploy/Les13-Huiswerk.pdf +++ b/Les13-Cursor-Vercel-Deploy/Les13-Huiswerk.pdf @@ -97,7 +97,7 @@ endobj endobj 13 0 obj << -/Author (NOVI Hogeschool Utrecht) /CreationDate (D:20260607091328+00'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260607091328+00'00') /Producer (ReportLab PDF Library - \(opensource\)) +/Author (NOVI Hogeschool Utrecht) /CreationDate (D:20260607134605+00'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260607134605+00'00') /Producer (ReportLab PDF Library - \(opensource\)) /Subject (\(unspecified\)) /Title (Les 13 Huiswerk) /Trapped /False >> endobj @@ -182,7 +182,7 @@ xref trailer << /ID -[<d9949b7f201730e155f883ddc79dfc36><d9949b7f201730e155f883ddc79dfc36>] +[<9e0017c2fae42cc449cacedd8dc86476><9e0017c2fae42cc449cacedd8dc86476>] % ReportLab generated PDF document -- digest (opensource) /Info 13 0 R diff --git a/Les13-Cursor-Vercel-Deploy/Les13-Lesopdracht.pdf b/Les13-Cursor-Vercel-Deploy/Les13-Lesopdracht.pdf index 1ad4a90..e784e1f 100644 --- a/Les13-Cursor-Vercel-Deploy/Les13-Lesopdracht.pdf +++ b/Les13-Cursor-Vercel-Deploy/Les13-Lesopdracht.pdf @@ -77,7 +77,7 @@ endobj endobj 11 0 obj << -/Author (NOVI Hogeschool Utrecht) /CreationDate (D:20260607091328+00'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260607091328+00'00') /Producer (ReportLab PDF Library - \(opensource\)) +/Author (NOVI Hogeschool Utrecht) /CreationDate (D:20260607134605+00'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260607134605+00'00') /Producer (ReportLab PDF Library - \(opensource\)) /Subject (\(unspecified\)) /Title (Les 13 Lesopdracht) /Trapped /False >> endobj @@ -144,7 +144,7 @@ xref trailer << /ID -[<d6162db91d2a02a68999ed8903f4a014><d6162db91d2a02a68999ed8903f4a014>] +[<6d65c6032a302e19cbfdfbf2e67cdcbe><6d65c6032a302e19cbfdfbf2e67cdcbe>] % ReportLab generated PDF document -- digest (opensource) /Info 11 0 R diff --git a/Les13-Cursor-Vercel-Deploy/Les13-Lesstof.md b/Les13-Cursor-Vercel-Deploy/Les13-Lesstof.md index 64f96b9..4941fb8 100644 --- a/Les13-Cursor-Vercel-Deploy/Les13-Lesstof.md +++ b/Les13-Cursor-Vercel-Deploy/Les13-Lesstof.md @@ -3,7 +3,7 @@ **Vak:** AI-Assisted Development **Opleiding:** NOVI Hogeschool Utrecht -**Vorige les:** Les 14 — RAG + Embeddings +**Vorige les:** Les 12 — Tool Calling **Volgende les:** Les 14 — Agents --- @@ -65,29 +65,49 @@ Drie dingen om te onthouden: --- -## 2. Server- vs client-side fetching +## 2. Vier manieren om een externe API te fetchen -### Server-side (Server Component of API route) +Next.js geeft je per fetch-call de keuze hoe je data wilt renderen. Voor 95% van je werk komt het neer op drie server-modes plus client-side. De code verandert minimaal — meestal één optie in je `fetch()`. + +### 2.1 Static (build-time) ```typescript -// app/pokemon/[name]/page.tsx -async function getPokemon(name) { - const res = await fetch(`https://pokeapi.co/api/v2/pokemon/${name}`, { - next: { revalidate: 3600 }, // cache 1 uur - }); +// app/page.tsx — Server Component +async function getPokemon() { + const res = await fetch("https://pokeapi.co/api/v2/pokemon?limit=151"); return res.json(); } ``` -**Voordelen:** -- API key blijft op de server (nooit in client-bundle) -- Caching gratis via Next.js -- SEO-vriendelijk (HTML met data terug) -- Snellere TTFB (geen extra roundtrip) +- Gefetched tijdens `next build`, daarna **HTML voor altijd** +- Geen server-werk per request → snelste optie +- Data ververst alleen bij een nieuwe build (= nieuwe deploy) +- **Goed voor:** marketing-pagina's, blogs, productlijsten, alles dat zelden verandert +- **Niet voor:** prijzen die per minuut updaten, user-specifieke data -**Wanneer gebruiken:** initiële data, lijsten, detail-pagina's. +### 2.2 ISR — Incremental Static Regeneration -### Client-side (`useEffect` of `useState` met fetch) +```typescript +const res = await fetch(URL, { next: { revalidate: 3600 } }); +``` + +- Eerste request: zelfde als static (HTML uit cache) +- Na 3600 seconden: volgende request krijgt nog steeds cache, maar achter de schermen wordt de pagina vernieuwd +- **Goed voor:** Pokédex detail-pages, een nieuws-feed die niet realtime hoeft, productdetails +- **De sweet spot tussen snel en redelijk vers** + +### 2.3 Dynamic (request-time / SSR) + +```typescript +const res = await fetch(URL, { cache: "no-store" }); +``` + +- Bij elke request opnieuw gefetched op de server +- Altijd 100% vers, maar trager (geen cache) +- **Goed voor:** dashboards met live data, user-specifieke views, anything per-request +- **Let op cost:** elke request = serverless function call + +### 2.4 Client-side (`useEffect`) ```typescript "use client"; @@ -102,63 +122,73 @@ export function LivePokemon({ name }) { } ``` -**Wanneer gebruiken:** -- User-interactie (search, filter, infinite scroll) -- Real-time updates (polling, websockets) -- Data die per user verschilt en niet op server kan +- Fetch gebeurt in de browser na hydration +- Goed voor user-interactie, real-time, infinite scroll +- **Cruciaal:** API-keys staan **in de browser** als je hier rechtstreeks naar een externe API roept. Alleen voor publieke APIs, of via een eigen `/api/...` proxy-route. -> **Belangrijke regel:** API keys NOOIT in client-code. Voor authenticated externe APIs: maak een API-route in `app/api/...` als proxy. +### Spiekbriefje -### Cache-opties bij `fetch` - -```typescript -fetch(url, { cache: "force-cache" }) // permanent (default Next.js) -fetch(url, { next: { revalidate: 3600 } }) // ISR — herval na N seconden -fetch(url, { cache: "no-store" }) // nooit cachen (per request) -fetch(url, { next: { tags: ["pokemon"] } }) // tag-based revalidation -``` +| Mode | `fetch()` optie | Wanneer | +|------|----------------|---------| +| Static | `fetch(URL)` (default) | Data verandert per deploy | +| ISR | `{ next: { revalidate: N } }` | Data verandert traag | +| Dynamic | `{ cache: "no-store" }` | Data verandert per request | +| Client | `useEffect` + fetch | User-interactie / live | +| Tag-based | `{ next: { tags: ["x"] } }` | Triggered revalidation via `revalidateTag()` | --- -## 3. Environment variabelen +## 3. Environment variabelen — server-only vs client-exposed -### Drie scopes in Next.js + Vercel +### Twee soorten variabelen -| Scope | Wanneer | Waar | -|-------|---------|------| -| `OPENAI_API_KEY` | Server-only | Process env op server | -| `NEXT_PUBLIC_APP_URL` | Server + client | In client-bundle (zichtbaar in DevTools!) | -| `.env.local` | Lokaal alleen | Niet committen, `.gitignore` | +| Type | Voorbeeld | Waar beschikbaar | Veiligheid | +|------|-----------|------------------|------------| +| Server-only | `OPENAI_API_KEY`, `DATABASE_URL` | Alleen op de server | **Geheim** — nooit zichtbaar voor de browser | +| Client-exposed | `NEXT_PUBLIC_APP_ENV`, `NEXT_PUBLIC_APP_URL` | Server + client bundle | **Publiek** — iedereen kan ze zien in DevTools | -### Regel - -**Alles wat geheim is — zonder `NEXT_PUBLIC_` prefix.** Met prefix = in client bundle = iedereen kan het zien. +**Regel:** alles met `NEXT_PUBLIC_` prefix wordt ingebakken in de browser-bundle. Zonder prefix = server-only. ```typescript -// ✅ Server-only — veilig +// ✅ Veilig — server-side gebruik process.env.OPENAI_API_KEY -// ❌ NEVER doen +// ❌ NOOIT "use client"; -const key = process.env.NEXT_PUBLIC_OPENAI_KEY; // staat in HTML response! +const key = process.env.NEXT_PUBLIC_OPENAI_KEY; // staat in de HTML response ``` -### Vercel environment scoping +### 3.1 Vercel — drie omgevingen, drie scopes -Op Vercel heb je drie environments: +Op Vercel heb je per project drie environments. Bij elke env-var kies je in welke scopes hij wordt geïnjecteerd: -- **Production** — deploys vanaf `main` -- **Preview** — alle andere branches + PRs -- **Development** — lokaal (`vercel env pull` om te syncen) +| Scope | Wordt gebruikt bij | URL-patroon | +|-------|---------------------|-------------| +| **Production** | Push naar `main` | `je-app.vercel.app` | +| **Preview** | Push naar elke andere branch | `je-app-git-{branch}-{user}.vercel.app` | +| **Development** | Lokaal (`pnpm dev`) | `localhost:3000` | -Per env-var kies je in welke scopes hij beschikbaar is. Handig: +### 3.2 Per-omgeving andere waarden -``` -OPENAI_API_KEY_PROD → Production scope -OPENAI_API_KEY_TEST → Preview + Development scope -``` +In **Vercel → Project → Settings → Environment Variables** zet je per variabele drie keer een waarde: -Op die manier verbruiken preview deploys niet je productie-quota. +| Var | Production | Preview | Development | +|-----|------------|---------|-------------| +| `DATABASE_URL` | productie-DB | staging-DB | lokale DB | +| `OPENAI_API_KEY` | echte key | test-key (lage limit) | jouw key | +| `STRIPE_KEY` | `sk_live_...` | `sk_test_...` | `sk_test_...` | +| `NEXT_PUBLIC_APP_URL` | `je-app.com` | preview-URL | `http://localhost:3000` | + +**Hoe in te stellen:** in de UI: Add new → vink alleen de juiste environment(s) aan → Save. + +**Belangrijke veiligheidsregels:** +- Productie-secrets (echte API keys, prod-DB-password): **alleen** Production vinken +- Preview krijgt een test-variant, anders kunnen experimentele branches je productie raken +- Development: `vercel env pull` om Vercel's dev-vars naar je `.env.local` te syncen, of zelf invullen + +### 3.3 Verandering pakt pas door bij nieuwe build + +Bestaande deploys zien een nieuwe env-var niet automatisch. Na het toevoegen of wijzigen: **redeploy** (Deployments → ··· → Redeploy) of push een nieuwe commit. --- diff --git a/Les13-Cursor-Vercel-Deploy/Les13-Lesstof.pdf b/Les13-Cursor-Vercel-Deploy/Les13-Lesstof.pdf index 6aae1b4..4f6966d 100644 --- a/Les13-Cursor-Vercel-Deploy/Les13-Lesstof.pdf +++ b/Les13-Cursor-Vercel-Deploy/Les13-Lesstof.pdf @@ -137,7 +137,7 @@ endobj endobj 17 0 obj << -/Author (NOVI Hogeschool Utrecht) /CreationDate (D:20260607091328+00'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260607091328+00'00') /Producer (ReportLab PDF Library - \(opensource\)) +/Author (NOVI Hogeschool Utrecht) /CreationDate (D:20260607134605+00'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260607134605+00'00') /Producer (ReportLab PDF Library - \(opensource\)) /Subject (\(unspecified\)) /Title (Les 13 Lesstof) /Trapped /False >> endobj @@ -259,7 +259,7 @@ xref trailer << /ID -[<7a091ff13b69dcda5597317f91fb07e0><7a091ff13b69dcda5597317f91fb07e0>] +[<1e77dbe9d9f83762252045861df07f97><1e77dbe9d9f83762252045861df07f97>] % ReportLab generated PDF document -- digest (opensource) /Info 17 0 R diff --git a/Les13-Cursor-Vercel-Deploy/Les13-Slide-Overzicht.md b/Les13-Cursor-Vercel-Deploy/Les13-Slide-Overzicht.md index ad3211d..28cc97f 100644 --- a/Les13-Cursor-Vercel-Deploy/Les13-Slide-Overzicht.md +++ b/Les13-Cursor-Vercel-Deploy/Les13-Slide-Overzicht.md @@ -71,51 +71,41 @@ **Voorbeelden:** - PokéAPI — Pokemon data (geen key) +- Open-Meteo — weer (geen key) +- GitHub API — repos, users, issues - Tavily — web search (key nodig) - Stripe — betalingen (key + secret) -- GitHub API — repos, users, issues -- Open-Meteo — weer (geen key) -**In Next.js — twee plekken om te fetchen:** - -| Server-side (RSC / API route) | Client-side (`useEffect`) | -|-------------------------------|---------------------------| -| Snel, key veilig, gecached | Nodig voor user-interactie | -| Voor initiële data | Voor live updates | +**API keys** horen in environment variables — nooit in je code committen. **Visual:** Diagram: Next.js → fetch → externe API → JSON terug. --- -## Slide 5: Externe API in Next.js — code -### Server Component met fetch +## Slide 5: Drie manieren om een API te fetchen in Next.js +### Static, Server (dynamic), Client — wanneer welke? + +| | Wanneer gerenderd | Data versheid | Externe API key veilig? | Wanneer kiezen | +|---|---|---|---|---| +| **Static** (build-time) | Tijdens `next build` | Bij elke build | Ja, server | Data verandert zelden (blog, marketing, lijst) | +| **Server / Dynamic** (request-time) | Bij elke request | Altijd vers | Ja, server | Data per user/request anders, of telkens vers nodig | +| **ISR** (revalidate) | Eerste keer + na X seconden | Periodiek vers | Ja, server | Sweet spot: snel + redelijk vers (Pokédex!) | +| **Client** (`useEffect`) | In de browser na hydration | Live | **Nee** — sleutel staat in browser | User-interactie, live updates, geen geheim | + +**Code-verschil = één optie in `fetch`:** ```typescript -// app/pokemon/[name]/page.tsx -async function getPokemon(name: string) { - const res = await fetch( - `https://pokeapi.co/api/v2/pokemon/${name}`, - { next: { revalidate: 3600 } } // cache 1 uur - ); - if (!res.ok) throw new Error("Pokemon niet gevonden"); - return res.json(); -} +// 1. STATIC — gecached forever (default in Next.js!) +const res = await fetch(URL); -export default async function PokemonPage({ params }) { - const pokemon = await getPokemon(params.name); - return ( - <div> - <h1>{pokemon.name}</h1> - <img src={pokemon.sprites.front_default} alt="" /> - </div> - ); -} +// 2. ISR — cache met revalidate +const res = await fetch(URL, { next: { revalidate: 3600 } }); + +// 3. DYNAMIC — altijd vers +const res = await fetch(URL, { cache: "no-store" }); ``` -**Drie dingen om te weten:** -1. **`async`** Server Component — fetch direct in component -2. **`next: { revalidate }`** — Next.js cache opties -3. **Error handling** — `!res.ok` netjes afvangen +**Vandaag gebruiken we:** Static voor de Pokédex-lijst, ISR voor detail-pages. --- @@ -139,27 +129,35 @@ export default async function PokemonPage({ params }) { --- -## Slide 7: Vercel preview deploys -### Een URL per branch — automatisch +## Slide 7: Vercel — productie, preview, environment variables +### Wat verandert er per omgeving? -**Hoe het werkt:** -1. Connect je GitHub repo aan Vercel (eenmalig) -2. Push naar `main` → **productie** deploy op `je-app.vercel.app` -3. Push naar elke andere branch → **preview** deploy op `je-app-git-{branch}-{user}.vercel.app` -4. PR krijgt automatisch een comment met preview URL +**Drie omgevingen, drie scopes:** -**Wat krijg je:** -- Stakeholders zien een nieuwe feature voor de merge -- Cursor Background Agent maakt een PR → preview URL → klikbaar -- Reviewer test live in browser, niet alleen code-diff +| Scope | Wordt gedeployed bij | URL | Wie ziet het | +|-------|---------------------|-----|--------------| +| **Production** | Push naar `main` | `je-app.vercel.app` | Iedereen | +| **Preview** | Push naar elke andere branch | `je-app-git-{branch}-{user}.vercel.app` | Iedereen met link (delen via PR) | +| **Development** | Lokaal `pnpm dev` | `localhost:3000` | Alleen jij | -**Environment scopes:** +**Environment variables per scope:** -| Scope | Wanneer | Voorbeeld var | -|-------|---------|---------------| -| **Production** | Deploys vanaf `main` | Echte API key | -| **Preview** | Alle andere branches | Test API key | -| **Development** | Lokaal (`.env.local`) | Dev API key | +In Vercel → Project → Settings → Environment Variables zet je per var **drie keer** een waarde: + +| Var | Production | Preview | Development | +|-----|------------|---------|-------------| +| `DATABASE_URL` | prod database | staging database | lokale database | +| `OPENAI_API_KEY` | echte key | test-key (lage limit) | jouw persoonlijke key | +| `STRIPE_KEY` | `sk_live_...` | `sk_test_...` | `sk_test_...` | +| `NEXT_PUBLIC_APP_URL` | je-app.com | preview-url | localhost:3000 | + +**Waarom is dit belangrijk?** +- Preview branches mogen NIET stagecoach naar je productie-database schrijven +- Test API-keys voorkomen kosten/quota-problemen bij experiments +- Eén branch = één geïsoleerde wereld om in te testen + +**Cursor Background Agent + Vercel preview = killer combo:** +Agent opent PR → preview URL automatisch in PR-comment → reviewer test live in browser, geen lokale setup nodig. --- @@ -224,31 +222,33 @@ jobs: --- -## Slide 10: LIVE DEMO 1 — Pokédex met Composer +## Slide 10: LIVE DEMO 1 — Pokédex met Composer + rendering modes ### ~30 min **Wat ik laat zien:** 1. `pnpm create next-app pokedex --typescript --tailwind --app` 2. Open in Cursor -3. **Composer (`Cmd+I`)**: "Bouw een lijst-pagina met de eerste 151 Pokémon van PokéAPI, gebruik Tailwind cards" -4. Composer maakt: `app/page.tsx` met fetch + map + cards +3. **Composer (`Cmd+I`)**: "Bouw een lijst-pagina met de eerste 151 Pokémon van PokéAPI als statische pagina. Gebruik Tailwind cards. De fetch moet static zijn — geen revalidate." +4. Composer maakt: `app/page.tsx` met `fetch(URL)` (static) + map + cards 5. `pnpm dev` — werkt -6. **Composer**: "Voeg detail-pagina toe op /pokemon/[name] met sprite + types + stats" -7. Composer maakt: `app/pokemon/[name]/page.tsx` -8. Cards op homepage linken naar detail-pages -9. Klein bugje fix-en in chat: "de cards zijn te smal" +6. **Composer**: "Voeg detail-pagina toe op /pokemon/[name] met sprite + types + stats. Gebruik ISR met revalidate van 3600 seconden." +7. Composer maakt: `app/pokemon/[name]/page.tsx` met `{ next: { revalidate: 3600 } }` +8. **Bewijs in de browser:** open detail-pagina, refresh — direct geladen (statisch). Verander URL → andere Pokémon → ook snel (ISR cache). +9. **Show de Network tab:** geen calls naar PokéAPI vanuit browser, alles server. +10. **Bonus:** maak één pagina met `cache: "no-store"` (dynamic) zodat studenten alle drie de modi gezien hebben. **Belangrijk om uit te leggen:** - Composer is een TAB in Cursor — niet hetzelfde als Chat - Multi-file edits zichtbaar als diffs — je accepteert per file - Terminal commands vragen toestemming +- De rendering-mode is één optie in `fetch()` — verder verandert je code niet **Visual:** Cursor screenshot met Composer panel. --- -## Slide 11: LIVE DEMO 2 — Deploy naar Vercel productie -### ~15 min +## Slide 11: LIVE DEMO 2 — Deploy naar Vercel + Environment variables +### ~20 min **Wat ik laat zien:** 1. **GitHub:** new repo `pokedex` — public @@ -261,15 +261,24 @@ jobs: git push -u origin main ``` 3. **Vercel:** Add New → Import Git Repository → kies `pokedex` → Deploy -4. Wachten 60-90s op build -5. Open productie URL — werkt! -6. **Wijziging:** title aanpassen, push naar main → 2e deploy, ~30s +4. Wachten 60-90s op build → Productie URL — werkt! +5. **Environment Variables demo:** voeg een var toe in `app/page.tsx`: + ```tsx + <p>Omgeving: {process.env.NEXT_PUBLIC_APP_ENV}</p> + ``` +6. **Vercel → Settings → Environment Variables:** + - `NEXT_PUBLIC_APP_ENV` = `production` → vinkje bij Production + - `NEXT_PUBLIC_APP_ENV` = `preview` → vinkje bij Preview + - Lokaal: `.env.local` → `NEXT_PUBLIC_APP_ENV=development` +7. Redeploy → productie URL toont "production" +8. Maak feature branch `chore/banner`, push → preview URL toont "preview" +9. Lokaal `pnpm dev` → toont "development" **Wat studenten moeten zien:** -- One-time setup (Vercel verbinden) -- Daarna: push to main = deploy -- Build logs in Vercel dashboard -- Custom domain mogelijk (skipping vandaag) +- Push to main = productie deploy +- Push to andere branch = preview deploy (eigen URL) +- Per omgeving andere env-waarden +- Voor secrets: vinkje **alleen** bij Production (preview-key gebruiken in preview!) --- @@ -375,21 +384,18 @@ Beide branches kunnen tegelijk draaien. **Vandaag gezien:** - Externe API integratie in Server Components +- Static / ISR / Dynamic / Client — vier rendering modes - Cursor Composer voor synchrone changes - Cursor Background Agent voor async features - Vercel productie + preview per branch +- Environment variables per omgeving (production / preview / development) - GitHub Actions CI (lint + build) -- Wanneer welke Cursor-modus -**Volgende les (Les 16): MCP — Model Context Protocol** -- Wat is MCP (Model Context Protocol) -- Bestaande MCP servers gebruiken in Cursor/Claude Desktop -- Eigen MCP server bouwen + laden -- Demo: eigen tools beschikbaar in alle MCP-clients - -**Daarna in deze leerlijn:** -- Les 17: Externe APIs in diepte (OAuth, webhooks, paid APIs) -- Les 18: Supabase Auth + RLS — multi-user apps +**Volgende les (Les 14): Agents** +- LLM in een loop met tools, autonoom 20-50 stappen +- `ToolLoopAgent`, `stopWhen`, `prepareStep` +- Research-agent from scratch +- Wanneer wel/niet agents gebruiken **Vragen? Feedback?** diff --git a/Les13-Cursor-Vercel-Deploy/Les13-Slides.pdf b/Les13-Cursor-Vercel-Deploy/Les13-Slides.pdf index b9da99f..ec92408 100644 Binary files a/Les13-Cursor-Vercel-Deploy/Les13-Slides.pdf and b/Les13-Cursor-Vercel-Deploy/Les13-Slides.pdf differ diff --git a/Les13-Cursor-Vercel-Deploy/Les13-Slides.pptx b/Les13-Cursor-Vercel-Deploy/Les13-Slides.pptx index 2d5150f..2173dfc 100644 Binary files a/Les13-Cursor-Vercel-Deploy/Les13-Slides.pptx and b/Les13-Cursor-Vercel-Deploy/Les13-Slides.pptx differ diff --git a/Les13-Cursor-Vercel-Deploy/lesbestanden/pokedex-finished.zip b/Les13-Cursor-Vercel-Deploy/lesbestanden/pokedex-finished.zip new file mode 100644 index 0000000..4b4ee26 Binary files /dev/null and b/Les13-Cursor-Vercel-Deploy/lesbestanden/pokedex-finished.zip differ diff --git a/Les13-Cursor-Vercel-Deploy/lesbestanden/pokedex-starter.zip b/Les13-Cursor-Vercel-Deploy/lesbestanden/pokedex-starter.zip new file mode 100644 index 0000000..8613deb Binary files /dev/null and b/Les13-Cursor-Vercel-Deploy/lesbestanden/pokedex-starter.zip differ diff --git a/Les14-Agents/lesbestanden/research-agent-finished.zip b/Les14-Agents/lesbestanden/research-agent-finished.zip new file mode 100644 index 0000000..29c620c Binary files /dev/null and b/Les14-Agents/lesbestanden/research-agent-finished.zip differ diff --git a/Les14-Agents/lesbestanden/research-agent-starter.zip b/Les14-Agents/lesbestanden/research-agent-starter.zip new file mode 100644 index 0000000..e7c75b1 Binary files /dev/null and b/Les14-Agents/lesbestanden/research-agent-starter.zip differ diff --git a/Les15-RAG-Embeddings/lesbestanden/rag-finished.zip b/Les15-RAG-Embeddings/lesbestanden/rag-finished.zip new file mode 100644 index 0000000..b7e41b1 Binary files /dev/null and b/Les15-RAG-Embeddings/lesbestanden/rag-finished.zip differ diff --git a/Les15-RAG-Embeddings/lesbestanden/rag-starter.zip b/Les15-RAG-Embeddings/lesbestanden/rag-starter.zip new file mode 100644 index 0000000..f2b667e Binary files /dev/null and b/Les15-RAG-Embeddings/lesbestanden/rag-starter.zip differ diff --git a/Les16-MCP/lesbestanden/mcp-starter.zip b/Les16-MCP/lesbestanden/mcp-starter.zip new file mode 100644 index 0000000..2ae68c3 Binary files /dev/null and b/Les16-MCP/lesbestanden/mcp-starter.zip differ diff --git a/Les16-MCP/lesbestanden/polderfest-mcp-finished.zip b/Les16-MCP/lesbestanden/polderfest-mcp-finished.zip new file mode 100644 index 0000000..fd4edef Binary files /dev/null and b/Les16-MCP/lesbestanden/polderfest-mcp-finished.zip differ diff --git a/Les17-Production-Polish/lesbestanden/polderfest-polish-finished.zip b/Les17-Production-Polish/lesbestanden/polderfest-polish-finished.zip new file mode 100644 index 0000000..afe301f Binary files /dev/null and b/Les17-Production-Polish/lesbestanden/polderfest-polish-finished.zip differ diff --git a/Les17-Production-Polish/lesbestanden/polderfest-starter.zip b/Les17-Production-Polish/lesbestanden/polderfest-starter.zip new file mode 100644 index 0000000..86b5ee7 Binary files /dev/null and b/Les17-Production-Polish/lesbestanden/polderfest-starter.zip differ diff --git a/Les18-AI-Toolbox-Next/lesbestanden/ai-toolbox-5-demos.zip b/Les18-AI-Toolbox-Next/lesbestanden/ai-toolbox-5-demos.zip new file mode 100644 index 0000000..2d5f1b8 Binary files /dev/null and b/Les18-AI-Toolbox-Next/lesbestanden/ai-toolbox-5-demos.zip differ