From 0af4ab367c892641ff036e652f4e1e5eab66893a Mon Sep 17 00:00:00 2001 From: joshuasilva414 Date: Tue, 27 Oct 2026 20:25:33 -0500 Subject: [PATCH 1/5] initial split --- .github/workflows/apps.yml | 82 + .github/workflows/integration.yml | 96 + .github/workflows/web.yml | 132 - .gitignore | 30 +- .npmrc | 3 + .prettierignore | 14 +- .prettierrc | 2 +- .tours/01-repository-map.tour | 72 + .tours/02-core-startup.tour | 83 + .tours/03-core-domain.tour | 119 + .tours/04-plugin-system.tour | 101 + .tours/05-cli-route-sync.tour | 59 + .tours/06-request-flow.tour | 113 + .tours/07-integrations-apps.tour | 107 + .tours/08-verification.tour | 86 + .tours/README.md | 26 + README.md | 21 +- apps/demo/.dev.vars.example | 6 + apps/demo/.env.example | 1 + apps/demo/README.md | 44 + .../{web => demo}/app/admin/check-in/page.tsx | 0 .../app/admin/events/[id]/edit/page.tsx | 0 .../app/admin/events/new/page.tsx | 0 apps/{web => demo}/app/admin/events/page.tsx | 0 apps/{web => demo}/app/admin/layout.tsx | 0 apps/{web => demo}/app/admin/page.tsx | 0 apps/{web => demo}/app/admin/roles/page.tsx | 0 .../app/admin/scanner/[eventId]/page.tsx | 0 .../{web => demo}/app/admin/settings/page.tsx | 0 .../app/admin/users/[authId]/page.tsx | 0 apps/{web => demo}/app/admin/users/page.tsx | 0 .../app/api/admin/export/route.ts | 0 .../app/api/auth/[...all]/route.ts | 0 apps/demo/app/api/files/register/route.ts | 23 + apps/demo/app/api/files/upload/route.ts | 36 + apps/demo/app/api/files/view/route.ts | 54 + .../app/api/hackkit/[...path]/route.ts | 0 apps/{web => demo}/app/app-bar.tsx | 0 apps/{web => demo}/app/contact/page.tsx | 0 apps/{web => demo}/app/dashboard/layout.tsx | 0 apps/{web => demo}/app/dashboard/page.tsx | 0 apps/demo/app/demo-actions.tsx | 84 + apps/{web => demo}/app/globals.css | 0 apps/{web => demo}/app/help/page.tsx | 0 apps/{web => demo}/app/i/approval/layout.tsx | 0 apps/{web => demo}/app/i/approval/page.tsx | 0 apps/{web => demo}/app/invites/layout.tsx | 0 apps/{web => demo}/app/invites/page.tsx | 0 apps/demo/app/layout.tsx | 45 + .../onboarding/hacker/hacker-form-defaults.ts | 0 .../hacker/hacker-registration-client.tsx | 0 .../app/onboarding/hacker/page.tsx | 0 .../app/onboarding/hacktag/page.tsx | 0 apps/{web => demo}/app/onboarding/layout.tsx | 0 .../app/onboarding/onboarding-shell.tsx | 0 .../app/onboarding/user-data/page.tsx | 0 apps/demo/app/page.tsx | 55 + apps/{web => demo}/app/participant-layout.tsx | 0 .../app/pass/event-pass-shell.tsx | 0 apps/{web => demo}/app/pass/layout.tsx | 0 apps/{web => demo}/app/pass/page.tsx | 0 apps/{web => demo}/app/profile-menu.tsx | 1 + apps/{web => demo}/app/providers.tsx | 0 apps/{web => demo}/app/register/page.tsx | 0 .../app/registration-closed/page.tsx | 0 apps/{web => demo}/app/rsvp/layout.tsx | 0 apps/{web => demo}/app/rsvp/page.tsx | 0 .../app/schedule/[eventId]/page.tsx | 0 apps/{web => demo}/app/schedule/page.tsx | 0 apps/{web => demo}/app/settings/layout.tsx | 0 apps/{web => demo}/app/settings/page.tsx | 0 .../app/settings/profile-settings-client.tsx | 0 .../app/settings/registration/page.tsx | 0 apps/{web => demo}/app/sign-in/auth-form.tsx | 0 apps/{web => demo}/app/sign-in/page.tsx | 4 +- apps/{web => demo}/app/sign-up/page.tsx | 4 +- apps/{web => demo}/app/suspended/page.tsx | 0 apps/{web => demo}/app/teams/layout.tsx | 0 apps/{web => demo}/app/teams/page.tsx | 0 apps/{web => demo}/app/user/[tag]/page.tsx | 0 apps/demo/db/migrations/sqlite/.snapshot.json | 3800 ++++ .../Migration20261020221614_demo_initial.ts | 258 + apps/demo/env.ts | 25 + apps/demo/hackkit.config.ts | 138 + apps/demo/hackkit.lock | 20 + apps/demo/lib/app-config.ts | 15 + apps/{web => demo}/lib/auth-client.ts | 0 apps/demo/lib/auth-options.ts | 8 + apps/{web => demo}/lib/auth.ts | 0 apps/demo/lib/blob.ts | 65 + apps/demo/lib/database-config.ts | 16 + apps/demo/lib/demo-accounts.ts | 20 + apps/{web => demo}/lib/hackkit-ui-routes.ts | 0 apps/demo/lib/http-libsql-dialect.ts | 66 + apps/{web => demo}/lib/logger.ts | 0 apps/{web => demo}/lib/onboarding.ts | 0 apps/{web => demo}/lib/plugin-navigation.ts | 0 apps/demo/lib/public-site-config.ts | 249 + apps/demo/lib/runtime.ts | 43 + .../{web => demo}/lib/upload-profile-photo.ts | 0 apps/{web => demo}/lib/upload-resume.ts | 0 apps/{web => demo}/middleware.ts | 0 apps/demo/next-env.d.ts | 7 + apps/demo/next.config.mjs | 2 + apps/demo/package.json | 72 + apps/demo/playwright.config.ts | 31 + apps/{web => demo}/postcss.config.cjs | 0 apps/demo/scripts/build.mjs | 20 + apps/demo/scripts/compile-orm.mjs | 24 + apps/demo/scripts/database.ts | 120 + apps/demo/scripts/db.mjs | 62 + apps/demo/scripts/orm.config.mjs | 5 + apps/demo/scripts/seed.mjs | 9 + apps/demo/scripts/seed.ts | 101 + apps/demo/scripts/test-database.mjs | 56 + apps/demo/tailwind.config.ts | 60 + apps/demo/tests/demo.spec.ts | 235 + apps/demo/tsconfig.json | 44 + apps/demo/tsconfig.typecheck.json | 22 + apps/demo/vite.config.ts | 21 + apps/demo/worker/env.d.ts | 43 + apps/demo/wrangler.jsonc | 15 + apps/docs/.gitignore | 26 + apps/docs/README.md | 16 + apps/docs/app/(home)/layout.tsx | 6 + apps/docs/app/(home)/page.tsx | 76 + apps/docs/app/api/search/route.ts | 9 + apps/docs/app/docs/[[...slug]]/page.tsx | 64 + apps/docs/app/docs/layout.tsx | 11 + apps/docs/app/global.css | 12 + apps/docs/app/layout.tsx | 18 + apps/docs/app/llms-full.txt/route.ts | 7 + .../app/llms.mdx/docs/[[...slug]]/route.ts | 27 + apps/docs/app/llms.txt/route.ts | 7 + apps/docs/app/og/docs/[...slug]/route.tsx | 28 + apps/docs/components/mdx.tsx | 15 + apps/docs/components/provider.tsx | 8 + apps/docs/components/search.tsx | 35 + apps/docs/content/docs/administration.mdx | 20 + apps/docs/content/docs/architecture.mdx | 27 + apps/docs/content/docs/configuration.mdx | 22 + apps/docs/content/docs/database.mdx | 31 + apps/docs/content/docs/demo.mdx | 32 + apps/docs/content/docs/deployment.mdx | 37 + apps/docs/content/docs/getting-started.mdx | 38 + apps/docs/content/docs/index.mdx | 25 + apps/docs/content/docs/meta.json | 16 + apps/docs/content/docs/plugins.mdx | 30 + apps/docs/content/docs/templates.mdx | 23 + apps/docs/content/docs/testing.mdx | 28 + apps/docs/lib/cn.ts | 1 + apps/docs/lib/layout.shared.tsx | 12 + apps/docs/lib/shared.ts | 29 + apps/docs/lib/source.ts | 30 + apps/docs/next.config.mjs | 11 + apps/docs/package.json | 35 + apps/docs/postcss.config.mjs | 7 + apps/docs/tsconfig.json | 34 + apps/docs/wrangler.jsonc | 12 + apps/web/scripts/test-db-workflow.sh | 54 - apps/web/scripts/test-runtime.mjs | 236 - docs/guides/database-migrations.md | 32 +- docs/guides/next-integration.md | 4 +- docs/plans/template-distribution.md | 16 + e2e/README.md | 37 + e2e/browser/participant.spec.ts | 95 + e2e/browser/teams.spec.ts | 56 + .../database}/database-workflow.test.ts | 7 +- .../database}/dialects.test.ts | 7 +- .../database}/migration-fixture-schema.ts | 0 .../database}/migration-workflow.test.ts | 12 +- .../database}/migration-workflow.ts | 13 +- .../database}/profile-concurrency.ts | 2 +- e2e/database/templates.test.ts | 138 + e2e/http/runtime.spec.ts | 215 + e2e/package.json | 33 + e2e/playwright.config.ts | 30 + e2e/support/accounts.ts | 96 + e2e/support/browser.ts | 85 + e2e/support/database-env.ts | 10 + e2e/support/database-task.mjs | 34 + e2e/support/fixtures.ts | 57 + e2e/support/processes.mjs | 50 + e2e/support/run.mjs | 100 + e2e/support/server.mjs | 108 + e2e/support/templates.mjs | 72 + e2e/tsconfig.json | 10 + e2e/vitest.config.ts | 26 + package.json | 38 +- packages/config/src/__tests__/config.test.ts | 26 +- .../src/__tests__/fixtures/hackkit.config.ts | 5 + packages/config/src/index.ts | 5 +- packages/core/package.json | 3 +- packages/core/src/mikro/options.ts | 2 + packages/next/README.md | 2 +- packages/plugin-teams/package.json | 3 + .../src/components/team-dashboard.tsx | 2 +- packages/ui/package.json | 3 + .../src/components/admin-console-controls.tsx | 189 +- packages/ui/src/components/admin-console.tsx | 100 +- .../components/hacker-registration-form.tsx | 5 +- packages/ui/src/components/public-shell.tsx | 16 +- packages/ui/src/components/user-data-form.tsx | 5 +- .../components/user-profile-settings-form.tsx | 39 +- pnpm-lock.yaml | 15526 +++++++++++----- pnpm-workspace.yaml | 20 + templates/nextjs-full/.env.example | 64 + {apps/web => templates/nextjs-full}/README.md | 33 +- .../nextjs-full/app/admin/check-in/page.tsx | 30 + .../app/admin/events/[id]/edit/page.tsx | 49 + .../nextjs-full/app/admin/events/new/page.tsx | 29 + .../nextjs-full/app/admin/events/page.tsx | 44 + templates/nextjs-full/app/admin/layout.tsx | 50 + templates/nextjs-full/app/admin/page.tsx | 24 + .../nextjs-full/app/admin/roles/page.tsx | 26 + .../app/admin/scanner/[eventId]/page.tsx | 44 + .../nextjs-full/app/admin/settings/page.tsx | 28 + .../app/admin/users/[authId]/page.tsx | 36 + .../nextjs-full/app/admin/users/page.tsx | 23 + .../nextjs-full/app/api/admin/export/route.ts | 57 + .../app/api/auth/[...all]/route.ts | 9 + .../app/api/files/register/route.ts | 0 .../app/api/files/upload/route.ts | 0 .../nextjs-full}/app/api/files/view/route.ts | 0 .../app/api/hackkit/[...path]/route.ts | 4 + templates/nextjs-full/app/app-bar.tsx | 80 + templates/nextjs-full/app/contact/page.tsx | 1 + .../nextjs-full/app/dashboard/layout.tsx | 1 + templates/nextjs-full/app/dashboard/page.tsx | 71 + .../nextjs-full}/app/discord/page.tsx | 0 .../nextjs-full}/app/discord/verify/page.tsx | 0 templates/nextjs-full/app/globals.css | 58 + templates/nextjs-full/app/help/page.tsx | 13 + .../nextjs-full/app/i/approval/layout.tsx | 14 + templates/nextjs-full/app/i/approval/page.tsx | 27 + templates/nextjs-full/app/invites/layout.tsx | 1 + templates/nextjs-full/app/invites/page.tsx | 4 + .../nextjs-full}/app/layout.tsx | 0 .../onboarding/hacker/hacker-form-defaults.ts | 18 + .../hacker/hacker-registration-client.tsx | 45 + .../app/onboarding/hacker/page.tsx | 40 + .../app/onboarding/hacktag/page.tsx | 30 + .../nextjs-full/app/onboarding/layout.tsx | 14 + .../app/onboarding/onboarding-shell.tsx | 35 + .../app/onboarding/user-data/page.tsx | 38 + .../nextjs-full}/app/page.tsx | 0 .../nextjs-full/app/participant-layout.tsx | 14 + .../nextjs-full/app/pass/event-pass-shell.tsx | 42 + templates/nextjs-full/app/pass/layout.tsx | 1 + templates/nextjs-full/app/pass/page.tsx | 22 + templates/nextjs-full/app/profile-menu.tsx | 116 + templates/nextjs-full/app/providers.tsx | 12 + templates/nextjs-full/app/register/page.tsx | 5 + .../app/registration-closed/page.tsx | 26 + templates/nextjs-full/app/rsvp/layout.tsx | 1 + templates/nextjs-full/app/rsvp/page.tsx | 19 + .../app/schedule/[eventId]/page.tsx | 37 + templates/nextjs-full/app/schedule/page.tsx | 29 + templates/nextjs-full/app/settings/layout.tsx | 1 + templates/nextjs-full/app/settings/page.tsx | 53 + .../app/settings/profile-settings-client.tsx | 14 + .../app/settings/registration/page.tsx | 54 + .../nextjs-full/app/sign-in/auth-form.tsx | 100 + templates/nextjs-full/app/sign-in/page.tsx | 24 + templates/nextjs-full/app/sign-up/page.tsx | 27 + templates/nextjs-full/app/suspended/page.tsx | 18 + templates/nextjs-full/app/teams/layout.tsx | 1 + templates/nextjs-full/app/teams/page.tsx | 4 + templates/nextjs-full/app/user/[tag]/page.tsx | 23 + .../db/migrations/mysql/.snapshot.json | 0 .../mysql/Migration20260927180400_initial.ts | 0 .../db/migrations/postgresql/.snapshot.json | 0 .../Migration20260927180400_initial.ts | 0 .../db/migrations/sqlite/.snapshot.json | 0 .../sqlite/Migration20260927180400_initial.ts | 0 {apps/web => templates/nextjs-full}/env.ts | 0 .../nextjs-full}/hackkit.config.ts | 0 .../nextjs-full}/hackkit.lock | 0 .../nextjs-full}/lib/app-config.ts | 0 templates/nextjs-full/lib/auth-client.ts | 5 + .../nextjs-full}/lib/auth-options.ts | 0 templates/nextjs-full/lib/auth.ts | 11 + .../web => templates/nextjs-full}/lib/blob.ts | 0 .../nextjs-full}/lib/database-config.ts | 0 .../nextjs-full/lib/hackkit-ui-routes.ts | 7 + templates/nextjs-full/lib/logger.ts | 11 + templates/nextjs-full/lib/onboarding.ts | 54 + .../nextjs-full/lib/plugin-navigation.ts | 20 + .../nextjs-full}/lib/public-site-config.ts | 0 .../nextjs-full}/lib/runtime.ts | 0 .../nextjs-full/lib/upload-profile-photo.ts | 34 + templates/nextjs-full/lib/upload-resume.ts | 59 + templates/nextjs-full/middleware.ts | 72 + .../nextjs-full}/next-env.d.ts | 0 .../nextjs-full}/next.config.mjs | 0 .../nextjs-full}/package.json | 12 +- templates/nextjs-full/postcss.config.cjs | 6 + .../nextjs-full}/scripts/database.ts | 0 .../nextjs-full}/scripts/db.mjs | 0 templates/nextjs-full/tailwind.config.ts | 60 + .../nextjs-full}/tsconfig.json | 0 templates/nextjs-minimal/.env.example | 18 + templates/nextjs-minimal/README.md | 38 + templates/nextjs-minimal/app/admin/layout.tsx | 48 + templates/nextjs-minimal/app/admin/page.tsx | 27 + .../nextjs-minimal/app/admin/roles/page.tsx | 26 + .../app/admin/settings/page.tsx | 38 + .../app/admin/users/[authId]/page.tsx | 40 + .../nextjs-minimal/app/admin/users/page.tsx | 26 + .../app/api/admin/export/route.ts | 57 + .../app/api/auth/[...all]/route.ts | 9 + .../app/api/files/register/route.ts | 41 + .../app/api/files/upload/route.ts | 30 + .../app/api/files/view/route.ts | 55 + .../app/api/hackkit/[...path]/route.ts | 4 + templates/nextjs-minimal/app/app-bar.tsx | 79 + templates/nextjs-minimal/app/contact/page.tsx | 1 + .../nextjs-minimal/app/dashboard/layout.tsx | 1 + .../nextjs-minimal/app/dashboard/page.tsx | 68 + templates/nextjs-minimal/app/globals.css | 58 + templates/nextjs-minimal/app/help/page.tsx | 13 + .../nextjs-minimal/app/i/approval/layout.tsx | 14 + .../nextjs-minimal/app/i/approval/page.tsx | 26 + templates/nextjs-minimal/app/layout.tsx | 38 + .../onboarding/hacker/hacker-form-defaults.ts | 18 + .../hacker/hacker-registration-client.tsx | 45 + .../app/onboarding/hacker/page.tsx | 40 + .../app/onboarding/hacktag/page.tsx | 30 + .../nextjs-minimal/app/onboarding/layout.tsx | 14 + .../app/onboarding/onboarding-shell.tsx | 35 + .../app/onboarding/user-data/page.tsx | 38 + templates/nextjs-minimal/app/page.tsx | 17 + .../nextjs-minimal/app/participant-layout.tsx | 14 + templates/nextjs-minimal/app/profile-menu.tsx | 116 + templates/nextjs-minimal/app/providers.tsx | 12 + .../nextjs-minimal/app/register/page.tsx | 5 + .../app/registration-closed/page.tsx | 26 + .../nextjs-minimal/app/settings/layout.tsx | 1 + .../nextjs-minimal/app/settings/page.tsx | 36 + .../app/settings/profile-settings-client.tsx | 15 + .../app/settings/registration/page.tsx | 54 + .../nextjs-minimal/app/sign-in/auth-form.tsx | 100 + templates/nextjs-minimal/app/sign-in/page.tsx | 24 + templates/nextjs-minimal/app/sign-up/page.tsx | 27 + .../nextjs-minimal/app/suspended/page.tsx | 18 + .../nextjs-minimal/app/user/[tag]/page.tsx | 23 + .../db/migrations/sqlite/.snapshot.json | 3334 ++++ .../sqlite/Migration20261020200349_initial.ts | 101 + templates/nextjs-minimal/env.ts | 49 + templates/nextjs-minimal/hackkit.config.ts | 105 + templates/nextjs-minimal/hackkit.lock | 4 + templates/nextjs-minimal/lib/app-config.ts | 11 + templates/nextjs-minimal/lib/auth-client.ts | 5 + templates/nextjs-minimal/lib/auth-options.ts | 8 + templates/nextjs-minimal/lib/auth.ts | 11 + templates/nextjs-minimal/lib/blob.ts | 11 + .../nextjs-minimal/lib/database-config.ts | 19 + .../nextjs-minimal/lib/hackkit-ui-routes.ts | 7 + templates/nextjs-minimal/lib/logger.ts | 11 + templates/nextjs-minimal/lib/onboarding.ts | 54 + .../nextjs-minimal/lib/public-site-config.ts | 122 + templates/nextjs-minimal/lib/runtime.ts | 35 + .../lib/upload-profile-photo.ts | 34 + templates/nextjs-minimal/lib/upload-resume.ts | 59 + templates/nextjs-minimal/middleware.ts | 68 + templates/nextjs-minimal/next-env.d.ts | 5 + templates/nextjs-minimal/next.config.mjs | 20 + templates/nextjs-minimal/package.json | 50 + templates/nextjs-minimal/postcss.config.cjs | 6 + templates/nextjs-minimal/scripts/database.ts | 146 + templates/nextjs-minimal/scripts/db.mjs | 66 + .../nextjs-minimal}/tailwind.config.ts | 0 templates/nextjs-minimal/tsconfig.json | 23 + tooling/check-client-bundle.mjs | 68 +- turbo.json | 203 +- 375 files changed, 28151 insertions(+), 5645 deletions(-) create mode 100644 .github/workflows/apps.yml create mode 100644 .github/workflows/integration.yml delete mode 100644 .github/workflows/web.yml create mode 100644 .tours/01-repository-map.tour create mode 100644 .tours/02-core-startup.tour create mode 100644 .tours/03-core-domain.tour create mode 100644 .tours/04-plugin-system.tour create mode 100644 .tours/05-cli-route-sync.tour create mode 100644 .tours/06-request-flow.tour create mode 100644 .tours/07-integrations-apps.tour create mode 100644 .tours/08-verification.tour create mode 100644 .tours/README.md create mode 100644 apps/demo/.dev.vars.example create mode 100644 apps/demo/.env.example create mode 100644 apps/demo/README.md rename apps/{web => demo}/app/admin/check-in/page.tsx (100%) rename apps/{web => demo}/app/admin/events/[id]/edit/page.tsx (100%) rename apps/{web => demo}/app/admin/events/new/page.tsx (100%) rename apps/{web => demo}/app/admin/events/page.tsx (100%) rename apps/{web => demo}/app/admin/layout.tsx (100%) rename apps/{web => demo}/app/admin/page.tsx (100%) rename apps/{web => demo}/app/admin/roles/page.tsx (100%) rename apps/{web => demo}/app/admin/scanner/[eventId]/page.tsx (100%) rename apps/{web => demo}/app/admin/settings/page.tsx (100%) rename apps/{web => demo}/app/admin/users/[authId]/page.tsx (100%) rename apps/{web => demo}/app/admin/users/page.tsx (100%) rename apps/{web => demo}/app/api/admin/export/route.ts (100%) rename apps/{web => demo}/app/api/auth/[...all]/route.ts (100%) create mode 100644 apps/demo/app/api/files/register/route.ts create mode 100644 apps/demo/app/api/files/upload/route.ts create mode 100644 apps/demo/app/api/files/view/route.ts rename apps/{web => demo}/app/api/hackkit/[...path]/route.ts (100%) rename apps/{web => demo}/app/app-bar.tsx (100%) rename apps/{web => demo}/app/contact/page.tsx (100%) rename apps/{web => demo}/app/dashboard/layout.tsx (100%) rename apps/{web => demo}/app/dashboard/page.tsx (100%) create mode 100644 apps/demo/app/demo-actions.tsx rename apps/{web => demo}/app/globals.css (100%) rename apps/{web => demo}/app/help/page.tsx (100%) rename apps/{web => demo}/app/i/approval/layout.tsx (100%) rename apps/{web => demo}/app/i/approval/page.tsx (100%) rename apps/{web => demo}/app/invites/layout.tsx (100%) rename apps/{web => demo}/app/invites/page.tsx (100%) create mode 100644 apps/demo/app/layout.tsx rename apps/{web => demo}/app/onboarding/hacker/hacker-form-defaults.ts (100%) rename apps/{web => demo}/app/onboarding/hacker/hacker-registration-client.tsx (100%) rename apps/{web => demo}/app/onboarding/hacker/page.tsx (100%) rename apps/{web => demo}/app/onboarding/hacktag/page.tsx (100%) rename apps/{web => demo}/app/onboarding/layout.tsx (100%) rename apps/{web => demo}/app/onboarding/onboarding-shell.tsx (100%) rename apps/{web => demo}/app/onboarding/user-data/page.tsx (100%) create mode 100644 apps/demo/app/page.tsx rename apps/{web => demo}/app/participant-layout.tsx (100%) rename apps/{web => demo}/app/pass/event-pass-shell.tsx (100%) rename apps/{web => demo}/app/pass/layout.tsx (100%) rename apps/{web => demo}/app/pass/page.tsx (100%) rename apps/{web => demo}/app/profile-menu.tsx (98%) rename apps/{web => demo}/app/providers.tsx (100%) rename apps/{web => demo}/app/register/page.tsx (100%) rename apps/{web => demo}/app/registration-closed/page.tsx (100%) rename apps/{web => demo}/app/rsvp/layout.tsx (100%) rename apps/{web => demo}/app/rsvp/page.tsx (100%) rename apps/{web => demo}/app/schedule/[eventId]/page.tsx (100%) rename apps/{web => demo}/app/schedule/page.tsx (100%) rename apps/{web => demo}/app/settings/layout.tsx (100%) rename apps/{web => demo}/app/settings/page.tsx (100%) rename apps/{web => demo}/app/settings/profile-settings-client.tsx (100%) rename apps/{web => demo}/app/settings/registration/page.tsx (100%) rename apps/{web => demo}/app/sign-in/auth-form.tsx (100%) rename apps/{web => demo}/app/sign-in/page.tsx (86%) rename apps/{web => demo}/app/sign-up/page.tsx (89%) rename apps/{web => demo}/app/suspended/page.tsx (100%) rename apps/{web => demo}/app/teams/layout.tsx (100%) rename apps/{web => demo}/app/teams/page.tsx (100%) rename apps/{web => demo}/app/user/[tag]/page.tsx (100%) create mode 100644 apps/demo/db/migrations/sqlite/.snapshot.json create mode 100644 apps/demo/db/migrations/sqlite/Migration20261020221614_demo_initial.ts create mode 100644 apps/demo/env.ts create mode 100644 apps/demo/hackkit.config.ts create mode 100644 apps/demo/hackkit.lock create mode 100644 apps/demo/lib/app-config.ts rename apps/{web => demo}/lib/auth-client.ts (100%) create mode 100644 apps/demo/lib/auth-options.ts rename apps/{web => demo}/lib/auth.ts (100%) create mode 100644 apps/demo/lib/blob.ts create mode 100644 apps/demo/lib/database-config.ts create mode 100644 apps/demo/lib/demo-accounts.ts rename apps/{web => demo}/lib/hackkit-ui-routes.ts (100%) create mode 100644 apps/demo/lib/http-libsql-dialect.ts rename apps/{web => demo}/lib/logger.ts (100%) rename apps/{web => demo}/lib/onboarding.ts (100%) rename apps/{web => demo}/lib/plugin-navigation.ts (100%) create mode 100644 apps/demo/lib/public-site-config.ts create mode 100644 apps/demo/lib/runtime.ts rename apps/{web => demo}/lib/upload-profile-photo.ts (100%) rename apps/{web => demo}/lib/upload-resume.ts (100%) rename apps/{web => demo}/middleware.ts (100%) create mode 100644 apps/demo/next-env.d.ts create mode 100644 apps/demo/next.config.mjs create mode 100644 apps/demo/package.json create mode 100644 apps/demo/playwright.config.ts rename apps/{web => demo}/postcss.config.cjs (100%) create mode 100644 apps/demo/scripts/build.mjs create mode 100644 apps/demo/scripts/compile-orm.mjs create mode 100644 apps/demo/scripts/database.ts create mode 100644 apps/demo/scripts/db.mjs create mode 100644 apps/demo/scripts/orm.config.mjs create mode 100644 apps/demo/scripts/seed.mjs create mode 100644 apps/demo/scripts/seed.ts create mode 100644 apps/demo/scripts/test-database.mjs create mode 100644 apps/demo/tailwind.config.ts create mode 100644 apps/demo/tests/demo.spec.ts create mode 100644 apps/demo/tsconfig.json create mode 100644 apps/demo/tsconfig.typecheck.json create mode 100644 apps/demo/vite.config.ts create mode 100644 apps/demo/worker/env.d.ts create mode 100644 apps/demo/wrangler.jsonc create mode 100644 apps/docs/.gitignore create mode 100644 apps/docs/README.md create mode 100644 apps/docs/app/(home)/layout.tsx create mode 100644 apps/docs/app/(home)/page.tsx create mode 100644 apps/docs/app/api/search/route.ts create mode 100644 apps/docs/app/docs/[[...slug]]/page.tsx create mode 100644 apps/docs/app/docs/layout.tsx create mode 100644 apps/docs/app/global.css create mode 100644 apps/docs/app/layout.tsx create mode 100644 apps/docs/app/llms-full.txt/route.ts create mode 100644 apps/docs/app/llms.mdx/docs/[[...slug]]/route.ts create mode 100644 apps/docs/app/llms.txt/route.ts create mode 100644 apps/docs/app/og/docs/[...slug]/route.tsx create mode 100644 apps/docs/components/mdx.tsx create mode 100644 apps/docs/components/provider.tsx create mode 100644 apps/docs/components/search.tsx create mode 100644 apps/docs/content/docs/administration.mdx create mode 100644 apps/docs/content/docs/architecture.mdx create mode 100644 apps/docs/content/docs/configuration.mdx create mode 100644 apps/docs/content/docs/database.mdx create mode 100644 apps/docs/content/docs/demo.mdx create mode 100644 apps/docs/content/docs/deployment.mdx create mode 100644 apps/docs/content/docs/getting-started.mdx create mode 100644 apps/docs/content/docs/index.mdx create mode 100644 apps/docs/content/docs/meta.json create mode 100644 apps/docs/content/docs/plugins.mdx create mode 100644 apps/docs/content/docs/templates.mdx create mode 100644 apps/docs/content/docs/testing.mdx create mode 100644 apps/docs/lib/cn.ts create mode 100644 apps/docs/lib/layout.shared.tsx create mode 100644 apps/docs/lib/shared.ts create mode 100644 apps/docs/lib/source.ts create mode 100644 apps/docs/next.config.mjs create mode 100644 apps/docs/package.json create mode 100644 apps/docs/postcss.config.mjs create mode 100644 apps/docs/tsconfig.json create mode 100644 apps/docs/wrangler.jsonc delete mode 100644 apps/web/scripts/test-db-workflow.sh delete mode 100644 apps/web/scripts/test-runtime.mjs create mode 100644 docs/plans/template-distribution.md create mode 100644 e2e/README.md create mode 100644 e2e/browser/participant.spec.ts create mode 100644 e2e/browser/teams.spec.ts rename {apps/web/db/__tests__ => e2e/database}/database-workflow.test.ts (88%) rename {apps/web/db/__tests__ => e2e/database}/dialects.test.ts (98%) rename {apps/web/db/__tests__ => e2e/database}/migration-fixture-schema.ts (100%) rename {apps/web/db/__tests__ => e2e/database}/migration-workflow.test.ts (89%) rename {apps/web/db/__tests__ => e2e/database}/migration-workflow.ts (96%) rename {apps/web/db/__tests__ => e2e/database}/profile-concurrency.ts (98%) create mode 100644 e2e/database/templates.test.ts create mode 100644 e2e/http/runtime.spec.ts create mode 100644 e2e/package.json create mode 100644 e2e/playwright.config.ts create mode 100644 e2e/support/accounts.ts create mode 100644 e2e/support/browser.ts create mode 100644 e2e/support/database-env.ts create mode 100644 e2e/support/database-task.mjs create mode 100644 e2e/support/fixtures.ts create mode 100644 e2e/support/processes.mjs create mode 100644 e2e/support/run.mjs create mode 100644 e2e/support/server.mjs create mode 100644 e2e/support/templates.mjs create mode 100644 e2e/tsconfig.json create mode 100644 e2e/vitest.config.ts create mode 100644 packages/config/src/__tests__/fixtures/hackkit.config.ts create mode 100644 templates/nextjs-full/.env.example rename {apps/web => templates/nextjs-full}/README.md (67%) create mode 100644 templates/nextjs-full/app/admin/check-in/page.tsx create mode 100644 templates/nextjs-full/app/admin/events/[id]/edit/page.tsx create mode 100644 templates/nextjs-full/app/admin/events/new/page.tsx create mode 100644 templates/nextjs-full/app/admin/events/page.tsx create mode 100644 templates/nextjs-full/app/admin/layout.tsx create mode 100644 templates/nextjs-full/app/admin/page.tsx create mode 100644 templates/nextjs-full/app/admin/roles/page.tsx create mode 100644 templates/nextjs-full/app/admin/scanner/[eventId]/page.tsx create mode 100644 templates/nextjs-full/app/admin/settings/page.tsx create mode 100644 templates/nextjs-full/app/admin/users/[authId]/page.tsx create mode 100644 templates/nextjs-full/app/admin/users/page.tsx create mode 100644 templates/nextjs-full/app/api/admin/export/route.ts create mode 100644 templates/nextjs-full/app/api/auth/[...all]/route.ts rename {apps/web => templates/nextjs-full}/app/api/files/register/route.ts (100%) rename {apps/web => templates/nextjs-full}/app/api/files/upload/route.ts (100%) rename {apps/web => templates/nextjs-full}/app/api/files/view/route.ts (100%) create mode 100644 templates/nextjs-full/app/api/hackkit/[...path]/route.ts create mode 100644 templates/nextjs-full/app/app-bar.tsx create mode 100644 templates/nextjs-full/app/contact/page.tsx create mode 100644 templates/nextjs-full/app/dashboard/layout.tsx create mode 100644 templates/nextjs-full/app/dashboard/page.tsx rename {apps/web => templates/nextjs-full}/app/discord/page.tsx (100%) rename {apps/web => templates/nextjs-full}/app/discord/verify/page.tsx (100%) create mode 100644 templates/nextjs-full/app/globals.css create mode 100644 templates/nextjs-full/app/help/page.tsx create mode 100644 templates/nextjs-full/app/i/approval/layout.tsx create mode 100644 templates/nextjs-full/app/i/approval/page.tsx create mode 100644 templates/nextjs-full/app/invites/layout.tsx create mode 100644 templates/nextjs-full/app/invites/page.tsx rename {apps/web => templates/nextjs-full}/app/layout.tsx (100%) create mode 100644 templates/nextjs-full/app/onboarding/hacker/hacker-form-defaults.ts create mode 100644 templates/nextjs-full/app/onboarding/hacker/hacker-registration-client.tsx create mode 100644 templates/nextjs-full/app/onboarding/hacker/page.tsx create mode 100644 templates/nextjs-full/app/onboarding/hacktag/page.tsx create mode 100644 templates/nextjs-full/app/onboarding/layout.tsx create mode 100644 templates/nextjs-full/app/onboarding/onboarding-shell.tsx create mode 100644 templates/nextjs-full/app/onboarding/user-data/page.tsx rename {apps/web => templates/nextjs-full}/app/page.tsx (100%) create mode 100644 templates/nextjs-full/app/participant-layout.tsx create mode 100644 templates/nextjs-full/app/pass/event-pass-shell.tsx create mode 100644 templates/nextjs-full/app/pass/layout.tsx create mode 100644 templates/nextjs-full/app/pass/page.tsx create mode 100644 templates/nextjs-full/app/profile-menu.tsx create mode 100644 templates/nextjs-full/app/providers.tsx create mode 100644 templates/nextjs-full/app/register/page.tsx create mode 100644 templates/nextjs-full/app/registration-closed/page.tsx create mode 100644 templates/nextjs-full/app/rsvp/layout.tsx create mode 100644 templates/nextjs-full/app/rsvp/page.tsx create mode 100644 templates/nextjs-full/app/schedule/[eventId]/page.tsx create mode 100644 templates/nextjs-full/app/schedule/page.tsx create mode 100644 templates/nextjs-full/app/settings/layout.tsx create mode 100644 templates/nextjs-full/app/settings/page.tsx create mode 100644 templates/nextjs-full/app/settings/profile-settings-client.tsx create mode 100644 templates/nextjs-full/app/settings/registration/page.tsx create mode 100644 templates/nextjs-full/app/sign-in/auth-form.tsx create mode 100644 templates/nextjs-full/app/sign-in/page.tsx create mode 100644 templates/nextjs-full/app/sign-up/page.tsx create mode 100644 templates/nextjs-full/app/suspended/page.tsx create mode 100644 templates/nextjs-full/app/teams/layout.tsx create mode 100644 templates/nextjs-full/app/teams/page.tsx create mode 100644 templates/nextjs-full/app/user/[tag]/page.tsx rename {apps/web => templates/nextjs-full}/db/migrations/mysql/.snapshot.json (100%) rename {apps/web => templates/nextjs-full}/db/migrations/mysql/Migration20260927180400_initial.ts (100%) rename {apps/web => templates/nextjs-full}/db/migrations/postgresql/.snapshot.json (100%) rename {apps/web => templates/nextjs-full}/db/migrations/postgresql/Migration20260927180400_initial.ts (100%) rename {apps/web => templates/nextjs-full}/db/migrations/sqlite/.snapshot.json (100%) rename {apps/web => templates/nextjs-full}/db/migrations/sqlite/Migration20260927180400_initial.ts (100%) rename {apps/web => templates/nextjs-full}/env.ts (100%) rename {apps/web => templates/nextjs-full}/hackkit.config.ts (100%) rename {apps/web => templates/nextjs-full}/hackkit.lock (100%) rename {apps/web => templates/nextjs-full}/lib/app-config.ts (100%) create mode 100644 templates/nextjs-full/lib/auth-client.ts rename {apps/web => templates/nextjs-full}/lib/auth-options.ts (100%) create mode 100644 templates/nextjs-full/lib/auth.ts rename {apps/web => templates/nextjs-full}/lib/blob.ts (100%) rename {apps/web => templates/nextjs-full}/lib/database-config.ts (100%) create mode 100644 templates/nextjs-full/lib/hackkit-ui-routes.ts create mode 100644 templates/nextjs-full/lib/logger.ts create mode 100644 templates/nextjs-full/lib/onboarding.ts create mode 100644 templates/nextjs-full/lib/plugin-navigation.ts rename {apps/web => templates/nextjs-full}/lib/public-site-config.ts (100%) rename {apps/web => templates/nextjs-full}/lib/runtime.ts (100%) create mode 100644 templates/nextjs-full/lib/upload-profile-photo.ts create mode 100644 templates/nextjs-full/lib/upload-resume.ts create mode 100644 templates/nextjs-full/middleware.ts rename {apps/web => templates/nextjs-full}/next-env.d.ts (100%) rename {apps/web => templates/nextjs-full}/next.config.mjs (100%) rename {apps/web => templates/nextjs-full}/package.json (77%) create mode 100644 templates/nextjs-full/postcss.config.cjs rename {apps/web => templates/nextjs-full}/scripts/database.ts (100%) rename {apps/web => templates/nextjs-full}/scripts/db.mjs (100%) create mode 100644 templates/nextjs-full/tailwind.config.ts rename {apps/web => templates/nextjs-full}/tsconfig.json (100%) create mode 100644 templates/nextjs-minimal/.env.example create mode 100644 templates/nextjs-minimal/README.md create mode 100644 templates/nextjs-minimal/app/admin/layout.tsx create mode 100644 templates/nextjs-minimal/app/admin/page.tsx create mode 100644 templates/nextjs-minimal/app/admin/roles/page.tsx create mode 100644 templates/nextjs-minimal/app/admin/settings/page.tsx create mode 100644 templates/nextjs-minimal/app/admin/users/[authId]/page.tsx create mode 100644 templates/nextjs-minimal/app/admin/users/page.tsx create mode 100644 templates/nextjs-minimal/app/api/admin/export/route.ts create mode 100644 templates/nextjs-minimal/app/api/auth/[...all]/route.ts create mode 100644 templates/nextjs-minimal/app/api/files/register/route.ts create mode 100644 templates/nextjs-minimal/app/api/files/upload/route.ts create mode 100644 templates/nextjs-minimal/app/api/files/view/route.ts create mode 100644 templates/nextjs-minimal/app/api/hackkit/[...path]/route.ts create mode 100644 templates/nextjs-minimal/app/app-bar.tsx create mode 100644 templates/nextjs-minimal/app/contact/page.tsx create mode 100644 templates/nextjs-minimal/app/dashboard/layout.tsx create mode 100644 templates/nextjs-minimal/app/dashboard/page.tsx create mode 100644 templates/nextjs-minimal/app/globals.css create mode 100644 templates/nextjs-minimal/app/help/page.tsx create mode 100644 templates/nextjs-minimal/app/i/approval/layout.tsx create mode 100644 templates/nextjs-minimal/app/i/approval/page.tsx create mode 100644 templates/nextjs-minimal/app/layout.tsx create mode 100644 templates/nextjs-minimal/app/onboarding/hacker/hacker-form-defaults.ts create mode 100644 templates/nextjs-minimal/app/onboarding/hacker/hacker-registration-client.tsx create mode 100644 templates/nextjs-minimal/app/onboarding/hacker/page.tsx create mode 100644 templates/nextjs-minimal/app/onboarding/hacktag/page.tsx create mode 100644 templates/nextjs-minimal/app/onboarding/layout.tsx create mode 100644 templates/nextjs-minimal/app/onboarding/onboarding-shell.tsx create mode 100644 templates/nextjs-minimal/app/onboarding/user-data/page.tsx create mode 100644 templates/nextjs-minimal/app/page.tsx create mode 100644 templates/nextjs-minimal/app/participant-layout.tsx create mode 100644 templates/nextjs-minimal/app/profile-menu.tsx create mode 100644 templates/nextjs-minimal/app/providers.tsx create mode 100644 templates/nextjs-minimal/app/register/page.tsx create mode 100644 templates/nextjs-minimal/app/registration-closed/page.tsx create mode 100644 templates/nextjs-minimal/app/settings/layout.tsx create mode 100644 templates/nextjs-minimal/app/settings/page.tsx create mode 100644 templates/nextjs-minimal/app/settings/profile-settings-client.tsx create mode 100644 templates/nextjs-minimal/app/settings/registration/page.tsx create mode 100644 templates/nextjs-minimal/app/sign-in/auth-form.tsx create mode 100644 templates/nextjs-minimal/app/sign-in/page.tsx create mode 100644 templates/nextjs-minimal/app/sign-up/page.tsx create mode 100644 templates/nextjs-minimal/app/suspended/page.tsx create mode 100644 templates/nextjs-minimal/app/user/[tag]/page.tsx create mode 100644 templates/nextjs-minimal/db/migrations/sqlite/.snapshot.json create mode 100644 templates/nextjs-minimal/db/migrations/sqlite/Migration20261020200349_initial.ts create mode 100644 templates/nextjs-minimal/env.ts create mode 100644 templates/nextjs-minimal/hackkit.config.ts create mode 100644 templates/nextjs-minimal/hackkit.lock create mode 100644 templates/nextjs-minimal/lib/app-config.ts create mode 100644 templates/nextjs-minimal/lib/auth-client.ts create mode 100644 templates/nextjs-minimal/lib/auth-options.ts create mode 100644 templates/nextjs-minimal/lib/auth.ts create mode 100644 templates/nextjs-minimal/lib/blob.ts create mode 100644 templates/nextjs-minimal/lib/database-config.ts create mode 100644 templates/nextjs-minimal/lib/hackkit-ui-routes.ts create mode 100644 templates/nextjs-minimal/lib/logger.ts create mode 100644 templates/nextjs-minimal/lib/onboarding.ts create mode 100644 templates/nextjs-minimal/lib/public-site-config.ts create mode 100644 templates/nextjs-minimal/lib/runtime.ts create mode 100644 templates/nextjs-minimal/lib/upload-profile-photo.ts create mode 100644 templates/nextjs-minimal/lib/upload-resume.ts create mode 100644 templates/nextjs-minimal/middleware.ts create mode 100644 templates/nextjs-minimal/next-env.d.ts create mode 100644 templates/nextjs-minimal/next.config.mjs create mode 100644 templates/nextjs-minimal/package.json create mode 100644 templates/nextjs-minimal/postcss.config.cjs create mode 100644 templates/nextjs-minimal/scripts/database.ts create mode 100644 templates/nextjs-minimal/scripts/db.mjs rename {apps/web => templates/nextjs-minimal}/tailwind.config.ts (100%) create mode 100644 templates/nextjs-minimal/tsconfig.json diff --git a/.github/workflows/apps.yml b/.github/workflows/apps.yml new file mode 100644 index 000000000..2923951a7 --- /dev/null +++ b/.github/workflows/apps.yml @@ -0,0 +1,82 @@ +name: Demo and documentation + +on: + pull_request: + paths: + - "apps/demo/**" + - "apps/docs/**" + - "packages/**" + - "package.json" + - "pnpm-workspace.yaml" + - ".npmrc" + - "pnpm-lock.yaml" + - "turbo.json" + - "tooling/**" + - ".github/workflows/apps.yml" + +jobs: + docs: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: pnpm/action-setup@v4 + - uses: actions/setup-node@v4 + with: + node-version: "24" + cache: pnpm + - run: pnpm install --frozen-lockfile + - run: pnpm build:docs + - run: pnpm --filter @hackkit/docs typecheck + - run: pnpm --filter @hackkit/docs deploy:check + demo: + runs-on: ubuntu-latest + services: + libsql: + image: ghcr.io/tursodatabase/libsql-server:latest + env: + SQLD_NODE: standalone + SQLD_HTTP_LISTEN_ADDR: 0.0.0.0:8080 + ports: + - 8080:8080 + steps: + - uses: actions/checkout@v4 + - uses: pnpm/action-setup@v4 + - uses: actions/setup-node@v4 + with: + node-version: "24" + cache: pnpm + - run: pnpm install --frozen-lockfile + - run: pnpm exec turbo run build --filter=@hackkit/demo^... + - run: pnpm --filter @hackkit/demo plugin:sync + - run: git diff --exit-code -- apps/demo/app apps/demo/hackkit.lock + - run: pnpm --filter @hackkit/demo typecheck + - run: node tooling/check-client-bundle.mjs + - name: Configure disposable database and local Worker bindings + run: | + mkdir -p apps/demo/.wrangler + cat > apps/demo/.dev.vars <<'EOF' + TURSO_DATABASE_URL=http://127.0.0.1:8080 + TURSO_AUTH_TOKEN=local-ci-no-remote-access + BETTER_AUTH_SECRET=ci-only-secret-for-disposable-demo-testing + BETTER_AUTH_URL=http://localhost:3001 + EOF + curl --fail --retry 20 --retry-connrefused --retry-delay 2 http://127.0.0.1:8080/health + - run: pnpm --filter @hackkit/demo db:demo + - run: pnpm --filter @hackkit/demo db:check + - run: pnpm --filter @hackkit/demo test:database + - run: pnpm --filter @hackkit/demo build + - run: pnpm --filter @hackkit/demo deploy:check + - run: pnpm --filter @hackkit/demo exec playwright install --with-deps chromium + - run: pnpm --filter @hackkit/demo test:smoke + env: + DEMO_TEST_URL: http://localhost:3001 + - name: Upload failure diagnostics + if: failure() + uses: actions/upload-artifact@v4 + with: + name: demo-diagnostics + path: | + apps/demo/test-results + apps/demo/playwright-report + apps/demo/.wrangler/ci-server.log + if-no-files-found: ignore diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml new file mode 100644 index 000000000..df2c3d9a7 --- /dev/null +++ b/.github/workflows/integration.yml @@ -0,0 +1,96 @@ +name: Templates and E2E + +on: + pull_request: + paths: + - "templates/**" + - "e2e/**" + - "packages/**" + - "tooling/**" + - "package.json" + - "pnpm-workspace.yaml" + - ".npmrc" + - "pnpm-lock.yaml" + - "turbo.json" + - ".github/workflows/integration.yml" + +jobs: + packages: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: pnpm/action-setup@v4 + - uses: actions/setup-node@v4 + with: + node-version: "22.17.0" + cache: pnpm + - run: pnpm install --frozen-lockfile + - run: pnpm test + - run: pnpm exec turbo run typecheck --filter='./packages/*' + + e2e: + runs-on: ubuntu-latest + services: + postgres: + image: postgres:16 + env: + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres + POSTGRES_DB: hackkit + ports: + - 5432:5432 + options: >- + --health-cmd "pg_isready -U postgres -d hackkit" + --health-interval 10s + --health-timeout 5s + --health-retries 5 + + mysql: + image: mysql:8.4 + env: + MYSQL_ROOT_PASSWORD: mysql + MYSQL_DATABASE: hackkit + ports: + - 3306:3306 + options: >- + --health-cmd "mysqladmin ping -h 127.0.0.1 -pmysql" + --health-interval 10s + --health-timeout 5s + --health-retries 10 + libsql: + image: ghcr.io/tursodatabase/libsql-server:latest + env: + SQLD_NODE: standalone + SQLD_HTTP_LISTEN_ADDR: 0.0.0.0:8080 + ports: + - 8080:8080 + + steps: + - uses: actions/checkout@v4 + - uses: pnpm/action-setup@v4 + - uses: actions/setup-node@v4 + with: + node-version: "22.17.0" + cache: pnpm + - run: pnpm install --frozen-lockfile + - run: pnpm --filter @hackkit/e2e exec playwright install --with-deps chromium + - name: Wait for network libSQL + run: curl --fail --retry 20 --retry-connrefused --retry-delay 2 http://127.0.0.1:8080/health + - name: Validate templates and all integrations + env: + HACKKIT_REQUIRE_DATABASE_MATRIX: "1" + HACKKIT_TEST_POSTGRESQL_URL: postgresql://postgres:postgres@127.0.0.1:5432/hackkit + HACKKIT_TEST_MYSQL_URL: mysql://root:mysql@127.0.0.1:3306/hackkit + HACKKIT_TEST_LIBSQL_URL: http://127.0.0.1:8080 + run: pnpm test:e2e + - name: Verify generated plugin files are committed + run: git diff --exit-code -- templates/*/app templates/*/hackkit.lock + - name: Upload failure diagnostics + if: failure() + uses: actions/upload-artifact@v4 + with: + name: e2e-diagnostics + path: | + e2e/test-results + e2e/playwright-report + if-no-files-found: ignore diff --git a/.github/workflows/web.yml b/.github/workflows/web.yml deleted file mode 100644 index e2a0dc4be..000000000 --- a/.github/workflows/web.yml +++ /dev/null @@ -1,132 +0,0 @@ -name: Web - -on: - pull_request: - paths: - - "apps/web/**" - - "packages/**" - - "pnpm-lock.yaml" - - "turbo.json" - - ".github/workflows/web.yml" - -jobs: - build: - runs-on: ubuntu-latest - - services: - postgres: - image: postgres:16 - env: - POSTGRES_USER: postgres - POSTGRES_PASSWORD: postgres - POSTGRES_DB: hackkit - ports: - - 5432:5432 - options: >- - --health-cmd "pg_isready -U postgres -d hackkit" - --health-interval 10s - --health-timeout 5s - --health-retries 5 - - mysql: - image: mysql:8.4 - env: - MYSQL_ROOT_PASSWORD: mysql - MYSQL_DATABASE: hackkit - ports: - - 3306:3306 - options: >- - --health-cmd "mysqladmin ping -h 127.0.0.1 -pmysql" - --health-interval 10s - --health-timeout 5s - --health-retries 10 - libsql: - image: ghcr.io/tursodatabase/libsql-server:latest - env: - SQLD_NODE: standalone - SQLD_HTTP_LISTEN_ADDR: 0.0.0.0:8080 - ports: - - 8080:8080 - - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Set up pnpm - uses: pnpm/action-setup@v4 - - - name: Set up Node.js - uses: actions/setup-node@v4 - with: - node-version: "22.17.0" - cache: pnpm - - - name: Install dependencies - run: pnpm install --frozen-lockfile - - - name: Build web dependency graph - run: pnpm exec turbo run build --filter=web^... - - - name: Sync plugin files - working-directory: apps/web - run: pnpm plugin:sync - - - name: Verify generated plugin files are current - run: git diff --exit-code -- apps/web/app apps/web/hackkit.lock - - - name: Wait for network libSQL - run: curl --fail --retry 20 --retry-connrefused --retry-delay 2 http://127.0.0.1:8080/health - - - name: Test all SQL drivers against committed migrations - env: - HACKKIT_REQUIRE_DATABASE_MATRIX: "1" - HACKKIT_TEST_POSTGRESQL_URL: postgresql://postgres:postgres@127.0.0.1:5432/hackkit - HACKKIT_TEST_MYSQL_URL: mysql://root:mysql@127.0.0.1:3306/hackkit - HACKKIT_TEST_LIBSQL_URL: http://127.0.0.1:8080 - run: pnpm --filter web test:db-matrix - - - name: Test database workflow isolation - run: pnpm --filter web test:db-workflow - - - name: Package tests - run: | - pnpm --filter web test - pnpm --filter @hackkit/core test - pnpm --filter @hackkit/cli test - pnpm --filter @hackkit/config test - pnpm --filter @hackkit/next test - pnpm --filter @hackkit/plugin-teams test - pnpm --filter @hackkit/plugin-discord test - pnpm --filter @hackkit/plugin-notifications-email test - - - name: Prepare isolated build database - env: - DATABASE_URL: file:.data/ci.db - run: | - mkdir -p apps/web/.data - pnpm --filter web db:migrate - pnpm --filter web db:seed - - - name: Typecheck - run: pnpm --filter web typecheck - - - name: Build web - env: - DATABASE_URL: file:.data/ci.db - NEXT_PUBLIC_APP_URL: https://web-ci.example.com - BETTER_AUTH_URL: https://web-ci.example.com - BETTER_AUTH_SECRET: ci-web-secret-that-is-at-least-32-characters - HACKKIT_BLOB_ADAPTER: s3 - HACKKIT_S3_BUCKET: ci-bucket - HACKKIT_S3_REGION: auto - HACKKIT_S3_ENDPOINT: https://example.r2.cloudflarestorage.com - HACKKIT_S3_ACCESS_KEY_ID: ci-access-key - HACKKIT_S3_SECRET_ACCESS_KEY: ci-secret-key - DISCORD_GUILD_ID: ci-guild - DISCORD_BOT_API_URL: https://discord-bot-ci.example.com - DISCORD_INTERNAL_AUTH_KEY: ci-internal-auth-key - DISCORD_PARTICIPANT_ROLE_ID: ci-participant-role - run: pnpm --filter web build - - - name: Test production HTTP runtime - run: pnpm --filter web test:runtime diff --git a/.gitignore b/.gitignore index 84cb2b5d5..de38cdb1c 100644 --- a/.gitignore +++ b/.gitignore @@ -47,7 +47,7 @@ yarn-error.log* sessions/ # web local sqlite -apps/web/.data/ +templates/*/.data/ # cursor .cursor/plans/ @@ -57,5 +57,33 @@ HANDOFF.md # build **/dist/ +experiments/ +scripts/ + # Local research notes /docs/research/**/*.md + +# Template-owned database commands must be tracked. +!templates/*/scripts/ +!templates/*/scripts/** + +# E2E artifacts +e2e/playwright-report/ +e2e/test-results/ + +# Deployable applications +apps/*/.data/ +.wrangler/ +.dev.vars +.dev.vars.* +!apps/demo/scripts/ +!apps/demo/scripts/** + +apps/demo/playwright-report/ +apps/demo/test-results/ + +# A credential-free reference for the demo Worker. +!apps/demo/.dev.vars.example + +.vinext/ +apps/demo/lib/generated/ diff --git a/.npmrc b/.npmrc index ded82e2f6..b257f8ad4 100644 --- a/.npmrc +++ b/.npmrc @@ -1 +1,4 @@ auto-install-peers = true +# Keep the React 18 templates and React 19 Worker/docs dependency contexts separate. +resolve-peers-from-workspace-root = false +dedupe-peer-dependents = false diff --git a/.prettierignore b/.prettierignore index b29406434..b6f949648 100644 --- a/.prettierignore +++ b/.prettierignore @@ -2,4 +2,16 @@ pnpm-lock.yaml pnpm-workspace.yaml **/package.json *.json -apps/web/db/migrations/** +templates/*/db/migrations/** + +e2e/playwright-report/ +e2e/test-results/ + +apps/docs/.source/ +apps/docs/out/ +apps/demo/playwright-report/ +apps/demo/test-results/ + +apps/demo/lib/generated/ +apps/demo/db/migrations/ +apps/demo/worker/env.d.ts diff --git a/.prettierrc b/.prettierrc index 836c001e9..a3051e7f3 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,6 +1,6 @@ { "plugins": ["prettier-plugin-tailwindcss"], - "tailwindConfig": "./apps/web/tailwind.config.ts", + "tailwindConfig": "./templates/nextjs-full/tailwind.config.ts", "semi": true, "singleQuote": false, "jsxSingleQuote": false, diff --git a/.tours/01-repository-map.tour b/.tours/01-repository-map.tour new file mode 100644 index 000000000..799588472 --- /dev/null +++ b/.tours/01-repository-map.tour @@ -0,0 +1,72 @@ +{ + "$schema": "https://aka.ms/codetour-schema", + "title": "01. Repository map and composition", + "steps": [ + { + "title": "What you will learn", + "description": "Start here with the repository root open in VS Code. These linked chapters explain the `templates-and-testing` working tree, including the template/E2E split. They use current files rather than a pinned commit, because the split includes uncommitted changes.\n\nFollow a participant who signs up, completes registration, creates a team, and receives event access. You will trace configuration into Core, then follow browser requests back to domain operations and persistence. Later chapters cover route generation, integrations, deployed apps, and verification.\n\nPrerequisites: TypeScript and basic React knowledge. An EntityManager is MikroORM's object for querying and tracking database records. A scope is one execution's EntityManager plus APIs that use it. Reading these tours does not start services, run migrations, or send external requests." + }, + { + "file": "pnpm-workspace.yaml", + "pattern": "packages:", + "title": "Locate each kind of workspace", + "description": "The workspace includes `packages/*`, `templates/*`, `apps/*`, and `e2e`. Packages contain reusable behavior. Templates are runnable reference applications. Apps contain the demo and documentation sites. E2E owns integration checks that exercise the real templates.\n\nThe full and minimal templates are application consumers of the packages. E2E does not keep a third copy of the application. Read this map before searching for the former `apps/web` path." + }, + { + "file": "package.json", + "pattern": "\"dev\": \"turbo run dev --filter=@hackkit/template-nextjs-full\"", + "title": "Choose the application explicitly", + "description": "Root `dev`, `start`, and `db:*` commands target the full template. `dev:minimal` selects the Core-only starter. `test` selects package tests, while `test:e2e` selects the integration workspace. Demo and docs have their own commands.\n\nUse the pinned pnpm through Corepack as described in the root README. These are command definitions to inspect, not instructions to reset or migrate a developer database. The database chapter explains their effects." + }, + { + "file": "turbo.json", + "pattern": "\"tasks\": \\{", + "title": "Read the task graph", + "description": "The `build` task depends on `^build`, which means the build task of dependency packages. A template can therefore import a library's `dist` output after Turbo builds that library. This is different from asking a package to depend on its own build.\n\nDevelopment and start tasks are persistent and uncached. Typechecking also builds dependencies first. The demo has a separate build override, and E2E tests disable caching. Outputs describe which generated files Turbo can restore; they do not replace runtime validation." + }, + { + "file": "packages/tsconfig/base.json", + "pattern": "\"strict\": true", + "title": "Share compiler defaults without hiding package boundaries", + "description": "The tsconfig workspace provides shared base, React-library, and Next configurations. Strict checking is a shared baseline. Individual packages still choose their own includes, outputs, and appropriate compiler configuration.\n\nCore's tsup.config.ts declares separate server, browser, testing, HTTP, and event-pass build entries and produces declarations. Package exports determine which entry a consumer imports. A source-level separation must also survive the build and published export map." + }, + { + "file": ".npmrc", + "pattern": "resolve-peers-from-workspace-root = false", + "title": "Keep the React dependency contexts separate", + "description": "The reference templates use React 18, while the Worker/demo and docs applications use React 19. These pnpm settings keep peer resolution from automatically using the workspace root and disable deduplication across peer contexts.\n\nA workspace install can therefore include different React contexts for separate applications. Inspect each package's actual dependencies before changing this setting or assuming all consumers run one framework version. The lockfile records the resolved contexts." + }, + { + "file": "packages/core/package.json", + "pattern": "\"\\./client\": \\{", + "title": "Find the browser and server entry points", + "description": "Core publishes several entry points. The main entry contains server/domain behavior. `/client` exports browser-safe schemas, constants, and DTO types. `/http` contains server endpoint construction. `/http/client` contains the browser transport.\n\nA DTO is a plain data object returned across a boundary. Importing its TypeScript type does not require importing the server implementation at runtime. This separation lets shared UI use validation and inferred endpoint types without bundling MikroORM or database drivers." + }, + { + "file": "templates/nextjs-full/hackkit.config.ts", + "pattern": "export default defineHackkitConfig\\(\\{", + "title": "Compose the full application", + "description": "The application chooses database options, Better Auth options, seed roles, file storage, registration choices, groups, event types, and plugin instances. Teams, Discord, and email notifications are declared in the `plugins` array below.\n\nThis file is the composition point. Core supplies behavior, but the host chooses which services and plugins exist. The plugin objects will feed both ORM discovery and scope creation. Provider factories defer optional service configuration until a plugin API is set up." + }, + { + "file": "templates/nextjs-minimal/hackkit.config.ts", + "pattern": "export default defineHackkitConfig\\(\\{", + "title": "Compare the minimal consumer", + "description": "The minimal template demonstrates Core registration, profiles, and administration without the full template's plugin set. Read its actual `plugins`, database, blob, and role configuration beside the full template.\n\nCore and Better Auth still need tables and migrations even when no feature plugins are enabled. The minimal template therefore has its own committed SQLite migration. Removing optional plugins does not remove the Core/auth lifecycle." + }, + { + "file": "packages/config/src/index.ts", + "pattern": "export function defineHackkitConfig", + "title": "Preserve the caller's inferred config type", + "description": "`defineHackkitConfig` returns its input unchanged. The const generic preserves specific configuration information in the inferred return type. This matters for literal plugin IDs and the API types associated with those plugins.\n\nIt does not validate environment credentials or initialize resources. `resolveHackkitConfig` below verifies that database driver and auth options exist, then supplies empty plugin and role lists when omitted. `loadHackkitConfig` uses Jiti to import a TypeScript config for CLI callers." + }, + { + "file": "templates/nextjs-full/lib/runtime.ts", + "pattern": "const host = createHackkitRuntimeFromConfig\\(\\{", + "title": "Connect application configuration to execution", + "description": "This server-only module creates the Next integration host from normalized app configuration. `setHackkitRuntime(host.getRuntime)` registers a factory for plugin-owned server pages. Convenience functions expose the current user's runtime and domain APIs.\n\nThe host keeps shared initialization, while `getRuntime` supplies request/render-specific state. The exported handler serves the catch-all HTTP route. Continue with [02. Core startup and persistence] to see what the host initializes." + } + ], + "isPrimary": true, + "nextTour": "02. Core startup and persistence" +} diff --git a/.tours/02-core-startup.tour b/.tours/02-core-startup.tour new file mode 100644 index 000000000..b63899bb9 --- /dev/null +++ b/.tours/02-core-startup.tour @@ -0,0 +1,83 @@ +{ + "$schema": "https://aka.ms/codetour-schema", + "title": "02. Core startup and persistence", + "steps": [ + { + "title": "What you will learn", + "description": "Goal: explain which resources are shared and which are rebuilt for each execution. Trace configuration into the entity registry, ORM, Better Auth, and a scoped `hackkit` object. Then inspect migration and role-seeding ownership.\n\nA database connection can be shared through an ORM instance. Managed entity objects and the current actor must belong to the execution that uses them." + }, + { + "file": "packages/core/src/runtime.ts", + "pattern": "export async function initializeHackkit", + "title": "Initialize shared resources once", + "description": "`initializeHackkit` receives database/auth options, plugins, optional app entities, and domain configuration. It builds a registry, initializes MikroORM using `createOrmOptions`, and creates Better Auth with the same ORM.\n\nIf auth construction fails after ORM initialization, it closes the ORM before rethrowing. The returned runtime exposes the shared `orm`, `auth`, and `registry`, plus factories for isolated executions. Startup does not apply migrations or seed roles." + }, + { + "file": "packages/core/src/plugins.ts", + "pattern": "export function createPluginRegistry", + "title": "Discover the complete schema", + "description": "The registry begins with Better Auth entities, Core models, Core permissions, and Core settings. Each plugin contributes its declarations, and application entities are appended afterward.\n\nThe function rejects duplicate plugin IDs, invalid plugin namespaces, duplicate setting/permission values, and duplicate entity names or tables. These checks run before the ORM relies on the schema. The plugin chapter will examine the runtime API contract separately." + }, + { + "file": "packages/core/src/mikro/options.ts", + "pattern": "export function createOrmOptions", + "title": "Use the same entity collection for runtime and migrations", + "description": "`createOrmOptions` rebuilds the registry from config, verifies that auth's requested tables and fields exist, and returns native MikroORM options with that entity list. It adds the Migrator extension while retaining configured extensions.\n\nBoth runtime initialization and database tools call this function. A plugin entity therefore enters ORM metadata through the same path in both places. Metadata discovery describes the desired schema; committed migrations still control changes to an existing database." + }, + { + "file": "packages/core/src/models.ts", + "pattern": "export const HackKitUser = defineEntity\\(\\{", + "title": "Keep one canonical user record", + "description": "`HackKitUser` maps to `core_user`. It contains auth identity fields and domain fields such as HackTag, role ID, approval status, and check-in time. The role reference maps to a primary key and uses a nullable foreign key.\n\nThe `p` builders define native MikroORM properties, defaults, relationships, and indexes. Nearby Core entities represent participant data, hacker registration, events, RSVP, settings, notifications, and operation locks. Plain domain types describe returned values; entity definitions describe persistence." + }, + { + "file": "packages/core/src/mikro/auth.ts", + "pattern": "export function resolveHackKitAuthOptions", + "title": "Map Better Auth onto Core's user table", + "description": "The application provides auth settings, but Core forces the user model to `core_user` and maps Better Auth's `image` field to `profilePhotoUrl`. Core creates the MikroORM database adapter in `createHackKitAuth`.\n\nThis avoids a second application profile row that would need synchronization with the auth user. Credentials, session policy, and providers still come from host options. Domain privileges stay behind Core APIs." + }, + { + "file": "packages/core/src/mikro/auth.ts", + "pattern": "export function assertAuthEntitySchema", + "title": "Reject unsupported auth schema before use", + "description": "Better Auth can require tables and fields according to its configuration. This function compares those requirements with registered entity metadata. A missing model or property throws with a request for a native entity and reviewed migration.\n\nIt also rejects exposing Core-owned user properties through auth field configuration. Enabling an auth feature is therefore a schema decision, not just a new provider option." + }, + { + "file": "packages/core/src/runtime.ts", + "pattern": "function createScope\\(actorAuthId\\?: string\\)", + "title": "Fork the EntityManager and construct scoped APIs", + "description": "Each call forks `orm.em` with context support and calls `createHackkit` using the fork, the shared registry, and the optional actor ID. A fork has its own identity map, the set of managed entity instances used by that execution.\n\nThe resulting scope contains `em` and `hackkit`. Plugin setup receives this same EntityManager. Do not retain this scoped API object as a global singleton. A later request must create its own scope." + }, + { + "file": "packages/core/src/runtime.ts", + "pattern": "return RequestContext\\.create\\(scope\\.em, \\(\\) => operation\\(scope\\)\\);", + "title": "Run a non-render operation in an ORM context", + "description": "`run` creates a scope, then executes the callback inside MikroORM's RequestContext. The callback receives the scope and returns a promise whose result becomes the result of `run`.\n\nThe HTTP handler uses this path after resolving a session. Context-aware ORM operations can resolve the correct manager during async work. Creating a request context is not a transaction around the whole request; domain operations create transactions where required." + }, + { + "file": "packages/core/src/hackkit.ts", + "pattern": "export function createHackkit", + "title": "Assemble Core around explicit dependencies", + "description": "`createHackkit` accepts an existing EntityManager. It resolves clock, ID generator, registration choices, event types, groups, and logger. It creates access control, settings, notifications, plugin APIs, and the domain API groups.\n\nThe function returns methods, not a listening server. Tests can inject time and ID functions. HTTP and Next integrations decide how to obtain the actor and invoke these methods. Keep transport details out of this composition function." + }, + { + "file": "templates/nextjs-full/scripts/database.ts", + "pattern": "export async function runDatabaseCommand", + "title": "Keep schema changes explicit and application-owned", + "description": "The template's database command runner owns generate, migrate, rollback, status, check, seed, and reset operations. It uses `createOrmOptions`, so it sees Core/auth/plugin/app entities, and always closes the ORM in `finally`.\n\n`check` examines pending migration history, entity-versus-snapshot differences, and live schema SQL. `reset` is destructive and restricted to a local SQLite database in development or tests. Reading this tour does not invoke it. Migration directories remain in the template that owns the deployed database." + }, + { + "file": "packages/core/src/seed.ts", + "pattern": "export async function seedRoles", + "title": "Seed roles without overwriting existing policy", + "description": "`seedRoles` inserts configured role IDs that are missing and skips IDs already present. It returns inserted and skipped IDs. Re-running it does not overwrite an administrator's existing role permissions.\n\nInitialization does not assign owner privileges automatically. Configured seed roles and the host's owner bootstrap procedure are separate concerns. Follow the template README before administering a real instance." + }, + { + "file": "packages/core/src/runtime.test.ts", + "pattern": "it\\(\"shares auth and connections while isolating domain execution scopes\"", + "title": "Check the shared-versus-scoped contract", + "description": "This test inspects runtime behavior across scopes. Read the assertions for different EntityManagers and domain reads, rather than assuming that shared auth implies shared managed entities.\n\nAlso inspect [auth lifecycle tests](./packages/core/src/mikro/auth-lifecycle.test.ts) for canonical user updates and privileged-field handling. These are source references, not a claim that the tests ran while authoring this tour. Continue with [03. Core domain behavior]." + } + ], + "nextTour": "03. Core domain behavior" +} diff --git a/.tours/03-core-domain.tour b/.tours/03-core-domain.tour new file mode 100644 index 000000000..924b4b92f --- /dev/null +++ b/.tours/03-core-domain.tour @@ -0,0 +1,119 @@ +{ + "$schema": "https://aka.ms/codetour-schema", + "title": "03. Core domain behavior", + "steps": [ + { + "title": "What you will learn", + "description": "Goal: trace the participant lifecycle through Core's actual functions. The scenario is a signed-in user who claims a HackTag, completes personal data, registers as a hacker, receives approval if required, and confirms attendance.\n\nServer callers must supply a trusted actor or target as each method requires. Authentication, authorization, validation, and transactions solve different problems. Watch where each one occurs." + }, + { + "file": "packages/core/src/hackkit.ts", + "pattern": "const runtimeContext: HackkitRuntimeContext = \\{", + "title": "Pass only the dependencies each API needs", + "description": "The context collects persistence, time, IDs, logging, configuration, permission helpers, and notifications. API factories receive this context or a typed subset of it.\n\n`createUsersApi` also receives registration policy and group behavior. `createEventsApi`, `createRsvpApi`, and `createAdminApi` return domain methods. These closures keep shared rules available without making every operation import a global runtime." + }, + { + "file": "packages/core/src/errors.ts", + "pattern": "export function parseInput", + "title": "Validate unknown domain inputs", + "description": "Core accepts `unknown` at many mutation boundaries. `parseInput` checks a Zod schema and turns validation failure into HackKit's domain error format. Successful parsing supplies the typed value used by the operation.\n\nHTTP endpoints also validate browser bodies, but Core methods remain usable from scripts and server code. Domain checks still need to run regardless of transport. Examine `schemas.ts` for field constraints and `user-data-options.ts` for configurable choices." + }, + { + "file": "packages/core/src/domain-log.ts", + "pattern": "export async function withDomainLog", + "title": "Log domain outcomes without changing returned errors", + "description": "This wrapper runs a domain callback and logs success when it returns. A known HackKitError records the stable error code and message. Unexpected errors use the error log level. Every failure is rethrown for the caller or HTTP layer to handle.\n\nThe logger is injected through Core configuration. This helper observes a callback outcome, not the final commit of every possible surrounding transaction. It is not a durable transaction audit table." + }, + { + "file": "packages/core/src/functions/users.ts", + "pattern": "async claimHackTag\\(input: unknown\\)", + "title": "Claim a public identifier", + "description": "`claimHackTag` parses the actor's request, uses an operation lock, and checks whether the requested HackTag is available before updating the canonical user. Follow normalization and conflict handling in the function.\n\nThis is the first participant-specific identity step after auth signup. The auth ID remains the persistence identity; the HackTag is a user-facing lookup value. The browser endpoint must supply the actor from its session." + }, + { + "file": "packages/core/src/hackkit.ts", + "pattern": "async completeUserData\\(input: unknown\\)", + "title": "Persist personal data before hacker registration", + "description": "The configured complete-user-data schema validates the input. Core checks the user exists, then updates or creates the user's data record inside the `user-data` operation lock. It preserves the original completion timestamp on edits and updates the modification timestamp.\n\nA completed auth account alone does not imply this row exists. `registerHacker` checks it explicitly. This ordering is also visible in the page guards and onboarding UI." + }, + { + "file": "packages/core/src/hackkit.ts", + "pattern": "async function registerHacker\\(input: unknown\\)", + "title": "Register atomically and preserve edit behavior", + "description": "`registerHacker` locks the registration decision, parses the input, and requires both an existing user and completed personal data. An existing hacker record is updated without re-running the policy for a new admission.\n\nFor a new record, the registration policy checks availability. Core creates the hacker, looks up the configured competitor role if present, and updates the user's role/approval fields before flushing. Failure must roll back the whole operation, including the hacker insert. The method returns a serialized Hacker value." + }, + { + "file": "packages/core/src/functions/registration-policy.ts", + "pattern": "async assertCanRegisterNewHacker\\(\\)", + "title": "Separate registration count from approved capacity", + "description": "The policy checks whether registration is open and whether the maximum registration count has been reached. A positive limit bounds admission; zero means unlimited.\n\nWhen approval is required, a new registration can remain pending. When approval is automatic, it also checks approved-hacker capacity before admission. `assertCanApproveUser` applies that capacity check when an existing registered user is approved later. Registration capacity and RSVP capacity are separate settings." + }, + { + "file": "packages/core/src/functions/users.ts", + "pattern": "async approveUser\\(input: unknown\\)", + "title": "Approve within capacity and assign a participant group", + "description": "`approveUser` shares the registration lock with admission. It requires `UsersApprove`, checks capacity when changing an unapproved user to approved, and applies role hierarchy to the target. It writes approval and then calls `groups.assignNextGroup` when approval is requested.\n\nThe group helper joins the surrounding transaction and keeps an existing assignment. This explicit approval path connects registration policy to group allocation. Automatic approval during new hacker registration does not call this function, so do not assume those paths perform identical group work." + }, + { + "file": "packages/core/src/functions/groups.ts", + "pattern": "async assignNextGroup\\(authId: AuthId\\)", + "title": "Choose the least-populated enabled group", + "description": "The method locks group allocation, returns null for a missing hacker, and preserves any existing group. With enabled groups, it counts registered hackers assigned to each, sorts by count, and breaks ties using configuration order.\n\nIt writes the chosen group to the hacker record and updates its timestamp. The result is a Hacker DTO. This module chooses an application group; Discord later translates that group into its configured role plan." + }, + { + "file": "packages/core/src/mikro/operation.ts", + "pattern": "export async function withOperationLock", + "title": "Protect read/check/write decisions across connections", + "description": "`withOperationLock` opens or joins a required transaction. It upserts a lock row with a fresh token and flushes before running the callback. The write obtains a database write/row lock before checks read capacity or membership.\n\nRelated operations use the same key, such as `registration` or `teams.membership`. A JavaScript mutex would protect only one process. This lock uses the database so separate connections coordinate. Unique constraint errors become `CONFLICT`. If this helper owns the transaction, it clears managed state after completion or failure. External network effects belong after commit." + }, + { + "file": "packages/core/src/access-control.ts", + "pattern": "async requirePermission\\(", + "title": "Load the principal and enforce role permissions", + "description": "An access principal contains the current user and their role. `requirePermission` resolves both and rejects a missing role or permission. `hasPermission` returns a boolean for a user with no role rather than throwing for that case.\n\nRole hierarchy is another rule. Lower position numbers outrank higher numbers, while SuperAdmin bypasses hierarchy. `assertCanGrantPermissions` prevents a non-super-admin from granting the SuperAdmin permission. A signed-in session alone does not grant administration rights." + }, + { + "file": "packages/core/src/hackkit.ts", + "pattern": "async assignRoleToUser\\(input: unknown\\)", + "title": "Check both current and replacement roles", + "description": "Role assignment requires `RolesAssign`. The actor must be allowed to manage the proposed role and, if the user has a current role, that current role too. The update occurs inside the roles operation lock.\n\nThis prevents an actor from bypassing hierarchy by demoting or replacing a role they cannot manage. Nearby create/update/delete methods apply their own permission, hierarchy, and assignment checks. Use these methods rather than writing `roleId` from a browser body." + }, + { + "file": "packages/core/src/functions/settings.ts", + "pattern": "async function getValue\\(key: SettingKey\\)", + "title": "Resolve stored values against registered definitions", + "description": "Settings definitions come from Core and plugins. Reads resolve the registered definition and stored override; absent overrides use the definition's default. Mutation methods below require settings-management permission and validate values against each definition.\n\nThis is how a plugin reads a team-size limit without owning a separate settings subsystem. Changing an app config default and writing a persisted setting are different operations. Inspect the resolver above this function to see which value wins." + }, + { + "file": "packages/core/src/functions/rsvp.ts", + "pattern": "async confirm\\(input: unknown\\)", + "title": "Confirm attendance or allocate a waitlist place", + "description": "`confirm` uses the `rsvp` lock, requires an approved registered hacker, and checks that RSVPs are open. An existing non-cancelled RSVP is returned unchanged. Otherwise it counts active confirmed records and chooses confirmed, waitlisted, or an error according to settings.\n\nThe function writes the RSVP and queues a notification intent before the transaction completes. Cancellation and administrative promotion have their own methods later in the file. Registration approval does not by itself reserve an RSVP place." + }, + { + "file": "packages/core/src/functions/users.ts", + "pattern": "async checkIn\\(input: unknown\\)", + "title": "Record organizer check-in without duplicating arrival", + "description": "`checkIn` requires `UsersCheckIn`, loads the target, rejects a user who is already checked in, and writes `checkedInAt` inside the `check-in` operation lock. It returns the refreshed plain user value.\n\nThis function records arrival. Group assignment occurs in the explicit approval path, which calls the groups API. Page guards, approval, check-in, and group assignment are distinct transitions; one timestamp does not establish that all of them occurred." + }, + { + "file": "packages/core/src/functions/events.ts", + "pattern": "async recordEventScan\\(input: unknown\\)", + "title": "Record event participation with prior-scan context", + "description": "The event scan operation parses its input, requires scanner permission, checks the event and target user, reads previous scans, and inserts another scan. Its result contains the new scan, prior scans, and a boolean indicating whether prior scans exist.\n\nA scan history can therefore support a repeated-scan warning without silently discarding the new record. Schedule visibility and event administration use separate methods earlier in this file. Inspect those permission checks when adding a new organizer workflow." + }, + { + "file": "packages/core/src/functions/admin.ts", + "pattern": "async function getOverview\\(input:", + "title": "Build administration views from Core records", + "description": "The admin API composes permission-checked data into dashboard and user views. It also exposes role/user lookup and export-related behavior. These methods are the server-side aggregation layer used by admin UI, rather than a second source of persistence models.\n\nFor a new dashboard statistic, trace its source records and authorization here before adding the rendered card. This keeps the meaning of a statistic consistent between views." + }, + { + "file": "packages/core/src/mikro/domain-transactions.test.ts", + "pattern": "it\\(\"admits only one concurrent registration into the final place\"", + "title": "Inspect the concurrency and rollback evidence", + "description": "This test competes for the last registration place. The earlier test in this file forces a role-assignment failure and checks rollback. Together they target observable domain outcomes, including behavior across transaction boundaries.\n\nFor related rules, read [RSVP tests](./packages/core/src/__tests__/rsvp.test.ts), [check-in tests](./packages/core/src/__tests__/check-in.test.ts), and [group tests](./packages/core/src/__tests__/groups.test.ts). Continue with [04. Plugin contracts and Teams]." + } + ], + "nextTour": "04. Plugin contracts and Teams" +} diff --git a/.tours/04-plugin-system.tour b/.tours/04-plugin-system.tour new file mode 100644 index 000000000..2c2d95c9c --- /dev/null +++ b/.tours/04-plugin-system.tour @@ -0,0 +1,101 @@ +{ + "$schema": "https://aka.ms/codetour-schema", + "title": "04. Plugin contracts and Teams", + "steps": [ + { + "title": "What you will learn", + "description": "Goal: understand how to build a plugin that participates in schema discovery, scoped domain APIs, HTTP transport, server pages, and client UI. Teams is the worked example.\n\nThere are two separate installation paths. Core composes runtime declarations and behavior. The CLI copies route reexports into a host application's filesystem. The next chapter explains that filesystem path." + }, + { + "file": "packages/core/src/plugins.ts", + "pattern": "export type HackKitPlugin<", + "title": "Read the plugin contract", + "description": "A plugin has a literal `id` and optional `enabled`, `packageName`, `entities`, `permissions`, `settings`, `endpoints`, and `setup` fields. These declarations have different lifetimes.\n\nEntities/settings/permissions describe composition. `endpoints` builds transport definitions around a request runner. `setup` receives an execution context and returns the plugin API. `packageName` lets the CLI find package-owned pages. A plugin may provide only some of these capabilities, as email notifications demonstrates." + }, + { + "file": "packages/core/src/plugins.ts", + "pattern": "export type HackKitPluginContext = \\{", + "title": "Use the execution context instead of global state", + "description": "The context supplies the scoped EntityManager, optional actor ID, user lookup, shared registry, setting reads, notifications, and groups. `setup` can close over these dependencies to create its API.\n\nThe registry is shared metadata; `em` and actor belong to this execution. Plugins should retain stable provider configuration separately from request-bound managed records. The actor is optional here because scripts and public server reads can create scopes without a session." + }, + { + "file": "packages/core/src/plugins.ts", + "pattern": "export type PluginApiMap<", + "title": "Infer API names and return types from the tuple", + "description": "The mapped type iterates over the union `TPlugins[number]`, remaps each member's key to its literal plugin ID, and infers its API type from `HackKitPlugin`.\n\nA known Teams tuple therefore gives `hackkit.plugins.teams` the API returned by `createTeamsApi`. Widening the tuple to a generic plugin array loses that specificity. This typing does not perform runtime discovery or verify permissions. The registry and API setup functions still enforce runtime behavior." + }, + { + "file": "packages/core/src/plugins.ts", + "pattern": "const prefix = `\\$\\{plugin\\.id\\.replaceAll\\(\"-\", \"_\"\\)\\}_`;", + "title": "Enforce plugin namespaces during registration", + "description": "Entity table names must begin with the plugin ID plus an underscore, with hyphens converted to underscores. Settings and permission values use the plugin ID followed by a dot.\n\nFor Teams this yields `teams_...` tables and `teams....` setting/permission values. The registry also checks duplicates. These checks make ownership visible and reject accidental overlap before initialization. They do not create a sandbox around arbitrary plugin code." + }, + { + "file": "packages/core/src/plugins.ts", + "pattern": "export function setupPluginApis", + "title": "Create each plugin API inside the current scope", + "description": "`setupPluginApis` walks the configured plugins and calls each enabled plugin's `setup(context)`. The result becomes the value at `hackkit.plugins[plugin.id]`; a plugin without setup gets an empty object.\n\nA disabled plugin receives an enumerable property getter that throws `INVALID_OPERATION` on access. Its entities, settings, and permissions remain registered. Disabling runtime behavior therefore does not request dropping its tables. The handler also omits disabled plugin endpoints." + }, + { + "file": "packages/plugin-teams/src/index.ts", + "pattern": "export function teamsPlugin\\(\\)", + "title": "Declare Teams' complete contribution", + "description": "`teamsPlugin` returns ID `teams`, its npm package name, models, a maximum-team-size setting, permission declarations, endpoint factory, and `setup: createTeamsApi`.\n\nThe return type preserves both the ID and `ReturnType`. Adding a domain method to that factory can update the plugin API type automatically. A browser-callable operation also needs an endpoint and client usage; adding a factory method alone does not expose an HTTP route." + }, + { + "file": "packages/plugin-teams/src/models.ts", + "pattern": "tableName: \"teams_member\",", + "title": "Enforce membership in the schema too", + "description": "The member entity maps to `teams_member`. Inspect its auth-user reference and uniqueness constraint. They complement the API's rule that a hacker can belong to only one team.\n\nThe adjacent team and invitation entities persist ownership and invitation state. These tables enter Core through `teamsPlugin().entities`; they are not discovered by scanning arbitrary source files. The host's migration must include them before the runtime can use them." + }, + { + "file": "packages/plugin-teams/src/api.ts", + "pattern": "export function createTeamsApi", + "title": "Bind the Teams API to the scoped context", + "description": "The factory closes over `context.em` and returns methods. Helpers above it perform registered-hacker checks, membership lookup, HackTag resolution, team-capacity checks, and hydration of members with user data.\n\nThe declared permissions in the plugin descriptor are available for policy and role configuration. Individual Teams methods here enforce their actual rules through hacker membership and owner comparisons. Do not assume that declaring a permission automatically guards every method." + }, + { + "file": "packages/plugin-teams/src/api.ts", + "pattern": "async createTeam\\(input:", + "title": "Create the team and owner membership together", + "description": "`createTeam` uses `teams.membership` as the lock key. It requires a registered hacker who is not already a member, normalizes the tag, rejects a duplicate tag, creates the team, and inserts its owner as a member.\n\nBoth flushes occur within the same transaction. The result hydrates the team with members and users for rendering. If a concurrent request tries to create another team for this owner, the serialized membership decision prevents both from succeeding." + }, + { + "file": "packages/plugin-teams/src/api.ts", + "pattern": "async inviteToTeam\\(input:", + "title": "Resolve an invitation without prematurely admitting the user", + "description": "Only the team owner can invite. The method resolves the target from an auth ID or normalized HackTag, rejects self-invitation, existing membership, and a duplicate pending invitation, then persists a pending invite.\n\nThe target can be invited before completing hacker registration. Acceptance is where registration and current team capacity are enforced. An invitation is not a reserved team place." + }, + { + "file": "packages/plugin-teams/src/api.ts", + "pattern": "async respondToInvite\\(input:", + "title": "Accept only the intended pending invitation", + "description": "The method locks the same membership key, loads the invite, verifies its recipient and pending status, and branches on acceptance. Declining updates the status without adding membership.\n\nAcceptance requires hacker registration, no existing team, and available capacity from `TeamsSetting.MaximumTeamSize`. It inserts membership and marks the invite accepted in the same transaction. A failed join must leave the losing invite consistent. This is the database result that the browser refresh will read." + }, + { + "file": "packages/plugin-teams/src/endpoints.ts", + "pattern": "export function createTeamsEndpoints", + "title": "Adapt the scoped API to browser endpoints", + "description": "The endpoint factory receives `run`, not a prebuilt Teams API. It creates strict schemas for `/teams/create`, `/teams/invite`, invitation response, leaving, and member removal.\n\nEach operation gets `{ api, actorAuthId }` from the authenticated scope. The browser supplies fields such as name and tag; the endpoint supplies the trusted actor. Schemas exclude an actor field and reject extra properties. Continue with the HTTP chapter for the runner's session and scope creation." + }, + { + "file": "packages/plugin-teams/src/components/team-create-form.tsx", + "pattern": "async function handleSubmit", + "title": "Follow the user action to the refreshed team page", + "description": "The form prevents normal submission, sets pending state, and invokes `@post/teams/create` with name and tag. `useHackkitClient` infers the legal path and body from endpoint types. Its type import does not load the endpoint implementation in the browser.\n\nFailure displays the structured error and stops. Success shows a toast and calls `router.refresh()`, causing the server page to read the committed team. The HTTP response does not install a global team store." + }, + { + "file": "packages/plugin-teams/app/teams/page.tsx", + "pattern": "export default async function TeamsPage\\(\\)", + "title": "Render plugin-owned pages through the host runtime", + "description": "The page asks `getHackkitRuntime` for the host's current execution. It hides a disabled plugin, loads the current user, requires hacker registration, then reads team and owner-visible invites.\n\nThe result chooses a create form or team dashboard. This server read calls the domain API directly; it does not make an HTTP round trip to the host's own endpoint. The next chapter explains how Next discovers this package-owned page." + }, + { + "file": "packages/plugin-teams/src/__tests__/teams.test.ts", + "pattern": "it\\(\"keeps the final team place and losing invite consistent across concurrent joins\"", + "title": "Check the last-place membership behavior", + "description": "Inspect the two competing invitation acceptances and assertions for membership and invite status. The nearby concurrent-creation test covers two creates by the same owner. Earlier tests cover ordinary creation and inviting before registration.\n\nTo add a Teams operation, update the API and its domain checks, schema/migration if needed, endpoint schema, and the relevant UI. Verify the user-visible result and failure behavior. Continue with [05. CLI and plugin page installation]." + } + ], + "nextTour": "05. CLI and plugin page installation" +} diff --git a/.tours/05-cli-route-sync.tour b/.tours/05-cli-route-sync.tour new file mode 100644 index 000000000..70ff17ee6 --- /dev/null +++ b/.tours/05-cli-route-sync.tour @@ -0,0 +1,59 @@ +{ + "$schema": "https://aka.ms/codetour-schema", + "title": "05. CLI and plugin page installation", + "steps": [ + { + "title": "What you will learn", + "description": "Goal: explain how package-owned Next pages become host routes and what `hackkit.lock` records. This is a filesystem generation process separate from Core's API registry and HTTP endpoint mounting.\n\nThese steps only inspect the sync implementation. Sync writes route files, so the tour does not run it automatically." + }, + { + "file": "packages/cli/src/cli.ts", + "pattern": "#!/usr/bin/env node", + "title": "Find the CLI command boundary", + "description": "This executable is the CLI entry point. Follow its command declarations to configuration loading, plugin commands, and explicit database operations. The CLI operates relative to a selected project, which matters now that this repository has several templates and apps.\n\nCompare template package scripts before invoking a command from the repository root. A command's current directory controls which configuration and migration directory it loads." + }, + { + "file": "packages/cli/src/plugin-manifest.ts", + "pattern": "export function resolvePluginPackage", + "title": "Resolve a plugin from the host application", + "description": "The resolver requires the plugin's `packageName`, creates a Node resolver rooted at the host's package.json, and finds the installed package root and version. It scans the package's `app` directory if present.\n\nEach discovered route becomes a host path and package import source. A plugin without pages can still resolve with an empty route list. This mechanism relies on package exports and installed dependencies, not the Core API map." + }, + { + "file": "packages/cli/src/protected-paths.ts", + "pattern": "export function discoverPluginRouteFiles", + "title": "Discover only Next route files", + "description": "The recursive walker keeps filenames that match known Next route conventions such as page, layout, loading, and route. It normalizes separators and sorts results.\n\nComponent files beside a page are not copied into the host. Generated files import the original package, so implementation and relative dependencies stay with that package. Review the package's exports when adding a route so the generated import can resolve." + }, + { + "file": "packages/cli/src/plugin-sync.ts", + "pattern": "function collectRouteClaims", + "title": "Reject protected-path and cross-plugin conflicts first", + "description": "Before writing, sync builds a map of claimed host paths. It rejects any route under a protected host path and rejects two different plugins claiming the same route.\n\nThe default protected list includes Core pages and `app/api`, keeping browser endpoints under the central handler rather than plugin route stubs. These are the explicit conflict checks here. Do not infer a general guarantee that all existing handwritten files are protected; the later write loop writes each allowed generated destination." + }, + { + "file": "packages/cli/src/plugin-sync.ts", + "pattern": "function renderRouteStub", + "title": "Generate a reexport instead of copying page code", + "description": "The stub includes a generated marker, owner/version comment, and `export *` from the package route module. For route filenames with a default component export, it adds the default reexport too.\n\nThe host route is small because the plugin owns the implementation. A handler route would have named method exports, but the default path protection rejects plugin claims under host `app/api`. Runtime API endpoints use the endpoint factory path explained in the HTTP chapter." + }, + { + "file": "packages/cli/src/plugin-sync.ts", + "pattern": "export async function runPluginSync", + "title": "Track current routes and remove stale generated stubs", + "description": "`runPluginSync` reads the previous lockfile, resolves configured plugins, validates claims, writes current stubs, and writes the new lockfile. It removes an old route only when it is no longer claimed and its contents still start with the generated marker.\n\nThe result reports routes written and stubs removed. The write loop is filesystem generation, not a database transaction. Inspect proposed route destinations before syncing a new third-party plugin. This implementation does not generate HTTP clients or per-endpoint route wrappers." + }, + { + "file": "templates/nextjs-full/hackkit.lock", + "pattern": "\"version\": 1", + "title": "Read the generated ownership record", + "description": "The lockfile records each plugin's ID, package, version, and generated route mappings. Compare Teams' route entries with its package `app` directory and the full template's route reexports.\n\nThis file tracks generated route ownership. It is separate from pnpm-lock.yaml, which locks package resolution, and separate from database migration history. The E2E preparation checks that syncing these routes leaves committed output unchanged." + }, + { + "file": "packages/cli/src/orm.ts", + "pattern": "export async function withOrm", + "title": "Keep CLI database connections bounded", + "description": "Database commands use the same `createOrmOptions` function as runtime startup. `withOrm` adds Jiti-based imports for native TypeScript migration files and closes the ORM in `finally` after the operation finishes or throws.\n\nMigration generation writes a reviewable migration. Applying migrations is a separate command. Continue with [06. HTTP, Next integration, and browser UI] to trace the runtime request path." + } + ], + "nextTour": "06. HTTP, Next integration, and browser UI" +} diff --git a/.tours/06-request-flow.tour b/.tours/06-request-flow.tour new file mode 100644 index 000000000..f02423b19 --- /dev/null +++ b/.tours/06-request-flow.tour @@ -0,0 +1,113 @@ +{ + "$schema": "https://aka.ms/codetour-schema", + "title": "06. HTTP, Next integration, and browser UI", + "steps": [ + { + "title": "What you will learn", + "description": "Goal: follow a browser mutation through JSON validation, origin checks, session resolution, a fresh Core scope, domain execution, and a typed response. Then compare that path with server-rendered reads.\n\nUse the Teams create request from chapter 04 as the running example. A request body contains the requested change. The session determines who requested it." + }, + { + "file": "templates/nextjs-full/app/api/hackkit/[...path]/route.ts", + "pattern": "export const POST", + "title": "Mount the central HackKit handler", + "description": "The catch-all route exports the application's handler as POST. Endpoint definitions stay in Core and plugins rather than one generated Next route per operation.\n\nBetter Auth has its own catch-all auth route. File upload/view routes remain host routes because they handle storage and access policy outside this JSON mutation handler. Next passes a Request to the host, which initializes the reusable endpoint router when needed." + }, + { + "file": "packages/next/src/runtime.ts", + "pattern": "export function createHackkitRuntimeFromConfig", + "title": "Create the Next host and initialize lazily mounted transport", + "description": "The host normalizes config, requires an explicit auth base URL, and accepts a static trusted-origins list. It starts Core initialization with Better Auth's `nextCookies` plugin.\n\nIt shares the Core promise and mounts the HTTP handler on first use. `getRuntime` is wrapped with React `cache`, whose reuse belongs to the server render. This does not authorize storing the current user's runtime globally. The global integration registration stores a provider function." + }, + { + "file": "packages/core/src/http/handler.ts", + "pattern": "export function createHackkitHandler", + "title": "Build endpoint definitions once", + "description": "The handler constructs a request runner, mounts Core endpoints, and asks each enabled plugin's endpoint factory for its definitions. It rejects plugin paths outside `//`, non-POST endpoints, and duplicate POST paths.\n\nOnly definitions and shared runtime resources persist in this handler. A plugin factory receives the runner so its eventual callback can obtain a fresh scope. The default base path is `/api/hackkit`." + }, + { + "file": "packages/core/src/http/http-server.ts", + "pattern": "export function protectHttpHandler", + "title": "Reject untrusted mutation origins before dispatch", + "description": "The outer wrapper requires an allowed Origin for methods other than GET/HEAD and rejects requests marked cross-site. A nonempty mutation body must use application/json. Empty POST streams receive special handling because Next can expose a stream for a bodyless request.\n\nThis policy runs before router dispatch. It reduces cross-site mutation risk but does not replace session authentication or domain permissions. The configured origin must describe the actual host that makes browser requests." + }, + { + "file": "packages/core/src/http/handler.ts", + "pattern": "const run: RequestRunner = async \\(request, operation\\) => \\{", + "title": "Resolve the actor from a fresh session lookup", + "description": "For an endpoint operation, the runner asks Better Auth for a session with cookie cache disabled and requests response headers. No session produces `UNAUTHORIZED`.\n\nIt takes `session.response.user.id` as actorAuthId, then calls `runtime.run` to create a fresh domain scope. The callback receives that scope's `hackkit` plus the trusted actor. Session headers are stored per Request and later propagated as Set-Cookie headers. They are not shared actor state." + }, + { + "file": "packages/core/src/http/mutation.ts", + "pattern": "export function createMutationFactory", + "title": "Connect validated bodies to domain operations", + "description": "`createMutationFactory(run)` returns a typed POST endpoint builder. Each endpoint declares a literal path, Zod body schema, and callback. Better-call parses the body before the callback uses `context.body`.\n\nThe endpoint invokes the request runner, passes the authenticated scope to the operation, then converts the domain result to its JSON DTO. Registration endpoints omit authId/userId from browser schemas and insert the session ID. That is how transport prevents a caller from choosing another participant as themselves." + }, + { + "file": "packages/core/src/http/endpoints/registration.ts", + "pattern": "export function createRegistrationEndpoints", + "title": "Bind personal writes to the session identity", + "description": "The personal-data schema omits authId and the hacker-registration schema omits userId. Both become strict browser schemas. Their callbacks insert the session's actorAuthId into the Core call.\n\nA browser cannot nominate another user's ID in these bodies or smuggle one through an extra field. Direct server calls use Core's target-bearing inputs, so server code remains responsible for choosing a trusted identity when it bypasses this adapter." + }, + { + "file": "packages/core/src/http/mutation.ts", + "pattern": "export function createPluginMutationFactory", + "title": "Resolve the plugin API inside the authenticated scope", + "description": "The plugin mutation factory wraps the Core mutation builder. It verifies the plugin path prefix and retrieves `scope.hackkit.plugins[plugin.id]` during execution. The API therefore uses the current request's EntityManager.\n\nThe setup factory in the declaration provides the API type used for inference. A small type assertion connects the dynamic registry lookup to that contract. Runtime plugin enablement and route validation still matter; compile-time inference cannot prove a deployed plugin is enabled." + }, + { + "file": "packages/core/src/http/http-contract.ts", + "pattern": "export function toJsonDto", + "title": "Make the declared wire type match JSON", + "description": "`toJsonDto` serializes and parses the domain value, converting Date values to strings and void/undefined results to null. The recursive `Wire` type models these conversions for client inference.\n\nA server DTO may contain Date instances while a browser receives ISO strings. UI code must parse a date when it needs Date methods. Matching the inferred endpoint output to the actual JSON avoids presenting browser callers with impossible runtime types." + }, + { + "file": "packages/core/src/http/http-server.ts", + "pattern": "export function httpError", + "title": "Return useful domain errors and hide exception details", + "description": "Known HackKit errors map to stable HTTP statuses and `{ code, message }`. Expected Better-call errors retain useful client messages. Unexpected exceptions become a generic 500 response, while the server callback logs details.\n\nThe final response policy below normalizes router results, applies JSON and no-store headers, and handles empty success responses. The client can therefore handle domain failure through its structured result instead of parsing arbitrary exception text." + }, + { + "file": "packages/core/src/http/client.ts", + "pattern": "export function createHackkitClient", + "title": "Infer paths without bundling endpoint implementations", + "description": "The browser client combines Core endpoint types with any plugin endpoint types supplied by the caller. It defaults to `/api/hackkit`, same-origin credentials, no retries, and errors returned through the result.\n\nType-only imports connect inference to server declarations without executing those modules in the browser. The transport still makes a real HTTP request. A path such as `@post/teams/create` selects a declared route and infers its body and response." + }, + { + "file": "packages/ui/src/provider.tsx", + "pattern": "export function useHackkitClient", + "title": "Share client settings and navigation through React context", + "description": "`HackKitUIProvider` holds the HTTP client, navigation adapter, and event-pass lifetime. Without an override it uses Next's router and the resolved route map. `useHackkitClient` creates a typed client using the provider's same options.\n\nPlugin forms can add endpoint types without replacing the application's provider. Shared Core components under `packages/ui/src/components` use the same transport and error helpers. The provider stores UI dependencies, not an EntityManager or auth secret." + }, + { + "file": "packages/next/src/runtime.ts", + "pattern": "export async function createHackkitRuntime<", + "title": "Compare server-rendered reads with HTTP mutations", + "description": "The server-render runtime reads Next request headers, resolves the session, and creates a scope. It exposes `getAuthId`, `getCurrentUser`, settings reads, and page guards. Unauthenticated required identity redirects to sign-in.\n\nServer pages call these domain APIs directly. They do not need to fetch their own browser endpoint. Unlike the HTTP runner, this function directly creates a scope rather than calling `runtime.run`; do not describe these two paths as identical RequestContext execution." + }, + { + "file": "packages/next/src/page-guards.ts", + "pattern": "async function requireParticipantAccess\\(\\)", + "title": "Gate pages with onboarding and approval state", + "description": "`requireParticipantAccess` requires completed onboarding and approval. Its helper checks a current user, bans, HackTag, personal data, and hacker registration, redirecting to the appropriate step when something is missing.\n\nPermission guards call Core access control and translate forbidden access into the configured Next navigation behavior. These guards control page entry. Domain mutations still need their own rules when accessed directly over HTTP." + }, + { + "file": "packages/core/src/http/event-pass.ts", + "pattern": "export function resolveEventPassTargetAuthId", + "title": "Decode the event pass and bound its age", + "description": "The pass payload contains authId and qrIssuedAt as JSON. Parsing checks field types, then validates the timestamp against a lifetime and a one-minute future tolerance. The resolver returns the target auth ID for scanner endpoints.\n\nThis is a timestamped identifier payload, not a cryptographic signature. Scanner authorization and target checks still run on the server. Changing its security properties would require changing both the payload producer and server validation, not just the QR renderer." + }, + { + "file": "packages/core/src/http/endpoints/event-pass.ts", + "pattern": "export function createEventPassEndpoints", + "title": "Authorize scanner preview before returning participant data", + "description": "The preview endpoint chooses EventsScan or UsersCheckIn permission according to whether an eventId is supplied. It reads the configured QR lifetime, resolves the target, loads the user, and optionally loads prior event scans.\n\nThe browser's raw QR text identifies a target; it does not authorize the scanner. Domain check-in and event-scan endpoints perform the final writes. Keep preview and mutation behavior distinct when adding scan warnings." + }, + { + "file": "tooling/check-client-bundle.mjs", + "pattern": "const forbidden = files\\.filter", + "title": "Check the actual provider bundle for server dependencies", + "description": "The script bundles providers.tsx for both templates and the demo using browser-targeted esbuild. It inspects metafile input paths and rejects MikroORM, Better Auth, and specified server implementation modules. It prints bundle size and module counts for each target.\n\nThis verifies the dependency boundary for these entry points. It does not prove every possible browser entry is safe, that a production Next build passes, or that permissions work. Use it alongside the relevant behavior checks." + } + ], + "nextTour": "07. Notifications, Discord, storage, and deployed apps" +} diff --git a/.tours/07-integrations-apps.tour b/.tours/07-integrations-apps.tour new file mode 100644 index 000000000..998ff60cf --- /dev/null +++ b/.tours/07-integrations-apps.tour @@ -0,0 +1,107 @@ +{ + "$schema": "https://aka.ms/codetour-schema", + "title": "07. Notifications, Discord, storage, and deployed apps", + "steps": [ + { + "title": "What you will learn", + "description": "Goal: see how Core supports external services without requiring every application to configure them. Trace durable notification intents into email delivery, Discord linking into role synchronization, and host storage routes into adapters.\n\nThe final steps distinguish the deployed demo and documentation apps from reference templates. Reading this chapter does not contact providers or verify a hosted deployment." + }, + { + "file": "packages/core/src/notifications.ts", + "pattern": "async queueIntent\\(", + "title": "Store delivery intent with the domain change", + "description": "`queueIntent` validates the notification kind/payload and optionally returns an existing intent by idempotency key. Otherwise it creates a pending row and flushes it through the current EntityManager.\n\nWhen a domain transaction calls this method, the intent is part of that database transaction. A committed RSVP can therefore leave durable work for a later delivery call. Queueing an intent does not send email or start a background worker." + }, + { + "file": "packages/core/src/notifications.ts", + "pattern": "async deliverPending\\(", + "title": "Claim work and record delivery attempts", + "description": "The delivery loop reads pending intents and conditionally changes each to processing. A zero-row claim means another execution already claimed it. Each supplied channel runs, and success, skip, or failure becomes a delivery-attempt record. Intent status is then summarized.\n\nThe method is explicit: a host or job must call it. Do not assume a scheduler, automatic retry, or exactly-once provider delivery from this loop. A process crash between claiming and recording results needs operational consideration beyond the code shown here." + }, + { + "file": "packages/plugin-notifications-email/src/index.ts", + "pattern": "export function emailNotificationsPlugin", + "title": "Keep provider configuration separate from scoped email APIs", + "description": "The email plugin has a setup API but no entity or endpoint declarations. It uses Core's notification tables and can accept options or a deferred options factory.\n\nThe resolved options are cached in the plugin closure, while `createEmailNotificationsApi` runs with each scope's context. Stable provider settings can therefore be reused without retaining a request's EntityManager. The plugin ID is `notificationsEmail`." + }, + { + "file": "packages/plugin-notifications-email/src/api.ts", + "pattern": "export function createEmailNotificationsApi", + "title": "Render and deliver one email channel", + "description": "The channel checks for a provider and a template, resolves a recipient through scoped user lookup, renders the template, and calls the provider. Missing provider/template/recipient returns a skipped result. Successful sends include provider and external message metadata.\n\n`deliverPending` delegates to Core with this channel. `deliverIntent` delivers one selected intent and records an attempt. SMTP and Resend implementations live in providers.ts; domain registration and RSVP code do not import either provider." + }, + { + "file": "packages/plugin-discord/src/index.ts", + "pattern": "export function discordPlugin", + "title": "Compose Discord persistence and API behavior", + "description": "Discord declares its own models, endpoint factory, package name, and scoped setup factory. Deferred configuration is resolved once and reused for new APIs, as in the email plugin.\n\nIts persisted verification/member/sync-attempt records are separate from the external Discord service. A local link can be committed even when a later provider call fails. Inspect the next steps for that ordering." + }, + { + "file": "packages/plugin-discord/src/api.ts", + "pattern": "async createVerification\\(", + "title": "Issue a pending verification with a bounded lifetime", + "description": "The method requires the configured guild, persists the code and Discord identity with an expiration time, and returns a verification URL. The browser link is a way to associate that pending verification with a signed-in HackKit participant.\n\nCreating the pending row does not approve a hacker or grant roles. Confirmation must verify current status, time, and ownership constraints before creating the member link." + }, + { + "file": "packages/plugin-discord/src/api.ts", + "pattern": "async confirmVerification\\(", + "title": "Commit the account link before contacting Discord", + "description": "Confirmation uses a verification lock and rejects missing/non-pending codes. It requires an approved registered hacker and prevents a Discord account from linking to a different user.\n\nExpiration and conflicting-link branches return an error value from the transaction so their expired/rejected status changes can commit, then throw afterward. Successful confirmation commits the member link and accepted code before `syncMemberRoles` contacts the provider. A network failure therefore does not roll back an already-consumed code." + }, + { + "file": "packages/plugin-discord/src/api.ts", + "pattern": "async syncMemberRoles\\(input:", + "title": "Separate role planning from provider delivery", + "description": "The method builds a plan from linked member and participant/group information. Without a provider it records a skipped attempt. With a provider it sends role IDs/names and nickname, updates last-sync time after success, and records the result.\n\nProvider errors become failed attempts. They do not delete the local member link. The provider module handles HTTP communication; the plan remains inspectable through the plugin API." + }, + { + "file": "templates/nextjs-full/lib/blob.ts", + "pattern": "export function createBlobStorageFromConfig", + "title": "Choose a storage adapter at the host boundary", + "description": "The full template chooses S3-compatible storage or local filesystem storage according to application config. The shared interface exposes upload targets and object reads. Additional capabilities let the host distinguish a local write path from a signed S3 view URL.\n\nStorage adapters do not know whether a user may view a resume. That decision stays in the host route. The Core profile stores a stable reference rather than depending on a temporary signed URL." + }, + { + "file": "packages/blob-local/src/index.ts", + "pattern": "export function createLocalBlobStorage", + "title": "Turn a local upload request into a stable reference", + "description": "The adapter generates a location/UUID key and returns the host's upload URL plus `/api/files/view?key=...` as the stored reference. It exposes directory preparation and filesystem reads for host routes.\n\nRead the path normalization and base-directory checks before changing key handling. The host must still validate accepted locations and access. The adapter's methods are storage operations, not a complete upload authorization policy." + }, + { + "file": "packages/blob-s3/src/index.ts", + "pattern": "export function createS3BlobStorage", + "title": "Use temporary S3 URLs with stable application references", + "description": "The S3 adapter creates signed PutObject URLs and returns a stable host view reference. It can read objects or create a signed GetObject URL. Signing expiry defaults to one hour unless overridden.\n\nThe browser can upload to the signed destination while application records keep the durable reference. Credentials stay in server configuration. A signed URL grants temporary object access, so the host checks permissions before returning one for private files." + }, + { + "file": "templates/nextjs-full/app/api/files/view/route.ts", + "pattern": "async function canViewFile", + "title": "Apply file access policy before storage access", + "description": "Profile photos are public under this route's policy. Other files require a session. A participant can view their registered resume reference; a user with `HackersView` can view other resumes.\n\nGET also restricts accepted key prefixes. After permission checks, S3 redirects to a signed view URL and local storage returns bytes. File privacy therefore depends on this host route as well as bucket/filesystem configuration." + }, + { + "file": "apps/demo/lib/runtime.ts", + "pattern": "function getHost\\(\\)", + "title": "Reuse packages in the demo with guarded lazy initialization", + "description": "The demo creates its host lazily after asserting demo environment configuration, then registers a provider for package-owned pages. Its convenience API mirrors the templates while using its own config and seeded fictional event data.\n\nThe demo is a deployed app with its own build, database scripts, and bindings. It is not the target for template E2E. Inspect apps/demo/README.md for local setup and deployment rather than inheriting the full template's database assumptions." + }, + { + "file": "apps/demo/lib/database-config.ts", + "pattern": "export const databaseOptions = \\{", + "title": "Adapt MikroORM to HTTP libSQL for the Worker", + "description": "The demo uses the generic SQLite driver from `@mikro-orm/sql` with a custom Kysely HTTP libSQL dialect. This avoids depending on a native SQLite binary in the Worker.\n\nThe dialect gets its URL/token from demo environment configuration. Reference templates can choose other driver configurations. Similar domain APIs do not imply identical deployment transports or database drivers." + }, + { + "file": "apps/demo/lib/http-libsql-dialect.ts", + "pattern": "override async acquireConnection\\(\\)", + "title": "Keep HTTP stream state within one connection checkout", + "description": "Each acquired connection gets a fresh web libSQL client. The driver tracks it in a WeakMap and closes it on release. A transaction retains its connection while unrelated requests acquire their own.\n\nThe same file implements savepoint, rollback-to-savepoint, and release-savepoint operations for nested transactions. Its adapter permits multiple connections. These details let Core's transaction behavior work through the demo's HTTP database transport." + }, + { + "file": "apps/docs/lib/source.ts", + "pattern": "const docs = defineDocs\\(\\{", + "title": "Keep the documentation site separate from the domain runtime", + "description": "Fumadocs reads MDX from content/docs, applies page/meta schemas, and constructs the site source. The loader exposes routes and processed Markdown for the docs' text representation.\n\nThis app teaches and documents HackKit; it does not implement registration or plugin composition. The docs' package/build configuration differs from the reference templates. Continue with [08. Verification and change guide] for the repository's test boundaries." + } + ], + "nextTour": "08. Verification and change guide" +} diff --git a/.tours/08-verification.tour b/.tours/08-verification.tour new file mode 100644 index 000000000..e5bd0a109 --- /dev/null +++ b/.tours/08-verification.tour @@ -0,0 +1,86 @@ +{ + "$schema": "https://aka.ms/codetour-schema", + "title": "08. Verification and change guide", + "steps": [ + { + "title": "What you will learn", + "description": "Goal: choose the right evidence for a Core, plugin, template, or deployment change. This chapter explains what package tests, database checks, production HTTP tests, browser journeys, and deployment checks actually cover.\n\nTour validation checks source anchors and links. It does not imply the application suites pass. The suite commands below are read-only text in the tour, with no automatic terminal actions." + }, + { + "file": "packages/core/src/testing.ts", + "pattern": "export async function createTestHackkit", + "title": "Use an isolated real database for focused domain tests", + "description": "The helper initializes Core against in-memory SQLite, injects a deterministic Core clock and ID generator, creates the schema, and returns a scoped API with access to the runtime and EntityManager. Vitest cleanup closes registered runtimes after each test.\n\n`createTestUser` can insert a known identity without password hashing when a test concerns domain behavior. This is useful focused evidence, but it bypasses auth signup and committed migrations. The auth lifecycle and application E2E tests cover those other boundaries." + }, + { + "file": "e2e/support/templates.mjs", + "pattern": "export const templates = \\{", + "title": "Point integration tests at the real templates", + "description": "The manifest names the full and minimal workspace packages, absolute directories, fixed ports, origins, and database dialect lists. Full targets SQLite/libSQL/PostgreSQL/MySQL; minimal targets SQLite.\n\nHelpers use these absolute locations rather than assuming the repository root is an application. This is the main architectural effect of the testing split: tests orchestrate real consumers and their committed migrations." + }, + { + "file": "e2e/support/templates.mjs", + "pattern": "export function testEnvironment", + "title": "Build explicit disposable test configuration", + "description": "The helper constructs a limited environment with fresh database/upload paths, template-specific origins, and a test auth secret. Full-template external-service settings use disabled or non-service test values so Next's dotenv loading cannot silently select developer services.\n\nRead which variables are intentionally inherited and which are replaced. Test isolation depends on the actual environment passed to each subprocess, not just a temporary directory name." + }, + { + "file": "e2e/support/run.mjs", + "pattern": "const suite = process\\.argv\\[2\\] \\?\\? \"all\";", + "title": "Prepare dependencies before choosing integration suites", + "description": "The runner accepts all, db, http, or browser. It builds dependency packages, snapshots generated route files and lockfiles, runs plugin sync, and asserts no generated drift. It then typechecks both templates and E2E and invokes the client-bundle guard.\n\nHTTP/browser runs also migrate and seed disposable build databases and create real production template builds. Finally it runs the selected Vitest or Playwright suites. Running one E2E invocation at a time avoids collisions in fixed ports and template output directories." + }, + { + "file": "e2e/support/server.mjs", + "pattern": "export async function startTemplate", + "title": "Start production Next with fresh storage", + "description": "The helper rejects an occupied port, creates a temporary runtime directory, and runs migrations and seeding with the template as cwd. It starts `next start`, captures logs, and polls the auth session endpoint for readiness.\n\nIt never treats an arbitrary process on the same port as the test application. The returned close function stops the child and removes temporary storage. Startup failure also performs cleanup and includes captured output in its error." + }, + { + "file": "e2e/playwright.config.ts", + "pattern": "projects: \\[\"full\", \"minimal\"\\]\\.flatMap", + "title": "Run transport and UI checks for each consumer", + "description": "Playwright creates full-http, full-browser, minimal-http, and minimal-browser projects. One worker and disabled full parallelism match the shared production output and fixed-port strategy.\n\nFailure traces, screenshots, HTML, and JUnit output support diagnosis. Retries are zero here, so intermittent behavior appears as a failure instead of silently passing a retry. Project selection determines coverage; a browser-only run does not execute the database matrix." + }, + { + "file": "e2e/http/runtime.spec.ts", + "pattern": "test\\(\"production HTTP auth, request isolation, permissions, Core and plugin transport\"", + "title": "Exercise the complete HTTP boundary", + "description": "Read the requests and assertions for sessions, actor isolation, invalid input, permissions, and plugin transport. These tests use a production template server rather than calling a domain function in memory.\n\nThe local-upload test later in this file checks minimal-template file round trips and resume access. Compare these assertions with the handler and file-route implementation before claiming a transport or authorization change is covered." + }, + { + "file": "e2e/browser/participant.spec.ts", + "pattern": "test\\(\"signup, onboarding, persisted registration, signout and signin\"", + "title": "Check the participant journey through rendered UI", + "description": "This browser journey signs up, completes onboarding, verifies persisted registration, signs out, and signs back in. Additional tests cover anonymous/incomplete-account redirects, approval waiting, participant denial from admin pages, and owner administration.\n\nThe browser assertions validate the integration among UI, Next routing, auth cookies, Core behavior, and storage. A package unit test alone cannot prove these rendered transitions work." + }, + { + "file": "e2e/browser/teams.spec.ts", + "pattern": "test\\(\"team creation, invitation and acceptance across separate sessions\"", + "title": "Close the worked Teams scenario", + "description": "This journey exercises team creation, invitation, and acceptance across separate browser sessions. Compare each action with the endpoint/API methods from chapter 04.\n\nTeams belongs to the full configuration; inspect the template-selection condition in this test before interpreting a skip for minimal. A skip because an optional feature is absent is different from demonstrating that feature works in that consumer." + }, + { + "file": "e2e/database/templates.test.ts", + "pattern": "it\\(\"minimal: real config and committed migrations initialize Core/auth without plugins\"", + "title": "Validate the minimal schema without feature plugins", + "description": "This test loads the real minimal config and committed migrations, then initializes Core/auth without feature plugins. It checks the split at the application/configuration boundary.\n\nThe parameterized test above covers storage isolation, sync without connecting, and reset restrictions. Other files in e2e/database cover dialect and migration workflows. Inspect matrix environment requirements before treating skipped network dialect tests as verified coverage." + }, + { + "file": ".github/workflows/integration.yml", + "pattern": "HACKKIT_REQUIRE_DATABASE_MATRIX: \"1\"", + "title": "Require the database matrix in CI", + "description": "The integration workflow provisions PostgreSQL, MySQL, and libSQL services, supplies their test URLs, and requires the matrix for its complete E2E invocation. It also verifies generated template route files and lockfiles have no diff.\n\nThe separate package job runs library tests and package typechecks. These are workflow definitions, not evidence of a successful run on this working tree. Check the actual CI result for the branch before making a release claim." + }, + { + "file": ".github/workflows/apps.yml", + "pattern": "name: Demo and documentation", + "title": "Check deployed-app packaging separately", + "description": "The app workflow builds/typechecks docs and the demo, checks deployment packaging, and uses disposable libSQL plus local Worker bindings for the demo's database and smoke checks.\n\nTemplate E2E does not replace these checks because Worker bindings and the demo dialect differ from Next template hosting. Likewise a local deploy check does not prove a hosted URL has the intended version. Verify hosted behavior separately when publishing is requested." + }, + { + "title": "Choose the change location and finish the route", + "description": "You have now followed configuration into shared initialization, scoped Core/plugin APIs, HTTP transport, server pages, storage, deployed apps, and test orchestration.\n\nFor a Core rule, start in `packages/core/src/functions`, then check the domain schema and focused behavior tests. For a new plugin capability, add its scoped API and checks, endpoint schema if browser access is needed, and UI. Change entities plus a reviewed host migration when persistence changes. Use CLI sync only for package-owned page installation.\n\nFor template behavior, compare full and minimal configurations and choose the relevant E2E journey. For deployment behavior, inspect the app's own runtime/bindings and app workflow. The root commands are `corepack pnpm test` for package tests and `corepack pnpm test:e2e` for the complete template suite; E2E builds production output and writes disposable databases. Read e2e/README.md before running it.\n\nRevisit [01. Repository map and composition], [03. Core domain behavior], or [04. Plugin contracts and Teams] when choosing the layer to change. Tour playback and source-anchor validation do not execute these application checks." + } + ] +} diff --git a/.tours/README.md b/.tours/README.md new file mode 100644 index 000000000..b9f3e36d2 --- /dev/null +++ b/.tours/README.md @@ -0,0 +1,26 @@ +# HackKit repository walkthrough + +Open the repository root in VS Code with the CodeTour extension enabled. In the Explorer's CodeTour view, start **01. Repository map and composition**. It is the primary tour. Each chapter names the next tour, and linked tour titles let you jump between topics. + +These tours describe the `templates-and-testing` working tree, including its uncommitted template/E2E split. They do not pin a Git ref. Paths and regex anchors refer to the current files. Read them with the repository root as the workspace folder. + +The walkthrough has 8 chapters and 117 steps. Each step explains the role of the selected code, its inputs and outputs, important checks, and the next boundary where relevant. No step runs a command or edits source automatically. + +- [01. Repository map and composition](01-repository-map.tour) (11 steps) +- [02. Core startup and persistence](02-core-startup.tour) (13 steps) +- [03. Core domain behavior](03-core-domain.tour) (19 steps) +- [04. Plugin contracts and Teams](04-plugin-system.tour) (16 steps) +- [05. CLI and plugin page installation](05-cli-route-sync.tour) (9 steps) +- [06. HTTP, Next integration, and browser UI](06-request-flow.tour) (18 steps) +- [07. Notifications, Discord, storage, and deployed apps](07-integrations-apps.tour) (17 steps) +- [08. Verification and change guide](08-verification.tour) (14 steps) + +The Core chapters explain shared initialization, per-execution EntityManagers, canonical auth users, registration, role hierarchy, settings, RSVP, check-in, groups, and transaction locking. The plugin chapter follows Teams through declarations, inferred API types, scoped setup, persistence, endpoints, forms, and server pages. Later chapters explain CLI route sync, request handling, notifications, Discord, storage, the demo Worker, docs, and the test suites. + +For a focused first pass on the plugin system, read chapters 01, 02, 04, 05, and 06. For participant behavior, read chapters 02, 03, 06, and 08. + +## Validation boundaries + +The CodeTour anchor checker verifies all local files and unique regex matches. Additional checks verify tour sequencing, tour-title links, local Markdown links, and the installed extension's JSON schema. Source review checks descriptions against implementation. Editor playback has not been exercised, so discovery, comment placement, and rendered links still need a VS Code playback check. + +Application tests are described as evidence to inspect. They were not run for this documentation-only change. Creating the tours does not verify current service credentials, deployment state, or hosted behavior. The tours do not install an extension or change workspace trust. diff --git a/README.md b/README.md index cf74a5dac..e5d438b40 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@

HackKit

Feature-packed Hackathon Managment Software That Just Works.


Putting together a hackathon is not an easy feat, like really not easy. While we can't help you with delayed packages, food orders being botched, or any of the other issues that can arise at the worst times, we can help you with the tech to make your hackathon go smoothly. HackKit is battle-tested and feature-packed to help your hackathon be the best it can be. From a seamless registration, to an easy-to-use admin panel, to event passes and more, HackKit has you covered.

-

Want to get started with using HackKit? Check out our OSS Documents that will be updated as we add new features and fix bugs!

+

Want to get started with using HackKit? Check out our documentation that will be updated as we add new features and fix bugs!

Have any questions, feedback, or need help hosting? Join our Discord or Contact our projects officer.

@@ -16,9 +16,26 @@ - Better Auth - Tailwind CSS +## Demo and documentation + +- [Interactive demo](https://hackkit-demo.acm-utsa.workers.dev): explore a shared fictional event as a participant or organizer. [Deployment and local setup](apps/demo/README.md). +- [Documentation](https://hackkit-docs.acm-utsa.workers.dev): setup, templates, architecture, plugins, operations, and testing. [Contributing to the docs](apps/docs/README.md). + +Configure the demo’s Turso credentials in `apps/demo/.dev.vars` and run its explicit database setup first; see [demo setup](apps/demo/README.md). `corepack pnpm dev:demo` then starts the demo on port 3001. `corepack pnpm dev:docs` starts Fumadocs on port 3002. The deployed apps live under `apps`; runnable workspace examples remain under `templates`. + ## Development -See [the reference app setup](apps/web/README.md) and [the persistence decision](docs/adr/0013-mikroorm-and-core-auth.md). This migration targets fresh databases. +Use Node.js 22.17+ and the repository-pinned pnpm 12.15.0 through Corepack. Run `corepack pnpm install` from this directory. + +- [Full Next.js template](templates/nextjs-full/README.md): the existing app with Teams, Discord, email notifications, and configurable storage. +- [Minimal Next.js template](templates/nextjs-minimal/README.md): Core registration, participant profiles, and basic administration with local SQLite and uploads. +- [E2E validation](e2e/README.md): database, production HTTP, and browser integration checks against these templates. + +`corepack pnpm dev` and `corepack pnpm dev:full` start the full template. `corepack pnpm dev:minimal` starts the minimal template. Root `db:*` commands target the full template. Select the minimal package explicitly for its database commands. Each template's README covers migrations, seeding, owner bootstrap, and production configuration. + +`corepack pnpm build` builds libraries, templates, demo, and docs; configure each template for production first. `corepack pnpm test` runs package tests. `corepack pnpm test:e2e` prepares isolated configurations and runs all integration suites. Run one E2E invocation at a time because tests use fixed ports and each template's production output. + +Both templates remain workspace examples. [CLI init and standalone releases](docs/plans/template-distribution.md) are a separate milestone. See the [persistence decision](docs/adr/0013-mikroorm-and-core-auth.md) for database ownership. ## Join The Team diff --git a/apps/demo/.dev.vars.example b/apps/demo/.dev.vars.example new file mode 100644 index 000000000..91f98c179 --- /dev/null +++ b/apps/demo/.dev.vars.example @@ -0,0 +1,6 @@ +# Copy this file to .dev.vars in this directory. Never commit .dev.vars. +TURSO_DATABASE_URL=libsql://your-database.turso.io +TURSO_AUTH_TOKEN= +BETTER_AUTH_SECRET= +# Local application origin. The deployed origin lives in wrangler.jsonc. +BETTER_AUTH_URL=http://localhost:3001 diff --git a/apps/demo/.env.example b/apps/demo/.env.example new file mode 100644 index 000000000..b598b592d --- /dev/null +++ b/apps/demo/.env.example @@ -0,0 +1 @@ +# The Worker reads .dev.vars. Copy .dev.vars.example to .dev.vars. diff --git a/apps/demo/README.md b/apps/demo/README.md new file mode 100644 index 000000000..7ac0dec7b --- /dev/null +++ b/apps/demo/README.md @@ -0,0 +1,44 @@ +# HackKit demo + +A public demonstration of HackKit Core, the Next integration, package UI, and Teams. Vinext runs the application on Cloudflare Workers. Turso stores application data over HTTP. A private R2 binding stores uploads. The app owns its pages and configuration and does not import either template or E2E support. + +## Credentials and local setup + +Copy `.dev.vars.example` to **`apps/demo/.dev.vars`**. Fill in `TURSO_DATABASE_URL`, `TURSO_AUTH_TOKEN`, and a random `BETTER_AUTH_SECRET` of at least 32 characters. Keep `BETTER_AUTH_URL=http://localhost:3001` for local development. This ignored file is the only local credential file used by the demo. Never point it at a real event database. + +From the repository root: + +```sh +corepack pnpm install +corepack pnpm exec turbo run build --filter=@hackkit/demo^... +corepack pnpm --filter @hackkit/demo plugin:sync +corepack pnpm --filter @hackkit/demo db:migrate +corepack pnpm --filter @hackkit/demo db:demo +corepack pnpm dev:demo +``` + +Open [localhost:3001](http://localhost:3001). Local development and preview run in Workerd. They use the configured Turso database and an emulated local R2 bucket. Local uploads persist under `.wrangler`. Database setup is an explicit Node command; requests never migrate or seed the database. + +`db:demo` seeds fictional accounts, a team, and four schedule entries only when there are no existing users. Existing users are retained. Owner assignment is an explicit demo bootstrap operation. Neither template assigns owners automatically. `db:reset` is disabled for the shared demo database. Other database commands follow the template interface. + +`corepack pnpm build:demo` compiles MikroORM entity functions ahead of time and builds the Worker. It needs no database connection or credentials. `corepack pnpm --filter @hackkit/demo start` previews that production build on port 3001. + +## Cloudflare deployment + +The committed configuration targets **ACM UTSA**, account `cdc7630e53b468f56a4453af71a58ade`, Worker `hackkit-demo`, and private R2 bucket `hackkit-demo-uploads`. Verify Wrangler's account with `corepack pnpm --filter @hackkit/demo exec wrangler whoami`. + +Set `vars.BETTER_AUTH_URL` in `wrangler.jsonc` to the exact public origin. Default: [hackkit-demo.acm-utsa.workers.dev](https://hackkit-demo.acm-utsa.workers.dev). Set these Worker secrets through Wrangler's interactive `secret put` command or the Cloudflare dashboard: + +- `TURSO_DATABASE_URL` +- `TURSO_AUTH_TOKEN` +- `BETTER_AUTH_SECRET` + +For example, `corepack pnpm --filter @hackkit/demo exec wrangler secret put TURSO_AUTH_TOKEN` prompts for the token without putting it in command history. Do not upload the local `BETTER_AUTH_URL` as a secret; the deployed origin belongs in Wrangler configuration. R2 uses the `DEMO_UPLOADS` binding and requires no access keys or public bucket URL. + +Run `corepack pnpm deploy:demo` after building workspace libraries. Run `corepack pnpm --filter @hackkit/demo deploy:check` after a build to inspect the deployment without publishing. + +The hosted demo shares persistent Turso data and R2 uploads between visitors. Participant and organizer accounts are public. **Try registration** creates a new fictional account. Use fictional data only. Email delivery, OAuth, and Discord synchronization are disabled. This public demonstration is unsuitable for real participant records. + +## Verification + +Run `DEMO_TEST_URL=http://localhost:3001 corepack pnpm --filter @hackkit/demo test:smoke` against a running production preview. The checks cover role navigation, onboarding, permissions, and authenticated R2 uploads. CI uses a disposable local libSQL service and emulated R2; it never receives deployed database credentials. diff --git a/apps/web/app/admin/check-in/page.tsx b/apps/demo/app/admin/check-in/page.tsx similarity index 100% rename from apps/web/app/admin/check-in/page.tsx rename to apps/demo/app/admin/check-in/page.tsx diff --git a/apps/web/app/admin/events/[id]/edit/page.tsx b/apps/demo/app/admin/events/[id]/edit/page.tsx similarity index 100% rename from apps/web/app/admin/events/[id]/edit/page.tsx rename to apps/demo/app/admin/events/[id]/edit/page.tsx diff --git a/apps/web/app/admin/events/new/page.tsx b/apps/demo/app/admin/events/new/page.tsx similarity index 100% rename from apps/web/app/admin/events/new/page.tsx rename to apps/demo/app/admin/events/new/page.tsx diff --git a/apps/web/app/admin/events/page.tsx b/apps/demo/app/admin/events/page.tsx similarity index 100% rename from apps/web/app/admin/events/page.tsx rename to apps/demo/app/admin/events/page.tsx diff --git a/apps/web/app/admin/layout.tsx b/apps/demo/app/admin/layout.tsx similarity index 100% rename from apps/web/app/admin/layout.tsx rename to apps/demo/app/admin/layout.tsx diff --git a/apps/web/app/admin/page.tsx b/apps/demo/app/admin/page.tsx similarity index 100% rename from apps/web/app/admin/page.tsx rename to apps/demo/app/admin/page.tsx diff --git a/apps/web/app/admin/roles/page.tsx b/apps/demo/app/admin/roles/page.tsx similarity index 100% rename from apps/web/app/admin/roles/page.tsx rename to apps/demo/app/admin/roles/page.tsx diff --git a/apps/web/app/admin/scanner/[eventId]/page.tsx b/apps/demo/app/admin/scanner/[eventId]/page.tsx similarity index 100% rename from apps/web/app/admin/scanner/[eventId]/page.tsx rename to apps/demo/app/admin/scanner/[eventId]/page.tsx diff --git a/apps/web/app/admin/settings/page.tsx b/apps/demo/app/admin/settings/page.tsx similarity index 100% rename from apps/web/app/admin/settings/page.tsx rename to apps/demo/app/admin/settings/page.tsx diff --git a/apps/web/app/admin/users/[authId]/page.tsx b/apps/demo/app/admin/users/[authId]/page.tsx similarity index 100% rename from apps/web/app/admin/users/[authId]/page.tsx rename to apps/demo/app/admin/users/[authId]/page.tsx diff --git a/apps/web/app/admin/users/page.tsx b/apps/demo/app/admin/users/page.tsx similarity index 100% rename from apps/web/app/admin/users/page.tsx rename to apps/demo/app/admin/users/page.tsx diff --git a/apps/web/app/api/admin/export/route.ts b/apps/demo/app/api/admin/export/route.ts similarity index 100% rename from apps/web/app/api/admin/export/route.ts rename to apps/demo/app/api/admin/export/route.ts diff --git a/apps/web/app/api/auth/[...all]/route.ts b/apps/demo/app/api/auth/[...all]/route.ts similarity index 100% rename from apps/web/app/api/auth/[...all]/route.ts rename to apps/demo/app/api/auth/[...all]/route.ts diff --git a/apps/demo/app/api/files/register/route.ts b/apps/demo/app/api/files/register/route.ts new file mode 100644 index 000000000..97cf1586d --- /dev/null +++ b/apps/demo/app/api/files/register/route.ts @@ -0,0 +1,23 @@ +import { NextResponse } from "next/server"; +import { z } from "zod"; +import { getAuthSession } from "@/lib/auth"; +import { createUploadTarget } from "@/lib/blob"; + +const upload = z.object({ + location: z.enum(["resumes", "profile-photos"]), + fileName: z.string().min(1).max(255), +}); +export async function POST(request: Request) { + const session = await getAuthSession(); + if (!session) + return NextResponse.json({ error: "Unauthorized" }, { status: 401 }); + const input = upload.safeParse(await request.json().catch(() => null)); + if (!input.success) + return NextResponse.json( + { error: "Choose a resume or profile photo and a file name." }, + { status: 400 }, + ); + return NextResponse.json( + createUploadTarget({ ...input.data, ownerId: session.user.id }), + ); +} diff --git a/apps/demo/app/api/files/upload/route.ts b/apps/demo/app/api/files/upload/route.ts new file mode 100644 index 000000000..6744e2b94 --- /dev/null +++ b/apps/demo/app/api/files/upload/route.ts @@ -0,0 +1,36 @@ +import { NextResponse } from "next/server"; +import { getAuthSession } from "@/lib/auth"; +import { canUploadKey, getBlobStorage, readUploadBody } from "@/lib/blob"; + +export async function PUT(request: Request) { + const session = await getAuthSession(); + if (!session) + return NextResponse.json({ error: "Unauthorized" }, { status: 401 }); + const key = new URL(request.url).searchParams.get("key"); + if (!key || !canUploadKey(key, session.user.id)) + return NextResponse.json( + { error: "Unsupported upload key." }, + { status: 403 }, + ); + try { + const body = await readUploadBody(request); + const contentType = + request.headers.get("content-type") ?? "application/octet-stream"; + if ( + key.startsWith("profile-photos/") && + !["image/png", "image/jpeg", "image/webp"].includes(contentType) + ) + return NextResponse.json( + { error: "Choose a PNG, JPEG, or WebP image." }, + { status: 400 }, + ); + await getBlobStorage().put(key, body, { + httpMetadata: { contentType }, + }); + return new NextResponse(null, { status: 204 }); + } catch (error) { + if (error instanceof RangeError) + return NextResponse.json({ error: error.message }, { status: 413 }); + throw error; + } +} diff --git a/apps/demo/app/api/files/view/route.ts b/apps/demo/app/api/files/view/route.ts new file mode 100644 index 000000000..0e40822cd --- /dev/null +++ b/apps/demo/app/api/files/view/route.ts @@ -0,0 +1,54 @@ +import { NextResponse } from "next/server"; +import { CorePermission } from "@hackkit/core"; +import { getAuthSession } from "@/lib/auth"; +import { getBlobStorage } from "@/lib/blob"; +import { getRuntime } from "@/lib/runtime"; + +function storedFileReferenceForKey(key: string): string { + return `/api/files/view?key=${encodeURIComponent(key)}`; +} + +async function canViewFile(key: string): Promise { + if (key.startsWith("profile-photos/")) return true; + + const session = await getAuthSession(); + if (!session) return false; + + const runtime = await getRuntime(); + const currentUser = await runtime.getCurrentUser(); + const hacker = await runtime.hackkit.hackers.getHacker(currentUser.id); + if (hacker?.resumeUrl === storedFileReferenceForKey(key)) return true; + + return runtime.hackkit.accessControl.hasPermission( + currentUser.id, + CorePermission.HackersView, + ); +} + +export async function GET(request: Request): Promise { + const url = new URL(request.url); + const key = url.searchParams.get("key"); + if (!key) { + return NextResponse.json({ error: "key is required" }, { status: 400 }); + } + if (!key.startsWith("resumes/") && !key.startsWith("profile-photos/")) { + return NextResponse.json({ error: "Not found" }, { status: 404 }); + } + if (!(await canViewFile(key))) { + return NextResponse.json({ error: "Unauthorized" }, { status: 401 }); + } + + const storage = getBlobStorage(); + + const result = await storage.get(key); + if (!result) + return NextResponse.json({ error: "Not found" }, { status: 404 }); + const headers = new Headers(); + result.writeHttpMetadata(headers); + headers.set("Cache-Control", "private, no-store"); + headers.set("X-Content-Type-Options", "nosniff"); + headers.set("Content-Security-Policy", "sandbox"); + if (!key.startsWith("profile-photos/")) + headers.set("Content-Disposition", "attachment"); + return new NextResponse(result.body, { headers }); +} diff --git a/apps/web/app/api/hackkit/[...path]/route.ts b/apps/demo/app/api/hackkit/[...path]/route.ts similarity index 100% rename from apps/web/app/api/hackkit/[...path]/route.ts rename to apps/demo/app/api/hackkit/[...path]/route.ts diff --git a/apps/web/app/app-bar.tsx b/apps/demo/app/app-bar.tsx similarity index 100% rename from apps/web/app/app-bar.tsx rename to apps/demo/app/app-bar.tsx diff --git a/apps/web/app/contact/page.tsx b/apps/demo/app/contact/page.tsx similarity index 100% rename from apps/web/app/contact/page.tsx rename to apps/demo/app/contact/page.tsx diff --git a/apps/web/app/dashboard/layout.tsx b/apps/demo/app/dashboard/layout.tsx similarity index 100% rename from apps/web/app/dashboard/layout.tsx rename to apps/demo/app/dashboard/layout.tsx diff --git a/apps/web/app/dashboard/page.tsx b/apps/demo/app/dashboard/page.tsx similarity index 100% rename from apps/web/app/dashboard/page.tsx rename to apps/demo/app/dashboard/page.tsx diff --git a/apps/demo/app/demo-actions.tsx b/apps/demo/app/demo-actions.tsx new file mode 100644 index 000000000..d47f3abe8 --- /dev/null +++ b/apps/demo/app/demo-actions.tsx @@ -0,0 +1,84 @@ +"use client"; + +import { useEffect, useState } from "react"; +import { authClient } from "@/lib/auth-client"; +import { demoAccounts, demoPassword } from "@/lib/demo-accounts"; + +export function DemoActions() { + const [ready, setReady] = useState(false); + const [pending, setPending] = useState(); + useEffect(() => setReady(true), []); + const [error, setError] = useState(); + async function enter(role: "participant" | "organizer" | "newcomer") { + setPending(role); + setError(undefined); + try { + await authClient.signOut(); + const result = + role === "newcomer" + ? await authClient.signUp.email({ + name: "Demo participant", + email: `demo-${crypto.randomUUID()}@example.com`, + password: demoPassword, + }) + : await authClient.signIn.email({ + email: demoAccounts[role].email, + password: demoPassword, + }); + if (result.error) + throw new Error(result.error.message ?? "Unable to open demo."); + window.location.assign( + role === "organizer" ? "/admin" : "/dashboard", + ); + } catch (cause) { + setError( + cause instanceof Error ? cause.message : "Unable to open demo.", + ); + setPending(undefined); + } + } + return ( + <> +
+ {( + [ + [ + "participant", + "Explore as a participant", + "Open a registered hacker’s dashboard, create a team, and manage your event pass.", + ], + [ + "organizer", + "Explore as an organizer", + "Review applications, manage roles and settings, and edit the event schedule.", + ], + [ + "newcomer", + "Try registration", + "Create a fresh fictional account and walk through the onboarding forms.", + ], + ] as const + ).map(([role, title, description]) => ( + + ))} +
+ {error && ( +

+ {error} +

+ )} + + ); +} diff --git a/apps/web/app/globals.css b/apps/demo/app/globals.css similarity index 100% rename from apps/web/app/globals.css rename to apps/demo/app/globals.css diff --git a/apps/web/app/help/page.tsx b/apps/demo/app/help/page.tsx similarity index 100% rename from apps/web/app/help/page.tsx rename to apps/demo/app/help/page.tsx diff --git a/apps/web/app/i/approval/layout.tsx b/apps/demo/app/i/approval/layout.tsx similarity index 100% rename from apps/web/app/i/approval/layout.tsx rename to apps/demo/app/i/approval/layout.tsx diff --git a/apps/web/app/i/approval/page.tsx b/apps/demo/app/i/approval/page.tsx similarity index 100% rename from apps/web/app/i/approval/page.tsx rename to apps/demo/app/i/approval/page.tsx diff --git a/apps/web/app/invites/layout.tsx b/apps/demo/app/invites/layout.tsx similarity index 100% rename from apps/web/app/invites/layout.tsx rename to apps/demo/app/invites/layout.tsx diff --git a/apps/web/app/invites/page.tsx b/apps/demo/app/invites/page.tsx similarity index 100% rename from apps/web/app/invites/page.tsx rename to apps/demo/app/invites/page.tsx diff --git a/apps/demo/app/layout.tsx b/apps/demo/app/layout.tsx new file mode 100644 index 000000000..23ab39b78 --- /dev/null +++ b/apps/demo/app/layout.tsx @@ -0,0 +1,45 @@ +import type * as React from "react"; +import type { Metadata } from "next"; +import { PublicSiteFooter } from "@hackkit/ui"; +import { + getPublicThemeStyle, + publicSiteConfig, +} from "@/lib/public-site-config"; +import "./globals.css"; +import { AppBar } from "./app-bar"; +import { Providers } from "./providers"; + +export const metadata: Metadata = { + title: publicSiteConfig.brand.name, + description: publicSiteConfig.brand.description, + robots: { index: false, follow: false }, +}; + +export default function RootLayout({ + children, +}: { + children: React.ReactNode; +}) { + return ( + + + +
+ Shared demo · Use fictional data only ·{" "} + + Switch role + +
+ + {children} + +
+ + + ); +} diff --git a/apps/web/app/onboarding/hacker/hacker-form-defaults.ts b/apps/demo/app/onboarding/hacker/hacker-form-defaults.ts similarity index 100% rename from apps/web/app/onboarding/hacker/hacker-form-defaults.ts rename to apps/demo/app/onboarding/hacker/hacker-form-defaults.ts diff --git a/apps/web/app/onboarding/hacker/hacker-registration-client.tsx b/apps/demo/app/onboarding/hacker/hacker-registration-client.tsx similarity index 100% rename from apps/web/app/onboarding/hacker/hacker-registration-client.tsx rename to apps/demo/app/onboarding/hacker/hacker-registration-client.tsx diff --git a/apps/web/app/onboarding/hacker/page.tsx b/apps/demo/app/onboarding/hacker/page.tsx similarity index 100% rename from apps/web/app/onboarding/hacker/page.tsx rename to apps/demo/app/onboarding/hacker/page.tsx diff --git a/apps/web/app/onboarding/hacktag/page.tsx b/apps/demo/app/onboarding/hacktag/page.tsx similarity index 100% rename from apps/web/app/onboarding/hacktag/page.tsx rename to apps/demo/app/onboarding/hacktag/page.tsx diff --git a/apps/web/app/onboarding/layout.tsx b/apps/demo/app/onboarding/layout.tsx similarity index 100% rename from apps/web/app/onboarding/layout.tsx rename to apps/demo/app/onboarding/layout.tsx diff --git a/apps/web/app/onboarding/onboarding-shell.tsx b/apps/demo/app/onboarding/onboarding-shell.tsx similarity index 100% rename from apps/web/app/onboarding/onboarding-shell.tsx rename to apps/demo/app/onboarding/onboarding-shell.tsx diff --git a/apps/web/app/onboarding/user-data/page.tsx b/apps/demo/app/onboarding/user-data/page.tsx similarity index 100% rename from apps/web/app/onboarding/user-data/page.tsx rename to apps/demo/app/onboarding/user-data/page.tsx diff --git a/apps/demo/app/page.tsx b/apps/demo/app/page.tsx new file mode 100644 index 000000000..e2b0f7f01 --- /dev/null +++ b/apps/demo/app/page.tsx @@ -0,0 +1,55 @@ +import Link from "next/link"; +import { DemoActions } from "./demo-actions"; + +export const dynamic = "force-dynamic"; + +export default function HomePage() { + return ( +
+

+ HackKit interactive demo +

+

+ A hackathon, from application to check-in. +

+

+ See what participants and organizers can do with HackKit. + Explore a working event with fictional people, teams, and a + schedule. +

+
+ +
+ +
+ + Browse the event schedule + + + Try account signup + + + Read the docs + + + View the source + +
+
+ ); +} diff --git a/apps/web/app/participant-layout.tsx b/apps/demo/app/participant-layout.tsx similarity index 100% rename from apps/web/app/participant-layout.tsx rename to apps/demo/app/participant-layout.tsx diff --git a/apps/web/app/pass/event-pass-shell.tsx b/apps/demo/app/pass/event-pass-shell.tsx similarity index 100% rename from apps/web/app/pass/event-pass-shell.tsx rename to apps/demo/app/pass/event-pass-shell.tsx diff --git a/apps/web/app/pass/layout.tsx b/apps/demo/app/pass/layout.tsx similarity index 100% rename from apps/web/app/pass/layout.tsx rename to apps/demo/app/pass/layout.tsx diff --git a/apps/web/app/pass/page.tsx b/apps/demo/app/pass/page.tsx similarity index 100% rename from apps/web/app/pass/page.tsx rename to apps/demo/app/pass/page.tsx diff --git a/apps/web/app/profile-menu.tsx b/apps/demo/app/profile-menu.tsx similarity index 98% rename from apps/web/app/profile-menu.tsx rename to apps/demo/app/profile-menu.tsx index 6b0a15a5c..25c01ee34 100644 --- a/apps/web/app/profile-menu.tsx +++ b/apps/demo/app/profile-menu.tsx @@ -40,6 +40,7 @@ export function ProfileMenu({ type="button" onClick={() => setIsOpen((value) => !value)} className="flex items-center gap-2 rounded-full border bg-background px-2 py-1.5 text-sm font-medium shadow-sm transition hover:bg-muted" + aria-label="Open account menu" aria-haspopup="menu" aria-expanded={isOpen} > diff --git a/apps/web/app/providers.tsx b/apps/demo/app/providers.tsx similarity index 100% rename from apps/web/app/providers.tsx rename to apps/demo/app/providers.tsx diff --git a/apps/web/app/register/page.tsx b/apps/demo/app/register/page.tsx similarity index 100% rename from apps/web/app/register/page.tsx rename to apps/demo/app/register/page.tsx diff --git a/apps/web/app/registration-closed/page.tsx b/apps/demo/app/registration-closed/page.tsx similarity index 100% rename from apps/web/app/registration-closed/page.tsx rename to apps/demo/app/registration-closed/page.tsx diff --git a/apps/web/app/rsvp/layout.tsx b/apps/demo/app/rsvp/layout.tsx similarity index 100% rename from apps/web/app/rsvp/layout.tsx rename to apps/demo/app/rsvp/layout.tsx diff --git a/apps/web/app/rsvp/page.tsx b/apps/demo/app/rsvp/page.tsx similarity index 100% rename from apps/web/app/rsvp/page.tsx rename to apps/demo/app/rsvp/page.tsx diff --git a/apps/web/app/schedule/[eventId]/page.tsx b/apps/demo/app/schedule/[eventId]/page.tsx similarity index 100% rename from apps/web/app/schedule/[eventId]/page.tsx rename to apps/demo/app/schedule/[eventId]/page.tsx diff --git a/apps/web/app/schedule/page.tsx b/apps/demo/app/schedule/page.tsx similarity index 100% rename from apps/web/app/schedule/page.tsx rename to apps/demo/app/schedule/page.tsx diff --git a/apps/web/app/settings/layout.tsx b/apps/demo/app/settings/layout.tsx similarity index 100% rename from apps/web/app/settings/layout.tsx rename to apps/demo/app/settings/layout.tsx diff --git a/apps/web/app/settings/page.tsx b/apps/demo/app/settings/page.tsx similarity index 100% rename from apps/web/app/settings/page.tsx rename to apps/demo/app/settings/page.tsx diff --git a/apps/web/app/settings/profile-settings-client.tsx b/apps/demo/app/settings/profile-settings-client.tsx similarity index 100% rename from apps/web/app/settings/profile-settings-client.tsx rename to apps/demo/app/settings/profile-settings-client.tsx diff --git a/apps/web/app/settings/registration/page.tsx b/apps/demo/app/settings/registration/page.tsx similarity index 100% rename from apps/web/app/settings/registration/page.tsx rename to apps/demo/app/settings/registration/page.tsx diff --git a/apps/web/app/sign-in/auth-form.tsx b/apps/demo/app/sign-in/auth-form.tsx similarity index 100% rename from apps/web/app/sign-in/auth-form.tsx rename to apps/demo/app/sign-in/auth-form.tsx diff --git a/apps/web/app/sign-in/page.tsx b/apps/demo/app/sign-in/page.tsx similarity index 86% rename from apps/web/app/sign-in/page.tsx rename to apps/demo/app/sign-in/page.tsx index aa7678afc..03f759629 100644 --- a/apps/web/app/sign-in/page.tsx +++ b/apps/demo/app/sign-in/page.tsx @@ -12,9 +12,7 @@ export default async function SignInPage() {
-

- HackKit UI test app -

+

HackKit

Sign in

diff --git a/apps/web/app/sign-up/page.tsx b/apps/demo/app/sign-up/page.tsx similarity index 89% rename from apps/web/app/sign-up/page.tsx rename to apps/demo/app/sign-up/page.tsx index eb5407deb..d43a22eeb 100644 --- a/apps/web/app/sign-up/page.tsx +++ b/apps/demo/app/sign-up/page.tsx @@ -12,9 +12,7 @@ export default async function SignUpPage() {
-

- HackKit UI test app -

+

HackKit

Sign up

diff --git a/apps/web/app/suspended/page.tsx b/apps/demo/app/suspended/page.tsx similarity index 100% rename from apps/web/app/suspended/page.tsx rename to apps/demo/app/suspended/page.tsx diff --git a/apps/web/app/teams/layout.tsx b/apps/demo/app/teams/layout.tsx similarity index 100% rename from apps/web/app/teams/layout.tsx rename to apps/demo/app/teams/layout.tsx diff --git a/apps/web/app/teams/page.tsx b/apps/demo/app/teams/page.tsx similarity index 100% rename from apps/web/app/teams/page.tsx rename to apps/demo/app/teams/page.tsx diff --git a/apps/web/app/user/[tag]/page.tsx b/apps/demo/app/user/[tag]/page.tsx similarity index 100% rename from apps/web/app/user/[tag]/page.tsx rename to apps/demo/app/user/[tag]/page.tsx diff --git a/apps/demo/db/migrations/sqlite/.snapshot.json b/apps/demo/db/migrations/sqlite/.snapshot.json new file mode 100644 index 000000000..07e423cd6 --- /dev/null +++ b/apps/demo/db/migrations/sqlite/.snapshot.json @@ -0,0 +1,3800 @@ +{ + "namespaces": [], + "tables": [ + { + "name": "account", + "columns": { + "access_token": { + "name": "access_token", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "access_token_expires_at": { + "name": "access_token_expires_at", + "type": "datetime", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "datetime" + }, + "account_id": { + "name": "account_id", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "created_at": { + "name": "created_at", + "type": "datetime", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "datetime" + }, + "id": { + "name": "id", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": true, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "id_token": { + "name": "id_token", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "password": { + "name": "password", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "provider_id": { + "name": "provider_id", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "refresh_token": { + "name": "refresh_token", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "refresh_token_expires_at": { + "name": "refresh_token_expires_at", + "type": "datetime", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "datetime" + }, + "scope": { + "name": "scope", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "updated_at": { + "name": "updated_at", + "type": "datetime", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "datetime" + }, + "user_id": { + "name": "user_id", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + } + }, + "indexes": [ + { + "columnNames": [ + "user_id" + ], + "composite": false, + "constraint": false, + "keyName": "account_user_id_index", + "primary": false, + "unique": false + }, + { + "columnNames": [ + "id" + ], + "composite": false, + "constraint": true, + "keyName": "primary", + "primary": true, + "unique": true + } + ], + "checks": [], + "triggers": [], + "foreignKeys": { + "account_user_id_foreign": { + "columnNames": [ + "user_id" + ], + "constraintName": "account_user_id_foreign", + "localTableName": "account", + "referencedColumnNames": [ + "id" + ], + "referencedTableName": "core_user", + "deleteRule": "cascade" + } + }, + "comment": null + }, + { + "name": "core_event", + "columns": { + "created_at": { + "name": "created_at", + "type": "datetime", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "datetime" + }, + "description": { + "name": "description", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "end_time": { + "name": "end_time", + "type": "datetime", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "datetime" + }, + "hidden": { + "name": "hidden", + "type": "integer", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": "false", + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "integer" + }, + "host": { + "name": "host", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "id": { + "name": "id", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": true, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "location": { + "name": "location", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": "'TBD'", + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "start_time": { + "name": "start_time", + "type": "datetime", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "datetime" + }, + "title": { + "name": "title", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "type": { + "name": "type", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "updated_at": { + "name": "updated_at", + "type": "datetime", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "datetime" + } + }, + "indexes": [ + { + "columnNames": [ + "hidden" + ], + "composite": false, + "constraint": false, + "keyName": "core_event_hidden_index", + "primary": false, + "unique": false + }, + { + "columnNames": [ + "start_time" + ], + "composite": false, + "constraint": false, + "keyName": "core_event_start_time_index", + "primary": false, + "unique": false + }, + { + "columnNames": [ + "type" + ], + "composite": false, + "constraint": false, + "keyName": "core_event_type_index", + "primary": false, + "unique": false + }, + { + "columnNames": [ + "id" + ], + "composite": false, + "constraint": true, + "keyName": "primary", + "primary": true, + "unique": true + } + ], + "checks": [], + "triggers": [], + "foreignKeys": {}, + "comment": null + }, + { + "name": "core_event_scan", + "columns": { + "auth_id": { + "name": "auth_id", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "event_id": { + "name": "event_id", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "id": { + "name": "id", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": true, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "scanned_at": { + "name": "scanned_at", + "type": "datetime", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "datetime" + }, + "scanned_by_auth_id": { + "name": "scanned_by_auth_id", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + } + }, + "indexes": [ + { + "columnNames": [ + "auth_id" + ], + "composite": false, + "constraint": false, + "keyName": "core_event_scan_auth_id_index", + "primary": false, + "unique": false + }, + { + "columnNames": [ + "event_id", + "auth_id" + ], + "composite": true, + "constraint": false, + "keyName": "core_event_scan_event_id_auth_id_index", + "primary": false, + "unique": false + }, + { + "columnNames": [ + "event_id" + ], + "composite": false, + "constraint": false, + "keyName": "core_event_scan_event_id_index", + "primary": false, + "unique": false + }, + { + "columnNames": [ + "scanned_at" + ], + "composite": false, + "constraint": false, + "keyName": "core_event_scan_scanned_at_index", + "primary": false, + "unique": false + }, + { + "columnNames": [ + "scanned_by_auth_id" + ], + "composite": false, + "constraint": false, + "keyName": "core_event_scan_scanned_by_auth_id_index", + "primary": false, + "unique": false + }, + { + "columnNames": [ + "id" + ], + "composite": false, + "constraint": true, + "keyName": "primary", + "primary": true, + "unique": true + } + ], + "checks": [], + "triggers": [], + "foreignKeys": { + "core_event_scan_auth_id_foreign": { + "columnNames": [ + "auth_id" + ], + "constraintName": "core_event_scan_auth_id_foreign", + "localTableName": "core_event_scan", + "referencedColumnNames": [ + "id" + ], + "referencedTableName": "core_user", + "deleteRule": "cascade" + }, + "core_event_scan_event_id_foreign": { + "columnNames": [ + "event_id" + ], + "constraintName": "core_event_scan_event_id_foreign", + "localTableName": "core_event_scan", + "referencedColumnNames": [ + "id" + ], + "referencedTableName": "core_event", + "deleteRule": "cascade" + }, + "core_event_scan_scanned_by_auth_id_foreign": { + "columnNames": [ + "scanned_by_auth_id" + ], + "constraintName": "core_event_scan_scanned_by_auth_id_foreign", + "localTableName": "core_event_scan", + "referencedColumnNames": [ + "id" + ], + "referencedTableName": "core_user" + } + }, + "comment": null + }, + { + "name": "core_hacker", + "columns": { + "auth_id": { + "name": "auth_id", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": true, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "github_url": { + "name": "github_url", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "group": { + "name": "group", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "hackathons_attended": { + "name": "hackathons_attended", + "type": "integer", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "integer" + }, + "heard_from": { + "name": "heard_from", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "level_of_study": { + "name": "level_of_study", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "linked_in_url": { + "name": "linked_in_url", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "major": { + "name": "major", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "personal_website_url": { + "name": "personal_website_url", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "registered_at": { + "name": "registered_at", + "type": "datetime", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "datetime" + }, + "resume_url": { + "name": "resume_url", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "school_id": { + "name": "school_id", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "software_experience": { + "name": "software_experience", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "university": { + "name": "university", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "updated_at": { + "name": "updated_at", + "type": "datetime", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "datetime" + } + }, + "indexes": [ + { + "columnNames": [ + "auth_id" + ], + "composite": false, + "constraint": false, + "keyName": "core_hacker_auth_id_index", + "primary": false, + "unique": false + }, + { + "columnNames": [ + "registered_at" + ], + "composite": false, + "constraint": false, + "keyName": "core_hacker_registered_at_index", + "primary": false, + "unique": false + }, + { + "columnNames": [ + "auth_id" + ], + "composite": false, + "constraint": true, + "keyName": "primary", + "primary": true, + "unique": true + } + ], + "checks": [], + "triggers": [], + "foreignKeys": { + "core_hacker_auth_id_foreign": { + "columnNames": [ + "auth_id" + ], + "constraintName": "core_hacker_auth_id_foreign", + "localTableName": "core_hacker", + "referencedColumnNames": [ + "id" + ], + "referencedTableName": "core_user", + "updateRule": "cascade", + "deleteRule": "cascade" + } + }, + "comment": null + }, + { + "name": "core_notification_delivery_attempt", + "columns": { + "attempted_at": { + "name": "attempted_at", + "type": "datetime", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "datetime" + }, + "channel": { + "name": "channel", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "error": { + "name": "error", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "external_id": { + "name": "external_id", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "id": { + "name": "id", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": true, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "intent_id": { + "name": "intent_id", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "metadata": { + "name": "metadata", + "type": "json", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "json" + }, + "provider": { + "name": "provider", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "recipient": { + "name": "recipient", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "status": { + "name": "status", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [ + "delivered", + "failed", + "skipped" + ], + "mappedType": "enum" + } + }, + "indexes": [ + { + "columnNames": [ + "attempted_at" + ], + "composite": false, + "constraint": false, + "keyName": "core_notification_delivery_attempt_attempted_at_index", + "primary": false, + "unique": false + }, + { + "columnNames": [ + "channel" + ], + "composite": false, + "constraint": false, + "keyName": "core_notification_delivery_attempt_channel_index", + "primary": false, + "unique": false + }, + { + "columnNames": [ + "intent_id" + ], + "composite": false, + "constraint": false, + "keyName": "core_notification_delivery_attempt_intent_id_index", + "primary": false, + "unique": false + }, + { + "columnNames": [ + "status" + ], + "composite": false, + "constraint": false, + "keyName": "core_notification_delivery_attempt_status_index", + "primary": false, + "unique": false + }, + { + "columnNames": [ + "id" + ], + "composite": false, + "constraint": true, + "keyName": "primary", + "primary": true, + "unique": true + } + ], + "checks": [ + { + "name": "core_notification_delivery_attempt_status_check", + "expression": "`status` in ('delivered', 'failed', 'skipped')", + "definition": "check (`status` in ('delivered', 'failed', 'skipped'))", + "columnName": "status" + } + ], + "triggers": [], + "foreignKeys": { + "core_notification_delivery_attempt_intent_id_foreign": { + "columnNames": [ + "intent_id" + ], + "constraintName": "core_notification_delivery_attempt_intent_id_foreign", + "localTableName": "core_notification_delivery_attempt", + "referencedColumnNames": [ + "id" + ], + "referencedTableName": "core_notification_intent", + "deleteRule": "cascade" + } + }, + "comment": null + }, + { + "name": "core_notification_intent", + "columns": { + "created_at": { + "name": "created_at", + "type": "datetime", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "datetime" + }, + "id": { + "name": "id", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": true, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "idempotency_key": { + "name": "idempotency_key", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "unique": true, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "kind": { + "name": "kind", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "payload": { + "name": "payload", + "type": "json", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "json" + }, + "recipient_auth_id": { + "name": "recipient_auth_id", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "status": { + "name": "status", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": "'pending'", + "comment": null, + "collation": null, + "enumItems": [ + "pending", + "processing", + "delivered", + "failed", + "skipped" + ], + "mappedType": "enum" + }, + "updated_at": { + "name": "updated_at", + "type": "datetime", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "datetime" + } + }, + "indexes": [ + { + "columnNames": [ + "created_at" + ], + "composite": false, + "constraint": false, + "keyName": "core_notification_intent_created_at_index", + "primary": false, + "unique": false + }, + { + "columnNames": [ + "idempotency_key" + ], + "composite": false, + "constraint": true, + "keyName": "core_notification_intent_idempotency_key_unique", + "primary": false, + "unique": true + }, + { + "columnNames": [ + "kind" + ], + "composite": false, + "constraint": false, + "keyName": "core_notification_intent_kind_index", + "primary": false, + "unique": false + }, + { + "columnNames": [ + "recipient_auth_id" + ], + "composite": false, + "constraint": false, + "keyName": "core_notification_intent_recipient_auth_id_index", + "primary": false, + "unique": false + }, + { + "columnNames": [ + "status" + ], + "composite": false, + "constraint": false, + "keyName": "core_notification_intent_status_index", + "primary": false, + "unique": false + }, + { + "columnNames": [ + "id" + ], + "composite": false, + "constraint": true, + "keyName": "primary", + "primary": true, + "unique": true + } + ], + "checks": [ + { + "name": "core_notification_intent_status_check", + "expression": "`status` in ('pending', 'processing', 'delivered', 'failed', 'skipped')", + "definition": "check (`status` in ('pending', 'processing', 'delivered', 'failed', 'skipped'))", + "columnName": "status" + } + ], + "triggers": [], + "foreignKeys": { + "core_notification_intent_recipient_auth_id_foreign": { + "columnNames": [ + "recipient_auth_id" + ], + "constraintName": "core_notification_intent_recipient_auth_id_foreign", + "localTableName": "core_notification_intent", + "referencedColumnNames": [ + "id" + ], + "referencedTableName": "core_user", + "deleteRule": "set null" + } + }, + "comment": null + }, + { + "name": "core_operation_lock", + "columns": { + "key": { + "name": "key", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": true, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "token": { + "name": "token", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + } + }, + "indexes": [ + { + "columnNames": [ + "key" + ], + "composite": false, + "constraint": true, + "keyName": "primary", + "primary": true, + "unique": true + } + ], + "checks": [], + "triggers": [], + "foreignKeys": {}, + "comment": null + }, + { + "name": "core_role", + "columns": { + "color": { + "name": "color", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "created_at": { + "name": "created_at", + "type": "datetime", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "datetime" + }, + "id": { + "name": "id", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": true, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "name": { + "name": "name", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": true, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "permissions": { + "name": "permissions", + "type": "json", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": "'[]'", + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "json" + }, + "position": { + "name": "position", + "type": "integer", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "integer" + }, + "updated_at": { + "name": "updated_at", + "type": "datetime", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "datetime" + } + }, + "indexes": [ + { + "columnNames": [ + "name" + ], + "composite": false, + "constraint": true, + "keyName": "core_role_name_unique", + "primary": false, + "unique": true + }, + { + "columnNames": [ + "position" + ], + "composite": false, + "constraint": false, + "keyName": "core_role_position_index", + "primary": false, + "unique": false + }, + { + "columnNames": [ + "id" + ], + "composite": false, + "constraint": true, + "keyName": "primary", + "primary": true, + "unique": true + } + ], + "checks": [], + "triggers": [], + "foreignKeys": {}, + "comment": null + }, + { + "name": "core_rsvp", + "columns": { + "auth_id": { + "name": "auth_id", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": true, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "cancelled_at": { + "name": "cancelled_at", + "type": "datetime", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "datetime" + }, + "cancelled_by_auth_id": { + "name": "cancelled_by_auth_id", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "confirmed_at": { + "name": "confirmed_at", + "type": "datetime", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "datetime" + }, + "created_at": { + "name": "created_at", + "type": "datetime", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "datetime" + }, + "promoted_at": { + "name": "promoted_at", + "type": "datetime", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "datetime" + }, + "promoted_by_auth_id": { + "name": "promoted_by_auth_id", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "status": { + "name": "status", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [ + "confirmed", + "waitlisted", + "cancelled" + ], + "mappedType": "enum" + }, + "updated_at": { + "name": "updated_at", + "type": "datetime", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "datetime" + }, + "waitlist_position": { + "name": "waitlist_position", + "type": "integer", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "integer" + }, + "waitlisted_at": { + "name": "waitlisted_at", + "type": "datetime", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "datetime" + } + }, + "indexes": [ + { + "columnNames": [ + "auth_id" + ], + "composite": false, + "constraint": false, + "keyName": "core_rsvp_auth_id_index", + "primary": false, + "unique": false + }, + { + "columnNames": [ + "cancelled_by_auth_id" + ], + "composite": false, + "constraint": false, + "keyName": "core_rsvp_cancelled_by_auth_id_index", + "primary": false, + "unique": false + }, + { + "columnNames": [ + "created_at" + ], + "composite": false, + "constraint": false, + "keyName": "core_rsvp_created_at_index", + "primary": false, + "unique": false + }, + { + "columnNames": [ + "promoted_by_auth_id" + ], + "composite": false, + "constraint": false, + "keyName": "core_rsvp_promoted_by_auth_id_index", + "primary": false, + "unique": false + }, + { + "columnNames": [ + "status" + ], + "composite": false, + "constraint": false, + "keyName": "core_rsvp_status_index", + "primary": false, + "unique": false + }, + { + "columnNames": [ + "updated_at" + ], + "composite": false, + "constraint": false, + "keyName": "core_rsvp_updated_at_index", + "primary": false, + "unique": false + }, + { + "columnNames": [ + "waitlist_position" + ], + "composite": false, + "constraint": false, + "keyName": "core_rsvp_waitlist_position_index", + "primary": false, + "unique": false + }, + { + "columnNames": [ + "auth_id" + ], + "composite": false, + "constraint": true, + "keyName": "primary", + "primary": true, + "unique": true + } + ], + "checks": [ + { + "name": "core_rsvp_status_check", + "expression": "`status` in ('confirmed', 'waitlisted', 'cancelled')", + "definition": "check (`status` in ('confirmed', 'waitlisted', 'cancelled'))", + "columnName": "status" + } + ], + "triggers": [], + "foreignKeys": { + "core_rsvp_auth_id_foreign": { + "columnNames": [ + "auth_id" + ], + "constraintName": "core_rsvp_auth_id_foreign", + "localTableName": "core_rsvp", + "referencedColumnNames": [ + "id" + ], + "referencedTableName": "core_user", + "updateRule": "cascade", + "deleteRule": "cascade" + }, + "core_rsvp_cancelled_by_auth_id_foreign": { + "columnNames": [ + "cancelled_by_auth_id" + ], + "constraintName": "core_rsvp_cancelled_by_auth_id_foreign", + "localTableName": "core_rsvp", + "referencedColumnNames": [ + "id" + ], + "referencedTableName": "core_user", + "deleteRule": "set null" + }, + "core_rsvp_promoted_by_auth_id_foreign": { + "columnNames": [ + "promoted_by_auth_id" + ], + "constraintName": "core_rsvp_promoted_by_auth_id_foreign", + "localTableName": "core_rsvp", + "referencedColumnNames": [ + "id" + ], + "referencedTableName": "core_user", + "deleteRule": "set null" + } + }, + "comment": null + }, + { + "name": "core_setting", + "columns": { + "created_at": { + "name": "created_at", + "type": "datetime", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "datetime" + }, + "created_by_auth_id": { + "name": "created_by_auth_id", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "key": { + "name": "key", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": true, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "updated_at": { + "name": "updated_at", + "type": "datetime", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "datetime" + }, + "updated_by_auth_id": { + "name": "updated_by_auth_id", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "value": { + "name": "value", + "type": "json", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "json" + } + }, + "indexes": [ + { + "columnNames": [ + "created_by_auth_id" + ], + "composite": false, + "constraint": false, + "keyName": "core_setting_created_by_auth_id_index", + "primary": false, + "unique": false + }, + { + "columnNames": [ + "updated_at" + ], + "composite": false, + "constraint": false, + "keyName": "core_setting_updated_at_index", + "primary": false, + "unique": false + }, + { + "columnNames": [ + "updated_by_auth_id" + ], + "composite": false, + "constraint": false, + "keyName": "core_setting_updated_by_auth_id_index", + "primary": false, + "unique": false + }, + { + "columnNames": [ + "key" + ], + "composite": false, + "constraint": true, + "keyName": "primary", + "primary": true, + "unique": true + } + ], + "checks": [], + "triggers": [], + "foreignKeys": { + "core_setting_created_by_auth_id_foreign": { + "columnNames": [ + "created_by_auth_id" + ], + "constraintName": "core_setting_created_by_auth_id_foreign", + "localTableName": "core_setting", + "referencedColumnNames": [ + "id" + ], + "referencedTableName": "core_user", + "deleteRule": "set null" + }, + "core_setting_updated_by_auth_id_foreign": { + "columnNames": [ + "updated_by_auth_id" + ], + "constraintName": "core_setting_updated_by_auth_id_foreign", + "localTableName": "core_setting", + "referencedColumnNames": [ + "id" + ], + "referencedTableName": "core_user", + "deleteRule": "set null" + } + }, + "comment": null + }, + { + "name": "core_user", + "columns": { + "bio": { + "name": "bio", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "checked_in_at": { + "name": "checked_in_at", + "type": "datetime", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "datetime" + }, + "created_at": { + "name": "created_at", + "type": "datetime", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "datetime" + }, + "discord_display_handle": { + "name": "discord_display_handle", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "email": { + "name": "email", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": true, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "email_verified": { + "name": "email_verified", + "type": "integer", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": "false", + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "integer" + }, + "hack_tag": { + "name": "hack_tag", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "unique": true, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "id": { + "name": "id", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": true, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "is_approved": { + "name": "is_approved", + "type": "integer", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": "false", + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "integer" + }, + "is_profile_searchable": { + "name": "is_profile_searchable", + "type": "integer", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": "true", + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "integer" + }, + "name": { + "name": "name", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "profile_photo_url": { + "name": "profile_photo_url", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "pronouns": { + "name": "pronouns", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "role_id": { + "name": "role_id", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "skills": { + "name": "skills", + "type": "json", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": "'[]'", + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "json" + }, + "updated_at": { + "name": "updated_at", + "type": "datetime", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "datetime" + } + }, + "indexes": [ + { + "columnNames": [ + "created_at" + ], + "composite": false, + "constraint": false, + "keyName": "core_user_created_at_index", + "primary": false, + "unique": false + }, + { + "columnNames": [ + "email" + ], + "composite": false, + "constraint": true, + "keyName": "core_user_email_unique", + "primary": false, + "unique": true + }, + { + "columnNames": [ + "hack_tag" + ], + "composite": false, + "constraint": false, + "keyName": "core_user_hack_tag_index", + "primary": false, + "unique": false + }, + { + "columnNames": [ + "hack_tag" + ], + "composite": false, + "constraint": true, + "keyName": "core_user_hack_tag_unique", + "primary": false, + "unique": true + }, + { + "columnNames": [ + "role_id" + ], + "composite": false, + "constraint": false, + "keyName": "core_user_role_id_index", + "primary": false, + "unique": false + }, + { + "columnNames": [ + "id" + ], + "composite": false, + "constraint": true, + "keyName": "primary", + "primary": true, + "unique": true + } + ], + "checks": [], + "triggers": [], + "foreignKeys": { + "core_user_role_id_foreign": { + "columnNames": [ + "role_id" + ], + "constraintName": "core_user_role_id_foreign", + "localTableName": "core_user", + "referencedColumnNames": [ + "id" + ], + "referencedTableName": "core_role", + "deleteRule": "set null" + } + }, + "comment": null + }, + { + "name": "core_user_ban", + "columns": { + "auth_id": { + "name": "auth_id", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": true, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "banned_by_auth_id": { + "name": "banned_by_auth_id", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "created_at": { + "name": "created_at", + "type": "datetime", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "datetime" + }, + "reason": { + "name": "reason", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + } + }, + "indexes": [ + { + "columnNames": [ + "auth_id" + ], + "composite": false, + "constraint": false, + "keyName": "core_user_ban_auth_id_index", + "primary": false, + "unique": false + }, + { + "columnNames": [ + "banned_by_auth_id" + ], + "composite": false, + "constraint": false, + "keyName": "core_user_ban_banned_by_auth_id_index", + "primary": false, + "unique": false + }, + { + "columnNames": [ + "auth_id" + ], + "composite": false, + "constraint": true, + "keyName": "primary", + "primary": true, + "unique": true + } + ], + "checks": [], + "triggers": [], + "foreignKeys": { + "core_user_ban_auth_id_foreign": { + "columnNames": [ + "auth_id" + ], + "constraintName": "core_user_ban_auth_id_foreign", + "localTableName": "core_user_ban", + "referencedColumnNames": [ + "id" + ], + "referencedTableName": "core_user", + "updateRule": "cascade", + "deleteRule": "cascade" + }, + "core_user_ban_banned_by_auth_id_foreign": { + "columnNames": [ + "banned_by_auth_id" + ], + "constraintName": "core_user_ban_banned_by_auth_id_foreign", + "localTableName": "core_user_ban", + "referencedColumnNames": [ + "id" + ], + "referencedTableName": "core_user" + } + }, + "comment": null + }, + { + "name": "core_user_data", + "columns": { + "accommodation_note": { + "name": "accommodation_note", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "age": { + "name": "age", + "type": "integer", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "integer" + }, + "auth_id": { + "name": "auth_id", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": true, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "completed_at": { + "name": "completed_at", + "type": "datetime", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "datetime" + }, + "country_of_residence": { + "name": "country_of_residence", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "dietary_restrictions": { + "name": "dietary_restrictions", + "type": "json", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": "'[]'", + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "json" + }, + "ethnicity": { + "name": "ethnicity", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "gender": { + "name": "gender", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "has_accepted_mlhcode_of_conduct": { + "name": "has_accepted_mlhcode_of_conduct", + "type": "integer", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "integer" + }, + "has_shared_data_with_mlh": { + "name": "has_shared_data_with_mlh", + "type": "integer", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "integer" + }, + "is_emailable": { + "name": "is_emailable", + "type": "integer", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "integer" + }, + "phone_number": { + "name": "phone_number", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "race": { + "name": "race", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "shirt_size": { + "name": "shirt_size", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "updated_at": { + "name": "updated_at", + "type": "datetime", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "datetime" + } + }, + "indexes": [ + { + "columnNames": [ + "auth_id" + ], + "composite": false, + "constraint": false, + "keyName": "core_user_data_auth_id_index", + "primary": false, + "unique": false + }, + { + "columnNames": [ + "auth_id" + ], + "composite": false, + "constraint": true, + "keyName": "primary", + "primary": true, + "unique": true + } + ], + "checks": [], + "triggers": [], + "foreignKeys": { + "core_user_data_auth_id_foreign": { + "columnNames": [ + "auth_id" + ], + "constraintName": "core_user_data_auth_id_foreign", + "localTableName": "core_user_data", + "referencedColumnNames": [ + "id" + ], + "referencedTableName": "core_user", + "updateRule": "cascade", + "deleteRule": "cascade" + } + }, + "comment": null + }, + { + "name": "session", + "columns": { + "created_at": { + "name": "created_at", + "type": "datetime", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "datetime" + }, + "expires_at": { + "name": "expires_at", + "type": "datetime", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "datetime" + }, + "id": { + "name": "id", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": true, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "ip_address": { + "name": "ip_address", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "token": { + "name": "token", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": true, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "updated_at": { + "name": "updated_at", + "type": "datetime", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "datetime" + }, + "user_agent": { + "name": "user_agent", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "user_id": { + "name": "user_id", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + } + }, + "indexes": [ + { + "columnNames": [ + "id" + ], + "composite": false, + "constraint": true, + "keyName": "primary", + "primary": true, + "unique": true + }, + { + "columnNames": [ + "token" + ], + "composite": false, + "constraint": true, + "keyName": "session_token_unique", + "primary": false, + "unique": true + }, + { + "columnNames": [ + "user_id" + ], + "composite": false, + "constraint": false, + "keyName": "session_user_id_index", + "primary": false, + "unique": false + } + ], + "checks": [], + "triggers": [], + "foreignKeys": { + "session_user_id_foreign": { + "columnNames": [ + "user_id" + ], + "constraintName": "session_user_id_foreign", + "localTableName": "session", + "referencedColumnNames": [ + "id" + ], + "referencedTableName": "core_user", + "deleteRule": "cascade" + } + }, + "comment": null + }, + { + "name": "teams_invite", + "columns": { + "created_at": { + "name": "created_at", + "type": "datetime", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "datetime" + }, + "id": { + "name": "id", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": true, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "invitee_auth_id": { + "name": "invitee_auth_id", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "status": { + "name": "status", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": "'pending'", + "comment": null, + "collation": null, + "enumItems": [ + "pending", + "accepted", + "declined" + ], + "mappedType": "enum" + }, + "team_id": { + "name": "team_id", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + } + }, + "indexes": [ + { + "columnNames": [ + "id" + ], + "composite": false, + "constraint": true, + "keyName": "primary", + "primary": true, + "unique": true + }, + { + "columnNames": [ + "invitee_auth_id" + ], + "composite": false, + "constraint": false, + "keyName": "teams_invite_invitee_auth_id_index", + "primary": false, + "unique": false + }, + { + "columnNames": [ + "team_id" + ], + "composite": false, + "constraint": false, + "keyName": "teams_invite_team_id_index", + "primary": false, + "unique": false + }, + { + "columnNames": [ + "team_id", + "invitee_auth_id" + ], + "composite": true, + "constraint": false, + "keyName": "teams_invite_team_id_invitee_auth_id_index", + "primary": false, + "unique": false + } + ], + "checks": [ + { + "name": "teams_invite_status_check", + "expression": "`status` in ('pending', 'accepted', 'declined')", + "definition": "check (`status` in ('pending', 'accepted', 'declined'))", + "columnName": "status" + } + ], + "triggers": [], + "foreignKeys": { + "teams_invite_invitee_auth_id_foreign": { + "columnNames": [ + "invitee_auth_id" + ], + "constraintName": "teams_invite_invitee_auth_id_foreign", + "localTableName": "teams_invite", + "referencedColumnNames": [ + "id" + ], + "referencedTableName": "core_user", + "deleteRule": "cascade" + }, + "teams_invite_team_id_foreign": { + "columnNames": [ + "team_id" + ], + "constraintName": "teams_invite_team_id_foreign", + "localTableName": "teams_invite", + "referencedColumnNames": [ + "id" + ], + "referencedTableName": "teams_team", + "deleteRule": "cascade" + } + }, + "comment": null + }, + { + "name": "teams_member", + "columns": { + "auth_id": { + "name": "auth_id", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": true, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "id": { + "name": "id", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": true, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "joined_at": { + "name": "joined_at", + "type": "datetime", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "datetime" + }, + "team_id": { + "name": "team_id", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + } + }, + "indexes": [ + { + "columnNames": [ + "id" + ], + "composite": false, + "constraint": true, + "keyName": "primary", + "primary": true, + "unique": true + }, + { + "columnNames": [ + "auth_id" + ], + "composite": false, + "constraint": false, + "keyName": "teams_member_auth_id_index", + "primary": false, + "unique": false + }, + { + "columnNames": [ + "auth_id" + ], + "composite": false, + "constraint": true, + "keyName": "teams_member_auth_id_unique", + "primary": false, + "unique": true + }, + { + "columnNames": [ + "team_id" + ], + "composite": false, + "constraint": false, + "keyName": "teams_member_team_id_index", + "primary": false, + "unique": false + } + ], + "checks": [], + "triggers": [], + "foreignKeys": { + "teams_member_auth_id_foreign": { + "columnNames": [ + "auth_id" + ], + "constraintName": "teams_member_auth_id_foreign", + "localTableName": "teams_member", + "referencedColumnNames": [ + "id" + ], + "referencedTableName": "core_user", + "deleteRule": "cascade" + }, + "teams_member_team_id_foreign": { + "columnNames": [ + "team_id" + ], + "constraintName": "teams_member_team_id_foreign", + "localTableName": "teams_member", + "referencedColumnNames": [ + "id" + ], + "referencedTableName": "teams_team", + "deleteRule": "cascade" + } + }, + "comment": null + }, + { + "name": "teams_team", + "columns": { + "created_at": { + "name": "created_at", + "type": "datetime", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "datetime" + }, + "id": { + "name": "id", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": true, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "name": { + "name": "name", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "owner_auth_id": { + "name": "owner_auth_id", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "tag": { + "name": "tag", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": true, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + } + }, + "indexes": [ + { + "columnNames": [ + "id" + ], + "composite": false, + "constraint": true, + "keyName": "primary", + "primary": true, + "unique": true + }, + { + "columnNames": [ + "owner_auth_id" + ], + "composite": false, + "constraint": false, + "keyName": "teams_team_owner_auth_id_index", + "primary": false, + "unique": false + }, + { + "columnNames": [ + "tag" + ], + "composite": false, + "constraint": false, + "keyName": "teams_team_tag_index", + "primary": false, + "unique": false + }, + { + "columnNames": [ + "tag" + ], + "composite": false, + "constraint": true, + "keyName": "teams_team_tag_unique", + "primary": false, + "unique": true + } + ], + "checks": [], + "triggers": [], + "foreignKeys": { + "teams_team_owner_auth_id_foreign": { + "columnNames": [ + "owner_auth_id" + ], + "constraintName": "teams_team_owner_auth_id_foreign", + "localTableName": "teams_team", + "referencedColumnNames": [ + "id" + ], + "referencedTableName": "core_user", + "deleteRule": "cascade" + } + }, + "comment": null + }, + { + "name": "verification", + "columns": { + "created_at": { + "name": "created_at", + "type": "datetime", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "datetime" + }, + "expires_at": { + "name": "expires_at", + "type": "datetime", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "datetime" + }, + "id": { + "name": "id", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": true, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "identifier": { + "name": "identifier", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "updated_at": { + "name": "updated_at", + "type": "datetime", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "datetime" + }, + "value": { + "name": "value", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + } + }, + "indexes": [ + { + "columnNames": [ + "id" + ], + "composite": false, + "constraint": true, + "keyName": "primary", + "primary": true, + "unique": true + }, + { + "columnNames": [ + "identifier" + ], + "composite": false, + "constraint": false, + "keyName": "verification_identifier_index", + "primary": false, + "unique": false + } + ], + "checks": [], + "triggers": [], + "foreignKeys": {}, + "comment": null + } + ], + "views": [], + "nativeEnums": {} +} \ No newline at end of file diff --git a/apps/demo/db/migrations/sqlite/Migration20261020221614_demo_initial.ts b/apps/demo/db/migrations/sqlite/Migration20261020221614_demo_initial.ts new file mode 100644 index 000000000..ff282dac9 --- /dev/null +++ b/apps/demo/db/migrations/sqlite/Migration20261020221614_demo_initial.ts @@ -0,0 +1,258 @@ +import { Migration } from "@mikro-orm/migrations"; + +export class Migration20261020221614_demo_initial extends Migration { + override name = "Migration20261020221614_demo_initial"; + + override up(): void | Promise { + this.addSql( + `create table \`verification\` (\`id\` text not null primary key, \`identifier\` text not null, \`value\` text not null, \`expires_at\` datetime not null, \`created_at\` datetime null, \`updated_at\` datetime null);`, + ); + this.addSql( + `create index \`verification_identifier_index\` on \`verification\` (\`identifier\`);`, + ); + + this.addSql( + `create table \`core_event\` (\`id\` text not null primary key, \`title\` text not null, \`start_time\` datetime not null, \`end_time\` datetime not null, \`location\` text not null default 'TBD', \`description\` text not null, \`type\` text not null, \`host\` text null, \`hidden\` integer not null default false, \`created_at\` datetime not null, \`updated_at\` datetime not null);`, + ); + this.addSql( + `create index \`core_event_start_time_index\` on \`core_event\` (\`start_time\`);`, + ); + this.addSql( + `create index \`core_event_type_index\` on \`core_event\` (\`type\`);`, + ); + this.addSql( + `create index \`core_event_hidden_index\` on \`core_event\` (\`hidden\`);`, + ); + + this.addSql( + `create table \`core_operation_lock\` (\`key\` text not null primary key, \`token\` text not null);`, + ); + + this.addSql( + `create table \`core_role\` (\`id\` text not null primary key, \`name\` text not null, \`position\` integer not null, \`permissions\` json not null default '[]', \`color\` text null, \`created_at\` datetime not null, \`updated_at\` datetime not null);`, + ); + this.addSql( + `create unique index \`core_role_name_unique\` on \`core_role\` (\`name\`);`, + ); + this.addSql( + `create index \`core_role_position_index\` on \`core_role\` (\`position\`);`, + ); + + this.addSql( + `create table \`core_user\` (\`id\` text not null primary key, \`name\` text not null, \`email\` text not null, \`email_verified\` integer not null default false, \`profile_photo_url\` text null, \`hack_tag\` text null, \`bio\` text null, \`pronouns\` text null, \`skills\` json not null default '[]', \`is_profile_searchable\` integer not null default true, \`discord_display_handle\` text null, \`role_id\` text null, \`is_approved\` integer not null default false, \`checked_in_at\` datetime null, \`created_at\` datetime not null, \`updated_at\` datetime not null, constraint \`core_user_role_id_foreign\` foreign key (\`role_id\`) references \`core_role\` (\`id\`) on delete set null);`, + ); + this.addSql( + `create unique index \`core_user_email_unique\` on \`core_user\` (\`email\`);`, + ); + this.addSql( + `create unique index \`core_user_hack_tag_unique\` on \`core_user\` (\`hack_tag\`);`, + ); + this.addSql( + `create index \`core_user_hack_tag_index\` on \`core_user\` (\`hack_tag\`);`, + ); + this.addSql( + `create index \`core_user_role_id_index\` on \`core_user\` (\`role_id\`);`, + ); + this.addSql( + `create index \`core_user_created_at_index\` on \`core_user\` (\`created_at\`);`, + ); + + this.addSql( + `create table \`core_user_data\` (\`auth_id\` text not null primary key, \`age\` integer not null, \`gender\` text not null, \`race\` text not null, \`ethnicity\` text not null, \`shirt_size\` text not null, \`dietary_restrictions\` json not null default '[]', \`accommodation_note\` text null, \`phone_number\` text null, \`country_of_residence\` text null, \`has_accepted_mlhcode_of_conduct\` integer not null, \`has_shared_data_with_mlh\` integer not null, \`is_emailable\` integer not null, \`completed_at\` datetime not null, \`updated_at\` datetime not null, constraint \`core_user_data_auth_id_foreign\` foreign key (\`auth_id\`) references \`core_user\` (\`id\`) on update cascade on delete cascade);`, + ); + this.addSql( + `create index \`core_user_data_auth_id_index\` on \`core_user_data\` (\`auth_id\`);`, + ); + + this.addSql( + `create table \`core_user_ban\` (\`auth_id\` text not null primary key, \`reason\` text null, \`banned_by_auth_id\` text not null, \`created_at\` datetime not null, constraint \`core_user_ban_auth_id_foreign\` foreign key (\`auth_id\`) references \`core_user\` (\`id\`) on update cascade on delete cascade, constraint \`core_user_ban_banned_by_auth_id_foreign\` foreign key (\`banned_by_auth_id\`) references \`core_user\` (\`id\`));`, + ); + this.addSql( + `create index \`core_user_ban_auth_id_index\` on \`core_user_ban\` (\`auth_id\`);`, + ); + this.addSql( + `create index \`core_user_ban_banned_by_auth_id_index\` on \`core_user_ban\` (\`banned_by_auth_id\`);`, + ); + + this.addSql( + `create table \`core_setting\` (\`key\` text not null primary key, \`value\` json not null, \`created_at\` datetime not null, \`created_by_auth_id\` text null, \`updated_at\` datetime not null, \`updated_by_auth_id\` text null, constraint \`core_setting_created_by_auth_id_foreign\` foreign key (\`created_by_auth_id\`) references \`core_user\` (\`id\`) on delete set null, constraint \`core_setting_updated_by_auth_id_foreign\` foreign key (\`updated_by_auth_id\`) references \`core_user\` (\`id\`) on delete set null);`, + ); + this.addSql( + `create index \`core_setting_created_by_auth_id_index\` on \`core_setting\` (\`created_by_auth_id\`);`, + ); + this.addSql( + `create index \`core_setting_updated_at_index\` on \`core_setting\` (\`updated_at\`);`, + ); + this.addSql( + `create index \`core_setting_updated_by_auth_id_index\` on \`core_setting\` (\`updated_by_auth_id\`);`, + ); + + this.addSql( + `create table \`core_rsvp\` (\`auth_id\` text not null primary key, \`status\` text check (\`status\` in ('confirmed', 'waitlisted', 'cancelled')) not null, \`waitlist_position\` integer null, \`created_at\` datetime not null, \`updated_at\` datetime not null, \`confirmed_at\` datetime null, \`waitlisted_at\` datetime null, \`cancelled_at\` datetime null, \`cancelled_by_auth_id\` text null, \`promoted_at\` datetime null, \`promoted_by_auth_id\` text null, constraint \`core_rsvp_auth_id_foreign\` foreign key (\`auth_id\`) references \`core_user\` (\`id\`) on update cascade on delete cascade, constraint \`core_rsvp_cancelled_by_auth_id_foreign\` foreign key (\`cancelled_by_auth_id\`) references \`core_user\` (\`id\`) on delete set null, constraint \`core_rsvp_promoted_by_auth_id_foreign\` foreign key (\`promoted_by_auth_id\`) references \`core_user\` (\`id\`) on delete set null);`, + ); + this.addSql( + `create index \`core_rsvp_auth_id_index\` on \`core_rsvp\` (\`auth_id\`);`, + ); + this.addSql( + `create index \`core_rsvp_cancelled_by_auth_id_index\` on \`core_rsvp\` (\`cancelled_by_auth_id\`);`, + ); + this.addSql( + `create index \`core_rsvp_promoted_by_auth_id_index\` on \`core_rsvp\` (\`promoted_by_auth_id\`);`, + ); + this.addSql( + `create index \`core_rsvp_status_index\` on \`core_rsvp\` (\`status\`);`, + ); + this.addSql( + `create index \`core_rsvp_waitlist_position_index\` on \`core_rsvp\` (\`waitlist_position\`);`, + ); + this.addSql( + `create index \`core_rsvp_created_at_index\` on \`core_rsvp\` (\`created_at\`);`, + ); + this.addSql( + `create index \`core_rsvp_updated_at_index\` on \`core_rsvp\` (\`updated_at\`);`, + ); + + this.addSql( + `create table \`core_notification_intent\` (\`id\` text not null primary key, \`kind\` text not null, \`recipient_auth_id\` text null, \`payload\` json not null, \`status\` text check (\`status\` in ('pending', 'processing', 'delivered', 'failed', 'skipped')) not null default 'pending', \`idempotency_key\` text null, \`created_at\` datetime not null, \`updated_at\` datetime not null, constraint \`core_notification_intent_recipient_auth_id_foreign\` foreign key (\`recipient_auth_id\`) references \`core_user\` (\`id\`) on delete set null);`, + ); + this.addSql( + `create unique index \`core_notification_intent_idempotency_key_unique\` on \`core_notification_intent\` (\`idempotency_key\`);`, + ); + this.addSql( + `create index \`core_notification_intent_kind_index\` on \`core_notification_intent\` (\`kind\`);`, + ); + this.addSql( + `create index \`core_notification_intent_recipient_auth_id_index\` on \`core_notification_intent\` (\`recipient_auth_id\`);`, + ); + this.addSql( + `create index \`core_notification_intent_status_index\` on \`core_notification_intent\` (\`status\`);`, + ); + this.addSql( + `create index \`core_notification_intent_created_at_index\` on \`core_notification_intent\` (\`created_at\`);`, + ); + + this.addSql( + `create table \`core_notification_delivery_attempt\` (\`id\` text not null primary key, \`intent_id\` text not null, \`channel\` text not null, \`provider\` text null, \`status\` text check (\`status\` in ('delivered', 'failed', 'skipped')) not null, \`recipient\` text null, \`external_id\` text null, \`error\` text null, \`metadata\` json not null, \`attempted_at\` datetime not null, constraint \`core_notification_delivery_attempt_intent_id_foreign\` foreign key (\`intent_id\`) references \`core_notification_intent\` (\`id\`) on delete cascade);`, + ); + this.addSql( + `create index \`core_notification_delivery_attempt_intent_id_index\` on \`core_notification_delivery_attempt\` (\`intent_id\`);`, + ); + this.addSql( + `create index \`core_notification_delivery_attempt_channel_index\` on \`core_notification_delivery_attempt\` (\`channel\`);`, + ); + this.addSql( + `create index \`core_notification_delivery_attempt_status_index\` on \`core_notification_delivery_attempt\` (\`status\`);`, + ); + this.addSql( + `create index \`core_notification_delivery_attempt_attempted_at_index\` on \`core_notification_delivery_attempt\` (\`attempted_at\`);`, + ); + + this.addSql( + `create table \`core_hacker\` (\`auth_id\` text not null primary key, \`university\` text not null, \`major\` text not null, \`school_id\` text null, \`level_of_study\` text not null, \`hackathons_attended\` integer not null, \`software_experience\` text not null, \`heard_from\` text null, \`github_url\` text null, \`linked_in_url\` text null, \`personal_website_url\` text null, \`resume_url\` text null, \`group\` text null, \`registered_at\` datetime not null, \`updated_at\` datetime not null, constraint \`core_hacker_auth_id_foreign\` foreign key (\`auth_id\`) references \`core_user\` (\`id\`) on update cascade on delete cascade);`, + ); + this.addSql( + `create index \`core_hacker_auth_id_index\` on \`core_hacker\` (\`auth_id\`);`, + ); + this.addSql( + `create index \`core_hacker_registered_at_index\` on \`core_hacker\` (\`registered_at\`);`, + ); + + this.addSql( + `create table \`core_event_scan\` (\`id\` text not null primary key, \`event_id\` text not null, \`auth_id\` text not null, \`scanned_by_auth_id\` text not null, \`scanned_at\` datetime not null, constraint \`core_event_scan_event_id_foreign\` foreign key (\`event_id\`) references \`core_event\` (\`id\`) on delete cascade, constraint \`core_event_scan_auth_id_foreign\` foreign key (\`auth_id\`) references \`core_user\` (\`id\`) on delete cascade, constraint \`core_event_scan_scanned_by_auth_id_foreign\` foreign key (\`scanned_by_auth_id\`) references \`core_user\` (\`id\`));`, + ); + this.addSql( + `create index \`core_event_scan_scanned_by_auth_id_index\` on \`core_event_scan\` (\`scanned_by_auth_id\`);`, + ); + this.addSql( + `create index \`core_event_scan_event_id_index\` on \`core_event_scan\` (\`event_id\`);`, + ); + this.addSql( + `create index \`core_event_scan_auth_id_index\` on \`core_event_scan\` (\`auth_id\`);`, + ); + this.addSql( + `create index \`core_event_scan_event_id_auth_id_index\` on \`core_event_scan\` (\`event_id\`, \`auth_id\`);`, + ); + this.addSql( + `create index \`core_event_scan_scanned_at_index\` on \`core_event_scan\` (\`scanned_at\`);`, + ); + + this.addSql( + `create table \`session\` (\`id\` text not null primary key, \`expires_at\` datetime not null, \`token\` text not null, \`created_at\` datetime not null, \`updated_at\` datetime not null, \`ip_address\` text null, \`user_agent\` text null, \`user_id\` text not null, constraint \`session_user_id_foreign\` foreign key (\`user_id\`) references \`core_user\` (\`id\`) on delete cascade);`, + ); + this.addSql( + `create unique index \`session_token_unique\` on \`session\` (\`token\`);`, + ); + this.addSql( + `create index \`session_user_id_index\` on \`session\` (\`user_id\`);`, + ); + + this.addSql( + `create table \`account\` (\`id\` text not null primary key, \`account_id\` text not null, \`provider_id\` text not null, \`user_id\` text not null, \`access_token\` text null, \`refresh_token\` text null, \`id_token\` text null, \`access_token_expires_at\` datetime null, \`refresh_token_expires_at\` datetime null, \`scope\` text null, \`password\` text null, \`created_at\` datetime not null, \`updated_at\` datetime not null, constraint \`account_user_id_foreign\` foreign key (\`user_id\`) references \`core_user\` (\`id\`) on delete cascade);`, + ); + this.addSql( + `create index \`account_user_id_index\` on \`account\` (\`user_id\`);`, + ); + + this.addSql( + `create table \`teams_team\` (\`id\` text not null primary key, \`name\` text not null, \`tag\` text not null, \`owner_auth_id\` text not null, \`created_at\` datetime not null, constraint \`teams_team_owner_auth_id_foreign\` foreign key (\`owner_auth_id\`) references \`core_user\` (\`id\`) on delete cascade);`, + ); + this.addSql( + `create unique index \`teams_team_tag_unique\` on \`teams_team\` (\`tag\`);`, + ); + this.addSql( + `create index \`teams_team_tag_index\` on \`teams_team\` (\`tag\`);`, + ); + this.addSql( + `create index \`teams_team_owner_auth_id_index\` on \`teams_team\` (\`owner_auth_id\`);`, + ); + + this.addSql( + `create table \`teams_member\` (\`id\` text not null primary key, \`team_id\` text not null, \`auth_id\` text not null, \`joined_at\` datetime not null, constraint \`teams_member_team_id_foreign\` foreign key (\`team_id\`) references \`teams_team\` (\`id\`) on delete cascade, constraint \`teams_member_auth_id_foreign\` foreign key (\`auth_id\`) references \`core_user\` (\`id\`) on delete cascade);`, + ); + this.addSql( + `create unique index \`teams_member_auth_id_unique\` on \`teams_member\` (\`auth_id\`);`, + ); + this.addSql( + `create index \`teams_member_team_id_index\` on \`teams_member\` (\`team_id\`);`, + ); + this.addSql( + `create index \`teams_member_auth_id_index\` on \`teams_member\` (\`auth_id\`);`, + ); + + this.addSql( + `create table \`teams_invite\` (\`id\` text not null primary key, \`team_id\` text not null, \`invitee_auth_id\` text not null, \`status\` text check (\`status\` in ('pending', 'accepted', 'declined')) not null default 'pending', \`created_at\` datetime not null, constraint \`teams_invite_team_id_foreign\` foreign key (\`team_id\`) references \`teams_team\` (\`id\`) on delete cascade, constraint \`teams_invite_invitee_auth_id_foreign\` foreign key (\`invitee_auth_id\`) references \`core_user\` (\`id\`) on delete cascade);`, + ); + this.addSql( + `create index \`teams_invite_team_id_index\` on \`teams_invite\` (\`team_id\`);`, + ); + this.addSql( + `create index \`teams_invite_invitee_auth_id_index\` on \`teams_invite\` (\`invitee_auth_id\`);`, + ); + this.addSql( + `create index \`teams_invite_team_id_invitee_auth_id_index\` on \`teams_invite\` (\`team_id\`, \`invitee_auth_id\`);`, + ); + } + + override down(): void | Promise { + this.addSql(`drop table if exists \`verification\`;`); + this.addSql(`drop table if exists \`core_event\`;`); + this.addSql(`drop table if exists \`core_operation_lock\`;`); + this.addSql(`drop table if exists \`core_role\`;`); + this.addSql(`drop table if exists \`core_user\`;`); + this.addSql(`drop table if exists \`core_user_data\`;`); + this.addSql(`drop table if exists \`core_user_ban\`;`); + this.addSql(`drop table if exists \`core_setting\`;`); + this.addSql(`drop table if exists \`core_rsvp\`;`); + this.addSql(`drop table if exists \`core_notification_intent\`;`); + this.addSql( + `drop table if exists \`core_notification_delivery_attempt\`;`, + ); + this.addSql(`drop table if exists \`core_hacker\`;`); + this.addSql(`drop table if exists \`core_event_scan\`;`); + this.addSql(`drop table if exists \`session\`;`); + this.addSql(`drop table if exists \`account\`;`); + this.addSql(`drop table if exists \`teams_team\`;`); + this.addSql(`drop table if exists \`teams_member\`;`); + this.addSql(`drop table if exists \`teams_invite\`;`); + } +} diff --git a/apps/demo/env.ts b/apps/demo/env.ts new file mode 100644 index 000000000..6ded78775 --- /dev/null +++ b/apps/demo/env.ts @@ -0,0 +1,25 @@ +// Worker secrets are exposed through process.env by nodejs_compat. Node scripts +// explicitly load .dev.vars before importing the application configuration. +export const env = { + appUrl: process.env.BETTER_AUTH_URL ?? "http://localhost:3001", + betterAuthUrl: process.env.BETTER_AUTH_URL ?? "http://localhost:3001", + betterAuthSecret: process.env.BETTER_AUTH_SECRET, + databaseUrl: process.env.TURSO_DATABASE_URL, + tursoAuthToken: process.env.TURSO_AUTH_TOKEN, +}; + +export function assertDemoEnvironment() { + if (!env.databaseUrl || !/^(libsql|https?):\/\//.test(env.databaseUrl)) + throw new Error( + "Set TURSO_DATABASE_URL in apps/demo/.dev.vars or Worker secrets.", + ); + if (!env.tursoAuthToken) + throw new Error( + "Set TURSO_AUTH_TOKEN in apps/demo/.dev.vars or Worker secrets.", + ); + if (!env.betterAuthSecret || env.betterAuthSecret.length < 32) + throw new Error( + "Set BETTER_AUTH_SECRET to a random value of at least 32 characters.", + ); + new URL(env.appUrl); +} diff --git a/apps/demo/hackkit.config.ts b/apps/demo/hackkit.config.ts new file mode 100644 index 000000000..ccc9edd52 --- /dev/null +++ b/apps/demo/hackkit.config.ts @@ -0,0 +1,138 @@ +import { defineHackkitConfig } from "@hackkit/config"; +import { CorePermission, type PermissionKey } from "@hackkit/core"; +import { databaseOptions } from "./lib/database-config"; +import { authOptions } from "./lib/auth-options"; +import { teamsPlugin, TeamsPermission } from "@hackkit/plugin-teams"; + +const participantPermissions = [] as PermissionKey[]; + +const adminPermissions = [ + ...Object.values(CorePermission), + ...Object.values(TeamsPermission), +] satisfies PermissionKey[]; + +const shirtSizeOptions = [ + { value: "s", label: "Small" }, + { value: "m", label: "Medium" }, + { value: "l", label: "Large" }, + { value: "xl", label: "Extra large" }, + { value: "2xl", label: "2XL" }, + { value: "3xl", label: "3XL" }, +]; + +const countryOptions = [ + { value: "us", label: "United States" }, + { value: "ca", label: "Canada" }, + { value: "mx", label: "Mexico" }, + { value: "gb", label: "United Kingdom" }, + { value: "other", label: "Other" }, +]; + +const schoolOptions = [ + { + value: "University of Texas at San Antonio", + label: "University of Texas at San Antonio", + }, + { + value: "University of Texas at Austin", + label: "University of Texas at Austin", + }, + { value: "Texas A&M University", label: "Texas A&M University" }, + { value: "Rice University", label: "Rice University" }, + { value: "other", label: "Other" }, +]; + +const majorOptions = [ + { value: "Computer Science", label: "Computer Science" }, + { value: "Computer Engineering", label: "Computer Engineering" }, + { value: "Electrical Engineering", label: "Electrical Engineering" }, + { value: "Data Science", label: "Data Science" }, + { value: "Design", label: "Design" }, + { value: "Business", label: "Business" }, + { value: "other", label: "Other" }, +]; + +const levelsOfStudy = [ + { value: "Freshman", label: "Freshman" }, + { value: "Sophomore", label: "Sophomore" }, + { value: "Junior", label: "Junior" }, + { value: "Senior", label: "Senior" }, + { value: "Graduate", label: "Graduate" }, + { value: "Recent Grad", label: "Recent Grad" }, + { value: "Other", label: "Other" }, +]; + +const softwareExperienceOptions = [ + { value: "Beginner", label: "Beginner" }, + { value: "Intermediate", label: "Intermediate" }, + { value: "Advanced", label: "Advanced" }, + { value: "Expert", label: "Expert" }, +]; + +const heardFromOptions = [ + { value: "Instagram", label: "Instagram" }, + { value: "Class Presentation", label: "Class presentation" }, + { value: "Twitter", label: "Twitter" }, + { value: "Event Site", label: "Event site" }, + { value: "Friend", label: "Friend" }, + { value: "Other", label: "Other" }, +]; + +const groups = [ + { + id: "guild-a", + label: "Guild A", + discordRoleName: "Guild A", + }, + { + id: "guild-b", + label: "Guild B", + discordRoleName: "Guild B", + }, + { + id: "guild-c", + label: "Guild C", + discordRoleName: "Guild C", + }, +] as const; + +export default defineHackkitConfig({ + database: databaseOptions, + auth: authOptions, + defaultCompetitorRoleId: "core.participant", + groups, + seedRoles: [ + { + id: "core.participant", + name: "Participant", + position: 10, + permissions: participantPermissions, + }, + { + id: "core.owner", + name: "Owner", + position: 0, + permissions: adminPermissions, + }, + ], + logger: { level: "warn" }, + plugins: [teamsPlugin()], + userDataOptions: { + shirtSize: shirtSizeOptions, + countryOfResidence: countryOptions, + }, + hackerRegistrationOptions: { + schools: schoolOptions, + majors: majorOptions, + levelsOfStudy, + softwareExperience: softwareExperienceOptions, + heardFrom: heardFromOptions, + }, + eventTypes: [ + { value: "meal", label: "Meal", color: "#FFC107" }, + { value: "workshop", label: "Workshop", color: "#10b981" }, + { value: "ceremony", label: "Ceremony", color: "#9C27B0" }, + { value: "social", label: "Social", color: "#2196F3" }, + { value: "other", label: "Other", color: "#795548" }, + ], +}); diff --git a/apps/demo/hackkit.lock b/apps/demo/hackkit.lock new file mode 100644 index 000000000..40c371735 --- /dev/null +++ b/apps/demo/hackkit.lock @@ -0,0 +1,20 @@ +{ + "version": 1, + "plugins": [ + { + "id": "teams", + "package": "@hackkit/plugin-teams", + "version": "0.0.0", + "routes": [ + { + "host": "app/invites/page.tsx", + "source": "@hackkit/plugin-teams/app/invites/page" + }, + { + "host": "app/teams/page.tsx", + "source": "@hackkit/plugin-teams/app/teams/page" + } + ] + } + ] +} diff --git a/apps/demo/lib/app-config.ts b/apps/demo/lib/app-config.ts new file mode 100644 index 000000000..0753fba17 --- /dev/null +++ b/apps/demo/lib/app-config.ts @@ -0,0 +1,15 @@ +import "server-only"; + +import { resolveHackkitConfig } from "@hackkit/config"; +import hackkitConfig from "../hackkit.config"; +import { env } from "../env"; +import compiledFunctions from "./generated/orm-functions.js"; + +export const appConfig = resolveHackkitConfig({ + ...hackkitConfig, + database: { ...hackkitConfig.database, compiledFunctions }, +}); + +export function resolveAppBaseUrl(): string { + return env.appUrl; +} diff --git a/apps/web/lib/auth-client.ts b/apps/demo/lib/auth-client.ts similarity index 100% rename from apps/web/lib/auth-client.ts rename to apps/demo/lib/auth-client.ts diff --git a/apps/demo/lib/auth-options.ts b/apps/demo/lib/auth-options.ts new file mode 100644 index 000000000..7019da877 --- /dev/null +++ b/apps/demo/lib/auth-options.ts @@ -0,0 +1,8 @@ +import type { HackKitAuthOptions } from "@hackkit/core"; +import { env } from "../env"; +export const authOptions = { + baseURL: env.betterAuthUrl, + secret: env.betterAuthSecret, + trustedOrigins: [env.appUrl], + emailAndPassword: { enabled: true }, +} satisfies HackKitAuthOptions; diff --git a/apps/web/lib/auth.ts b/apps/demo/lib/auth.ts similarity index 100% rename from apps/web/lib/auth.ts rename to apps/demo/lib/auth.ts diff --git a/apps/demo/lib/blob.ts b/apps/demo/lib/blob.ts new file mode 100644 index 000000000..ed70dc54e --- /dev/null +++ b/apps/demo/lib/blob.ts @@ -0,0 +1,65 @@ +import "server-only"; +import { env } from "cloudflare:workers"; +import { env as settings } from "../env"; + +export const maximumUploadBytes = 10 * 1024 * 1024; + +export function createUploadTarget(input: { + ownerId: string; + location: string; + fileName: string; +}) { + const extension = input.fileName + .split(".") + .pop() + ?.replace(/[^a-z0-9]/gi, "") + .slice(0, 12); + const key = `${input.location}/${input.ownerId}/${crypto.randomUUID()}${extension ? `.${extension}` : ""}`; + return { + uploadUrl: `${settings.appUrl}/api/files/upload?key=${encodeURIComponent(key)}`, + storedFileReference: `/api/files/view?key=${encodeURIComponent(key)}`, + }; +} + +export function canUploadKey(key: string, ownerId: string) { + return ( + ["resumes", "profile-photos"].some((location) => + key.startsWith(`${location}/${ownerId}/`), + ) && + !key.includes("..") && + key.split("/").length === 3 + ); +} + +/** Read a bounded body even when a client omits Content-Length. */ +export async function readUploadBody(request: Request) { + const reader = request.body?.getReader(); + if (!reader) return new Uint8Array(); + const chunks: Uint8Array[] = []; + let length = 0; + try { + while (true) { + const { done, value } = await reader.read(); + if (done) break; + length += value.byteLength; + if (length > maximumUploadBytes) { + await reader.cancel(); + throw new RangeError("Files must be 10 MiB or smaller."); + } + chunks.push(value); + } + } finally { + reader.releaseLock(); + } + const body = new Uint8Array(length); + let offset = 0; + for (const chunk of chunks) { + body.set(chunk, offset); + offset += chunk.byteLength; + } + return body; +} + +export function getBlobStorage() { + return env.DEMO_UPLOADS; +} diff --git a/apps/demo/lib/database-config.ts b/apps/demo/lib/database-config.ts new file mode 100644 index 000000000..5925f6fab --- /dev/null +++ b/apps/demo/lib/database-config.ts @@ -0,0 +1,16 @@ +import { SqliteDriver } from "@mikro-orm/sql"; +import { HttpLibsqlDialect } from "./http-libsql-dialect"; +import type { HackKitDatabaseOptions } from "@hackkit/core"; +import { env } from "../env"; + +// The generic SQLite driver accepts a Kysely dialect without loading native +// SQLite binaries. The web client uses Turso's HTTP API and supports transactions. +export const databaseOptions = { + driver: SqliteDriver, + dbName: "hackkit-demo", + driverOptions: () => + new HttpLibsqlDialect({ + url: env.databaseUrl ?? "http://127.0.0.1:9", + authToken: env.tursoAuthToken, + }), +} satisfies HackKitDatabaseOptions; diff --git a/apps/demo/lib/demo-accounts.ts b/apps/demo/lib/demo-accounts.ts new file mode 100644 index 000000000..b54a7d496 --- /dev/null +++ b/apps/demo/lib/demo-accounts.ts @@ -0,0 +1,20 @@ +// Public, fictional accounts in the shared demonstration database. +export const demoPassword = "Explore-HackKit-2026!"; +export const demoAccounts = { + participant: { + name: "Alex Rivera", + email: "alex@example.com", + tag: "alex", + }, + organizer: { name: "Sam Chen", email: "sam@example.com", tag: "sam" }, + newcomer: { + name: "Jordan Park", + email: "jordan@example.com", + tag: "jordan", + }, + teammate: { + name: "Taylor Morgan", + email: "taylor@example.com", + tag: "taylor", + }, +}; diff --git a/apps/web/lib/hackkit-ui-routes.ts b/apps/demo/lib/hackkit-ui-routes.ts similarity index 100% rename from apps/web/lib/hackkit-ui-routes.ts rename to apps/demo/lib/hackkit-ui-routes.ts diff --git a/apps/demo/lib/http-libsql-dialect.ts b/apps/demo/lib/http-libsql-dialect.ts new file mode 100644 index 000000000..a9cc34464 --- /dev/null +++ b/apps/demo/lib/http-libsql-dialect.ts @@ -0,0 +1,66 @@ +import { createClient, type Client, type Config } from "@libsql/client/web"; +import { + LibsqlConnection, + LibsqlDialect, + LibsqlDriver, +} from "@libsql/kysely-libsql"; +import { CompiledQuery, SqliteAdapter, type DatabaseConnection } from "kysely"; + +/** Complete Kysely's savepoint API for MikroORM's nested transactions. */ +class HttpLibsqlDriver extends LibsqlDriver { + private readonly clients = new WeakMap(); + constructor(private readonly createClient: () => Client) { + super(createClient(), true); + } + // libSQL HTTP clients retain stream state. Each checkout must belong to the + // current Worker request, while a transaction keeps its own connection. + override async acquireConnection() { + const client = this.createClient(); + const connection = new LibsqlConnection(client); + this.clients.set(connection, client); + return connection; + } + override async releaseConnection(connection: DatabaseConnection) { + this.clients.get(connection)?.close(); + this.clients.delete(connection); + } + async savepoint(connection: DatabaseConnection, name: string) { + await connection.executeQuery( + CompiledQuery.raw(`savepoint "${name.replaceAll('"', '""')}"`), + ); + } + async rollbackToSavepoint(connection: DatabaseConnection, name: string) { + await connection.executeQuery( + CompiledQuery.raw( + `rollback to savepoint "${name.replaceAll('"', '""')}"`, + ), + ); + } + async releaseSavepoint(connection: DatabaseConnection, name: string) { + await connection.executeQuery( + CompiledQuery.raw( + `release savepoint "${name.replaceAll('"', '""')}"`, + ), + ); + } +} + +// Remote libSQL supports separate connections. Kysely's native SQLite mutex +// would otherwise make unrelated Worker requests wait on one another's I/O. +class HttpLibsqlAdapter extends SqliteAdapter { + override get supportsMultipleConnections() { + return true; + } +} + +export class HttpLibsqlDialect extends LibsqlDialect { + constructor(private readonly options: Config) { + super(options); + } + override createAdapter() { + return new HttpLibsqlAdapter(); + } + override createDriver() { + return new HttpLibsqlDriver(() => createClient(this.options)); + } +} diff --git a/apps/web/lib/logger.ts b/apps/demo/lib/logger.ts similarity index 100% rename from apps/web/lib/logger.ts rename to apps/demo/lib/logger.ts diff --git a/apps/web/lib/onboarding.ts b/apps/demo/lib/onboarding.ts similarity index 100% rename from apps/web/lib/onboarding.ts rename to apps/demo/lib/onboarding.ts diff --git a/apps/web/lib/plugin-navigation.ts b/apps/demo/lib/plugin-navigation.ts similarity index 100% rename from apps/web/lib/plugin-navigation.ts rename to apps/demo/lib/plugin-navigation.ts diff --git a/apps/demo/lib/public-site-config.ts b/apps/demo/lib/public-site-config.ts new file mode 100644 index 000000000..313aedddf --- /dev/null +++ b/apps/demo/lib/public-site-config.ts @@ -0,0 +1,249 @@ +import type { CSSProperties } from "react"; +import type { + PublicLandingPageProps, + PublicShellLink, + PublicSiteFooterGroup, +} from "@hackkit/ui"; + +export type PublicSiteConfig = { + brand: { + name: string; + shortName: string; + description: string; + }; + event: { + name: string; + dates: string; + location: string; + timezone: string; + }; + theme: { + primary: string; + ring: string; + }; + nav: { + public: PublicShellLink[]; + participant: PublicShellLink[]; + }; + landing: Omit< + PublicLandingPageProps, + "primaryAction" | "secondaryAction" + > & { + primaryAction: PublicShellLink; + secondaryAction: PublicShellLink; + signedInAction: PublicShellLink; + }; + help: { + title: string; + description: string; + contacts: PublicShellLink[]; + resources: PublicShellLink[]; + }; + dashboard: { + primaryActions: PublicShellLink[]; + resourceLinks: PublicShellLink[]; + }; + footer: { + linkGroups: PublicSiteFooterGroup[]; + }; +}; + +export const publicSiteConfig = { + brand: { + name: "HackKit Demo", + shortName: "HackKit", + description: + "A production-ready hackathon shell for registration, event operations, and participant support.", + }, + event: { + name: "HackKit Demo Weekend", + dates: "March 21-23, 2027", + location: "San Antonio, Texas", + timezone: "America/Chicago", + }, + theme: { + primary: "221.2 83.2% 53.3%", + ring: "221.2 83.2% 53.3%", + }, + nav: { + public: [ + { label: "Schedule", href: "/schedule" }, + { label: "Help", href: "/help" }, + ], + participant: [ + { label: "Dashboard", href: "/dashboard" }, + { label: "Event Pass", href: "/pass" }, + { label: "Teams", href: "/teams" }, + { label: "RSVP", href: "/rsvp" }, + ], + }, + landing: { + eyebrow: "HackKit demo event", + title: "Everything participants need before and during event weekend.", + description: + "Register, keep your profile current, follow the public schedule, manage your event pass, and get help from the organizing team in one place.", + primaryAction: { label: "Apply now", href: "/sign-up" }, + secondaryAction: { label: "View schedule", href: "/schedule" }, + signedInAction: { label: "Open dashboard", href: "/dashboard" }, + stats: [ + { value: "48h", label: "Build window" }, + { value: "24/7", label: "Participant support" }, + { value: "1", label: "Source of truth" }, + { value: "Live", label: "Schedule updates" }, + ], + highlights: [ + { + title: "Public schedule", + description: + "Browse event programming before signing in, then open details from your dashboard during the event.", + }, + { + title: "Participant dashboard", + description: + "Jump to event pass, RSVP, team tools, settings, and day-of resources after approval.", + }, + { + title: "Organizer-ready routing", + description: + "Admin, settings, profile, and RSVP routes stay connected without exposing their internals on the public site.", + }, + ], + sections: [ + { + title: "Before the event", + description: + "Create your account, finish onboarding, update registration details, and watch for approval updates.", + }, + { + title: "During the event", + description: + "Keep your event pass handy, check the latest schedule, and find support links without digging through email.", + }, + { + title: "After launch", + description: + "App-owned content and theme tokens keep this shell adaptable for each HackKit deployment.", + }, + ], + }, + help: { + title: "Contact and help", + description: + "Need support before or during the event? Use these entry points for organizer help, technical issues, and participant resources.", + contacts: [ + { + label: "Organizer support", + href: "https://hackkit-docs.acm-utsa.workers.dev/docs/demo", + description: + "Questions about registration, approvals, travel, or event logistics.", + }, + { + label: "Report a bug", + href: "https://github.com/acmutsa/HackKitPlugin/issues/new", + description: + "File a HackKit issue for broken flows, confusing copy, or production shell polish.", + external: true, + }, + { + label: "Discord help", + href: "https://hackkit-docs.acm-utsa.workers.dev/docs/demo?subject=Discord%20help", + description: + "Ask organizers for the current Discord invite or access help.", + }, + { + label: "Emergency contact", + href: "https://hackkit-docs.acm-utsa.workers.dev/docs/demo?subject=Urgent%20event%20support", + description: + "Use for urgent safety or day-of operations issues.", + }, + ], + resources: [ + { label: "Schedule", href: "/schedule" }, + { label: "Dashboard", href: "/dashboard" }, + { label: "Settings", href: "/settings" }, + { label: "Registration", href: "/settings/registration" }, + ], + }, + dashboard: { + primaryActions: [ + { label: "Open event pass", href: "/pass" }, + { label: "View schedule", href: "/schedule" }, + { label: "Manage RSVP", href: "/rsvp" }, + ], + resourceLinks: [ + { + label: "Schedule", + href: "/schedule", + description: + "See public events and open detailed schedule pages.", + }, + { + label: "Event pass", + href: "/pass", + description: "Use your QR pass for check-in and event scans.", + }, + { + label: "Teams", + href: "/teams", + description: + "Manage team participation through the existing team route.", + }, + { + label: "Invites", + href: "/invites", + description: "Review pending team or participant invitations.", + }, + { + label: "Settings", + href: "/settings", + description: + "Update profile details and registration information.", + }, + { + label: "Survival guide", + href: "/help", + description: + "Find help contacts, logistics links, and Discord instructions.", + }, + { + label: "Discord", + href: "/help", + description: + "Get the current invite and access instructions from organizers.", + }, + { + label: "Admin console", + href: "/admin", + description: + "Organizer tools are available to authorized users.", + }, + ], + }, + footer: { + linkGroups: [ + { + title: "Event", + links: [ + { label: "Schedule", href: "/schedule" }, + { label: "Help", href: "/help" }, + { label: "Apply", href: "/sign-up" }, + ], + }, + { + title: "Participant", + links: [ + { label: "Dashboard", href: "/dashboard" }, + { label: "Event pass", href: "/pass" }, + { label: "Settings", href: "/settings" }, + ], + }, + ], + }, +} satisfies PublicSiteConfig; + +export function getPublicThemeStyle(): CSSProperties { + return { + "--primary": publicSiteConfig.theme.primary, + "--ring": publicSiteConfig.theme.ring, + } as CSSProperties; +} diff --git a/apps/demo/lib/runtime.ts b/apps/demo/lib/runtime.ts new file mode 100644 index 000000000..08224fa1c --- /dev/null +++ b/apps/demo/lib/runtime.ts @@ -0,0 +1,43 @@ +import "server-only"; + +import { + createHackkitRuntimeFromConfig, + setHackkitRuntime, +} from "@hackkit/next"; +import { appConfig } from "./app-config"; + +import { assertDemoEnvironment } from "../env"; + +let host: + | ReturnType< + typeof createHackkitRuntimeFromConfig + > + | undefined; +function getHost() { + assertDemoEnvironment(); + return (host ??= createHackkitRuntimeFromConfig({ config: appConfig })); +} +setHackkitRuntime(async () => getHost().getRuntime()); + +export async function getRuntime() { + return getHost().getRuntime(); +} + +export async function getCurrentUser() { + return (await getRuntime()).getCurrentUser(); +} + +export async function getHackkit() { + return (await getRuntime()).hackkit; +} + +export async function getPageGuards() { + return (await getRuntime()).pageGuards; +} + +export function getCoreRuntime() { + return getHost().core; +} + +export const handleHackkitRequest = (request: Request) => + getHost().handler(request); diff --git a/apps/web/lib/upload-profile-photo.ts b/apps/demo/lib/upload-profile-photo.ts similarity index 100% rename from apps/web/lib/upload-profile-photo.ts rename to apps/demo/lib/upload-profile-photo.ts diff --git a/apps/web/lib/upload-resume.ts b/apps/demo/lib/upload-resume.ts similarity index 100% rename from apps/web/lib/upload-resume.ts rename to apps/demo/lib/upload-resume.ts diff --git a/apps/web/middleware.ts b/apps/demo/middleware.ts similarity index 100% rename from apps/web/middleware.ts rename to apps/demo/middleware.ts diff --git a/apps/demo/next-env.d.ts b/apps/demo/next-env.d.ts new file mode 100644 index 000000000..100986254 --- /dev/null +++ b/apps/demo/next-env.d.ts @@ -0,0 +1,7 @@ +/// +/// +import "vinext/types/augmentations"; +import "./.next/types/routes.d.ts"; + +// NOTE: This file should not be edited +// see https://nextjs.org/docs/app/api-reference/config/typescript for more information. diff --git a/apps/demo/next.config.mjs b/apps/demo/next.config.mjs new file mode 100644 index 000000000..c4a407b7c --- /dev/null +++ b/apps/demo/next.config.mjs @@ -0,0 +1,2 @@ +/** @type {import('next').NextConfig} */ +export default {}; diff --git a/apps/demo/package.json b/apps/demo/package.json new file mode 100644 index 000000000..1499e372a --- /dev/null +++ b/apps/demo/package.json @@ -0,0 +1,72 @@ +{ + "name": "@hackkit/demo", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "plugin:sync": "hackkit plugin sync", + "db:generate": "node scripts/db.mjs generate", + "db:migrate": "node scripts/db.mjs migrate", + "db:seed": "node scripts/db.mjs seed", + "db:reset": "node scripts/db.mjs reset", + "sync": "pnpm plugin:sync", + "dev": "node scripts/compile-orm.mjs && vite dev --port 3001", + "build": "node scripts/build.mjs", + "verify": "pnpm sync && pnpm typecheck && pnpm build", + "start": "vite preview --port 3001", + "typecheck": "pnpm orm:compile && tsc -p tsconfig.typecheck.json --noEmit", + "db:status": "node scripts/db.mjs status", + "db:check": "node scripts/db.mjs check", + "db:rollback": "node scripts/db.mjs rollback", + "deploy": "pnpm build && wrangler deploy", + "deploy:check": "wrangler deploy --dry-run", + "cf:types": "wrangler types --include-runtime=false worker/env.d.ts", + "test:smoke": "playwright test", + "orm:compile": "node scripts/compile-orm.mjs", + "db:demo": "node scripts/seed.mjs", + "test:database": "node --test scripts/test-database.mjs" + }, + "dependencies": { + "@hackkit/cli": "workspace:*", + "@hackkit/config": "workspace:*", + "@hackkit/core": "workspace:*", + "@hackkit/next": "workspace:*", + "@hackkit/plugin-teams": "workspace:*", + "@hackkit/ui": "workspace:*", + "better-auth": "1.7.6", + "next": "14.2.35", + "react": "19.3.1", + "react-dom": "19.3.1", + "sonner": "^1.5.0", + "typescript": "5.9.3", + "@mikro-orm/migrations": "7.2.1", + "@mikro-orm/core": "7.2.1", + "jiti": "2.4.2", + "@next/env": "14.2.35", + "@libsql/client": "0.17.4", + "react-server-dom-webpack": "19.3.1", + "vinext": "1.2.1", + "@mikro-orm/sql": "7.2.1", + "@libsql/kysely-libsql": "0.4.1", + "kysely": "0.29.6", + "zod": "^3.25.67" + }, + "devDependencies": { + "@types/node": "22.18.6", + "@types/react": "19.3.0", + "@types/react-dom": "19.3.0", + "autoprefixer": "10.4.19", + "postcss": "8.4.39", + "tailwindcss": "3.4.6", + "tailwindcss-animate": "1.0.7", + "wrangler": "4.151.3", + "@cloudflare/workers-types": "5.20261019.1", + "@playwright/test": "1.64.1", + "vite": "8.3.4", + "@cloudflare/vite-plugin": "1.64.0", + "@vitejs/plugin-rsc": "0.5.38", + "@vitejs/plugin-react": "6.0.1", + "@mikro-orm/cli": "7.2.1", + "dotenv": "16.6.1" + } +} diff --git a/apps/demo/playwright.config.ts b/apps/demo/playwright.config.ts new file mode 100644 index 000000000..8a84ec2a3 --- /dev/null +++ b/apps/demo/playwright.config.ts @@ -0,0 +1,31 @@ +import { defineConfig } from "@playwright/test"; + +if (!process.env.DEMO_TEST_URL) + throw new Error("Set DEMO_TEST_URL to a running demo deployment."); + +export default defineConfig({ + testDir: "./tests", + fullyParallel: false, + workers: 1, + retries: 0, + timeout: 120_000, + expect: { timeout: 30_000 }, + reporter: [["list"], ["html", { open: "never" }]], + webServer: process.env.CI + ? { + command: "pnpm start > .wrangler/ci-server.log 2>&1", + url: process.env.DEMO_TEST_URL, + reuseExistingServer: false, + timeout: 60_000, + gracefulShutdown: { signal: "SIGTERM", timeout: 5_000 }, + } + : undefined, + use: { + baseURL: process.env.DEMO_TEST_URL, + actionTimeout: 20_000, + navigationTimeout: 30_000, + browserName: "chromium", + screenshot: "only-on-failure", + trace: "retain-on-failure", + }, +}); diff --git a/apps/web/postcss.config.cjs b/apps/demo/postcss.config.cjs similarity index 100% rename from apps/web/postcss.config.cjs rename to apps/demo/postcss.config.cjs diff --git a/apps/demo/scripts/build.mjs b/apps/demo/scripts/build.mjs new file mode 100644 index 000000000..c2662cb42 --- /dev/null +++ b/apps/demo/scripts/build.mjs @@ -0,0 +1,20 @@ +import { chmodSync, existsSync, readdirSync } from "node:fs"; +import { spawnSync } from "node:child_process"; + +for (const args of [ + ["scripts/compile-orm.mjs"], + ["node_modules/vite/bin/vite.js", "build"], +]) { + const result = spawnSync(process.execPath, args, { stdio: "inherit" }); + if (result.error) throw result.error; + if (result.status !== 0) process.exit(result.status ?? 1); +} + +// Cloudflare copies local variables into the preview output. Keep that ignored +// file private. Turbo excludes credential files and never caches this build. +if (existsSync("dist/server")) { + for (const file of readdirSync("dist/server")) { + if (/^\.(dev\.vars|env)(\.|$)/.test(file)) + chmodSync(`dist/server/${file}`, 0o600); + } +} diff --git a/apps/demo/scripts/compile-orm.mjs b/apps/demo/scripts/compile-orm.mjs new file mode 100644 index 000000000..aa4c4b514 --- /dev/null +++ b/apps/demo/scripts/compile-orm.mjs @@ -0,0 +1,24 @@ +import { spawnSync } from "node:child_process"; +// Compiling entity functions never needs credentials or a database connection. +const result = spawnSync( + process.execPath, + [ + "node_modules/@mikro-orm/cli/cli.js", + "compile", + "--config", + "scripts/orm.config.mjs", + "--out", + "lib/generated/orm-functions.js", + ], + { + stdio: "inherit", + env: { + ...process.env, + TURSO_DATABASE_URL: "http://127.0.0.1:9", + TURSO_AUTH_TOKEN: "metadata-only", + BETTER_AUTH_SECRET: "build-only-secret-no-network-or-runtime-use", + }, + }, +); +if (result.error) throw result.error; +process.exitCode = result.status ?? 1; diff --git a/apps/demo/scripts/database.ts b/apps/demo/scripts/database.ts new file mode 100644 index 000000000..8a665c219 --- /dev/null +++ b/apps/demo/scripts/database.ts @@ -0,0 +1,120 @@ +import { resolve } from "node:path"; +import { resolveHackkitConfig, type HackkitConfig } from "@hackkit/config"; +import { createOrmOptions, seedRoles } from "@hackkit/core"; +import { MikroORM } from "@mikro-orm/core"; +import { createJiti } from "jiti"; + +const jiti = createJiti(import.meta.url); + +export type DatabaseCommand = + | { command: "generate"; name?: string; blank?: boolean } + | { command: "status" | "check" | "seed" | "reset" } + | { command: "migrate"; to?: string } + | { command: "rollback"; to?: string }; + +/** Runs an explicit database operation. App startup never calls this function. */ +export async function runDatabaseCommand( + input: HackkitConfig, + request: DatabaseCommand, +) { + if (request.command === "reset") + throw new Error( + "Reset is disabled for the shared Turso demo database.", + ); + const config = resolveHackkitConfig({ + ...input, + database: { + ...input.database, + migrations: { + path: resolve("db/migrations/sqlite"), + emit: "ts", + snapshot: true, + snapshotName: ".snapshot", + snapshotOnMigrate: false, + }, + }, + }); + const orm = await MikroORM.init({ + ...createOrmOptions(config), + dynamicImportProvider: (id) => jiti.import(id), + }); + try { + // MikroORM 7 initializes lazily. History operations must establish a + // connection first: native getPending can otherwise report all files + // as pending when a snapshot exists but the database is unreachable. + if (request.command !== "generate") await orm.connect(); + const migrator = orm.migrator; + switch (request.command) { + case "generate": { + const migration = await migrator.create( + undefined, + request.blank, + false, + request.name, + ); + return { + command: "generate" as const, + migration, + // SQLite table rebuilding also contains DROP TABLE. Review the + // complete migration; this list is a warning, not an SQL parser. + destructiveStatements: migration.diff.up.filter((sql) => + /\bdrop\s+(?:table|column|schema)\b|\btruncate\b/i.test( + sql, + ), + ), + }; + } + case "status": + case "check": { + // Native migrator history calls ensure its tracking table exists. + const executed = await migrator.getExecuted(); + const pending = await migrator.getPending(); + if (request.command === "status") + return { command: "status" as const, executed, pending }; + // checkSchema compares entities to the committed snapshot. Separately + // compare the live database so a clean snapshot cannot hide drift. + const needsMigration = await migrator.checkSchema(); + const schemaSql = await orm.schema.getUpdateSchemaSQL({ + wrap: false, + }); + return { + command: "check" as const, + executed, + pending, + needsMigration, + schemaSql, + ok: + !needsMigration && + pending.length === 0 && + schemaSql.trim() === "", + }; + } + case "migrate": + return { + command: "migrate" as const, + migrations: await migrator.up( + request.to ? { to: request.to } : undefined, + ), + }; + case "rollback": + return { + command: "rollback" as const, + migrations: await migrator.down( + request.to + ? { to: request.to === "0" ? 0 : request.to } + : undefined, + ), + }; + case "seed": + return { + command: "seed" as const, + seed: await seedRoles({ + em: orm.em.fork(), + roles: config.seedRoles, + }), + }; + } + } finally { + await orm.close(); + } +} diff --git a/apps/demo/scripts/db.mjs b/apps/demo/scripts/db.mjs new file mode 100644 index 000000000..62cd93d81 --- /dev/null +++ b/apps/demo/scripts/db.mjs @@ -0,0 +1,62 @@ +import { parseArgs } from "node:util"; +import { writeFile } from "node:fs/promises"; +import { fileURLToPath } from "node:url"; +import { createJiti } from "jiti"; +import { config as loadEnv } from "dotenv"; +import { loadHackkitConfig } from "@hackkit/config"; + +loadEnv({ path: ".dev.vars", quiet: true }); +const jiti = createJiti(fileURLToPath(import.meta.url)); +const { runDatabaseCommand } = await jiti.import("./database.ts"); +const { assertDemoEnvironment } = await jiti.import("../env.ts"); +assertDemoEnvironment(); + +try { + const { values, positionals } = parseArgs({ + allowPositionals: true, + options: { + config: { type: "string", default: "hackkit.config.ts" }, + output: { type: "string" }, + name: { type: "string" }, + blank: { type: "boolean", default: false }, + to: { type: "string" }, + }, + }); + const [command] = positionals; + const commands = [ + "generate", + "status", + "check", + "migrate", + "rollback", + "reset", + "seed", + ]; + if (positionals.length !== 1 || !commands.includes(command)) { + throw new Error(`Choose a database command: ${commands.join(", ")}.`); + } + if ((values.name !== undefined || values.blank) && command !== "generate") { + throw new Error("--name and --blank are only supported by generate."); + } + if (values.to !== undefined && !["migrate", "rollback"].includes(command)) { + throw new Error("--to is only supported by migrate and rollback."); + } + if (values.to !== undefined && !values.to.trim()) { + throw new Error("--to requires a migration name (or 0 for rollback)."); + } + const config = await loadHackkitConfig(values.config); + const result = await runDatabaseCommand(config, { command, ...values }); + // Native drivers can write diagnostics to stdout. A separate result file + // gives release jobs structured output without parsing their logs. + if (values.output) { + await writeFile(values.output, `${JSON.stringify(result, null, 2)}\n`); + } + console.log(JSON.stringify(result, null, 2)); + if (result.command === "check" && !result.ok) process.exitCode = 1; +} catch (error) { + // Print the operation's error without printing the config or connection URL. + console.error( + error instanceof Error ? error.message : "Database command failed.", + ); + process.exitCode = 1; +} diff --git a/apps/demo/scripts/orm.config.mjs b/apps/demo/scripts/orm.config.mjs new file mode 100644 index 000000000..7ae139587 --- /dev/null +++ b/apps/demo/scripts/orm.config.mjs @@ -0,0 +1,5 @@ +import { createJiti } from "jiti"; +import { createOrmOptions } from "@hackkit/core"; +const jiti = createJiti(import.meta.url); +const { default: config } = await jiti.import("../hackkit.config.ts"); +export default { ...createOrmOptions(config), connect: false }; diff --git a/apps/demo/scripts/seed.mjs b/apps/demo/scripts/seed.mjs new file mode 100644 index 000000000..f326f06c7 --- /dev/null +++ b/apps/demo/scripts/seed.mjs @@ -0,0 +1,9 @@ +import { config as loadEnv } from "dotenv"; +import { createJiti } from "jiti"; +loadEnv({ path: ".dev.vars", quiet: true }); +const jiti = createJiti(import.meta.url); +const { assertDemoEnvironment } = await jiti.import("../env.ts"); +assertDemoEnvironment(); +const { seedDemo } = await jiti.import("./seed.ts"); +await seedDemo(); +console.log("Demo setup complete. Existing users were retained."); diff --git a/apps/demo/scripts/seed.ts b/apps/demo/scripts/seed.ts new file mode 100644 index 000000000..b95072554 --- /dev/null +++ b/apps/demo/scripts/seed.ts @@ -0,0 +1,101 @@ +import { initializeHackkit, HackKitUser, CoreSetting } from "@hackkit/core"; +import { RequestContext } from "@mikro-orm/core"; +import { resolveHackkitConfig } from "@hackkit/config"; +import config from "../hackkit.config"; +import { demoAccounts, demoPassword } from "../lib/demo-accounts"; +import { runDatabaseCommand } from "./database"; + +/** Explicit setup for an empty demo database. Never replaces existing users. */ +export async function seedDemo() { + await runDatabaseCommand(config, { command: "migrate" }); + await runDatabaseCommand(config, { command: "seed" }); + const core = await initializeHackkit(resolveHackkitConfig(config)); + try { + const scope = core.createScope(); + await RequestContext.create(scope.em, async () => { + if (await scope.em.count(HackKitUser, {})) return; + const users = new Map(); + for (const key of Object.keys( + demoAccounts, + ) as (keyof typeof demoAccounts)[]) { + const account = demoAccounts[key]; + const { user } = await core.auth.api.signUpEmail({ + body: { + name: account.name, + email: account.email, + password: demoPassword, + }, + }); + users.set(key, user.id); + if (key === "newcomer") continue; + await scope.hackkit.users.claimHackTag({ + authId: user.id, + hackTag: account.tag, + }); + await scope.hackkit.userData.completeUserData({ + authId: user.id, + age: 21, + gender: "prefer_not_to_answer", + race: "prefer_not_to_answer", + ethnicity: "prefer_not_to_answer", + shirtSize: "m", + dietaryRestrictions: ["none"], + hasAcceptedMLHCodeOfConduct: true, + hasSharedDataWithMLH: true, + isEmailable: false, + }); + await scope.hackkit.hackers.registerHacker({ + userId: user.id, + university: "University of Texas at San Antonio", + major: "Computer Science", + levelOfStudy: "Senior", + hackathonsAttended: 2, + softwareExperience: "Intermediate", + }); + } + const organizerId = users.get("organizer")!; + await scope.em.nativeUpdate( + HackKitUser, + { id: organizerId }, + { roleId: "core.owner", isApproved: true }, + ); + scope.em.clear(); + await scope.hackkit.settings.set({ + actorAuthId: organizerId, + key: CoreSetting.RsvpOpen, + value: true, + }); + for (const [title, type, hour, location] of [ + ["Opening ceremony", "ceremony", 9, "Main auditorium"], + [ + "Build your first HackKit plugin", + "workshop", + 11, + "Workshop room A", + ], + ["Lunch and team matching", "meal", 12, "Student union"], + ["Project showcase", "ceremony", 17, "Main auditorium"], + ] as const) { + await scope.hackkit.events.createEvent({ + actorAuthId: organizerId, + title, + type, + location, + description: + "A fictional event for exploring HackKit. Try editing this event in the organizer console.", + startTime: new Date(Date.UTC(2027, 2, 21, hour + 5)), + endTime: new Date(Date.UTC(2027, 2, 21, hour + 6)), + host: "Demo organizers", + hidden: false, + }); + } + await scope.hackkit.plugins.teams.createTeam({ + actorAuthId: users.get("teammate")!, + name: "Weekend Builders", + tag: "weekend-builders", + }); + }); + } finally { + await core.orm.close(); + } +} diff --git a/apps/demo/scripts/test-database.mjs b/apps/demo/scripts/test-database.mjs new file mode 100644 index 000000000..1c2489a60 --- /dev/null +++ b/apps/demo/scripts/test-database.mjs @@ -0,0 +1,56 @@ +import assert from "node:assert/strict"; +import { randomUUID } from "node:crypto"; +import { test } from "node:test"; +import { config as loadEnv } from "dotenv"; +import { createJiti } from "jiti"; +import { Kysely, sql } from "kysely"; + +loadEnv({ path: ".dev.vars", quiet: true }); +const jiti = createJiti(import.meta.url); +const { HttpLibsqlDialect } = await jiti.import( + "../lib/http-libsql-dialect.ts", +); +const { env, assertDemoEnvironment } = await jiti.import("../env.ts"); +assertDemoEnvironment(); + +test("HTTP libSQL isolates connections and rolls back nested and outer transactions", async () => { + const dialect = new HttpLibsqlDialect({ + url: env.databaseUrl, + authToken: env.tursoAuthToken, + }); + assert.equal(dialect.createAdapter().supportsMultipleConnections, true); + const db = new Kysely({ dialect }); + const key = `demo-transaction-test:${randomUUID()}`; + try { + const transaction = await db.startTransaction().execute(); + try { + await sql`insert into core_operation_lock (key, token) values (${key}, ${"outer"})`.execute( + transaction, + ); + const nested = await transaction.savepoint("nested").execute(); + await sql`update core_operation_lock set token = ${"inner"} where key = ${key}`.execute( + nested, + ); + await nested.rollbackToSavepoint("nested").execute(); + const result = + await sql`select token from core_operation_lock where key = ${key}`.execute( + nested, + ); + assert.equal(result.rows[0].token, "outer"); + await nested.releaseSavepoint("nested").execute(); + } finally { + await transaction.rollback().execute(); + } + const result = + await sql`select token from core_operation_lock where key = ${key}`.execute( + db, + ); + assert.equal(result.rows.length, 0); + const reads = await Promise.all( + Array.from({ length: 4 }, () => sql`select 1 as value`.execute(db)), + ); + assert.ok(reads.every((result) => result.rows[0].value === 1)); + } finally { + await db.destroy(); + } +}); diff --git a/apps/demo/tailwind.config.ts b/apps/demo/tailwind.config.ts new file mode 100644 index 000000000..cff883b9f --- /dev/null +++ b/apps/demo/tailwind.config.ts @@ -0,0 +1,60 @@ +import type { Config } from "tailwindcss"; + +const config = { + darkMode: ["class"], + content: [ + "./app/**/*.{ts,tsx}", + "./components/**/*.{ts,tsx}", + "./lib/**/*.{ts,tsx}", + "../../packages/ui/src/**/*.{ts,tsx}", + "../../packages/plugin-*/src/**/*.{ts,tsx}", + "../../packages/plugin-*/app/**/*.{ts,tsx}", + ], + theme: { + extend: { + colors: { + border: "hsl(var(--border))", + input: "hsl(var(--input))", + ring: "hsl(var(--ring))", + background: "hsl(var(--background))", + foreground: "hsl(var(--foreground))", + primary: { + DEFAULT: "hsl(var(--primary))", + foreground: "hsl(var(--primary-foreground))", + }, + secondary: { + DEFAULT: "hsl(var(--secondary))", + foreground: "hsl(var(--secondary-foreground))", + }, + destructive: { + DEFAULT: "hsl(var(--destructive))", + foreground: "hsl(var(--destructive-foreground))", + }, + muted: { + DEFAULT: "hsl(var(--muted))", + foreground: "hsl(var(--muted-foreground))", + }, + accent: { + DEFAULT: "hsl(var(--accent))", + foreground: "hsl(var(--accent-foreground))", + }, + popover: { + DEFAULT: "hsl(var(--popover))", + foreground: "hsl(var(--popover-foreground))", + }, + card: { + DEFAULT: "hsl(var(--card))", + foreground: "hsl(var(--card-foreground))", + }, + }, + borderRadius: { + lg: "var(--radius)", + md: "calc(var(--radius) - 2px)", + sm: "calc(var(--radius) - 4px)", + }, + }, + }, + plugins: [require("tailwindcss-animate")], +} satisfies Config; + +export default config; diff --git a/apps/demo/tests/demo.spec.ts b/apps/demo/tests/demo.spec.ts new file mode 100644 index 000000000..7b7b60e7b --- /dev/null +++ b/apps/demo/tests/demo.spec.ts @@ -0,0 +1,235 @@ +import { test, expect } from "@playwright/test"; +import { z } from "zod"; +import { demoPassword } from "../lib/demo-accounts"; + +const sessionSchema = z.object({ + user: z.object({ email: z.string().email() }), +}); +const uploadTargetSchema = z.object({ + uploadUrl: z.string().url(), + storedFileReference: z.string(), +}); + +test("launcher opens the participant, organizer, and onboarding experiences", async ({ + page, +}) => { + await page.goto("/"); + await expect( + page.getByRole("heading", { + name: "A hackathon, from application to check-in.", + }), + ).toBeVisible(); + await page + .getByRole("button", { name: "Explore as a participant" }) + .click(); + await expect(page).toHaveURL(/\/dashboard$/); + await page.goto("/teams"); + await expect( + page.getByRole("heading", { name: "Your team" }).first(), + ).toBeVisible(); + await page.goto("/"); + await page.getByRole("button", { name: "Explore as an organizer" }).click(); + await expect(page).toHaveURL(/\/admin$/); + await page.goto("/admin/users"); + await expect(page.getByText("Taylor Morgan").first()).toBeVisible(); + await page.goto("/schedule"); + await expect( + page.getByText("Build your first HackKit plugin").first(), + ).toBeVisible(); + await page.goto("/"); + await page.getByRole("button", { name: "Try registration" }).click(); + await expect(page).toHaveURL(/\/onboarding\/hacktag$/); + const tag = `wk${crypto.randomUUID().replaceAll("-", "").slice(0, 16)}`; + const session = sessionSchema.parse( + await (await page.request.get("/api/auth/get-session")).json(), + ); + await page.getByLabel("HackTag", { exact: true }).fill(tag); + await page.getByRole("button", { name: "Claim HackTag" }).click(); + await expect(page).toHaveURL(/\/onboarding\/user-data$/); + await page.getByLabel("Age", { exact: true }).fill("22"); + for (const [label, option] of [ + ["Gender", "Prefer not to answer"], + ["Race", "Prefer not to answer"], + ["Ethnicity", "Prefer not to answer"], + ["Shirt size", "Medium"], + ["Country of residence", "United States"], + ]) { + await page.getByRole("combobox", { name: label, exact: true }).click(); + await page.getByRole("option", { name: option, exact: true }).click(); + } + await page + .getByRole("checkbox", { name: "No dietary restrictions", exact: true }) + .check(); + await page + .getByRole("checkbox", { + name: "I have read and agree to the MLH Code of Conduct.", + }) + .check(); + await page.getByRole("checkbox", { name: /I authorize sharing/ }).check(); + await page + .getByRole("checkbox", { name: /I agree to receive email/ }) + .check(); + await page.getByRole("button", { name: "Save user data" }).click(); + await expect(page).toHaveURL(/\/onboarding\/hacker$/); + for (const [label, option] of [ + ["University", "University of Texas at San Antonio"], + ["Major", "Computer Science"], + ["Level of study", "Freshman"], + ["Software experience", "Beginner"], + ]) { + await page.getByRole("combobox", { name: label, exact: true }).click(); + await page.getByRole("option", { name: option, exact: true }).click(); + } + await page.getByLabel("Hackathons attended", { exact: true }).fill("0"); + await page.getByLabel("Resume (optional, PDF)").setInputFiles({ + name: "fictional-resume.pdf", + mimeType: "application/pdf", + buffer: Buffer.from("%PDF-1.4 fictional browser upload"), + }); + const uploadRegistration = page.waitForResponse( + (response) => + response.url().includes("/api/files/register") && + response.request().method() === "POST", + ); + await page.getByRole("button", { name: "Complete registration" }).click(); + await expect(page).toHaveURL(/\/dashboard$/); + const upload = uploadTargetSchema.parse( + await (await uploadRegistration).json(), + ); + const ownerRead = await page.request.get(upload.storedFileReference); + expect(ownerRead.status()).toBe(200); + expect(await ownerRead.text()).toContain("fictional browser upload"); + await page.getByRole("button", { name: "Open account menu" }).click(); + await page.getByRole("menuitem", { name: "Log out" }).click(); + await expect(page).toHaveURL(/\/sign-in$/); + await page.getByLabel("Email", { exact: true }).fill(session.user.email); + await page.getByLabel("Password", { exact: true }).fill(demoPassword); + await page.getByRole("button", { name: "Sign in", exact: true }).click(); + await expect(page).toHaveURL(/\/$/); + await page.goto("/settings/registration"); + await expect( + page.getByRole("combobox", { name: "University", exact: true }), + ).toContainText("University of Texas at San Antonio"); +}); + +test("Worker sessions stay independent and private R2 uploads enforce ownership", async ({ + browser, + baseURL, +}) => { + const participant = await browser.newContext({ baseURL }); + const teammate = await browser.newContext({ baseURL }); + const organizer = await browser.newContext({ baseURL }); + const anonymous = await browser.newContext({ baseURL }); + const contexts = [participant, teammate, organizer, anonymous]; + const headers = { origin: baseURL! }; + try { + for (const [context, email] of [ + [participant, "alex@example.com"], + [teammate, "taylor@example.com"], + [organizer, "sam@example.com"], + ] as const) { + const login = await context.request.post( + "/api/auth/sign-in/email", + { + headers, + data: { email, password: demoPassword }, + timeout: 20_000, + }, + ); + expect(login.status()).toBe(200); + } + // Repeated, concurrent requests catch HTTP clients retaining another + // Worker invocation's stream state. + for (let round = 0; round < 2; round++) { + const sessions = await Promise.all( + [participant, teammate].map((context) => + context.request.get("/api/auth/get-session", { + timeout: 20_000, + }), + ), + ); + const users = await Promise.all( + sessions.map(async (response) => { + expect(response.status()).toBe(200); + return sessionSchema.parse(await response.json()).user + .email; + }), + ); + expect(users).toEqual(["alex@example.com", "taylor@example.com"]); + } + const blocked = await participant.request.post( + "/api/hackkit/settings/list", + { headers }, + ); + expect(blocked.status()).toBe(403); + const protectedPage = await anonymous.request.get("/admin", { + maxRedirects: 0, + }); + expect(protectedPage.status()).toBe(307); + expect(protectedPage.headers().location).toContain("/sign-in"); + const anonymousUpload = await anonymous.request.post( + "/api/files/register", + { + headers, + data: { location: "profile-photos", fileName: "sample.png" }, + }, + ); + expect(anonymousUpload.status()).toBe(401); + for (const location of ["profile-photos", "resumes"] as const) { + const registration = await organizer.request.post( + "/api/files/register", + { + headers, + data: { + location, + fileName: + location === "resumes" + ? "sample.pdf" + : "sample.png", + }, + }, + ); + expect(registration.status()).toBe(200); + const target = uploadTargetSchema.parse(await registration.json()); + const upload = await organizer.request.put(target.uploadUrl, { + headers: { + ...headers, + "content-type": + location === "resumes" + ? "application/pdf" + : "image/png", + }, + data: Buffer.from( + location === "resumes" + ? "%PDF-1.4 fictional resume" + : "fictional profile photo", + ), + }); + expect(upload.status()).toBe(204); + const spoof = await participant.request.put(target.uploadUrl, { + headers, + data: "overwrite", + }); + expect(spoof.status()).toBe(403); + const read = await organizer.request.get( + target.storedFileReference, + ); + expect(read.status()).toBe(200); + expect(await read.text()).toContain("fictional"); + const anonymousRead = await anonymous.request.get( + target.storedFileReference, + ); + expect(anonymousRead.status()).toBe( + location === "resumes" ? 401 : 200, + ); + if (location === "resumes") { + const participantRead = await participant.request.get( + target.storedFileReference, + ); + expect(participantRead.status()).toBe(401); + } + } + } finally { + await Promise.all(contexts.map((context) => context.close())); + } +}); diff --git a/apps/demo/tsconfig.json b/apps/demo/tsconfig.json new file mode 100644 index 000000000..b1063234e --- /dev/null +++ b/apps/demo/tsconfig.json @@ -0,0 +1,44 @@ +{ + "compilerOptions": { + "target": "ESNext", + "lib": [ + "dom", + "dom.iterable", + "esnext" + ], + "allowJs": true, + "skipLibCheck": true, + "strict": true, + "noEmit": true, + "esModuleInterop": true, + "module": "esnext", + "moduleResolution": "bundler", + "resolveJsonModule": true, + "isolatedModules": true, + "jsx": "preserve", + "incremental": true, + "plugins": [ + { + "name": "next" + } + ], + "paths": { + "@/*": [ + "./*" + ] + }, + "types": [ + "node", + "@cloudflare/workers-types" + ] + }, + "include": [ + "next-env.d.ts", + "**/*.ts", + "**/*.tsx" + ], + "exclude": [ + "node_modules", + "dist" + ] +} diff --git a/apps/demo/tsconfig.typecheck.json b/apps/demo/tsconfig.typecheck.json new file mode 100644 index 000000000..0daf0c4fd --- /dev/null +++ b/apps/demo/tsconfig.typecheck.json @@ -0,0 +1,22 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "paths": { + "@/*": [ + "./*" + ], + "react": [ + "./node_modules/@types/react/index.d.ts" + ], + "react/*": [ + "./node_modules/@types/react/*" + ], + "react-dom": [ + "./node_modules/@types/react-dom/index.d.ts" + ], + "react-dom/*": [ + "./node_modules/@types/react-dom/*" + ] + } + } +} diff --git a/apps/demo/vite.config.ts b/apps/demo/vite.config.ts new file mode 100644 index 000000000..2003b30b5 --- /dev/null +++ b/apps/demo/vite.config.ts @@ -0,0 +1,21 @@ +import { defineConfig } from "vite"; +import vinext from "vinext"; +import { cloudflare } from "@cloudflare/vite-plugin"; + +export default defineConfig({ + plugins: [ + vinext(), + cloudflare({ + viteEnvironment: { name: "rsc", childEnvironments: ["ssr"] }, + }), + ], + resolve: { + dedupe: [ + "react", + "react-dom", + "react-server-dom-webpack", + "@mikro-orm/core", + "kysely", + ], + }, +}); diff --git a/apps/demo/worker/env.d.ts b/apps/demo/worker/env.d.ts new file mode 100644 index 000000000..2a52f5431 --- /dev/null +++ b/apps/demo/worker/env.d.ts @@ -0,0 +1,43 @@ +/* eslint-disable */ +// Generated by Wrangler by running `wrangler types --include-runtime=false worker/env.d.ts` (hash: 26abef5bcb8c811327312c7f4cc02a6b) +interface __BaseEnv_Env { + DEMO_UPLOADS: R2Bucket; + TURSO_DATABASE_URL: string; + TURSO_AUTH_TOKEN: string; + BETTER_AUTH_SECRET: string; + BETTER_AUTH_URL: string; +} +declare namespace Cloudflare { + interface Env extends __BaseEnv_Env {} +} +interface Env extends __BaseEnv_Env {} +type StringifyValues> = { + [Binding in keyof EnvType]: EnvType[Binding] extends string ? EnvType[Binding] : string; +}; +declare namespace NodeJS { + interface ProcessEnv extends StringifyValues> {} +} +declare module "*.txt" { + const value: string; + export default value; +} +declare module "*.html" { + const value: string; + export default value; +} +declare module "*.sql" { + const value: string; + export default value; +} +declare module "*.bin" { + const value: ArrayBuffer; + export default value; +} +declare module "*.wasm" { + const value: WebAssembly.Module; + export default value; +} +declare module "*.wasm?module" { + const value: WebAssembly.Module; + export default value; +} \ No newline at end of file diff --git a/apps/demo/wrangler.jsonc b/apps/demo/wrangler.jsonc new file mode 100644 index 000000000..af350b618 --- /dev/null +++ b/apps/demo/wrangler.jsonc @@ -0,0 +1,15 @@ +{ + "$schema": "node_modules/wrangler/config-schema.json", + "name": "hackkit-demo", + "account_id": "cdc7630e53b468f56a4453af71a58ade", + "main": "vinext/server/app-router-entry", + "compatibility_date": "2026-10-19", + "compatibility_flags": ["nodejs_compat"], + "workers_dev": true, + "observability": { "enabled": true }, + "vars": { "BETTER_AUTH_URL": "https://hackkit-demo.acm-utsa.workers.dev" }, + "assets": { "not_found_handling": "none" }, + "r2_buckets": [ + { "binding": "DEMO_UPLOADS", "bucket_name": "hackkit-demo-uploads" }, + ], +} diff --git a/apps/docs/.gitignore b/apps/docs/.gitignore new file mode 100644 index 000000000..9e429e498 --- /dev/null +++ b/apps/docs/.gitignore @@ -0,0 +1,26 @@ +# deps +/node_modules + +# generated content +.source + +# test & build +/coverage +/.next/ +/out/ +/build +*.tsbuildinfo + +# misc +.DS_Store +*.pem +/.pnp +.pnp.js +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# others +.env*.local +.vercel +next-env.d.ts \ No newline at end of file diff --git a/apps/docs/README.md b/apps/docs/README.md new file mode 100644 index 000000000..1882f5c3f --- /dev/null +++ b/apps/docs/README.md @@ -0,0 +1,16 @@ +# HackKit documentation + +Fumadocs MDX with local search, a documentation sidebar, dark mode, and static export. Source pages live in `content/docs`. Generated MDX output and `out` are ignored. + +From the repository root: + +- `corepack pnpm dev:docs`: develop at http://localhost:3002. +- `corepack pnpm build:docs`: export the complete site to `apps/docs/out`. +- `corepack pnpm --filter @hackkit/docs typecheck`: generate route types and check TypeScript. +- `corepack pnpm deploy:docs`: build and publish static assets to ACM UTSA's `hackkit-docs` Worker. + +No environment variables, database, or runtime secrets are required. Wrangler pins the ACM UTSA account. Verify the signed-in identity before deployment. The Worker is independent of ACM's existing `docs` Worker. + +Public URL: https://hackkit-docs.acm-utsa.workers.dev. The site's demo link targets the separate `hackkit-demo` deployment. + +The docs use Next.js static export rather than a Workers SSR adapter. Fumadocs' generated search index and Markdown endpoints are exported as files. No Next.js server runs in production. This app has its own current Fumadocs/Next/React/Tailwind dependencies; the template versions remain unchanged. diff --git a/apps/docs/app/(home)/layout.tsx b/apps/docs/app/(home)/layout.tsx new file mode 100644 index 000000000..5959b87d9 --- /dev/null +++ b/apps/docs/app/(home)/layout.tsx @@ -0,0 +1,6 @@ +import { HomeLayout } from "fumadocs-ui/layouts/home"; +import { baseOptions } from "@/lib/layout.shared"; + +export default function Layout({ children }: LayoutProps<"/">) { + return {children}; +} diff --git a/apps/docs/app/(home)/page.tsx b/apps/docs/app/(home)/page.tsx new file mode 100644 index 000000000..c6b279761 --- /dev/null +++ b/apps/docs/app/(home)/page.tsx @@ -0,0 +1,76 @@ +import Link from "next/link"; +import { BookOpen, Puzzle, Terminal, ArrowRight } from "lucide-react"; + +export default function HomePage() { + return ( +
+
+ Open source hackathon software +
+

+ Your event. +
+ Your HackKit. +

+

+ Build a hackathon portal around your event. Start with + registration and profiles, then add teams, event operations, and + the integrations you need. +

+
+ + Get started + + + Explore the demo + +
+
+ {[ + { + icon: Terminal, + title: "Runnable templates", + description: + "Choose minimal Core registration or the full example. Run either locally with the workspace.", + href: "/docs/templates", + }, + { + icon: Puzzle, + title: "A shared Core, optional plugins", + description: + "Keep domain rules and permissions in Core. Configure features and pages in your application.", + href: "/docs/architecture", + }, + { + icon: BookOpen, + title: "Operate with confidence", + description: + "Use reviewed migrations, explicit roles, and integration checks against the actual templates.", + href: "/docs/testing", + }, + ].map(({ icon: Icon, title, description, href }) => ( + + +

{title}

+

+ {description} +

+ + ))} +
+
+ ); +} diff --git a/apps/docs/app/api/search/route.ts b/apps/docs/app/api/search/route.ts new file mode 100644 index 000000000..6aab6e1dc --- /dev/null +++ b/apps/docs/app/api/search/route.ts @@ -0,0 +1,9 @@ +import { source } from "@/lib/source"; +import { createFromSource } from "fumadocs-core/search/server"; + +export const revalidate = false; + +export const { staticGET: GET } = createFromSource(source, { + // https://docs.orama.com/docs/orama-js/supported-languages + language: "english", +}); diff --git a/apps/docs/app/docs/[[...slug]]/page.tsx b/apps/docs/app/docs/[[...slug]]/page.tsx new file mode 100644 index 000000000..fb04b6d6a --- /dev/null +++ b/apps/docs/app/docs/[[...slug]]/page.tsx @@ -0,0 +1,64 @@ +import { source } from "@/lib/source"; +import { + DocsBody, + DocsDescription, + DocsPage, + DocsTitle, + MarkdownCopyButton, + ViewOptionsPopover, +} from "fumadocs-ui/layouts/docs/page"; +import { notFound } from "next/navigation"; +import { getMDXComponents } from "@/components/mdx"; +import type { Metadata } from "next"; +import { createRelativeLink } from "fumadocs-ui/mdx"; +import { getPageImageUrl, getPageMarkdownUrl } from "@/lib/shared"; + +export default async function Page(props: PageProps<"/docs/[[...slug]]">) { + const params = await props.params; + const page = source.getPage(params.slug); + if (!page) notFound(); + + const MDX = page.data.body; + const markdownUrl = getPageMarkdownUrl(page).url; + + return ( + + {page.data.title} + + {page.data.description} + +
+ + +
+ + + +
+ ); +} + +export async function generateStaticParams() { + return source.generateParams(); +} + +export async function generateMetadata( + props: PageProps<"/docs/[[...slug]]">, +): Promise { + const params = await props.params; + const page = source.getPage(params.slug); + if (!page) notFound(); + + return { + title: page.data.title, + description: page.data.description, + openGraph: { + images: getPageImageUrl(page).url, + }, + }; +} diff --git a/apps/docs/app/docs/layout.tsx b/apps/docs/app/docs/layout.tsx new file mode 100644 index 000000000..b162e3594 --- /dev/null +++ b/apps/docs/app/docs/layout.tsx @@ -0,0 +1,11 @@ +import { source } from "@/lib/source"; +import { DocsLayout } from "fumadocs-ui/layouts/docs"; +import { baseOptions } from "@/lib/layout.shared"; + +export default function Layout({ children }: LayoutProps<"/docs">) { + return ( + + {children} + + ); +} diff --git a/apps/docs/app/global.css b/apps/docs/app/global.css new file mode 100644 index 000000000..69090c62c --- /dev/null +++ b/apps/docs/app/global.css @@ -0,0 +1,12 @@ +@import "tailwindcss"; +@import "fumadocs-ui/css/neutral.css"; +@import "fumadocs-ui/css/preset.css"; + +html { + scrollbar-gutter: stable; +} + +html > body[data-scroll-locked] { + margin-right: 0px !important; + --removed-body-scroll-bar-size: 0px !important; +} diff --git a/apps/docs/app/layout.tsx b/apps/docs/app/layout.tsx new file mode 100644 index 000000000..336aa033f --- /dev/null +++ b/apps/docs/app/layout.tsx @@ -0,0 +1,18 @@ +import { Provider } from "@/components/provider"; +import "./global.css"; + +export const metadata = { + title: { default: "HackKit documentation", template: "%s | HackKit" }, + description: + "Build and operate a hackathon with HackKit. Runnable templates, authentication, registration, plugins, and event operations.", +}; + +export default function Layout({ children }: LayoutProps<"/">) { + return ( + + + {children} + + + ); +} diff --git a/apps/docs/app/llms-full.txt/route.ts b/apps/docs/app/llms-full.txt/route.ts new file mode 100644 index 000000000..92f8382ef --- /dev/null +++ b/apps/docs/app/llms-full.txt/route.ts @@ -0,0 +1,7 @@ +import { docsLlms } from "@/lib/source"; + +export const revalidate = false; + +export async function GET() { + return new Response(await docsLlms.full()); +} diff --git a/apps/docs/app/llms.mdx/docs/[[...slug]]/route.ts b/apps/docs/app/llms.mdx/docs/[[...slug]]/route.ts new file mode 100644 index 000000000..3770c523e --- /dev/null +++ b/apps/docs/app/llms.mdx/docs/[[...slug]]/route.ts @@ -0,0 +1,27 @@ +import { docsLlms, source } from "@/lib/source"; +import { getPageMarkdownUrl } from "@/lib/shared"; +import { notFound } from "next/navigation"; + +export const revalidate = false; + +export async function GET( + _req: Request, + { params }: RouteContext<"/llms.mdx/docs/[[...slug]]">, +) { + const { slug } = await params; + // remove the appended "content.md" + const page = source.getPage(slug?.slice(0, -1)); + if (!page) notFound(); + + return new Response(await docsLlms.page(page), { + headers: { + "Content-Type": "text/markdown", + }, + }); +} + +export function generateStaticParams() { + return source.getPages().map((page) => ({ + slug: getPageMarkdownUrl(page).segments, + })); +} diff --git a/apps/docs/app/llms.txt/route.ts b/apps/docs/app/llms.txt/route.ts new file mode 100644 index 000000000..e8017f6f8 --- /dev/null +++ b/apps/docs/app/llms.txt/route.ts @@ -0,0 +1,7 @@ +import { docsLlms } from "@/lib/source"; + +export const revalidate = false; + +export async function GET() { + return new Response(await docsLlms.index()); +} diff --git a/apps/docs/app/og/docs/[...slug]/route.tsx b/apps/docs/app/og/docs/[...slug]/route.tsx new file mode 100644 index 000000000..66f6bad8b --- /dev/null +++ b/apps/docs/app/og/docs/[...slug]/route.tsx @@ -0,0 +1,28 @@ +import { source } from "@/lib/source"; +import { notFound } from "next/navigation"; +import { generateOGImage } from "fumadocs-ui/og"; +import { appName, getPageImageUrl } from "@/lib/shared"; + +export const revalidate = false; + +export async function GET( + _req: Request, + { params }: RouteContext<"/og/docs/[...slug]">, +) { + const { slug } = await params; + const page = source.getPage(slug.slice(0, -1)); + if (!page) notFound(); + + return generateOGImage({ + title: page.data.title, + description: page.data.description, + site: appName, + }); +} + +export function generateStaticParams() { + return source.getPages().map((page) => ({ + lang: page.locale, + slug: getPageImageUrl(page).segments, + })); +} diff --git a/apps/docs/components/mdx.tsx b/apps/docs/components/mdx.tsx new file mode 100644 index 000000000..a154b4f33 --- /dev/null +++ b/apps/docs/components/mdx.tsx @@ -0,0 +1,15 @@ +import defaultMdxComponents from "fumadocs-ui/mdx"; +import type { MDXComponents } from "mdx/types"; + +export function getMDXComponents(components?: MDXComponents) { + return { + ...defaultMdxComponents, + ...components, + } satisfies MDXComponents; +} + +export const useMDXComponents = getMDXComponents; + +declare global { + type MDXProvidedComponents = ReturnType; +} diff --git a/apps/docs/components/provider.tsx b/apps/docs/components/provider.tsx new file mode 100644 index 000000000..3ae060d5c --- /dev/null +++ b/apps/docs/components/provider.tsx @@ -0,0 +1,8 @@ +"use client"; +import SearchDialog from "@/components/search"; +import { RootProvider } from "fumadocs-ui/provider/next"; +import { type ReactNode } from "react"; + +export function Provider({ children }: { children: ReactNode }) { + return {children}; +} diff --git a/apps/docs/components/search.tsx b/apps/docs/components/search.tsx new file mode 100644 index 000000000..03f92d0ec --- /dev/null +++ b/apps/docs/components/search.tsx @@ -0,0 +1,35 @@ +"use client"; +import { + SearchDialog, + SearchDialogClose, + SearchDialogContent, + SearchDialogHeader, + SearchDialogIcon, + SearchDialogInput, + SearchDialogList, + SearchDialogOverlay, + type SharedProps, +} from "fumadocs-ui/components/dialog/search"; +import { useStaticSearch } from "fumadocs-core/search/client"; +import { useI18n } from "fumadocs-ui/contexts/i18n"; + +export default function DefaultSearchDialog(props: SharedProps) { + const { locale } = useI18n(); // (optional) for i18n + const search = useStaticSearch({ + locale, + }); + + return ( + + + + + + + + + + + + ); +} diff --git a/apps/docs/content/docs/administration.mdx b/apps/docs/content/docs/administration.mdx new file mode 100644 index 000000000..e211d2a3d --- /dev/null +++ b/apps/docs/content/docs/administration.mdx @@ -0,0 +1,20 @@ +--- +title: "Administration" +description: "Bootstrap an owner explicitly, then manage access through the console." +--- + +Creating an account does not grant organizer access. `db:seed` creates roles but never automatically assigns an owner. + +For a real installation, create the intended account, verify its canonical Core user ID, and use a controlled administrative database operation to assign the seeded `core.owner` role to that ID. Keep this operation outside public application routes. The template README describes this bootstrap boundary. + +Once bootstrapped, an owner can open `/admin`, inspect users, manage roles and settings, and export participant data. Full also provides event administration, check-in, and scanner pages. + +## Registration policy + +Settings control whether registration is open, whether approval is required, registration limits, and event capacity. Guards route incomplete accounts back to onboarding. Approval-pending and suspended accounts have dedicated states. Core checks these policies on the server. + +Use a separate participant account to confirm permissions after changing roles. Hiding an admin navigation link does not replace permission checks. + +## Demo access + +The public demo seeds a fictional organizer through an explicit database command. This is a demo-specific bootstrap operation. It does not add automatic owner assignment to either template. diff --git a/apps/docs/content/docs/architecture.mdx b/apps/docs/content/docs/architecture.mdx new file mode 100644 index 000000000..5a796da11 --- /dev/null +++ b/apps/docs/content/docs/architecture.mdx @@ -0,0 +1,27 @@ +--- +title: "Architecture" +description: "Core owns rules. Applications own presentation and deployment." +--- + +The repository separates libraries, runnable examples, integration tests, and deployed applications. + +| Directory | Responsibility | +| ------------------- | ------------------------------------------------------------------------------- | +| `packages/core` | Domain rules, permissions, native entities, Better Auth mapping, HTTP contracts | +| `packages/next` | Next.js request context, handlers, guards, runtime integration | +| `packages/ui` | Reusable React forms and views | +| `packages/plugin-*` | Optional domain features and their contracts | +| `templates` | Runnable minimal and full workspace examples | +| `e2e` | Real database, production HTTP, and browser checks | +| `apps/demo` | Public demonstration on Workers | +| `apps/docs` | This Fumadocs site | + +## Request lifecycle + +The application initializes shared database connections and authentication once. Each execution creates a scoped entity manager and HackKit instance. Authentication identifies the canonical Core user. Core APIs enforce permissions and policy. HTTP handlers derive the actor from the session, rather than accepting a privileged actor supplied by a browser. + +The Next integration binds this runtime to route handlers and server-rendered pages. Browser code uses the typed HackKit HTTP client. Do not import a database driver, server runtime, or secret-bearing config into a client component. + +## Data ownership + +A Better Auth user ID is the Core user ID. Roles grant explicit permissions. A team is owned by its plugin; Core does not require Teams to register a participant. Adding a plugin can change the application registry and therefore its migrations. diff --git a/apps/docs/content/docs/configuration.mdx b/apps/docs/content/docs/configuration.mdx new file mode 100644 index 000000000..d3a55f3ef --- /dev/null +++ b/apps/docs/content/docs/configuration.mdx @@ -0,0 +1,22 @@ +--- +title: "Configuration" +description: "Keep event configuration and credentials inside the application." +--- + +`hackkit.config.ts` declares the database driver, Better Auth options, seed roles, blob adapter, registration options, event types, and plugins. The application's `env.ts` validates environment variables before the runtime starts. + +## Minimal + +Local defaults use SQLite and local uploads. In production, set an explicit application URL and a random `BETTER_AUTH_SECRET` of at least 32 characters. SQLite and uploads require persistent disk storage. An ephemeral serverless filesystem will lose them. + +## Full + +The full example keeps stricter production requirements: an explicit application URL and authentication secret, S3 configuration, and the Discord bot integration settings. Its `.env.example` separates local defaults, required production variables, and optional integrations. + +Email defaults to no external delivery. Enable Resend or SMTP only when you have configured that provider. OAuth credentials must be provided as matching client ID and secret pairs. + +## Secrets + +Use each application's `.env.example` as the variable reference. Keep actual credentials in ignored local files or the hosting provider's secret storage. Never put secrets in `NEXT_PUBLIC_*` variables; those values can reach the browser. + +Restart or redeploy after changing configuration. Do not copy a developer database or uploads into a demo deployment. diff --git a/apps/docs/content/docs/database.mdx b/apps/docs/content/docs/database.mdx new file mode 100644 index 000000000..8a9ac251f --- /dev/null +++ b/apps/docs/content/docs/database.mdx @@ -0,0 +1,31 @@ +--- +title: "Database operations" +description: "Use reviewed migrations and explicit administrative commands." +--- + +Core uses MikroORM's native entity registry. Migration files and snapshots belong to the application because its plugin registry determines its schema. + +## Routine commands + +From the repository root, `corepack pnpm db:migrate` and `corepack pnpm db:seed` target full. Seed creates configured roles and does not assign an owner. + +For minimal, select its package explicitly: + +```sh +corepack pnpm --filter @hackkit/template-nextjs-minimal db:migrate +corepack pnpm --filter @hackkit/template-nextjs-minimal db:seed +corepack pnpm --filter @hackkit/template-nextjs-minimal db:status +corepack pnpm --filter @hackkit/template-nextjs-minimal db:check +``` + +`db:status` reports executed and pending migrations. `db:check` verifies migration history, entity/snapshot agreement, and live schema drift. + +## Change the schema + +After changing registered entities, run `db:generate` in the selected application. Review every generated statement and the snapshot before committing. Test the upgrade against existing data as well as a fresh database. + +`db:rollback` rolls back the most recent migration. Review the down migration and take a backup first. `db:reset` drops local SQLite data and is restricted to development and test environments; it is not a production recovery tool. + +## Drivers + +Full supports SQLite, libSQL, PostgreSQL, and MySQL. Integration coverage includes both local and HTTP libSQL. Minimal intentionally uses SQLite. Each template has its own migrations. Do not copy full's plugin tables into minimal. diff --git a/apps/docs/content/docs/demo.mdx b/apps/docs/content/docs/demo.mdx new file mode 100644 index 000000000..46f75985a --- /dev/null +++ b/apps/docs/content/docs/demo.mdx @@ -0,0 +1,32 @@ +--- +title: "Interactive demo" +description: "Explore HackKit with fictional accounts and shared sample data." +--- + +[Open the live demo](https://hackkit-demo.acm-utsa.workers.dev). + +The application lives in `apps/demo`. It uses the same Core, Next integration, UI, and Teams packages as the full workspace example. Vinext runs it on Cloudflare Workers, with Turso for application data and private R2 storage for uploads. + +The launcher offers a registered participant and an organizer. **Try registration** creates a new fictional account for onboarding. The organizer can inspect users, roles, settings, and events. Seeded fictional people and schedule entries make these screens useful immediately. + +## Local demo + +Copy `apps/demo/.dev.vars.example` to `apps/demo/.dev.vars`. Supply your demo Turso URL, Turso token, and an authentication secret of at least 32 characters. Keep the local application URL as `http://localhost:3001`. + +Build workspace libraries, then run the demo's explicit database setup: + +```sh +corepack pnpm exec turbo run build --filter=@hackkit/demo^... +corepack pnpm --filter @hackkit/demo plugin:sync +corepack pnpm --filter @hackkit/demo db:migrate +corepack pnpm --filter @hackkit/demo db:demo +corepack pnpm dev:demo +``` + +Open [localhost:3001](http://localhost:3001). Workerd uses the configured Turso database and local R2 emulation. Use a separate development database when you need isolated changes. Database setup never runs inside a request. + +## Hosted behavior + +The demo shares persistent data between visitors. Changes to sample accounts, teams, and settings are visible to other visitors. Use fictional information only. Demo account passwords are public by design. Email delivery, OAuth, and Discord synchronization are disabled. + +Uploads pass through authenticated application routes to a private R2 bucket. Resume access retains HackKit's owner and organizer permission checks. Profile photos can be viewed publicly. diff --git a/apps/docs/content/docs/deployment.mdx b/apps/docs/content/docs/deployment.mdx new file mode 100644 index 000000000..9b76d2015 --- /dev/null +++ b/apps/docs/content/docs/deployment.mdx @@ -0,0 +1,37 @@ +--- +title: "Deployment" +description: "Deploy the documentation and interactive demo to Cloudflare." +--- + +## Account selection + +Run Wrangler's `whoami` command in the application directory and verify the intended ACM account before publishing. If you belong to several accounts, set `CLOUDFLARE_ACCOUNT_ID` explicitly. Do not deploy these applications into a personal account accidentally. + +## Documentation + +`apps/docs` uses Fumadocs MDX, local search, and Next.js static export. It needs no database, secrets, or Worker runtime adapter. + +```sh +corepack pnpm deploy:docs +``` + +Wrangler uploads `apps/docs/out` as Worker static assets. `apps/docs/wrangler.jsonc` owns its Worker name and routing configuration. Custom domains can be added once their ACM zone is selected. + +## Demo + +The demo runs directly on Cloudflare Workers through Vinext. It uses Turso's HTTP client and a private R2 binding. MikroORM entity functions are compiled during the build because Workers prohibit runtime code generation. + +Put the Turso URL, Turso token, and authentication secret in the ignored `apps/demo/.dev.vars` file for local setup and database commands. See `apps/demo/.dev.vars.example` for required names. Migrate explicitly using `db:migrate`, then run `db:demo` to populate an empty demo database with fictional accounts. Existing users are retained. + +For deployment, configure `TURSO_DATABASE_URL`, `TURSO_AUTH_TOKEN`, and `BETTER_AUTH_SECRET` as Worker secrets. Use Wrangler's interactive `secret put` commands or the Cloudflare dashboard. Set `vars.BETTER_AUTH_URL` in `apps/demo/wrangler.jsonc` to the public HTTPS origin. Keep the local URL out of deployed secrets. + +The `DEMO_UPLOADS` R2 binding targets `hackkit-demo-uploads`. It requires no S3 credentials or public bucket access. Create the bucket before the first deployment if deploying to another account. + +```sh +corepack pnpm exec turbo run build --filter=@hackkit/demo^... +corepack pnpm deploy:demo +``` + +The hosted demo shares persistent Turso data and R2 uploads. Its sample organizer credentials are public. Use fictional information only. Do not connect a real event database to this demonstration. + +Run the selected application's `deploy:check` script after building to inspect packaging without publishing. Verify the launcher, participant and organizer access, onboarding, and upload permissions on the hosted URL. diff --git a/apps/docs/content/docs/getting-started.mdx b/apps/docs/content/docs/getting-started.mdx new file mode 100644 index 000000000..42c2f2bff --- /dev/null +++ b/apps/docs/content/docs/getting-started.mdx @@ -0,0 +1,38 @@ +--- +title: "Getting started" +description: "Run the minimal workspace example with SQLite and local uploads." +--- + +## Prerequisites + +Use Node.js 22.17 or newer and the repository-pinned pnpm 12.15.0 through Corepack. Start from the repository root. + +```sh +corepack enable +corepack pnpm install +corepack pnpm exec turbo run build --filter='./packages/*' +``` + +## Configure the minimal template + +```sh +cp templates/nextjs-minimal/.env.example templates/nextjs-minimal/.env +corepack pnpm --filter @hackkit/template-nextjs-minimal plugin:sync +corepack pnpm --filter @hackkit/template-nextjs-minimal db:migrate +corepack pnpm --filter @hackkit/template-nextjs-minimal db:seed +corepack pnpm dev:minimal +``` + +Open [localhost:3000](http://localhost:3000). Create an account and complete HackTag, user data, and hacker registration. No cloud credentials are needed for local development. + +The committed `.env.example` documents the variables. The local `.env` is empty until you configure it and is ignored by Git. + +## Run the full template + +Repeat the setup using `templates/nextjs-full`, the package filter `@hackkit/template-nextjs-full`, and `corepack pnpm dev:full`. Run one template at a time on port 3000. + +Root `db:*` commands target the full template. Use an explicit package filter when working with minimal. Each template stores its own SQLite database and uploads in its own `.data` directory. + +## Next steps + +Read [configuration](/docs/configuration), [database operations](/docs/database), and [owner access](/docs/administration). New accounts never become owners automatically. diff --git a/apps/docs/content/docs/index.mdx b/apps/docs/content/docs/index.mdx new file mode 100644 index 000000000..b1ccd2227 --- /dev/null +++ b/apps/docs/content/docs/index.mdx @@ -0,0 +1,25 @@ +--- +title: "Introduction" +description: "Hackathon software you can adapt to your event." +--- + +HackKit provides authentication, registration, participant profiles, permissions, event operations, and optional plugins. Applications own their pages and configuration. Core owns the domain rules and database model. + +Start with a runnable workspace example. Use **minimal** for Core registration and basic administration. Use **full** when you also want Teams, Discord, email adapters, schedules, RSVP, and event passes. + + + + Install dependencies and start a local application. + + + Compare the two workspace examples. + + + Learn where configuration, permissions, and HTTP handlers belong. + + + Explore a fictional event as a participant or organizer. + + + +The packages are private workspace packages. A standalone installer and published package distribution are a separate milestone. There is no supported `hackkit init` command yet. diff --git a/apps/docs/content/docs/meta.json b/apps/docs/content/docs/meta.json new file mode 100644 index 000000000..545ca0448 --- /dev/null +++ b/apps/docs/content/docs/meta.json @@ -0,0 +1,16 @@ +{ + "title": "Documentation", + "pages": [ + "index", + "getting-started", + "templates", + "configuration", + "database", + "architecture", + "plugins", + "administration", + "testing", + "demo", + "deployment" + ] +} diff --git a/apps/docs/content/docs/plugins.mdx b/apps/docs/content/docs/plugins.mdx new file mode 100644 index 000000000..a9eba28a2 --- /dev/null +++ b/apps/docs/content/docs/plugins.mdx @@ -0,0 +1,30 @@ +--- +title: "Plugins" +description: "Enable optional features through the application registry." +--- + +Full demonstrates the Teams, Discord, and email notification plugins. Minimal has an empty plugin registry. + +## Synchronize after configuration changes + +```sh +corepack pnpm --filter @hackkit/template-nextjs-full plugin:sync +``` + +Synchronization updates the application-owned generated plugin files and lock information. Review those changes. Schema changes also require reviewed migrations; synchronization does not replace migration generation or execution. + +## Teams + +Participants can create teams, invite another registered participant by HackTag, and accept invitations. The plugin enforces membership rules through its APIs and typed HTTP endpoints. + +## Discord + +The Discord plugin supports verification and role synchronization. The full production example requires its bot configuration. A local or demo application can omit the provider, but must describe that limitation in its UI. + +## Email notifications + +The notification plugin queues local domain notifications and can deliver through configured providers. A missing provider must not be described as successful external delivery. Tests keep provider operations local and never send real email. + +## Client boundaries + +Import a plugin's client contract for browser calls. Keep providers, entities, and runtime setup in server code. Integration checks verify that browser bundles exclude MikroORM and other server-only dependencies. diff --git a/apps/docs/content/docs/templates.mdx b/apps/docs/content/docs/templates.mdx new file mode 100644 index 000000000..fb99abbaa --- /dev/null +++ b/apps/docs/content/docs/templates.mdx @@ -0,0 +1,23 @@ +--- +title: "Templates" +description: "Choose a starting point without changing the shared libraries." +--- + +| Capability | Minimal | Full | +| ----------------------------------------- | ------- | ----------- | +| Authentication and onboarding | Yes | Yes | +| Dashboard, profiles, registration editing | Yes | Yes | +| Users, roles, settings, CSV export | Yes | Yes | +| Local SQLite and file storage | Yes | Development | +| Teams and invitations | No | Yes | +| Discord and email adapters | No | Yes | +| Schedule, RSVP, passes, scanners | No | Yes | +| Production S3 adapter | No | Yes | + +The examples live at `templates/nextjs-minimal` and `templates/nextjs-full`. Each owns its pages, configuration, database scripts, and migrations. Neither imports the other or E2E support. + +Minimal registers no plugins. It seeds participant and owner roles with Core permissions. Full registers Teams, Discord, and email notifications, with provider choices in its configuration. + +Reuse `@hackkit/ui` components when adapting a template. Keep event-specific copy and navigation in the application. Plugins contribute their declared schemas and HTTP contracts through the registry. + +Both examples remain part of this workspace. Copying a folder outside the monorepo is not yet a supported installation flow. diff --git a/apps/docs/content/docs/testing.mdx b/apps/docs/content/docs/testing.mdx new file mode 100644 index 000000000..ab26edb1f --- /dev/null +++ b/apps/docs/content/docs/testing.mdx @@ -0,0 +1,28 @@ +--- +title: "Testing" +description: "Run package checks and integration suites against actual templates." +--- + +## Package checks + +```sh +corepack pnpm test +corepack pnpm typecheck +``` + +Focused tests live beside the libraries. Repository integration tests live in `e2e`, which runs the actual templates rather than maintaining a separate test application. + +## End-to-end checks + +```sh +corepack pnpm --filter @hackkit/e2e exec playwright install chromium +corepack pnpm test:e2e +``` + +The runner builds libraries, synchronizes plugins, checks generated-file drift, typechecks, prepares disposable build databases, and builds both templates once. Runtime fixtures use fresh databases and uploads. They do not reuse developer `.env` values or databases. + +Use `test:e2e:db`, `test:e2e:http`, or `test:e2e:browser` for a selected suite. Browser and HTTP checks use one Playwright worker, no automatic retries, and ports 33017 and 33018. An occupied port fails instead of attaching to another server. + +Database checks cover SQLite, local libSQL, PostgreSQL, MySQL, and HTTP libSQL. Unavailable external targets may skip locally; CI requires the complete matrix. Browser journeys cover onboarding, persistent accounts, redirects, approval, permissions, and organizer access. Full also exercises team invitations across sessions. + +The public demo has a separate smoke test for its launcher, seeded roles, schedule, and onboarding. It is not a replacement for template integration tests. diff --git a/apps/docs/lib/cn.ts b/apps/docs/lib/cn.ts new file mode 100644 index 000000000..fe0d16987 --- /dev/null +++ b/apps/docs/lib/cn.ts @@ -0,0 +1 @@ +export { cn } from "cn"; diff --git a/apps/docs/lib/layout.shared.tsx b/apps/docs/lib/layout.shared.tsx new file mode 100644 index 000000000..dc0b01328 --- /dev/null +++ b/apps/docs/lib/layout.shared.tsx @@ -0,0 +1,12 @@ +import type { BaseLayoutProps } from "fumadocs-ui/layouts/shared"; +import { appName, gitConfig } from "./shared"; + +export function baseOptions(): BaseLayoutProps { + return { + nav: { + // JSX supported + title: appName, + }, + githubUrl: `https://github.com/${gitConfig.user}/${gitConfig.repo}`, + }; +} diff --git a/apps/docs/lib/shared.ts b/apps/docs/lib/shared.ts new file mode 100644 index 000000000..a8532ebbb --- /dev/null +++ b/apps/docs/lib/shared.ts @@ -0,0 +1,29 @@ +import { createGetUrl } from "fumadocs-core/source"; + +export const appName = "HackKit"; +export const docsRoute = "/docs"; +export const docsImageRoute = "/og/docs"; +export const docsContentRoute = "/llms.mdx/docs"; + +// fill this with your actual GitHub info, for example: +export const gitConfig = { + user: "acmutsa", + repo: "HackKitPlugin", + branch: "dev", +}; + +const getContentUrl = createGetUrl(docsContentRoute); + +export function getPageMarkdownUrl(page: { slugs: string[]; locale?: string }) { + const segments = [...page.slugs, "content.md"]; + + return { segments, url: getContentUrl(segments, page.locale) }; +} + +const getImageUrl = createGetUrl(docsImageRoute); + +export function getPageImageUrl(page: { slugs: string[]; locale?: string }) { + const segments = [...page.slugs, "image.png"]; + + return { segments, url: getImageUrl(segments, page.locale) }; +} diff --git a/apps/docs/lib/source.ts b/apps/docs/lib/source.ts new file mode 100644 index 000000000..08932db6e --- /dev/null +++ b/apps/docs/lib/source.ts @@ -0,0 +1,30 @@ +import { llms, loader } from "fumadocs-core/source"; +import { docsContentRoute, docsImageRoute, docsRoute } from "./shared"; +import { defineDocs } from "fumadocs-mdx/macro"; +import { metaSchema, pageSchema } from "fumadocs-core/source/schema"; + +const docs = defineDocs({ + dir: "content/docs", + docs: { + schema: pageSchema, + postprocess: { + includeProcessedMarkdown: true, + }, + }, + meta: { + schema: metaSchema, + }, +}); + +// See https://fumadocs.dev/docs/headless/source-api for more info +export const source = loader({ + baseUrl: docsRoute, + source: docs.toFumadocsSource(), + plugins: [], +}); + +export const docsLlms = llms(source, { + renderPage: async (page) => `# ${page.data.title} (${page.url}) + +${await page.data.getText("processed")}`, +}); diff --git a/apps/docs/next.config.mjs b/apps/docs/next.config.mjs new file mode 100644 index 000000000..9ac496d5b --- /dev/null +++ b/apps/docs/next.config.mjs @@ -0,0 +1,11 @@ +import { createMDX } from "fumadocs-mdx/next"; + +const withMDX = createMDX(); + +/** @type {import('next').NextConfig} */ +const config = { + output: "export", + reactStrictMode: true, +}; + +export default withMDX(config); diff --git a/apps/docs/package.json b/apps/docs/package.json new file mode 100644 index 000000000..4c6848ef7 --- /dev/null +++ b/apps/docs/package.json @@ -0,0 +1,35 @@ +{ + "name": "@hackkit/docs", + "version": "0.0.0", + "private": true, + "scripts": { + "build": "next build", + "dev": "next dev -p 3002", + "start": "serve out", + "typecheck": "next typegen && tsc --noEmit", + "deploy": "pnpm build && wrangler deploy", + "deploy:check": "wrangler deploy --dry-run" + }, + "dependencies": { + "cn": "^0.5.0", + "fumadocs-core": "16.17.7", + "fumadocs-mdx": "15.4.9", + "fumadocs-ui": "npm:@fumadocs/base-ui@16.17.7", + "lucide-react": "^1.59.0", + "next": "16.4.2", + "react": "^19.3.1", + "react-dom": "^19.3.1" + }, + "devDependencies": { + "@tailwindcss/postcss": "^4.3.3", + "@types/mdx": "^2.0.14", + "@types/node": "^26.6.5", + "@types/react": "^19.3.0", + "@types/react-dom": "^19.3.0", + "postcss": "^8.5.31", + "serve": "^14.2.6", + "tailwindcss": "^4.3.3", + "typescript": "^7.0.2", + "wrangler": "4.151.3" + } +} diff --git a/apps/docs/postcss.config.mjs b/apps/docs/postcss.config.mjs new file mode 100644 index 000000000..c42f31cab --- /dev/null +++ b/apps/docs/postcss.config.mjs @@ -0,0 +1,7 @@ +const config = { + plugins: { + "@tailwindcss/postcss": {}, + }, +}; + +export default config; diff --git a/apps/docs/tsconfig.json b/apps/docs/tsconfig.json new file mode 100644 index 000000000..67086f3f1 --- /dev/null +++ b/apps/docs/tsconfig.json @@ -0,0 +1,34 @@ +{ + "compilerOptions": { + "target": "ESNext", + "lib": ["dom", "dom.iterable", "esnext"], + "allowJs": true, + "skipLibCheck": true, + "strict": true, + "forceConsistentCasingInFileNames": true, + "noEmit": true, + "esModuleInterop": true, + "module": "esnext", + "moduleResolution": "bundler", + "resolveJsonModule": true, + "isolatedModules": true, + "jsx": "react-jsx", + "incremental": true, + "paths": { + "@/*": ["./*"] + }, + "plugins": [ + { + "name": "next" + } + ] + }, + "include": [ + "next-env.d.ts", + "**/*.ts", + "**/*.tsx", + ".next/types/**/*.ts", + ".next/dev/types/**/*.ts" + ], + "exclude": ["node_modules"] +} diff --git a/apps/docs/wrangler.jsonc b/apps/docs/wrangler.jsonc new file mode 100644 index 000000000..0bac4db30 --- /dev/null +++ b/apps/docs/wrangler.jsonc @@ -0,0 +1,12 @@ +{ + "$schema": "node_modules/wrangler/config-schema.json", + "name": "hackkit-docs", + "account_id": "cdc7630e53b468f56a4453af71a58ade", + "compatibility_date": "2026-10-20", + "workers_dev": true, + "assets": { + "directory": "./out", + "html_handling": "auto-trailing-slash", + "not_found_handling": "404-page", + }, +} diff --git a/apps/web/scripts/test-db-workflow.sh b/apps/web/scripts/test-db-workflow.sh deleted file mode 100644 index e464fc62d..000000000 --- a/apps/web/scripts/test-db-workflow.sh +++ /dev/null @@ -1,54 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" -TEST_DIR="$(mktemp -d "${TMPDIR:-/tmp}/hackkit-db-workflow.XXXXXX")" -export HACKKIT_DATABASE_DIALECT=sqlite -trap 'rm -rf "$TEST_DIR"' EXIT - -cd "$ROOT" - -DATABASE_URL="file:$TEST_DIR/sync-must-not-connect.db" pnpm sync -test ! -e "$TEST_DIR/sync-must-not-connect.db" - -# Exercise the actual Node entry point, including check's nonzero exit code. -DATABASE_URL="file:$TEST_DIR/selected.db" node scripts/db.mjs status >"$TEST_DIR/status.json" -if DATABASE_URL="file:$TEST_DIR/selected.db" node scripts/db.mjs check >"$TEST_DIR/check.json"; then - echo "db:check accepted an unmigrated database" >&2 - exit 1 -fi -node --input-type=module -e ' - import assert from "node:assert/strict"; - import { readFileSync } from "node:fs"; - const status = JSON.parse(readFileSync(process.argv[1], "utf8")); - const check = JSON.parse(readFileSync(process.argv[2], "utf8")); - assert.equal(status.executed.length, 0); - assert.equal(status.pending.length, 1); - assert.equal(check.ok, false); - assert.equal(check.needsMigration, false); - assert.ok(check.schemaSql.includes("core_user")); -' "$TEST_DIR/status.json" "$TEST_DIR/check.json" - -if DATABASE_URL="libsql://remote.example.com" pnpm db:reset >/dev/null 2>&1; then - echo "db:reset accepted a remote URL" >&2 - exit 1 -fi - -printf 'leave me alone\n' >"$TEST_DIR/untouched.db" -DATABASE_URL="file:$TEST_DIR/selected.db" pnpm db:reset -DATABASE_URL="file:$TEST_DIR/selected.db" node scripts/db.mjs check >"$TEST_DIR/checked.json" - -test -f "$TEST_DIR/selected.db" -test "$(cat "$TEST_DIR/untouched.db")" = "leave me alone" - -node --input-type=module -e ' - import { MikroORM, SqliteDriver } from "@mikro-orm/sqlite"; - import { coreModels, authEntities } from "@hackkit/core"; - const orm = await MikroORM.init({driver: SqliteDriver, dbName: process.argv[1], entities: [...Object.values(coreModels), ...authEntities]}); - try { - const roles = await orm.em.fork().find(coreModels.role, {}, {orderBy: {id: "asc"}}); - if (JSON.stringify(roles.map(role => role.id)) !== JSON.stringify(["core.owner", "core.participant"])) process.exitCode = 1; - } finally { await orm.close(); } -' "$TEST_DIR/selected.db" - -echo "Database workflow isolation checks passed." diff --git a/apps/web/scripts/test-runtime.mjs b/apps/web/scripts/test-runtime.mjs deleted file mode 100644 index 75f49f799..000000000 --- a/apps/web/scripts/test-runtime.mjs +++ /dev/null @@ -1,236 +0,0 @@ -import assert from "node:assert/strict"; -import { createHackkitClient } from "@hackkit/core/http/client"; -import { spawn } from "node:child_process"; -import { once } from "node:events"; -import { mkdtemp, rm } from "node:fs/promises"; -import { tmpdir } from "node:os"; -import { join } from "node:path"; -import { fileURLToPath } from "node:url"; -import { setTimeout } from "node:timers/promises"; - -// Exercise the production build against a new disposable database on every run. -const directory = await mkdtemp(join(tmpdir(), "hackkit-http-")); -const port = 33017; -const baseURL = `http://127.0.0.1:${port}`; -const env = { - PATH: process.env.PATH, - NODE_ENV: "production", - NEXT_TELEMETRY_DISABLED: "1", - DATABASE_URL: `file:${join(directory, "web.db")}`, - HACKKIT_DATABASE_DIALECT: "sqlite", - NEXT_PUBLIC_APP_URL: baseURL, - BETTER_AUTH_URL: baseURL, - BETTER_AUTH_SECRET: "isolated-http-test-secret-with-at-least-32-characters", - HACKKIT_EMAIL_PROVIDER: "none", - HACKKIT_BLOB_ADAPTER: "s3", - HACKKIT_S3_BUCKET: "test", - HACKKIT_S3_REGION: "auto", - HACKKIT_S3_ENDPOINT: "https://example.invalid", - HACKKIT_S3_ACCESS_KEY_ID: "test", - HACKKIT_S3_SECRET_ACCESS_KEY: "test", - DISCORD_GUILD_ID: "test", - DISCORD_BOT_API_URL: "https://example.invalid", - DISCORD_INTERNAL_AUTH_KEY: "test", - DISCORD_PARTICIPANT_ROLE_ID: "test", -}; - -async function run(...args) { - const command = spawn(process.execPath, args, { env, stdio: "inherit" }); - const [code] = await once(command, "exit"); - assert.equal(code, 0, `Command failed: ${args.join(" ")}`); -} - -let server; -try { - const cli = join( - process.cwd(), - "node_modules/@hackkit/cli/bin/hackkit.mjs", - ); - await run(cli, "db", "migrate"); - await run(cli, "db", "seed"); - server = spawn( - process.execPath, - [ - fileURLToPath(import.meta.resolve("next/dist/bin/next")), - "start", - "-p", - String(port), - "-H", - "127.0.0.1", - ], - { env, stdio: "inherit" }, - ); - let ready = false; - for (let attempt = 0; attempt < 40; attempt++) { - if (server.exitCode !== null) - throw new Error("Next exited before becoming ready."); - try { - const response = await fetch(`${baseURL}/api/auth/get-session`); - ready = response.ok; - } catch { - /* Server may still be starting. */ - } - if (ready) break; - await setTimeout(250); - } - assert.ok(ready, "Next did not become ready."); - - const accounts = []; - for (const name of ["First", "Second"]) { - const response = await fetch(`${baseURL}/api/auth/sign-up/email`, { - method: "POST", - headers: { "content-type": "application/json", origin: baseURL }, - body: JSON.stringify({ - name: `HTTP ${name}`, - email: `${name.toLowerCase()}@example.com`, - password: "a sufficiently long password", - }), - }); - assert.equal(response.status, 200); - const body = await response.json(); - const cookie = response.headers - .getSetCookie() - .map((value) => value.split(";")[0]) - .join("; "); - assert.ok(cookie.includes("better-auth.session_token=")); - accounts.push({ id: body.user.id, cookie }); - } - - for (const account of accounts) { - const headers = { cookie: account.cookie }; - const session = await fetch(`${baseURL}/api/auth/get-session`, { - headers, - }).then((response) => response.json()); - assert.equal(session.user.id, account.id); - const page = await fetch(`${baseURL}/onboarding/hacktag`, { - headers, - redirect: "manual", - }); - assert.equal(page.status, 200); - assert.ok(!(await page.text()).includes("data-next-error-message")); - const forbidden = await fetch(`${baseURL}/api/admin/export`, { - headers, - }); - assert.equal(forbidden.status, 403); - } - assert.equal( - await fetch(`${baseURL}/api/auth/get-session`).then((response) => - response.json(), - ), - null, - ); - assert.equal( - (await fetch(`${baseURL}/dashboard`, { redirect: "manual" })).status, - 307, - ); - assert.equal((await fetch(`${baseURL}/api/admin/export`)).status, 401); - const client = createHackkitClient({ - baseURL: baseURL + "/api/hackkit", - }); - const callOptions = accounts.map((account) => ({ - headers: { cookie: account.cookie, origin: baseURL }, - })); - const tags = ["http-first", "http-second"]; - const claimed = await Promise.all( - accounts.map((_, index) => - client("@post/users/claim-hack-tag", { - body: { hackTag: tags[index] }, - ...callOptions[index], - }), - ), - ); - assert.deepEqual( - claimed.map((result) => result.data?.id), - accounts.map((account) => account.id), - ); - assert.equal(typeof claimed[0].data.createdAt, "string"); - const unauthenticated = await client("@post/users/claim-hack-tag", { - body: { hackTag: "anon" }, - headers: { origin: baseURL }, - }); - assert.equal(unauthenticated.error.code, "UNAUTHORIZED"); - assert.equal(unauthenticated.error.status, 401); - const forbidden = await client("@post/roles/create", { - body: { name: "Forbidden", position: 0, permissions: [] }, - ...callOptions[0], - }); - assert.equal(forbidden.error.status, 403); - const spoof = await fetch(baseURL + "/api/hackkit/users/claim-hack-tag", { - method: "POST", - headers: { - ...callOptions[0].headers, - "content-type": "application/json", - }, - body: JSON.stringify({ hackTag: "spoof", authId: accounts[1].id }), - }); - assert.equal(spoof.status, 400); - for (let index = 0; index < accounts.length; index++) { - const data = await client("@post/user-data/complete", { - body: { - age: 20, - gender: "prefer_not_to_answer", - race: "prefer_not_to_answer", - ethnicity: "prefer_not_to_answer", - shirtSize: "m", - dietaryRestrictions: ["none"], - hasAcceptedMLHCodeOfConduct: true, - hasSharedDataWithMLH: true, - isEmailable: true, - }, - ...callOptions[index], - }); - assert.equal(data.error, null, JSON.stringify(data.error)); - const registration = await client("@post/hackers/register", { - body: { - university: "Test University", - major: "CS", - levelOfStudy: "undergraduate", - hackathonsAttended: 0, - softwareExperience: "beginner", - }, - ...callOptions[index], - }); - assert.equal( - registration.error, - null, - JSON.stringify(registration.error), - ); - assert.equal(registration.data.userId, accounts[index].id); - } - const team = await client("@post/teams/create", { - body: { name: "HTTP team", tag: "http-team" }, - ...callOptions[0], - }); - assert.equal(team.error, null, JSON.stringify(team.error)); - assert.equal(team.data.ownerAuthId, accounts[0].id); - const invite = await client("@post/teams/invite", { - body: { teamId: team.data.id, hackTag: tags[1] }, - ...callOptions[0], - }); - assert.equal(invite.error, null, JSON.stringify(invite.error)); - const accepted = await client("@post/teams/respond-to-invite", { - body: { inviteId: invite.data.id, accept: true }, - ...callOptions[1], - }); - assert.equal(accepted.error, null, JSON.stringify(accepted.error)); - const left = await client("@post/teams/leave", callOptions[1]); - assert.deepEqual(left, { data: null, error: null }); - const ownerCannotLeave = await client("@post/teams/leave", callOptions[0]); - assert.equal(ownerCannotLeave.error.status, 422); - const discord = await client("@post/discord/confirm-verification", { - body: { code: "missing-code" }, - ...callOptions[0], - }); - assert.equal(discord.error.status, 404); - - console.log( - "Passed: HTTP signup, isolated sessions, onboarding rendering, Core and Teams path mutations, actor rejection, permissions, and Discord routing.", - ); -} finally { - if (server && server.exitCode === null) { - const exited = once(server, "exit"); - server.kill("SIGTERM"); - await exited; - } - await rm(directory, { recursive: true, force: true }); -} diff --git a/docs/guides/database-migrations.md b/docs/guides/database-migrations.md index d5cabaa52..d61aa100d 100644 --- a/docs/guides/database-migrations.md +++ b/docs/guides/database-migrations.md @@ -2,28 +2,28 @@ The application owns one ordered migration history for Core, Better Auth, installed plugins, and application entities. Core supplies native entity definitions and a shared registry. The reference app supplies runnable scripts and database-specific configuration. Package authors supply reviewed transformation SQL and upgrade instructions when their schema changes require them. -The scripts live in `apps/web/scripts/database.ts`, with `scripts/db.mjs` as the Node entry point. They use MikroORM's native migrator and its `mikro_orm_migrations` history table. They do not call the HackKit CLI. Plugin route/action synchronization continues to use the existing CLI. +The scripts live in `templates/nextjs-full/scripts/database.ts`, with `scripts/db.mjs` as the Node entry point. They use MikroORM's native migrator and its `mikro_orm_migrations` history table. They do not call the HackKit CLI. Plugin route/action synchronization continues to use the existing CLI. ## Commands Run from the repository root after installing dependencies and building workspace packages: -| Command | Behavior | -| ------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- | -| `pnpm --filter web db:generate --name describe_change` | Generates a migration and updates the target snapshot. Outputs the SQL proposal and potentially destructive statements. | -| `pnpm --filter web db:generate --name backfill --blank` | Creates a migration for authored SQL. | -| `pnpm --filter web db:status` | Lists applied and pending migrations. | -| `pnpm --filter web db:check` | Checks metadata against the snapshot, pending history, and the live schema. Exits with status 1 when any check differs. | -| `pnpm --filter web db:migrate` | Applies all pending migrations. | -| `pnpm --filter web db:migrate --to Migration20261006120000_expand` | Applies up to and including the named migration. | -| `pnpm --filter web db:rollback` | Runs the latest applied migration's `down()` method. | -| `pnpm --filter web db:rollback --to Migration20261006120000_expand` | Reverts later migrations, leaving the named migration applied. `--to 0` reverts all. | -| `pnpm --filter web db:seed` | Inserts missing configured role IDs. Existing roles and assignments remain unchanged. | -| `pnpm --filter web db:reset` | In development/tests, drops registered tables and migration history in the selected local SQLite database, then migrates and seeds. | +| Command | Behavior | +| --------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- | +| `pnpm --filter @hackkit/template-nextjs-full db:generate --name describe_change` | Generates a migration and updates the target snapshot. Outputs the SQL proposal and potentially destructive statements. | +| `pnpm --filter @hackkit/template-nextjs-full db:generate --name backfill --blank` | Creates a migration for authored SQL. | +| `pnpm --filter @hackkit/template-nextjs-full db:status` | Lists applied and pending migrations. | +| `pnpm --filter @hackkit/template-nextjs-full db:check` | Checks metadata against the snapshot, pending history, and the live schema. Exits with status 1 when any check differs. | +| `pnpm --filter @hackkit/template-nextjs-full db:migrate` | Applies all pending migrations. | +| `pnpm --filter @hackkit/template-nextjs-full db:migrate --to Migration20261006120000_expand` | Applies up to and including the named migration. | +| `pnpm --filter @hackkit/template-nextjs-full db:rollback` | Runs the latest applied migration's `down()` method. | +| `pnpm --filter @hackkit/template-nextjs-full db:rollback --to Migration20261006120000_expand` | Reverts later migrations, leaving the named migration applied. `--to 0` reverts all. | +| `pnpm --filter @hackkit/template-nextjs-full db:seed` | Inserts missing configured role IDs. Existing roles and assignments remain unchanged. | +| `pnpm --filter @hackkit/template-nextjs-full db:reset` | In development/tests, drops registered tables and migration history in the selected local SQLite database, then migrates and seeds. | Every command accepts `--config path/to/hackkit.config.ts` and optional `--output path/to/result.json`. The output file contains the command result separately from driver diagnostics; a failed `check` still writes its result and exits with status 1. The entry point loads `.env` files with Next's environment precedence before loading the config. Explicit shell environment variables take precedence. Configuration paths and relative database paths are resolved from the application directory. -The selected dialect determines the migration directory. PostgreSQL, MySQL, and SQLite have separate histories in `apps/web/db/migrations`; libSQL uses the SQLite history. Generate and test each supported history when changing a shared entity. A generated migration for one dialect is not a replacement for the other dialects' histories. +The selected dialect determines the migration directory. PostgreSQL, MySQL, and SQLite have separate histories in `templates/nextjs-full/db/migrations`; libSQL uses the SQLite history. Generate and test each supported history when changing a shared entity. A generated migration for one dialect is not a replacement for the other dialects' histories. `status` and `check` use native migration history APIs. These APIs may create the tracking table if it does not exist. They do not apply application migrations or seed data. A database connection failure is an error, not a successful status check. Generation can use a committed snapshot without connecting; without a snapshot, MikroORM needs a database for its starting schema. @@ -90,8 +90,8 @@ Reset rejects production and all non-SQLite drivers, including local libSQL. It ## Validation -`pnpm --filter web test` exercises the app scripts against SQLite/local libSQL. It checks existing-data expansion/backfill/contraction, staged migration, plugin upgrade, rollback/reapply, live drift, disabled-schema retention, destructive uninstall proposals, fresh replay, and reset/seed behavior. +`corepack pnpm test:e2e:db` exercises the app scripts against SQLite/local libSQL. It checks existing-data expansion/backfill/contraction, staged migration, plugin upgrade, rollback/reapply, live drift, disabled-schema retention, destructive uninstall proposals, fresh replay, and reset/seed behavior. -`pnpm --filter web test:db-matrix` runs the same upgrade flow after auth/domain validation on each configured target. CI requires PostgreSQL, MySQL, and HTTP libSQL URLs; missing local targets are reported as skipped. Test URLs must name empty, disposable databases. The native libSQL client can hang when repeatedly creating and destroying ORM instances in one Node process. The HTTP upgrade test uses one Node process per command, matching the utility scripts’ release-job lifecycle. Do not run a sequence of these commands inside a long-lived application process. Hosted Turso authentication/TLS and deployment-specific runtime behavior need separate validation. +`corepack pnpm test:e2e:db` runs the same upgrade flow after auth/domain validation on each configured target. CI requires PostgreSQL, MySQL, and HTTP libSQL URLs; missing local targets are reported as skipped. Test URLs must name empty, disposable databases. The native libSQL client can hang when repeatedly creating and destroying ORM instances in one Node process. The HTTP upgrade test uses one Node process per command, matching the utility scripts’ release-job lifecycle. Do not run a sequence of these commands inside a long-lived application process. Hosted Turso authentication/TLS and deployment-specific runtime behavior need separate validation. Primary reference: [MikroORM 7.2 migrations](https://mikro-orm.io/docs/migrations). diff --git a/docs/guides/next-integration.md b/docs/guides/next-integration.md index 2a2c82501..8ba60e280 100644 --- a/docs/guides/next-integration.md +++ b/docs/guides/next-integration.md @@ -1,6 +1,6 @@ # Next.js integration -HackKit uses package-owned better-call endpoints and its typed path client. `@hackkit/next` supplies Next request setup and page guards. See [its README](../../packages/next/README.md) for the interface and [the reference app](../../apps/web/README.md) for database commands. +HackKit uses package-owned better-call endpoints and its typed path client. `@hackkit/next` supplies Next request setup and page guards. See [its README](../../packages/next/README.md) for the interface and [the reference app](../../templates/nextjs-full/README.md) for database commands. | Concern | Owner | App integration | | --------------------------------------- | ------------------- | ---------------------------------------------------------- | @@ -41,4 +41,4 @@ Core endpoint definitions are grouped by domain in `packages/core/src/http/endpo ## Verification -Use the repository-pinned pnpm through `corepack pnpm`. Run package builds, typechecks, and tests, then the web production build and `corepack pnpm --filter web test:runtime`. HTTP checks use a fresh disposable SQLite database. `node tooling/check-client-bundle.mjs` bundles the provider entry and checks its inputs for recognized server implementations. +Use the repository-pinned pnpm through `corepack pnpm`. Run package builds, typechecks, and tests, then the web production build and `corepack pnpm test:e2e:http`. HTTP checks use a fresh disposable SQLite database. `node tooling/check-client-bundle.mjs` bundles the provider entry and checks its inputs for recognized server implementations. diff --git a/docs/plans/template-distribution.md b/docs/plans/template-distribution.md new file mode 100644 index 000000000..ffdfeb3f7 --- /dev/null +++ b/docs/plans/template-distribution.md @@ -0,0 +1,16 @@ +# Standalone templates and CLI initialization + +Status: deferred. Current templates are runnable workspace examples. Packages remain private. This change does not publish packages or add an init command. + +The next distribution milestone will add `hackkit init --template minimal|full`, defaulting to minimal. The command must create a complete project without overwriting an existing destination. It must not copy repository credentials, databases, uploads, build output, or test infrastructure. + +Required work: + +- Establish public package metadata, dependency versions, release versioning, and npm scope access before publication. +- Include distributable template assets with the CLI and substitute released package versions for workspace references. +- Make application scripts and Tailwind content discovery work without monorepo source paths. +- Keep each template's configuration, database commands, reviewed migrations, and setup documentation inside the generated project. +- Validate packed packages and both generated projects outside the monorepo. Verify initialization, dependency installation, plugin synchronization, migrations, seeding, typechecking, and production builds without workspace symlinks. +- Review the release artifacts before publishing. Define the first release version, registry ownership, authentication, and publishing workflow as part of that milestone. + +Acceptance requires a working fresh project from the distributed CLI for each template. An in-workspace build alone does not establish standalone readiness. diff --git a/e2e/README.md b/e2e/README.md new file mode 100644 index 000000000..f89acf35a --- /dev/null +++ b/e2e/README.md @@ -0,0 +1,37 @@ +# HackKit end-to-end validation + +Tests run the actual [full](../templates/nextjs-full/README.md) and [minimal](../templates/nextjs-minimal/README.md) templates. There is no separate test application. Package tests remain beside the libraries. + +## Commands + +From the repository root, use Node.js 22.17+ and pinned pnpm 12.15.0: + +1. Run `corepack pnpm install`. +2. Install Chromium with `corepack pnpm --filter @hackkit/e2e exec playwright install chromium`. On Linux CI, add `--with-deps`. +3. Run `corepack pnpm test:e2e`. + +Choose `test:e2e:db`, `test:e2e:http`, or `test:e2e:browser` to run a focused suite. The runner builds library dependencies, checks plugin sync for changes, typechecks templates and E2E, and checks both browser bundles. HTTP/browser suites also migrate and seed temporary build databases and build both production apps once. Runtime databases are separate from build databases. + +Stop template development servers before testing, and run one E2E invocation at a time. The fixtures use loopback ports 33017 for full and 33018 for minimal, refuse occupied ports, and never reuse an existing server. Each worker gets a new temporary database and upload directory. Application commands run from the selected template's directory using explicit test configuration. No developer database or uploads are selected. One Chromium worker runs without retries; browser sessions and accounts are independent. Each test supplies a distinct simulated proxy client IP so production authentication rate limits remain enabled without sharing one test-client bucket. + +## Coverage + +- `database`: committed migrations, auth/domain integration, schema upgrades, drift, rollback/reapply, plugin retention, concurrency, and real application command isolation. +- `http`: production cookies/sessions, access control, Core and plugin mutations, actor rejection, and JSON serialization. Playwright API tests do not launch a browser. +- `browser`: signup and complete onboarding, persisted registration, signout/signin, participant/admin guards, approval state, owner access, and full-template team invitations across sessions. + +E2E-only database helpers promote known test user IDs and configure approval. Applications expose no testing or bootstrap endpoints. Tests that change approval settings restore them in teardown. External OAuth, hosted Turso authentication/TLS, email delivery, Discord role synchronization, and S3 operations require separate deployment validation. + +## Database matrix + +SQLite and local libSQL run locally. Supply URLs for empty, disposable external databases to add: + +- `HACKKIT_TEST_POSTGRESQL_URL` +- `HACKKIT_TEST_MYSQL_URL` +- `HACKKIT_TEST_LIBSQL_URL` + +Set `HACKKIT_REQUIRE_DATABASE_MATRIX=1` to fail if any URL is missing. CI requires all five targets. The full template runs the multi-driver migration/upgrade suite; the minimal template uses its own SQLite schema. HTTP libSQL migration commands retain one Node process per operation to avoid native-client lifecycle hangs. + +## Diagnostics + +Playwright writes HTML reports to `playwright-report` and JUnit results, worker server logs, traces, and failure screenshots to `test-results`. CI uploads these artifacts on failure. Startup failures include captured server output. Child processes have timeouts and bounded shutdown; temporary runtime storage is removed after teardown. diff --git a/e2e/browser/participant.spec.ts b/e2e/browser/participant.spec.ts new file mode 100644 index 000000000..d4633c70e --- /dev/null +++ b/e2e/browser/participant.spec.ts @@ -0,0 +1,95 @@ +import { test, expect } from "../support/fixtures"; +import { + accountDetails, + signup, + completeRegistration, +} from "../support/accounts"; +import { registerThroughUI, signIn, databaseAction } from "../support/browser"; + +test("signup, onboarding, persisted registration, signout and signin", async ({ + page, +}) => { + const account = accountDetails(); + await registerThroughUI(page, account); + await expect( + page.getByRole("heading", { name: `Welcome, ${account.name}` }), + ).toBeVisible(); + await page.getByRole("button", { name: "Open account menu" }).click(); + await page.getByRole("menuitem", { name: "Log out" }).click(); + await expect(page).toHaveURL(/\/sign-in$/); + await signIn(page, account); + await page.goto("/dashboard"); + await expect(page).toHaveURL(/\/dashboard$/); + await expect(page.getByText(account.tag, { exact: true })).toBeVisible(); + await page.goto("/settings/registration"); + await expect( + page.getByRole("combobox", { name: "University", exact: true }), + ).toContainText("University of Texas at San Antonio"); +}); + +test("anonymous and incomplete accounts are redirected; participants cannot open admin pages", async ({ + app, + page, + request, +}) => { + await page.goto("/dashboard"); + await expect(page).toHaveURL(/\/sign-in(?:\?.*)?$/); + const account = await signup(request, app.baseURL); + await signIn(page, account); + await page.goto("/dashboard"); + await expect(page).toHaveURL(/\/onboarding\/hacktag$/); + await completeRegistration(app.baseURL, account); + await page.goto("/dashboard"); + await expect(page).toHaveURL(/\/dashboard$/); + const denied = await page.goto("/admin"); + expect(denied?.status()).toBe(404); + await expect( + page.getByRole("heading", { name: "Admin Overview" }), + ).not.toBeVisible(); +}); + +test("a registered participant waits for approval when approval is required", async ({ + app, + page, + request, +}) => { + const owner = await signup(request, app.baseURL); + await databaseAction(app, "promote", owner.id); + await databaseAction(app, "approval", owner.id, true); + try { + const account = await signup(request, app.baseURL); + await completeRegistration(app.baseURL, account); + await signIn(page, account); + await page.goto("/dashboard"); + await expect(page).toHaveURL(/\/i\/approval$/); + await expect( + page.getByRole("heading", { + name: "Your account is awaiting approval.", + }), + ).toBeVisible(); + } finally { + await databaseAction(app, "approval", owner.id, false); + } +}); + +test("a seeded owner can open basic administration", async ({ + app, + page, + request, +}) => { + const owner = await signup(request, app.baseURL); + await databaseAction(app, "promote", owner.id); + await signIn(page, owner); + for (const [path, heading] of [ + ["/admin", "Admin Overview"], + ["/admin/users", "Users"], + ["/admin/roles", "Roles"], + ["/admin/settings", "Hackathon Settings"], + ]) { + const response = await page.goto(path); + expect(response?.status()).toBe(200); + await expect( + page.getByRole("heading", { name: heading, exact: true }), + ).toBeVisible(); + } +}); diff --git a/e2e/browser/teams.spec.ts b/e2e/browser/teams.spec.ts new file mode 100644 index 000000000..db5ee713a --- /dev/null +++ b/e2e/browser/teams.spec.ts @@ -0,0 +1,56 @@ +import { test, expect } from "../support/fixtures"; +import { signup, completeRegistration } from "../support/accounts"; +import { signIn } from "../support/browser"; + +test("team creation, invitation and acceptance across separate sessions", async ({ + app, + browser, + request, + page, + extraHTTPHeaders, +}) => { + test.skip( + app.template.id !== "full", + "Teams is included only in the full template.", + ); + const owner = await signup(request, app.baseURL); + const teammate = await signup(request, app.baseURL); + await completeRegistration(app.baseURL, owner); + await completeRegistration(app.baseURL, teammate); + await signIn(page, owner); + await page.goto("/teams"); + const teamName = `Team ${owner.tag}`; + await page.getByLabel("Team name").fill(teamName); + await page.getByLabel("Team tag").fill(`t-${owner.tag}`); + await page + .getByRole("button", { name: "Create team", exact: true }) + .click(); + await expect(page.getByRole("heading", { name: teamName })).toBeVisible(); + await page.getByLabel("HackTag", { exact: true }).fill(teammate.tag); + await page.getByRole("button", { name: "Send invite" }).click(); + await expect(page.getByText("Invite sent.", { exact: true })).toBeVisible(); + const context = await browser.newContext({ + baseURL: app.baseURL, + extraHTTPHeaders, + }); + try { + const memberPage = await context.newPage(); + await signIn(memberPage, teammate); + await memberPage.goto("/invites"); + await memberPage + .getByRole("button", { name: "Accept", exact: true }) + .click(); + await memberPage.goto("/teams"); + await expect( + memberPage.getByRole("heading", { name: teamName }), + ).toBeVisible(); + await page.reload(); + await expect( + page + .getByRole("list", { name: "Team members" }) + .getByText(teammate.name, { exact: true }), + ).toBeVisible(); + } finally { + await context.close(); + } +}); diff --git a/apps/web/db/__tests__/database-workflow.test.ts b/e2e/database/database-workflow.test.ts similarity index 88% rename from apps/web/db/__tests__/database-workflow.test.ts rename to e2e/database/database-workflow.test.ts index 3fe8d8f61..d8b673eec 100644 --- a/apps/web/db/__tests__/database-workflow.test.ts +++ b/e2e/database/database-workflow.test.ts @@ -1,11 +1,12 @@ +import { templates } from "../support/templates.mjs"; import { mkdtemp, rm } from "node:fs/promises"; import { join } from "node:path"; import { tmpdir } from "node:os"; -import { runDatabaseCommand } from "../../scripts/database"; +import { runDatabaseCommand } from "../../templates/nextjs-full/scripts/database"; import { initializeHackkit } from "@hackkit/core"; import { SqliteDriver } from "@mikro-orm/sqlite"; import { expect, it } from "vitest"; -import appConfig from "../../hackkit.config"; +import appConfig from "../../templates/nextjs-full/hackkit.config"; it("runs Core, plugins, and Better Auth against committed app migrations", async () => { const directory = await mkdtemp(join(tmpdir(), "hackkit-web-db-")); @@ -17,7 +18,7 @@ it("runs Core, plugins, and Better Auth against committed app migrations", async dbName: join(directory, "web.db"), clientUrl: undefined, migrations: { - path: join(process.cwd(), "db/migrations/sqlite"), + path: join(templates.full.directory, "db/migrations/sqlite"), snapshotOnMigrate: false, }, }, diff --git a/apps/web/db/__tests__/dialects.test.ts b/e2e/database/dialects.test.ts similarity index 98% rename from apps/web/db/__tests__/dialects.test.ts rename to e2e/database/dialects.test.ts index 1097834fa..6f4c9d7d8 100644 --- a/apps/web/db/__tests__/dialects.test.ts +++ b/e2e/database/dialects.test.ts @@ -1,3 +1,4 @@ +import { templates } from "../support/templates.mjs"; import { mkdtemp, rm } from "node:fs/promises"; import { tmpdir } from "node:os"; import { join } from "node:path"; @@ -6,7 +7,7 @@ import { SqliteDriver } from "@mikro-orm/sqlite"; import { LibSqlDriver } from "@mikro-orm/libsql"; import { MySqlDriver } from "@mikro-orm/mysql"; import { PostgreSqlDriver } from "@mikro-orm/postgresql"; -import { runDatabaseCommand } from "../../scripts/database"; +import { runDatabaseCommand } from "../../templates/nextjs-full/scripts/database"; import { HackKitUser, AuthSession, @@ -19,7 +20,7 @@ import { } from "@hackkit/core"; import { teamsModels } from "@hackkit/plugin-teams"; import { discordModels } from "@hackkit/plugin-discord"; -import appConfig from "../../hackkit.config"; +import appConfig from "../../templates/nextjs-full/hackkit.config"; import { verifyMigrationUpgrade } from "./migration-workflow"; import { verifyProfileConcurrency } from "./profile-concurrency"; @@ -81,7 +82,7 @@ for (const target of targets) { : { clientUrl: target.url! }), migrations: { path: join( - process.cwd(), + templates.full.directory, "db/migrations", target.dialect, ), diff --git a/apps/web/db/__tests__/migration-fixture-schema.ts b/e2e/database/migration-fixture-schema.ts similarity index 100% rename from apps/web/db/__tests__/migration-fixture-schema.ts rename to e2e/database/migration-fixture-schema.ts diff --git a/apps/web/db/__tests__/migration-workflow.test.ts b/e2e/database/migration-workflow.test.ts similarity index 89% rename from apps/web/db/__tests__/migration-workflow.test.ts rename to e2e/database/migration-workflow.test.ts index 87c6492a7..29ab6fe80 100644 --- a/apps/web/db/__tests__/migration-workflow.test.ts +++ b/e2e/database/migration-workflow.test.ts @@ -1,3 +1,4 @@ +import { templates } from "../support/templates.mjs"; import { mkdtemp, rm } from "node:fs/promises"; import { tmpdir } from "node:os"; import { join } from "node:path"; @@ -6,8 +7,8 @@ import { SqliteDriver } from "@mikro-orm/sqlite"; import { LibSqlDriver } from "@mikro-orm/libsql"; import { createOrmOptions } from "@hackkit/core"; import { expect, it, vi } from "vitest"; -import appConfig from "../../hackkit.config"; -import { runDatabaseCommand } from "../../scripts/database"; +import appConfig from "../../templates/nextjs-full/hackkit.config"; +import { runDatabaseCommand } from "../../templates/nextjs-full/scripts/database"; import { verifyMigrationUpgrade } from "./migration-workflow"; for (const driver of [SqliteDriver, LibSqlDriver]) { @@ -21,7 +22,10 @@ for (const driver of [SqliteDriver, LibSqlDriver]) { driver, dbName: join(directory, "upgrade.db"), migrations: { - path: join(process.cwd(), "db/migrations/sqlite"), + path: join( + templates.full.directory, + "db/migrations/sqlite", + ), snapshotOnMigrate: false, }, }, @@ -67,7 +71,7 @@ it("limits reset to development SQLite and seeds missing roles without changing driver: SqliteDriver, dbName: join(directory, "reset.db"), migrations: { - path: join(process.cwd(), "db/migrations/sqlite"), + path: join(templates.full.directory, "db/migrations/sqlite"), snapshotOnMigrate: false, }, }, diff --git a/apps/web/db/__tests__/migration-workflow.ts b/e2e/database/migration-workflow.ts similarity index 96% rename from apps/web/db/__tests__/migration-workflow.ts rename to e2e/database/migration-workflow.ts index 350032f59..eff3a4027 100644 --- a/apps/web/db/__tests__/migration-workflow.ts +++ b/e2e/database/migration-workflow.ts @@ -1,3 +1,4 @@ +import { templates, e2eDirectory } from "../support/templates.mjs"; import { access, cp, @@ -19,7 +20,7 @@ import { expect } from "vitest"; import { runDatabaseCommand, type DatabaseCommand, -} from "../../scripts/database"; +} from "../../templates/nextjs-full/scripts/database"; import { LegacyNote, ExpandedNote, @@ -69,11 +70,11 @@ export async function verifyMigrationUpgrade( : undefined; const configPath = join(directory, "command.config.ts"); const schemaPath = join( - process.cwd(), - "db/__tests__/migration-fixture-schema.ts", + e2eDirectory, + "database/migration-fixture-schema.ts", ); await symlink( - join(process.cwd(), "node_modules"), + join(e2eDirectory, "node_modules"), join(directory, "node_modules"), "dir", ).catch((error: unknown) => { @@ -89,7 +90,7 @@ export async function verifyMigrationUpgrade( await writeFile( configPath, ` -import appConfig from ${JSON.stringify(join(process.cwd(), "hackkit.config.ts"))}; +import appConfig from ${JSON.stringify(join(templates.full.directory, "hackkit.config.ts"))}; import { LibSqlDriver } from '@mikro-orm/libsql'; import { ${noteName}, probePlugin, PriorityPluginEntry } from ${JSON.stringify(schemaPath)}; export default { @@ -129,7 +130,7 @@ export default { try { await runProcess(process.execPath, args, { - cwd: process.cwd(), + cwd: templates.full.directory, timeout: 15000, }); } catch (error) { diff --git a/apps/web/db/__tests__/profile-concurrency.ts b/e2e/database/profile-concurrency.ts similarity index 98% rename from apps/web/db/__tests__/profile-concurrency.ts rename to e2e/database/profile-concurrency.ts index bf726ba24..8fa4e529a 100644 --- a/apps/web/db/__tests__/profile-concurrency.ts +++ b/e2e/database/profile-concurrency.ts @@ -27,7 +27,7 @@ export async function verifyProfileConcurrency( runtime: HackKitRuntime, rowLocking: boolean, ) { - const ids = [crypto.randomUUID(), crypto.randomUUID()]; + const ids: string[] = [crypto.randomUUID(), crypto.randomUUID()]; const seed = runtime.createScope().em; for (const id of ids) { seed.create(HackKitUser, { diff --git a/e2e/database/templates.test.ts b/e2e/database/templates.test.ts new file mode 100644 index 000000000..a2289a99a --- /dev/null +++ b/e2e/database/templates.test.ts @@ -0,0 +1,138 @@ +import { execFile } from "node:child_process"; +import { promisify } from "node:util"; +import { mkdtemp, readFile, writeFile, access, rm } from "node:fs/promises"; +import { join } from "node:path"; +import { tmpdir } from "node:os"; +import { expect, it } from "vitest"; +import { templates, testEnvironment } from "../support/templates.mjs"; +import { loadHackkitConfig } from "@hackkit/config"; +import { initializeHackkit } from "@hackkit/core"; +import { SqliteDriver } from "@mikro-orm/sqlite"; +import { runDatabaseCommand } from "../../templates/nextjs-minimal/scripts/database"; + +const execute = promisify(execFile); +for (const template of Object.values(templates)) { + it(`${template.id}: app commands isolate storage, sync without connecting, and enforce reset restrictions`, async () => { + const directory = await mkdtemp( + join(tmpdir(), `hackkit-commands-${template.id}-`), + ); + const env = { + ...testEnvironment(template, directory), + NODE_ENV: "test", + }; + const run = (args: string[], overrides: NodeJS.ProcessEnv = {}) => + execute(process.execPath, args, { + cwd: template.directory, + env: { ...env, ...overrides }, + timeout: 30000, + }); + const command = (name: string, overrides: NodeJS.ProcessEnv = {}) => + run(["scripts/db.mjs", name], overrides); + try { + const syncDatabase = join(directory, "sync-must-not-connect.db"); + await run( + ["node_modules/@hackkit/cli/bin/hackkit.mjs", "plugin", "sync"], + { DATABASE_URL: `file:${syncDatabase}` }, + ); + await expect(access(syncDatabase)).rejects.toMatchObject({ + code: "ENOENT", + }); + const status = await command("status"); + expect(JSON.parse(status.stdout)).toMatchObject({ + executed: [], + pending: [expect.anything()], + }); + const resultPath = join(directory, "unmigrated.json"); + await expect( + run(["scripts/db.mjs", "check", "--output", resultPath]), + ).rejects.toMatchObject({ code: 1 }); + expect( + JSON.parse(await readFile(resultPath, "utf8")), + ).toMatchObject({ + ok: false, + needsMigration: false, + schemaSql: expect.stringContaining("core_user"), + }); + await expect( + command("reset", { NODE_ENV: "production" }), + ).rejects.toMatchObject({ code: 1 }); + await expect( + command("reset", { + DATABASE_URL: "libsql://remote.example.com", + }), + ).rejects.toMatchObject({ code: 1 }); + const untouched = join(directory, "untouched.db"); + await writeFile(untouched, "leave me alone\n"); + await command("reset"); + expect(JSON.parse((await command("check")).stdout)).toMatchObject({ + ok: true, + }); + expect(JSON.parse((await command("seed")).stdout)).toMatchObject({ + seed: { + insertedRoleIds: [], + skippedRoleIds: ["core.participant", "core.owner"], + }, + }); + expect(await readFile(untouched, "utf8")).toBe("leave me alone\n"); + } finally { + await rm(directory, { recursive: true, force: true }); + } + }); +} + +it("minimal: real config and committed migrations initialize Core/auth without plugins", async () => { + const directory = await mkdtemp(join(tmpdir(), "hackkit-minimal-db-")); + try { + const input = await loadHackkitConfig("hackkit.config.ts", { + cwd: templates.minimal.directory, + }); + expect(input.plugins).toEqual([]); + expect(input.seedRoles.map((role) => role.id)).toEqual([ + "core.participant", + "core.owner", + ]); + const config = { + ...input, + database: { + driver: SqliteDriver, + dbName: join(directory, "web.db"), + migrations: { + path: join( + templates.minimal.directory, + "db/migrations/sqlite", + ), + snapshotOnMigrate: false, + }, + }, + auth: { + baseURL: templates.minimal.origin, + secret: "minimal-db-secret-at-least-32-characters", + emailAndPassword: { enabled: true }, + }, + logger: { disabled: true }, + }; + await runDatabaseCommand(config, { command: "migrate" }); + await runDatabaseCommand(config, { command: "seed" }); + expect( + await runDatabaseCommand(config, { command: "check" }), + ).toMatchObject({ ok: true }); + const core = await initializeHackkit(config); + try { + const signup = await core.auth.api.signUpEmail({ + body: { + name: "Minimal", + email: "minimal@example.com", + password: "correct-horse-battery-staple", + }, + }); + expect( + await core.createScope().hackkit.users.getUser(signup.user.id), + ).toMatchObject({ email: "minimal@example.com" }); + expect(await core.orm.schema.getUpdateSchemaSQL()).toBe(""); + } finally { + await core.orm.close(); + } + } finally { + await rm(directory, { recursive: true, force: true }); + } +}); diff --git a/e2e/http/runtime.spec.ts b/e2e/http/runtime.spec.ts new file mode 100644 index 000000000..0c348838d --- /dev/null +++ b/e2e/http/runtime.spec.ts @@ -0,0 +1,215 @@ +import { test, expect } from "../support/fixtures"; +import { signup, clientFor, completeRegistration } from "../support/accounts"; + +test("production HTTP auth, request isolation, permissions, Core and plugin transport", async ({ + app, + request, +}) => { + const accounts = await Promise.all([ + signup(request, app.baseURL), + signup(request, app.baseURL), + ]); + for (const account of accounts) { + const headers = { cookie: account.cookie }; + const session = await request.get("/api/auth/get-session", { headers }); + expect(await session.json()).toMatchObject({ + user: { id: account.id }, + }); + const page = await request.get("/onboarding/hacktag", { headers }); + expect(page.status()).toBe(200); + expect(await page.text()).not.toContain("data-next-error-message"); + expect( + (await request.get("/api/admin/export", { headers })).status(), + ).toBe(403); + } + // Explicit empty cookies avoid the request fixture's signup cookie jar. + expect( + await ( + await request.get("/api/auth/get-session", { + headers: { cookie: "" }, + }) + ).json(), + ).toBeNull(); + expect( + ( + await request.get("/dashboard", { + headers: { cookie: "" }, + maxRedirects: 0, + }) + ).status(), + ).toBe(307); + expect( + ( + await request.get("/api/admin/export", { headers: { cookie: "" } }) + ).status(), + ).toBe(401); + const claimed = await Promise.all( + accounts.map((account) => + clientFor(app.baseURL, account.cookie)( + "@post/users/claim-hack-tag", + { body: { hackTag: account.tag } }, + ), + ), + ); + expect(claimed.map((result) => result.data?.id)).toEqual( + accounts.map((account) => account.id), + ); + expect(typeof claimed[0]?.data?.createdAt).toBe("string"); + expect( + ( + await clientFor(app.baseURL)("@post/users/claim-hack-tag", { + body: { hackTag: "anonymous" }, + }) + ).error, + ).toMatchObject({ code: "UNAUTHORIZED", status: 401 }); + expect( + ( + await clientFor(app.baseURL, accounts[0].cookie)( + "@post/roles/create", + { body: { name: "Forbidden", position: 0, permissions: [] } }, + ) + ).error, + ).toMatchObject({ status: 403 }); + const spoof = await request.post("/api/hackkit/users/claim-hack-tag", { + headers: { cookie: accounts[0].cookie, origin: app.baseURL }, + data: { hackTag: "spoof", authId: accounts[1].id }, + }); + expect(spoof.status()).toBe(400); + for (const account of accounts) + await completeRegistration(app.baseURL, account); + if (app.template.id === "minimal") { + for (const path of ["teams/create", "discord/confirm-verification"]) + expect( + ( + await request.post(`/api/hackkit/${path}`, { + headers: { + cookie: accounts[0].cookie, + origin: app.baseURL, + }, + data: {}, + }) + ).status(), + ).toBe(404); + return; + } + const owner = clientFor(app.baseURL, accounts[0].cookie); + const member = clientFor(app.baseURL, accounts[1].cookie); + const created = await owner("@post/teams/create", { + body: { name: "HTTP team", tag: `t-${accounts[0].tag}` }, + }); + expect(created.error).toBeNull(); + if (!created.data) throw new Error("Team creation returned no team."); + expect(created.data.ownerAuthId).toBe(accounts[0].id); + const invited = await owner("@post/teams/invite", { + body: { teamId: created.data.id, hackTag: accounts[1].tag }, + }); + expect(invited.error).toBeNull(); + if (!invited.data) throw new Error("Invitation returned no invite."); + expect( + ( + await member("@post/teams/respond-to-invite", { + body: { inviteId: invited.data.id, accept: true }, + }) + ).error, + ).toBeNull(); + expect(await member("@post/teams/leave")).toEqual({ + data: null, + error: null, + }); + expect((await owner("@post/teams/leave")).error).toMatchObject({ + status: 422, + }); + expect( + ( + await owner("@post/discord/confirm-verification", { + body: { code: "missing-code" }, + }) + ).error, + ).toMatchObject({ status: 404 }); +}); + +test("minimal local uploads roundtrip and preserve resume access checks", async ({ + app, + request, +}) => { + test.skip( + app.template.id !== "minimal", + "The full template uses S3 in production.", + ); + const account = await signup(request, app.baseURL); + const other = await signup(request, app.baseURL); + expect( + ( + await request.post("/api/files/register", { + headers: { cookie: "" }, + data: { location: "resumes", fileName: "resume.pdf" }, + }) + ).status(), + ).toBe(401); + for (const location of ["resumes", "profile-photos"]) { + const registration = await request.post("/api/files/register", { + headers: { cookie: account.cookie }, + data: { + location, + fileName: location === "resumes" ? "resume.pdf" : "photo.png", + }, + }); + expect(registration.status()).toBe(200); + const target: unknown = await registration.json(); + if ( + !target || + typeof target !== "object" || + !("uploadUrl" in target) || + typeof target.uploadUrl !== "string" || + !("storedFileReference" in target) || + typeof target.storedFileReference !== "string" + ) + throw new Error("Invalid local upload target."); + expect(new URL(target.uploadUrl).origin).toBe(app.baseURL); + const bytes = Buffer.from("E2E file upload"); + expect( + ( + await request.put(target.uploadUrl, { + headers: { cookie: "" }, + data: bytes, + }) + ).status(), + ).toBe(401); + expect( + ( + await request.put(target.uploadUrl, { + headers: { cookie: account.cookie }, + data: bytes, + }) + ).status(), + ).toBe(204); + if (location === "resumes") { + await completeRegistration( + app.baseURL, + account, + target.storedFileReference, + ); + for (const cookie of ["", other.cookie]) + expect( + ( + await request.get(target.storedFileReference, { + headers: { cookie }, + }) + ).status(), + ).toBe(401); + } else { + expect( + ( + await request.get(target.storedFileReference, { + headers: { cookie: "" }, + }) + ).status(), + ).toBe(200); + } + const viewed = await request.get(target.storedFileReference, { + headers: { cookie: account.cookie }, + }); + expect(viewed.status()).toBe(200); + expect(await viewed.body()).toEqual(bytes); + } +}); diff --git a/e2e/package.json b/e2e/package.json new file mode 100644 index 000000000..3e25307e4 --- /dev/null +++ b/e2e/package.json @@ -0,0 +1,33 @@ +{ + "name": "@hackkit/e2e", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "test": "node support/run.mjs all", + "test:db": "node support/run.mjs db", + "test:http": "node support/run.mjs http", + "test:browser": "node support/run.mjs browser", + "typecheck": "tsc --noEmit" + }, + "devDependencies": { + "@hackkit/core": "workspace:*", + "@hackkit/config": "workspace:*", + "@hackkit/cli": "workspace:*", + "@hackkit/plugin-teams": "workspace:*", + "@hackkit/plugin-discord": "workspace:*", + "@hackkit/plugin-notifications-email": "workspace:*", + "@mikro-orm/core": "7.2.1", + "@mikro-orm/sqlite": "7.2.1", + "@mikro-orm/libsql": "7.2.1", + "@mikro-orm/mysql": "7.2.1", + "@mikro-orm/postgresql": "7.2.1", + "@playwright/test": "1.64.1", + "@types/node": "22.18.6", + "esbuild": "0.25.12", + "jiti": "2.4.2", + "typescript": "5.9.3", + "vitest": "^3.2.4", + "@mikro-orm/migrations": "7.2.1" + } +} diff --git a/e2e/playwright.config.ts b/e2e/playwright.config.ts new file mode 100644 index 000000000..c9377cb80 --- /dev/null +++ b/e2e/playwright.config.ts @@ -0,0 +1,30 @@ +import { defineConfig, devices } from "@playwright/test"; +import { e2eDirectory } from "./support/templates.mjs"; + +export default defineConfig({ + testDir: e2eDirectory, + testMatch: ["http/**/*.spec.ts", "browser/**/*.spec.ts"], + outputDir: "test-results", + workers: 1, + fullyParallel: false, + forbidOnly: Boolean(process.env.CI), + retries: 0, + timeout: 60000, + expect: { timeout: 10000 }, + reporter: [ + ["list"], + ["html", { open: "never" }], + ["junit", { outputFile: "test-results/results.xml" }], + ], + use: { + ...devices["Desktop Chrome"], + trace: "retain-on-failure", + screenshot: "only-on-failure", + }, + projects: ["full", "minimal"].flatMap((template) => + ["http", "browser"].map((kind) => ({ + name: `${template}-${kind}`, + testMatch: `${kind}/**/*.spec.ts`, + })), + ), +}); diff --git a/e2e/support/accounts.ts b/e2e/support/accounts.ts new file mode 100644 index 000000000..bf8bae285 --- /dev/null +++ b/e2e/support/accounts.ts @@ -0,0 +1,96 @@ +import { randomUUID } from "node:crypto"; +import type { APIRequestContext } from "@playwright/test"; +import { expect } from "@playwright/test"; +import { createHackkitClient } from "@hackkit/core/http/client"; +import type { TeamsEndpoints } from "@hackkit/plugin-teams/client"; +import type { DiscordEndpoints } from "@hackkit/plugin-discord/client"; + +export function accountDetails() { + const tag = `h-${randomUUID().slice(0, 8)}`; + return { + name: `Hacker ${tag}`, + email: `${tag}@example.com`, + password: "correct-horse-battery-staple", + tag, + }; +} + +export async function signup(request: APIRequestContext, baseURL: string) { + const account = accountDetails(); + const response = await request.post(`${baseURL}/api/auth/sign-up/email`, { + headers: { origin: baseURL }, + data: account, + }); + expect(response.status(), await response.text()).toBe(200); + const body: unknown = await response.json(); + if ( + !body || + typeof body !== "object" || + !("user" in body) || + !body.user || + typeof body.user !== "object" || + !("id" in body.user) || + typeof body.user.id !== "string" + ) + throw new Error("Signup did not return a canonical user ID."); + const cookie = response + .headersArray() + .filter((header) => header.name.toLowerCase() === "set-cookie") + .map((header) => header.value.split(";")[0]) + .join("; "); + expect(cookie).toContain("better-auth.session_token="); + return { ...account, id: body.user.id, cookie }; +} + +export function clientFor(baseURL: string, cookie?: string) { + return createHackkitClient({ + baseURL: `${baseURL}/api/hackkit`, + headers: { origin: baseURL, ...(cookie ? { cookie } : {}) }, + }); +} + +export async function completeRegistration( + baseURL: string, + account: Awaited>, + resumeUrl?: string, +) { + const client = clientFor(baseURL, account.cookie); + expect( + ( + await client("@post/users/claim-hack-tag", { + body: { hackTag: account.tag }, + }) + ).error, + ).toBeNull(); + expect( + ( + await client("@post/user-data/complete", { + body: { + age: 20, + gender: "prefer_not_to_answer", + race: "prefer_not_to_answer", + ethnicity: "prefer_not_to_answer", + shirtSize: "m", + dietaryRestrictions: ["none"], + hasAcceptedMLHCodeOfConduct: true, + hasSharedDataWithMLH: true, + isEmailable: true, + }, + }) + ).error, + ).toBeNull(); + expect( + ( + await client("@post/hackers/register", { + body: { + university: "Test University", + major: "CS", + levelOfStudy: "undergraduate", + hackathonsAttended: 0, + softwareExperience: "beginner", + resumeUrl, + }, + }) + ).error, + ).toBeNull(); +} diff --git a/e2e/support/browser.ts b/e2e/support/browser.ts new file mode 100644 index 000000000..9eeef169c --- /dev/null +++ b/e2e/support/browser.ts @@ -0,0 +1,85 @@ +import { expect, type Page } from "@playwright/test"; +import { promisify } from "node:util"; +import { execFile } from "node:child_process"; +import { join } from "node:path"; +import { e2eDirectory } from "./templates.mjs"; +import type { startTemplate } from "./server.mjs"; +import { accountDetails } from "./accounts"; + +const execute = promisify(execFile); +export async function databaseAction( + app: Awaited>, + action: "promote" | "approval", + userId: string, + value?: boolean, +) { + await execute( + process.execPath, + [ + join(e2eDirectory, "support/database-task.mjs"), + action, + userId, + ...(value === undefined ? [] : [String(value)]), + ], + { cwd: app.template.directory, env: app.env, timeout: 30000 }, + ); +} + +export async function signIn( + page: Page, + account: ReturnType, +) { + await page.goto("/sign-in"); + await page.getByLabel("Email", { exact: true }).fill(account.email); + await page.getByLabel("Password", { exact: true }).fill(account.password); + await page.getByRole("button", { name: "Sign in", exact: true }).click(); + await expect(page).toHaveURL(/\/$/); +} + +async function select(page: Page, label: string, option: string) { + await page.getByRole("combobox", { name: label, exact: true }).click(); + await page.getByRole("option", { name: option, exact: true }).click(); +} + +/** Exercise every form through the browser instead of bypassing registration. */ +export async function registerThroughUI( + page: Page, + account: ReturnType, +) { + await page.goto("/sign-up"); + await page.getByLabel("Name", { exact: true }).fill(account.name); + await page.getByLabel("Email", { exact: true }).fill(account.email); + await page.getByLabel("Password", { exact: true }).fill(account.password); + await page.getByRole("button", { name: "Create account" }).click(); + await expect(page).toHaveURL(/\/onboarding\/hacktag$/); + await page.getByLabel("HackTag", { exact: true }).fill(account.tag); + await page.getByRole("button", { name: "Claim HackTag" }).click(); + await expect(page).toHaveURL(/\/onboarding\/user-data$/); + await page.getByLabel("Age", { exact: true }).fill("22"); + await select(page, "Gender", "Prefer not to answer"); + await select(page, "Race", "Prefer not to answer"); + await select(page, "Ethnicity", "Prefer not to answer"); + await select(page, "Shirt size", "Medium"); + await select(page, "Country of residence", "United States"); + await page + .getByRole("checkbox", { name: "No dietary restrictions", exact: true }) + .check(); + await page + .getByRole("checkbox", { + name: "I have read and agree to the MLH Code of Conduct.", + }) + .check(); + await page.getByRole("checkbox", { name: /I authorize sharing/ }).check(); + await page + .getByRole("checkbox", { name: /I agree to receive email/ }) + .check(); + await page.getByRole("button", { name: "Save user data" }).click(); + await expect(page).toHaveURL(/\/onboarding\/hacker$/); + await select(page, "University", "University of Texas at San Antonio"); + await select(page, "Major", "Computer Science"); + await select(page, "Level of study", "Freshman"); + await page.getByLabel("Hackathons attended", { exact: true }).fill("0"); + await select(page, "Software experience", "Beginner"); + await page.getByRole("button", { name: "Complete registration" }).click(); + await expect(page).toHaveURL(/\/dashboard$/); +} diff --git a/e2e/support/database-env.ts b/e2e/support/database-env.ts new file mode 100644 index 000000000..e21088041 --- /dev/null +++ b/e2e/support/database-env.ts @@ -0,0 +1,10 @@ +// Config imports are intentionally inert: each database test supplies an explicit +// disposable connection before initializing an ORM or invoking an app command. +import { testEnvironment, templates } from "./templates.mjs"; +import { join } from "node:path"; +import { tmpdir } from "node:os"; +Object.assign( + process.env, + testEnvironment(templates.full, join(tmpdir(), "hackkit-unused-config")), + { NODE_ENV: "test" }, +); diff --git a/e2e/support/database-task.mjs b/e2e/support/database-task.mjs new file mode 100644 index 000000000..448b9cd62 --- /dev/null +++ b/e2e/support/database-task.mjs @@ -0,0 +1,34 @@ +import { createJiti } from "jiti"; +import { initializeHackkit, HackKitUser, CoreSetting } from "@hackkit/core"; +import { resolve } from "node:path"; + +// This executable belongs only to E2E. Applications expose no bootstrap endpoint. +const [action, userId, value] = process.argv.slice(2); +if (!userId || !["promote", "approval"].includes(action)) + throw new Error( + "Choose promote or approval and provide a canonical test user ID.", + ); +const jiti = createJiti(import.meta.url); +const { default: config } = await jiti.import(resolve("hackkit.config.ts")); +const core = await initializeHackkit(config); +try { + const scope = core.createScope(); + if (action === "promote") { + const updated = await scope.em.nativeUpdate( + HackKitUser, + { id: userId }, + { roleId: "core.owner" }, + ); + if (updated !== 1) throw new Error("Expected one existing test user."); + } else { + if (value !== "true" && value !== "false") + throw new Error("Approval requires true or false."); + await scope.hackkit.settings.set({ + actorAuthId: userId, + key: CoreSetting.RequireApproval, + value: value === "true", + }); + } +} finally { + await core.orm.close(); +} diff --git a/e2e/support/fixtures.ts b/e2e/support/fixtures.ts new file mode 100644 index 000000000..5b3cbcccb --- /dev/null +++ b/e2e/support/fixtures.ts @@ -0,0 +1,57 @@ +import { test as base, expect } from "@playwright/test"; +import { templates } from "./templates.mjs"; +import { startTemplate } from "./server.mjs"; +import { mkdir, writeFile } from "node:fs/promises"; +import { join } from "node:path"; +import { createHash } from "node:crypto"; + +type Server = Awaited>; +export const test = base.extend<{ serverLogs: void }, { app: Server }>({ + extraHTTPHeaders: async ({}, use, testInfo) => { + // Separate simulated clients retain real production auth rate limiting. + const digest = createHash("sha256").update(testInfo.testId).digest(); + await use({ "x-forwarded-for": `198.18.${digest[0]}.${digest[1]}` }); + }, + app: [ + async ({}, use, workerInfo) => { + const template = workerInfo.project.name.startsWith("full-") + ? templates.full + : templates.minimal; + const app = await startTemplate(template); + try { + await use(app); + } finally { + try { + await mkdir(workerInfo.project.outputDir, { + recursive: true, + }); + await writeFile( + join( + workerInfo.project.outputDir, + `server-${workerInfo.workerIndex}.log`, + ), + app.logs(), + ); + } finally { + await app.close(); + } + } + }, + { scope: "worker", timeout: 90000 }, + ], + baseURL: async ({ app }, use) => { + await use(app.baseURL); + }, + serverLogs: [ + async ({ app }, use, testInfo) => { + await use(); + if (testInfo.status !== testInfo.expectedStatus) + await testInfo.attach("server.log", { + body: app.logs(), + contentType: "text/plain", + }); + }, + { auto: true }, + ], +}); +export { expect }; diff --git a/e2e/support/processes.mjs b/e2e/support/processes.mjs new file mode 100644 index 000000000..56076a521 --- /dev/null +++ b/e2e/support/processes.mjs @@ -0,0 +1,50 @@ +import { spawn } from "node:child_process"; + +/** Execute commands without a shell, with bounded lifetime and visible diagnostics. */ +export async function runCommand(command, args, options = {}) { + const child = spawn(command, args, { + cwd: options.cwd, + env: options.env ?? process.env, + stdio: "inherit", + detached: process.platform !== "win32", + }); + const timer = setTimeout(() => { + if (process.platform === "win32" || !child.pid) child.kill("SIGKILL"); + else { + try { + process.kill(-child.pid, "SIGKILL"); + } catch (error) { + if (error.code !== "ESRCH") throw error; + } + } + }, options.timeout ?? 300000); + try { + await new Promise((resolve, reject) => { + child.once("error", reject); + child.once("exit", (code, signal) => + code === 0 + ? resolve() + : reject( + new Error( + `${command} ${args.join(" ")} failed (${code ?? signal}).`, + ), + ), + ); + }); + } finally { + clearTimeout(timer); + } +} + +export async function stopServer(child) { + if (!child.pid || child.exitCode !== null || child.signalCode !== null) + return; + await new Promise((resolve) => { + const timer = setTimeout(() => child.kill("SIGKILL"), 5000); + child.once("exit", () => { + clearTimeout(timer); + resolve(); + }); + child.kill("SIGTERM"); + }); +} diff --git a/e2e/support/run.mjs b/e2e/support/run.mjs new file mode 100644 index 000000000..fc4b51681 --- /dev/null +++ b/e2e/support/run.mjs @@ -0,0 +1,100 @@ +import assert from "node:assert/strict"; +import { mkdtemp, rm, readdir, readFile } from "node:fs/promises"; +import { createHash } from "node:crypto"; +import { tmpdir } from "node:os"; +import { join, relative } from "node:path"; +import { + templates, + e2eDirectory, + repositoryRoot, + testEnvironment, +} from "./templates.mjs"; +import { runCommand } from "./processes.mjs"; + +const suite = process.argv[2] ?? "all"; +assert.ok( + ["all", "db", "http", "browser"].includes(suite), + "Choose all, db, http, or browser.", +); +const pnpm = (args, options = {}) => + runCommand("corepack", ["pnpm", ...args], { + cwd: repositoryRoot, + ...options, + }); + +async function generatedFiles(template) { + const entries = []; + async function collect(directory) { + for (const entry of await readdir(directory, { withFileTypes: true })) { + const path = join(directory, entry.name); + if (entry.isDirectory()) await collect(path); + else + entries.push([ + relative(template.directory, path), + createHash("sha256") + .update(await readFile(path)) + .digest("hex"), + ]); + } + } + await collect(join(template.directory, "app")); + entries.push([ + "hackkit.lock", + (await readFile(join(template.directory, "hackkit.lock"))).toString(), + ]); + return entries.sort(([a], [b]) => a.localeCompare(b)); +} + +await pnpm([ + "exec", + "turbo", + "run", + "build", + "--filter=@hackkit/template-nextjs-full^...", + "--filter=@hackkit/template-nextjs-minimal^...", +]); +const buildDirectory = await mkdtemp(join(tmpdir(), "hackkit-build-")); +try { + const targets = Object.values(templates).map((template) => ({ + template, + options: { + cwd: template.directory, + env: testEnvironment(template, join(buildDirectory, template.id)), + }, + })); + for (const { template, options } of targets) { + const before = await generatedFiles(template); + await pnpm(["sync"], options); + assert.deepEqual( + await generatedFiles(template), + before, + `Plugin sync changed ${template.id} generated files. Run its sync command and commit the result.`, + ); + } + for (const { options } of targets) await pnpm(["typecheck"], options); + await pnpm(["typecheck"], { cwd: e2eDirectory }); + await runCommand(process.execPath, ["tooling/check-client-bundle.mjs"], { + cwd: repositoryRoot, + }); + if (suite !== "db") { + for (const { options } of targets) { + await pnpm(["db:migrate"], options); + await pnpm(["db:seed"], options); + await pnpm(["build"], options); + } + } +} finally { + await rm(buildDirectory, { recursive: true, force: true }); +} +if (suite === "all" || suite === "db") + await pnpm(["exec", "vitest", "run"], { cwd: e2eDirectory }); +if (suite !== "db") { + const projects = ["full", "minimal"].flatMap((id) => + (suite === "all" ? ["http", "browser"] : [suite]).map( + (kind) => `--project=${id}-${kind}`, + ), + ); + await pnpm(["exec", "playwright", "test", ...projects], { + cwd: e2eDirectory, + }); +} diff --git a/e2e/support/server.mjs b/e2e/support/server.mjs new file mode 100644 index 000000000..d48e982b9 --- /dev/null +++ b/e2e/support/server.mjs @@ -0,0 +1,108 @@ +import { createRequire } from "node:module"; +import { spawn } from "node:child_process"; +import { mkdtemp, rm } from "node:fs/promises"; +import { createServer } from "node:net"; +import { join } from "node:path"; +import { tmpdir } from "node:os"; +import { setTimeout as delay } from "node:timers/promises"; +import { runCommand, stopServer } from "./processes.mjs"; +import { testEnvironment } from "./templates.mjs"; + +async function assertPortAvailable(port) { + const probe = createServer(); + await new Promise((resolve, reject) => { + probe.once("error", () => + reject( + new Error( + `E2E port ${port} is occupied. Stop that process; tests never reuse running apps.`, + ), + ), + ); + probe.listen(port, "127.0.0.1", () => probe.close(resolve)); + }); +} + +/** Start the real template build with fresh storage; never inherit developer config. */ +export async function startTemplate(template) { + await assertPortAvailable(template.port); + const directory = await mkdtemp( + join(tmpdir(), `hackkit-runtime-${template.id}-`), + ); + const env = testEnvironment(template, directory); + let server; + let output = ""; + try { + for (const command of ["migrate", "seed"]) + await runCommand(process.execPath, ["scripts/db.mjs", command], { + cwd: template.directory, + env, + timeout: 15000, + }); + const require = createRequire(join(template.directory, "package.json")); + server = spawn( + process.execPath, + [ + require.resolve("next/dist/bin/next"), + "start", + "-H", + "127.0.0.1", + "-p", + String(template.port), + ], + { cwd: template.directory, env, stdio: ["ignore", "pipe", "pipe"] }, + ); + server.stdout.on("data", (chunk) => { + output += chunk.toString(); + }); + server.stderr.on("data", (chunk) => { + output += chunk.toString(); + }); + server.once("error", (error) => { + output += error.message; + }); + let ready = false; + const deadline = Date.now() + 30000; + while (Date.now() < deadline) { + if ( + server.exitCode !== null || + server.signalCode !== null || + !server.pid + ) + throw new Error("Next exited before becoming ready."); + try { + const response = await fetch( + `${template.origin}/api/auth/get-session`, + { signal: AbortSignal.timeout(1000) }, + ); + ready = response.status === 200; + } catch { + /* Retry only while the process is starting. */ + } + if (ready) break; + await delay(250); + } + if (!ready) + throw new Error( + "Next did not become ready within the startup timeout.", + ); + const child = server; + return { + template, + directory, + env, + baseURL: template.origin, + logs: () => output, + async close() { + await stopServer(child); + await rm(directory, { recursive: true, force: true }); + }, + }; + } catch (error) { + if (server) await stopServer(server); + await rm(directory, { recursive: true, force: true }); + throw new Error( + `Failed starting ${template.id}: ${error instanceof Error ? error.message : String(error)}\n${output}`, + { cause: error }, + ); + } +} diff --git a/e2e/support/templates.mjs b/e2e/support/templates.mjs new file mode 100644 index 000000000..95941b044 --- /dev/null +++ b/e2e/support/templates.mjs @@ -0,0 +1,72 @@ +import { fileURLToPath } from "node:url"; +import { join } from "node:path"; + +export const repositoryRoot = fileURLToPath(new URL("../../", import.meta.url)); +export const e2eDirectory = join(repositoryRoot, "e2e"); +export const templates = { + full: { + id: "full", + directory: join(repositoryRoot, "templates/nextjs-full"), + packageName: "@hackkit/template-nextjs-full", + dialects: ["sqlite", "libsql", "postgresql", "mysql"], + port: 33017, + origin: "http://127.0.0.1:33017", + }, + minimal: { + id: "minimal", + directory: join(repositoryRoot, "templates/nextjs-minimal"), + packageName: "@hackkit/template-nextjs-minimal", + dialects: ["sqlite"], + port: 33018, + origin: "http://127.0.0.1:33018", + }, +}; + +/** Use explicit values so Next's dotenv loader cannot select developer services. */ +export function testEnvironment(template, directory) { + const common = { + PATH: process.env.PATH, + HOME: process.env.HOME, + TMPDIR: process.env.TMPDIR, + SystemRoot: process.env.SystemRoot, + NODE_ENV: "production", + NEXT_TELEMETRY_DISABLED: "1", + DATABASE_URL: `file:${join(directory, "web.db")}`, + HACKKIT_DATABASE_DIALECT: "sqlite", + HACKKIT_LOCAL_BLOB_BASE_DIR: join(directory, "uploads"), + NEXT_PUBLIC_APP_URL: template.origin, + BETTER_AUTH_URL: template.origin, + BETTER_AUTH_SECRET: "isolated-e2e-secret-with-at-least-32-characters", + BETTER_AUTH_TRUSTED_ORIGINS: template.origin, + }; + if (template.id === "minimal") return common; + return { + ...common, + HACKKIT_EMAIL_PROVIDER: "none", + GITHUB_CLIENT_ID: "", + GITHUB_CLIENT_SECRET: "", + GOOGLE_CLIENT_ID: "", + GOOGLE_CLIENT_SECRET: "", + TURSO_AUTH_TOKEN: "", + RESEND_API_KEY: "", + SMTP_HOST: "", + SMTP_PORT: "", + SMTP_SECURE: "false", + HACKKIT_EMAIL_FROM: "HackKit ", + HACKKIT_EMAIL_REPLY_TO: "", + SMTP_PASSWORD: "", + SMTP_USERNAME: "", + HACKKIT_BLOB_ADAPTER: template.id === "full" ? "s3" : "local", + HACKKIT_S3_BUCKET: "e2e", + HACKKIT_S3_REGION: "auto", + HACKKIT_S3_ENDPOINT: "https://example.invalid", + HACKKIT_S3_ACCESS_KEY_ID: "e2e", + HACKKIT_S3_SECRET_ACCESS_KEY: "e2e", + DISCORD_GUILD_ID: "e2e", + DISCORD_VERIFICATION_BASE_URL: template.origin, + DISCORD_PARTICIPANT_ROLE_NAME: "", + DISCORD_BOT_API_URL: "https://example.invalid", + DISCORD_INTERNAL_AUTH_KEY: "e2e", + DISCORD_PARTICIPANT_ROLE_ID: "e2e", + }; +} diff --git a/e2e/tsconfig.json b/e2e/tsconfig.json new file mode 100644 index 000000000..d82831cce --- /dev/null +++ b/e2e/tsconfig.json @@ -0,0 +1,10 @@ +{ + "compilerOptions": { + "target": "ES2022", "module": "ESNext", "moduleResolution": "bundler", + "lib": ["ES2022", "DOM"], "strict": true, "noEmit": true, + "allowJs": true, "skipLibCheck": true, "esModuleInterop": true, + "resolveJsonModule": true + }, + "include": ["**/*.ts", "support/templates.mjs"], + "exclude": ["node_modules", "test-results", "playwright-report"] +} diff --git a/e2e/vitest.config.ts b/e2e/vitest.config.ts new file mode 100644 index 000000000..86ad38a22 --- /dev/null +++ b/e2e/vitest.config.ts @@ -0,0 +1,26 @@ +import { defineConfig } from "vitest/config"; +import { + e2eDirectory, + templates, + testEnvironment, +} from "./support/templates.mjs"; +import { join } from "node:path"; +import { tmpdir } from "node:os"; + +export default defineConfig({ + test: { + root: e2eDirectory, + include: ["database/**/*.test.ts"], + setupFiles: ["./support/database-env.ts"], + fileParallelism: false, + testTimeout: 120000, + hookTimeout: 30000, + env: { + ...testEnvironment( + templates.full, + join(tmpdir(), "hackkit-unused-config"), + ), + NODE_ENV: "test", + }, + }, +}); diff --git a/package.json b/package.json index ecff63ec1..f3be83eca 100644 --- a/package.json +++ b/package.json @@ -2,36 +2,50 @@ "private": true, "scripts": { "build": "turbo run build", - "start": "turbo run start", - "dev": "turbo run dev", + "start": "turbo run start --filter=@hackkit/template-nextjs-full", + "dev": "turbo run dev --filter=@hackkit/template-nextjs-full", "lint": "turbo run lint", "preinstall": "npx only-allow pnpm", - "db:generate": "pnpm --filter=web db:generate", - "db:migrate": "pnpm --filter=web db:migrate", - "db:seed": "pnpm --filter=web db:seed", - "db:reset": "pnpm --filter=web db:reset", + "db:generate": "pnpm --filter=@hackkit/template-nextjs-full db:generate", + "db:migrate": "pnpm --filter=@hackkit/template-nextjs-full db:migrate", + "db:seed": "pnpm --filter=@hackkit/template-nextjs-full db:seed", + "db:reset": "pnpm --filter=@hackkit/template-nextjs-full db:reset", "deploy-discord:dev": "pnpm --filter=bot deploy:dev", "deploy-discord:prod": "pnpm --filter=bot deploy:prod", "format": "prettier --write .", "format-check": "prettier --check .", - "db:status": "pnpm --filter=web db:status", - "db:check": "pnpm --filter=web db:check", - "db:rollback": "pnpm --filter=web db:rollback" + "db:status": "pnpm --filter=@hackkit/template-nextjs-full db:status", + "db:check": "pnpm --filter=@hackkit/template-nextjs-full db:check", + "db:rollback": "pnpm --filter=@hackkit/template-nextjs-full db:rollback", + "dev:full": "turbo run dev --filter=@hackkit/template-nextjs-full", + "dev:minimal": "turbo run dev --filter=@hackkit/template-nextjs-minimal", + "test": "turbo run test --filter=./packages/*", + "typecheck": "turbo run typecheck", + "test:e2e": "pnpm --filter @hackkit/e2e test", + "test:e2e:db": "pnpm --filter @hackkit/e2e test:db", + "test:e2e:http": "pnpm --filter @hackkit/e2e test:http", + "test:e2e:browser": "pnpm --filter @hackkit/e2e test:browser", + "dev:demo": "turbo run dev --filter=@hackkit/demo", + "dev:docs": "pnpm --filter @hackkit/docs dev", + "build:demo": "turbo run build --filter=@hackkit/demo", + "build:docs": "pnpm --filter @hackkit/docs build", + "deploy:demo": "pnpm --filter @hackkit/demo run deploy", + "deploy:docs": "pnpm --filter @hackkit/docs run deploy" }, "devDependencies": { "@turbo/gen": "^2.0.9", "@types/node": "20.14.11", "dotenv-cli": "^7.4.2", - "eslint": "^9.7.0", + "eslint": "^10.13.0", "prettier": "^3.3.3", "turbo": "^2.0.9" }, - "packageManager": "pnpm@8.3.1+sha512.d264f6640bf4f09de7cfcc547568515bcf0613cf485a03e8ff16616fa69c4172b6f9a0a2925ee44fb060df565c9c9a8eaf061749e77af318cb77f6684a7051f3", "name": "hackkit", "dependencies": { "prettier-plugin-tailwindcss": "^0.6.5" }, "engines": { "node": ">=22.17.0" - } + }, + "packageManager": "pnpm@12.15.0" } diff --git a/packages/config/src/__tests__/config.test.ts b/packages/config/src/__tests__/config.test.ts index 628afcb54..0937b5a7c 100644 --- a/packages/config/src/__tests__/config.test.ts +++ b/packages/config/src/__tests__/config.test.ts @@ -1,6 +1,6 @@ import { SqliteDriver } from "@mikro-orm/sqlite"; import { describe, expect, expectTypeOf, it } from "vitest"; -import { dirname, resolve } from "node:path"; +import { dirname } from "node:path"; import { fileURLToPath } from "node:url"; import { defineHackkitConfig, @@ -23,25 +23,13 @@ describe("HackKit config", () => { expect(config.database).toBe(database); }); - it("loads the web HackKit config through the shared loader", async () => { - const repoRoot = resolve( - dirname(fileURLToPath(import.meta.url)), - "../../../..", - ); - const config = await loadHackkitConfig("apps/web/hackkit.config.ts", { - cwd: repoRoot, + it("loads a config through the shared loader", async () => { + const cwd = dirname(fileURLToPath(import.meta.url)); + const config = await loadHackkitConfig("fixtures/hackkit.config.ts", { + cwd, }); - - expect(config.database).toBeDefined(); - expect(config.plugins.map((plugin) => plugin.id)).toEqual([ - "teams", - "discord", - "notificationsEmail", - ]); - expect(config.seedRoles.map((role) => role.id)).toEqual([ - "core.participant", - "core.owner", - ]); + expect(config.database.dbName).toBe(":memory:"); + expect(config.plugins).toEqual([]); }); }); diff --git a/packages/config/src/__tests__/fixtures/hackkit.config.ts b/packages/config/src/__tests__/fixtures/hackkit.config.ts new file mode 100644 index 000000000..2ab459645 --- /dev/null +++ b/packages/config/src/__tests__/fixtures/hackkit.config.ts @@ -0,0 +1,5 @@ +import { SqliteDriver } from "@mikro-orm/sqlite"; +export default { + database: { driver: SqliteDriver, dbName: ":memory:" }, + auth: {}, +}; diff --git a/packages/config/src/index.ts b/packages/config/src/index.ts index 82c2cb7ba..e648d79f2 100644 --- a/packages/config/src/index.ts +++ b/packages/config/src/index.ts @@ -9,7 +9,6 @@ import type { SeedRoleInput, UserDataOptionsInput, } from "@hackkit/core"; -import { createJiti } from "jiti"; import { resolve } from "node:path"; import { fileURLToPath } from "node:url"; @@ -94,12 +93,12 @@ export function resolveHackkitConfig< }; } -const jiti = createJiti(fileURLToPath(import.meta.url)); - export async function loadHackkitConfig( configFile = "hackkit.config.ts", options: { cwd?: string } = {}, ): Promise { + const { createJiti } = await import("jiti"); + const jiti = createJiti(fileURLToPath(import.meta.url)); const configPath = resolve(options.cwd ?? process.cwd(), configFile); const module = await jiti.import(configPath); const config = ((module as { default?: HackkitConfig }).default ?? diff --git a/packages/core/package.json b/packages/core/package.json index 1ae955d35..8d4bb8c76 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -51,7 +51,8 @@ "better-auth": "1.7.6", "zod": "^3.25.67", "better-call": "1.4.0", - "@better-fetch/fetch": "1.3.2" + "@better-fetch/fetch": "1.3.2", + "@mikro-orm/sql": "7.2.1" }, "devDependencies": { "typescript": "5.9.3", diff --git a/packages/core/src/mikro/options.ts b/packages/core/src/mikro/options.ts index 2b381db6c..2275acd09 100644 --- a/packages/core/src/mikro/options.ts +++ b/packages/core/src/mikro/options.ts @@ -1,5 +1,6 @@ import type { Options, EntitySchema } from "@mikro-orm/core"; import type { SqliteDriver } from "@mikro-orm/sqlite"; +import type { SqliteDriver as GenericSqliteDriver } from "@mikro-orm/sql"; import type { LibSqlDriver } from "@mikro-orm/libsql"; import type { MySqlDriver } from "@mikro-orm/mysql"; import type { PostgreSqlDriver } from "@mikro-orm/postgresql"; @@ -9,6 +10,7 @@ import { assertAuthEntitySchema, type HackKitAuthOptions } from "./auth"; export type HackKitDriver = | SqliteDriver + | GenericSqliteDriver | LibSqlDriver | MySqlDriver | PostgreSqlDriver; diff --git a/packages/next/README.md b/packages/next/README.md index 55ca3199f..c0c23172a 100644 --- a/packages/next/README.md +++ b/packages/next/README.md @@ -4,7 +4,7 @@ Next.js request setup and page guards for HackKit. Core owns the HTTP endpoints ## Runtime setup -`createHackkitRuntimeFromConfig({ config, afterCurrentUser? })` returns a shared `core` promise, a request-local `getRuntime` factory, and an HTTP `handler`. Register `host.getRuntime` with `setHackkitRuntime` for package-owned plugin pages. The reference implementation is [the app runtime](../../apps/web/lib/runtime.ts). +`createHackkitRuntimeFromConfig({ config, afterCurrentUser? })` returns a shared `core` promise, a request-local `getRuntime` factory, and an HTTP `handler`. Register `host.getRuntime` with `setHackkitRuntime` for package-owned plugin pages. The reference implementation is [the app runtime](../../templates/nextjs-full/lib/runtime.ts). The host initializes one Core ORM and Better Auth instance. Each server render resolves its session from Next headers and creates a fresh domain scope. React caches this runtime within that render. HTTP calls resolve the session from their Web Request and run their operation inside Core's native MikroORM RequestContext. Shared endpoint definitions never retain a request's actor or EntityManager. diff --git a/packages/plugin-teams/package.json b/packages/plugin-teams/package.json index 050d6ace3..526ec7a7a 100644 --- a/packages/plugin-teams/package.json +++ b/packages/plugin-teams/package.json @@ -51,6 +51,9 @@ "react-dom": ">=18" }, "devDependencies": { + "next": "14.2.35", + "react": "18.3.1", + "react-dom": "18.3.1", "@types/react": "18.3.3", "@types/react-dom": "18.3.0", "typescript": "5.9.3", diff --git a/packages/plugin-teams/src/components/team-dashboard.tsx b/packages/plugin-teams/src/components/team-dashboard.tsx index 0b5371f24..d2db913f9 100644 --- a/packages/plugin-teams/src/components/team-dashboard.tsx +++ b/packages/plugin-teams/src/components/team-dashboard.tsx @@ -94,7 +94,7 @@ export function TeamDashboard({

Members

-
    +
      {team.members.map((member) => (
    • =18" }, "devDependencies": { + "next": "14.2.35", + "react": "18.3.1", + "react-dom": "18.3.1", "@types/react": "18.3.3", "@types/react-dom": "18.3.0", "typescript": "5.9.3", diff --git a/packages/ui/src/components/admin-console-controls.tsx b/packages/ui/src/components/admin-console-controls.tsx index 3b30448cc..69229811e 100644 --- a/packages/ui/src/components/admin-console-controls.tsx +++ b/packages/ui/src/components/admin-console-controls.tsx @@ -50,9 +50,11 @@ const permissionValues = Object.values(CorePermission); export function AdminUserActions({ record, roles, + showEventOperations = true, }: { record: AdminUserRecord; roles: Role[]; + showEventOperations?: boolean; }) { const { client, navigation } = useHackKitUI(); const [pendingAction, setPendingAction] = @@ -215,97 +217,104 @@ export function AdminUserActions({ )}
-
- -

- Current status: {formatRsvpStatus(record.rsvp)} -

-
- - - - + {showEventOperations ? ( +
+ +

+ Current status: {formatRsvpStatus(record.rsvp)} +

+
+ + + + +
-
+ ) : null} ); diff --git a/packages/ui/src/components/admin-console.tsx b/packages/ui/src/components/admin-console.tsx index c7e3d602c..c063ed287 100644 --- a/packages/ui/src/components/admin-console.tsx +++ b/packages/ui/src/components/admin-console.tsx @@ -19,9 +19,13 @@ import { AdminUserActions, AdminRoleManager } from "./admin-console-controls"; export type AdminOverviewPanelProps = { overview: AdminOverview; + showEventOperations?: boolean; }; -export function AdminOverviewPanel({ overview }: AdminOverviewPanelProps) { +export function AdminOverviewPanel({ + overview, + showEventOperations = true, +}: AdminOverviewPanelProps) { const { Link, routes } = useHackKitNavigation(); const stats = [ ["Registrations", overview.totalUsers], @@ -29,9 +33,13 @@ export function AdminOverviewPanel({ overview }: AdminOverviewPanelProps) { ["Approved", overview.approvedUsers], ["Pending Approval", overview.pendingApprovalUsers], ["Suspended", overview.bannedUsers], - ["Check-ins", overview.checkedInUsers], - ["RSVPs", overview.confirmedRsvps], - ["Waitlist", overview.waitlistedRsvps], + ...(showEventOperations + ? ([ + ["Check-ins", overview.checkedInUsers], + ["RSVPs", overview.confirmedRsvps], + ["Waitlist", overview.waitlistedRsvps], + ] as const) + : []), ] as const; return ( @@ -118,9 +126,14 @@ export function AdminOverviewPanel({ overview }: AdminOverviewPanelProps) { export type AdminUsersTableProps = { users: AdminUserRecord[]; exportHref?: string; + showEventOperations?: boolean; }; -export function AdminUsersTable({ users, exportHref }: AdminUsersTableProps) { +export function AdminUsersTable({ + users, + exportHref, + showEventOperations = true, +}: AdminUsersTableProps) { const { Link, routes } = useHackKitNavigation(); return ( @@ -142,11 +155,17 @@ export function AdminUsersTable({ users, exportHref }: AdminUsersTableProps) { User Role Status - RSVP + {showEventOperations ? ( + RSVP + ) : null} Registered - Check-in + {showEventOperations ? ( + + Check-in + + ) : null} @@ -198,19 +217,23 @@ export function AdminUsersTable({ users, exportHref }: AdminUsersTableProps) { ) : null}
- - {formatRsvpStatus(record.rsvp)} - + {showEventOperations ? ( + + {formatRsvpStatus(record.rsvp)} + + ) : null} {formatDateTime(record.user.createdAt)} - - {record.user.checkedInAt - ? formatDateTime( - record.user.checkedInAt, - ) - : "Not checked in"} - + {showEventOperations ? ( + + {record.user.checkedInAt + ? formatDateTime( + record.user.checkedInAt, + ) + : "Not checked in"} + + ) : null} ))} @@ -223,9 +246,14 @@ export function AdminUsersTable({ users, exportHref }: AdminUsersTableProps) { export type AdminUserDetailProps = { record: AdminUserRecord; roles: Role[]; + showEventOperations?: boolean; }; -export function AdminUserDetail({ record, roles }: AdminUserDetailProps) { +export function AdminUserDetail({ + record, + roles, + showEventOperations = true, +}: AdminUserDetailProps) { return (
@@ -258,18 +286,24 @@ export function AdminUserDetail({ record, roles }: AdminUserDetailProps) { record.user.isApproved ? "Approved" : "Pending" } /> - - + {showEventOperations ? ( + <> + + + + ) : null} @@ -366,7 +400,11 @@ export function AdminUserDetail({ record, roles }: AdminUserDetailProps) {
- +
); } diff --git a/packages/ui/src/components/hacker-registration-form.tsx b/packages/ui/src/components/hacker-registration-form.tsx index 0bf6b23ff..938b14b00 100644 --- a/packages/ui/src/components/hacker-registration-form.tsx +++ b/packages/ui/src/components/hacker-registration-form.tsx @@ -94,11 +94,12 @@ function SelectField({ options: readonly { value: string; label: string }[]; error?: string; }) { + const id = React.useId(); return (
- + - + diff --git a/packages/ui/src/components/user-profile-settings-form.tsx b/packages/ui/src/components/user-profile-settings-form.tsx index 5a8a9468a..c63d56306 100644 --- a/packages/ui/src/components/user-profile-settings-form.tsx +++ b/packages/ui/src/components/user-profile-settings-form.tsx @@ -38,6 +38,7 @@ type FormValues = z.input; export type UserProfileSettingsFormProps = { currentUser: User; uploadProfilePhoto?: (file: File) => Promise; + showDiscordHandle?: boolean; className?: string; }; @@ -74,6 +75,7 @@ function userToFormValues(user: User | Wire): FormValues { export function UserProfileSettingsForm({ currentUser, uploadProfilePhoto, + showDiscordHandle = true, className, }: UserProfileSettingsFormProps) { const { client, navigation } = useHackKitUI(); @@ -150,8 +152,9 @@ export function UserProfileSettingsForm({ Profile - Update your public profile, HackTag, and Discord display - handle. + {showDiscordHandle + ? "Update your public profile, HackTag, and Discord display handle." + : "Update your public profile and HackTag."} @@ -222,21 +225,23 @@ export function UserProfileSettingsForm({ } />
-
- - - -
+ {showDiscordHandle ? ( +
+ + + +
+ ) : null}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6cb146045..8117b2f89 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1,4 +1,171 @@ -lockfileVersion: '6.0' +--- +lockfileVersion: '9.0' + +importers: + + .: + configDependencies: {} + packageManagerDependencies: + pnpm: + specifier: 12.15.0 + version: 12.15.0 + +packages: + + '@pnpm/exe.android-arm64@12.15.0': + resolution: {integrity: sha512-eVCqmscY70LGvgRzu3mi8IBWBFGix+a6mNZoWmXxESsBdeiKEF9xQSuaeel10yn+zI7TXy2jlI63vFLzETk+aQ==} + cpu: [arm64] + os: [android] + + '@pnpm/exe.android-x64@12.15.0': + resolution: {integrity: sha512-Gx/WbkFcdUFUg8g8AShezcS9EiQxfYvdAm2hfKLO8sfJmJvKOCt5fzlgHWDzmGhoclibgW+tUGZ/KF4F4wOTCA==} + cpu: [x64] + os: [android] + + '@pnpm/exe.darwin-arm64@12.15.0': + resolution: {integrity: sha512-N0ZykiDWCvqSBJvt71j7cSoBR993FqvYZFtmpCtqvW3pguiI+NAgraLPA5OTwu5mV+/d8hYpVcPktJA3xFDLtA==} + cpu: [arm64] + os: [darwin] + + '@pnpm/exe.darwin-x64@12.15.0': + resolution: {integrity: sha512-7Ntr2HlBUxzwWOg7NwDxCbRW/3vXuqKO+hcXm+w3SBi9rrHY53li1wLqWVT7Gjxd+lVEHM1QJZo6WJEGFU8C6A==} + cpu: [x64] + os: [darwin] + + '@pnpm/exe.freebsd-x64@12.15.0': + resolution: {integrity: sha512-btOiyL7fL7W4uQGH0aqFai2TNC3IoKcZ7gNHBVbEFZt2dWrnrD0SufL3iGs3fLlmb4OtuU35uf4Zpr9V9Jh9mA==} + cpu: [x64] + os: [freebsd] + + '@pnpm/exe.linux-arm64-musl@12.15.0': + resolution: {integrity: sha512-pNC38k+O+90FOjbPNSnw0E7apq1PKTmz3fFe1amn+lys/U5kL++uzir8bRiho8ONcyA3d9EU7wdqcY0DKkj+JA==} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@pnpm/exe.linux-arm64@12.15.0': + resolution: {integrity: sha512-qML/8aCXslh8td/w4U+HJNqUcZ2+m6EfTbWScIzZRmyPsRFN+xB4LP1U/hymxc1iSJiKtG56HJx2fvUErWFIGw==} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@pnpm/exe.linux-ppc64@12.15.0': + resolution: {integrity: sha512-tjRDUUl7RCJ6T/6eoNPxOqkwU4Mzi5RtTXmSAxujyz37OTwwsMU7Ps087Zk4gHcUvRSeyF40ZFsew3vtE+nmUA==} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@pnpm/exe.linux-riscv64@12.15.0': + resolution: {integrity: sha512-bF1uBWEfbwaeryz6lIiaJ8AWD082otZfvzGX5l+6LZRpRwUEpJHUsJrORaYP5/cNMv5ZR2p6TvvcJcQzwtDzmw==} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@pnpm/exe.linux-s390x@12.15.0': + resolution: {integrity: sha512-zKMhIzsexYMToeLmqV5jPsvV/f9vwsJb2kUH2NFYzalbxImeBrlA4kL7GwF8gD4pagV6jYYcJb8RjbZIdjHptg==} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@pnpm/exe.linux-x64-musl@12.15.0': + resolution: {integrity: sha512-A9J0Jg0Rdx+qQU4qXtwyST5tto9IOu1zi4fDk35nbc6DWahggbcKtFvZPKFwL2qgUXGXOX//hXv6z/sp6emO8A==} + cpu: [x64] + os: [linux] + libc: [musl] + + '@pnpm/exe.linux-x64@12.15.0': + resolution: {integrity: sha512-yc+QlZR+9+nr29J4fRzhMoapgxTBDndq/+peyoq1XUufnQFnfbXUMFudDIKzHi545linGqmOmXfn0NoufNgcOg==} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@pnpm/exe.win32-arm64@12.15.0': + resolution: {integrity: sha512-fPXZxuY1VclkOga9bc53qNCXcegfeoBR8+Ue+AospDwKzuGGSHll0oDxkLfkmpjyRqpe7bH5DyQPYp/xSMaIVA==} + cpu: [arm64] + os: [win32] + + '@pnpm/exe.win32-x64@12.15.0': + resolution: {integrity: sha512-nrd+Tp1We1DGj4DGG5Bea9lZNh9y1PjlLBdEwdInS4D0h0UIDtM7JaGGGDJhNzIwcHASyihWI7HLV+dtG+fhYg==} + cpu: [x64] + os: [win32] + + pnpm@12.15.0: + resolution: {integrity: sha512-s5UdbW/0qfE9x89WzSjSuOs328ycaOUuHhGRhz6p+CoBcoerULqtxczElPA2xnwOR+sTYIwvo29HcRth6hKOYQ==} + engines: {node: '>=18'} + hasBin: true + +snapshots: + + '@pnpm/exe.android-arm64@12.15.0': + optional: true + + '@pnpm/exe.android-x64@12.15.0': + optional: true + + '@pnpm/exe.darwin-arm64@12.15.0': + optional: true + + '@pnpm/exe.darwin-x64@12.15.0': + optional: true + + '@pnpm/exe.freebsd-x64@12.15.0': + optional: true + + '@pnpm/exe.linux-arm64-musl@12.15.0': + optional: true + + '@pnpm/exe.linux-arm64@12.15.0': + optional: true + + '@pnpm/exe.linux-ppc64@12.15.0': + optional: true + + '@pnpm/exe.linux-riscv64@12.15.0': + optional: true + + '@pnpm/exe.linux-s390x@12.15.0': + optional: true + + '@pnpm/exe.linux-x64-musl@12.15.0': + optional: true + + '@pnpm/exe.linux-x64@12.15.0': + optional: true + + '@pnpm/exe.win32-arm64@12.15.0': + optional: true + + '@pnpm/exe.win32-x64@12.15.0': + optional: true + + pnpm@12.15.0: + optionalDependencies: + '@pnpm/exe.android-arm64': 12.15.0 + '@pnpm/exe.android-x64': 12.15.0 + '@pnpm/exe.darwin-arm64': 12.15.0 + '@pnpm/exe.darwin-x64': 12.15.0 + '@pnpm/exe.freebsd-x64': 12.15.0 + '@pnpm/exe.linux-arm64': 12.15.0 + '@pnpm/exe.linux-arm64-musl': 12.15.0 + '@pnpm/exe.linux-ppc64': 12.15.0 + '@pnpm/exe.linux-riscv64': 12.15.0 + '@pnpm/exe.linux-s390x': 12.15.0 + '@pnpm/exe.linux-x64': 12.15.0 + '@pnpm/exe.linux-x64-musl': 12.15.0 + '@pnpm/exe.win32-arm64': 12.15.0 + '@pnpm/exe.win32-x64': 12.15.0 + +--- +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +overrides: + '@libsql/kysely-libsql>@libsql/client': 0.17.4 + +packageExtensionsChecksum: sha256-fUKBU8JkqVHLyag+QvOzgbRoRIXlBrMZC5u5GfPR3x4= importers: @@ -6,35 +173,29 @@ importers: dependencies: prettier-plugin-tailwindcss: specifier: ^0.6.5 - version: 0.6.5(prettier@3.3.3) + version: 0.6.14(prettier@3.9.10) devDependencies: '@turbo/gen': specifier: ^2.0.9 - version: 2.0.9(@types/node@20.14.11)(typescript@5.9.3) + version: 2.11.10(@types/node@20.14.11) '@types/node': specifier: 20.14.11 version: 20.14.11 dotenv-cli: specifier: ^7.4.2 - version: 7.4.2 + version: 7.4.4 eslint: - specifier: ^9.7.0 - version: 9.7.0 + specifier: ^10.13.0 + version: 10.13.0(jiti@2.7.0)(supports-color@10.2.2) prettier: specifier: ^3.3.3 - version: 3.3.3 + version: 3.9.10 turbo: specifier: ^2.0.9 - version: 2.0.9 + version: 2.11.10 - apps/web: + apps/demo: dependencies: - '@hackkit/blob-local': - specifier: workspace:* - version: link:../../packages/blob-local - '@hackkit/blob-s3': - specifier: workspace:* - version: link:../../packages/blob-s3 '@hackkit/cli': specifier: workspace:* version: link:../../packages/cli @@ -47,34 +208,25 @@ importers: '@hackkit/next': specifier: workspace:* version: link:../../packages/next - '@hackkit/plugin-discord': - specifier: workspace:* - version: link:../../packages/plugin-discord - '@hackkit/plugin-notifications-email': - specifier: workspace:* - version: link:../../packages/plugin-notifications-email '@hackkit/plugin-teams': specifier: workspace:* version: link:../../packages/plugin-teams '@hackkit/ui': specifier: workspace:* version: link:../../packages/ui + '@libsql/client': + specifier: 0.17.4 + version: 0.17.4 + '@libsql/kysely-libsql': + specifier: 0.4.1 + version: 0.4.1(kysely@0.29.6) '@mikro-orm/core': specifier: 7.2.1 version: 7.2.1 - '@mikro-orm/libsql': - specifier: 7.2.1 - version: 7.2.1(@mikro-orm/core@7.2.1) '@mikro-orm/migrations': specifier: 7.2.1 version: 7.2.1(@mikro-orm/core@7.2.1) - '@mikro-orm/mysql': - specifier: 7.2.1 - version: 7.2.1(@mikro-orm/core@7.2.1)(@types/node@22.18.6) - '@mikro-orm/postgresql': - specifier: 7.2.1 - version: 7.2.1(@mikro-orm/core@7.2.1) - '@mikro-orm/sqlite': + '@mikro-orm/sql': specifier: 7.2.1 version: 7.2.1(@mikro-orm/core@7.2.1) '@next/env': @@ -82,38 +234,71 @@ importers: version: 14.2.35 better-auth: specifier: 1.7.6 - version: 1.7.6(next@14.2.35)(pg@8.23.0)(react-dom@18.3.1)(react@18.3.1)(vitest@3.2.4) + version: 1.7.6(mysql2@3.24.4(@types/node@22.18.6))(next@14.2.35(@playwright/test@1.64.1)(@types/react@19.3.0)(react-dom@19.3.1(react@19.3.1))(react@19.3.1))(pg@8.23.0)(react-dom@19.3.1(react@19.3.1))(react@19.3.1)(vitest@3.2.7(@types/debug@4.1.13)(@types/node@22.18.6)(jiti@2.4.2)(lightningcss@1.33.0)(supports-color@10.2.2)(terser@5.51.2)(yaml@2.9.1)) jiti: specifier: 2.4.2 version: 2.4.2 + kysely: + specifier: 0.29.6 + version: 0.29.6 next: specifier: 14.2.35 - version: 14.2.35(react-dom@18.3.1)(react@18.3.1) + version: 14.2.35(@playwright/test@1.64.1)(@types/react@19.3.0)(react-dom@19.3.1(react@19.3.1))(react@19.3.1) react: - specifier: 18.3.1 - version: 18.3.1 + specifier: 19.3.1 + version: 19.3.1 react-dom: - specifier: 18.3.1 - version: 18.3.1(react@18.3.1) + specifier: 19.3.1 + version: 19.3.1(react@19.3.1) + react-server-dom-webpack: + specifier: 19.3.1 + version: 19.3.1(react-dom@19.3.1(react@19.3.1))(react@19.3.1)(webpack@5.112.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.4.39)(sharp@0.35.5(@types/node@22.18.6))) sonner: specifier: ^1.5.0 - version: 1.5.0(react-dom@18.3.1)(react@18.3.1) + version: 1.7.4(@types/react@19.3.0)(react-dom@19.3.1(react@19.3.1))(react@19.3.1) typescript: specifier: 5.9.3 version: 5.9.3 + vinext: + specifier: 1.2.1 + version: 1.2.1(@types/node@22.18.6)(@vitejs/plugin-react@6.0.1(vite@8.3.4(@types/node@22.18.6)(esbuild@0.28.2)(jiti@2.4.2)(terser@5.51.2)(yaml@2.9.1)))(@vitejs/plugin-rsc@0.5.38(react-dom@19.3.1(react@19.3.1))(react-server-dom-webpack@19.3.1(react-dom@19.3.1(react@19.3.1))(react@19.3.1)(webpack@5.112.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.4.39)(sharp@0.35.5(@types/node@22.18.6))))(react@19.3.1)(vite@8.3.4(@types/node@22.18.6)(esbuild@0.28.2)(jiti@2.4.2)(terser@5.51.2)(yaml@2.9.1)))(next@14.2.35(@playwright/test@1.64.1)(@types/react@19.3.0)(react-dom@19.3.1(react@19.3.1))(react@19.3.1))(react-dom@19.3.1(react@19.3.1))(react-server-dom-webpack@19.3.1(react-dom@19.3.1(react@19.3.1))(react@19.3.1)(webpack@5.112.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.4.39)(sharp@0.35.5(@types/node@22.18.6))))(react@19.3.1)(vite@8.3.4(@types/node@22.18.6)(esbuild@0.28.2)(jiti@2.4.2)(terser@5.51.2)(yaml@2.9.1)) + zod: + specifier: ^3.25.67 + version: 3.25.76 devDependencies: + '@cloudflare/vite-plugin': + specifier: 1.64.0 + version: 1.64.0(@types/node@22.18.6)(vite@8.3.4(@types/node@22.18.6)(esbuild@0.28.2)(jiti@2.4.2)(terser@5.51.2)(yaml@2.9.1))(wrangler@4.151.3(@cloudflare/workers-types@5.20261019.1)(@types/node@22.18.6)) + '@cloudflare/workers-types': + specifier: 5.20261019.1 + version: 5.20261019.1 + '@mikro-orm/cli': + specifier: 7.2.1 + version: 7.2.1 + '@playwright/test': + specifier: 1.64.1 + version: 1.64.1 '@types/node': specifier: 22.18.6 version: 22.18.6 '@types/react': - specifier: 18.3.3 - version: 18.3.3 + specifier: 19.3.0 + version: 19.3.0 '@types/react-dom': - specifier: 18.3.0 - version: 18.3.0 + specifier: 19.3.0 + version: 19.3.0(@types/react@19.3.0) + '@vitejs/plugin-react': + specifier: 6.0.1 + version: 6.0.1(vite@8.3.4(@types/node@22.18.6)(esbuild@0.28.2)(jiti@2.4.2)(terser@5.51.2)(yaml@2.9.1)) + '@vitejs/plugin-rsc': + specifier: 0.5.38 + version: 0.5.38(react-dom@19.3.1(react@19.3.1))(react-server-dom-webpack@19.3.1(react-dom@19.3.1(react@19.3.1))(react@19.3.1)(webpack@5.112.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.4.39)(sharp@0.35.5(@types/node@22.18.6))))(react@19.3.1)(vite@8.3.4(@types/node@22.18.6)(esbuild@0.28.2)(jiti@2.4.2)(terser@5.51.2)(yaml@2.9.1)) autoprefixer: specifier: 10.4.19 version: 10.4.19(postcss@8.4.39) + dotenv: + specifier: 16.6.1 + version: 16.6.1 postcss: specifier: 8.4.39 version: 8.4.39 @@ -123,9 +308,127 @@ importers: tailwindcss-animate: specifier: 1.0.7 version: 1.0.7(tailwindcss@3.4.6) + vite: + specifier: 8.3.4 + version: 8.3.4(@types/node@22.18.6)(esbuild@0.28.2)(jiti@2.4.2)(terser@5.51.2)(yaml@2.9.1) + wrangler: + specifier: 4.151.3 + version: 4.151.3(@cloudflare/workers-types@5.20261019.1)(@types/node@22.18.6) + + apps/docs: + dependencies: + cn: + specifier: ^0.5.0 + version: 0.5.0 + fumadocs-core: + specifier: 16.17.7 + version: 16.17.7(@mdx-js/mdx@3.1.1(supports-color@10.2.2))(@types/estree-jsx@1.0.5)(@types/hast@3.0.5)(@types/mdast@4.0.4)(@types/react@19.3.0)(lucide-react@1.61.0(@types/react@19.3.0)(react@19.3.1))(next@16.4.2(@playwright/test@1.64.1)(@types/node@26.6.5)(react-dom@19.3.1(react@19.3.1))(react@19.3.1))(react-dom@19.3.1(react@19.3.1))(react@19.3.1)(supports-color@10.2.2)(zod@4.6.7) + fumadocs-mdx: + specifier: 15.4.9 + version: 15.4.9(@types/mdast@4.0.4)(@types/mdx@2.0.14)(@types/react@19.3.0)(fumadocs-core@16.17.7(@mdx-js/mdx@3.1.1(supports-color@10.2.2))(@types/estree-jsx@1.0.5)(@types/hast@3.0.5)(@types/mdast@4.0.4)(@types/react@19.3.0)(lucide-react@1.61.0(@types/react@19.3.0)(react@19.3.1))(next@16.4.2(@playwright/test@1.64.1)(@types/node@26.6.5)(react-dom@19.3.1(react@19.3.1))(react@19.3.1))(react-dom@19.3.1(react@19.3.1))(react@19.3.1)(supports-color@10.2.2)(zod@4.6.7))(next@16.4.2(@playwright/test@1.64.1)(@types/node@26.6.5)(react-dom@19.3.1(react@19.3.1))(react@19.3.1))(react@19.3.1)(rolldown@1.2.15)(supports-color@10.2.2)(vite@8.3.4(@types/node@26.6.5)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1)) + fumadocs-ui: + specifier: npm:@fumadocs/base-ui@16.17.7 + version: '@fumadocs/base-ui@16.17.7(@types/mdx@2.0.14)(@types/react@19.3.0)(fumadocs-core@16.17.7(@mdx-js/mdx@3.1.1(supports-color@10.2.2))(@types/estree-jsx@1.0.5)(@types/hast@3.0.5)(@types/mdast@4.0.4)(@types/react@19.3.0)(lucide-react@1.61.0(@types/react@19.3.0)(react@19.3.1))(next@16.4.2(@playwright/test@1.64.1)(@types/node@26.6.5)(react-dom@19.3.1(react@19.3.1))(react@19.3.1))(react-dom@19.3.1(react@19.3.1))(react@19.3.1)(supports-color@10.2.2)(zod@4.6.7))(next@16.4.2(@playwright/test@1.64.1)(@types/node@26.6.5)(react-dom@19.3.1(react@19.3.1))(react@19.3.1))(react-dom@19.3.1(react@19.3.1))(react@19.3.1)(supports-color@10.2.2)(tailwindcss@4.3.3)' + lucide-react: + specifier: ^1.59.0 + version: 1.61.0(@types/react@19.3.0)(react@19.3.1) + next: + specifier: 16.4.2 + version: 16.4.2(@playwright/test@1.64.1)(@types/node@26.6.5)(react-dom@19.3.1(react@19.3.1))(react@19.3.1) + react: + specifier: ^19.3.1 + version: 19.3.1 + react-dom: + specifier: ^19.3.1 + version: 19.3.1(react@19.3.1) + devDependencies: + '@tailwindcss/postcss': + specifier: ^4.3.3 + version: 4.3.3 + '@types/mdx': + specifier: ^2.0.14 + version: 2.0.14 + '@types/node': + specifier: ^26.6.5 + version: 26.6.5 + '@types/react': + specifier: ^19.3.0 + version: 19.3.0 + '@types/react-dom': + specifier: ^19.3.0 + version: 19.3.0(@types/react@19.3.0) + postcss: + specifier: ^8.5.31 + version: 8.5.32 + serve: + specifier: ^14.2.6 + version: 14.2.6(supports-color@10.2.2) + tailwindcss: + specifier: ^4.3.3 + version: 4.3.3 + typescript: + specifier: ^7.0.2 + version: 7.0.2 + wrangler: + specifier: 4.151.3 + version: 4.151.3(@cloudflare/workers-types@5.20261019.1)(@types/node@26.6.5) + + e2e: + devDependencies: + '@hackkit/cli': + specifier: workspace:* + version: link:../packages/cli + '@hackkit/config': + specifier: workspace:* + version: link:../packages/config + '@hackkit/core': + specifier: workspace:* + version: link:../packages/core + '@hackkit/plugin-discord': + specifier: workspace:* + version: link:../packages/plugin-discord + '@hackkit/plugin-notifications-email': + specifier: workspace:* + version: link:../packages/plugin-notifications-email + '@hackkit/plugin-teams': + specifier: workspace:* + version: link:../packages/plugin-teams + '@mikro-orm/core': + specifier: 7.2.1 + version: 7.2.1 + '@mikro-orm/libsql': + specifier: 7.2.1 + version: 7.2.1(@mikro-orm/core@7.2.1) + '@mikro-orm/migrations': + specifier: 7.2.1 + version: 7.2.1(@mikro-orm/core@7.2.1) + '@mikro-orm/mysql': + specifier: 7.2.1 + version: 7.2.1(@mikro-orm/core@7.2.1)(@types/node@22.18.6) + '@mikro-orm/postgresql': + specifier: 7.2.1 + version: 7.2.1(@mikro-orm/core@7.2.1) + '@mikro-orm/sqlite': + specifier: 7.2.1 + version: 7.2.1(@mikro-orm/core@7.2.1) + '@playwright/test': + specifier: 1.64.1 + version: 1.64.1 + '@types/node': + specifier: 22.18.6 + version: 22.18.6 + esbuild: + specifier: 0.25.12 + version: 0.25.12 + jiti: + specifier: 2.4.2 + version: 2.4.2 + typescript: + specifier: 5.9.3 + version: 5.9.3 vitest: specifier: ^3.2.4 - version: 3.2.4(@types/node@22.18.6)(jiti@2.4.2) + version: 3.2.7(@types/debug@4.1.13)(@types/node@22.18.6)(jiti@2.4.2)(lightningcss@1.33.0)(supports-color@10.2.2)(terser@5.51.2)(yaml@2.9.1) packages/blob-local: dependencies: @@ -138,7 +441,7 @@ importers: version: 22.18.6 tsup: specifier: ^8.5.1 - version: 8.5.1(jiti@2.4.2)(typescript@5.9.3) + version: 8.5.1(jiti@2.7.0)(postcss@8.5.32)(supports-color@10.2.2)(typescript@5.9.3)(yaml@2.9.1) typescript: specifier: 5.9.3 version: 5.9.3 @@ -147,10 +450,10 @@ importers: dependencies: '@aws-sdk/client-s3': specifier: ^3.744.0 - version: 3.744.0 + version: 3.1157.0 '@aws-sdk/s3-request-presigner': specifier: ^3.744.0 - version: 3.744.0 + version: 3.1157.0 '@hackkit/core': specifier: workspace:* version: link:../core @@ -160,7 +463,7 @@ importers: version: 22.18.6 tsup: specifier: ^8.5.1 - version: 8.5.1(jiti@2.4.2)(typescript@5.9.3) + version: 8.5.1(jiti@2.7.0)(postcss@8.5.32)(supports-color@10.2.2)(typescript@5.9.3)(yaml@2.9.1) typescript: specifier: 5.9.3 version: 5.9.3 @@ -197,13 +500,13 @@ importers: version: 22.18.6 tsup: specifier: ^8.5.1 - version: 8.5.1(jiti@2.4.2)(typescript@5.9.3) + version: 8.5.1(jiti@2.4.2)(postcss@8.5.32)(supports-color@10.2.2)(typescript@5.9.3)(yaml@2.9.1) typescript: specifier: 5.9.3 version: 5.9.3 vitest: specifier: ^3.2.4 - version: 3.2.4(@types/node@22.18.6)(jiti@2.4.2) + version: 3.2.7(@types/debug@4.1.13)(@types/node@22.18.6)(jiti@2.4.2)(lightningcss@1.33.0)(supports-color@10.2.2)(terser@5.51.2)(yaml@2.9.1) packages/config: dependencies: @@ -222,19 +525,19 @@ importers: version: 22.18.6 tsup: specifier: ^8.5.1 - version: 8.5.1(jiti@2.4.2)(typescript@5.9.3) + version: 8.5.1(jiti@2.4.2)(postcss@8.5.32)(supports-color@10.2.2)(typescript@5.9.3)(yaml@2.9.1) typescript: specifier: 5.9.3 version: 5.9.3 vitest: specifier: ^3.2.4 - version: 3.2.4(@types/node@22.18.6)(jiti@2.4.2) + version: 3.2.7(@types/debug@4.1.13)(@types/node@22.18.6)(jiti@2.4.2)(lightningcss@1.33.0)(supports-color@10.2.2)(terser@5.51.2)(yaml@2.9.1) packages/core: dependencies: '@a77ay/better-auth-mikro-orm': specifier: 0.1.1 - version: 0.1.1(@mikro-orm/core@7.2.1)(better-auth@1.7.6) + version: 0.1.1(@mikro-orm/core@7.2.1)(better-auth@1.7.6(mysql2@3.24.4(@types/node@20.14.11))(next@16.4.2(@playwright/test@1.64.1)(@types/node@20.14.11)(react-dom@19.3.1(react@19.3.1))(react@19.3.1))(pg@8.23.0)(react-dom@19.3.1(react@19.3.1))(react@19.3.1)(vitest@3.2.7(@types/debug@4.1.13)(@types/node@20.14.11)(jiti@2.7.0)(lightningcss@1.33.0)(supports-color@10.2.2)(terser@5.51.2)(yaml@2.9.1))) '@better-fetch/fetch': specifier: 1.3.2 version: 1.3.2 @@ -249,32 +552,35 @@ importers: version: 7.2.1(@mikro-orm/core@7.2.1) '@mikro-orm/mysql': specifier: 7.2.1 - version: 7.2.1(@mikro-orm/core@7.2.1)(@types/node@22.18.6) + version: 7.2.1(@mikro-orm/core@7.2.1)(@types/node@20.14.11) '@mikro-orm/postgresql': specifier: 7.2.1 version: 7.2.1(@mikro-orm/core@7.2.1) + '@mikro-orm/sql': + specifier: 7.2.1 + version: 7.2.1(@mikro-orm/core@7.2.1) '@mikro-orm/sqlite': specifier: 7.2.1 version: 7.2.1(@mikro-orm/core@7.2.1) better-auth: specifier: 1.7.6 - version: 1.7.6(next@14.2.35)(pg@8.23.0)(react-dom@18.3.1)(react@18.3.1)(vitest@3.2.4) + version: 1.7.6(mysql2@3.24.4(@types/node@20.14.11))(next@16.4.2(@playwright/test@1.64.1)(@types/node@20.14.11)(react-dom@19.3.1(react@19.3.1))(react@19.3.1))(pg@8.23.0)(react-dom@19.3.1(react@19.3.1))(react@19.3.1)(vitest@3.2.7(@types/debug@4.1.13)(@types/node@20.14.11)(jiti@2.7.0)(lightningcss@1.33.0)(supports-color@10.2.2)(terser@5.51.2)(yaml@2.9.1)) better-call: specifier: 1.4.0 - version: 1.4.0(zod@3.25.67) + version: 1.4.0(zod@3.25.76) zod: specifier: ^3.25.67 - version: 3.25.67 + version: 3.25.76 devDependencies: tsup: specifier: ^8.5.1 - version: 8.5.1(jiti@2.4.2)(typescript@5.9.3) + version: 8.5.1(jiti@2.7.0)(postcss@8.5.32)(supports-color@10.2.2)(typescript@5.9.3)(yaml@2.9.1) typescript: specifier: 5.9.3 version: 5.9.3 vitest: specifier: ^3.2.4 - version: 3.2.4(@types/node@22.18.6)(jiti@2.4.2) + version: 3.2.7(@types/debug@4.1.13)(@types/node@20.14.11)(jiti@2.7.0)(lightningcss@1.33.0)(supports-color@10.2.2)(terser@5.51.2)(yaml@2.9.1) packages/next: dependencies: @@ -286,10 +592,10 @@ importers: version: link:../core better-auth: specifier: 1.7.6 - version: 1.7.6(next@14.2.35)(pg@8.23.0)(react-dom@18.3.1)(react@18.3.1)(vitest@3.2.4) + version: 1.7.6(mysql2@3.24.4(@types/node@22.18.6))(next@14.2.35(@playwright/test@1.64.1)(@types/react@18.3.3)(react-dom@18.3.1(react@19.3.1))(react@19.3.1))(pg@8.23.0)(react-dom@18.3.1(react@19.3.1))(react@19.3.1)(vitest@3.2.7(@types/debug@4.1.13)(@types/node@22.18.6)(jiti@2.7.0)(lightningcss@1.33.0)(supports-color@10.2.2)(terser@5.51.2)(yaml@2.9.1)) react: specifier: '>=18' - version: 18.3.1 + version: 19.3.1 devDependencies: '@types/node': specifier: 22.18.6 @@ -299,16 +605,16 @@ importers: version: 18.3.3 next: specifier: 14.2.35 - version: 14.2.35(react-dom@18.3.1)(react@18.3.1) + version: 14.2.35(@playwright/test@1.64.1)(@types/react@18.3.3)(react-dom@18.3.1(react@19.3.1))(react@19.3.1) tsup: specifier: ^8.5.1 - version: 8.5.1(jiti@2.4.2)(typescript@5.9.3) + version: 8.5.1(jiti@2.7.0)(postcss@8.5.32)(supports-color@10.2.2)(typescript@5.9.3)(yaml@2.9.1) typescript: specifier: 5.9.3 version: 5.9.3 vitest: specifier: ^3.2.4 - version: 3.2.4(@types/node@22.18.6)(jiti@2.4.2) + version: 3.2.7(@types/debug@4.1.13)(@types/node@22.18.6)(jiti@2.7.0)(lightningcss@1.33.0)(supports-color@10.2.2)(terser@5.51.2)(yaml@2.9.1) packages/plugin-discord: dependencies: @@ -326,22 +632,22 @@ importers: version: 7.2.1 better-call: specifier: 1.4.0 - version: 1.4.0(zod@3.25.67) + version: 1.4.0(zod@3.25.76) next: specifier: '>=14' - version: 14.2.35(react-dom@18.3.1)(react@18.3.1) + version: 16.4.2(@playwright/test@1.64.1)(@types/node@20.14.11)(react-dom@19.3.1(react@19.3.1))(react@19.3.1) react: specifier: '>=18' - version: 18.3.1 + version: 19.3.1 react-dom: specifier: '>=18' - version: 18.3.1(react@18.3.1) + version: 19.3.1(react@19.3.1) sonner: specifier: ^1.5.0 - version: 1.5.0(react-dom@18.3.1)(react@18.3.1) + version: 1.7.4(@types/react@18.3.3)(react-dom@19.3.1(react@19.3.1))(react@19.3.1) zod: specifier: ^3.25.67 - version: 3.25.67 + version: 3.25.76 devDependencies: '@types/react': specifier: 18.3.3 @@ -351,13 +657,13 @@ importers: version: 18.3.0 tsup: specifier: ^8.5.1 - version: 8.5.1(jiti@2.4.2)(typescript@5.9.3) + version: 8.5.1(jiti@2.7.0)(postcss@8.5.32)(supports-color@10.2.2)(typescript@5.9.3)(yaml@2.9.1) typescript: specifier: 5.9.3 version: 5.9.3 vitest: specifier: ^3.2.4 - version: 3.2.4(@types/node@22.18.6)(jiti@2.4.2) + version: 3.2.7(@types/debug@4.1.13)(@types/node@20.14.11)(jiti@2.7.0)(lightningcss@1.33.0)(supports-color@10.2.2)(terser@5.51.2)(yaml@2.9.1) packages/plugin-notifications-email: dependencies: @@ -370,13 +676,13 @@ importers: version: 22.18.6 tsup: specifier: ^8.5.1 - version: 8.5.1(jiti@2.4.2)(typescript@5.9.3) + version: 8.5.1(jiti@2.7.0)(postcss@8.5.32)(supports-color@10.2.2)(typescript@5.9.3)(yaml@2.9.1) typescript: specifier: 5.9.3 version: 5.9.3 vitest: specifier: ^3.2.4 - version: 3.2.4(@types/node@22.18.6)(jiti@2.4.2) + version: 3.2.7(@types/debug@4.1.13)(@types/node@22.18.6)(jiti@2.7.0)(lightningcss@1.33.0)(supports-color@10.2.2)(terser@5.51.2)(yaml@2.9.1) packages/plugin-teams: dependencies: @@ -394,22 +700,13 @@ importers: version: 7.2.1 better-call: specifier: 1.4.0 - version: 1.4.0(zod@3.25.67) - next: - specifier: '>=14' - version: 14.2.35(react-dom@18.3.1)(react@18.3.1) - react: - specifier: '>=18' - version: 18.3.1 - react-dom: - specifier: '>=18' - version: 18.3.1(react@18.3.1) + version: 1.4.0(zod@3.25.76) sonner: specifier: ^1.5.0 - version: 1.5.0(react-dom@18.3.1)(react@18.3.1) + version: 1.7.4(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) zod: specifier: ^3.25.67 - version: 3.25.67 + version: 3.25.76 devDependencies: '@types/react': specifier: 18.3.3 @@ -417,15 +714,24 @@ importers: '@types/react-dom': specifier: 18.3.0 version: 18.3.0 + next: + specifier: 14.2.35 + version: 14.2.35(@playwright/test@1.64.1)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + react: + specifier: 18.3.1 + version: 18.3.1 + react-dom: + specifier: 18.3.1 + version: 18.3.1(react@18.3.1) tsup: specifier: ^8.5.1 - version: 8.5.1(jiti@2.4.2)(typescript@5.9.3) + version: 8.5.1(jiti@2.7.0)(postcss@8.5.32)(supports-color@10.2.2)(typescript@5.9.3)(yaml@2.9.1) typescript: specifier: 5.9.3 version: 5.9.3 vitest: specifier: ^3.2.4 - version: 3.2.4(@types/node@22.18.6)(jiti@2.4.2) + version: 3.2.7(@types/debug@4.1.13)(@types/node@20.14.11)(jiti@2.7.0)(lightningcss@1.33.0)(supports-color@10.2.2)(terser@5.51.2)(yaml@2.9.1) packages/tsconfig: {} @@ -436,52 +742,43 @@ importers: version: link:../core '@hookform/resolvers': specifier: ^3.9.0 - version: 3.9.0(react-hook-form@7.52.1) + version: 3.10.0(react-hook-form@7.52.1(react@18.3.1)) '@radix-ui/react-checkbox': specifier: ^1.0.4 - version: 1.0.4(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1)(react@18.3.1) + version: 1.4.1(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-label': specifier: ^2.0.2 - version: 2.0.2(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1)(react@18.3.1) + version: 2.1.17(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-select': specifier: ^1.2.2 - version: 1.2.2(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1)(react@18.3.1) + version: 1.2.2(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-slot': specifier: ^1.0.2 - version: 1.0.2(@types/react@18.3.3)(react@18.3.1) + version: 1.5.0(@types/react@18.3.3)(react@18.3.1) '@yudiel/react-qr-scanner': specifier: ^2.1.0 - version: 2.1.0(react-dom@18.3.1)(react@18.3.1) + version: 2.6.0(@types/emscripten@1.41.6)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) class-variance-authority: specifier: ^0.7.0 - version: 0.7.0 + version: 0.7.1 clsx: specifier: ^2.1.1 version: 2.1.1 - next: - specifier: '>=14' - version: 14.2.35(react-dom@18.3.1)(react@18.3.1) qrcode.react: specifier: ^4.2.0 - version: 4.2.0(react@18.3.1) - react: - specifier: '>=18' - version: 18.3.1 - react-dom: - specifier: '>=18' - version: 18.3.1(react@18.3.1) + version: 4.2.0(@types/react@18.3.3)(react@18.3.1) react-hook-form: specifier: 7.52.1 version: 7.52.1(react@18.3.1) sonner: specifier: ^1.5.0 - version: 1.5.0(react-dom@18.3.1)(react@18.3.1) + version: 1.7.4(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) tailwind-merge: specifier: ^2.4.0 - version: 2.4.0 + version: 2.6.1 zod: specifier: ^3.25.67 - version: 3.25.67 + version: 3.25.76 devDependencies: '@types/react': specifier: 18.3.3 @@ -489,1461 +786,6942 @@ importers: '@types/react-dom': specifier: 18.3.0 version: 18.3.0 + next: + specifier: 14.2.35 + version: 14.2.35(@playwright/test@1.64.1)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + react: + specifier: 18.3.1 + version: 18.3.1 + react-dom: + specifier: 18.3.1 + version: 18.3.1(react@18.3.1) tsup: specifier: ^8.5.1 - version: 8.5.1(jiti@2.4.2)(typescript@5.9.3) + version: 8.5.1(jiti@2.7.0)(postcss@8.5.32)(supports-color@10.2.2)(typescript@5.9.3)(yaml@2.9.1) typescript: specifier: 5.9.3 version: 5.9.3 -packages: - - /@a77ay/better-auth-mikro-orm@0.1.1(@mikro-orm/core@7.2.1)(better-auth@1.7.6): - resolution: {integrity: sha512-WT0EwaIwG6TI0crFDD5bzF823p2o4qMVgSCDFqqzw2pdWSA0TzSVTL8GGjUxNTiPFgOVjFc/GLQnKSYVjnQaPg==} - hasBin: true - peerDependencies: - '@mikro-orm/core': ^7.0.0 - better-auth: ^1.0.0 - dependencies: - '@mikro-orm/core': 7.2.1 - better-auth: 1.7.6(next@14.2.35)(pg@8.23.0)(react-dom@18.3.1)(react@18.3.1)(vitest@3.2.4) - jiti: 2.7.0 - dev: false - - /@alloc/quick-lru@5.2.0: - resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} - engines: {node: '>=10'} - dev: true - - /@aws-crypto/crc32@5.2.0: - resolution: {integrity: sha512-nLbCWqQNgUiwwtFsen1AdzAtvuLRsQS8rYgMuxCrdKf9kOssamGLuPwyTY9wyYblNr9+1XM8v6zoDTPPSIeANg==} - engines: {node: '>=16.0.0'} - dependencies: - '@aws-crypto/util': 5.2.0 - '@aws-sdk/types': 3.734.0 - tslib: 2.8.1 - dev: false - - /@aws-crypto/crc32c@5.2.0: - resolution: {integrity: sha512-+iWb8qaHLYKrNvGRbiYRHSdKRWhto5XlZUEBwDjYNf+ly5SVYG6zEoYIdxvf5R3zyeP16w4PLBn3rH1xc74Rag==} - dependencies: - '@aws-crypto/util': 5.2.0 - '@aws-sdk/types': 3.734.0 - tslib: 2.8.1 - dev: false - - /@aws-crypto/sha1-browser@5.2.0: - resolution: {integrity: sha512-OH6lveCFfcDjX4dbAvCFSYUjJZjDr/3XJ3xHtjn3Oj5b9RjojQo8npoLeA/bNwkOkrSQ0wgrHzXk4tDRxGKJeg==} - dependencies: - '@aws-crypto/supports-web-crypto': 5.2.0 - '@aws-crypto/util': 5.2.0 - '@aws-sdk/types': 3.734.0 - '@aws-sdk/util-locate-window': 3.965.8 - '@smithy/util-utf8': 2.3.0 - tslib: 2.8.1 - dev: false - - /@aws-crypto/sha256-browser@5.2.0: - resolution: {integrity: sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw==} - dependencies: - '@aws-crypto/sha256-js': 5.2.0 - '@aws-crypto/supports-web-crypto': 5.2.0 - '@aws-crypto/util': 5.2.0 - '@aws-sdk/types': 3.734.0 - '@aws-sdk/util-locate-window': 3.965.8 - '@smithy/util-utf8': 2.3.0 - tslib: 2.8.1 - dev: false - - /@aws-crypto/sha256-js@5.2.0: - resolution: {integrity: sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA==} - engines: {node: '>=16.0.0'} - dependencies: - '@aws-crypto/util': 5.2.0 - '@aws-sdk/types': 3.734.0 - tslib: 2.8.1 - dev: false - - /@aws-crypto/supports-web-crypto@5.2.0: - resolution: {integrity: sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg==} - dependencies: - tslib: 2.8.1 - dev: false - - /@aws-crypto/util@5.2.0: - resolution: {integrity: sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==} - dependencies: - '@aws-sdk/types': 3.734.0 - '@smithy/util-utf8': 2.3.0 - tslib: 2.8.1 - dev: false - - /@aws-sdk/client-s3@3.744.0: - resolution: {integrity: sha512-UuiqxVI5FKlnNcWoDP8bsyJcMJa7XjGcCbVCfKSpSboNeBM4tQS3ZIViSYuz+BeO8/MuwCy7hKn7+Zjivit1nA==} - engines: {node: '>=18.0.0'} - dependencies: - '@aws-crypto/sha1-browser': 5.2.0 - '@aws-crypto/sha256-browser': 5.2.0 - '@aws-crypto/sha256-js': 5.2.0 - '@aws-sdk/core': 3.744.0 - '@aws-sdk/credential-provider-node': 3.744.0 - '@aws-sdk/middleware-bucket-endpoint': 3.734.0 - '@aws-sdk/middleware-expect-continue': 3.734.0 - '@aws-sdk/middleware-flexible-checksums': 3.744.0 - '@aws-sdk/middleware-host-header': 3.734.0 - '@aws-sdk/middleware-location-constraint': 3.734.0 - '@aws-sdk/middleware-logger': 3.734.0 - '@aws-sdk/middleware-recursion-detection': 3.734.0 - '@aws-sdk/middleware-sdk-s3': 3.744.0 - '@aws-sdk/middleware-ssec': 3.734.0 - '@aws-sdk/middleware-user-agent': 3.744.0 - '@aws-sdk/region-config-resolver': 3.734.0 - '@aws-sdk/signature-v4-multi-region': 3.744.0 - '@aws-sdk/types': 3.734.0 - '@aws-sdk/util-endpoints': 3.743.0 - '@aws-sdk/util-user-agent-browser': 3.734.0 - '@aws-sdk/util-user-agent-node': 3.744.0 - '@aws-sdk/xml-builder': 3.734.0 - '@smithy/config-resolver': 4.6.8 - '@smithy/core': 3.29.3 - '@smithy/eventstream-serde-browser': 4.4.8 - '@smithy/eventstream-serde-config-resolver': 4.5.8 - '@smithy/eventstream-serde-node': 4.4.8 - '@smithy/fetch-http-handler': 5.6.5 - '@smithy/hash-blob-browser': 4.4.8 - '@smithy/hash-node': 4.4.8 - '@smithy/hash-stream-node': 4.4.8 - '@smithy/invalid-dependency': 4.4.8 - '@smithy/md5-js': 4.4.8 - '@smithy/middleware-content-length': 4.4.8 - '@smithy/middleware-endpoint': 4.6.8 - '@smithy/middleware-retry': 4.7.8 - '@smithy/middleware-serde': 4.4.8 - '@smithy/middleware-stack': 4.4.8 - '@smithy/node-config-provider': 4.5.8 - '@smithy/node-http-handler': 4.9.5 - '@smithy/protocol-http': 5.5.8 - '@smithy/smithy-client': 4.14.8 - '@smithy/types': 4.16.1 - '@smithy/url-parser': 4.4.8 - '@smithy/util-base64': 4.5.8 - '@smithy/util-body-length-browser': 4.4.8 - '@smithy/util-body-length-node': 4.4.8 - '@smithy/util-defaults-mode-browser': 4.5.8 - '@smithy/util-defaults-mode-node': 4.4.8 - '@smithy/util-endpoints': 3.6.8 - '@smithy/util-middleware': 4.4.8 - '@smithy/util-retry': 4.5.8 - '@smithy/util-stream': 4.7.8 - '@smithy/util-utf8': 4.4.8 - '@smithy/util-waiter': 4.5.8 - tslib: 2.8.1 - transitivePeerDependencies: - - aws-crt - dev: false - - /@aws-sdk/client-sso@3.744.0: - resolution: {integrity: sha512-mzJxPQ9mcnNY50pi7+pxB34/Dt7PUn0OgkashHdJPTnavoriLWvPcaQCG1NEVAtyzxNdowhpi4KjC+aN1EwAeA==} - engines: {node: '>=18.0.0'} - dependencies: - '@aws-crypto/sha256-browser': 5.2.0 - '@aws-crypto/sha256-js': 5.2.0 - '@aws-sdk/core': 3.744.0 - '@aws-sdk/middleware-host-header': 3.734.0 - '@aws-sdk/middleware-logger': 3.734.0 - '@aws-sdk/middleware-recursion-detection': 3.734.0 - '@aws-sdk/middleware-user-agent': 3.744.0 - '@aws-sdk/region-config-resolver': 3.734.0 - '@aws-sdk/types': 3.734.0 - '@aws-sdk/util-endpoints': 3.743.0 - '@aws-sdk/util-user-agent-browser': 3.734.0 - '@aws-sdk/util-user-agent-node': 3.744.0 - '@smithy/config-resolver': 4.6.8 - '@smithy/core': 3.29.3 - '@smithy/fetch-http-handler': 5.6.5 - '@smithy/hash-node': 4.4.8 - '@smithy/invalid-dependency': 4.4.8 - '@smithy/middleware-content-length': 4.4.8 - '@smithy/middleware-endpoint': 4.6.8 - '@smithy/middleware-retry': 4.7.8 - '@smithy/middleware-serde': 4.4.8 - '@smithy/middleware-stack': 4.4.8 - '@smithy/node-config-provider': 4.5.8 - '@smithy/node-http-handler': 4.9.5 - '@smithy/protocol-http': 5.5.8 - '@smithy/smithy-client': 4.14.8 - '@smithy/types': 4.16.1 - '@smithy/url-parser': 4.4.8 - '@smithy/util-base64': 4.5.8 - '@smithy/util-body-length-browser': 4.4.8 - '@smithy/util-body-length-node': 4.4.8 - '@smithy/util-defaults-mode-browser': 4.5.8 - '@smithy/util-defaults-mode-node': 4.4.8 - '@smithy/util-endpoints': 3.6.8 - '@smithy/util-middleware': 4.4.8 - '@smithy/util-retry': 4.5.8 - '@smithy/util-utf8': 4.4.8 - tslib: 2.8.1 - transitivePeerDependencies: - - aws-crt - dev: false - - /@aws-sdk/core@3.744.0: - resolution: {integrity: sha512-R0XLfDDq7MAXYyDf7tPb+m0R7gmzTRRDtPNQ5jvuq8dbkefph5gFMkxZ2zSx7dfTsfYHhBPuTBsQ0c5Xjal3Vg==} - engines: {node: '>=18.0.0'} + templates/nextjs-full: dependencies: - '@aws-sdk/types': 3.734.0 - '@smithy/core': 3.29.3 - '@smithy/node-config-provider': 4.5.8 - '@smithy/property-provider': 4.4.8 - '@smithy/protocol-http': 5.5.8 - '@smithy/signature-v4': 5.6.4 - '@smithy/smithy-client': 4.14.8 - '@smithy/types': 4.16.1 - '@smithy/util-middleware': 4.4.8 - fast-xml-parser: 4.4.1 + '@hackkit/blob-local': + specifier: workspace:* + version: link:../../packages/blob-local + '@hackkit/blob-s3': + specifier: workspace:* + version: link:../../packages/blob-s3 + '@hackkit/cli': + specifier: workspace:* + version: link:../../packages/cli + '@hackkit/config': + specifier: workspace:* + version: link:../../packages/config + '@hackkit/core': + specifier: workspace:* + version: link:../../packages/core + '@hackkit/next': + specifier: workspace:* + version: link:../../packages/next + '@hackkit/plugin-discord': + specifier: workspace:* + version: link:../../packages/plugin-discord + '@hackkit/plugin-notifications-email': + specifier: workspace:* + version: link:../../packages/plugin-notifications-email + '@hackkit/plugin-teams': + specifier: workspace:* + version: link:../../packages/plugin-teams + '@hackkit/ui': + specifier: workspace:* + version: link:../../packages/ui + '@mikro-orm/core': + specifier: 7.2.1 + version: 7.2.1 + '@mikro-orm/libsql': + specifier: 7.2.1 + version: 7.2.1(@mikro-orm/core@7.2.1) + '@mikro-orm/migrations': + specifier: 7.2.1 + version: 7.2.1(@mikro-orm/core@7.2.1) + '@mikro-orm/mysql': + specifier: 7.2.1 + version: 7.2.1(@mikro-orm/core@7.2.1)(@types/node@22.18.6) + '@mikro-orm/postgresql': + specifier: 7.2.1 + version: 7.2.1(@mikro-orm/core@7.2.1) + '@mikro-orm/sqlite': + specifier: 7.2.1 + version: 7.2.1(@mikro-orm/core@7.2.1) + '@next/env': + specifier: 14.2.35 + version: 14.2.35 + better-auth: + specifier: 1.7.6 + version: 1.7.6(mysql2@3.24.4(@types/node@22.18.6))(next@14.2.35(@playwright/test@1.64.1)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(pg@8.23.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(vitest@3.2.7(@types/debug@4.1.13)(@types/node@22.18.6)(jiti@2.4.2)(lightningcss@1.33.0)(supports-color@10.2.2)(terser@5.51.2)(yaml@2.9.1)) + jiti: + specifier: 2.4.2 + version: 2.4.2 + next: + specifier: 14.2.35 + version: 14.2.35(@playwright/test@1.64.1)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + react: + specifier: 18.3.1 + version: 18.3.1 + react-dom: + specifier: 18.3.1 + version: 18.3.1(react@18.3.1) + sonner: + specifier: ^1.5.0 + version: 1.7.4(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + typescript: + specifier: 5.9.3 + version: 5.9.3 + devDependencies: + '@types/node': + specifier: 22.18.6 + version: 22.18.6 + '@types/react': + specifier: 18.3.3 + version: 18.3.3 + '@types/react-dom': + specifier: 18.3.0 + version: 18.3.0 + autoprefixer: + specifier: 10.4.19 + version: 10.4.19(postcss@8.4.39) + postcss: + specifier: 8.4.39 + version: 8.4.39 + tailwindcss: + specifier: 3.4.6 + version: 3.4.6 + tailwindcss-animate: + specifier: 1.0.7 + version: 1.0.7(tailwindcss@3.4.6) + + templates/nextjs-minimal: + dependencies: + '@hackkit/blob-local': + specifier: workspace:* + version: link:../../packages/blob-local + '@hackkit/cli': + specifier: workspace:* + version: link:../../packages/cli + '@hackkit/config': + specifier: workspace:* + version: link:../../packages/config + '@hackkit/core': + specifier: workspace:* + version: link:../../packages/core + '@hackkit/next': + specifier: workspace:* + version: link:../../packages/next + '@hackkit/ui': + specifier: workspace:* + version: link:../../packages/ui + '@mikro-orm/core': + specifier: 7.2.1 + version: 7.2.1 + '@mikro-orm/migrations': + specifier: 7.2.1 + version: 7.2.1(@mikro-orm/core@7.2.1) + '@mikro-orm/sqlite': + specifier: 7.2.1 + version: 7.2.1(@mikro-orm/core@7.2.1) + '@next/env': + specifier: 14.2.35 + version: 14.2.35 + better-auth: + specifier: 1.7.6 + version: 1.7.6(mysql2@3.24.4(@types/node@22.18.6))(next@14.2.35(@playwright/test@1.64.1)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(pg@8.23.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(vitest@3.2.7(@types/debug@4.1.13)(@types/node@22.18.6)(jiti@2.4.2)(lightningcss@1.33.0)(supports-color@10.2.2)(terser@5.51.2)(yaml@2.9.1)) + jiti: + specifier: 2.4.2 + version: 2.4.2 + next: + specifier: 14.2.35 + version: 14.2.35(@playwright/test@1.64.1)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + react: + specifier: 18.3.1 + version: 18.3.1 + react-dom: + specifier: 18.3.1 + version: 18.3.1(react@18.3.1) + sonner: + specifier: ^1.5.0 + version: 1.7.4(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + typescript: + specifier: 5.9.3 + version: 5.9.3 + devDependencies: + '@types/node': + specifier: 22.18.6 + version: 22.18.6 + '@types/react': + specifier: 18.3.3 + version: 18.3.3 + '@types/react-dom': + specifier: 18.3.0 + version: 18.3.0 + autoprefixer: + specifier: 10.4.19 + version: 10.4.19(postcss@8.4.39) + postcss: + specifier: 8.4.39 + version: 8.4.39 + tailwindcss: + specifier: 3.4.6 + version: 3.4.6 + tailwindcss-animate: + specifier: 1.0.7 + version: 1.0.7(tailwindcss@3.4.6) + +packages: + + '@a77ay/better-auth-mikro-orm@0.1.1': + resolution: {integrity: sha512-WT0EwaIwG6TI0crFDD5bzF823p2o4qMVgSCDFqqzw2pdWSA0TzSVTL8GGjUxNTiPFgOVjFc/GLQnKSYVjnQaPg==} + hasBin: true + peerDependencies: + '@mikro-orm/core': ^7.0.0 + better-auth: ^1.0.0 + + '@alloc/quick-lru@5.3.0': + resolution: {integrity: sha512-U4+70Pc5ZS9osnCBCE5Jha/ciHM+Yp+CNMNC/7HvYbNRk1Ldd+f7qO65W5qfhu/TCv+/ozljlXXe9Nj8419DMA==} + engines: {node: '>=10'} + + '@aws-sdk/checksums@3.1001.6': + resolution: {integrity: sha512-DSo+EqLq2PkS8gjit311LliRrYzydneP6vRhxMzDh9c8P3wWGzHf4fjmQN3d8sl4qh+aMqzn9+o+gZZo4+uqIQ==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/client-s3@3.1157.0': + resolution: {integrity: sha512-fbZIxqZVzK/PMLj9az3+ieAcYdZhzpTrfIVAnrE4PnRc1C6SokMDnaxAJycKTNmzLlY1fvmlItZWBDPUEFlGLQ==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/core@3.978.6': + resolution: {integrity: sha512-ykF/MiYoM15dgZwF/WLgjJXVbAK2wU6vjPigeEnOHwyUJ0rdlraO5uekecKNVPkvOnz+oju/5zljViQs1nI1FQ==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-env@3.972.77': + resolution: {integrity: sha512-CN6dQCDo32a8n2gvm2HBeqGV5BNI9noG96nTj5bGO2HWtt0Rucu/A8pcnJIqkzILOHSuilnCk0Do8/7h6SOXhQ==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-http@3.972.79': + resolution: {integrity: sha512-Netsu0nnmvP2HiN1ZFQBeUu+JehQIuubqz+j2kHDgeSE4HDzniCpIZ7RzoWABq+LTcbCi9W03hywifUagoVIWQ==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-ini@3.973.22': + resolution: {integrity: sha512-x7/5h58cqOoZR0RWUZC7v/cJOADQR42iSIQkvU+00HVHR4jh8ZpqEgRPGf2zei59iH5qP40lL3bkq49PuWl71g==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-login@3.972.84': + resolution: {integrity: sha512-G9Ty1uIV0laEvEp2KiMbEhsuBAjgaD3KYrwVjAM5VUxpcIuPBqQI5riA7/qzrnSgYiAKQbubbgkwcqCICKCIxg==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-node@3.972.89': + resolution: {integrity: sha512-O8xj7/sanrnXfFHu/LUujVBiiwn5mknYenU7xt1w6+yvhR1QoDZWXLFh1gLITaFVPtb1jWgEirC+kFNw+//tyw==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-process@3.972.77': + resolution: {integrity: sha512-sWA8Jm+ASzkTxoqLizHWRbt8Gj3yZCmZ0hYdvg0uIxuLzWseYcfrDFzaSnkRWlEWSJV38rAWFimdrN0J4NR7Pg==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-sso@3.973.21': + resolution: {integrity: sha512-KV2LM8fbYUhDzGEBnPwb+ISNfNlhmnpLS+y6A6VsJpg1EI9aUJ0+dRTxh2GrGdneFH0T4TiuboHxz8i6+M38JA==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-web-identity@3.972.83': + resolution: {integrity: sha512-iekYilmo2Re51fC7gMkEfZ7jFDXwehSCmXjDESaYQsdgYhsLQFG7rTYr3GBvRIyj+Fkda2NxbZX7hAZDaFD0JQ==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/middleware-sdk-s3@3.972.82': + resolution: {integrity: sha512-MTW3FIYs3yFuSuBKCrm3nWLWzHyz454SPxKQjhY2pcpV4ijKBXselC7wh9VdDstVKJn5ESWx5s1OGvB+p6XUzA==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/nested-clients@3.997.51': + resolution: {integrity: sha512-DJK4iGIHWU8Jh8ODMvqFYcX9yGBMXV4tSZAvqlHF5EDd8hbmF3eFO9KIWOnA7wcQjPzEkyMMW1/FgZ9RU8oimQ==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/s3-request-presigner@3.1157.0': + resolution: {integrity: sha512-zHdXg1UuA4Z2ICQeGCBfSL5A+0TbFCkS6uq4WoX74jpv3PozoPsaDswu2OBU6cIUJLg6JWUZd226SLM/MGHAKA==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/signature-v4-multi-region@3.996.49': + resolution: {integrity: sha512-nvuAZNRrRRVCiARRKsYlQ0VnXiEQiq7vXPH+UA+LSo+kN3Djl9eo/V2r0udkw85PnsNshmv2Em1clld5M3j67w==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/token-providers@3.1157.0': + resolution: {integrity: sha512-AeAzcwWRP2uANO2TjFpKjRdvOCzgfIu6YQl9Ceibd6E0gnq5dfOzujFnq2aeqgbLg4wRtXbUZE4gekCCPrz/OQ==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/types@3.975.0': + resolution: {integrity: sha512-WQlhs6juByzWOzj5fwxOx0mPJaEqMcG/sDpl3Id61B3XhKE63xY+0QWcnG+sWR/sCfprmreyUo1lM7IKZmHMzw==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/xml-builder@3.972.41': + resolution: {integrity: sha512-ctjVSyCMegrWfXlx6VqzSBFI6UqmQ5ZlnfMhdLIiWmhoH8UAQxSCP5N3OpG7X3k4LnS7ou74C4mt20+bfTW2aQ==} + engines: {node: '>=20.0.0'} + + '@aws/lambda-invoke-store@0.3.0': + resolution: {integrity: sha512-sl4Bm6yiMNYrZKkqqDFWN0UfnWhlS8ivKxrYl+6t0gCLrqr8y3B2IqZZbFRkfaVVp7C/baApyh71P+LeE1A2sQ==} + engines: {node: '>=18.0.0'} + + '@babel/runtime@7.29.10': + resolution: {integrity: sha512-NpugTzbKgGrNe45Ui32cN8vCFFMxVtP/9rtfwv0nP5FRDAjvYBxJcLVpYA9mr1jxP6cnIT7x9LUzuDTbWYYNRA==} + engines: {node: '>=6.9.0'} + + '@babel/runtime@8.0.8': + resolution: {integrity: sha512-dEu8nGlRqjsJsvviUUoSMfcRHpwomCiRlXsc2mPfJ79+ffTpDm+JtfUtTMzUrqCApHQnCsVPD3gT1ZT8RgBRCQ==} + + '@base-ui/react@1.9.0': + resolution: {integrity: sha512-S8CSYosASBKtpL8SWUfS78rFElfLijiCgA7oHOK22jCJ95FULsYyKwBNFOgudt0RA+/7yNc7F81bOvQnRgbBiQ==} + engines: {node: '>=14.0.0'} + peerDependencies: + '@date-fns/tz': ^1.2.0 + '@types/react': ^17 || ^18 || ^19 + date-fns: ^4.0.0 + react: ^17 || ^18 || ^19 + react-dom: ^17 || ^18 || ^19 + peerDependenciesMeta: + '@date-fns/tz': + optional: true + '@types/react': + optional: true + date-fns: + optional: true + + '@base-ui/utils@0.5.0': + resolution: {integrity: sha512-dYGGcEttjkYiMoa5nHm8vLaJ2UcuTWxo3BFAwOYXeRg/q7UVVvA6cacEIXEs3FgBfK1CGtW1ptElqs7wsx+t9A==} + peerDependencies: + '@types/react': ^17 || ^18 || ^19 + react: ^17 || ^18 || ^19 + react-dom: ^17 || ^18 || ^19 + peerDependenciesMeta: + '@types/react': + optional: true + + '@better-auth/core@1.7.6': + resolution: {integrity: sha512-yBDDO0J4VCHT1qEZtzj6aMexX4etyLesitoxehcWHzPrzYqrFHwe/hgskye+imlGhQVOysuljMg8M8BA6GrtIg==} + peerDependencies: + '@better-auth/utils': 0.4.2 + '@better-fetch/fetch': 1.3.2 + '@opentelemetry/api': ^1.9.0 + better-call: 1.4.0 + jose: ^6.1.0 + kysely: ^0.28.5 || ^0.29.0 + nanostores: ^1.0.1 + peerDependenciesMeta: + '@opentelemetry/api': + optional: true + + '@better-auth/drizzle-adapter@1.7.6': + resolution: {integrity: sha512-ENlhwC7kkTjquuiel3Efggik0hC4vtD7ppJ8FhsiHhRJA8K6RT4hbhzkfm6keNvjdnAeWwCejm7FmMO4GoSGpA==} + peerDependencies: + '@better-auth/core': ^1.7.6 + '@better-auth/utils': 0.4.2 + drizzle-orm: ^0.45.2 || >=1.0.0-rc.1 <2.0.0 + peerDependenciesMeta: + drizzle-orm: + optional: true + + '@better-auth/kysely-adapter@1.7.6': + resolution: {integrity: sha512-BV+DX2/z/6ozNC9DYSge78wjLerq6Bxd/lSPjzzuq9eEutkQDAJTuiaETzgGYqNV5LlEWi8TZFAQTEq/wavOEQ==} + peerDependencies: + '@better-auth/core': ^1.7.6 + '@better-auth/utils': 0.4.2 + kysely: ^0.28.17 || ^0.29.0 + peerDependenciesMeta: + kysely: + optional: true + + '@better-auth/memory-adapter@1.7.6': + resolution: {integrity: sha512-ng1xv8k2JsEIjnqzJzdoVOQrnoCLRuk4EiQL9yYAThyg6zYzV00LynlhH+O9OMUZ+yGVpGqGZmr5xcTiUSV2uA==} + peerDependencies: + '@better-auth/core': ^1.7.6 + '@better-auth/utils': 0.4.2 + + '@better-auth/mongo-adapter@1.7.6': + resolution: {integrity: sha512-GvBwZli8i4XINMAj9tlW7eV9E8Dr+JWqavXjUs2o81GZt/Vh8wiX+31KK1jQ4iOuejfjpLoXcoFtlIPgf/pVog==} + peerDependencies: + '@better-auth/core': ^1.7.6 + '@better-auth/utils': 0.4.2 + mongodb: ^6.0.0 || ^7.0.0 + peerDependenciesMeta: + mongodb: + optional: true + + '@better-auth/prisma-adapter@1.7.6': + resolution: {integrity: sha512-31rz2OXIx2Q1L4Jhd5F71dafIWqder/Bo6vJ+eCgO5iZ0gvnv7fUmM95DvbVUoPC69XYpcIM/6PJmQ3M6RydWg==} + peerDependencies: + '@better-auth/core': ^1.7.6 + '@better-auth/utils': 0.4.2 + '@prisma/client': ^5.0.0 || ^6.0.0 || ^7.0.0 + prisma: ^5.0.0 || ^6.0.0 || ^7.0.0 + peerDependenciesMeta: + '@prisma/client': + optional: true + prisma: + optional: true + + '@better-auth/telemetry@1.7.6': + resolution: {integrity: sha512-xgRwPja2wTJtcu+OQZR2IiNpAmviddnW3n5Do5umXRugJFW3v9KlSmYjYm580mVsPnU4upvZkvSRl9v8DgSDtA==} + peerDependencies: + '@better-auth/core': ^1.7.6 + '@better-auth/utils': 0.4.2 + '@better-fetch/fetch': 1.3.2 + + '@better-auth/utils@0.4.2': + resolution: {integrity: sha512-AUxrvu+HaaODsUyzDxFgwd/8RZ1yZaYo42LXKSrU2oGgR38pS1ij8nqQKNgtTWoYGpNevNXtCfgTy6loHveW9A==} + + '@better-auth/utils@0.5.1': + resolution: {integrity: sha512-WETqw5vQ52uQ/xwWR4E8rTgT6fDEr/wnS+otDNkBCa/69281FCF32OKDdQUcahMCnjsvqXBNiEvAQHFB0EVRRg==} + + '@better-fetch/fetch@1.3.2': + resolution: {integrity: sha512-Gs7n99b5tqUC6cQAPbV0uED3IraHB6xQbHLQ/C3l7ZFafHScOx9pQ+DYmP5blbLFShVWLqxNUlI9wi4xU/X+ow==} + + '@cacheable/memory@2.2.0': + resolution: {integrity: sha512-CTLKqLItRCEixEAewD3/j9DB3/o96gpTPD4eJ1v+DGOlxZRZncRQkGYqqnAGCscYd6RNeXfGeiuCphsPtqyIfQ==} + + '@cacheable/utils@2.5.0': + resolution: {integrity: sha512-buipgOVDkkPXNR5+xBpDw7Zk2n1EvU7qBJCNUcL7rhQ//kfpOXPAvQ511Os0vpLYJ1pZnvudNytkQt2hst3wqA==} + + '@cloudflare/kv-asset-handler@0.5.0': + resolution: {integrity: sha512-jxQYkj8dSIzc0cD6cMMNdOc1UVjqSqu8BZdor5s8cGjW2I8BjODt/kWPVdY+u9zj3ms75Q5qaZgnxUad83+eAg==} + engines: {node: '>=22.0.0'} + + '@cloudflare/unenv-preset@2.16.2': + resolution: {integrity: sha512-JBP1+Z7ZSNG/d4mRP+y8VC5dka3tZVMLEZRvS+rzQ4DGV1EoxRFQckcJTTkXbHSQiTj0DtNI01Zwb/V2fX0mvQ==} + peerDependencies: + unenv: 2.0.0-rc.24 + workerd: '>1.20260305.0 <2.0.0-0' + peerDependenciesMeta: + workerd: + optional: true + + '@cloudflare/vite-plugin@1.64.0': + resolution: {integrity: sha512-h7Tunx9Ou5fUoao8O9jYTH0ParfrtNZzZVPA0IS19O7AoWA1SpYjwzDA6pZC78qzuV8sQSEOpYCN/yTShmd+gg==} + hasBin: true + peerDependencies: + vite: ^6.1.0 || ^7.0.0 || ^8.0.0 + wrangler: ^4.151.0 + + '@cloudflare/workerd-darwin-64@1.20261012.1': + resolution: {integrity: sha512-dkTL9aY3V4D40b+jBpGPCistWUPFQ/M61wlWi6i1o8MvHFFgEw7EQkcaYEv6Yd3bkPDD/3TFT4hRsMb2xVZSwQ==} + engines: {node: '>=16'} + cpu: [x64] + os: [darwin] + + '@cloudflare/workerd-darwin-64@1.20261019.1': + resolution: {integrity: sha512-5ZILbAta/fBQvhmAYeCE7dKMMYIr7N9wJEX50fEGLKSIwGtvT0HzSfHNIK/O7cBQ4gHQ2WfIiPClvwcye6E0fA==} + engines: {node: '>=16'} + cpu: [x64] + os: [darwin] + + '@cloudflare/workerd-darwin-arm64@1.20261012.1': + resolution: {integrity: sha512-2/nVGcKXjNNI+DhxKSepTKvFng9H7aN2WXv6Zu67iqgI6JrxypNt5kTPv4ZHosxrcfyKMci/2RfN7GIrN0BitQ==} + engines: {node: '>=16'} + cpu: [arm64] + os: [darwin] + + '@cloudflare/workerd-darwin-arm64@1.20261019.1': + resolution: {integrity: sha512-cww2Ab6lVMxpTiEEjKmPI58p5EMo0vYTZSH+3WkqXJdQgc3ES66GuL247+U2B2YWajhhu2tqj7jySrXneU749g==} + engines: {node: '>=16'} + cpu: [arm64] + os: [darwin] + + '@cloudflare/workerd-linux-64@1.20261012.1': + resolution: {integrity: sha512-uMe7ONHnLxStD1Ye0YFHBO36uj4cStv5P53rW+5GVWXFT8BRjqVixlH0IqCAHe1Pmcwyd1+7fVoGde89MZSCJg==} + engines: {node: '>=16'} + cpu: [x64] + os: [linux] + + '@cloudflare/workerd-linux-64@1.20261019.1': + resolution: {integrity: sha512-4++VRi9vkQROYqrpZYOixIJuVDmujkwrT4kszsxNFlvcmsX6Mr2GumvxIN3gIixS3vJUh3Umdtkthqj5X0S3Xw==} + engines: {node: '>=16'} + cpu: [x64] + os: [linux] + + '@cloudflare/workerd-linux-arm64@1.20261012.1': + resolution: {integrity: sha512-I0VMdcXk7ygG5vYDce0ePTBFdnBXC0i9WiBY5mWiv0iTinbfea6/rHqSQ7B1UMpjgrYVs9E0m4bZ9ufsk5GCFA==} + engines: {node: '>=16'} + cpu: [arm64] + os: [linux] + + '@cloudflare/workerd-linux-arm64@1.20261019.1': + resolution: {integrity: sha512-75PVtJOwfjScQ53sbLtQXI7D8yP1c21t+WEUPaYbqkzaz4ZqfR5wAd+zuWs8G5Q7kOj2SQIvEfY5Sn8Y+UVrnA==} + engines: {node: '>=16'} + cpu: [arm64] + os: [linux] + + '@cloudflare/workerd-windows-64@1.20261012.1': + resolution: {integrity: sha512-c5hQvNx574UEoknaCFvMa/NdLrrYiALNbe6sx1okW8uOiRYWxrFuA8WpXFnBJ5XJypm0TEAHYaUTGv3rRLpY7Q==} + engines: {node: '>=16'} + cpu: [x64] + os: [win32] + + '@cloudflare/workerd-windows-64@1.20261019.1': + resolution: {integrity: sha512-z49fvKTETMCnG6wnMcQwxx9CpryFceiKz04FRjq26EkhCyzRNJ6c3UXhyZz3r5f1CXnnBZc5DcU8ZouPkUJCqw==} + engines: {node: '>=16'} + cpu: [x64] + os: [win32] + + '@cloudflare/workers-types@5.20261019.1': + resolution: {integrity: sha512-llvvy7WBVhK+OfykyBkG9A7OgsGvgwHSNyU40XGVkiy/xVFy0t/xflyhEBHT+U59yQECZQbmcZsJtqCNnLpIRg==} + + '@cspotcode/source-map-support@0.8.1': + resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} + engines: {node: '>=12'} + + '@emnapi/runtime@1.11.3': + resolution: {integrity: sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA==} + + '@esbuild/aix-ppc64@0.25.12': + resolution: {integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/aix-ppc64@0.27.7': + resolution: {integrity: sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/aix-ppc64@0.28.2': + resolution: {integrity: sha512-XExcO+dvLKvVtNTibSTBej1NCAbaGhWn9Ww1ZPx80qsahhPFe/8jgWP0IchNe0F3HwkU7n8ejhH8bjonqht8mQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.25.12': + resolution: {integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm64@0.27.7': + resolution: {integrity: sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm64@0.28.2': + resolution: {integrity: sha512-5YfKeeI8qWfBZIX+u2xZC3Zlb3Os/gLS2sbEKM+I4ZOcsWmHS2WLysCcQZDAFRslDUU5Oiq44gf6PYN1vGwG5A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.25.12': + resolution: {integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-arm@0.27.7': + resolution: {integrity: sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-arm@0.28.2': + resolution: {integrity: sha512-kXXoiPVVGQcnIYGOeaovwOURpniDBpSq4A03qkQ+BMQqtGG6HYap3xne9C1O1yo4TR3qxlCX5IqqmX6fFo2Lqg==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.25.12': + resolution: {integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/android-x64@0.27.7': + resolution: {integrity: sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/android-x64@0.28.2': + resolution: {integrity: sha512-O387ite7SzUyCcy3JQX4P4bLtEA7bLLkx+esve5JHnyYfNTxcVpXZo9jhdB0lTKN44gztELTdU7nS8Nr16Fs1Q==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.25.12': + resolution: {integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-arm64@0.27.7': + resolution: {integrity: sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-arm64@0.28.2': + resolution: {integrity: sha512-n4KqkOQrraxHJcgjM1RvwbigfQKIKJVpM7xp+KsxiyUSrRdIXnt73VhrPAx0fV44hgfmIVKjxMN9J1t5jySVkw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.25.12': + resolution: {integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/darwin-x64@0.27.7': + resolution: {integrity: sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/darwin-x64@0.28.2': + resolution: {integrity: sha512-uq6suIWYP37qzGddBKPw5QEQPi6HiLGsO7UmkpfyaYNQ3D+rN6w6WfwH+nuqcGXWvawGwxOEroO4YGnFh95azw==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.25.12': + resolution: {integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-arm64@0.27.7': + resolution: {integrity: sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-arm64@0.28.2': + resolution: {integrity: sha512-n+I0BTSRIoy+d6RPKnEVwql5UwBJolytvY4mAOIEJorKlqgPII8ix6slVVrfZ5Tnj7glIZvloylbB/EJPMWEXw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.25.12': + resolution: {integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.27.7': + resolution: {integrity: sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.28.2': + resolution: {integrity: sha512-78XJTJkvPs0kz2w61301PJjXl4g7q3JqiYMZ/M/yVI73EHBrCRTgkhu9oqG7vPqq+a/yadEW8aD+agKlk5xrmg==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.25.12': + resolution: {integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm64@0.27.7': + resolution: {integrity: sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm64@0.28.2': + resolution: {integrity: sha512-pW4AC0P3it8c7do9MVM4p51FzHzdM/TZrerurgRcHJ2WTa1VQ1CIq18xncfpBJw4ojkiZZrKW2yIBWBP92j6Ug==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.25.12': + resolution: {integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-arm@0.27.7': + resolution: {integrity: sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-arm@0.28.2': + resolution: {integrity: sha512-XlDnu2q5yoqems+xay6wSAcg9DDD7K9RLKZEBOMZm3ckNpJBvOX20tSfby8KfrrhINDyv9V2YVZKY/SpoGJI8w==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.25.12': + resolution: {integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-ia32@0.27.7': + resolution: {integrity: sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-ia32@0.28.2': + resolution: {integrity: sha512-CYbnj78HsIeA+DhgUKgFCfvNsTHFhMMrinUrMZpDXJXKN8T3XViTZ/+wtHeVxEWY8ewSzTFN+nRmSwO2tZaLUQ==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.25.12': + resolution: {integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-loong64@0.27.7': + resolution: {integrity: sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-loong64@0.28.2': + resolution: {integrity: sha512-buwkd8nsph4R+ajRvw0qM5Hja/TXQow3ptzWO2EbG/cqcIkHloRrdlBtQlshyYGTNFvfkfJ5tpPLVkY4DtsPfQ==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.25.12': + resolution: {integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-mips64el@0.27.7': + resolution: {integrity: sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-mips64el@0.28.2': + resolution: {integrity: sha512-ZVykbDyk7519VwiNb9Lcj9m8XM6v5V9uKPvrEMkkEedVewf+0itkhahp4HDpgERXhwLRpWFypsGbG/J8s0QjJA==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.25.12': + resolution: {integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-ppc64@0.27.7': + resolution: {integrity: sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-ppc64@0.28.2': + resolution: {integrity: sha512-CAXl+Dtd9UUuJd8pKKdwh6MLm3MUMiqMPmhZ3tTSXPqfyQ3vDl6R5hZdZ/kYojK4ofXtdfSv1tFq8XzWx3heNQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.25.12': + resolution: {integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-riscv64@0.27.7': + resolution: {integrity: sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-riscv64@0.28.2': + resolution: {integrity: sha512-GeXCej4IQtU1B+QlDV8W/RRvbzI3O/Stss+/bCXv4lZls5WGRtu2a+3JkA3i4qIUlMXpcHebWpF8AkJhATowuA==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.25.12': + resolution: {integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-s390x@0.27.7': + resolution: {integrity: sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-s390x@0.28.2': + resolution: {integrity: sha512-3H1weTYZPxt/WOhByszQZybS9w5lKzUn1FDMsgEChbHWQwHYQQRfBxgCcZvPhjHfKyJjIievvMmEUawJrdY9Dg==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.25.12': + resolution: {integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/linux-x64@0.27.7': + resolution: {integrity: sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/linux-x64@0.28.2': + resolution: {integrity: sha512-4xTZr1FUmSoQW4XIWmit3tzQrUTZM+N3P0XV8xROKYF50XfI7xeO90+1bZvNwxIufQ9hDQVRJH5YhgPVF8A/HQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-arm64@0.25.12': + resolution: {integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + + '@esbuild/netbsd-arm64@0.27.7': + resolution: {integrity: sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + + '@esbuild/netbsd-arm64@0.28.2': + resolution: {integrity: sha512-sSATRjPeDBg3pdgHoQfoYBob11Kk1FGa9lui5RIHZCoCkJa9QKlvl3/vKz2usCmYYjs7ymJR/2Nnsqe+Hjt5nw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.25.12': + resolution: {integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.27.7': + resolution: {integrity: sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.28.2': + resolution: {integrity: sha512-lqnzCV+mM0gIADaKihiCg6ifgfU2L3h5E33rNQBN1Y4MaVGnzryzmvvf7UHxprpQdE8hpqLolJ9Rl+SkIRDpyw==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-arm64@0.25.12': + resolution: {integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-arm64@0.27.7': + resolution: {integrity: sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-arm64@0.28.2': + resolution: {integrity: sha512-AL2qJILH7lNjrDmCQDvdxMfAUIv8KMNZOvrwAQ8i8//ntL9FflhOyMJ8OZSMBb8/AWXe3/5v5S20y3zCoZWKoQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.25.12': + resolution: {integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.27.7': + resolution: {integrity: sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.28.2': + resolution: {integrity: sha512-QtiuPytchRyC4rwUKhexJdQKvDuZ6hWloi3igqPQNUJCS1/v9EiO3UTOXR6A3FoMo4fnAKbWJdqaIwhOzh8qEw==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openharmony-arm64@0.25.12': + resolution: {integrity: sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + + '@esbuild/openharmony-arm64@0.27.7': + resolution: {integrity: sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + + '@esbuild/openharmony-arm64@0.28.2': + resolution: {integrity: sha512-WkhYDmpTjLvGlScA1rwjRUmhl4k8oXR3cIbtqWmELgU/dFeHHlEllxDvdWcNJV9rbzCexB5vz8gtNewWLgCT7Q==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + + '@esbuild/sunos-x64@0.25.12': + resolution: {integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/sunos-x64@0.27.7': + resolution: {integrity: sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/sunos-x64@0.28.2': + resolution: {integrity: sha512-GPMSkTOtMnv2U2F8gxe4Io6qmVs+YKyp832Etqqxr0hFngmXQ3rzwytelm3GIn7T4VviRUlf3sOgBOiTdvaf7g==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.25.12': + resolution: {integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-arm64@0.27.7': + resolution: {integrity: sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-arm64@0.28.2': + resolution: {integrity: sha512-PIhhEkE9uPBleRBrQEJpUn7MBnibZzbGzYWPmY3x+YoVg/95zbjB4CxPPOQ8l5tYYM4mMaCthF8/1DIfBQQyWQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.25.12': + resolution: {integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-ia32@0.27.7': + resolution: {integrity: sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-ia32@0.28.2': + resolution: {integrity: sha512-YmJbfTlvU7Sdn9BB+4PRES4oB6pxgS37MAONj+hBr/cpXS1aBPKXxNnDbu+QCWPj0o9dgyxeq79g6c5P8KeuYA==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.25.12': + resolution: {integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + + '@esbuild/win32-x64@0.27.7': + resolution: {integrity: sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + + '@esbuild/win32-x64@0.28.2': + resolution: {integrity: sha512-5ebpxr3nWMzrL/rnUI755Jkuee0bHL/Gq0WTF9lvcpv73wAp5eu8MfBUgWK9bhWvZjj7yX8etf/8tI8Ney695g==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + + '@eslint-community/eslint-utils@4.10.1': + resolution: {integrity: sha512-cuadcxVFE8sDK6iWJbs8Sn0av2Nrh2QSGQhVlBW9AaAHqHwjWsZHT8LJ4hFGPh7ASBV2deFdM7H/DPjulmh8rg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + + '@eslint-community/regexpp@4.12.2': + resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + + '@eslint/config-array@0.23.5': + resolution: {integrity: sha512-Y3kKLvC1dvTOT+oGlqNQ1XLqK6D1HU2YXPc52NmAlJZbMMWDzGYXMiPRJ8TYD39muD/OTjlZmNJ4ib7dvSrMBA==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + + '@eslint/config-helpers@0.7.0': + resolution: {integrity: sha512-DObd/KKUsU+FaFv4PLxSRenpXfQWmPXXP3pPZ6/K1PCrMu2vQpMDMuQe/BqYeoLcz8ro0bVDF1RxOJgfVEdhUw==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + + '@eslint/core@1.2.1': + resolution: {integrity: sha512-MwcE1P+AZ4C6DWlpin/OmOA54mmIZ/+xZuJiQd4SyB29oAJjN30UW9wkKNptW2ctp4cEsvhlLY/CsQ1uoHDloQ==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + + '@eslint/object-schema@3.0.5': + resolution: {integrity: sha512-vqTaUEgxzm+YDSdElad6PiRoX4t8VGDjCtt05zn4nU810UIx/uNEV7/lZJ6KwFThKZOzOxzXy48da+No7HZaMw==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + + '@eslint/plugin-kit@0.7.3': + resolution: {integrity: sha512-IkO+/KEUvwbVpiURZg+P7zF74z5Jxe0UgJxVni+RtoHQ6IZieXaO02kmadomap/q+l6bc/jdPGGqTjhuZnuz1Q==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + + '@floating-ui/core@1.8.0': + resolution: {integrity: sha512-0CIZ5itps/8x7BG8dEIhs53BvCUH2PCoogtakwRTut+Arm58sJooJ0AuZhLw2HJYIR5cMLNPBSS728sPho2khQ==} + + '@floating-ui/dom@1.8.0': + resolution: {integrity: sha512-yXSrzeHZBTZadLOlfyhCkJHNeLJnHRnRInwdZ40L7ZiaAtrBwoYlsDrX3v5zB1Utk7CLfzcOVnVVWoXEky7Ceg==} + + '@floating-ui/react-dom@2.1.9': + resolution: {integrity: sha512-JDjEFGCpImxDCA7JJKviA0M9+RtmJdj0m/NVU5IMgBK+AmZouAQQ7/+2GLH0GXXY0YMw9oXPB8hKdbPYg5QLYg==} + peerDependencies: + react: '>=16.8.0' + react-dom: '>=16.8.0' + + '@floating-ui/utils@0.2.12': + resolution: {integrity: sha512-HpCo8tmWzLVad5s2d19EhAz5zqrrQ6s69qd6moPMQvkOuSwDT1YgRfWSVuc4ennqrgv3OHppiOGMQ7oC13yIww==} + + '@fuma-translate/react@1.0.2': + resolution: {integrity: sha512-uOiOtBx3nRXR8Nu1GzBf1tApgF1FErDBTHxRIAQeyQdyOoZbrNRN6H4kDCWObY4qyGeGbHydG0DHzgeUgFDMIw==} + peerDependencies: + '@types/react': '*' + react: ^19.2.0 + react-dom: ^19.2.0 + peerDependenciesMeta: + '@types/react': + optional: true + + '@fumadocs/base-ui@16.17.7': + resolution: {integrity: sha512-t9Am0mxPrGuAG9BeC/ACLhNbBtxXbc+JIbTTzr7j5apnCFRQSDxGaZT9/+BRWG6DqltnsccGqGB1x3kPz7WaYw==} + peerDependencies: + '@types/mdx': '*' + '@types/react': '*' + fumadocs-core: 16.17.7 + next: 16.x.x + react: ^19.2.0 + react-dom: ^19.2.0 + takumi-js: '*' + peerDependenciesMeta: + '@types/mdx': + optional: true + '@types/react': + optional: true + next: + optional: true + takumi-js: + optional: true + + '@fumadocs/tailwind@0.1.4': + resolution: {integrity: sha512-1LAmuroJ6TJoQodyODRhMC9ThAkfrV2N5vZjaj4KKs+dpF2bs0d/2z0604iMKBLv2BKstR7zE9TUa/L0pxGnhA==} + peerDependencies: + tailwindcss: ^4.0.0 + peerDependenciesMeta: + tailwindcss: + optional: true + + '@fumari/image-size@0.1.1': + resolution: {integrity: sha512-iaiV2wyzJ4mW358NX4CX3yGit+WjKYzpaQ+rldK9BjL/5jFpeV6ruWnZVq7MEyMn3Gd0DLi8g/79NZAAQaGscw==} + + '@hookform/resolvers@3.10.0': + resolution: {integrity: sha512-79Dv+3mDF7i+2ajj7SkypSKHhl1cbln1OGavqrsF7p6mbUv11xpqpacPsGDCTRvCSjEEIez2ef1NveSVL3b0Ag==} + peerDependencies: + react-hook-form: ^7.0.0 + + '@humanfs/core@0.19.2': + resolution: {integrity: sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==} + engines: {node: '>=18.18.0'} + + '@humanfs/node@0.16.8': + resolution: {integrity: sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==} + engines: {node: '>=18.18.0'} + + '@humanfs/types@0.15.0': + resolution: {integrity: sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==} + engines: {node: '>=18.18.0'} + + '@humanwhocodes/module-importer@1.0.1': + resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} + engines: {node: '>=12.22'} + + '@humanwhocodes/retry@0.4.3': + resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} + engines: {node: '>=18.18'} + + '@img/colour@1.1.0': + resolution: {integrity: sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==} + engines: {node: '>=18'} + + '@img/sharp-darwin-arm64@0.35.5': + resolution: {integrity: sha512-QRUlFQ0WxvdWyqqG/WtI3iupfD5rBzmCHXSdPsY91sAtVtTo7Q4cb6zOccZ3gqEqkr0f1As1ehLqmEpDsRf+lg==} + engines: {node: '>=20.9.0'} + cpu: [arm64] + os: [darwin] + + '@img/sharp-darwin-x64@0.35.5': + resolution: {integrity: sha512-+BR255RhDlpygUpOc/Jdt1nT6DQ3XG/ERo5wbcdOf5Q320dKtPCKPLR1LJs9VGXRaMa8l1uUa0tkCNOXiAxZUw==} + engines: {node: '>=20.9.0'} + cpu: [x64] + os: [darwin] + + '@img/sharp-freebsd-wasm32@0.35.5': + resolution: {integrity: sha512-Y/z91nEZ4uIBX5X3nfTovjU9lHNKFYbL2lpHCLVNmXQK03VIZvXBBt0KxbPGp2SdGSF+2mQU4e+hQaWOt86iAw==} + engines: {node: '>=20.9.0'} + os: [freebsd] + + '@img/sharp-libvips-darwin-arm64@1.3.4': + resolution: {integrity: sha512-5R89nBYiRdUlSWJxPhO+GVtaXzXSxKnRu/xqMn3KTA3L9EB9Oy/P+Nn2f2vlhPuUdy/Zusb2DarbyTpGCfEDuw==} + cpu: [arm64] + os: [darwin] + + '@img/sharp-libvips-darwin-x64@1.3.4': + resolution: {integrity: sha512-iR2OKH80yi0U+dUplyh3/xdpFvps6YkCwsXenIJxqxR1v9o+xtKTGbS9H7cps+2Vxjc8B1j96p75NmTGjIhtpQ==} + cpu: [x64] + os: [darwin] + + '@img/sharp-libvips-linux-arm64@1.3.4': + resolution: {integrity: sha512-Y3dgX/6lE2QhQb+Gxy0WZxfg9MEm/JBjamZpS2IklP7xIQoKN4hzAm7KcMVGtaVDt3neE9OKBC7vAfonA/Lr1A==} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-arm@1.3.4': + resolution: {integrity: sha512-LmRtTsOHuvM2+wlO2Db37dx5MiZhB0FvSunciw48YjdOkZz9KAiRbm8ujeMOA1INqmei5NapFxYEK1D1ZSidmw==} + cpu: [arm] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-ppc64@1.3.4': + resolution: {integrity: sha512-Le6boB8Tai0Nis+gIxIpKx68UDVVIqdR8Tin5Yf1z2LJJQLDJvCDRqRu+jC2qCoD+eIomonmOwB4smBRxfVpYQ==} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-riscv64@1.3.4': + resolution: {integrity: sha512-aHkkIEHPRdQEegJN20MLmGtxYD9R2wQr3Cwpddnu5+YKMt6Uzax7S9h5gpZTo8wyrGuZSlfQ63OevL5mTyOC7Q==} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-s390x@1.3.4': + resolution: {integrity: sha512-ra/mB6MikESDUO7Yg+Mi95bFBb9GsObURuhnOv3OqknjGe9sZrG8tCe9q0xSIGrtLgvgw0gKnFWcK4blSgQOuQ==} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-x64@1.3.4': + resolution: {integrity: sha512-GJ//SSXbnwSDes02umB3nDJLFcQzw8a18V8fyhqr6tV515tOEMdImjjxj1AoafMRz56F3PHgftnj1QEKSU1zkw==} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linuxmusl-arm64@1.3.4': + resolution: {integrity: sha512-hvulFwtjUcagsis6BBxHwGFwWoNZjgYmULGVrZcyfNbjA8hKILbRxGg15/7w5HDyXHXUos/j6baAWqnCyQ2DWA==} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@img/sharp-libvips-linuxmusl-x64@1.3.4': + resolution: {integrity: sha512-6zXKeE/p39I1AmA3cJG35eyBGNqNddLnUXjhwBnsGjFPWqf5VKkDBEqaEkPDoTEtkxwi2vv8Tcr2mDyP4So7Fg==} + cpu: [x64] + os: [linux] + libc: [musl] + + '@img/sharp-linux-arm64@0.35.5': + resolution: {integrity: sha512-LYVx5JTsOM2CBzmxreh+nl64/3H6Xb09iSLknqH47z2T2DFFxDeFLP5y4dJwe6H7uGQlHPyEEtIqyo3DYsRwdQ==} + engines: {node: '>=20.9.0'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-arm@0.35.5': + resolution: {integrity: sha512-LEaXK2WdXVK5ykcw0buWyPMsmLLL2vpHLD6yrNSW+JGEL3BZPA4tpKN6iaMc4AxTTAoaX/sU1rOL51lcIz48ZQ==} + engines: {node: '>=20.9.0'} + cpu: [arm] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-ppc64@0.35.5': + resolution: {integrity: sha512-QVxAAq8evVRI9ia2vqgwrmWucn5Dfv+JdWzj75pD8omHLPSP7f8p20O8jxzjCcuCEQEOtYOZUmX1hkiZ0kdevA==} + engines: {node: '>=20.9.0'} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-riscv64@0.35.5': + resolution: {integrity: sha512-LtdreXguaavKODPIfzJ4kffx7UNt1omwtK0rch4EBbbSTXPnxWmYSayXdLJw0fJzQ97kHt1gL/yh4tvU+nCyRQ==} + engines: {node: '>=20.9.0'} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-s390x@0.35.5': + resolution: {integrity: sha512-UZasTOFiYzotTsGOCu42BfUzP6Tu6Do/947iRm1RsLKvlllxwGcn4RN27LibGWceix4Y+Pmw3jsnTcCQIgWjqA==} + engines: {node: '>=20.9.0'} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-x64@0.35.5': + resolution: {integrity: sha512-SxFtLTeJInhAA9Q836kux2vZNeOBQEx658qvbboZScr0wIARym3IcGmW7KpVD5sbVg0Ojy+udFQdayYIZyoNog==} + engines: {node: '>=20.9.0'} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@img/sharp-linuxmusl-arm64@0.35.5': + resolution: {integrity: sha512-9HbMclmI1zlNkFRs3z9/eBtDjfD0sGlrX1z6b1qwmiFY5ElDLh4BC0LPBdVp7z1DXFiKlIcznf+ZlsuZzLxQqg==} + engines: {node: '>=20.9.0'} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@img/sharp-linuxmusl-x64@0.35.5': + resolution: {integrity: sha512-4KOphqB035HrVdqLZfCgMzzERrQkkzOwRhl4OAkRO1YCldbaFjySXMaK534Mo0V+LndnlJk+sbUyLeU0ULyD1A==} + engines: {node: '>=20.9.0'} + cpu: [x64] + os: [linux] + libc: [musl] + + '@img/sharp-wasm32@0.35.5': + resolution: {integrity: sha512-Ptsga1su4tQx+LLF1ECS9U6nz5kmrXKo6XVbtR48Ke3ZRxxgaWBu7IDtEe1quo8hiupwm6WFqxVlXaSf7IINGQ==} + engines: {node: '>=20.9.0'} + + '@img/sharp-webcontainers-wasm32@0.35.5': + resolution: {integrity: sha512-hfhF/FmoQyTUkA0bIKFOtw536BQSeBMe6BF6QyWlrPxT754+TFLaZ7sKKTfvvM0yJgKgaYTwnFCIZ/GuDw5SUA==} + engines: {node: '>=20.9.0'} + cpu: [wasm32] + + '@img/sharp-win32-arm64@0.35.5': + resolution: {integrity: sha512-X4t7g+7ZA5DKblCBEXGjUqqemj4vczING/5viFwAL8h4N3qYeyjwdCvRLHi4EdOUI+2Z7UFlp1VM+p/AuEtm6Q==} + engines: {node: '>=20.9.0'} + cpu: [arm64] + os: [win32] + + '@img/sharp-win32-ia32@0.35.5': + resolution: {integrity: sha512-5Zm82LoBc43nhwNybZlG7Y1KO//Zhsn306fQl29ZOuStHLGTo3BWL83q3cznX0poxSAMuYL1On/BHBxkBeKr6A==} + engines: {node: ^20.9.0} + cpu: [ia32] + os: [win32] + + '@img/sharp-win32-x64@0.35.5': + resolution: {integrity: sha512-x76eH0vEiHlcMQu8Y8IenntaACtddpT6W0wmXtWrnKcnKI7ME5DdgqhAD6SEWOEl1v2zDvkZDhFA9KnURwpfqg==} + engines: {node: '>=20.9.0'} + cpu: [x64] + os: [win32] + + '@inquirer/ansi@1.0.2': + resolution: {integrity: sha512-S8qNSZiYzFd0wAcyG5AXCvUHC5Sr7xpZ9wZ2py9XR88jUz8wooStVx5M6dRzczbBWjic9NP7+rY0Xi7qqK/aMQ==} + engines: {node: '>=18'} + + '@inquirer/checkbox@4.3.2': + resolution: {integrity: sha512-VXukHf0RR1doGe6Sm4F0Em7SWYLTHSsbGfJdS9Ja2bX5/D5uwVOEjr07cncLROdBvmnvCATYEWlHqYmXv2IlQA==} + engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@inquirer/confirm@5.1.21': + resolution: {integrity: sha512-KR8edRkIsUayMXV+o3Gv+q4jlhENF9nMYUZs9PA2HzrXeHI8M5uDag70U7RJn9yyiMZSbtF5/UexBtAVtZGSbQ==} + engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@inquirer/core@10.3.2': + resolution: {integrity: sha512-43RTuEbfP8MbKzedNqBrlhhNKVwoK//vUFNW3Q3vZ88BLcrs4kYpGg+B2mm5p2K/HfygoCxuKwJJiv8PbGmE0A==} + engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@inquirer/editor@4.2.23': + resolution: {integrity: sha512-aLSROkEwirotxZ1pBaP8tugXRFCxW94gwrQLxXfrZsKkfjOYC1aRvAZuhpJOb5cu4IBTJdsCigUlf2iCOu4ZDQ==} + engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@inquirer/expand@4.0.23': + resolution: {integrity: sha512-nRzdOyFYnpeYTTR2qFwEVmIWypzdAx/sIkCMeTNTcflFOovfqUk+HcFhQQVBftAh9gmGrpFj6QcGEqrDMDOiew==} + engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@inquirer/external-editor@1.0.3': + resolution: {integrity: sha512-RWbSrDiYmO4LbejWY7ttpxczuwQyZLBUyygsA9Nsv95hpzUWwnNTVQmAq3xuh7vNwCp07UTmE5i11XAEExx4RA==} + engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@inquirer/figures@1.0.15': + resolution: {integrity: sha512-t2IEY+unGHOzAaVM5Xx6DEWKeXlDDcNPeDyUpsRc6CUhBfU3VQOEl+Vssh7VNp1dR8MdUJBWhuObjXCsVpjN5g==} + engines: {node: '>=18'} + + '@inquirer/input@4.3.1': + resolution: {integrity: sha512-kN0pAM4yPrLjJ1XJBjDxyfDduXOuQHrBB8aLDMueuwUGn+vNpF7Gq7TvyVxx8u4SHlFFj4trmj+a2cbpG4Jn1g==} + engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@inquirer/number@3.0.23': + resolution: {integrity: sha512-5Smv0OK7K0KUzUfYUXDXQc9jrf8OHo4ktlEayFlelCjwMXz0299Y8OrI+lj7i4gCBY15UObk76q0QtxjzFcFcg==} + engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@inquirer/password@4.0.23': + resolution: {integrity: sha512-zREJHjhT5vJBMZX/IUbyI9zVtVfOLiTO66MrF/3GFZYZ7T4YILW5MSkEYHceSii/KtRk+4i3RE7E1CUXA2jHcA==} + engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@inquirer/prompts@7.10.1': + resolution: {integrity: sha512-Dx/y9bCQcXLI5ooQ5KyvA4FTgeo2jYj/7plWfV5Ak5wDPKQZgudKez2ixyfz7tKXzcJciTxqLeK7R9HItwiByg==} + engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@inquirer/rawlist@4.1.11': + resolution: {integrity: sha512-+LLQB8XGr3I5LZN/GuAHo+GpDJegQwuPARLChlMICNdwW7OwV2izlCSCxN6cqpL0sMXmbKbFcItJgdQq5EBXTw==} + engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@inquirer/search@3.2.2': + resolution: {integrity: sha512-p2bvRfENXCZdWF/U2BXvnSI9h+tuA8iNqtUKb9UWbmLYCRQxd8WkvwWvYn+3NgYaNwdUkHytJMGG4MMLucI1kA==} + engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@inquirer/select@4.4.2': + resolution: {integrity: sha512-l4xMuJo55MAe+N7Qr4rX90vypFwCajSakx59qe/tMaC1aEHWLyw68wF4o0A4SLAY4E0nd+Vt+EyskeDIqu1M6w==} + engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@inquirer/type@3.0.10': + resolution: {integrity: sha512-BvziSRxfz5Ov8ch0z/n3oijRSEcEsHnhggm4xFZe93DHcUCTlutlq9Ox4SVENAfcRD22UQq7T/atg9Wr3k09eA==} + engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@jridgewell/gen-mapping@0.3.13': + resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} + + '@jridgewell/remapping@2.3.5': + resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/source-map@0.3.11': + resolution: {integrity: sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==} + + '@jridgewell/sourcemap-codec@1.6.0': + resolution: {integrity: sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==} + + '@jridgewell/trace-mapping@0.3.31': + resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + + '@jridgewell/trace-mapping@0.3.9': + resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} + + '@keyv/bigmap@1.3.1': + resolution: {integrity: sha512-WbzE9sdmQtKy8vrNPa9BRnwZh5UF4s1KTmSK0KUVLo3eff5BlQNNWDnFOouNpKfPKDnms9xynJjsMYjMaT/aFQ==} + engines: {node: '>= 18'} + peerDependencies: + keyv: ^5.6.0 + + '@keyv/serialize@1.1.1': + resolution: {integrity: sha512-dXn3FZhPv0US+7dtJsIi2R+c7qWYiReoEh5zUntWCf4oSpMNib8FDhSoed6m3QyZdx5hK7iLFkYk3rNxwt8vTA==} + + '@libsql/client@0.17.4': + resolution: {integrity: sha512-lYayFWasDV78A+TjlEhr6ubb3odBV6OHjb+wdp8VQcyWWAEIjuwbCHaraEUS4m4yWoo0BvZo96It4VdzZRmRWw==} + + '@libsql/core@0.17.4': + resolution: {integrity: sha512-LqF9gIvnJ38nmAH1y/ChizHqDO/MO1wLgA96XrraulEEbqXxLjleSH92YWTolbuJKgPUmGu4aJk9W3UnAcxLOQ==} + + '@libsql/darwin-arm64@0.5.29': + resolution: {integrity: sha512-K+2RIB1OGFPYQbfay48GakLhqf3ArcbHqPFu7EZiaUcRgFcdw8RoltsMyvbj5ix2fY0HV3Q3Ioa/ByvQdaSM0A==} + cpu: [arm64] + os: [darwin] + + '@libsql/darwin-x64@0.5.29': + resolution: {integrity: sha512-OtT+KFHsKFy1R5FVadr8FJ2Bb1mghtXTyJkxv0trocq7NuHntSki1eUbxpO5ezJesDvBlqFjnWaYYY516QNLhQ==} + cpu: [x64] + os: [darwin] + + '@libsql/hrana-client@0.10.0': + resolution: {integrity: sha512-OoA4EMqRAC7kn7V2P6EQqRcpZf2W+AjsNIyCizBg339Tq/aMC7sRnzs3SklderhmQWAqEzvv8A2vhxVmWpkVvw==} + + '@libsql/isomorphic-ws@0.1.5': + resolution: {integrity: sha512-DtLWIH29onUYR00i0GlQ3UdcTRC6EP4u9w/h9LxpUZJWRMARk6dQwZ6Jkd+QdwVpuAOrdxt18v0K2uIYR3fwFg==} + + '@libsql/kysely-libsql@0.4.1': + resolution: {integrity: sha512-mCTa6OWgoME8LNu22COM6XjKBmcMAvNtIO6DYM10jSAFq779fVlrTKQEmXIB8TwJVU65dA5jGCpT8gkDdWS0HQ==} + peerDependencies: + kysely: '*' + + '@libsql/linux-arm-gnueabihf@0.5.29': + resolution: {integrity: sha512-CD4n4zj7SJTHso4nf5cuMoWoMSS7asn5hHygsDuhRl8jjjCTT3yE+xdUvI4J7zsyb53VO5ISh4cwwOtf6k2UhQ==} + cpu: [arm] + os: [linux] + + '@libsql/linux-arm-musleabihf@0.5.29': + resolution: {integrity: sha512-2Z9qBVpEJV7OeflzIR3+l5yAd4uTOLxklScYTwpZnkm2vDSGlC1PRlueLaufc4EFITkLKXK2MWBpexuNJfMVcg==} + cpu: [arm] + os: [linux] + + '@libsql/linux-arm64-gnu@0.5.29': + resolution: {integrity: sha512-gURBqaiXIGGwFNEaUj8Ldk7Hps4STtG+31aEidCk5evMMdtsdfL3HPCpvys+ZF/tkOs2MWlRWoSq7SOuCE9k3w==} + cpu: [arm64] + os: [linux] + + '@libsql/linux-arm64-musl@0.5.29': + resolution: {integrity: sha512-fwgYZ0H8mUkyVqXZHF3mT/92iIh1N94Owi/f66cPVNsk9BdGKq5gVpoKO+7UxaNzuEH1roJp2QEwsCZMvBLpqg==} + cpu: [arm64] + os: [linux] + + '@libsql/linux-x64-gnu@0.5.29': + resolution: {integrity: sha512-y14V0vY0nmMC6G0pHeJcEarcnGU2H6cm21ZceRkacWHvQAEhAG0latQkCtoS2njFOXiYIg+JYPfAoWKbi82rkg==} + cpu: [x64] + os: [linux] + + '@libsql/linux-x64-musl@0.5.29': + resolution: {integrity: sha512-gquqwA/39tH4pFl+J9n3SOMSymjX+6kZ3kWgY3b94nXFTwac9bnFNMffIomgvlFaC4ArVqMnOZD3nuJ3H3VO1w==} + cpu: [x64] + os: [linux] + + '@libsql/win32-x64-msvc@0.5.29': + resolution: {integrity: sha512-4/0CvEdhi6+KjMxMaVbFM2n2Z44escBRoEYpR+gZg64DdetzGnYm8mcNLcoySaDJZNaBd6wz5DNdgRmcI4hXcg==} + cpu: [x64] + os: [win32] + + '@mdx-js/mdx@3.1.1': + resolution: {integrity: sha512-f6ZO2ifpwAQIpzGWaBQT2TXxPv6z3RBzQKpVftEWN78Vl/YweF1uwussDx8ECAXVtr3Rs89fKyG9YlzUs9DyGQ==} + + '@mikro-orm/cli@7.2.1': + resolution: {integrity: sha512-YNt8HKsb90awZqcionp1oZgL2ZLRyGl76x0lYdcfVkYkYY0zrNQs3ZZ76+6AS/FXSX5oEp6q94LCIiYwnr04jA==} + engines: {node: '>= 22.17.0'} + hasBin: true + + '@mikro-orm/core@7.2.1': + resolution: {integrity: sha512-+gtJoScbin/C3wPItSZkj5vlMTq/LphBLIxHyi5brCbeA6VDcYuoMopiqoFUMQxdhXXrZlKNIHXGrhb8r3biVg==} + engines: {node: '>= 22.17.0'} + peerDependencies: + dataloader: 2.2.3 + peerDependenciesMeta: + dataloader: + optional: true + + '@mikro-orm/libsql@7.2.1': + resolution: {integrity: sha512-jXvptoHpbzfj8XUy5V5BvVee2LOsxgI/GnITfmh6Jl42tpIEDJx6Talqbv+z1PNGkHhw8OU5GoHXDJqYpNqo5w==} + engines: {node: '>= 22.17.0'} + peerDependencies: + '@mikro-orm/core': 7.2.1 + + '@mikro-orm/migrations@7.2.1': + resolution: {integrity: sha512-sxGcB7na0AkcREsD5U3xP+Psb/nhQFkx7/eY1Nsqq9MBs67O5RoCL97bn3lmgq6GwKZFbktMuuOGozq42+GaNg==} + engines: {node: '>= 22.17.0'} + peerDependencies: + '@mikro-orm/core': 7.2.1 + + '@mikro-orm/mysql@7.2.1': + resolution: {integrity: sha512-IxCEnfHUzFcxVkRCVaC0KtGoHRRLogxxgeI+J4Pk7oxtDf/jtvYQuFL4tSbmlrH3qzmLQeYYPyJPuDr+a2F7ag==} + engines: {node: '>= 22.17.0'} + peerDependencies: + '@mikro-orm/core': 7.2.1 + + '@mikro-orm/postgresql@7.2.1': + resolution: {integrity: sha512-PQ1qe4Bj/hQSHYJjR02l06FfEDwniAvncduwZSCLSKuaCUddHc5AN2Utj3yo4xRIVRY8pOa7DFitEQPBozTMJA==} + engines: {node: '>= 22.17.0'} + peerDependencies: + '@mikro-orm/core': 7.2.1 + + '@mikro-orm/sql@7.2.1': + resolution: {integrity: sha512-3M9dQeUDLlvAT5VJr/KBGAk9C7xez+psVCnvNkAO4hRhwx2Wm7N1HkuyP4Bwj0MjkHVB6LYvhTw/V6pYsVM8lA==} + engines: {node: '>= 22.17.0'} + peerDependencies: + '@mikro-orm/core': 7.2.1 + + '@mikro-orm/sqlite@7.2.1': + resolution: {integrity: sha512-+iAPGORAqLl+TcBF+JSLOfRq+PwTQG1NLts+AvN9D8C2czlbDpyjyeaAFSR+5wJlMEZ4wv2rdzt4jSS5T7x3XQ==} + engines: {node: '>= 22.17.0'} + peerDependencies: + '@mikro-orm/core': 7.2.1 + + '@napi-rs/lzma-linux-x64-gnu@1.5.1': + resolution: {integrity: sha512-oTXEIha4SsuXdTA4Iyskj0kpdx2yVXdhd75c2v3xGrHFfVMsbhTPZU/nMPL4sWKo4pBHm3aucLaqGlF696dTyQ==} + engines: {node: ^22.20 || ^24.12 || >=25} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@neon-rs/load@0.0.4': + resolution: {integrity: sha512-kTPhdZyTQxB+2wpiRcFWrDcejc4JI6tkPuS7UZCG4l6Zvc5kU/gGQ/ozvHTh1XR5tS+UlfAfGuPajjzQjCiHCw==} + + '@next/env@14.2.35': + resolution: {integrity: sha512-DuhvCtj4t9Gwrx80dmz2F4t/zKQ4ktN8WrMwOuVzkJfBilwAwGr6v16M5eI8yCuZ63H9TTuEU09Iu2HqkzFPVQ==} + + '@next/env@16.4.2': + resolution: {integrity: sha512-nTUTFH7G5/J/fmpkjVLegOkqyKOP0CEsJcMsyO4UCYeN1su+YMW/MfaSErnJskL7XM+UDK6aTvslxsRCyya/sA==} + + '@next/swc-darwin-arm64@14.2.33': + resolution: {integrity: sha512-HqYnb6pxlsshoSTubdXKu15g3iivcbsMXg4bYpjL2iS/V6aQot+iyF4BUc2qA/J/n55YtvE4PHMKWBKGCF/+wA==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + + '@next/swc-darwin-arm64@16.4.2': + resolution: {integrity: sha512-ONkhFvZNFWlsEHOM/81AtxdyuJP2KRYKYR0JxPwvcu1AuPMMMgcL+wW2luldJvMtZwKtUxoSkCychW5wIeoYSw==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + + '@next/swc-darwin-x64@14.2.33': + resolution: {integrity: sha512-8HGBeAE5rX3jzKvF593XTTFg3gxeU4f+UWnswa6JPhzaR6+zblO5+fjltJWIZc4aUalqTclvN2QtTC37LxvZAA==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + + '@next/swc-darwin-x64@16.4.2': + resolution: {integrity: sha512-luPCMbOsCoaF+kXJEUjmjmOZg1lC3BflhmUu+ZmW4tBu2vW/4AXak8JBFvePizGkxVmNiAw/r9ra+6UviCWtWQ==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + + '@next/swc-linux-arm64-gnu@14.2.33': + resolution: {integrity: sha512-JXMBka6lNNmqbkvcTtaX8Gu5by9547bukHQvPoLe9VRBx1gHwzf5tdt4AaezW85HAB3pikcvyqBToRTDA4DeLw==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@next/swc-linux-arm64-gnu@16.4.2': + resolution: {integrity: sha512-xhwFTAncJyaCNy5KqKKuKaIIdCy1/1ZV1s5S1G0hhT7wGMkDTlfJ6aQbfRFnIG/s3/kDrxQ8aycVe+c5QnP8ow==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@next/swc-linux-arm64-musl@14.2.33': + resolution: {integrity: sha512-Bm+QulsAItD/x6Ih8wGIMfRJy4G73tu1HJsrccPW6AfqdZd0Sfm5Imhgkgq2+kly065rYMnCOxTBvmvFY1BKfg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@next/swc-linux-arm64-musl@16.4.2': + resolution: {integrity: sha512-T1PNmfbPcxr5ndtWUL/3wQtLXsz808lq6sc2GrNT5k2oquF7UyqZddHSuAewHVsWsGXe6nsl9HoN1YNriVjuSg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@next/swc-linux-x64-gnu@14.2.33': + resolution: {integrity: sha512-FnFn+ZBgsVMbGDsTqo8zsnRzydvsGV8vfiWwUo1LD8FTmPTdV+otGSWKc4LJec0oSexFnCYVO4hX8P8qQKaSlg==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@next/swc-linux-x64-gnu@16.4.2': + resolution: {integrity: sha512-N9cDUOCGtkJG5PNKDFZUF3xXndrJJcpLp121uAGjIGvO/U2p9tfdNOM9htj7+5f72l0m8rMw/cvYacUJBQoudg==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@next/swc-linux-x64-musl@14.2.33': + resolution: {integrity: sha512-345tsIWMzoXaQndUTDv1qypDRiebFxGYx9pYkhwY4hBRaOLt8UGfiWKr9FSSHs25dFIf8ZqIFaPdy5MljdoawA==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + libc: [musl] + + '@next/swc-linux-x64-musl@16.4.2': + resolution: {integrity: sha512-yY2uh1YhX6ufuYy2FCbw1dqblbhI57GLYAJfCkqD9auTv6pLrH67Uccjc3QMKBeCYAG6lkgu08ExmX1bbjejjQ==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + libc: [musl] + + '@next/swc-win32-arm64-msvc@14.2.33': + resolution: {integrity: sha512-nscpt0G6UCTkrT2ppnJnFsYbPDQwmum4GNXYTeoTIdsmMydSKFz9Iny2jpaRupTb+Wl298+Rh82WKzt9LCcqSQ==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + + '@next/swc-win32-arm64-msvc@16.4.2': + resolution: {integrity: sha512-j/ArWRIHpMMB6wYLMhr2puTguBt70lNU/Cmjl9p6dTDE8DGknYJMP9PdwPk2dqpCNL/KIX9yfngDvIesxJPmsg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + + '@next/swc-win32-ia32-msvc@14.2.33': + resolution: {integrity: sha512-pc9LpGNKhJ0dXQhZ5QMmYxtARwwmWLpeocFmVG5Z0DzWq5Uf0izcI8tLc+qOpqxO1PWqZ5A7J1blrUIKrIFc7Q==} + engines: {node: '>= 10'} + cpu: [ia32] + os: [win32] + + '@next/swc-win32-x64-msvc@14.2.33': + resolution: {integrity: sha512-nOjfZMy8B94MdisuzZo9/57xuFVLHJaDj5e/xrduJp9CV2/HrfxTRH2fbyLe+K9QT41WBLUd4iXX3R7jBp0EUg==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] + + '@next/swc-win32-x64-msvc@16.4.2': + resolution: {integrity: sha512-AA4edyWHDko3NCSo0x6GomsdgFb0oR1J3MXU1b5xt6FRFg4AucrMPW3S0hCe/9onU0O1BbpGQBsqo1r0Gneu1g==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] + + '@noble/ciphers@2.4.0': + resolution: {integrity: sha512-AnjFn0Jv92laAkvMrghlFZq4qQCIN/4DxFV/eooqtC2YTjB7kBeLMS2T9KJX4Dn+ZVXLOwK0lSgqDtx9gvxtiw==} + engines: {node: '>= 20.19.0'} + + '@noble/hashes@2.4.0': + resolution: {integrity: sha512-X5XaVWZIBCT7HHZGm5I7ZQXDwLG+bGXuSrMQAW+7Zvl87h1kmc1ZB1VSRJcpUfoUrGQp4Fkoxm5kZ+Ms+aW+eA==} + engines: {node: '>= 20.19.0'} + + '@nodelib/fs.scandir@2.1.5': + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} + + '@nodelib/fs.stat@2.0.5': + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + + '@nodelib/fs.walk@1.2.8': + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} + + '@opentelemetry/semantic-conventions@1.43.0': + resolution: {integrity: sha512-eSYWTm620tTk45EKSedaUL8MFYI8hW164hIXsgIHyxu3VobUB3fFCu5t0hQby6OoWRPsG1KkKUG2M5UadiLiVg==} + engines: {node: '>=14'} + + '@oxc-project/types@0.155.0': + resolution: {integrity: sha512-SeE8JPwW1xs1tHeNycjUtUBdhorRa8o4jlvjwk49R7/Z291i+4DQa7JJIgOm/TaYQZx+QrPQbVJ/9c8dMIZN8Q==} + + '@playwright/test@1.64.1': + resolution: {integrity: sha512-IaYGml/nSOiZWROfPtuIL7neuu9qDOZ3TNvNljUIrhDMxiGTgPjzj/g9p9RxpS2tSepPDRY+UwAaEeiKtUvIAg==} + engines: {node: '>=20'} + hasBin: true + + '@poppinss/colors@4.1.6': + resolution: {integrity: sha512-H9xkIdFswbS8n1d6vmRd8+c10t2Qe+rZITbbDHHkQixH5+2x1FDGmi/0K+WgWiqQFKPSlIYB7jlH6Kpfn6Fleg==} + + '@poppinss/dumper@0.6.5': + resolution: {integrity: sha512-NBdYIb90J7LfOI32dOewKI1r7wnkiH6m920puQ3qHUeZkxNkQiFnXVWoE6YtFSv6QOiPPf7ys6i+HWWecDz7sw==} + + '@poppinss/exception@1.2.3': + resolution: {integrity: sha512-dCED+QRChTVatE9ibtoaxc+WkdzOSjYTKi/+uacHWIsfodVfpsueo3+DKpgU5Px8qXjgmXkSvhXvSCz3fnP9lw==} + + '@radix-ui/number@1.0.1': + resolution: {integrity: sha512-T5gIdVO2mmPW3NNhjNgEP3cqMXjXL9UbO0BzWcXfvdBs+BohbQxvd/K5hSVKmn9/lbTdsQVKbUcP5WLCwvUbBg==} + + '@radix-ui/primitive@1.0.1': + resolution: {integrity: sha512-yQ8oGX2GVsEYMWGxcovu1uGWPCxV5BFfeeYxqPmuAzUyLT9qmaMXSAhXpb0WrspIeqYzdJpkh2vHModJPgRIaw==} + + '@radix-ui/primitive@1.2.0': + resolution: {integrity: sha512-KABY+VMIRPJL+Vyzv/335FEhXXD/xDv8BMb1kl48/aXJZMH0LtHCTx5ga5RnxaEP3nZHtmTLf1P9vanmFX46bw==} + + '@radix-ui/react-arrow@1.0.3': + resolution: {integrity: sha512-wSP+pHsB/jQRaL6voubsQ/ZlrGBHHrOjmBnr19hxYgtS0WvAFwZhK2WP/YY5yF9uKECCEEDGxuLxq1NBK51wFA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-checkbox@1.4.1': + resolution: {integrity: sha512-KWtwhh+98ML3seZ9vO9yRY2OwaQG90dCiDAxjpSNY2AaZ3Hik3B0dsk6m0ILywo/no3A9/SozadyPMNweVT8yw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-collection@1.0.3': + resolution: {integrity: sha512-3SzW+0PW7yBBoQlT8wNcGtaxaD0XSu0uLUFgrtHY08Acx05TaHaOmVLR73c0j/cqpDy53KBMO7s0dx2wmOIDIA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-compose-refs@1.0.1': + resolution: {integrity: sha512-fDSBgd44FKHa1FRMU59qBMPFcl2PZE+2nmqunj+BWFyYYjnhIDWL2ItDs3rrbJDQOtzt5nIebLCQc4QRfz6LJw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-compose-refs@1.1.5': + resolution: {integrity: sha512-+48PbAAbq3didjJxa+OaWY2ZwgAKsNiRGyeHKszblZMQ+kcpd9pAaT11cMkGEie0vsOi3QdeTE6d5Fe3Gn61kA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-context@1.0.1': + resolution: {integrity: sha512-ebbrdFoYTcuZ0v4wG5tedGnp9tzcV8awzsxYph7gXUyvnNLuTIcCk1q17JEbnVhXAKG9oX3KtchwiMIAYp9NLg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-context@1.3.0': + resolution: {integrity: sha512-v5AYEocMISkbJ+1fTXzZpiFv7NRr3D2WiYbLIKf+FkmJ8VkP6d503eV2n34MFussHXY1pcoq3yfJiQH77dc4Mg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-direction@1.0.1': + resolution: {integrity: sha512-RXcvnXgyvYvBEOhCBuddKecVkoMiI10Jcm5cTI7abJRAHYfFxeu+FBQs/DvdxSYucxR5mna0dNsL6QFlds5TMA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-dismissable-layer@1.0.4': + resolution: {integrity: sha512-7UpBa/RKMoHJYjie1gkF1DlK8l1fdU/VKDpoS3rCCo8YBJR294GwcEHyxHw72yvphJ7ld0AXEcSLAzY2F/WyCg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-focus-guards@1.0.1': + resolution: {integrity: sha512-Rect2dWbQ8waGzhMavsIbmSVCgYxkXLxxR3ZvCX79JOglzdEy4JXMb98lq4hPxUbLr77nP0UOGf4rcMU+s1pUA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-focus-scope@1.0.3': + resolution: {integrity: sha512-upXdPfqI4islj2CslyfUBNlaJCPybbqRHAi1KER7Isel9Q2AtSJ0zRBZv8mWQiFXD2nyAJ4BhC3yXgZ6kMBSrQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-id@1.0.1': + resolution: {integrity: sha512-tI7sT/kqYp8p96yGWY1OAnLHrqDgzHefRBKQ2YAkBS5ja7QLcZ9Z/uY7bEjPUatf8RomoXM8/1sMj1IJaE5UzQ==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-label@2.1.17': + resolution: {integrity: sha512-xmj7MN/drx1oUAXkfiFIvyDmGNUIN/omGobvA5oAoNqu9zO2MkISYGZOkBcqSzs/UZXXwV+/3ACRE7q7mGcmkA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-popper@1.1.2': + resolution: {integrity: sha512-1CnGGfFi/bbqtJZZ0P/NQY20xdG3E0LALJaLUEoKwPLwl6PPPfbeiCqMVQnhoFRAxjJj4RpBRJzDmUgsex2tSg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-portal@1.0.3': + resolution: {integrity: sha512-xLYZeHrWoPmA5mEKEfZZevoVRK/Q43GfzRXkWV6qawIWWK8t6ifIiLQdd7rmQ4Vk1bmI21XhqF9BN3jWf+phpA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-presence@1.1.11': + resolution: {integrity: sha512-Z7/atlkab36Z8hm+V8zYc79r0W+tiOB1o0tun1By94JyadkekLQmtEAnBSP9XKXBNQsStoStS4+gX10JpS5akA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-primitive@1.0.3': + resolution: {integrity: sha512-yi58uVyoAcK/Nq1inRY56ZSjKypBNKTa/1mcL8qdl6oJeEaDbOldlzrGn7P6Q3Id5d+SYNGc5AJgc4vGhjs5+g==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-primitive@2.2.0': + resolution: {integrity: sha512-HCTSPMNqv55Qk0IX4geJbpyXazmqulcimwuyjxTkKi29v+QZbG2Zho9BnbBq4YS2PF+KlNb2CXoLz66uUmblkg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-select@1.2.2': + resolution: {integrity: sha512-zI7McXr8fNaSrUY9mZe4x/HC0jTLY9fWNhO1oLWYMQGDXuV4UCivIGTxwioSzO0ZCYX9iSLyWmAh/1TOmX3Cnw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-slot@1.0.2': + resolution: {integrity: sha512-YeTpuq4deV+6DusvVUW4ivBgnkHwECUu0BiN43L5UCDFgdhsRUWAghhTF5MbvNTPzmiFOx90asDSUjWuCNapwg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-slot@1.5.0': + resolution: {integrity: sha512-tyYd9ddPXAysAbdbD9eYxgwpCSv6f3PncqVSNKQFSR5lcJVLz3cb/pANDoYrLiHBpXv7skortyUgGUWsYuPPFQ==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-callback-ref@1.0.1': + resolution: {integrity: sha512-D94LjX4Sp0xJFVaoQOd3OO9k7tpBYNOXdVhkltUbGv2Qb9OXdrg/CpsjlZv7ia14Sylv398LswWBVVu5nqKzAQ==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-controllable-state@1.0.1': + resolution: {integrity: sha512-Svl5GY5FQeN758fWKrjM6Qb7asvXeiZltlT4U2gVfl8Gx5UAv2sMR0LWo8yhsIZh2oQ0eFdZ59aoOOMV7b47VA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-controllable-state@1.3.0': + resolution: {integrity: sha512-TAcBI7bw2ljYCbv4+zuTSd6zICu8pRt6SDN2vJ/Z06K2MXh6I9WYFe/A9ovlFDtR5HVHGm5iDxDoABm/++dbKg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-effect-event@0.0.5': + resolution: {integrity: sha512-7cshFL8HGS/7HEiHH+9kL9HBwp2sa9yX18Knwek6KYWmXwM7pegMgta2AXMQKI+rq3JnfSj9x8wYqFMTdG1Jgg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-escape-keydown@1.0.3': + resolution: {integrity: sha512-vyL82j40hcFicA+M4Ex7hVkB9vHgSse1ZWomAqV2Je3RleKGO5iM8KMOEtfoSB0PnIelMd2lATjTGMYqN5ylTg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-layout-effect@1.0.1': + resolution: {integrity: sha512-v/5RegiJWYdoCvMnITBkNNx6bCj20fiaJnWtRkU18yITptraXjffz5Qbn05uOiQnOvi+dbkznkoaMltz1GnszQ==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-layout-effect@1.1.4': + resolution: {integrity: sha512-K20DkRkUwDnxEYMBPcg3Y6voLkEy5p5QQmszZgLngKKiC7dzBR/aEuK3w1qlx2JWDUNH6FluahYdgR3BP+QbYw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-previous@1.0.1': + resolution: {integrity: sha512-cV5La9DPwiQ7S0gf/0qiD6YgNqM5Fk97Kdrlc5yBcrF3jyEZQwm7vYFqMo4IfeHgJXsRaMvLABFtd0OVEmZhDw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-rect@1.0.1': + resolution: {integrity: sha512-Cq5DLuSiuYVKNU8orzJMbl15TXilTnJKUCltMVQg53BQOF1/C5toAaGrowkgksdBQ9H+SRL23g0HDmg9tvmxXw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-size@1.0.1': + resolution: {integrity: sha512-ibay+VqrgcaI6veAojjofPATwledXiSmX+C0KrBk/xgpX9rBzPV3OsfwlhQdUOFbh+LKQorLYT+xTXW9V8yd0g==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-size@1.1.5': + resolution: {integrity: sha512-V1McDQkMGzgivwqdu7u96APs7oi0Jvj9LTzgq3WWrDZqxWdAqU9yZnZQqk5OizGFR8badUQwZsrlao7MOlWYOA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-visually-hidden@1.0.3': + resolution: {integrity: sha512-D4w41yN5YRKtu464TLnByKzMDG/JlMPHtfZgQAu9v6mNakUqGUI9vUrfQKz8NK41VMm/xbZbh76NUTVtIYqOMA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/rect@1.0.1': + resolution: {integrity: sha512-fyrgCaedtvMg9NK3en0pnOYJdtfwxUcNolezkNPUsoX57X8oQk+NkqcvzHXD2uKNij6GXmWU9NDru2IWjrO4BQ==} + + '@resvg/resvg-wasm@2.4.1': + resolution: {integrity: sha512-yi6R0HyHtsoWTRA06Col4WoDs7SvlXU3DLMNP2bdAgs7HK18dTEVl1weXgxRzi8gwLteGUbIg29zulxIB3GSdg==} + engines: {node: '>= 10'} + + '@rolldown/binding-android-arm-eabi@1.2.15': + resolution: {integrity: sha512-aLcgK9gIJ3YRvrrtfSBbRa27F5WrpiTaPulnFpsHPxpUHgFlSgnU4854MHwoRGEBhfRJDWCS2WQ7lIjskE9Olw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [android] + + '@rolldown/binding-android-arm64@1.2.15': + resolution: {integrity: sha512-xD7DdZCrbThKuxNg7ooQmvp07ys4J/pnSEMTG3/OdOWl6daC67m/Q4fL78sRHMxTH/N4fGUbYhcPM0MF5WFHkg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [android] + + '@rolldown/binding-darwin-arm64@1.2.15': + resolution: {integrity: sha512-m2WuQ6r0B4OTYxyPpNLtXaMRbRDUbG8YQV2Q3KTdSSK8Th6KHCnC8jVCJt8bvYeSB5WivkkNbc85mKadaSdOxA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [darwin] + + '@rolldown/binding-darwin-x64@1.2.15': + resolution: {integrity: sha512-5RtnsHM36nodM9WbMy+zip0LGS/G+y5wro5RHrpOlr4ac24+1zSi9kiV2MP1myZeZ/ifEHfulQcWjnAXzc2C2A==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [darwin] + + '@rolldown/binding-freebsd-x64@1.2.15': + resolution: {integrity: sha512-g3l09pyFqhu+135JKkbkwiKGQmwU5hUMUPJ4VdBADvuqR8d33L6H578rh8m7rtxbdp+VmX/+nzI7nvhSZlzpUQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [freebsd] + + '@rolldown/binding-linux-arm-gnueabihf@1.2.15': + resolution: {integrity: sha512-nIe3VugI97nGQtspPxDqA4sXMUpeiocKIP/CqpY/u/vgbT+alX+cVxu1C/oVBPKg4feNTmYovE91v4DgXvXNwQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + + '@rolldown/binding-linux-arm64-gnu@1.2.15': + resolution: {integrity: sha512-iTBjXx+B5QSvgI89lJfmqh4wTh8NabR1YZIIN3hNx4zSG0EVfVqkOvLulNpG4251pbd6/IAmZ/LefVk1Y4rPhw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-arm64-musl@1.2.15': + resolution: {integrity: sha512-uN26XOnVR7rqQupG3V9oAG2EGGatWjcJHOeDOHUFCh4TBWmP2tHTFoVN13aYbwfm0aHqJAEmcwhAu6sooIjfqQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@rolldown/binding-linux-ppc64-gnu@1.2.15': + resolution: {integrity: sha512-9nWkcdd+H+XhaA3fQIwpHnKIrfx/PQ6rO0pivr78Og07tXlUlctBBJoEYLPfhTmCR/QxEVdn6uPjHV5SymPhdw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-s390x-gnu@1.2.15': + resolution: {integrity: sha512-Ggh0ciFjLwIusLSLz7LZYEaGdxOAUJXI+Qu5JCbhPJJHEt8vP+IjRATTJheiJsdzzTYgUiHUiw3X1Ea3ZpMBdA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-x64-gnu@1.2.15': + resolution: {integrity: sha512-FHg60rS6DBePAYZ9X9F67x+JObFdmgn6tupA1C/a3B+CufFmTD4mX+e8M75tCiAO3foR/6xwVBI0KQiI7sn/rw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-x64-musl@1.2.15': + resolution: {integrity: sha512-/cvV/7v5VGz/moiz0XKRj2dE8DzsKyhIu1KpOvJGPjRywg3yscON889UGvAe8zfiJLHup7VLjBduoGWi3HusWQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [musl] + + '@rolldown/binding-openharmony-arm64@1.2.15': + resolution: {integrity: sha512-MyzC5Hrv/sm+Z7TSGKP/j8001RO2xQm1zOpCNVL4j0cY/VhBZviludA2YFQ7i4lH6ZAXxQm0lcMdBzM+99mE7w==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [openharmony] + + '@rolldown/binding-win32-arm64-msvc@1.2.15': + resolution: {integrity: sha512-+PgYiS+AH5omy6L45ZLxybasauJaj3M8buoT83D+nzPmCayXlxUV9hydhciCKVyIg0B/v0BtXPDE1uGqNwCPpg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [win32] + + '@rolldown/binding-win32-x64-msvc@1.2.15': + resolution: {integrity: sha512-HFZd2QNQYn1JbIi+Hpd7H+r/lkWxcfIu28nirZ6eCn2LafuvmExMlb/P96Sfx5tf7pPArw39IdhmCF8vmV+NhQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [win32] + + '@rolldown/pluginutils@1.0.0-rc.7': + resolution: {integrity: sha512-qujRfC8sFVInYSPPMLQByRh7zhwkGFS4+tyMQ83srV1qrxL4g8E2tyxVVyxd0+8QeBM1mIk9KbWxkegRr76XzA==} + + '@rolldown/pluginutils@1.0.1': + resolution: {integrity: sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==} + + '@rollup/rollup-android-arm-eabi@4.65.1': + resolution: {integrity: sha512-5coxNSjqOI2J3NkVhlp3u+zGcyjnowQFsU9sg7MMz4UPXY4Dv63kFGLt7ConXz9CNq2i0yuOJZAF/2RMrgI2OA==} + cpu: [arm] + os: [android] + + '@rollup/rollup-android-arm64@4.65.1': + resolution: {integrity: sha512-K0HFf6XMB3IYs+jDZ1/RRhZaVOwxNXrl0n4MDEyGDjuK7+B6K/nDJp8DCBitO3S1sK/fzNxAf9QZAny4AIUPtg==} + cpu: [arm64] + os: [android] + + '@rollup/rollup-darwin-arm64@4.65.1': + resolution: {integrity: sha512-zkZrXYwNlIcSUmcwY2DpsaDHr0XjVUeQHCuSunG3eQD7/5Wn/DvI7OMUE8NRRweK87yG8ebJ1xGOzmwpMsbZQA==} + cpu: [arm64] + os: [darwin] + + '@rollup/rollup-darwin-x64@4.65.1': + resolution: {integrity: sha512-Zaed+R3cpkkA3aiNd7NO0GV5KFh/LVf8j6bGcoRdpoXkSm/mWH8M0oX2/3u/nyGcx/bHEovD9CzX+w9/gcpI4A==} + cpu: [x64] + os: [darwin] + + '@rollup/rollup-freebsd-arm64@4.65.1': + resolution: {integrity: sha512-h12p3WJWhyJ9kir0zqAPr0rKNmBzOWIjoaOMT9OULs9KZQZCeOMKd+mGSvERjd9VxJYShd3zIxtrVxkYz6BEVA==} + cpu: [arm64] + os: [freebsd] + + '@rollup/rollup-freebsd-x64@4.65.1': + resolution: {integrity: sha512-yRBwh/5imKY4DydDulVtrjy8Jf7h7NQJUqZbgmZ3zFsCD9QqlnWvZ7RtEF+ecO1b+IukKjXlu5Bb9fehV3tIbg==} + cpu: [x64] + os: [freebsd] + + '@rollup/rollup-linux-arm-gnueabihf@4.65.1': + resolution: {integrity: sha512-1XuPiWYYaLE1UDOqhbKVOfsqxvfmFS/lYPSk92U1hEX1qRfSYH0hNeAlbxFIgjp4d6+YQmL95EPRgdvjbZEddA==} + cpu: [arm] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-arm-musleabihf@4.65.1': + resolution: {integrity: sha512-Y3C5e55Yrf6p2r5rBcc4P9hFWVNi6oqWy/53I/AyCJJGlp3KRSpTP8eoUmVntchTbEnhgBgAgLO9flj9AvOdUw==} + cpu: [arm] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-arm64-gnu@4.65.1': + resolution: {integrity: sha512-Itj6coSswkYPIcVLczObXmwdplHNQQxyfnK1ppBg4czDaX8RiEzLKqU7EMc64BiBuiDZEUS+M93ktM18rv5llw==} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-arm64-musl@4.65.1': + resolution: {integrity: sha512-KeO8jTEqdrnhvcahufbimyMoI44vedRUp1bVz2QUnRX2vDm/hxzCPt5F8fERVD5fsHyTW/vXmCElT054VOSVOA==} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-loong64-gnu@4.65.1': + resolution: {integrity: sha512-dDOz5VZZ+ZGnglpmET6VJefamWXFsgaVtuhSClf2/URZBp048jprD6z1hddsIMN6n1w+oUzGZEBp9u6Mlszsfg==} + cpu: [loong64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-loong64-musl@4.65.1': + resolution: {integrity: sha512-JbfRKz8nJCuo8gn1Dqx8lQWEHw4qhZ3uRaHphw5vrSjnSptJTKTRC/bLKHh8QQMsEnhL4uq+bdg3tkiXbJ2q/A==} + cpu: [loong64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-ppc64-gnu@4.65.1': + resolution: {integrity: sha512-3oQpe1q0emSeCAssVHMQdOz5fz3PBH5my/Fr0ZekV2UMNL4ZiRa1ciikYlGQXyDkeqseYYv1InwOY8YPqY7RIQ==} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-ppc64-musl@4.65.1': + resolution: {integrity: sha512-nNV3HHi23o1LtpGGwH+Bav4hqnc4+klQtC96tSvCfvql8bLlNFTnTFiGl/jai2nve3eEr/vT2ocuyf+h+eMnYQ==} + cpu: [ppc64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-riscv64-gnu@4.65.1': + resolution: {integrity: sha512-b5zab0FryBxuocuDeqOsYGAg2EzjKw4mKA6LjQXCyewXjGv/BXqACBsY2cO45xM4hV2weYtdjGThP2VB2ByAYg==} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-riscv64-musl@4.65.1': + resolution: {integrity: sha512-Rh08xZakiUxKNgI3hbgH9mivlx478lSqckS9s+Oc3/TX1VrAH3W8z/5wpJXR/v5VjqcJ/jJNVBg64PU1+iQsTQ==} + cpu: [riscv64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-s390x-gnu@4.65.1': + resolution: {integrity: sha512-qDgtS6juN3/k97y4kcD6XLFpXEo4f6CnG8lTOGYwlhrUYTrMyhN0WHdZCPAW5rqS0MqQG7qI7dxnjugt6QB39Q==} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-x64-gnu@4.65.1': + resolution: {integrity: sha512-44IKzBPqXXVm0kt1O+F5eW4juR5FyIxGNlFkpP8qwIDzucBsjM1HCbdYUQrQw8rU/g6HRl/tfBm0+Qq4H4Ro3w==} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-x64-musl@4.65.1': + resolution: {integrity: sha512-tvYWZ/h2PCHs558Xu7B6LptuRCV8lXV2xI75ONMcldII1m2zlFwuI4BJZi9M6rSMkYqcPLLtPUPrjyqfbzLOdg==} + cpu: [x64] + os: [linux] + libc: [musl] + + '@rollup/rollup-openbsd-x64@4.65.1': + resolution: {integrity: sha512-gdyeucgZCnei3pXwadKVTEAOgRx0B+c847DUPR/PdOMmp3olhfkYo6r0J4PzRFZB5ZICZQTxntyvgmWH5xT7rg==} + cpu: [x64] + os: [openbsd] + + '@rollup/rollup-openharmony-arm64@4.65.1': + resolution: {integrity: sha512-Wf/NEKdn2SAL4Nvt8HyDtdkseWTwiLbZEOoNYnEaHkbso0B9eHO42vKnZh+OYsn+IMhAMcWcuIwPlBOgOXsUzg==} + cpu: [arm64] + os: [openharmony] + + '@rollup/rollup-win32-arm64-msvc@4.65.1': + resolution: {integrity: sha512-x9VSsDmsMsEWy4cr/mFeaEsXnVJ6Kc4NCAU/lCnwml3s7LQbZoa9+/qwc9etWHbuuDT5mYxdyyKUwo76njtjZw==} + cpu: [arm64] + os: [win32] + + '@rollup/rollup-win32-ia32-msvc@4.65.1': + resolution: {integrity: sha512-RIDbiVvvLkN45mOFpbo6eYMgnuiBEB62BGR/0s4QJgGg2AvVxucDDNn67kpAcUoYyfmY8iX8/RifMcmxmmnejA==} + cpu: [ia32] + os: [win32] + + '@rollup/rollup-win32-x64-gnu@4.65.1': + resolution: {integrity: sha512-+KN8HIr88vN59JNxlrM2fMimzY43Y0lQB7+0xdVsFbvFCAA74CLKCdfzIHzzvndJryBc94Pm+MvwtukKjaS2ug==} + cpu: [x64] + os: [win32] + + '@rollup/rollup-win32-x64-msvc@4.65.1': + resolution: {integrity: sha512-+Y1Sd49cSDq60UOl8/U2HI0ebUvnSl/hDhMHQn+ouw17yb8fYwMWIazzJ4JFpSkjPE7sj5NTNSX9IoyEqcFfyQ==} + cpu: [x64] + os: [win32] + + '@shikijs/core@4.5.0': + resolution: {integrity: sha512-6CIgwq+bt2JZ3OSjb/nBkkwEf/CfpHcbam+Mg5Pllco7HAGRQ2/EFhZrrJtbyNTgKwknfVS+llsXGygiDGwJWw==} + engines: {node: '>=20'} + + '@shikijs/engine-javascript@4.5.0': + resolution: {integrity: sha512-Ed6UdEj84LyYkwnxM5CvSMWAD+id9ExTYri0/+x41U9zrgNifPSS9lZm0JqBP0VfYI8yr8tY5nbNq9+p9R0kFA==} + engines: {node: '>=20'} + + '@shikijs/engine-oniguruma@4.5.0': + resolution: {integrity: sha512-dKVmbJecVdB9recl8a/CU4jdpNXyjJQrIcesIkpS70s5HS02ohpnCSpMUbotPnEUzbAcLQ+S4hwZYbkBBiTcJw==} + engines: {node: '>=20'} + + '@shikijs/langs@4.5.0': + resolution: {integrity: sha512-wwBTqwduXSz0X4v9Qa2EWeFaYJEw1clCncWjoRNQRbVDu3SPRTRWucnouYapKj3b8Q+sk/41Vbc4B5c8nuYzLA==} + engines: {node: '>=20'} + + '@shikijs/primitive@4.5.0': + resolution: {integrity: sha512-UM7ShlA8oz0OWxLLO8BmO9Ip6fVqdkt8yF0EH7nOCqHfrx1eEAzF0ZUVK7L+I8NEgeu1PEWSRlxaiPPeCb4iDg==} + engines: {node: '>=20'} + + '@shikijs/themes@4.5.0': + resolution: {integrity: sha512-zGb87H3UBbpuI4yoh5UguB1XbU+2BDU3kflM7UfZ+Cy2hWo9lBtqjSVK20gmLY6ukYl040hAypGXMgud9vul8Q==} + engines: {node: '>=20'} + + '@shikijs/types@4.5.0': + resolution: {integrity: sha512-drtPrtD8N0DENyD2cyt6Ajy+IWsiCLgMxODwLTpvH1UsN6a9jf90tNTPjqwHvA+0Lzu9e0txk8DjfqH1p9UJRw==} + engines: {node: '>=20'} + + '@shikijs/vscode-textmate@10.1.0': + resolution: {integrity: sha512-cVBuhDQjBZaNMTwBquYfPydrUP+E3hE6oYGasx8h6ZrODIM7/r+gxLDXdd66oszbrggZHEntdE6j+5gYIVyMWQ==} + + '@shuding/opentype.js@1.4.0-beta.0': + resolution: {integrity: sha512-3NgmNyH3l/Hv6EvsWJbsvpcpUba6R8IREQ83nH83cyakCw7uM1arZKNfHwv1Wz6jgqrF/j4x5ELvR6PnK9nTcA==} + engines: {node: '>= 8.0.0'} + hasBin: true + + '@sindresorhus/is@7.2.0': + resolution: {integrity: sha512-P1Cz1dWaFfR4IR+U13mqqiGsLFf1KbayybWwdd2vfctdV6hDpUkgCY0nKOLLTMSoRd/jJNjtbqzf13K8DCCXQw==} + engines: {node: '>=18'} + + '@smithy/core@3.37.0': + resolution: {integrity: sha512-97imTcCyiPd8k0e9+ts/Sp0W65Dn9Ti357J7M09Ov4tI8Q1JDJVFSoAJtjEVKqfHEr3Pdo2jfolqKCaaiszH0g==} + engines: {node: '>=18.0.0'} + + '@smithy/credential-provider-imds@4.5.2': + resolution: {integrity: sha512-A9uSdn72ozbRUSit0eib0TW7nXuNPlaeM0zcGkJ+nE6tFcSDbnmtwoxbTCFBukVQcszDAyvsd7+rTduPTXpygg==} + engines: {node: '>=18.0.0'} + + '@smithy/fetch-http-handler@5.8.0': + resolution: {integrity: sha512-ycSJu3tFAQ4v04CBB0agqFMVsSQ1iG3yw+SpgxRqKfaURpQD4CZ8Wn0zPMmSnOuTpTh65Vz+EA0rMrw089wvkA==} + engines: {node: '>=18.0.0'} + + '@smithy/node-http-handler@4.13.0': + resolution: {integrity: sha512-/GGcPoNJ2nzGytdAanpbx7mpp9Coa8LP+/Rpmbktr8YeLuIXs9B0SEz+X3AeonHdyzOIFJdKbN7jOZ+Tj+pMGw==} + engines: {node: '>=18.0.0'} + + '@smithy/signature-v4@5.7.4': + resolution: {integrity: sha512-tHy0K0VtqNd5Y7Y41h0a0Lhh0L1GzC08dTWg0F7vRJWFtTENg7IZikf3wQkanYIRdb7ngoIPMTmqgUi401fEeQ==} + engines: {node: '>=18.0.0'} + + '@smithy/types@4.19.0': + resolution: {integrity: sha512-r7jh49VJxGerfAcTQA6gXcKc+98zOp/tqRwzYjgOE+iSQsP6cEU1hq2QzbuipmP68QtYdY9wKEhiCQZIzHgZ4Q==} + engines: {node: '>=18.0.0'} + + '@speed-highlight/core@1.2.24': + resolution: {integrity: sha512-qeW2e1l78afw8VhRPfPQ1Gjj+KU5XFQ/OFV5ti6eTa9bruO7mJyZtA4vw0ofqmA3tKCkROE9xLk3VZoeRc98nw==} + + '@standard-schema/spec@1.1.0': + resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} + + '@swc/counter@0.1.3': + resolution: {integrity: sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==} + + '@swc/helpers@0.5.23': + resolution: {integrity: sha512-5lSsMOTXURePglDfvuAQUqkGek9Hg2kksOYay2m0+XR++b2NWYL/4sWyuvVBIs8oKnJaxkdi9whaL/sqN13afw==} + + '@swc/helpers@0.5.5': + resolution: {integrity: sha512-KGYxvIOXcceOAbEk4bi/dVLEK9z8sZ0uBB3Il5b1rhfClSpcX0yfRO0KmTkqR2cnQDymwLB+25ZyMzICg/cm/A==} + + '@tailwindcss/node@4.3.3': + resolution: {integrity: sha512-/T8IKEsf9VTU6tLjgC7+sv2mOPtQxzE2jMw7u4Tt40Tx+QSZxpzh95/H6cMKoja9XuW7iMdLJYBB0o9G1CaAgg==} + + '@tailwindcss/oxide-android-arm64@4.3.3': + resolution: {integrity: sha512-Y85A2gmPSkl5Ve5qR86GL4HT509cFqQh1aes9p3sSkyTPwt0Pppf3GkwGe4JPACcRYjgJIEhQgM6dBClnr0NYw==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [android] + + '@tailwindcss/oxide-darwin-arm64@4.3.3': + resolution: {integrity: sha512-BiaWatpBcERQFDlOjRDpIVXuFK5PJez5SA4JMg6VYZdBYU+qKfV/vqjcIs+IYmtitf1xYQZTwXvU/8y4lfZUGw==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [darwin] + + '@tailwindcss/oxide-darwin-x64@4.3.3': + resolution: {integrity: sha512-fAeUqfV5ndhxRwai8cXGzdLvul9utWOmeTkv69unv4ZXixjn61Z+p9lCWdwOwA3TYboG3BwdVuN/RDjhBRl0mw==} + engines: {node: '>= 20'} + cpu: [x64] + os: [darwin] + + '@tailwindcss/oxide-freebsd-x64@4.3.3': + resolution: {integrity: sha512-iyf5bV6+wnAlflVeEy7R25dupxTNECZN5QMI0qNT6eT+EgaGdZcKhGkr5SdoaWiLJ3spLqIY9VCeSGrwmtg4kw==} + engines: {node: '>= 20'} + cpu: [x64] + os: [freebsd] + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.3.3': + resolution: {integrity: sha512-aAYUprJAJQWWbRrPvtjdroZ56Md+JM8pMiopS6xGEwDfLhqj+2ver2p4nU4Mb3CRqcMmNBjo8KkUgcxhkzVQGQ==} + engines: {node: '>= 20'} + cpu: [arm] + os: [linux] + + '@tailwindcss/oxide-linux-arm64-gnu@4.3.3': + resolution: {integrity: sha512-nDxldcEENOxZRzC2uu9jrutZdAAQtb+8WWDCSnWL1zvBk1+FN+x6MtDViPB5AJMfttVCUhehGWus3XBPgatM/w==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@tailwindcss/oxide-linux-arm64-musl@4.3.3': + resolution: {integrity: sha512-Md44bD6veX/PC5iyF8cDVnw4HBIANZepRZZ7a8DQOvkfo5WUBwcp6iAuCUz23u+4SUkhJlD3eL7hNdW8ezd/kA==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@tailwindcss/oxide-linux-x64-gnu@4.3.3': + resolution: {integrity: sha512-tx7us1muwOKAKWao2v/GaafFeQboE6aj88vC6ziN2NCGcRm8gWUhwjzg+YdVB1e4boAtdtma4L43onunI6NS4w==} + engines: {node: '>= 20'} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@tailwindcss/oxide-linux-x64-musl@4.3.3': + resolution: {integrity: sha512-SJxX60smvHgasZoBy11dX6YRjXJFovwWBoedhbQPOBzgFWBHGB+TVPWB9BxzR7TTxU8FQZAI2AyiNCMzFm8Img==} + engines: {node: '>= 20'} + cpu: [x64] + os: [linux] + libc: [musl] + + '@tailwindcss/oxide-wasm32-wasi@4.3.3': + resolution: {integrity: sha512-jx1+rPhY/5Ympkktd656HBWEBLxP7dH06losBLjjf5vgCODXvi9KhtftWcMIwTFIDqBr7cRnQkdLnAG+IOlGvQ==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + bundledDependencies: + - '@napi-rs/wasm-runtime' + - '@emnapi/core' + - '@emnapi/runtime' + - '@tybys/wasm-util' + - '@emnapi/wasi-threads' + - tslib + + '@tailwindcss/oxide-win32-arm64-msvc@4.3.3': + resolution: {integrity: sha512-3rc292Ca2ceK6Ulcc/bAVnTs/3nDtoPhyEKlgPv+yQJQi/JS/AMJlqzxvlDacL1nekbrcf6bTqp/jV4qgnPxNQ==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [win32] + + '@tailwindcss/oxide-win32-x64-msvc@4.3.3': + resolution: {integrity: sha512-yJ0pwIVc/nYeGoV02WtsN8KYyLQv7kyI2wDnkezyJlGGjkd4QLwDGAwl47YpPJeuI0M0ObaXGSPjvWDPeTPggw==} + engines: {node: '>= 20'} + cpu: [x64] + os: [win32] + + '@tailwindcss/oxide@4.3.3': + resolution: {integrity: sha512-krXjAikiaFSPaK/FkAQT5UTx3VormQaiZ5hBFlJZ9UFQGB/rwg1MZIhHAG9smMQRTdyJxP6Qt5MwMtdyU5FWrA==} + engines: {node: '>= 20'} + + '@tailwindcss/postcss@4.3.3': + resolution: {integrity: sha512-JTSZZGQi1AyKirbLN3azmjVzef92tcX7h+iSqPdaeStyFpGpDlKvvpxeOE8njhbUanbRwr3z8DyzhICWnMtQeg==} + + '@turbo/darwin-64@2.11.10': + resolution: {integrity: sha512-By4idRap5+nLnMuRzLB4qkOPRlvNdyY1ne4VJYDyUoUB11H94k7uif9mbe3JT8JSNXs1D68uMcBj6hJ/jMQRvA==} + cpu: [x64] + os: [darwin] + + '@turbo/darwin-arm64@2.11.10': + resolution: {integrity: sha512-pyEYlVcuexOPa92p0Wlwl9YT1Is5D60lxN3ItWm3g30YLvFaUq86TF4BBWg5ZAc0uMTnrOzCvuCsOBTdzUWnRQ==} + cpu: [arm64] + os: [darwin] + + '@turbo/gen@2.11.10': + resolution: {integrity: sha512-PL/OEEJLdsmS8zF/ijMrG9yi/j+PYe0nOCcZ1XbKndcjdYmeALnqHaxwoGmOo73FwDzC8mnsy2KrqNV6biaGlA==} + hasBin: true + + '@turbo/linux-64@2.11.10': + resolution: {integrity: sha512-1tYeR/IDZ5HEdsb0jNq2L2xam5nMQ+g80tlV2BZmv4OFw+pMcUM0mMmUcfc5wXPPNHVNPuDMjh9Y8G8HgXPLZA==} + cpu: [x64] + os: [android, linux] + + '@turbo/linux-arm64@2.11.10': + resolution: {integrity: sha512-HuekQxvVGhUd46g1Im/DKdOtglHr4/gguZAvzEpPUgtxNkztSa8lWhQEGQ+EmPQ0n7w19qjThFU+OfEEd0uvlw==} + cpu: [arm64] + os: [android, linux] + + '@turbo/windows-64@2.11.10': + resolution: {integrity: sha512-UJOP3BkbreY3/JlMgJR6ZiimxYIBn+c+B4tnBIxD0E9c3Estmk+XoVNVBNBottZLNRXe3/ScgOU4+/k8tIWysg==} + cpu: [x64] + os: [win32] + + '@turbo/windows-arm64@2.11.10': + resolution: {integrity: sha512-xOkEjF3ws/b/YNlc+bvJHMYBn+vL+QbEISZFVi0qS+ImmhA1X3/gmNmBrjjIG3dg6aeN+n6gQitzSkXQ286qJQ==} + cpu: [arm64] + os: [win32] + + '@types/chai@5.2.3': + resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==} + + '@types/debug@4.1.13': + resolution: {integrity: sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw==} + + '@types/deep-eql@4.0.2': + resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} + + '@types/emscripten@1.41.6': + resolution: {integrity: sha512-uN+9i8bFT5CUcZfyIEYDrSueACEyKGbUs5kC/72DGlZZoinh84sJfVV0i8UOJD1asdzkvLPBRrKs41kZ8MdEXg==} + + '@types/esrecurse@4.3.1': + resolution: {integrity: sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==} + + '@types/estree-jsx@1.0.5': + resolution: {integrity: sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==} + + '@types/estree@1.0.9': + resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==} + + '@types/hast@3.0.5': + resolution: {integrity: sha512-rp/ezSWaD1m44dPKICGhiskI13nVr7qTloFwDa/IYkhhf5nzwP+zIQcIJh3WIFSBOy/H1PzB40jPjMDksN4F+g==} + + '@types/json-schema@7.0.15': + resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + + '@types/mdast@4.0.4': + resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==} + + '@types/mdx@2.0.14': + resolution: {integrity: sha512-T48PeuJtvLosNTPVhfnIp3i/n3a4g4Bad7YCq5k64D4u7NwDrAotikQ+5+sjtUvBmxCMlbo3dVL+C2dP0rWHzg==} + + '@types/ms@2.1.0': + resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} + + '@types/node@20.14.11': + resolution: {integrity: sha512-kprQpL8MMeszbz6ojB5/tU8PLN4kesnN8Gjzw349rDlNgsSzg90lAVj3llK99Dh7JON+t9AuscPPFW6mPbTnSA==} + + '@types/node@22.18.6': + resolution: {integrity: sha512-r8uszLPpeIWbNKtvWRt/DbVi5zbqZyj1PTmhRMqBMvDnaz1QpmSKujUtJLrqGZeoM8v72MfYggDceY4K1itzWQ==} + + '@types/node@26.6.5': + resolution: {integrity: sha512-uMzsv9stDdofIZBx4UGh4Z9ZgXnGC9seRDscilBcTHAeOFk67MZg/k9bWVfO+bk4qZmG+l52hRnLwUiH2LnJTg==} + + '@types/prop-types@15.7.15': + resolution: {integrity: sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==} + + '@types/react-dom@18.3.0': + resolution: {integrity: sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg==} + + '@types/react-dom@19.3.0': + resolution: {integrity: sha512-ZI7bU42mZXXKHn/qNLEw2IrbiINU7X5+vfgdixBHkCNpYWXjKgfQ/P+uyGb5CjOLB9UcnTeg3rylQtV2hym44Q==} + peerDependencies: + '@types/react': ^19.3.0 + + '@types/react@18.3.3': + resolution: {integrity: sha512-hti/R0pS0q1/xx+TsI73XIqk26eBsISZ2R0wUijXIngRK9R/e7Xw/cXVxQK7R5JjW+SV4zGcn5hXjudkN/pLIw==} + + '@types/react@19.3.0': + resolution: {integrity: sha512-N0rFCuH9YoxG9/m61l9MfpJKfmLOVU0em7ipIz6TRgSSkvReLB9vL85GB+yr8Bs5leqpvg96JSwF4ZS1s4viQg==} + + '@types/unist@2.0.11': + resolution: {integrity: sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==} + + '@types/unist@3.0.3': + resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} + + '@types/ws@8.18.2': + resolution: {integrity: sha512-67MQl+fpWKVTT1NYdnmo3U4sc/xPo/zQBncVnI74qmQa0z/b+1g6iYqNmGCPbxO+zz2aklb08a0oHfegiVd0/w==} + + '@typescript/typescript-aix-ppc64@7.0.2': + resolution: {integrity: sha512-MTKKkWB7p/0E9xi1d1tHtZ5PiLkGEMIq88pK2CubZjOsLtYTLqhgIgi6zepFa+9GHZ6h05NMCkQxGKiPXMxXtQ==} + engines: {node: '>=16.20.0'} + cpu: [ppc64] + os: [aix] + + '@typescript/typescript-darwin-arm64@7.0.2': + resolution: {integrity: sha512-gowzar9MwS/aRWp6f3a4KUqzRjAZjOsmGNCM6LcTgXum+dBfgsBVMN+AgvOCCbguXyick6LJhpBszxMebJ8syA==} + engines: {node: '>=16.20.0'} + cpu: [arm64] + os: [darwin] + + '@typescript/typescript-darwin-x64@7.0.2': + resolution: {integrity: sha512-SZ9xZInqApNlNGc9s0W1VSsktYSOe9cFqNOIqmN1Gs8SmkjKZYFt017G4VwPxASInODuAdbTW7sXiFUf893RgA==} + engines: {node: '>=16.20.0'} + cpu: [x64] + os: [darwin] + + '@typescript/typescript-freebsd-arm64@7.0.2': + resolution: {integrity: sha512-W5NH4y/J0plIIS5b2xvTEkU7JFxyqdMAOgf+Ilhl0vHQXKO5dZoxd+C/jEtq56c4F3wk71RB4BMRQ2XdI+bwYQ==} + engines: {node: '>=16.20.0'} + cpu: [arm64] + os: [freebsd] + + '@typescript/typescript-freebsd-x64@7.0.2': + resolution: {integrity: sha512-UMGDx5sTpzNw3WiPebH7l90IWfJggEd+egHt/q6p7/Cm3zqoV7VxkGXt+3DxPIw8CcmvAB0j3sVVfbhX+M4Tpw==} + engines: {node: '>=16.20.0'} + cpu: [x64] + os: [freebsd] + + '@typescript/typescript-linux-arm64@7.0.2': + resolution: {integrity: sha512-Qh4eU4/y3yDjnfjjyPYihMj5/ODIlmt+Bzu17OI+fiSRDW57QmU5SiN63exPRNJPKUzcc1INa1NXdrJ+MqHjUQ==} + engines: {node: '>=16.20.0'} + cpu: [arm64] + os: [linux] + + '@typescript/typescript-linux-arm@7.0.2': + resolution: {integrity: sha512-gffT3xPz9sR7j/YJExkyPntrI0P2EP9XbOyWzth2/Gs0RstK+90RBcO0ncXoXy/beYll1SXw846Nf2zdnEz0QQ==} + engines: {node: '>=16.20.0'} + cpu: [arm] + os: [linux] + + '@typescript/typescript-linux-loong64@7.0.2': + resolution: {integrity: sha512-uEHck9i8hoAzXPiYRib1O7miOnz23SxIeVl6F4LXox+qov1K35jHcEW6VHKvZI+pyvl7fZEP4MCU5LYvIq1GuQ==} + engines: {node: '>=16.20.0'} + cpu: [loong64] + os: [linux] + + '@typescript/typescript-linux-mips64el@7.0.2': + resolution: {integrity: sha512-R4KvAMnE43W5Qeqb0Ly56O3mWMWIAgsMyz36DCaycd5nbg/9kzm0liw3JocfRqyJY0KPmzFjbswozXyW0DnIYA==} + engines: {node: '>=16.20.0'} + cpu: [mips64el] + os: [linux] + + '@typescript/typescript-linux-ppc64@7.0.2': + resolution: {integrity: sha512-DORx5b3sd/4S7eayxm4FQv+A7CrkUIGRaHiwI8oiHTAI1fAPWhF4J0vAlkC8biAlHSVVwxMQ3tjZ2/DVbnQiiA==} + engines: {node: '>=16.20.0'} + cpu: [ppc64] + os: [linux] + + '@typescript/typescript-linux-riscv64@7.0.2': + resolution: {integrity: sha512-wf0jqEDOjrPRnKwYRyyJDRo11KMbvMFrU+q4zqKyChODBzvlkbhNQfKvLxQCcwTpdDaXSHZTVuh0JoCrKCUMHQ==} + engines: {node: '>=16.20.0'} + cpu: [riscv64] + os: [linux] + + '@typescript/typescript-linux-s390x@7.0.2': + resolution: {integrity: sha512-IkwJc3L7yhytWd/ewjyxNDfOmswCm9GWMJT/ue/dU4aZNbwZeYAetq42VyLmsmSjvoX7z74X6ZaYCtzAr0EuGw==} + engines: {node: '>=16.20.0'} + cpu: [s390x] + os: [linux] + + '@typescript/typescript-linux-x64@7.0.2': + resolution: {integrity: sha512-EYdf2cNg7rgCWJnxCdJ+F3V39O8ihb37eHAu1LK8oAFizgTQbPOK7zHHXbPt8rX24COqODXeI3sIf0fCXG7H/A==} + engines: {node: '>=16.20.0'} + cpu: [x64] + os: [linux] + + '@typescript/typescript-netbsd-arm64@7.0.2': + resolution: {integrity: sha512-+polYF4MF04aPpO5FTkHran9yUQDSXqy5GiSDKpsll5jy3l3+g9QLhpf39T+ePtefhXLOGrLl0QIjkQP6VnelA==} + engines: {node: '>=16.20.0'} + cpu: [arm64] + os: [netbsd] + + '@typescript/typescript-netbsd-x64@7.0.2': + resolution: {integrity: sha512-8YIT0EHM/3dq10ZOVF/A7pc/YSMtbcecct4rWtexrnSCHOPcpC2KTLXfTCR6vDpnSiY12heNb1GiN/wu+T/FyA==} + engines: {node: '>=16.20.0'} + cpu: [x64] + os: [netbsd] + + '@typescript/typescript-openbsd-arm64@7.0.2': + resolution: {integrity: sha512-APT8+ClYnuYm1u9+kgGXoMj2VzWzcymwh2gNSQVySHfkRDGOTVkoWLjCmOQSaO+PoqQ57B0flRp9SA+7GnnkzQ==} + engines: {node: '>=16.20.0'} + cpu: [arm64] + os: [openbsd] + + '@typescript/typescript-openbsd-x64@7.0.2': + resolution: {integrity: sha512-yX7s+Q0Dln0Dt9tEzZsAjXXR/+ytBM7AlglaqyeMPxQszJ1JhlJdZ6jLA+IzldHtflX81em7lDao1xXu+aRRkg==} + engines: {node: '>=16.20.0'} + cpu: [x64] + os: [openbsd] + + '@typescript/typescript-sunos-x64@7.0.2': + resolution: {integrity: sha512-dLJDGaLZ1D4HPQn62u1n8mBDkJREwMsAkCdkwd4Ieqw+x3TUyTsqY0YiBCtE6H6OzzgGk3iuZ3vFWRS+E8/d1g==} + engines: {node: '>=16.20.0'} + cpu: [x64] + os: [sunos] + + '@typescript/typescript-win32-arm64@7.0.2': + resolution: {integrity: sha512-Gyl1Vy6OsWesLzmq+EP0Fb7b4Nid5232AvcA2SFcdYreldpNtYFFofPjnt62y9hQy7VTaZp65ICJjuAQRaVcIQ==} + engines: {node: '>=16.20.0'} + cpu: [arm64] + os: [win32] + + '@typescript/typescript-win32-x64@7.0.2': + resolution: {integrity: sha512-0BQ3HkAHHlKLSp1qRvf3SUhGpGsDuhB/jgFw75guyqbxJqEaS0Cw/VFO8i2nHglJUzQCRtMMR/IBAKE3ETMC4g==} + engines: {node: '>=16.20.0'} + cpu: [x64] + os: [win32] + + '@ungap/structured-clone@1.4.0': + resolution: {integrity: sha512-1mEZtMKPM09vDmQt5y7YvmN2+DFTP7Tg0EWXdic8/C6VRnpb33e4ghisCIE3WZjsE2N8mf+QV1Zqh7ZFYLWInQ==} + + '@unpic/core@1.0.3': + resolution: {integrity: sha512-aum9YNVUGso7MjGLD0Rp/08kywCGLqZ03/q6VQBFFakDBOXWEc8D4kPGcZ8v5wEnGRex3lE+++bOuucBp3KJ/w==} + + '@unpic/react@1.0.2': + resolution: {integrity: sha512-5RmRfELwTF8w+4zjtQGqjpvX+RU2VLvis3xDCS1O2uWk0PZN2cvatL+3/KAR3mshAuRrkFGTX1XwyAezSXaoCA==} + peerDependencies: + next: ^13.0.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 + react: ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + next: + optional: true + + '@vercel/og@1.0.3': + resolution: {integrity: sha512-/iYJ34PDu4lty1TXdL86qHEw8viveHTllG1PWLuJX8tSFfqKL7kyVJeUORJmQ250bHB0h+alcalXUlza3c/NSA==} + engines: {node: '>=22'} + + '@vinext/types@1.0.2': + resolution: {integrity: sha512-ORcuy4DNiT2EFsLsCh2FtZz1I7Q3HGf1PSu80ALqwlq+en7UJeLKQE7FmKgvW0cJL79GvZuZe4jddzGpqDMw/Q==} + engines: {node: '>=22'} + + '@vitejs/plugin-react@6.0.1': + resolution: {integrity: sha512-l9X/E3cDb+xY3SWzlG1MOGt2usfEHGMNIaegaUGFsLkb3RCn/k8/TOXBcab+OndDI4TBtktT8/9BwwW8Vi9KUQ==} + engines: {node: ^20.19.0 || >=22.12.0} + peerDependencies: + '@rolldown/plugin-babel': ^0.1.7 || ^0.2.0 + babel-plugin-react-compiler: ^1.0.0 + vite: ^8.0.0 + peerDependenciesMeta: + '@rolldown/plugin-babel': + optional: true + babel-plugin-react-compiler: + optional: true + + '@vitejs/plugin-rsc@0.5.38': + resolution: {integrity: sha512-SoiRBJBVd3Qg6Frnvdk6LwugJYlQKgee+uqySxKz5T/KsCZUgdw529Klzg4IDJuP/EOfsIJ2YiOKAFY8tnr1kg==} + peerDependencies: + react: '*' + react-dom: '*' + react-server-dom-webpack: '*' + vite: '*' + peerDependenciesMeta: + react-server-dom-webpack: + optional: true + + '@vitest/expect@3.2.7': + resolution: {integrity: sha512-E8eBXaKibuvH2pSZErOjdVb5vF4PbKYcrnluBTYxEk1l/VhhwZg1kZQsdtjq+CsF5CFydf2Rdkz7jDHKSisi3w==} + + '@vitest/mocker@3.2.7': + resolution: {integrity: sha512-Trr0hYO9CM3Wj6ksWHRhK9IZpIY6wTMO5u/MqXurMxT57sWBaOPEtP3Oq60ihZuh5JsiagKfz95OcxdEP6dBrA==} + peerDependencies: + msw: ^2.4.9 + vite: ^5.0.0 || ^6.0.0 || ^7.0.0-0 + peerDependenciesMeta: + msw: + optional: true + vite: + optional: true + + '@vitest/pretty-format@3.2.7': + resolution: {integrity: sha512-KUHlwqVu0sRlhCdyPdQ/wBoTfRahjUky1MubOmYw9fWfIZy1gNoHpuaaQBPAaMaVYdQYHJLurzj8ECCj5OwTqA==} + + '@vitest/runner@3.2.7': + resolution: {integrity: sha512-sB9y4ovltoQP+WaUPwmSxO9WIg9Ig694Di5PalVPsYHklAdE027mehpWF2SQSVq+k6sFgaivbTjTJwZLSHbedA==} + + '@vitest/snapshot@3.2.7': + resolution: {integrity: sha512-7C+MwShwtBSI5Buwoyg3s/iY1eHL9PKAf+O1wVh/TdnjXUtkoL/9YQtre90i4MtNXM6edP1wJ2zOBpfCyhIS7g==} + + '@vitest/spy@3.2.7': + resolution: {integrity: sha512-Q2eQGI6d2L/hBtZ0qNuKcAGid68XK6cv1xsoaIma6PaJhHPoqcEJhYpXZ/5myCMqkNgtP6UKuBhbc0nHKnrkuQ==} + + '@vitest/utils@3.2.7': + resolution: {integrity: sha512-x6BDOd7dyo3PFLY3I9/HJ25X/6OurhGXk2/B9gOZNPF7XDVjeBK4k01lQE5uvDpbuheErh91qYuE1E2OEjK3Rw==} + + '@webassemblyjs/ast@1.14.1': + resolution: {integrity: sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==} + + '@webassemblyjs/floating-point-hex-parser@1.13.2': + resolution: {integrity: sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==} + + '@webassemblyjs/helper-api-error@1.13.2': + resolution: {integrity: sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==} + + '@webassemblyjs/helper-buffer@1.14.1': + resolution: {integrity: sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==} + + '@webassemblyjs/helper-numbers@1.13.2': + resolution: {integrity: sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==} + + '@webassemblyjs/helper-wasm-bytecode@1.13.2': + resolution: {integrity: sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==} + + '@webassemblyjs/helper-wasm-section@1.14.1': + resolution: {integrity: sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==} + + '@webassemblyjs/ieee754@1.13.2': + resolution: {integrity: sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==} + + '@webassemblyjs/leb128@1.13.2': + resolution: {integrity: sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==} + + '@webassemblyjs/utf8@1.13.2': + resolution: {integrity: sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==} + + '@webassemblyjs/wasm-edit@1.14.1': + resolution: {integrity: sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==} + + '@webassemblyjs/wasm-gen@1.14.1': + resolution: {integrity: sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==} + + '@webassemblyjs/wasm-opt@1.14.1': + resolution: {integrity: sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==} + + '@webassemblyjs/wasm-parser@1.14.1': + resolution: {integrity: sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==} + + '@webassemblyjs/wast-printer@1.14.1': + resolution: {integrity: sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==} + + '@xtuc/ieee754@1.2.0': + resolution: {integrity: sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==} + + '@xtuc/long@4.2.2': + resolution: {integrity: sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==} + + '@yudiel/react-qr-scanner@2.6.0': + resolution: {integrity: sha512-WjNcSt7qquYUz1LVbwKzSnRQI47sNrh4Vh6nNiGKVxnYcP+KgN5q9rcSzXyZ/7GRV9PPrnzoIuE5YdOxB9yAog==} + engines: {node: '>=18.0.0'} + peerDependencies: + '@types/react': '*' + react: ^17 || ^18 || ^19 + react-dom: ^17 || ^18 || ^19 + + '@yuku-core/binding-android-arm64@0.19.0': + resolution: {integrity: sha512-wdL2XmTiZixAOaHk9Z0JJZ8u9Qm8d333Zjpc6gaxXFX+UR5BlsfxZ7a2+2Rm71pamppsPYGUGFq2oVLbh6DISw==} + cpu: [arm64] + os: [android] + + '@yuku-core/binding-darwin-arm64@0.19.0': + resolution: {integrity: sha512-7sNJa6XJhyetnTy64jw3NEi4YgUcezHk1G5GH9FSvXAuC8wIlbaOwT9lgq5qo5sspjrZJQlBR1TWflP49uRpMw==} + cpu: [arm64] + os: [darwin] + + '@yuku-core/binding-darwin-x64@0.19.0': + resolution: {integrity: sha512-pTC7dYEc59isdyizc3nsuyFNBu2LU5wMYZ1be6UMr59PY/AJNtO1aBLWV0MgL/z7C1nv/2sX4TNjGgKLoeevJw==} + cpu: [x64] + os: [darwin] + + '@yuku-core/binding-freebsd-x64@0.19.0': + resolution: {integrity: sha512-xrZjF6XOEwyLOiDIfrwDdRCS6ghxcJeirNC1KivQhVcUwlRonaU79S3/Uiyx3lBylPnT8qKJ3/aMT+H52nGTJQ==} + cpu: [x64] + os: [freebsd] + + '@yuku-core/binding-linux-arm-gnu@0.19.0': + resolution: {integrity: sha512-0OyIH53C0I1CbADHn9FSdCfX5qbpeLwJhmOVhonFJNYheybOnkSJ50qGMfTJIb8y5zrwqvLs7FVBvz6Fk8maZg==} + cpu: [arm] + os: [linux] + libc: [glibc] + + '@yuku-core/binding-linux-arm-musl@0.19.0': + resolution: {integrity: sha512-z/iPfkCOCSXE34VXNt0uP1ORSW+4mEa9b5CiJcWZeqZH08g49bFU/jRM2T04f+Wpw5mJ6HIzNBiojxeAbrHjeg==} + cpu: [arm] + os: [linux] + libc: [musl] + + '@yuku-core/binding-linux-arm64-gnu@0.19.0': + resolution: {integrity: sha512-jLNTi+gzaRwBJ+gwhCJ+rDb5dmx/8hEBx93UWd7hjMSqPTL1D1wvVSvXVAldV5kALvju7b0/m51EHEhs4+I1fA==} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@yuku-core/binding-linux-arm64-musl@0.19.0': + resolution: {integrity: sha512-YwyPIdW/rN2Fmv0MTFWi47FaB3F9g+2b+sJISyAw83Yd60RWH4T3Nx6XkAHHVN+uKJNBAd6So7/BVihSiFYvuQ==} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@yuku-core/binding-linux-x64-gnu@0.19.0': + resolution: {integrity: sha512-/vskaAXVX3ESR43FiTdfiYS7z1b9uoQJwVQ/0RgUHgN2sWoAyCZs+aX4CgU7eKGIHTVfp9VFwv+c+2XchYiEtQ==} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@yuku-core/binding-linux-x64-musl@0.19.0': + resolution: {integrity: sha512-FuXL5igeSKib9Rye02TdH+D6SQezTyGxIATMu1Qsn/QywrzwpGl35OLpS2C1x5vpGLeVE2XgiLd5mVPFHmIglQ==} + cpu: [x64] + os: [linux] + libc: [musl] + + '@yuku-core/binding-win32-arm64@0.19.0': + resolution: {integrity: sha512-YuJAe7zEKT1Xa7LuHlhGJpPnYQeVtvo0rZvNjJRqkH0hQGOw4C8QeP30Tg5VKGzZfo2x8CjhjEhKt4TmLwfmdg==} + cpu: [arm64] + os: [win32] + + '@yuku-core/binding-win32-x64@0.19.0': + resolution: {integrity: sha512-o8iY/mXwlRkedp0LNTr4+TEfXTPQwoNZmv6k+1WIAd1ZXEn8xJJTBCtB0osaVvdZo/x/cNmV16UrWrrGpM5Mvw==} + cpu: [x64] + os: [win32] + + '@yuku-toolchain/types@0.19.0': + resolution: {integrity: sha512-tFkNbsP4WXX9UMUC5syJGdK9dPMLK0PPaIuXCcCYH75sZ8MrebfBZ2XvCILRTw8AgLivSSCfDa4R67iYBDa4Kg==} + + '@zeit/schemas@2.36.0': + resolution: {integrity: sha512-7kjMwcChYEzMKjeex9ZFXkt1AyNov9R5HZtjBKVsmVpw7pa7ZtlCGvCBC2vnnXctaYN+aRI61HjIqeetZW5ROg==} + + acorn-jsx@5.3.2: + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + + acorn-loose@8.5.2: + resolution: {integrity: sha512-PPvV6g8UGMGgjrMu+n/f9E/tCSkNQ2Y97eFvuVdJfG11+xdIeDcLyNdC8SHcrHbRqkfwLASdplyR6B6sKM1U4A==} + engines: {node: '>=0.4.0'} + + acorn@8.19.0: + resolution: {integrity: sha512-oJlA3XiRm7Cyk6qFD2Jn8ak9B7jSy0qy00ADO3+8dpT0LSjFihQYv4C02LFCSYJV3Q37xYwwRy5m+IpIiUzqWw==} + engines: {node: '>=0.4.0'} + hasBin: true + + ajv-formats@3.0.1: + resolution: {integrity: sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==} + peerDependencies: + ajv: ^8.0.0 + peerDependenciesMeta: + ajv: + optional: true + + ajv-keywords@5.1.0: + resolution: {integrity: sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==} + peerDependencies: + ajv: ^8.8.2 + + ajv@6.15.0: + resolution: {integrity: sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==} + + ajv@8.18.0: + resolution: {integrity: sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==} + + ajv@8.20.0: + resolution: {integrity: sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==} + + ansi-align@3.0.1: + resolution: {integrity: sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==} + + ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + + ansi-regex@6.4.0: + resolution: {integrity: sha512-KzTVk2tCWAHtYrvvvaP8bJKJq2pVinhLcGEQdtLIYPbmNGNyYe8QwNaTUYQp2J7/vIsUKt5QCqAfUkYyG9DkOw==} + engines: {node: '>=12'} + + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + + ansi-styles@6.2.3: + resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==} + engines: {node: '>=12'} + + any-promise@1.3.0: + resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} + + anymatch@3.1.3: + resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} + engines: {node: '>= 8'} + + arch@2.2.0: + resolution: {integrity: sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==} + + arg@5.0.2: + resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} + + aria-hidden@1.2.6: + resolution: {integrity: sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==} + engines: {node: '>=10'} + + assertion-error@2.0.1: + resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} + engines: {node: '>=12'} + + astring@1.9.0: + resolution: {integrity: sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg==} + hasBin: true + + autoprefixer@10.4.19: + resolution: {integrity: sha512-BaENR2+zBZ8xXhM4pUaKUxlVdxZ0EZhjvbopwnXmxRUfqDmwSpC2lAi/QXvx7NRdPCo1WKEcEF6mV64si1z4Ew==} + engines: {node: ^10 || ^12 || >=14} + hasBin: true + peerDependencies: + postcss: ^8.1.0 + + aws-ssl-profiles@1.1.2: + resolution: {integrity: sha512-NZKeq9AfyQvEeNlN0zSYAaWrmBffJh3IELMZfRpJVWgrpEbtEpnjvzqBPf+mxoI287JohRDoa+/nsfqqiZmF6g==} + engines: {node: '>= 6.0.0'} + + bail@2.0.2: + resolution: {integrity: sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==} + + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + balanced-match@4.0.4: + resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==} + engines: {node: 18 || 20 || >=22} + + barcode-detector@3.2.3: + resolution: {integrity: sha512-PLinpWGiOQoQH4X+YObWZ6iXeffXKDM3d4vnOD86481SvukIfvkf7jEE/tud9oI4HTDxtDdlHaFilA5Kn7Xa7A==} + + base64-js@0.0.8: + resolution: {integrity: sha512-3XSA2cR/h/73EzlXXdU6YNycmYI7+kicTxks4eJg2g39biHR84slg2+des+p7iHYhbRg/udIS4TD53WabcOUkw==} + engines: {node: '>= 0.4'} + + baseline-browser-mapping@2.11.33: + resolution: {integrity: sha512-yiVKDX+qCMRKBE084lXvq9EcwFUhKZ2nU8TK1EQQuOgPNR/lmbGxXOeDdlGUqC2Zz11Cs9rk1d/8NfgBmlkt0w==} + engines: {node: '>=6.0.0'} + hasBin: true + + better-auth@1.7.6: + resolution: {integrity: sha512-WTMqOpmTTj+oBoX7zzPOzL85342Upyf+/v0IkH1kvGRA85lV4JGRFIYMIRKqvjZ6ShsuL5VX/c9C13jtoZXcKA==} + peerDependencies: + '@lynx-js/react': '*' + '@prisma/client': ^5.0.0 || ^6.0.0 || ^7.0.0 + '@sveltejs/kit': ^2.0.0 + '@tanstack/react-start': ^1.0.0 + '@tanstack/solid-start': ^1.0.0 + drizzle-kit: '>=0.31.4 || >=1.0.0-beta.1' + drizzle-orm: ^0.45.2 || >=1.0.0-rc.1 <2.0.0 + mongodb: ^6.0.0 || ^7.0.0 + mysql2: ^3.0.0 + next: ^14.0.0 || ^15.0.0 || ^16.0.0 + pg: ^8.0.0 + prisma: ^5.0.0 || ^6.0.0 || ^7.0.0 + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + solid-js: ^1.0.0 + svelte: ^4.0.0 || ^5.0.0 + vitest: ^2.0.0 || ^3.0.0 || ^4.0.0 || ^5.0.0 + vue: ^3.0.0 + peerDependenciesMeta: + '@lynx-js/react': + optional: true + '@prisma/client': + optional: true + '@sveltejs/kit': + optional: true + '@tanstack/react-start': + optional: true + '@tanstack/solid-start': + optional: true + drizzle-kit: + optional: true + drizzle-orm: + optional: true + mongodb: + optional: true + mysql2: + optional: true + next: + optional: true + pg: + optional: true + prisma: + optional: true + react: + optional: true + react-dom: + optional: true + solid-js: + optional: true + svelte: + optional: true + vitest: + optional: true + vue: + optional: true + + better-call@1.4.0: + resolution: {integrity: sha512-bBKOT4vv1kZLDgxVePdilk/Jwkn+dtRRsmi3DzHcDP+WnswyVl6dR59l2HEeP/0cB+bDoopASAesWDPIdd/zZA==} + peerDependencies: + zod: ^4.0.0 + peerDependenciesMeta: + zod: + optional: true + + better-sqlite3@13.0.3: + resolution: {integrity: sha512-RbOBxmLBG8uvFUc15X9+9SFemKcQ0WBuISBVkpuiaUB2qblC8UWlHEjdWVoZ8AdhSwmoEgsiXKfopX0CQxaACQ==} + engines: {node: '>=22'} + + binary-extensions@2.3.0: + resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} + engines: {node: '>=8'} + + blake3-wasm@2.1.5: + resolution: {integrity: sha512-F1+K8EbfOZE49dtoPtmxUQrpXaBIl3ICvasLh+nJta0xkz+9kF/7uet9fLnwKqhDrmj6g+6K3Tw9yQPUg2ka5g==} + + bowser@2.15.0: + resolution: {integrity: sha512-xic6KSZglg/I4ymp45fdM4GWfYpBK79Fxd/TOvJktlaPgQqqDxvmGwOPZl2V0dyeS3Lj5c180bLhXF43iyAjZQ==} + + boxen@7.0.0: + resolution: {integrity: sha512-j//dBVuyacJbvW+tvZ9HuH03fZ46QcaKvvhZickZqtB271DxJ7SNRSNxrV/dZX0085m7hISRZWbzWlJvx/rHSg==} + engines: {node: '>=14.16'} + + brace-expansion@1.1.21: + resolution: {integrity: sha512-9zeA+KLZNNzglF2TPKRQEDyx6Yby7daAkuy8MiPzpXPsYDWi/DRM8jmwUDxokQjYqBpv5DgPiwD4h4ZZSy1Ujw==} + + brace-expansion@5.0.12: + resolution: {integrity: sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==} + engines: {node: 20 || >=22} + + braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} + + browserslist@4.29.5: + resolution: {integrity: sha512-khTmKu5NGYTotqcYo8Bew2k4RAE9PuXRSFRXG2lQBrCEQHyeQ/vX6gKMxfokwywBsLiXZMnHsmWMG1pnO8J7uQ==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + + buffer-from@1.1.2: + resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + + bundle-require@5.1.0: + resolution: {integrity: sha512-3WrrOuZiyaaZPWiEt4G3+IffISVC9HYlWueJEBWED4ZH4aIAC2PnkdnuRrR94M+w6yGWn4AglWtJtBI8YqvgoA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + peerDependencies: + esbuild: '>=0.18' + + busboy@1.6.0: + resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==} + engines: {node: '>=10.16.0'} + + bytes@3.0.0: + resolution: {integrity: sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==} + engines: {node: '>= 0.8'} + + bytes@3.1.2: + resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} + engines: {node: '>= 0.8'} + + cac@6.7.14: + resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} + engines: {node: '>=8'} + + cacheable@2.5.0: + resolution: {integrity: sha512-60cyAOytib/OzBw1JNSoSV/boK1AtHryDIjvVBk7XbN4ugfkM3+Sry7fEjNgPMGgOjuaZPAp8ruZ0Cxafwyq9g==} + + camelcase-css@2.0.1: + resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==} + engines: {node: '>= 6'} + + camelcase@7.0.1: + resolution: {integrity: sha512-xlx1yCK2Oc1APsPXDL2LdlNP6+uu8OCDdhOBSVT279M/S+y75O30C2VuD8T2ogdePBBl7PfPF4504tnLgX3zfw==} + engines: {node: '>=14.16'} + + camelize@1.0.1: + resolution: {integrity: sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==} + + caniuse-lite@1.0.30001819: + resolution: {integrity: sha512-LFUqIIAwpzsIuevnKnsR9qnStBcgzPShTX61lBwN9uFkkf8o8zLiebEjbW8AYtZiF+1YKDWfdt/pWDtMuG8Xwg==} + + ccount@2.0.1: + resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} + + chai@5.3.3: + resolution: {integrity: sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==} + engines: {node: '>=18'} + + chalk-template@0.4.0: + resolution: {integrity: sha512-/ghrgmhfY8RaSdeo43hNXxpoHAtxdbskUHjPpfqUWGttFgycUhYPGx3YZBCnUCvOa7Doivn1IZec3DEGFoMgLg==} + engines: {node: '>=12'} + + chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + + chalk@5.0.1: + resolution: {integrity: sha512-Fo07WOYGqMfCWHOzSXOt2CxDbC6skS/jO9ynEcmpANMoPrD+W1r1K6Vx7iNm+AQmETU1Xr2t+n8nzkV9t6xh3w==} + engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + + character-entities-html4@2.1.0: + resolution: {integrity: sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==} + + character-entities-legacy@3.0.0: + resolution: {integrity: sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==} + + character-entities@2.0.2: + resolution: {integrity: sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==} + + character-reference-invalid@2.0.1: + resolution: {integrity: sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==} + + chardet@2.2.0: + resolution: {integrity: sha512-rddelWYNPRrXq6PtNEN2S3f6t9ILzvqaN5pVgi4kqt9jHQaXIial9PznB5iSPVlQSLNaaH22ItWz3EJtQ10+OA==} + + check-error@2.1.3: + resolution: {integrity: sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA==} + engines: {node: '>= 16'} + + chokidar@3.6.0: + resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} + engines: {node: '>= 8.10.0'} + + chokidar@4.0.3: + resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} + engines: {node: '>= 14.16.0'} + + chokidar@5.0.0: + resolution: {integrity: sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==} + engines: {node: '>= 20.19.0'} + + chrome-trace-event@1.0.4: + resolution: {integrity: sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==} + engines: {node: '>=6.0'} + + class-variance-authority@0.7.1: + resolution: {integrity: sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==} + + cli-boxes@3.0.0: + resolution: {integrity: sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==} + engines: {node: '>=10'} + + cli-width@4.1.0: + resolution: {integrity: sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==} + engines: {node: '>= 12'} + + client-only@0.0.1: + resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} + + clipboardy@3.0.0: + resolution: {integrity: sha512-Su+uU5sr1jkUy1sGRpLKjKrvEOVXgSgiSInwa/qeID6aJ07yh+5NWc3h2QfjHjBnfX4LhtFcuAWKUsJ3r+fjbg==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + cliui@8.0.1: + resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} + engines: {node: '>=12'} + + clsx@2.1.1: + resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} + engines: {node: '>=6'} + + cn@0.4.0: + resolution: {integrity: sha512-qOAeUhPwPzBxx6jaeQdo646XIKliKHc2j1ZF7Ngb1o0pJZKH5gq8FkA0aVdUdPFUDXNXyUCXpCtoJISo6dhizg==} + engines: {node: '>=20'} + hasBin: true + + cn@0.5.0: + resolution: {integrity: sha512-JGEixZEpfFXm1P5uXwvEobOFLlHwIWi5v4tjd1ZwfiYmcEilkuD2l+054rvJcYCR1B+uVThHeUbgmNz1FwuxuA==} + engines: {node: '>=22'} + hasBin: true + + collapse-white-space@2.1.0: + resolution: {integrity: sha512-loKTxY1zCOuG4j9f6EPnuyyYkf58RnhhWTvRoZEokgB+WbdXehfjFviyOVYkqzEWz1Q5kRiZdBYS5SwxbQYwzw==} + + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + comma-separated-tokens@2.0.3: + resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==} + + commander@12.1.0: + resolution: {integrity: sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==} + engines: {node: '>=18'} + + commander@2.20.3: + resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} + + commander@4.1.1: + resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} + engines: {node: '>= 6'} + + compressible@2.0.18: + resolution: {integrity: sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==} + engines: {node: '>= 0.6'} + + compression@1.8.1: + resolution: {integrity: sha512-9mAqGPHLakhCLeNyxPkK4xVo746zQ/czLH1Ky+vkitMnWfWZps8r0qXuwhwizagCRttsL4lfG4pIOvaWLpAP0w==} + engines: {node: '>= 0.8.0'} + + compute-scroll-into-view@3.1.1: + resolution: {integrity: sha512-VRhuHOLoKYOy4UbilLbUzbYg93XLjv2PncJC50EuTWPA3gaja1UjBsUP/D/9/juV3vQFr6XBEzn9KCAHdUvOHw==} + + concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + + confbox@0.1.8: + resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} + + consola@3.4.2: + resolution: {integrity: sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==} + engines: {node: ^14.18.0 || >=16.10.0} + + content-disposition@0.5.2: + resolution: {integrity: sha512-kRGRZw3bLlFISDBgwTSA1TMBFN6J6GWDeubmDE3AF+3+yXL8hTWv8r5rkLbqYXY4RjPk/EzHnClI3zQf1cFmHA==} + engines: {node: '>= 0.6'} + + cookie@1.1.1: + resolution: {integrity: sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==} + engines: {node: '>=18'} + + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} + engines: {node: '>= 8'} + + css-background-parser@0.1.0: + resolution: {integrity: sha512-2EZLisiZQ+7m4wwur/qiYJRniHX4K5Tc9w93MT3AS0WS1u5kaZ4FKXlOTBhOjc+CgEgPiGY+fX1yWD8UwpEqUA==} + + css-box-shadow@1.0.0-3: + resolution: {integrity: sha512-9jaqR6e7Ohds+aWwmhe6wILJ99xYQbfmK9QQB9CcMjDbTxPZjwEmUQpU91OG05Xgm8BahT5fW+svbsQGjS/zPg==} + + css-color-keywords@1.0.0: + resolution: {integrity: sha512-FyyrDHZKEjXDpNJYvVsV960FiqQyXc/LlYmsxl2BcdMb2WPx0OGRVgTg55rPSyLSNMqP52R9r8geSp7apN3Ofg==} + engines: {node: '>=4'} + + css-gradient-parser@0.0.17: + resolution: {integrity: sha512-w2Xy9UMMwlKtou0vlRnXvWglPAceXCTtcmVSo8ZBUvqCV5aXEFP/PC6d+I464810I9FT++UACwTD5511bmGPUg==} + engines: {node: '>=16'} + + css-to-react-native@3.2.0: + resolution: {integrity: sha512-e8RKaLXMOFii+02mOlqwjbD00KSEKqblnpO9e++1aXS1fPQOpS1YoqdVHBqPjHNoxeF2mimzVqawm2KCbEdtHQ==} + + cssesc@3.0.0: + resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} + engines: {node: '>=4'} + hasBin: true + + csstype@3.2.3: + resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} + + debug@2.6.9: + resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + decode-named-character-reference@1.3.0: + resolution: {integrity: sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==} + + deep-eql@5.0.2: + resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==} + engines: {node: '>=6'} + + deep-extend@0.6.0: + resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==} + engines: {node: '>=4.0.0'} + + deep-is@0.1.4: + resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + + defu@6.1.7: + resolution: {integrity: sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ==} + + dequal@2.0.3: + resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} + engines: {node: '>=6'} + + detect-libc@2.0.2: + resolution: {integrity: sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==} + engines: {node: '>=8'} + + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} + engines: {node: '>=8'} + + detect-node-es@1.1.0: + resolution: {integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==} + + devlop@1.1.0: + resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} + + didyoumean@1.2.2: + resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==} + + dlv@1.1.3: + resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==} + + dotenv-cli@7.4.4: + resolution: {integrity: sha512-XkBYCG0tPIes+YZr4SpfFv76SQrV/LeCE8CI7JSEMi3VR9MvTihCGTOtbIexD6i2mXF+6px7trb1imVCXSNMDw==} + hasBin: true + + dotenv-expand@10.0.0: + resolution: {integrity: sha512-GopVGCpVS1UKH75VKHGuQFqS1Gusej0z4FyQkPdwjil2gNIv+LNsqBlboOzpJFZKVT95GkCyWJbBSdFEFUWI2A==} + engines: {node: '>=12'} + + dotenv@16.6.1: + resolution: {integrity: sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==} + engines: {node: '>=12'} + + eastasianwidth@0.2.0: + resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + + electron-to-chromium@1.5.465: + resolution: {integrity: sha512-zg4iUpbeGw7YNZsswc2xKr2uiBex2d8dELAXo92Icw3but1ULbrvK8USe6wVLaWjgJnKBARv0pchx9Owktx6wQ==} + + emoji-regex-xs@2.0.1: + resolution: {integrity: sha512-1QFuh8l7LqUcKe24LsPUNzjrzJQ7pgRwp1QMcZ5MX6mFplk2zQ08NVCM84++1cveaUUYtcCYHmeFEuNg16sU4g==} + engines: {node: '>=10.0.0'} + + emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + + emoji-regex@9.2.2: + resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + + enhanced-resolve@5.26.0: + resolution: {integrity: sha512-9vhedylFonb2YGogzUKX6+Ja72gOJbN1QHAqdrvqLwhdl/QWbKopzoUC9EbQNVsAns/bx/4uyqalrQAoy1IByw==} + engines: {node: '>=10.13.0'} + + error-stack-parser-es@1.0.5: + resolution: {integrity: sha512-5qucVt2XcuGMcEGgWI7i+yZpmpByQ8J1lHhcL7PwqCwu9FPP3VUXzT4ltHe5i2z9dePwEHcDVOAfSnHsOlCXRA==} + + es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + + es-module-lexer@1.7.0: + resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} + + es-module-lexer@2.3.2: + resolution: {integrity: sha512-poHGpORABojJJucnV9KbOavETW8lBVnphkW77ER5/BQ5Fz7oXSoCNek7IH3vR5nRjdsEz926ibFYX8KtLQmdyw==} + + es-module-lexer@3.0.4: + resolution: {integrity: sha512-BldNY5mwkVu+cQ5Ymn3e6hB9Sx8XHx4ZevWbiUyZbfKxJxYO27Hf0wfzkxIaD5CAJMaGl3YspKELj0ff/7nCMA==} + + esast-util-from-estree@2.0.0: + resolution: {integrity: sha512-4CyanoAudUSBAn5K13H4JhsMH6L9ZP7XbLVe/dKybkxMO7eDyLsT8UHl9TRNrU2Gr9nz+FovfSIjuXWJ81uVwQ==} + + esast-util-from-js@2.0.1: + resolution: {integrity: sha512-8Ja+rNJ0Lt56Pcf3TAmpBZjmx8ZcK5Ts4cAzIOjsjevg9oSXJnl6SUQ2EevU8tv3h6ZLWmoKL5H4fgWvdvfETw==} + + esbuild@0.25.12: + resolution: {integrity: sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==} + engines: {node: '>=18'} + hasBin: true + + esbuild@0.27.7: + resolution: {integrity: sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==} + engines: {node: '>=18'} + hasBin: true + + esbuild@0.28.2: + resolution: {integrity: sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA==} + engines: {node: '>=18'} + hasBin: true + + escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} + engines: {node: '>=6'} + + escape-html@1.0.3: + resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} + + escape-string-regexp@4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + + escape-string-regexp@5.0.0: + resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==} + engines: {node: '>=12'} + + eslint-scope@9.1.2: + resolution: {integrity: sha512-xS90H51cKw0jltxmvmHy2Iai1LIqrfbw57b79w/J7MfvDfkIkFZ+kj6zC3BjtUwh150HsSSdxXZcsuv72miDFQ==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + + eslint-visitor-keys@3.4.3: + resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + eslint-visitor-keys@5.0.1: + resolution: {integrity: sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + + eslint@10.13.0: + resolution: {integrity: sha512-UohDjD4zSzEwhf58M3O7vc/ycc8O1I7dNlhtD0WxE8Px8EHNJKtUwzBqrzeGhisRuv2ag4sAYswszCJRgKXYUg==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + hasBin: true + peerDependencies: + jiti: '*' + peerDependenciesMeta: + jiti: + optional: true + + espree@11.2.0: + resolution: {integrity: sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + + esquery@1.7.0: + resolution: {integrity: sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==} + engines: {node: '>=0.10'} + + esrecurse@4.3.0: + resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} + engines: {node: '>=4.0'} + + estraverse@5.3.0: + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} + engines: {node: '>=4.0'} + + estree-util-attach-comments@3.0.0: + resolution: {integrity: sha512-cKUwm/HUcTDsYh/9FgnuFqpfquUbwIqwKM26BVCGDPVgvaCl/nDCCjUfiLlx6lsEZ3Z4RFxNbOQ60pkaEwFxGw==} + + estree-util-build-jsx@3.0.1: + resolution: {integrity: sha512-8U5eiL6BTrPxp/CHbs2yMgP8ftMhR5ww1eIKoWRMlqvltHF8fZn5LRDvTKuxD3DUn+shRbLGqXemcP51oFCsGQ==} + + estree-util-is-identifier-name@3.0.0: + resolution: {integrity: sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==} + + estree-util-scope@1.0.1: + resolution: {integrity: sha512-B0np3dcdxqILX5e9nEi5/Fr4K7gL4oYFVPV1zRa2e9wRCbQoZZNWOZFYyoInvXUPJXBXjss+QXlWLJChDEHDkA==} + + estree-util-to-js@2.0.0: + resolution: {integrity: sha512-WDF+xj5rRWmD5tj6bIqRi6CkLIXbbNQUcxQHzGysQzvHmdYG2G7p/Tf0J0gpxGgkeMZNTIjT/AoSvC9Xehcgdg==} + + estree-util-value-to-estree@3.5.0: + resolution: {integrity: sha512-aMV56R27Gv3QmfmF1MY12GWkGzzeAezAX+UplqHVASfjc9wNzI/X6hC0S9oxq61WT4aQesLGslWP9tKk6ghRZQ==} + + estree-util-visit@2.0.0: + resolution: {integrity: sha512-m5KgiH85xAhhW8Wta0vShLcUvOsh3LLPI2YVwcbio1l7E09NTLL1EyMZFM1OyWowoH0skScNbhOPl4kcBgzTww==} + + estree-walker@3.0.3: + resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} + + esutils@2.0.3: + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} + engines: {node: '>=0.10.0'} + + events@3.3.0: + resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} + engines: {node: '>=0.8.x'} + + execa@5.1.1: + resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} + engines: {node: '>=10'} + + expect-type@1.4.0: + resolution: {integrity: sha512-KfYbmpRm0VbLjEvVa9yGwCi9GI34xvi7A/HXYWQO65CSD2u3MczUJSuwXKFIxlGsgBQizV9q5J9NHj4VG0n+pA==} + engines: {node: '>=12.0.0'} + + extend@3.0.2: + resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} + + fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + + fast-glob@3.3.3: + resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} + engines: {node: '>=8.6.0'} + + fast-json-stable-stringify@2.1.0: + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + + fast-levenshtein@2.0.6: + resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + + fast-uri@3.1.9: + resolution: {integrity: sha512-hS/0Wt3Ya043oKXs0sIxrMpKQITXhMLIrVAKKXi4gozGC9v7YRWVnXIZzjNPTO02M9BdxLCWqK1yRXgNziVyJQ==} + + fastq@1.20.3: + resolution: {integrity: sha512-XKv5nnLs6nLF71NgiKJLIZFLkPyIEuOselLG7ujZnGrRfQK8HpvY+WqKhAJUAdLomwVHErVS4LfxFlPq0/FTAw==} + + fdir@6.5.0: + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} + engines: {node: '>=12.0.0'} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + + fflate@0.7.3: + resolution: {integrity: sha512-0Zz1jOzJWERhyhsimS54VTqOteCNwRtIlh8isdL0AXLo0g7xNTfTL7oWrkmCnPhZGocKIkWHBistBrrpoNH3aw==} + + file-entry-cache@11.1.5: + resolution: {integrity: sha512-+PFTHITI08JIGhnNpGNI8T8inUpgZfk3GNEqfT9R2zZV2iFXg3CvqzSl/uEhs7TSGujYRELEANyDvS8Fj7+S7Q==} + + fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + engines: {node: '>=8'} + + find-up@5.0.0: + resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} + engines: {node: '>=10'} + + fix-dts-default-cjs-exports@1.0.1: + resolution: {integrity: sha512-pVIECanWFC61Hzl2+oOCtoJ3F17kglZC/6N94eRWycFgBH35hHx0Li604ZIzhseh97mf2p0cv7vVrOZGoqhlEg==} + + flat-cache@6.1.23: + resolution: {integrity: sha512-f++BY9pTk+983xK1FLzlLpmM0i0z+jHmx3QESGkURMXujQZz1k5wzwX6hjnQ8goaD0B+sYnDK1yZ6MTyZfUaqA==} + + flatted@3.4.4: + resolution: {integrity: sha512-5+ybhBZANEJxaH3X5evAFatUxLfEHSr7n6kYJ+1Qd0mUqr4eu9gIf6GDbWHf8RJijHrjjO8G+la14SlL2SeS1Q==} + + fraction.js@4.3.7: + resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==} + + framer-motion@14.6.0: + resolution: {integrity: sha512-MzBgZxGgoHPfSLEXmo4o5XlZvb+nVRFdHtGjVhm6LMIEJKTt/8hNO023euL5mYyzc8llV/hQTfjnN68tNRHalw==} + peerDependencies: + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + react: + optional: true + react-dom: + optional: true + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + fumadocs-core@16.17.7: + resolution: {integrity: sha512-o8uR1JuFgAHrUSbX/hzThOsvW8tFXfV4vlrWf7VeFd+lbQsRqwr8R7gvs96Vwwzn5xSDfgg0boQalyv1llJAQQ==} + peerDependencies: + '@mdx-js/mdx': '*' + '@mixedbread/sdk': 0.x.x + '@modelcontextprotocol/server': 2.x.x + '@orama/core': 1.x.x + '@oramacloud/client': 2.x.x + '@tanstack/react-router': 1.x.x + '@types/estree-jsx': '*' + '@types/hast': '*' + '@types/mdast': '*' + '@types/react': '*' + algoliasearch: 5.x.x + flexsearch: '*' + lucide-react: '*' + meilisearch: '>=0.50.0 <1.0.0' + next: 16.x.x + react: ^19.2.0 + react-dom: ^19.2.0 + react-router: 7.x.x || 8.x.x + waku: '*' + zod: 4.x.x + peerDependenciesMeta: + '@mdx-js/mdx': + optional: true + '@mixedbread/sdk': + optional: true + '@modelcontextprotocol/server': + optional: true + '@orama/core': + optional: true + '@oramacloud/client': + optional: true + '@tanstack/react-router': + optional: true + '@types/estree-jsx': + optional: true + '@types/hast': + optional: true + '@types/mdast': + optional: true + '@types/react': + optional: true + algoliasearch: + optional: true + flexsearch: + optional: true + lucide-react: + optional: true + meilisearch: + optional: true + next: + optional: true + react: + optional: true + react-dom: + optional: true + react-router: + optional: true + waku: + optional: true + zod: + optional: true + + fumadocs-mdx@15.4.9: + resolution: {integrity: sha512-vsZGzpGsWptlBAX8sWb7R87KIt9+3GhJa5GpkwJqBv/OaN9QGul34hJikKdq6C8pT2XOwKMB499lvj31JaHbGg==} + hasBin: true + peerDependencies: + '@fumadocs/satteri': 0.x.x + '@types/mdast': '*' + '@types/mdx': '*' + '@types/react': '*' + fumadocs-core: ^16.17.0 + mdast-util-directive: '*' + next: ^15.3.0 || ^16.0.0 + react: ^19.2.0 + rolldown: '*' + satteri: ^0.10.5 + vite: 7.x.x || 8.x.x + peerDependenciesMeta: + '@fumadocs/satteri': + optional: true + '@types/mdast': + optional: true + '@types/mdx': + optional: true + '@types/react': + optional: true + mdast-util-directive: + optional: true + next: + optional: true + react: + optional: true + rolldown: + optional: true + satteri: + optional: true + vite: + optional: true + + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + generate-function@2.3.1: + resolution: {integrity: sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==} + + get-caller-file@2.0.5: + resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} + engines: {node: 6.* || 8.* || >= 10.*} + + get-nonce@1.0.1: + resolution: {integrity: sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==} + engines: {node: '>=6'} + + get-stream@6.0.1: + resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} + engines: {node: '>=10'} + + github-slugger@2.0.0: + resolution: {integrity: sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==} + + glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + + glob-parent@6.0.2: + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} + engines: {node: '>=10.13.0'} + + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + harfbuzzjs@0.10.0: + resolution: {integrity: sha512-SN8LVwCOzvTq3OPNd0+EAghgXugItz56wst567D1vs7LnnKGWprhi3EG58aVOBwhN8HEbQxL4I9NDWkcXUutRw==} + + has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + + hashery@1.5.1: + resolution: {integrity: sha512-iZyKG96/JwPz1N55vj2Ie2vXbhu440zfUfJvSwEqEbeLluk7NnapfGqa7LH0mOsnDxTF85Mx8/dyR6HfqcbmbQ==} + engines: {node: '>=20'} + + hasown@2.0.4: + resolution: {integrity: sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==} + engines: {node: '>= 0.4'} + + hast-util-from-dom@5.0.1: + resolution: {integrity: sha512-N+LqofjR2zuzTjCPzyDUdSshy4Ma6li7p/c3pA78uTwzFgENbgbUrm2ugwsOdcjI1muO+o6Dgzp9p8WHtn/39Q==} + + hast-util-parse-selector@4.0.0: + resolution: {integrity: sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==} + + hast-util-to-estree@3.1.3: + resolution: {integrity: sha512-48+B/rJWAp0jamNbAAf9M7Uf//UVqAoMmgXhBdxTDJLGKY+LRnZ99qcG+Qjl5HfMpYNzS5v4EAwVEF34LeAj7w==} + + hast-util-to-html@9.0.5: + resolution: {integrity: sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw==} + + hast-util-to-jsx-runtime@2.3.6: + resolution: {integrity: sha512-zl6s8LwNyo1P9uw+XJGvZtdFF1GdAkOg8ujOw+4Pyb76874fLps4ueHXDhXWdk6YHQ6OgUtinliG7RsYvCbbBg==} + + hast-util-whitespace@3.0.0: + resolution: {integrity: sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==} + + hastscript@9.0.1: + resolution: {integrity: sha512-g7df9rMFX/SPi34tyGCyUBREQoKkapwdY/T04Qn9TDWfHhAYt4/I0gMVirzK5wEzeUqIjEB+LXC/ypb7Aqno5w==} + + hex-rgb@4.3.0: + resolution: {integrity: sha512-Ox1pJVrDCyGHMG9CFg1tmrRUMRPRsAWYc/PinY0XzJU4K7y7vjNoLKIQ7BR5UJMCxNN8EM1MNDmHWA/B3aZUuw==} + engines: {node: '>=6'} + + hookified@1.15.1: + resolution: {integrity: sha512-MvG/clsADq1GPM2KGo2nyfaWVyn9naPiXrqIe4jYjXNZQt238kWyOGrsyc/DmRAQ+Re6yeo6yX/yoNCG5KAEVg==} + + hookified@2.2.0: + resolution: {integrity: sha512-p/LgFzRN5FeoD3DLS6bkUapeye6E4SI6yJs6KetENd18S+FBthqYq2amJUWpt5z0EQwwHemidjY5OqJGEKm5uA==} + + html-void-elements@3.0.0: + resolution: {integrity: sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==} + + human-signals@2.1.0: + resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} + engines: {node: '>=10.17.0'} + + iconv-lite@0.7.3: + resolution: {integrity: sha512-IKXpvIzjnC9XTAUbVBcMfGS0EPaIXtW6v+zr+RRp+hqULEpo0owZax6wyRwPOJbWbzjYspQwusTsfVr0ifh4uQ==} + engines: {node: '>=0.10.0'} + + ignore@5.3.2: + resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} + engines: {node: '>= 4'} + + imurmurhash@0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} + engines: {node: '>=0.8.19'} + + ini@1.3.8: + resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} + + inline-style-parser@0.2.7: + resolution: {integrity: sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA==} + + ipaddr.js@2.5.0: + resolution: {integrity: sha512-aq+t5NAc+cS6rZQQVWC2x98CPqGtKKTMDd4Gaodv0wShnItdKg/51djkGJ1hqH+Oy0ivDftCbSLCQob8zso01w==} + engines: {node: '>= 10'} + + is-alphabetical@2.0.1: + resolution: {integrity: sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==} + + is-alphanumerical@2.0.1: + resolution: {integrity: sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==} + + is-binary-path@2.1.0: + resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} + engines: {node: '>=8'} + + is-core-module@2.17.0: + resolution: {integrity: sha512-J/vG0zBCbIKOQFfufSwyXdMrsohyJIUNkrnmo6WZGzoM7tr/lsbfW5b2BvisL6zsyMzK9UxV9L6c7AoFbyXHOA==} + engines: {node: '>= 0.4'} + + is-decimal@2.0.1: + resolution: {integrity: sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==} + + is-docker@2.2.1: + resolution: {integrity: sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==} + engines: {node: '>=8'} + hasBin: true + + is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + + is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + + is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + + is-hexadecimal@2.0.1: + resolution: {integrity: sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==} + + is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + + is-plain-obj@4.1.0: + resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==} + engines: {node: '>=12'} + + is-port-reachable@4.0.0: + resolution: {integrity: sha512-9UoipoxYmSk6Xy7QFgRv2HDyaysmgSG75TFQs6S+3pDM7ZhKTF/bskZV+0UlABHzKjNVhPjYCLfeZUEg1wXxig==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + is-property@1.0.2: + resolution: {integrity: sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==} + + is-stream@2.0.1: + resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} + engines: {node: '>=8'} + + is-wsl@2.2.0: + resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==} + engines: {node: '>=8'} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + jest-worker@27.5.1: + resolution: {integrity: sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==} + engines: {node: '>= 10.13.0'} + + jiti@1.21.7: + resolution: {integrity: sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==} + hasBin: true + + jiti@2.4.2: + resolution: {integrity: sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==} + hasBin: true + + jiti@2.7.0: + resolution: {integrity: sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==} + hasBin: true + + jose@6.2.13: + resolution: {integrity: sha512-7TIg10ZE1x82YediN+lcrPNvGMKge9yFHQD+Qho/b8y2adfugU3AsvvHfxV0fzyFllT6l9xCjf4RWY9g/Z9PJQ==} + + joycon@3.1.1: + resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==} + engines: {node: '>=10'} + + js-base64@3.9.5: + resolution: {integrity: sha512-u0CFDUca8BbBRkMkF/fDcuoLCx9nTNbXdVtbjVnBqySA9E221u0uYKbACiYGOEk1heY69qM4caeX3OwjSyxevw==} + + js-tokens@10.0.0: + resolution: {integrity: sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q==} + + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + + js-tokens@9.0.1: + resolution: {integrity: sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==} + + json-schema-traverse@0.4.1: + resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + + json-schema-traverse@1.0.0: + resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + + json-stable-stringify-without-jsonify@1.0.1: + resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + + keyv@5.6.0: + resolution: {integrity: sha512-CYDD3SOtsHtyXeEORYRx2qBtpDJFjRTGXUtmNEMGyzYOKj1TE3tycdlho7kA1Ufx9OYWZzg52QFBGALTirzDSw==} + + kleur@4.1.5: + resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==} + engines: {node: '>=6'} + + kysely@0.29.6: + resolution: {integrity: sha512-hHaB8C/rfzDDtr/t8YZwxAuPJTT0zHyaPoVzcXwDYhYNAgH/4sIfVhi/XLLIY+bL/FqaIJnjATDbi8ObSELmxg==} + engines: {node: '>=22.0.0'} + + levn@0.4.1: + resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} + engines: {node: '>= 0.8.0'} + + libsql@0.5.29: + resolution: {integrity: sha512-8lMP8iMgiBzzoNbAPQ59qdVcj6UaE/Vnm+fiwX4doX4Narook0a4GPKWBEv+CR8a1OwbfkgL18uBfBjWdF0Fzg==} + cpu: [x64, arm64, wasm32, arm] + os: [darwin, linux, win32] + + lightningcss-android-arm64@1.32.0: + resolution: {integrity: sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [android] + + lightningcss-android-arm64@1.33.0: + resolution: {integrity: sha512-gEpRTalKdosp4Bb8qWtc2iOgE5SeIHlpS1up9bFq2wAyYhl1UdTObYiHe98zEM9SQvSoqQZ1IQD0JNpg3Ml5pg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [android] + + lightningcss-darwin-arm64@1.32.0: + resolution: {integrity: sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] + + lightningcss-darwin-arm64@1.33.0: + resolution: {integrity: sha512-Sciaz8eenNTKn9b3t7+xr0ipTp9YxKQY4npwQ3mrRuL0BAVHBLyZxofhaKBAVtzmtRZ/zTyo0/to4B1uWG/Djg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] + + lightningcss-darwin-x64@1.32.0: + resolution: {integrity: sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] + + lightningcss-darwin-x64@1.33.0: + resolution: {integrity: sha512-Z5UPAxzrjlWNNyGy6i65cJzzvgJ5D3T6wMvs+gWpY9d7qRhANrxqAp6LhxIgZhWEw18RfJTGcRxjuLIBr+m8XQ==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] + + lightningcss-freebsd-x64@1.32.0: + resolution: {integrity: sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [freebsd] + + lightningcss-freebsd-x64@1.33.0: + resolution: {integrity: sha512-QQM/Ti/hQajJwCY+RiWuCZ9sdtI/XQk7nDK5vC8kkdwixezOlDgvDx7+RT+QjK6FcFT4MpsuoBnHIo/O3StRRg==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [freebsd] + + lightningcss-linux-arm-gnueabihf@1.32.0: + resolution: {integrity: sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] + + lightningcss-linux-arm-gnueabihf@1.33.0: + resolution: {integrity: sha512-N7FVBe6iS24MlM6R/4RBTxGhQheZGs7tiQ9U32UtF75NzP5Q7xWPRqLBCKxlRQRk3rY1jCIPLzx7WzOhuUIRLQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] + + lightningcss-linux-arm64-gnu@1.32.0: + resolution: {integrity: sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + lightningcss-linux-arm64-gnu@1.33.0: + resolution: {integrity: sha512-j2v/itmy4HlNxlc6voKXYgBqNi0Ng2LShg4z7GufpEgs05P+2suBVyi9I6YHq5uoVFx9ETin3eCEhLVyXGQnKg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + lightningcss-linux-arm64-musl@1.32.0: + resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + libc: [musl] + + lightningcss-linux-arm64-musl@1.33.0: + resolution: {integrity: sha512-yiO5ROMuYQgXbC60yjZU5CYSFZGKXL0HFATXt9mHJn1+zW55oCtMI9NfcVhYLMFDL7gV7oBPon/EmMMGg2OvtQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + libc: [musl] + + lightningcss-linux-x64-gnu@1.32.0: + resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + libc: [glibc] + + lightningcss-linux-x64-gnu@1.33.0: + resolution: {integrity: sha512-ar+Ju7LmcN0Jo4FpL4hpFybwNG9/3A/Br5KW2n2jyODg3MEZXaDYADdemoNS+BDNfMgKvylJLj4S5tyRActuAg==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + libc: [glibc] + + lightningcss-linux-x64-musl@1.32.0: + resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + libc: [musl] + + lightningcss-linux-x64-musl@1.33.0: + resolution: {integrity: sha512-RYiYbkokw0trfKqqzfF55lginwEPrD3OJDfTuJzFs1MK6iFnDenaz1fqLLtX4ITG3OktJQXOeTaw1awrBAlZPw==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + libc: [musl] + + lightningcss-win32-arm64-msvc@1.32.0: + resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [win32] + + lightningcss-win32-arm64-msvc@1.33.0: + resolution: {integrity: sha512-1K+MPfLSFVpphzpdbfkhlWk6wBrTObBzS2T6db10PNOZgR9GoVsAWzwNyuhUYYbTp23j+4RrncfujZ4uAzXvwA==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [win32] + + lightningcss-win32-x64-msvc@1.32.0: + resolution: {integrity: sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] + + lightningcss-win32-x64-msvc@1.33.0: + resolution: {integrity: sha512-OlEICDx/Xl0FqSp4bry8zFnCvGpig3Gl4gCquvYwHuqJKEC1+n9NgDniFvqHGmMv1ZkqDJrDqKKSykTDX+ehuA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] + + lightningcss@1.32.0: + resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==} + engines: {node: '>= 12.0.0'} + + lightningcss@1.33.0: + resolution: {integrity: sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA==} + engines: {node: '>= 12.0.0'} + + lilconfig@2.1.0: + resolution: {integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==} + engines: {node: '>=10'} + + lilconfig@3.1.4: + resolution: {integrity: sha512-zJZyBmQhArDRefuWTypZxwDpFDIYmrj8ypSBvwGD5P13Y95s6DjzKgu4DVdGbeQa5PDEsAOCAPNk4X+QOR006w==} + engines: {node: '>=14'} + + linebreak@1.1.0: + resolution: {integrity: sha512-MHp03UImeVhB7XZtjd0E4n6+3xr5Dq/9xI/5FptGk5FrbDR3zagPa2DS6U8ks/3HjbKWG9Q1M2ufOzxV2qLYSQ==} + + lines-and-columns@1.2.4: + resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + + load-tsconfig@0.2.5: + resolution: {integrity: sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + locate-path@6.0.0: + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} + engines: {node: '>=10'} + + long@5.3.2: + resolution: {integrity: sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==} + + longest-streak@3.1.0: + resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==} + + loose-envify@1.4.0: + resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} + hasBin: true + + loupe@3.2.1: + resolution: {integrity: sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==} + + lru.min@1.1.5: + resolution: {integrity: sha512-5J9ysMYUpYIg9RF2vJpy9SinEmSviFSe0GyPpCQ4L5QSkLAgeLXlTAOu2ZwWUU5m+0SBl6gUU1R1ZQB3aKypfA==} + engines: {bun: '>=1.0.0', deno: '>=1.30.0', node: '>=8.0.0'} + + lucide-react@1.61.0: + resolution: {integrity: sha512-v2SQPPPNjnr+BlhL9Spuzmo5yR+hLkftfuE4E3jaxdNPgSH0hJKPcLJBP7yAta87jQNPsSERS59PJjCJ/CorBA==} + peerDependencies: + '@types/react': '*' + react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + + magic-string@0.30.21: + resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + + magic-string@1.4.4: + resolution: {integrity: sha512-jQz9sVhrZuphH4NrAIHSgkDJCluQO7Ioi4KGRLa7aTUjAODQ13hENX0YIytqYE/rIkO485gQG2LeBxJaW53kkQ==} + + markdown-extensions@2.0.0: + resolution: {integrity: sha512-o5vL7aDWatOTX8LzaS1WMoaoxIiLRQJuIKKe2wAw6IeULDHaqbiqiggmx+pKvZDb1Sj+pE46Sn1T7lCqfFtg1Q==} + engines: {node: '>=16'} + + markdown-table@3.0.4: + resolution: {integrity: sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==} + + mdast-util-find-and-replace@3.0.4: + resolution: {integrity: sha512-z4B5c6jrnJ1ltOQemhWYPBSAo6y42Z8Gt2yEgfgNTMcLSU59B8bfj8Z8AnAlJrBGLnqkdAUZ7jdDEqQw3KuipQ==} + + mdast-util-from-markdown@2.1.0: + resolution: {integrity: sha512-KRLgmPaP2H1ul2bpoJkOS+9pAcDAAj9Nu1mqLnh8NLeJG5tlvj42TH80PIGBpROWlRXLk0lDrWNuZCFy/tsB4A==} + + mdast-util-gfm-autolink-literal@2.0.1: + resolution: {integrity: sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==} + + mdast-util-gfm-footnote@2.1.0: + resolution: {integrity: sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ==} + + mdast-util-gfm-strikethrough@2.0.1: + resolution: {integrity: sha512-OuJHqvr455pwu2OaOrir7dbzqs4jlWKOtlu9L6GjcIjjQwNyw02VntQsr/Ek6/A13vgnXfUhBekWRUP1OkNivw==} + + mdast-util-gfm-table@2.0.0: + resolution: {integrity: sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==} + + mdast-util-gfm-task-list-item@2.0.0: + resolution: {integrity: sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==} + + mdast-util-gfm@3.1.0: + resolution: {integrity: sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==} + + mdast-util-mdx-expression@2.0.1: + resolution: {integrity: sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ==} + + mdast-util-mdx-jsx@3.2.0: + resolution: {integrity: sha512-lj/z8v0r6ZtsN/cGNNtemmmfoLAFZnjMbNyLzBafjzikOM+glrjNHPlf6lQDOTccj9n5b0PPihEBbhneMyGs1Q==} + + mdast-util-mdx@3.0.0: + resolution: {integrity: sha512-JfbYLAW7XnYTTbUsmpu0kdBUVe+yKVJZBItEjwyYJiDJuZ9w4eeaqks4HQO+R7objWgS2ymV60GYpI14Ug554w==} + + mdast-util-mdxjs-esm@2.0.1: + resolution: {integrity: sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg==} + + mdast-util-phrasing@4.1.0: + resolution: {integrity: sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==} + + mdast-util-to-hast@13.2.1: + resolution: {integrity: sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==} + + mdast-util-to-markdown@2.2.0: + resolution: {integrity: sha512-2Jn/ADrHFFyyniBMi0bncTbJqU78K3/TEYvzvwrWWzD9MYPUa/Gm4r3nOeKFQg/PDM5BsbDYdc8ackW4NTY6NA==} + + mdast-util-to-string@4.0.0: + resolution: {integrity: sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==} + + merge-stream@2.0.0: + resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} + + merge2@1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} + + micromark-core-commonmark@2.0.4: + resolution: {integrity: sha512-wxEeE8v8XVvOrxn1TZj74qYhAtTQsSqufHVS3uNVyT1MupXxhyaHk8/9xDNPh9BmL77QNDgWTkZ3RsYHB2ry7w==} + + micromark-extension-gfm-autolink-literal@2.1.0: + resolution: {integrity: sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==} + + micromark-extension-gfm-footnote@2.1.0: + resolution: {integrity: sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==} + + micromark-extension-gfm-strikethrough@2.1.0: + resolution: {integrity: sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==} + + micromark-extension-gfm-table@2.1.2: + resolution: {integrity: sha512-pRzm4kDTu0MjlmBkxmS9yYhw60nncfcEwu9NNdPFSQEFXS95ZKyIIyTSHu/o3ReBUrLKYEq+7YaXCRn/bPB4MA==} + + micromark-extension-gfm-tagfilter@2.0.0: + resolution: {integrity: sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==} + + micromark-extension-gfm-task-list-item@2.1.0: + resolution: {integrity: sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==} + + micromark-extension-gfm@3.0.0: + resolution: {integrity: sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==} + + micromark-extension-mdx-expression@3.0.1: + resolution: {integrity: sha512-dD/ADLJ1AeMvSAKBwO22zG22N4ybhe7kFIZ3LsDI0GlsNr2A3KYxb0LdC1u5rj4Nw+CHKY0RVdnHX8vj8ejm4Q==} + + micromark-extension-mdx-jsx@3.0.2: + resolution: {integrity: sha512-e5+q1DjMh62LZAJOnDraSSbDMvGJ8x3cbjygy2qFEi7HCeUT4BDKCvMozPozcD6WmOt6sVvYDNBKhFSz3kjOVQ==} + + micromark-extension-mdx-md@2.0.0: + resolution: {integrity: sha512-EpAiszsB3blw4Rpba7xTOUptcFeBFi+6PY8VnJ2hhimH+vCQDirWgsMpz7w1XcZE7LVrSAUGb9VJpG9ghlYvYQ==} + + micromark-extension-mdxjs-esm@3.0.0: + resolution: {integrity: sha512-DJFl4ZqkErRpq/dAPyeWp15tGrcrrJho1hKK5uBS70BCtfrIFg81sqcTVu3Ta+KD1Tk5vAtBNElWxtAa+m8K9A==} + + micromark-extension-mdxjs@3.0.0: + resolution: {integrity: sha512-A873fJfhnJ2siZyUrJ31l34Uqwy4xIFmvPY1oj+Ean5PHcPBYzEsvqvWGaWcfEIr11O5Dlw3p2y0tZWpKHDejQ==} + + micromark-factory-destination@2.0.1: + resolution: {integrity: sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==} + + micromark-factory-label@2.0.1: + resolution: {integrity: sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==} + + micromark-factory-mdx-expression@2.0.3: + resolution: {integrity: sha512-kQnEtA3vzucU2BkrIa8/VaSAsP+EJ3CKOvhMuJgOEGg9KDC6OAY6nSnNDVRiVNRqj7Y4SlSzcStaH/5jge8JdQ==} + + micromark-factory-space@2.1.0: + resolution: {integrity: sha512-fS8hnLIjnjvdQIj39Geug8wWsR0HrYZ43KShKxNfwT7t2LOHo/LbWZEzEaSOjwtjdCsjoE6syHhonEzW0zv0+Q==} + + micromark-factory-title@2.0.1: + resolution: {integrity: sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==} + + micromark-factory-whitespace@2.0.1: + resolution: {integrity: sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==} + + micromark-util-character@2.1.1: + resolution: {integrity: sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==} + + micromark-util-chunked@2.0.1: + resolution: {integrity: sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==} + + micromark-util-classify-character@2.0.1: + resolution: {integrity: sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==} + + micromark-util-combine-extensions@2.0.1: + resolution: {integrity: sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==} + + micromark-util-decode-numeric-character-reference@2.0.2: + resolution: {integrity: sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==} + + micromark-util-decode-string@2.0.1: + resolution: {integrity: sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==} + + micromark-util-edit-map@1.0.0: + resolution: {integrity: sha512-Pa2ljlsEL6sVwFaYeyrOLSYbQt73JvGbPOYFq+9AElXiSnfI5Q4465RRZ1sHv7lDjDOnGRDDaqPXqClqWK/q1Q==} + + micromark-util-encode@2.0.1: + resolution: {integrity: sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==} + + micromark-util-events-to-acorn@2.0.3: + resolution: {integrity: sha512-jmsiEIiZ1n7X1Rr5k8wVExBQCg5jy4UXVADItHmNk1zkwEVhBuIUKRu3fqv+hs4nxLISi2DQGlqIOGiFxgbfHg==} + + micromark-util-html-tag-name@2.0.1: + resolution: {integrity: sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==} + + micromark-util-normalize-identifier@2.0.1: + resolution: {integrity: sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==} + + micromark-util-resolve-all@2.0.1: + resolution: {integrity: sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==} + + micromark-util-sanitize-uri@2.0.1: + resolution: {integrity: sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==} + + micromark-util-subtokenize@2.1.0: + resolution: {integrity: sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==} + + micromark-util-symbol@2.0.1: + resolution: {integrity: sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==} + + micromark-util-types@2.0.3: + resolution: {integrity: sha512-oxB2Ik03hI0gv+VNn9tnh1t1YEe9MDPptViAEgfdf3YQHsn0pzGTgCdlSCJXcwhqm8phaEuM7zeEu3QQzVBrPg==} + + micromark@4.0.3: + resolution: {integrity: sha512-oGYfQzHSG5dOMovQcJ3fyTmZlWAWpi0XA0sJwJs+i6OT88o1+Jtw/8z0CmdowSLxGhhFK89rQ/oXph/wN02PNw==} + + micromatch@4.0.8: + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} + engines: {node: '>=8.6'} + + mikro-orm@7.2.1: + resolution: {integrity: sha512-IUUYgO5T+S67sw1Xp5r3vL0JeYnkampUIRJaHG6AzTcjujRbyRUOEc6NVAIsojKdXq9WbWRU0hI6ivUv9qSDLA==} + engines: {node: '>= 22.17.0'} + + mime-db@1.33.0: + resolution: {integrity: sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==} + engines: {node: '>= 0.6'} + + mime-db@1.54.0: + resolution: {integrity: sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==} + engines: {node: '>= 0.6'} + + mime-types@2.1.18: + resolution: {integrity: sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==} + engines: {node: '>= 0.6'} + + mimic-fn@2.1.0: + resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} + engines: {node: '>=6'} + + miniflare@5.20261012.0-beta: + resolution: {integrity: sha512-Cjrs+vHHQ7krLO4HYELYpYBJBuMhcnNZD/Z5z/UcQSnFqWSQY3DhtTCFalXgI1/yO1iK+YrRKK8EYkumrEopxg==} + engines: {node: '>=22.0.0'} + + miniflare@5.20261019.1-beta: + resolution: {integrity: sha512-1n7MN2UqZnPniyYAqNuV1YEAaja66ozKGVCc5ZTmYQhTubnoAwGLccwb+ZWYLOajuw3pOaJ70u//bZMuURlRew==} + engines: {node: '>=22.0.0'} + + minimatch@10.2.6: + resolution: {integrity: sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==} + engines: {node: 18 || 20 || >=22} + + minimatch@3.1.5: + resolution: {integrity: sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==} + + minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + + minimizer-webpack-plugin@5.13.1: + resolution: {integrity: sha512-1mhAfvachWYYOm8tpmany5NLuvP+F2wxZWBSX8DC0uFS2wJpM9q3rWgN9wBooAH9d5V12wX0BjyJe4fMjHMarQ==} + engines: {node: '>= 10.13.0'} + peerDependencies: + '@minify-html/node': '*' + '@napi-rs/image': '*' + '@swc/core': '*' + '@swc/css': '*' + '@swc/html': '*' + clean-css: '*' + cssnano: '*' + csso: '*' + esbuild: '*' + html-minifier-terser: '*' + imagemin: '*' + lightningcss: '*' + postcss: '*' + sharp: '*' + svgo: '*' + uglify-js: '*' + webpack: ^5.1.0 + peerDependenciesMeta: + '@minify-html/node': + optional: true + '@napi-rs/image': + optional: true + '@swc/core': + optional: true + '@swc/css': + optional: true + '@swc/html': + optional: true + clean-css: + optional: true + cssnano: + optional: true + csso: + optional: true + esbuild: + optional: true + html-minifier-terser: + optional: true + imagemin: + optional: true + lightningcss: + optional: true + postcss: + optional: true + sharp: + optional: true + svgo: + optional: true + uglify-js: + optional: true + + mlly@1.8.2: + resolution: {integrity: sha512-d+ObxMQFmbt10sretNDytwt85VrbkhhUA/JBGm1MPaWJ65Cl4wOgLaB1NYvJSZ0Ef03MMEU/0xpPMXUIQ29UfA==} + + motion-dom@14.6.0: + resolution: {integrity: sha512-lIojTl9aYSPIkeOOSzBliy1nNvpdO3JtVzW2WgTXQlOP4ZMuJhtWO3fP7OD4TVFwlRucdvxlDSMkL+fEQnQ52A==} + + motion-utils@14.6.0: + resolution: {integrity: sha512-bZJo2AmQ2aOFkaato6VXrTbkPG0XhMzivWUWSaI59pxyllj8QMQUFZ84MYRQnPkK+7dr4KldyJwF2+RM0sdq/w==} + + motion@14.6.0: + resolution: {integrity: sha512-qqaZbyubgk7x3zxjPgP1l3Br/KQXol/IIV1uqb358SoN4ApcqNuV7+wyDPg/XLErmuyQL5lL8JVI/fOmDsmBKQ==} + peerDependencies: + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + react: + optional: true + react-dom: + optional: true + + ms@2.0.0: + resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + mute-stream@2.0.0: + resolution: {integrity: sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==} + engines: {node: ^18.17.0 || >=20.5.0} + + mysql2@3.24.4: + resolution: {integrity: sha512-A2olluVlj0mvgyIRRISMEzXc51m+21mRtcMVjJyIpt2GG98+XrC9m9HzsqcMsX2LcnfccJvY5NB22g8fENBnOA==} + engines: {node: '>= 8.0'} + peerDependencies: + '@types/node': '>= 8' + + mz@2.7.0: + resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} + + named-placeholders@1.1.6: + resolution: {integrity: sha512-Tz09sEL2EEuv5fFowm419c1+a/jSMiBjI9gHxVLrVdbUkkNUUfjsVYs9pVZu5oCon/kmRh9TfLEObFtkVxmY0w==} + engines: {node: '>=8.0.0'} + + nanoid@3.3.20: + resolution: {integrity: sha512-uKdg2G3GNCKQn9byYOpxbGqrT2fGO5KRt5J/8b3pok8rT6qxGWF6hxMyJiEYtAf+FVyYuD9hRaDqX5uPFYJ4ZQ==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + nanostores@1.5.5: + resolution: {integrity: sha512-FixtE239Gl6Gz0ZGCK0WzvNwObNCIwVT+L7zQcf1QgcA6AzBxblzqe9OT88qiucNkhsjSOqiogSaF5jVbJiqSA==} + engines: {node: ^20.0.0 || >=22.0.0} + + natural-compare@1.4.0: + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + + negotiator@0.6.4: + resolution: {integrity: sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==} + engines: {node: '>= 0.6'} + + neo-async@2.6.2: + resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} + + next-themes@0.4.6: + resolution: {integrity: sha512-pZvgD5L0IEvX5/9GWyHMf3m8BKiVQwsCMHfoFosXtXBMnaS0ZnIJ9ST4b4NqLVKDEm8QBxoNNGNaBv2JNF6XNA==} + peerDependencies: + react: ^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc + react-dom: ^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc + + next@14.2.35: + resolution: {integrity: sha512-KhYd2Hjt/O1/1aZVX3dCwGXM1QmOV4eNM2UTacK5gipDdPN/oHHK/4oVGy7X8GMfPMsUTUEmGlsy0EY1YGAkig==} + engines: {node: '>=18.17.0'} + hasBin: true + peerDependencies: + '@opentelemetry/api': ^1.1.0 + '@playwright/test': ^1.41.2 + '@types/react': '*' + react: ^18.2.0 + react-dom: ^18.2.0 + sass: ^1.3.0 + peerDependenciesMeta: + '@opentelemetry/api': + optional: true + '@playwright/test': + optional: true + sass: + optional: true + + next@16.4.2: + resolution: {integrity: sha512-r+oBJojfefUjOiWkBhXgLS+igxX/7BWyK59uHnyOyplMSLtBZ+QLP3okrdYTbrfrbrmNTVWLBPaHDX9KRaIt3w==} + engines: {node: '>=20.9.0'} + hasBin: true + 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-addon-api@8.9.2: + resolution: {integrity: sha512-VijLXbi3UACN69I0JVXJsX4tjACjNoQDgv2gTF6sx2wWEi8tkSg2eX8p5gSIFi8z2+DL3oHmY6OyKce38SDolg==} + engines: {node: ^18 || ^20 || >= 21} + + node-releases@2.0.60: + resolution: {integrity: sha512-OmO8+GM1JUZqXET720VrJCwkjUCXmCMQm0Z3UDDRbfNLHS4NEAvY60j5jiFv0tkKw2PNNlqOLhahVmwJIOLDIQ==} + engines: {node: '>=18'} + + normalize-path@3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} + + normalize-range@0.1.2: + resolution: {integrity: sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==} + engines: {node: '>=0.10.0'} + + npm-run-path@4.0.1: + resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} + engines: {node: '>=8'} + + npm-to-yarn@3.2.0: + resolution: {integrity: sha512-K1HmQeZT2HrjpsR6KgqbN2FAXL2NrJJmNUSD9ck7HGTVu1JKXox8n9SB+tjbU8m8JGLF4OscrroPepew/L7/Xw==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + object-assign@4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} + + object-hash@3.0.0: + resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==} + engines: {node: '>= 6'} + + obug@3.0.0: + resolution: {integrity: sha512-5vvB5+W7ePv+p3uqxi+RcW1XAzLW0/hxt3/4X4Lc4qHudzOhmBiBwOY6DRob4WnanAEGvNcLjF+KNOufrUoEQw==} + engines: {node: '>=12.20.0'} + + on-headers@1.1.0: + resolution: {integrity: sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==} + engines: {node: '>= 0.8'} + + onetime@5.1.2: + resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} + engines: {node: '>=6'} + + oniguruma-parser@0.12.2: + resolution: {integrity: sha512-6HVa5oIrgMC6aA6WF6XyyqbhRPJrKR02L20+2+zpDtO5QAzGHAUGw5TKQvwi5vctNnRHkJYmjAhRVQF2EKdTQw==} + + oniguruma-to-es@4.3.6: + resolution: {integrity: sha512-csuQ9x3Yr0cEIs/Zgx/OEt9iBw9vqIunAPQkx19R/fiMq2oGVTgcMqO/V3Ybqefr1TBvosI6jU539ksaBULJyA==} + + optionator@0.9.4: + resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} + engines: {node: '>= 0.8.0'} + + p-limit@3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} + + p-locate@5.0.0: + resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} + engines: {node: '>=10'} + + pako@0.2.9: + resolution: {integrity: sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==} + + parse-css-color@0.2.1: + resolution: {integrity: sha512-bwS/GGIFV3b6KS4uwpzCFj4w297Yl3uqnSgIPsoQkx7GMLROXfMnWvxfNkL0oh8HVhZA4hvJoEoEIqonfJ3BWg==} + + parse-entities@4.0.2: + resolution: {integrity: sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==} + + path-exists@4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + + path-is-inside@1.0.2: + resolution: {integrity: sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w==} + + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + path-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + + path-to-regexp@3.3.0: + resolution: {integrity: sha512-qyCH421YQPS2WFDxDjftfc1ZR5WKQzVzqsp4n9M2kQhVOo/ByahFoUNJfl58kOcEGfQ//7weFTDhm+ss8Ecxgw==} + + path-to-regexp@6.3.0: + resolution: {integrity: sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==} + + pathe@2.0.3: + resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} + + pathval@2.0.1: + resolution: {integrity: sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==} + engines: {node: '>= 14.16'} + + pg-cloudflare@1.4.1: + resolution: {integrity: sha512-6PQbsFWZcp9EmJEwy5cGQ2La+AMWpP46lgbb8X+U/XsHIUweYDNCpeuKck5RxL2MdVFi7krbbEi5nX4Zh7JhrQ==} + + pg-connection-string@2.14.1: + resolution: {integrity: sha512-qR3kGNPBLpCNtz0evbKA0Y/MRFXwSSdT+pTJvYp/bXTcReZbvX1kzF0IyTc1QnxqF7AZbOeBhNL8R5mYQZV/MA==} + + pg-cursor@2.22.0: + resolution: {integrity: sha512-knzXLKqarTjOvb3qDSW0JiGsazmxwEKXrqHfWRte7XUsOYccQRafn3BLnQobWwInkzFJSyOej8y8cQRh2z3kGw==} + peerDependencies: + pg: ^8 + + pg-int8@1.0.1: + resolution: {integrity: sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==} + engines: {node: '>=4.0.0'} + + pg-pool@3.14.0: + resolution: {integrity: sha512-gKtPkFdQPU3DksooVLi9LsjZxrsBUZIpa+7aVx+LV5pNh0KzP4Zleud2po+ConrxbuXGBJ6Hfer6hdgpIBpBaw==} + peerDependencies: + pg: '>=8.0' + + pg-protocol@1.16.1: + resolution: {integrity: sha512-p9VOFMiHB/ZbJATetbg+99PxssTVSQRnyuPSQ67mN1+1KBOjZaZ83ZQzltnxPhJwSsC3nwVjJ10DVJlerbFzLg==} + + pg-types@2.2.0: + resolution: {integrity: sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==} + engines: {node: '>=4'} + + pg@8.23.0: + resolution: {integrity: sha512-Ip2EQCngowJLGOfCwkFhPXU7/ljlhn6Rxlmy4XYfL2Y+vyRM59+8uR2xqRWKdYmbXmxCFOAmKxBuSUCdF34qLg==} + engines: {node: '>= 16.0.0'} + peerDependencies: + pg-native: '>=3.0.1' + peerDependenciesMeta: + pg-native: + optional: true + + pgpass@1.0.5: + resolution: {integrity: sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@2.3.2: + resolution: {integrity: sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==} + engines: {node: '>=8.6'} + + picomatch@4.0.7: + resolution: {integrity: sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==} + engines: {node: '>=12'} + + pirates@4.0.7: + resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==} + engines: {node: '>= 6'} + + pkg-types@1.3.1: + resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} + + playwright-core@1.64.1: + resolution: {integrity: sha512-BC4s8y6SEVA6Q1rSxZTto8hI1KUI3xXlHGZgvGqP4IqPdI/a6FX9H29IDNz7vKo9l21b6LfYosScPL6M3xxyDQ==} + engines: {node: '>=20'} + hasBin: true + + playwright@1.64.1: + resolution: {integrity: sha512-HCrVhHr5QQuwYoswEUGTb7gGp522yflbv/ST8nF4sFWGuLjQCt17Q/EubpGGSNKYn1tsTCPZxqHhHCfVURu7UA==} + engines: {node: '>=20'} + hasBin: true + + postcss-import@15.1.0: + resolution: {integrity: sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==} + engines: {node: '>=14.0.0'} + peerDependencies: + postcss: ^8.0.0 + + postcss-js@4.1.0: + resolution: {integrity: sha512-oIAOTqgIo7q2EOwbhb8UalYePMvYoIeRY2YKntdpFQXNosSu3vLrniGgmH9OKs/qAkfoj5oB3le/7mINW1LCfw==} + engines: {node: ^12 || ^14 || >= 16} + peerDependencies: + postcss: ^8.4.21 + + postcss-load-config@4.0.2: + resolution: {integrity: sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==} + engines: {node: '>= 14'} + peerDependencies: + postcss: '>=8.0.9' + ts-node: '>=9.0.0' + peerDependenciesMeta: + postcss: + optional: true + ts-node: + optional: true + + postcss-load-config@6.0.1: + resolution: {integrity: sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==} + engines: {node: '>= 18'} + peerDependencies: + jiti: '>=1.21.0' + postcss: '>=8.0.9' + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + jiti: + optional: true + postcss: + optional: true + tsx: + optional: true + yaml: + optional: true + + postcss-nested@6.2.0: + resolution: {integrity: sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==} + engines: {node: '>=12.0'} + peerDependencies: + postcss: ^8.2.14 + + postcss-selector-parser@6.1.5: + resolution: {integrity: sha512-TEHFzb5KRDKaOgJ4TYE+0jyJtFbjLvkdVOu0fZ2b6MTWzoqZd4Le+61aEppWkvTlYePgOX4ATL1wsAIPMLTw6Q==} + engines: {node: '>=4'} + + postcss-value-parser@4.2.0: + resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} + + postcss@8.4.31: + resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==} + engines: {node: ^10 || ^12 || >=14} + + postcss@8.4.39: + resolution: {integrity: sha512-0vzE+lAiG7hZl1/9I8yzKLx3aR9Xbof3fBHKunvMfOCYAtMhrsnccJY2iTURb9EZd5+pLuiNV9/c/GZJOHsgIw==} + engines: {node: ^10 || ^12 || >=14} + + postcss@8.5.23: + resolution: {integrity: sha512-g50586zr4bZmwFiTlflMu8E0bDTb5I5gertgwAKmsdUlTQIhZtunzUlD1WSzwcVWPoAVpsrA6vlfCD7oXvRwgg==} + engines: {node: ^10 || ^12 || >=14} + + postcss@8.5.32: + resolution: {integrity: sha512-LJlKCCAUFKOuZxipUdYw1NzIITEsPcgyOG9LkvRJvuKj/bRzbuRY0ARXvL0pWGpsZvn8jku+LMep2eU0seHp8g==} + engines: {node: ^10 || ^12 || >=14} + + postgres-array@2.0.0: + resolution: {integrity: sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==} + engines: {node: '>=4'} + + postgres-array@3.0.4: + resolution: {integrity: sha512-nAUSGfSDGOaOAEGwqsRY27GPOea7CNipJPOA7lPbdEpx5Kg3qzdP0AaWC5MlhTWV9s4hFX39nomVZ+C4tnGOJQ==} + engines: {node: '>=12'} + + postgres-bytea@1.0.1: + resolution: {integrity: sha512-5+5HqXnsZPE65IJZSMkZtURARZelel2oXUEO8rH83VS/hxH5vv1uHquPg5wZs8yMAfdv971IU+kcPUczi7NVBQ==} + engines: {node: '>=0.10.0'} + + postgres-date@1.0.7: + resolution: {integrity: sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==} + engines: {node: '>=0.10.0'} + + postgres-date@2.1.0: + resolution: {integrity: sha512-K7Juri8gtgXVcDfZttFKVmhglp7epKb1K4pgrkLxehjqkrgPhfG6OO8LHLkfaqkbpjNRnra018XwAr1yQFWGcA==} + engines: {node: '>=12'} + + postgres-interval@1.2.0: + resolution: {integrity: sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==} + engines: {node: '>=0.10.0'} + + postgres-interval@4.1.0: + resolution: {integrity: sha512-nJLACcOHi2iyRuMJeW6CuIA0Dc0i1YEpRr26XDyHAfxPjYUJOFxwZjmOc5oFFctTTh/OlRAMlnlXEJvr170fJg==} + engines: {node: '>=12'} + + prelude-ls@1.2.1: + resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} + engines: {node: '>= 0.8.0'} + + prettier-plugin-tailwindcss@0.6.14: + resolution: {integrity: sha512-pi2e/+ZygeIqntN+vC573BcW5Cve8zUB0SSAGxqpB4f96boZF4M3phPVoOFCeypwkpRYdi7+jQ5YJJUwrkGUAg==} + engines: {node: '>=14.21.3'} + peerDependencies: + '@ianvs/prettier-plugin-sort-imports': '*' + '@prettier/plugin-hermes': '*' + '@prettier/plugin-oxc': '*' + '@prettier/plugin-pug': '*' + '@shopify/prettier-plugin-liquid': '*' + '@trivago/prettier-plugin-sort-imports': '*' + '@zackad/prettier-plugin-twig': '*' + prettier: ^3.0 + prettier-plugin-astro: '*' + prettier-plugin-css-order: '*' + prettier-plugin-import-sort: '*' + prettier-plugin-jsdoc: '*' + prettier-plugin-marko: '*' + prettier-plugin-multiline-arrays: '*' + prettier-plugin-organize-attributes: '*' + prettier-plugin-organize-imports: '*' + prettier-plugin-sort-imports: '*' + prettier-plugin-style-order: '*' + prettier-plugin-svelte: '*' + peerDependenciesMeta: + '@ianvs/prettier-plugin-sort-imports': + optional: true + '@prettier/plugin-hermes': + optional: true + '@prettier/plugin-oxc': + optional: true + '@prettier/plugin-pug': + optional: true + '@shopify/prettier-plugin-liquid': + optional: true + '@trivago/prettier-plugin-sort-imports': + optional: true + '@zackad/prettier-plugin-twig': + optional: true + prettier-plugin-astro: + optional: true + prettier-plugin-css-order: + optional: true + prettier-plugin-import-sort: + optional: true + prettier-plugin-jsdoc: + optional: true + prettier-plugin-marko: + optional: true + prettier-plugin-multiline-arrays: + optional: true + prettier-plugin-organize-attributes: + optional: true + prettier-plugin-organize-imports: + optional: true + prettier-plugin-sort-imports: + optional: true + prettier-plugin-style-order: + optional: true + prettier-plugin-svelte: + optional: true + + prettier@3.9.10: + resolution: {integrity: sha512-skGHTH1Yb9QvaTC4hWnRTzEYtCpApF0UMBPz+t/0ZPzP8ihefo/btKd+QA7pUE0fEwA1SbS/NmhyEcstdXOIdA==} + engines: {node: '>=14'} + hasBin: true + + promise-limit@2.7.0: + resolution: {integrity: sha512-7nJ6v5lnJsXwGprnGXga4wx6d1POjvi5Qmf1ivTRxTjH4Z/9Czja/UCMLVmB9N93GeWOU93XaFaEt6jbuoagNw==} + + property-information@7.2.0: + resolution: {integrity: sha512-IAtzIB6sUiWaJYrX9smp3V46pBGbBeLFRGdh25kg1334VcBlD8HzhPeNIWQH9zhGmo2itIe25EHt9dQP7G5hmg==} + + punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + + qified@0.10.1: + resolution: {integrity: sha512-+Owyggi9IxT1ePKGafcI87ubSmxol6smwJ+RAHDQlx9+9cPwFWDiKFFCPuWhr9ignlGpZ9vDQLw67N4dcTVFEA==} + engines: {node: '>=20'} + + qrcode.react@4.2.0: + resolution: {integrity: sha512-QpgqWi8rD9DsS9EP3z7BT+5lY5SFhsqGjpgW5DY/i3mK4M9DTBNz3ErMi8BWYEfI3L0d8GIbGmcdFAS1uIRGjA==} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + + queue-microtask@1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + + range-parser@1.2.0: + resolution: {integrity: sha512-kA5WQoNVo4t9lNx2kQNFCxKeBl5IbbSNBl1M/tLkw9WCn+hxNBAW5Qh8gdhs63CJnhjJ2zQWFoqPJP2sK1AV5A==} + engines: {node: '>= 0.6'} + + rc@1.2.8: + resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} + hasBin: true + + react-dom@18.3.1: + resolution: {integrity: sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==} + peerDependencies: + react: ^18.3.1 + + react-dom@19.3.1: + resolution: {integrity: sha512-Y0bARz53lhEC1NMCASs0/j+faB/zqt3R8hpvg1e8+61ZVJ4UL0UdC4cBbXfZMcIuhrfgeILTLe+ZeBCavQPtKQ==} + peerDependencies: + react: ^19.3.1 + + react-hook-form@7.52.1: + resolution: {integrity: sha512-uNKIhaoICJ5KQALYZ4TOaOLElyM+xipord+Ha3crEFhTntdLvWZqVY49Wqd/0GiVCA/f9NjemLeiNPjG7Hpurg==} + engines: {node: '>=12.22.0'} + peerDependencies: + react: ^16.8.0 || ^17 || ^18 || ^19 + + react-remove-scroll-bar@2.3.8: + resolution: {integrity: sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + + react-remove-scroll@2.5.5: + resolution: {integrity: sha512-ImKhrzJJsyXJfBZ4bzu8Bwpka14c/fQt0k+cyFp/PBhTfyDnU5hjOtM4AG/0AMyy8oKzOTR0lDgJIM7pYXI0kw==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + + react-remove-scroll@2.7.2: + resolution: {integrity: sha512-Iqb9NjCCTt6Hf+vOdNIZGdTiH1QSqr27H/Ek9sv/a97gfueI/5h1s3yRi1nngzMUaOOToin5dI1dXKdXiF+u0Q==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + react-server-dom-webpack@19.3.1: + resolution: {integrity: sha512-I1Smf6Yc+389rFWPwyYjvCQVK1XFWpb2M9gvgYgfpbZ+LPqkZtb0tT9Fwdk0K+wknK2E+ns82lC0DCYLnXCVGA==} + engines: {node: '>=0.10.0'} + peerDependencies: + react: ^19.3.1 + react-dom: ^19.3.1 + webpack: ^5.59.0 + + react-style-singleton@2.2.3: + resolution: {integrity: sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + react@18.3.1: + resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==} + engines: {node: '>=0.10.0'} + + react@19.3.1: + resolution: {integrity: sha512-QNhWdt7nrgVWWQG58QuGsAR3jv3Hbe4mb4vz7w2csnHavciZJgda1CPNaldF6eVxv90ud3jUXpKlHL69gO38yw==} + engines: {node: '>=0.10.0'} + + read-cache@1.0.2: + resolution: {integrity: sha512-/peqiBB/n07gQGLsWaHho3WfvUyRscw0gYTsEFMhrIe/nWLkYaf5SbKYjGYqtRV3aPwykJgF2VEMo1ac4bnsGA==} + + readdirp@3.6.0: + resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} + engines: {node: '>=8.10.0'} + + readdirp@4.1.2: + resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} + engines: {node: '>= 14.18.0'} + + readdirp@5.1.1: + resolution: {integrity: sha512-Kko+Y5XQ6fM+Ce3dq3m9YGxnacYZYl9cA1wZjaF3Vbry2L3i1qVg8+CAgNPsXRArPMUMCaOR7oa9Nqntc43JKA==} + engines: {node: '>= 20.19.0'} + + recma-build-jsx@1.0.0: + resolution: {integrity: sha512-8GtdyqaBcDfva+GUKDr3nev3VpKAhup1+RvkMvUxURHpW7QyIvk9F5wz7Vzo06CEMSilw6uArgRqhpiUcWp8ew==} + + recma-jsx@1.0.1: + resolution: {integrity: sha512-huSIy7VU2Z5OLv6oFLosQGGDqPqdO1iq6bWNAdhzMxSJP7RAso4fCZ1cKu8j9YHCZf3TPrq4dw3okhrylgcd7w==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + + recma-parse@1.0.0: + resolution: {integrity: sha512-OYLsIGBB5Y5wjnSnQW6t3Xg7q3fQ7FWbw/vcXtORTnyaSFscOtABg+7Pnz6YZ6c27fG1/aN8CjfwoUEUIdwqWQ==} + + recma-stringify@1.0.0: + resolution: {integrity: sha512-cjwII1MdIIVloKvC9ErQ+OgAtwHBmcZ0Bg4ciz78FtbT8In39aAYbaA7zvxQ61xVMSPE8WxhLwLbhif4Js2C+g==} + + regex-recursion@6.0.2: + resolution: {integrity: sha512-0YCaSCq2VRIebiaUviZNs0cBz1kg5kVS2UKUfNIx8YVs1cN3AV7NTctO5FOKBA+UT2BPJIWZauYHPqJODG50cg==} + + regex-utilities@2.3.0: + resolution: {integrity: sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng==} + + regex@6.1.0: + resolution: {integrity: sha512-6VwtthbV4o/7+OaAF9I5L5V3llLEsoPyq9P1JVXkedTP33c7MfCG0/5NOPcSJn0TzXcG9YUrR0gQSWioew3LDg==} + + registry-auth-token@3.3.2: + resolution: {integrity: sha512-JL39c60XlzCVgNrO+qq68FoNb56w/m7JYvGR2jT5iR1xBrUA3Mfx5Twk5rqTThPmQKMWydGmq8oFtDlxfrmxnQ==} + + registry-url@3.1.0: + resolution: {integrity: sha512-ZbgR5aZEdf4UKZVBPYIgaglBmSF2Hi94s2PcIHhRGFjKYu+chjJdYfHn4rt3hB6eCKLJ8giVIIfgMa1ehDfZKA==} + engines: {node: '>=0.10.0'} + + rehype-recma@1.0.0: + resolution: {integrity: sha512-lqA4rGUf1JmacCNWWZx0Wv1dHqMwxzsDWYMTowuplHF3xH0N/MmrZ/G3BDZnzAkRmxDadujCjaKM2hqYdCBOGw==} + + remark-gfm@4.0.1: + resolution: {integrity: sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==} + + remark-mdx@3.1.1: + resolution: {integrity: sha512-Pjj2IYlUY3+D8x00UJsIOg5BEvfMyeI+2uLPn9VO9Wg4MEtN/VTIq2NEJQfde9PnX15KgtHyl9S0BcTnWrIuWg==} + + remark-parse@11.0.0: + resolution: {integrity: sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==} + + remark-rehype@11.1.2: + resolution: {integrity: sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw==} + + remark-stringify@11.0.0: + resolution: {integrity: sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==} + + remark@15.0.1: + resolution: {integrity: sha512-Eht5w30ruCXgFmxVUSlNWQ9iiimq07URKeFS3hNc8cUWy1llX4KDWfyEDZRycMc+znsN9Ux5/tJ/BFdgdOwA3A==} + + require-directory@2.1.1: + resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} + engines: {node: '>=0.10.0'} + + require-from-string@2.0.2: + resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} + engines: {node: '>=0.10.0'} + + reselect@5.3.0: + resolution: {integrity: sha512-XGoLeRAVzUTcJ1qkxPQhDJyIZ5d6zzZD9nT7AEZOaaU9UbWclhycElmhO+VD5bFeLuzhPBaOV2oXC8uG35ZSpg==} + + resolve-from@5.0.0: + resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} + engines: {node: '>=8'} + + resolve@1.22.13: + resolution: {integrity: sha512-Dj/cW9zBV2aRj6XzCxuGIs3ESZKv02jixne3q6jFZYZ3/Tg09gHHviSMDL4kObh9pqSahdRHEnDoaP2gn8YLhA==} + engines: {node: '>= 0.4'} + hasBin: true + + reusify@1.1.0: + resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + + rolldown@1.2.15: + resolution: {integrity: sha512-6odND+fel5zVw3I4Yc2e69gvguDnX0CAAGiNDZSq4ik5WUcaLrkD2GLuog0XcODbor31hZ5ayEMgVDno+KPV5g==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + + rollup@4.65.1: + resolution: {integrity: sha512-HzD4IdphaPMvuAacnL/vtoq5B8FwqewKvxTtqYibWvP6VDyZ+UsTtlw5F8HIOIIpLQAkN2NOP/0sM3puo9xN/A==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + + rou3@0.9.2: + resolution: {integrity: sha512-3SOzvaAg8rkHrXtRjpCvCvbyO5to9oOO27Z/XqHEYXfMRVSw/qMIVdmaOk9W2lcRLtR6dlqTjo9hDeJk70QBYQ==} + + run-parallel@1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + + safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + + safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + + satori@0.33.5: + resolution: {integrity: sha512-PNW6ktrQ8SM6kk7u4aOuTkkUewkzyTOrj+QeEzXSsnNMAdff4ire9CAqIz8+4C3rCiBtK8QTELv52AZEd1PbRw==} + engines: {node: '>=16'} + + scheduler@0.23.2: + resolution: {integrity: sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==} + + scheduler@0.28.0: + resolution: {integrity: sha512-juorfCmIkIw8tT+p5BXSm6PJjQF/ycEYmKyzURCIt/RaZIhL+PulbQ9Yu2z1HdOJDdqDTlxA1+xKBmHXJsczAw==} + + schema-utils@4.8.1: + resolution: {integrity: sha512-x39pYlJPyH7Uge5QO64B9XGP9zLDc9WNmiQZc+CE3IzZPvMu3lHOuAMGpYNoPixEL7MSWlGhYTg5UlLSL8G6iw==} + engines: {node: '>= 10.13.0'} + hasBin: true + peerDependencies: + webpack: ^5.112.0 + peerDependenciesMeta: + webpack: + optional: true + + scroll-into-view-if-needed@3.1.0: + resolution: {integrity: sha512-49oNpRjWRvnU8NyGVmUaYG4jtTkNonFZI86MmGRDqBphEK2EXT9gdEUoQPZhuBM8yWHxCWbobltqYO5M4XrUvQ==} + + sdp@3.2.2: + resolution: {integrity: sha512-xZocWwfyp4hkbN4hLWxMjmv2Q8aNa9MhmOZ7L9aCZPT+dZsgRr6wZRrSYE3HTdyk/2pZKPSgqI7ns7Een1xMSA==} + + semver@7.8.5: + resolution: {integrity: sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==} + engines: {node: '>=10'} + hasBin: true + + serve-handler@6.1.7: + resolution: {integrity: sha512-CinAq1xWb0vR3twAv9evEU8cNWkXCb9kd5ePAHUKJBkOsUpR1wt/CvGdeca7vqumL1U5cSaeVQ6zZMxiJ3yWsg==} + + serve@14.2.6: + resolution: {integrity: sha512-QEjUSA+sD4Rotm1znR8s50YqA3kYpRGPmtd5GlFxbaL9n/FdUNbqMhxClqdditSk0LlZyA/dhud6XNRTOC9x2Q==} + engines: {node: '>= 14'} + hasBin: true + + set-cookie-parser@3.2.1: + resolution: {integrity: sha512-Npd1Pt+4zb3BrSZDPd2qFwRpS6b1EUEasRrO8xS0zMJi0fApXXK5YuzP0minyJnxwnFHoVoJwA55q0A0cu63gQ==} + + sharp@0.35.5: + resolution: {integrity: sha512-Ywn4OnzGukp7CDMrp08RQ50YKmuwG47brZgIVPTvBaaAfQlRlygrRqSrxdCiL9M+LlzLBiJ68IR1QqvzHyjC7g==} + engines: {node: '>=20.9.0'} + peerDependencies: + '@types/node': '*' + peerDependenciesMeta: + '@types/node': + optional: true + + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + shiki@4.5.0: + resolution: {integrity: sha512-OcRW72ngQvc+MSVWBRIovC/BTW589iUE/Vxav7VeM4RcY9MUjqB+IR6ILG1k9nuW6LiG/nct9uma4/MBtnZbmQ==} + engines: {node: '>=20'} + + siginfo@2.0.0: + resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} + + signal-exit@3.0.7: + resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} + + signal-exit@4.1.0: + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} + engines: {node: '>=14'} + + sonner@1.7.4: + resolution: {integrity: sha512-DIS8z4PfJRbIyfVFDVnK9rO3eYDtse4Omcm6bt0oEr5/jtLgysmjuBl1frJ9E/EQZrFmKx2A8m/s5s9CRXIzhw==} + peerDependencies: + '@types/react': '*' + react: ^18.0.0 || ^19.0.0 || ^19.0.0-rc + react-dom: ^18.0.0 || ^19.0.0 || ^19.0.0-rc + + source-map-js@1.2.2: + resolution: {integrity: sha512-KGj/8Y43x35aZVDtt+J4mK1hoLGHULMYfSkODJNQjNDC3oW1PqPoxMwo0pLUsWM/UEGzON/NxeHywEfNXNP3Vw==} + engines: {node: '>=0.10.0'} + + source-map-support@0.5.21: + resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} + + source-map@0.6.1: + resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} + engines: {node: '>=0.10.0'} + + source-map@0.7.6: + resolution: {integrity: sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==} + engines: {node: '>= 12'} + + space-separated-tokens@2.0.2: + resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==} + + split2@4.2.0: + resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} + engines: {node: '>= 10.x'} + + sql-escaper@1.5.2: + resolution: {integrity: sha512-6CKD38c31SENivxOADeMNLdukOnUxUcflKtzVWzace7Riv1v7cAEym5Cx9Q7gYZ3ezIJI7ZpqecQq8cqNeSSFg==} + engines: {bun: '>=1.0.0', deno: '>=2.0.0', node: '>=12.0.0'} + + sqlstring@2.3.3: + resolution: {integrity: sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg==} + engines: {node: '>= 0.6'} + + srvx@1.0.7: + resolution: {integrity: sha512-8h30Qy2cpYkcXgByHNpV4+jp609bU3ic7MqnfyLQ2Fpa8BgjIaI2zfsDKAIbwm8DcYDrCLqm5izF5KeL2nxdvg==} + engines: {node: '>=20.16.0'} + hasBin: true + + stackback@0.0.2: + resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} + + std-env@3.10.0: + resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==} + + streamsearch@1.1.0: + resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==} + engines: {node: '>=10.0.0'} + + string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + + string-width@5.1.2: + resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} + engines: {node: '>=12'} + + string.prototype.codepointat@0.2.1: + resolution: {integrity: sha512-2cBVCj6I4IOvEnjgO/hWqXjqBGsY+zwPmHl12Srk9IXSZ56Jwwmy+66XO5Iut/oQVR7t5ihYdLB0GMa4alEUcg==} + + stringify-entities@4.0.4: + resolution: {integrity: sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==} + + strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + + strip-ansi@7.2.0: + resolution: {integrity: sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==} + engines: {node: '>=12'} + + strip-final-newline@2.0.0: + resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} + engines: {node: '>=6'} + + strip-json-comments@2.0.1: + resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==} + engines: {node: '>=0.10.0'} + + strip-literal@3.1.0: + resolution: {integrity: sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==} + + strip-literal@4.0.0: + resolution: {integrity: sha512-PaqAvfUZKBwc/SLmNZtHmzK+v19Z4O4eS3cKPeGvbIv/U3pnyEq4Tuw3/4v/FwfM8VQaEawsyCcOQ0P+kpwWWw==} + + style-to-js@1.1.21: + resolution: {integrity: sha512-RjQetxJrrUJLQPHbLku6U/ocGtzyjbJMP9lCNK7Ag0CNh690nSH8woqWH9u16nMjYBAok+i7JO1NP2pOy8IsPQ==} + + style-to-object@1.0.14: + resolution: {integrity: sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw==} + + styled-jsx@5.1.1: + resolution: {integrity: sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==} + engines: {node: '>= 12.0.0'} + peerDependencies: + '@babel/core': '*' + babel-plugin-macros: '*' + react: '>= 16.8.0 || 17.x.x || ^18.0.0-0' + peerDependenciesMeta: + '@babel/core': + optional: true + babel-plugin-macros: + optional: true + + styled-jsx@5.1.6: + resolution: {integrity: sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==} + engines: {node: '>= 12.0.0'} + peerDependencies: + '@babel/core': '*' + babel-plugin-macros: '*' + 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 + + sucrase@3.35.1: + resolution: {integrity: sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==} + engines: {node: '>=16 || 14 >=14.17'} + hasBin: true + + supports-color@10.2.2: + resolution: {integrity: sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g==} + engines: {node: '>=18'} + + supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + + supports-color@8.1.1: + resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} + engines: {node: '>=10'} + + supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + + tagged-tag@1.0.0: + resolution: {integrity: sha512-yEFYrVhod+hdNyx7g5Bnkkb0G6si8HJurOoOEgC8B/O0uXLHlaey/65KRv6cuWBNhBgHKAROVpc7QyYqE5gFng==} + engines: {node: '>=20'} + + tailwind-merge@2.6.1: + resolution: {integrity: sha512-Oo6tHdpZsGpkKG88HJ8RR1rg/RdnEkQEfMoEk2x1XRI3F1AxeU+ijRXpiVUF4UbLfcxxRGw6TbUINKYdWVsQTQ==} + + tailwindcss-animate@1.0.7: + resolution: {integrity: sha512-bl6mpH3T7I3UFxuvDEXLxy/VuFxBk5bbzplh7tXI68mwMokNYd1t9qPBHlnyTwfa4JGC4zP516I1hYYtQ/vspA==} + peerDependencies: + tailwindcss: '>=3.0.0 || insiders' + + tailwindcss@3.4.6: + resolution: {integrity: sha512-1uRHzPB+Vzu57ocybfZ4jh5Q3SdlH7XW23J5sQoM9LhE9eIOlzxer/3XPSsycvih3rboRsvt0QCmzSrqyOYUIA==} + engines: {node: '>=14.0.0'} + hasBin: true + + tailwindcss@4.3.3: + resolution: {integrity: sha512-gOhV3P7ufE62QDGg1zVaTgCR+EtPv92k2nIhVcVKcLmxT1sUBsQGhnZj175j+MqRt4zLF7ic+sCYjfhxMxj7YQ==} + + tapable@2.3.3: + resolution: {integrity: sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==} + engines: {node: '>=6'} + + terser@5.51.2: + resolution: {integrity: sha512-bWnjSNscmuI+GJze6ZupnHP8G/cTcsJF+bXCeQknk2SHQsgbNJnLrqiH9jZ2W4STPVXH2mDKKRX3iwPhc9Cn/Q==} + engines: {node: '>=10'} + hasBin: true + + thenify-all@1.6.0: + resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} + engines: {node: '>=0.8'} + + thenify@3.3.1: + resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} + + tiny-inflate@1.0.3: + resolution: {integrity: sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==} + + tinybench@2.9.0: + resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} + + tinyexec@0.3.2: + resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} + + tinyexec@1.3.1: + resolution: {integrity: sha512-GCvB3aoys96IuDFBMcTB46JOR6mdMtAToqwiW8JlWhsoh1mhHi/xn9ss/Dg7N555GiJyEt2qzoG/NHCwM6h1EA==} + engines: {node: '>=18'} + + tinyglobby@0.2.17: + resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==} + engines: {node: '>=12.0.0'} + + tinypool@1.1.1: + resolution: {integrity: sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==} + engines: {node: ^18.0.0 || >=20.0.0} + + tinyrainbow@2.0.0: + resolution: {integrity: sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==} + engines: {node: '>=14.0.0'} + + tinyspy@4.0.6: + resolution: {integrity: sha512-u8KszXvGfU68hVcZpRHKG28T0krMuv2G5nDhiHaMLen/gIuFEgIJhaJuO69qjnXg5paSrbPMFfx3brNuN8eVSg==} + engines: {node: '>=14.0.0'} + + to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + + tree-kill@1.2.2: + resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} + hasBin: true + + trim-lines@3.0.1: + resolution: {integrity: sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==} + + trough@2.2.0: + resolution: {integrity: sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==} + + ts-interface-checker@0.1.13: + resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} + + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + + tsup@8.5.1: + resolution: {integrity: sha512-xtgkqwdhpKWr3tKPmCkvYmS9xnQK3m3XgxZHwSUjvfTjp7YfXe5tT3GgWi0F2N+ZSMsOeWeZFh7ZZFg5iPhing==} + engines: {node: '>=18'} + hasBin: true + peerDependencies: + '@microsoft/api-extractor': ^7.36.0 + '@swc/core': ^1 + postcss: ^8.4.12 + typescript: '>=4.5.0' + peerDependenciesMeta: + '@microsoft/api-extractor': + optional: true + '@swc/core': + optional: true + postcss: + optional: true + typescript: + optional: true + + turbo-stream@3.2.1: + resolution: {integrity: sha512-BaX0eWz3IrypOVDFqPv3VGD6uZZW8y3oFAOJqZQ+oopmOyQ8/xNm7IMwAJFvxax2DBa8zSk+/AeqA6D6b1PXGg==} + + turbo@2.11.10: + resolution: {integrity: sha512-3GJYwig8ygEI89oaOZdduJX8/aw6O9eRPYHoIt6T3FZl9hkKjiyIspufJoVgqXihPoJu8M5CSV0DlZvzfohBCw==} + hasBin: true + + type-check@0.4.0: + resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} + engines: {node: '>= 0.8.0'} + + type-fest@2.19.0: + resolution: {integrity: sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==} + engines: {node: '>=12.20'} + + type-fest@5.10.0: + resolution: {integrity: sha512-NoSdpq/WEiAg5sjmBkmV/hfxv6HJH4NqPNrqjtSO5CwRmpsDfaf4begxW34KdJykH/l1yHtwBWQkCRdoXO8mPA==} + engines: {node: '>=20'} + + typescript@5.9.3: + resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} + engines: {node: '>=14.17'} + hasBin: true + + typescript@7.0.2: + resolution: {integrity: sha512-8FYau96o3NKOhbjKi/qNvG/W5jhzxkbdm5sj9AbZ/5T5sWqn3hJgLfGx27sRKZWTvyzCP8dLRBTf5tBTSRVUNA==} + engines: {node: '>=16.20.0'} + hasBin: true + + ufo@1.6.4: + resolution: {integrity: sha512-JFNbkD1Svwe0KvGi8GOeLcP4kAWQ609twvCdcHxq1oSL8svv39ZuSvajcD8B+5D0eL4+s1Is2D/O6KN3qcTeRA==} + + undici-types@5.26.5: + resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} + + undici-types@6.21.0: + resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} + + undici-types@8.9.0: + resolution: {integrity: sha512-KTDyRTYX8sWmKXAikPHHSyc63CRPETMctyjKFupcC6OBLXT3xsN0e9aF7m+mIXutFWpUXuedtowG7iLOzp0kQg==} + + undici@7.29.1: + resolution: {integrity: sha512-RYONW2MeafgYlkVOKYKkA/Ag7BmXqgIWCa8t1m0JcxrQg9pI9lEqRhAOruOBCbAohOa/gkCF+iPi9hrgvTzu6Q==} + engines: {node: '>=20.18.1'} + + unenv@2.0.0-rc.24: + resolution: {integrity: sha512-i7qRCmY42zmCwnYlh9H2SvLEypEFGye5iRmEMKjcGi7zk9UquigRjFtTLz0TYqr0ZGLZhaMHl/foy1bZR+Cwlw==} + + unicode-trie@2.0.0: + resolution: {integrity: sha512-x7bc76x0bm4prf1VLg79uhAzKw8DVboClSN5VxJuQ+LKDOVEW9CdH+VY7SP+vX7xCYQqzzgQpFqz15zeLvAtZQ==} + + unified@11.0.5: + resolution: {integrity: sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==} + + unist-util-is@6.0.1: + resolution: {integrity: sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==} + + unist-util-position-from-estree@2.0.0: + resolution: {integrity: sha512-KaFVRjoqLyF6YXCbVLNad/eS4+OfPQQn2yOd7zF/h5T/CSL2v8NpN6a5TPvtbXthAGw5nG+PuTtq+DdIZr+cRQ==} + + unist-util-position@5.0.0: + resolution: {integrity: sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==} + + unist-util-remove-position@5.0.0: + resolution: {integrity: sha512-Hp5Kh3wLxv0PHj9m2yZhhLt58KzPtEYKQQ4yxfYFEO7EvHwzyDYnduhHnY1mDxoqr7VUwVuHXk9RXKIiYS1N8Q==} + + unist-util-stringify-position@4.0.0: + resolution: {integrity: sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==} + + unist-util-visit-parents@6.1.0: + resolution: {integrity: sha512-vKXxz6O38sKDj1mtx/k2cWvkkFBuYGx6uGrlzBkVeWCRF/F8sdI0j3Wbkz/5rVNRRuVc8UrgRdbCxNhmYXgP3w==} + + unist-util-visit@5.2.0: + resolution: {integrity: sha512-fpsYs/VVoZxfGY9/j3FQpZmN8wdLJaV1Pt38AaJNZu9uKIHcFU3halCdBveEq1HGKO1OEfJY65w1zvoFV1b3qQ==} + + unpic@4.2.2: + resolution: {integrity: sha512-z6T2ScMgRV2y2H8MwwhY5xHZWXhUx/YxtOCGJwfURSl7ypVy4HpLIMWoIZKnnxQa/RKzM0kg8hUh0paIrpLfvw==} + + update-browserslist-db@1.3.4: + resolution: {integrity: sha512-t8wonIOdQyOjtPd2VktlBu6QjTVTks6v8bSi7kd0r2Vll8TK1JYDZtRRdbmCHOAMphkZgrzK+L+vXK4pyZ8t4A==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + + update-check@1.5.4: + resolution: {integrity: sha512-5YHsflzHP4t1G+8WGPlvKbJEbAJGCgw+Em+dGR1KmBUbr1J36SJBqlHLjR7oob7sco5hWHGQVcr9B2poIVDDTQ==} + + uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + + use-callback-ref@1.3.3: + resolution: {integrity: sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + use-sidecar@1.1.3: + resolution: {integrity: sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + use-sync-external-store@1.7.0: + resolution: {integrity: sha512-6L+EeigHMQhdaIPNIFUKwfWJSwWFQ8gJbJ2DLOs5sDIegTwR9fRxvnM3uciHKjIZhFz+KAv2emhWMRvDmMcY8A==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + + util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + + vary@1.1.2: + resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} + engines: {node: '>= 0.8'} + + vfile-message@4.0.3: + resolution: {integrity: sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==} + + vfile@6.0.3: + resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==} + + vinext@1.2.1: + resolution: {integrity: sha512-cB8ViQ4JuxoM2jcsvEB2kdVNSm4zWfNgpYU8Bx6781mRuArlgDsI0Y4w5EqQwkK8e3BzMMHeOreiUbMc8xLLiA==} + engines: {node: '>=22'} + hasBin: true + peerDependencies: + '@mdx-js/rollup': ^3.0.0 + '@vitejs/plugin-react': ^5.1.4 || ^6.0.0 + '@vitejs/plugin-rsc': ^0.5.37 + react: ^19.3.1 + react-dom: ^19.3.1 + react-server-dom-webpack: ^19.3.1 + vite: ^8.0.0 + peerDependenciesMeta: + '@mdx-js/rollup': + optional: true + '@vitejs/plugin-rsc': + optional: true + react-server-dom-webpack: + optional: true + + vite-node@3.2.4: + resolution: {integrity: sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==} + engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} + hasBin: true + + vite-plugin-commonjs@0.10.4: + resolution: {integrity: sha512-eWQuvQKCcx0QYB5e5xfxBNjQKyrjEWZIR9UOkOV6JAgxVhtbZvCOF+FNC2ZijBJ3U3Px04ZMMyyMyFBVWIJ5+g==} + + vite-plugin-dynamic-import@1.6.0: + resolution: {integrity: sha512-TM0sz70wfzTIo9YCxVFwS8OA9lNREsh+0vMHGSkWDTZ7bgd1Yjs5RV8EgB634l/91IsXJReg0xtmuQqP0mf+rg==} + + vite@7.3.7: + resolution: {integrity: sha512-AHEzTORMbi7/7aXp7w7KZ5+DCUdSeLsJz0grY8xHpc9DHdYb0vQu6DqJfm2tOw3gDExNgPgnJTXxM6syYFHaCA==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + '@types/node': ^20.19.0 || >=22.12.0 + jiti: '>=1.21.0' + less: ^4.0.0 + lightningcss: ^1.21.0 + sass: ^1.70.0 + sass-embedded: ^1.70.0 + stylus: '>=0.54.8' + sugarss: ^5.0.0 + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + '@types/node': + optional: true + jiti: + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + + vite@8.3.4: + resolution: {integrity: sha512-IftLE8phJhdNRIGNEV4JCCvfNScoZQVfcXaN8TQropWGJtOHcu+iAB9pHcuGvmEb/kddw0LBe/jS8ztdC6xdiQ==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + '@types/node': ^20.19.0 || >=22.12.0 + '@vitejs/devtools': ^0.7.1 + esbuild: ^0.27.0 || ^0.28.0 + jiti: '>=1.21.0' + less: ^4.0.0 + sass: ^1.70.0 + sass-embedded: ^1.70.0 + stylus: '>=0.54.8' + sugarss: ^5.0.0 + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + '@types/node': + optional: true + '@vitejs/devtools': + optional: true + esbuild: + optional: true + jiti: + optional: true + less: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + + vitefu@1.1.3: + resolution: {integrity: sha512-ub4okH7Z5KLjb6hDyjqrGXqWtWvoYdU3IGm/NorpgHncKoLTCfRIbvlhBm7r0YstIaQRYlp4yEbFqDcKSzXSSg==} + peerDependencies: + vite: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 + peerDependenciesMeta: + vite: + optional: true + + vitest@3.2.7: + resolution: {integrity: sha512-KrxIJ62Fd89gfysR4WotlgZABiz2dqFPgqGzX7s+CwsqLFomRH7777ZcrOD6+WVAh7khPQP41A+BKbpcJFrdEg==} + engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} + hasBin: true + peerDependencies: + '@edge-runtime/vm': '*' + '@types/debug': ^4.1.12 + '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 + '@vitest/browser': 3.2.7 + '@vitest/ui': 3.2.7 + happy-dom: '*' + jsdom: '*' + peerDependenciesMeta: + '@edge-runtime/vm': + optional: true + '@types/debug': + optional: true + '@types/node': + optional: true + '@vitest/browser': + optional: true + '@vitest/ui': + optional: true + happy-dom: + optional: true + jsdom: + optional: true + + watchpack@2.6.3: + resolution: {integrity: sha512-s3NZy0QpTY9qGqzc0wtz4qI28z3+5qKbbAec4MV4G9N3CfgZ9wgvQRr0cl2jh/tqkWG1NWHkmVMHZpCamev5Wg==} + engines: {node: '>=10.13.0'} + + web-namespaces@2.0.1: + resolution: {integrity: sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==} + + web-vitals@4.2.4: + resolution: {integrity: sha512-r4DIlprAGwJ7YM11VZp4R884m0Vmgr6EAKe3P+kO0PPj3Unqyvv59rczf6UiGcb9Z8QxZVcqKNwv/g0WNdWwsw==} + + webpack-sources@3.6.0: + resolution: {integrity: sha512-EIMmPVvNI0CYXyRPp34F2Qk7W37/BZVZIofS6LAUnrNjCVahS+hO4mxwFJDjQjODTGZDtVzLYoN2+1dYkhk9qA==} + engines: {node: '>=10.13.0'} + + webpack@5.112.2: + resolution: {integrity: sha512-B2tp1LI9D8GVpPDqprdt12ukTkXXahj9MzqSWJq4faSPgOUM7CdZaGAB6HrL/8E6UwbBpdj4vzWDbKoFnVoU6g==} + engines: {node: '>=10.13.0'} + hasBin: true + peerDependencies: + webpack-cli: '*' + peerDependenciesMeta: + webpack-cli: + optional: true + + webrtc-adapter@9.0.6: + resolution: {integrity: sha512-CHbl2ZQbxx164IgWRgzJno4hWtM4tFbRam1QfI3Yxhs3w/DvqluVxVWeXs3oL5/fbGkSNLKo0Ty5MgUWceNhog==} + engines: {node: '>=6.0.0', npm: '>=3.10.0'} + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + + why-is-node-running@2.3.0: + resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} + engines: {node: '>=8'} + hasBin: true + + widest-line@4.0.1: + resolution: {integrity: sha512-o0cyEG0e8GPzT4iGHphIOh0cJOV8fivsXxddQasHPHfoZf1ZexrfeA21w2NaEN1RHE+fXlfISmOE8R9N3u3Qig==} + engines: {node: '>=12'} + + word-wrap@1.2.5: + resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} + engines: {node: '>=0.10.0'} + + workerd@1.20261012.1: + resolution: {integrity: sha512-tEHoMPsMga0seVjxfsR8Pd3f8IRqYwkq++dTUKI5Gdgj6zuSDluYwisydq+dn90SsIACwBquJUQ1nBpcOqaWTA==} + engines: {node: '>=16'} + hasBin: true + + workerd@1.20261019.1: + resolution: {integrity: sha512-UUYRUq/7DmeCl11YriNbcVbjUZVLtt8uuCXFu+nz77hGFf8d4DEVXoCYtnA+MlBatE4+wxoj47DVqzK3xGBAiw==} + engines: {node: '>=16'} + hasBin: true + + wrangler@4.151.3: + resolution: {integrity: sha512-mzPQLmkAhZUV7CdiAhE+hiIAJlS9xPL6vZe1B8oQFuWxFu7nmQnvHAVjcAcabwSGkXFXH9uspzXwHOFrfbQmqQ==} + engines: {node: '>=22.0.0'} + hasBin: true + peerDependencies: + '@cloudflare/workers-types': ^5.20261019.1 + peerDependenciesMeta: + '@cloudflare/workers-types': + optional: true + + wrap-ansi@6.2.0: + resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} + engines: {node: '>=8'} + + wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + + wrap-ansi@8.1.0: + resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} + engines: {node: '>=12'} + + ws@8.21.0: + resolution: {integrity: sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + + ws@8.22.0: + resolution: {integrity: sha512-Ydggc987+RO0AnWtZ/7Wq9FtNvcrL1b/RO0ud9mWjUPgDrsAAwQSF51sm2hm1XofbU/4jkpGEsLFsZZxU+1DOg==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + + xtend@4.0.2: + resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} + engines: {node: '>=0.4'} + + y18n@5.0.8: + resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} + engines: {node: '>=10'} + + yaml@2.9.1: + resolution: {integrity: sha512-3NxN8+78OdzbT7C/WjGsyfPAtJaN3FNDsWxv7Y7mcDsT/oOmgW8BpyQQFFBnvZE3j9Y2Sdz1ULFLezL7Eb2yFw==} + engines: {node: '>= 14.6'} + hasBin: true + + yargs-parser@21.1.1: + resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} + engines: {node: '>=12'} + + yargs@17.7.2: + resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} + engines: {node: '>=12'} + + yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + + yoctocolors-cjs@2.1.3: + resolution: {integrity: sha512-U/PBtDf35ff0D8X8D0jfdzHYEPFxAI7jJlxZXwCSez5M3190m+QobIfh+sWDWSHMCWWJN2AWamkegn6vr6YBTw==} + engines: {node: '>=18'} + + yoga-layout@3.2.1: + resolution: {integrity: sha512-0LPOt3AxKqMdFBZA3HBAt/t/8vIKq7VaQYbuA8WxCgung+p9TVyKRYdpvCb80HcdTN2NkbIKbhNwKUfm3tQywQ==} + + youch-core@0.3.3: + resolution: {integrity: sha512-ho7XuGjLaJ2hWHoK8yFnsUGy2Y5uDpqSTq1FkHLK4/oqKtyUU1AFbOOxY4IpC9f0fTLjwYbslUz0Po5BpD1wrA==} + + youch@4.1.0-beta.10: + resolution: {integrity: sha512-rLfVLB4FgQneDr0dv1oddCVZmKjcJ6yX6mS4pU82Mq/Dt9a3cLZQ62pDBL4AUO+uVrCvtWz3ZFUL2HFAFJ/BXQ==} + + yuku-analyzer@0.19.0: + resolution: {integrity: sha512-Iu7DV5cWOQ3ERSA7oBquz/RT5IEGsUyUeCivYs9lQaZ4nSjM31yD17mH616JKcTyVoVWYivsFZ+twT3UyBosTA==} + engines: {node: '>=14.18.0'} + + yuku-ast@0.19.0: + resolution: {integrity: sha512-PyCsiScaelhxBGzL8dyeJkLqvRZycoh78R31Vrt/WqYrm0hMFoKwIw/X7Dx5mBKLWAMlV9I9HEyBOHnj2gZVyw==} + engines: {node: '>=14.18.0'} + + yuku-core@0.19.0: + resolution: {integrity: sha512-kYK9e1XdfirNhkipzW0wmMcSWcVF/CWnuugodfVYRCUwvoBefweL9HzB96OiKEhsx78V5WbUxbJqlizMX869Qg==} + engines: {node: '>=14.18.0'} + + zbsearch@4.0.1: + resolution: {integrity: sha512-lmnEEnb93QQcNv7qARDr7jBVPxYdZbZ9XdZ0dbZ0qaOvGne4jJMW4fjwPfVaUKQXv3FNWvGbDwRDgyaSb1pc8w==} + engines: {node: '>= 20.0.0'} + + zod@3.25.76: + resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} + + zod@4.6.7: + resolution: {integrity: sha512-g8W2D2kU6a8untc053fX1uVBKzM7yqAxW/3zwk83+6RyF2+SKOuV+c0wBDhUwzV1PaGapmZH+rmcUzPf+3CGwg==} + + zwitch@2.0.4: + resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} + + zxing-wasm@3.1.6: + resolution: {integrity: sha512-mU7UNuvl+hOT+nlSOQTMHZ2tM8lRMsbjDIp5IO/+HmBl/FOq77q0OSZPJ3cm42A9c1MKU6Uve67FiGdkhsrT9g==} + peerDependencies: + '@types/emscripten': '>=1.39.6' + +snapshots: + + '@a77ay/better-auth-mikro-orm@0.1.1(@mikro-orm/core@7.2.1)(better-auth@1.7.6(mysql2@3.24.4(@types/node@20.14.11))(next@16.4.2(@playwright/test@1.64.1)(@types/node@20.14.11)(react-dom@19.3.1(react@19.3.1))(react@19.3.1))(pg@8.23.0)(react-dom@19.3.1(react@19.3.1))(react@19.3.1)(vitest@3.2.7(@types/debug@4.1.13)(@types/node@20.14.11)(jiti@2.7.0)(lightningcss@1.33.0)(supports-color@10.2.2)(terser@5.51.2)(yaml@2.9.1)))': + dependencies: + '@mikro-orm/core': 7.2.1 + better-auth: 1.7.6(mysql2@3.24.4(@types/node@20.14.11))(next@16.4.2(@playwright/test@1.64.1)(@types/node@20.14.11)(react-dom@19.3.1(react@19.3.1))(react@19.3.1))(pg@8.23.0)(react-dom@19.3.1(react@19.3.1))(react@19.3.1)(vitest@3.2.7(@types/debug@4.1.13)(@types/node@20.14.11)(jiti@2.7.0)(lightningcss@1.33.0)(supports-color@10.2.2)(terser@5.51.2)(yaml@2.9.1)) + jiti: 2.7.0 + + '@alloc/quick-lru@5.3.0': {} + + '@aws-sdk/checksums@3.1001.6': + dependencies: + '@aws-sdk/core': 3.978.6 + '@aws-sdk/types': 3.975.0 + '@smithy/core': 3.37.0 + '@smithy/types': 4.19.0 tslib: 2.8.1 - dev: false - /@aws-sdk/credential-provider-env@3.744.0: - resolution: {integrity: sha512-hyjC7xqzAeERorYYjhQG1ivcr1XlxgfBpa+r4pG29toFG60mACyVzaR7+og3kgzjRFAB7D1imMxPQyEvQ1QokA==} - engines: {node: '>=18.0.0'} + '@aws-sdk/client-s3@3.1157.0': + dependencies: + '@aws-sdk/checksums': 3.1001.6 + '@aws-sdk/core': 3.978.6 + '@aws-sdk/credential-provider-node': 3.972.89 + '@aws-sdk/middleware-sdk-s3': 3.972.82 + '@aws-sdk/signature-v4-multi-region': 3.996.49 + '@aws-sdk/types': 3.975.0 + '@smithy/core': 3.37.0 + '@smithy/fetch-http-handler': 5.8.0 + '@smithy/node-http-handler': 4.13.0 + '@smithy/types': 4.19.0 + tslib: 2.8.1 + + '@aws-sdk/core@3.978.6': dependencies: - '@aws-sdk/core': 3.744.0 - '@aws-sdk/types': 3.734.0 - '@smithy/property-provider': 4.4.8 - '@smithy/types': 4.16.1 + '@aws-sdk/types': 3.975.0 + '@aws-sdk/xml-builder': 3.972.41 + '@aws/lambda-invoke-store': 0.3.0 + '@smithy/core': 3.37.0 + '@smithy/signature-v4': 5.7.4 + '@smithy/types': 4.19.0 + bowser: 2.15.0 tslib: 2.8.1 - dev: false - /@aws-sdk/credential-provider-http@3.744.0: - resolution: {integrity: sha512-k+P1Tl5ewBvVByR6hB726qFIzANgQVf2cY87hZ/e09pQYlH4bfBcyY16VJhkqYnKmv6HMdWxKHX7D8nwlc8Obg==} - engines: {node: '>=18.0.0'} + '@aws-sdk/credential-provider-env@3.972.77': dependencies: - '@aws-sdk/core': 3.744.0 - '@aws-sdk/types': 3.734.0 - '@smithy/fetch-http-handler': 5.6.5 - '@smithy/node-http-handler': 4.9.5 - '@smithy/property-provider': 4.4.8 - '@smithy/protocol-http': 5.5.8 - '@smithy/smithy-client': 4.14.8 - '@smithy/types': 4.16.1 - '@smithy/util-stream': 4.7.8 + '@aws-sdk/core': 3.978.6 + '@aws-sdk/types': 3.975.0 + '@smithy/core': 3.37.0 + '@smithy/types': 4.19.0 tslib: 2.8.1 - dev: false - /@aws-sdk/credential-provider-ini@3.744.0: - resolution: {integrity: sha512-hjEWgkF86tkvg8PIsDiB3KkTj7z8ZFGR0v0OLQYD47o17q1qfoMzZmg9wae3wXp9KzU+lZETo+8oMqX9a+7aVQ==} - engines: {node: '>=18.0.0'} + '@aws-sdk/credential-provider-http@3.972.79': dependencies: - '@aws-sdk/core': 3.744.0 - '@aws-sdk/credential-provider-env': 3.744.0 - '@aws-sdk/credential-provider-http': 3.744.0 - '@aws-sdk/credential-provider-process': 3.744.0 - '@aws-sdk/credential-provider-sso': 3.744.0 - '@aws-sdk/credential-provider-web-identity': 3.744.0 - '@aws-sdk/nested-clients': 3.744.0 - '@aws-sdk/types': 3.734.0 - '@smithy/credential-provider-imds': 4.4.8 - '@smithy/property-provider': 4.4.8 - '@smithy/shared-ini-file-loader': 4.6.8 - '@smithy/types': 4.16.1 + '@aws-sdk/core': 3.978.6 + '@aws-sdk/types': 3.975.0 + '@smithy/core': 3.37.0 + '@smithy/fetch-http-handler': 5.8.0 + '@smithy/node-http-handler': 4.13.0 + '@smithy/types': 4.19.0 tslib: 2.8.1 - transitivePeerDependencies: - - aws-crt - dev: false - /@aws-sdk/credential-provider-node@3.744.0: - resolution: {integrity: sha512-4oUfRd6pe/VGmKoav17pPoOO0WP0L6YXmHqtJHSDmFUOAa+Vh0ZRljTj/yBdleRgdO6rOfdWqoGLFSFiAZDrsQ==} - engines: {node: '>=18.0.0'} + '@aws-sdk/credential-provider-ini@3.973.22': + dependencies: + '@aws-sdk/core': 3.978.6 + '@aws-sdk/credential-provider-env': 3.972.77 + '@aws-sdk/credential-provider-http': 3.972.79 + '@aws-sdk/credential-provider-login': 3.972.84 + '@aws-sdk/credential-provider-process': 3.972.77 + '@aws-sdk/credential-provider-sso': 3.973.21 + '@aws-sdk/credential-provider-web-identity': 3.972.83 + '@aws-sdk/nested-clients': 3.997.51 + '@aws-sdk/types': 3.975.0 + '@smithy/core': 3.37.0 + '@smithy/credential-provider-imds': 4.5.2 + '@smithy/types': 4.19.0 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-login@3.972.84': dependencies: - '@aws-sdk/credential-provider-env': 3.744.0 - '@aws-sdk/credential-provider-http': 3.744.0 - '@aws-sdk/credential-provider-ini': 3.744.0 - '@aws-sdk/credential-provider-process': 3.744.0 - '@aws-sdk/credential-provider-sso': 3.744.0 - '@aws-sdk/credential-provider-web-identity': 3.744.0 - '@aws-sdk/types': 3.734.0 - '@smithy/credential-provider-imds': 4.4.8 - '@smithy/property-provider': 4.4.8 - '@smithy/shared-ini-file-loader': 4.6.8 - '@smithy/types': 4.16.1 + '@aws-sdk/core': 3.978.6 + '@aws-sdk/nested-clients': 3.997.51 + '@aws-sdk/types': 3.975.0 + '@smithy/core': 3.37.0 + '@smithy/types': 4.19.0 tslib: 2.8.1 - transitivePeerDependencies: - - aws-crt - dev: false - /@aws-sdk/credential-provider-process@3.744.0: - resolution: {integrity: sha512-m0d/pDBIaiEAAxWXt/c79RHsKkUkyPOvF2SAMRddVhhOt1GFZI4ml+3f4drmAZfXldIyJmvJTJJqWluVPwTIqQ==} - engines: {node: '>=18.0.0'} + '@aws-sdk/credential-provider-node@3.972.89': + dependencies: + '@aws-sdk/credential-provider-env': 3.972.77 + '@aws-sdk/credential-provider-http': 3.972.79 + '@aws-sdk/credential-provider-ini': 3.973.22 + '@aws-sdk/credential-provider-process': 3.972.77 + '@aws-sdk/credential-provider-sso': 3.973.21 + '@aws-sdk/credential-provider-web-identity': 3.972.83 + '@aws-sdk/types': 3.975.0 + '@smithy/core': 3.37.0 + '@smithy/credential-provider-imds': 4.5.2 + '@smithy/types': 4.19.0 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-process@3.972.77': dependencies: - '@aws-sdk/core': 3.744.0 - '@aws-sdk/types': 3.734.0 - '@smithy/property-provider': 4.4.8 - '@smithy/shared-ini-file-loader': 4.6.8 - '@smithy/types': 4.16.1 + '@aws-sdk/core': 3.978.6 + '@aws-sdk/types': 3.975.0 + '@smithy/core': 3.37.0 + '@smithy/types': 4.19.0 tslib: 2.8.1 - dev: false - /@aws-sdk/credential-provider-sso@3.744.0: - resolution: {integrity: sha512-xdMufTZOvpbDoDPI2XLu0/Rg3qJ/txpS8IJR63NsCGotHJZ/ucLNKwTcGS40hllZB8qSHTlvmlOzElDahTtx/A==} - engines: {node: '>=18.0.0'} + '@aws-sdk/credential-provider-sso@3.973.21': dependencies: - '@aws-sdk/client-sso': 3.744.0 - '@aws-sdk/core': 3.744.0 - '@aws-sdk/token-providers': 3.744.0 - '@aws-sdk/types': 3.734.0 - '@smithy/property-provider': 4.4.8 - '@smithy/shared-ini-file-loader': 4.6.8 - '@smithy/types': 4.16.1 + '@aws-sdk/core': 3.978.6 + '@aws-sdk/nested-clients': 3.997.51 + '@aws-sdk/token-providers': 3.1157.0 + '@aws-sdk/types': 3.975.0 + '@smithy/core': 3.37.0 + '@smithy/types': 4.19.0 tslib: 2.8.1 - transitivePeerDependencies: - - aws-crt - dev: false - /@aws-sdk/credential-provider-web-identity@3.744.0: - resolution: {integrity: sha512-cNk93GZxORzqEojWfXdrPBF6a7Nu3LpPCWG5mV+lH2tbuGsmw6XhKkwpt7o+OiIP4tKCpHlvqOD8f1nmhe1KDA==} - engines: {node: '>=18.0.0'} + '@aws-sdk/credential-provider-web-identity@3.972.83': dependencies: - '@aws-sdk/core': 3.744.0 - '@aws-sdk/nested-clients': 3.744.0 - '@aws-sdk/types': 3.734.0 - '@smithy/property-provider': 4.4.8 - '@smithy/types': 4.16.1 + '@aws-sdk/core': 3.978.6 + '@aws-sdk/nested-clients': 3.997.51 + '@aws-sdk/types': 3.975.0 + '@smithy/core': 3.37.0 + '@smithy/types': 4.19.0 tslib: 2.8.1 - transitivePeerDependencies: - - aws-crt - dev: false - /@aws-sdk/middleware-bucket-endpoint@3.734.0: - resolution: {integrity: sha512-etC7G18aF7KdZguW27GE/wpbrNmYLVT755EsFc8kXpZj8D6AFKxc7OuveinJmiy0bYXAMspJUWsF6CrGpOw6CQ==} - engines: {node: '>=18.0.0'} + '@aws-sdk/middleware-sdk-s3@3.972.82': dependencies: - '@aws-sdk/types': 3.734.0 - '@aws-sdk/util-arn-parser': 3.723.0 - '@smithy/node-config-provider': 4.5.8 - '@smithy/protocol-http': 5.5.8 - '@smithy/types': 4.16.1 - '@smithy/util-config-provider': 4.4.8 + '@aws-sdk/core': 3.978.6 + '@aws-sdk/signature-v4-multi-region': 3.996.49 + '@aws-sdk/types': 3.975.0 + '@smithy/core': 3.37.0 + '@smithy/types': 4.19.0 tslib: 2.8.1 - dev: false - /@aws-sdk/middleware-expect-continue@3.734.0: - resolution: {integrity: sha512-P38/v1l6HjuB2aFUewt7ueAW5IvKkFcv5dalPtbMGRhLeyivBOHwbCyuRKgVs7z7ClTpu9EaViEGki2jEQqEsQ==} - engines: {node: '>=18.0.0'} + '@aws-sdk/nested-clients@3.997.51': dependencies: - '@aws-sdk/types': 3.734.0 - '@smithy/protocol-http': 5.5.8 - '@smithy/types': 4.16.1 + '@aws-sdk/core': 3.978.6 + '@aws-sdk/signature-v4-multi-region': 3.996.49 + '@aws-sdk/types': 3.975.0 + '@smithy/core': 3.37.0 + '@smithy/fetch-http-handler': 5.8.0 + '@smithy/node-http-handler': 4.13.0 + '@smithy/types': 4.19.0 tslib: 2.8.1 - dev: false - /@aws-sdk/middleware-flexible-checksums@3.744.0: - resolution: {integrity: sha512-4AuBdvkwfwagZQt3kt1b0x2dtC54cOrN5gt96V2b4wIjHBRxB/IfAyynahOgx3fd7Zjf74xwmxasjs7iJ8yglg==} - engines: {node: '>=18.0.0'} + '@aws-sdk/s3-request-presigner@3.1157.0': dependencies: - '@aws-crypto/crc32': 5.2.0 - '@aws-crypto/crc32c': 5.2.0 - '@aws-crypto/util': 5.2.0 - '@aws-sdk/core': 3.744.0 - '@aws-sdk/types': 3.734.0 - '@smithy/is-array-buffer': 4.4.8 - '@smithy/node-config-provider': 4.5.8 - '@smithy/protocol-http': 5.5.8 - '@smithy/types': 4.16.1 - '@smithy/util-middleware': 4.4.8 - '@smithy/util-stream': 4.7.8 - '@smithy/util-utf8': 4.4.8 + '@aws-sdk/core': 3.978.6 + '@aws-sdk/signature-v4-multi-region': 3.996.49 + '@aws-sdk/types': 3.975.0 + '@smithy/core': 3.37.0 + '@smithy/types': 4.19.0 tslib: 2.8.1 - dev: false - /@aws-sdk/middleware-host-header@3.734.0: - resolution: {integrity: sha512-LW7RRgSOHHBzWZnigNsDIzu3AiwtjeI2X66v+Wn1P1u+eXssy1+up4ZY/h+t2sU4LU36UvEf+jrZti9c6vRnFw==} - engines: {node: '>=18.0.0'} + '@aws-sdk/signature-v4-multi-region@3.996.49': dependencies: - '@aws-sdk/types': 3.734.0 - '@smithy/protocol-http': 5.5.8 - '@smithy/types': 4.16.1 + '@aws-sdk/types': 3.975.0 + '@smithy/signature-v4': 5.7.4 + '@smithy/types': 4.19.0 tslib: 2.8.1 - dev: false - /@aws-sdk/middleware-location-constraint@3.734.0: - resolution: {integrity: sha512-EJEIXwCQhto/cBfHdm3ZOeLxd2NlJD+X2F+ZTOxzokuhBtY0IONfC/91hOo5tWQweerojwshSMHRCKzRv1tlwg==} - engines: {node: '>=18.0.0'} + '@aws-sdk/token-providers@3.1157.0': + dependencies: + '@aws-sdk/core': 3.978.6 + '@aws-sdk/nested-clients': 3.997.51 + '@aws-sdk/types': 3.975.0 + '@smithy/core': 3.37.0 + '@smithy/types': 4.19.0 + tslib: 2.8.1 + + '@aws-sdk/types@3.975.0': + dependencies: + '@smithy/types': 4.19.0 + tslib: 2.8.1 + + '@aws-sdk/xml-builder@3.972.41': + dependencies: + '@smithy/types': 4.19.0 + tslib: 2.8.1 + + '@aws/lambda-invoke-store@0.3.0': {} + + '@babel/runtime@7.29.10': {} + + '@babel/runtime@8.0.8': {} + + '@base-ui/react@1.9.0(@types/react@19.3.0)(react-dom@19.3.1(react@19.3.1))(react@19.3.1)': + dependencies: + '@babel/runtime': 8.0.8 + '@base-ui/utils': 0.5.0(@types/react@19.3.0)(react-dom@19.3.1(react@19.3.1))(react@19.3.1) + '@floating-ui/react-dom': 2.1.9(react-dom@19.3.1(react@19.3.1))(react@19.3.1) + '@floating-ui/utils': 0.2.12 + react: 19.3.1 + react-dom: 19.3.1(react@19.3.1) + use-sync-external-store: 1.7.0(react@19.3.1) + optionalDependencies: + '@types/react': 19.3.0 + + '@base-ui/utils@0.5.0(@types/react@19.3.0)(react-dom@19.3.1(react@19.3.1))(react@19.3.1)': + dependencies: + '@babel/runtime': 8.0.8 + '@floating-ui/utils': 0.2.12 + react: 19.3.1 + react-dom: 19.3.1(react@19.3.1) + reselect: 5.3.0 + use-sync-external-store: 1.7.0(react@19.3.1) + optionalDependencies: + '@types/react': 19.3.0 + + '@better-auth/core@1.7.6(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@3.25.76))(jose@6.2.13)(kysely@0.29.6)(nanostores@1.5.5)': + dependencies: + '@better-auth/utils': 0.4.2 + '@better-fetch/fetch': 1.3.2 + '@opentelemetry/semantic-conventions': 1.43.0 + '@standard-schema/spec': 1.1.0 + better-call: 1.4.0(zod@3.25.76) + jose: 6.2.13 + kysely: 0.29.6 + nanostores: 1.5.5 + zod: 4.6.7 + + '@better-auth/core@1.7.6(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.6.7))(jose@6.2.13)(kysely@0.29.6)(nanostores@1.5.5)': + dependencies: + '@better-auth/utils': 0.4.2 + '@better-fetch/fetch': 1.3.2 + '@opentelemetry/semantic-conventions': 1.43.0 + '@standard-schema/spec': 1.1.0 + better-call: 1.4.0(zod@4.6.7) + jose: 6.2.13 + kysely: 0.29.6 + nanostores: 1.5.5 + zod: 4.6.7 + + '@better-auth/drizzle-adapter@1.7.6(@better-auth/core@1.7.6(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.6.7))(jose@6.2.13)(kysely@0.29.6)(nanostores@1.5.5))(@better-auth/utils@0.4.2)': + dependencies: + '@better-auth/core': 1.7.6(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.6.7))(jose@6.2.13)(kysely@0.29.6)(nanostores@1.5.5) + '@better-auth/utils': 0.4.2 + + '@better-auth/kysely-adapter@1.7.6(@better-auth/core@1.7.6(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.6.7))(jose@6.2.13)(kysely@0.29.6)(nanostores@1.5.5))(@better-auth/utils@0.4.2)(kysely@0.29.6)': + dependencies: + '@better-auth/core': 1.7.6(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.6.7))(jose@6.2.13)(kysely@0.29.6)(nanostores@1.5.5) + '@better-auth/utils': 0.4.2 + optionalDependencies: + kysely: 0.29.6 + + '@better-auth/memory-adapter@1.7.6(@better-auth/core@1.7.6(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.6.7))(jose@6.2.13)(kysely@0.29.6)(nanostores@1.5.5))(@better-auth/utils@0.4.2)': + dependencies: + '@better-auth/core': 1.7.6(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.6.7))(jose@6.2.13)(kysely@0.29.6)(nanostores@1.5.5) + '@better-auth/utils': 0.4.2 + + '@better-auth/mongo-adapter@1.7.6(@better-auth/core@1.7.6(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.6.7))(jose@6.2.13)(kysely@0.29.6)(nanostores@1.5.5))(@better-auth/utils@0.4.2)': + dependencies: + '@better-auth/core': 1.7.6(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.6.7))(jose@6.2.13)(kysely@0.29.6)(nanostores@1.5.5) + '@better-auth/utils': 0.4.2 + + '@better-auth/prisma-adapter@1.7.6(@better-auth/core@1.7.6(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.6.7))(jose@6.2.13)(kysely@0.29.6)(nanostores@1.5.5))(@better-auth/utils@0.4.2)': + dependencies: + '@better-auth/core': 1.7.6(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.6.7))(jose@6.2.13)(kysely@0.29.6)(nanostores@1.5.5) + '@better-auth/utils': 0.4.2 + + '@better-auth/telemetry@1.7.6(@better-auth/core@1.7.6(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.6.7))(jose@6.2.13)(kysely@0.29.6)(nanostores@1.5.5))(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)': + dependencies: + '@better-auth/core': 1.7.6(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.6.7))(jose@6.2.13)(kysely@0.29.6)(nanostores@1.5.5) + '@better-auth/utils': 0.4.2 + '@better-fetch/fetch': 1.3.2 + + '@better-auth/utils@0.4.2': + dependencies: + '@noble/hashes': 2.4.0 + + '@better-auth/utils@0.5.1': + dependencies: + '@noble/hashes': 2.4.0 + + '@better-fetch/fetch@1.3.2': {} + + '@cacheable/memory@2.2.0': + dependencies: + '@cacheable/utils': 2.5.0 + '@keyv/bigmap': 1.3.1(keyv@5.6.0) + hookified: 1.15.1 + keyv: 5.6.0 + + '@cacheable/utils@2.5.0': + dependencies: + hashery: 1.5.1 + keyv: 5.6.0 + + '@cloudflare/kv-asset-handler@0.5.0': {} + + '@cloudflare/unenv-preset@2.16.2(unenv@2.0.0-rc.24)(workerd@1.20261012.1)': + dependencies: + unenv: 2.0.0-rc.24 + optionalDependencies: + workerd: 1.20261012.1 + + '@cloudflare/unenv-preset@2.16.2(unenv@2.0.0-rc.24)(workerd@1.20261019.1)': + dependencies: + unenv: 2.0.0-rc.24 + optionalDependencies: + workerd: 1.20261019.1 + + '@cloudflare/vite-plugin@1.64.0(@types/node@22.18.6)(vite@8.3.4(@types/node@22.18.6)(esbuild@0.28.2)(jiti@2.4.2)(terser@5.51.2)(yaml@2.9.1))(wrangler@4.151.3(@cloudflare/workers-types@5.20261019.1)(@types/node@22.18.6))': + dependencies: + '@cloudflare/unenv-preset': 2.16.2(unenv@2.0.0-rc.24)(workerd@1.20261012.1) + miniflare: 5.20261012.0-beta(@types/node@22.18.6) + unenv: 2.0.0-rc.24 + vite: 8.3.4(@types/node@22.18.6)(esbuild@0.28.2)(jiti@2.4.2)(terser@5.51.2)(yaml@2.9.1) + workerd: 1.20261012.1 + wrangler: 4.151.3(@cloudflare/workers-types@5.20261019.1)(@types/node@22.18.6) + ws: 8.21.0 + transitivePeerDependencies: + - '@types/node' + - bufferutil + - utf-8-validate + + '@cloudflare/workerd-darwin-64@1.20261012.1': + optional: true + + '@cloudflare/workerd-darwin-64@1.20261019.1': + optional: true + + '@cloudflare/workerd-darwin-arm64@1.20261012.1': + optional: true + + '@cloudflare/workerd-darwin-arm64@1.20261019.1': + optional: true + + '@cloudflare/workerd-linux-64@1.20261012.1': + optional: true + + '@cloudflare/workerd-linux-64@1.20261019.1': + optional: true + + '@cloudflare/workerd-linux-arm64@1.20261012.1': + optional: true + + '@cloudflare/workerd-linux-arm64@1.20261019.1': + optional: true + + '@cloudflare/workerd-windows-64@1.20261012.1': + optional: true + + '@cloudflare/workerd-windows-64@1.20261019.1': + optional: true + + '@cloudflare/workers-types@5.20261019.1': {} + + '@cspotcode/source-map-support@0.8.1': + dependencies: + '@jridgewell/trace-mapping': 0.3.9 + + '@emnapi/runtime@1.11.3': dependencies: - '@aws-sdk/types': 3.734.0 - '@smithy/types': 4.16.1 tslib: 2.8.1 - dev: false + optional: true + + '@esbuild/aix-ppc64@0.25.12': + optional: true + + '@esbuild/aix-ppc64@0.27.7': + optional: true + + '@esbuild/aix-ppc64@0.28.2': + optional: true + + '@esbuild/android-arm64@0.25.12': + optional: true + + '@esbuild/android-arm64@0.27.7': + optional: true + + '@esbuild/android-arm64@0.28.2': + optional: true + + '@esbuild/android-arm@0.25.12': + optional: true + + '@esbuild/android-arm@0.27.7': + optional: true + + '@esbuild/android-arm@0.28.2': + optional: true + + '@esbuild/android-x64@0.25.12': + optional: true + + '@esbuild/android-x64@0.27.7': + optional: true + + '@esbuild/android-x64@0.28.2': + optional: true + + '@esbuild/darwin-arm64@0.25.12': + optional: true + + '@esbuild/darwin-arm64@0.27.7': + optional: true + + '@esbuild/darwin-arm64@0.28.2': + optional: true + + '@esbuild/darwin-x64@0.25.12': + optional: true + + '@esbuild/darwin-x64@0.27.7': + optional: true + + '@esbuild/darwin-x64@0.28.2': + optional: true + + '@esbuild/freebsd-arm64@0.25.12': + optional: true + + '@esbuild/freebsd-arm64@0.27.7': + optional: true + + '@esbuild/freebsd-arm64@0.28.2': + optional: true + + '@esbuild/freebsd-x64@0.25.12': + optional: true + + '@esbuild/freebsd-x64@0.27.7': + optional: true + + '@esbuild/freebsd-x64@0.28.2': + optional: true + + '@esbuild/linux-arm64@0.25.12': + optional: true + + '@esbuild/linux-arm64@0.27.7': + optional: true + + '@esbuild/linux-arm64@0.28.2': + optional: true + + '@esbuild/linux-arm@0.25.12': + optional: true + + '@esbuild/linux-arm@0.27.7': + optional: true + + '@esbuild/linux-arm@0.28.2': + optional: true + + '@esbuild/linux-ia32@0.25.12': + optional: true + + '@esbuild/linux-ia32@0.27.7': + optional: true + + '@esbuild/linux-ia32@0.28.2': + optional: true - /@aws-sdk/middleware-logger@3.734.0: - resolution: {integrity: sha512-mUMFITpJUW3LcKvFok176eI5zXAUomVtahb9IQBwLzkqFYOrMJvWAvoV4yuxrJ8TlQBG8gyEnkb9SnhZvjg67w==} - engines: {node: '>=18.0.0'} - dependencies: - '@aws-sdk/types': 3.734.0 - '@smithy/types': 4.16.1 - tslib: 2.8.1 - dev: false + '@esbuild/linux-loong64@0.25.12': + optional: true - /@aws-sdk/middleware-recursion-detection@3.734.0: - resolution: {integrity: sha512-CUat2d9ITsFc2XsmeiRQO96iWpxSKYFjxvj27Hc7vo87YUHRnfMfnc8jw1EpxEwMcvBD7LsRa6vDNky6AjcrFA==} - engines: {node: '>=18.0.0'} - dependencies: - '@aws-sdk/types': 3.734.0 - '@smithy/protocol-http': 5.5.8 - '@smithy/types': 4.16.1 - tslib: 2.8.1 - dev: false + '@esbuild/linux-loong64@0.27.7': + optional: true - /@aws-sdk/middleware-sdk-s3@3.744.0: - resolution: {integrity: sha512-zE0kNjMV7B8pC2ClhrV2gCj/gWLiinRkfPeiUevfjl+Hdke9zcAWVNHLeGV54FJjXQEdwIAjeE7WJdHo7hio7g==} - engines: {node: '>=18.0.0'} - dependencies: - '@aws-sdk/core': 3.744.0 - '@aws-sdk/types': 3.734.0 - '@aws-sdk/util-arn-parser': 3.723.0 - '@smithy/core': 3.29.3 - '@smithy/node-config-provider': 4.5.8 - '@smithy/protocol-http': 5.5.8 - '@smithy/signature-v4': 5.6.4 - '@smithy/smithy-client': 4.14.8 - '@smithy/types': 4.16.1 - '@smithy/util-config-provider': 4.4.8 - '@smithy/util-middleware': 4.4.8 - '@smithy/util-stream': 4.7.8 - '@smithy/util-utf8': 4.4.8 - tslib: 2.8.1 - dev: false + '@esbuild/linux-loong64@0.28.2': + optional: true - /@aws-sdk/middleware-ssec@3.734.0: - resolution: {integrity: sha512-d4yd1RrPW/sspEXizq2NSOUivnheac6LPeLSLnaeTbBG9g1KqIqvCzP1TfXEqv2CrWfHEsWtJpX7oyjySSPvDQ==} - engines: {node: '>=18.0.0'} - dependencies: - '@aws-sdk/types': 3.734.0 - '@smithy/types': 4.16.1 - tslib: 2.8.1 - dev: false + '@esbuild/linux-mips64el@0.25.12': + optional: true - /@aws-sdk/middleware-user-agent@3.744.0: - resolution: {integrity: sha512-ROUbDQHfVWiBHXd4m9E9mKj1Azby8XCs8RC8OCf9GVH339GSE6aMrPJSzMlsV1LmzPdPIypgp5qqh5NfSrKztg==} - engines: {node: '>=18.0.0'} - dependencies: - '@aws-sdk/core': 3.744.0 - '@aws-sdk/types': 3.734.0 - '@aws-sdk/util-endpoints': 3.743.0 - '@smithy/core': 3.29.3 - '@smithy/protocol-http': 5.5.8 - '@smithy/types': 4.16.1 - tslib: 2.8.1 - dev: false + '@esbuild/linux-mips64el@0.27.7': + optional: true - /@aws-sdk/nested-clients@3.744.0: - resolution: {integrity: sha512-Mnrlh4lRY1gZQnKvN2Lh/5WXcGkzC41NM93mtn2uaqOh+DZLCXCttNCfbUesUvYJLOo3lYaOpiDsjTkPVB1yjw==} - engines: {node: '>=18.0.0'} - dependencies: - '@aws-crypto/sha256-browser': 5.2.0 - '@aws-crypto/sha256-js': 5.2.0 - '@aws-sdk/core': 3.744.0 - '@aws-sdk/middleware-host-header': 3.734.0 - '@aws-sdk/middleware-logger': 3.734.0 - '@aws-sdk/middleware-recursion-detection': 3.734.0 - '@aws-sdk/middleware-user-agent': 3.744.0 - '@aws-sdk/region-config-resolver': 3.734.0 - '@aws-sdk/types': 3.734.0 - '@aws-sdk/util-endpoints': 3.743.0 - '@aws-sdk/util-user-agent-browser': 3.734.0 - '@aws-sdk/util-user-agent-node': 3.744.0 - '@smithy/config-resolver': 4.6.8 - '@smithy/core': 3.29.3 - '@smithy/fetch-http-handler': 5.6.5 - '@smithy/hash-node': 4.4.8 - '@smithy/invalid-dependency': 4.4.8 - '@smithy/middleware-content-length': 4.4.8 - '@smithy/middleware-endpoint': 4.6.8 - '@smithy/middleware-retry': 4.7.8 - '@smithy/middleware-serde': 4.4.8 - '@smithy/middleware-stack': 4.4.8 - '@smithy/node-config-provider': 4.5.8 - '@smithy/node-http-handler': 4.9.5 - '@smithy/protocol-http': 5.5.8 - '@smithy/smithy-client': 4.14.8 - '@smithy/types': 4.16.1 - '@smithy/url-parser': 4.4.8 - '@smithy/util-base64': 4.5.8 - '@smithy/util-body-length-browser': 4.4.8 - '@smithy/util-body-length-node': 4.4.8 - '@smithy/util-defaults-mode-browser': 4.5.8 - '@smithy/util-defaults-mode-node': 4.4.8 - '@smithy/util-endpoints': 3.6.8 - '@smithy/util-middleware': 4.4.8 - '@smithy/util-retry': 4.5.8 - '@smithy/util-utf8': 4.4.8 - tslib: 2.8.1 - transitivePeerDependencies: - - aws-crt - dev: false + '@esbuild/linux-mips64el@0.28.2': + optional: true - /@aws-sdk/region-config-resolver@3.734.0: - resolution: {integrity: sha512-Lvj1kPRC5IuJBr9DyJ9T9/plkh+EfKLy+12s/mykOy1JaKHDpvj+XGy2YO6YgYVOb8JFtaqloid+5COtje4JTQ==} - engines: {node: '>=18.0.0'} - dependencies: - '@aws-sdk/types': 3.734.0 - '@smithy/node-config-provider': 4.5.8 - '@smithy/types': 4.16.1 - '@smithy/util-config-provider': 4.4.8 - '@smithy/util-middleware': 4.4.8 - tslib: 2.8.1 - dev: false + '@esbuild/linux-ppc64@0.25.12': + optional: true - /@aws-sdk/s3-request-presigner@3.744.0: - resolution: {integrity: sha512-RDMiGOr9HOb+JE5yaidNObY5hG/ZXZRYOhphvOekW5nCiIof03BIArQwF7w1eYbDErJinLpLU+SbUx3Ln/9KIw==} - engines: {node: '>=18.0.0'} - dependencies: - '@aws-sdk/signature-v4-multi-region': 3.744.0 - '@aws-sdk/types': 3.734.0 - '@aws-sdk/util-format-url': 3.734.0 - '@smithy/middleware-endpoint': 4.6.8 - '@smithy/protocol-http': 5.5.8 - '@smithy/smithy-client': 4.14.8 - '@smithy/types': 4.16.1 - tslib: 2.8.1 - dev: false + '@esbuild/linux-ppc64@0.27.7': + optional: true - /@aws-sdk/signature-v4-multi-region@3.744.0: - resolution: {integrity: sha512-QyrAevGGwceM+knGfV5r2NvSAjI94PETu6u+Fxalf8F/ybpK7qn1va0w3cGDU68oRqC0JHfo53JXjm9yQokj9Q==} - engines: {node: '>=18.0.0'} - dependencies: - '@aws-sdk/middleware-sdk-s3': 3.744.0 - '@aws-sdk/types': 3.734.0 - '@smithy/protocol-http': 5.5.8 - '@smithy/signature-v4': 5.6.4 - '@smithy/types': 4.16.1 - tslib: 2.8.1 - dev: false + '@esbuild/linux-ppc64@0.28.2': + optional: true - /@aws-sdk/token-providers@3.744.0: - resolution: {integrity: sha512-v/1+lWkDCd60Ei6oyhJqli6mTsPEVepLoSMB50vHUVlJP0fzXu/3FMje90/RzeUoh/VugZQJCEv/NNpuC6wztg==} - engines: {node: '>=18.0.0'} - dependencies: - '@aws-sdk/nested-clients': 3.744.0 - '@aws-sdk/types': 3.734.0 - '@smithy/property-provider': 4.4.8 - '@smithy/shared-ini-file-loader': 4.6.8 - '@smithy/types': 4.16.1 - tslib: 2.8.1 - transitivePeerDependencies: - - aws-crt - dev: false + '@esbuild/linux-riscv64@0.25.12': + optional: true - /@aws-sdk/types@3.734.0: - resolution: {integrity: sha512-o11tSPTT70nAkGV1fN9wm/hAIiLPyWX6SuGf+9JyTp7S/rC2cFWhR26MvA69nplcjNaXVzB0f+QFrLXXjOqCrg==} - engines: {node: '>=18.0.0'} - dependencies: - '@smithy/types': 4.16.1 - tslib: 2.8.1 - dev: false + '@esbuild/linux-riscv64@0.27.7': + optional: true - /@aws-sdk/util-arn-parser@3.723.0: - resolution: {integrity: sha512-ZhEfvUwNliOQROcAk34WJWVYTlTa4694kSVhDSjW6lE1bMataPnIN8A0ycukEzBXmd8ZSoBcQLn6lKGl7XIJ5w==} - engines: {node: '>=18.0.0'} - dependencies: - tslib: 2.8.1 - dev: false + '@esbuild/linux-riscv64@0.28.2': + optional: true - /@aws-sdk/util-endpoints@3.743.0: - resolution: {integrity: sha512-sN1l559zrixeh5x+pttrnd0A3+r34r0tmPkJ/eaaMaAzXqsmKU/xYre9K3FNnsSS1J1k4PEfk/nHDTVUgFYjnw==} - engines: {node: '>=18.0.0'} - dependencies: - '@aws-sdk/types': 3.734.0 - '@smithy/types': 4.16.1 - '@smithy/util-endpoints': 3.6.8 - tslib: 2.8.1 - dev: false + '@esbuild/linux-s390x@0.25.12': + optional: true - /@aws-sdk/util-format-url@3.734.0: - resolution: {integrity: sha512-TxZMVm8V4aR/QkW9/NhujvYpPZjUYqzLwSge5imKZbWFR806NP7RMwc5ilVuHF/bMOln/cVHkl42kATElWBvNw==} - engines: {node: '>=18.0.0'} - dependencies: - '@aws-sdk/types': 3.734.0 - '@smithy/querystring-builder': 4.4.8 - '@smithy/types': 4.16.1 - tslib: 2.8.1 - dev: false + '@esbuild/linux-s390x@0.27.7': + optional: true - /@aws-sdk/util-locate-window@3.965.8: - resolution: {integrity: sha512-uUbMs1cBZPafD0ohUj6EwNf0fPZ534NvBxHox4hjX+0Rxq5paSYUem7+hi833pYrzrcnBATKIYpR02MDXT5M9g==} - engines: {node: '>=20.0.0'} - dependencies: - tslib: 2.8.1 - dev: false + '@esbuild/linux-s390x@0.28.2': + optional: true - /@aws-sdk/util-user-agent-browser@3.734.0: - resolution: {integrity: sha512-xQTCus6Q9LwUuALW+S76OL0jcWtMOVu14q+GoLnWPUM7QeUw963oQcLhF7oq0CtaLLKyl4GOUfcwc773Zmwwng==} - dependencies: - '@aws-sdk/types': 3.734.0 - '@smithy/types': 4.16.1 - bowser: 2.14.1 - tslib: 2.8.1 - dev: false + '@esbuild/linux-x64@0.25.12': + optional: true - /@aws-sdk/util-user-agent-node@3.744.0: - resolution: {integrity: sha512-BJURjwIXhNa4heXkLC0+GcL+8wVXaU7JoyW6ckdvp93LL+sVHeR1d5FxXZHQW/pMI4E3gNlKyBqjKaT75tObNQ==} - engines: {node: '>=18.0.0'} - peerDependencies: - aws-crt: '>=1.0.0' - peerDependenciesMeta: - aws-crt: - optional: true - dependencies: - '@aws-sdk/middleware-user-agent': 3.744.0 - '@aws-sdk/types': 3.734.0 - '@smithy/node-config-provider': 4.5.8 - '@smithy/types': 4.16.1 - tslib: 2.8.1 - dev: false + '@esbuild/linux-x64@0.27.7': + optional: true - /@aws-sdk/xml-builder@3.734.0: - resolution: {integrity: sha512-Zrjxi5qwGEcUsJ0ru7fRtW74WcTS0rbLcehoFB+rN1GRi2hbLcFaYs4PwVA5diLeAJH0gszv3x4Hr/S87MfbKQ==} - engines: {node: '>=18.0.0'} - dependencies: - '@smithy/types': 4.16.1 - tslib: 2.8.1 - dev: false + '@esbuild/linux-x64@0.28.2': + optional: true - /@babel/runtime-corejs3@7.29.7: - resolution: {integrity: sha512-ppj9ouYku+RX0ljtgZd+KMO5mkM2bCqg8H2PYAFWnLsHEIKIdRojqbJ2i3eVHrisuxy7nOFCmngTDdWtUCdXUQ==} - engines: {node: '>=6.9.0'} - dependencies: - core-js-pure: 3.49.0 - dev: true + '@esbuild/netbsd-arm64@0.25.12': + optional: true - /@babel/runtime@7.29.7: - resolution: {integrity: sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==} - engines: {node: '>=6.9.0'} - dev: false + '@esbuild/netbsd-arm64@0.27.7': + optional: true - /@better-auth/core@1.7.6(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0)(jose@6.2.3)(kysely@0.29.6)(nanostores@1.4.0): - resolution: {integrity: sha512-yBDDO0J4VCHT1qEZtzj6aMexX4etyLesitoxehcWHzPrzYqrFHwe/hgskye+imlGhQVOysuljMg8M8BA6GrtIg==} - peerDependencies: - '@better-auth/utils': 0.4.2 - '@better-fetch/fetch': 1.3.2 - '@opentelemetry/api': ^1.9.0 - better-call: 1.4.0 - jose: ^6.1.0 - kysely: ^0.28.5 || ^0.29.0 - nanostores: ^1.0.1 - peerDependenciesMeta: - '@opentelemetry/api': - optional: true - dependencies: - '@better-auth/utils': 0.4.2 - '@better-fetch/fetch': 1.3.2 - '@opentelemetry/semantic-conventions': 1.43.0 - '@standard-schema/spec': 1.1.0 - better-call: 1.4.0(zod@3.25.67) - jose: 6.2.3 - kysely: 0.29.6 - nanostores: 1.4.0 - zod: 4.6.5 - dev: false + '@esbuild/netbsd-arm64@0.28.2': + optional: true - /@better-auth/drizzle-adapter@1.7.6(@better-auth/core@1.7.6)(@better-auth/utils@0.4.2): - resolution: {integrity: sha512-ENlhwC7kkTjquuiel3Efggik0hC4vtD7ppJ8FhsiHhRJA8K6RT4hbhzkfm6keNvjdnAeWwCejm7FmMO4GoSGpA==} - peerDependencies: - '@better-auth/core': ^1.7.6 - '@better-auth/utils': 0.4.2 - drizzle-orm: ^0.45.2 || >=1.0.0-rc.1 <2.0.0 - peerDependenciesMeta: - drizzle-orm: - optional: true - dependencies: - '@better-auth/core': 1.7.6(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0)(jose@6.2.3)(kysely@0.29.6)(nanostores@1.4.0) - '@better-auth/utils': 0.4.2 - dev: false + '@esbuild/netbsd-x64@0.25.12': + optional: true - /@better-auth/kysely-adapter@1.7.6(@better-auth/core@1.7.6)(@better-auth/utils@0.4.2)(kysely@0.29.6): - resolution: {integrity: sha512-BV+DX2/z/6ozNC9DYSge78wjLerq6Bxd/lSPjzzuq9eEutkQDAJTuiaETzgGYqNV5LlEWi8TZFAQTEq/wavOEQ==} - peerDependencies: - '@better-auth/core': ^1.7.6 - '@better-auth/utils': 0.4.2 - kysely: ^0.28.17 || ^0.29.0 - peerDependenciesMeta: - kysely: - optional: true - dependencies: - '@better-auth/core': 1.7.6(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0)(jose@6.2.3)(kysely@0.29.6)(nanostores@1.4.0) - '@better-auth/utils': 0.4.2 - kysely: 0.29.6 - dev: false + '@esbuild/netbsd-x64@0.27.7': + optional: true - /@better-auth/memory-adapter@1.7.6(@better-auth/core@1.7.6)(@better-auth/utils@0.4.2): - resolution: {integrity: sha512-ng1xv8k2JsEIjnqzJzdoVOQrnoCLRuk4EiQL9yYAThyg6zYzV00LynlhH+O9OMUZ+yGVpGqGZmr5xcTiUSV2uA==} - peerDependencies: - '@better-auth/core': ^1.7.6 - '@better-auth/utils': 0.4.2 - dependencies: - '@better-auth/core': 1.7.6(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0)(jose@6.2.3)(kysely@0.29.6)(nanostores@1.4.0) - '@better-auth/utils': 0.4.2 - dev: false + '@esbuild/netbsd-x64@0.28.2': + optional: true - /@better-auth/mongo-adapter@1.7.6(@better-auth/core@1.7.6)(@better-auth/utils@0.4.2): - resolution: {integrity: sha512-GvBwZli8i4XINMAj9tlW7eV9E8Dr+JWqavXjUs2o81GZt/Vh8wiX+31KK1jQ4iOuejfjpLoXcoFtlIPgf/pVog==} - peerDependencies: - '@better-auth/core': ^1.7.6 - '@better-auth/utils': 0.4.2 - mongodb: ^6.0.0 || ^7.0.0 - peerDependenciesMeta: - mongodb: - optional: true - dependencies: - '@better-auth/core': 1.7.6(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0)(jose@6.2.3)(kysely@0.29.6)(nanostores@1.4.0) - '@better-auth/utils': 0.4.2 - dev: false + '@esbuild/openbsd-arm64@0.25.12': + optional: true - /@better-auth/prisma-adapter@1.7.6(@better-auth/core@1.7.6)(@better-auth/utils@0.4.2): - resolution: {integrity: sha512-31rz2OXIx2Q1L4Jhd5F71dafIWqder/Bo6vJ+eCgO5iZ0gvnv7fUmM95DvbVUoPC69XYpcIM/6PJmQ3M6RydWg==} - peerDependencies: - '@better-auth/core': ^1.7.6 - '@better-auth/utils': 0.4.2 - '@prisma/client': ^5.0.0 || ^6.0.0 || ^7.0.0 - prisma: ^5.0.0 || ^6.0.0 || ^7.0.0 - peerDependenciesMeta: - '@prisma/client': - optional: true - prisma: - optional: true - dependencies: - '@better-auth/core': 1.7.6(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0)(jose@6.2.3)(kysely@0.29.6)(nanostores@1.4.0) - '@better-auth/utils': 0.4.2 - dev: false + '@esbuild/openbsd-arm64@0.27.7': + optional: true - /@better-auth/telemetry@1.7.6(@better-auth/core@1.7.6)(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2): - resolution: {integrity: sha512-xgRwPja2wTJtcu+OQZR2IiNpAmviddnW3n5Do5umXRugJFW3v9KlSmYjYm580mVsPnU4upvZkvSRl9v8DgSDtA==} - peerDependencies: - '@better-auth/core': ^1.7.6 - '@better-auth/utils': 0.4.2 - '@better-fetch/fetch': 1.3.2 - dependencies: - '@better-auth/core': 1.7.6(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0)(jose@6.2.3)(kysely@0.29.6)(nanostores@1.4.0) - '@better-auth/utils': 0.4.2 - '@better-fetch/fetch': 1.3.2 - dev: false + '@esbuild/openbsd-arm64@0.28.2': + optional: true - /@better-auth/utils@0.4.2: - resolution: {integrity: sha512-AUxrvu+HaaODsUyzDxFgwd/8RZ1yZaYo42LXKSrU2oGgR38pS1ij8nqQKNgtTWoYGpNevNXtCfgTy6loHveW9A==} - dependencies: - '@noble/hashes': 2.2.0 - dev: false + '@esbuild/openbsd-x64@0.25.12': + optional: true - /@better-auth/utils@0.5.0: - resolution: {integrity: sha512-BL8W4EfIZFwlu0r54m3v1ztjDhu6dDe/amLTm0xybmbZaNgYUqhD3SjpAsnq0q8YD6/ki4iwIgxJNLP/N3TxiA==} - dependencies: - '@noble/hashes': 2.2.0 - dev: false + '@esbuild/openbsd-x64@0.27.7': + optional: true - /@better-fetch/fetch@1.3.2: - resolution: {integrity: sha512-Gs7n99b5tqUC6cQAPbV0uED3IraHB6xQbHLQ/C3l7ZFafHScOx9pQ+DYmP5blbLFShVWLqxNUlI9wi4xU/X+ow==} - dev: false + '@esbuild/openbsd-x64@0.28.2': + optional: true - /@cspotcode/source-map-support@0.8.1: - resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} - engines: {node: '>=12'} - dependencies: - '@jridgewell/trace-mapping': 0.3.9 - dev: true + '@esbuild/openharmony-arm64@0.25.12': + optional: true - /@esbuild/aix-ppc64@0.27.7: - resolution: {integrity: sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [aix] - requiresBuild: true - dev: true + '@esbuild/openharmony-arm64@0.27.7': optional: true - /@esbuild/aix-ppc64@0.28.1: - resolution: {integrity: sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [aix] - requiresBuild: true + '@esbuild/openharmony-arm64@0.28.2': optional: true - /@esbuild/android-arm64@0.27.7: - resolution: {integrity: sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==} - engines: {node: '>=18'} - cpu: [arm64] - os: [android] - requiresBuild: true - dev: true + '@esbuild/sunos-x64@0.25.12': optional: true - /@esbuild/android-arm64@0.28.1: - resolution: {integrity: sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [android] - requiresBuild: true + '@esbuild/sunos-x64@0.27.7': optional: true - /@esbuild/android-arm@0.27.7: - resolution: {integrity: sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==} - engines: {node: '>=18'} - cpu: [arm] - os: [android] - requiresBuild: true - dev: true + '@esbuild/sunos-x64@0.28.2': optional: true - /@esbuild/android-arm@0.28.1: - resolution: {integrity: sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ==} - engines: {node: '>=18'} - cpu: [arm] - os: [android] - requiresBuild: true + '@esbuild/win32-arm64@0.25.12': optional: true - /@esbuild/android-x64@0.27.7: - resolution: {integrity: sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==} - engines: {node: '>=18'} - cpu: [x64] - os: [android] - requiresBuild: true - dev: true + '@esbuild/win32-arm64@0.27.7': optional: true - /@esbuild/android-x64@0.28.1: - resolution: {integrity: sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng==} - engines: {node: '>=18'} - cpu: [x64] - os: [android] - requiresBuild: true + '@esbuild/win32-arm64@0.28.2': optional: true - /@esbuild/darwin-arm64@0.27.7: - resolution: {integrity: sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==} - engines: {node: '>=18'} - cpu: [arm64] - os: [darwin] - requiresBuild: true - dev: true + '@esbuild/win32-ia32@0.25.12': optional: true - /@esbuild/darwin-arm64@0.28.1: - resolution: {integrity: sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q==} - engines: {node: '>=18'} - cpu: [arm64] - os: [darwin] - requiresBuild: true + '@esbuild/win32-ia32@0.27.7': optional: true - /@esbuild/darwin-x64@0.27.7: - resolution: {integrity: sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==} - engines: {node: '>=18'} - cpu: [x64] - os: [darwin] - requiresBuild: true - dev: true + '@esbuild/win32-ia32@0.28.2': optional: true - /@esbuild/darwin-x64@0.28.1: - resolution: {integrity: sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ==} - engines: {node: '>=18'} - cpu: [x64] - os: [darwin] - requiresBuild: true + '@esbuild/win32-x64@0.25.12': optional: true - /@esbuild/freebsd-arm64@0.27.7: - resolution: {integrity: sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==} - engines: {node: '>=18'} - cpu: [arm64] - os: [freebsd] - requiresBuild: true - dev: true + '@esbuild/win32-x64@0.27.7': optional: true - /@esbuild/freebsd-arm64@0.28.1: - resolution: {integrity: sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw==} - engines: {node: '>=18'} - cpu: [arm64] - os: [freebsd] - requiresBuild: true + '@esbuild/win32-x64@0.28.2': optional: true - /@esbuild/freebsd-x64@0.27.7: - resolution: {integrity: sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==} - engines: {node: '>=18'} - cpu: [x64] - os: [freebsd] - requiresBuild: true - dev: true - optional: true + '@eslint-community/eslint-utils@4.10.1(eslint@10.13.0(jiti@2.7.0)(supports-color@10.2.2))': + dependencies: + eslint: 10.13.0(jiti@2.7.0)(supports-color@10.2.2) + eslint-visitor-keys: 3.4.3 + + '@eslint-community/regexpp@4.12.2': {} + + '@eslint/config-array@0.23.5(supports-color@10.2.2)': + dependencies: + '@eslint/object-schema': 3.0.5 + debug: 4.4.3(supports-color@10.2.2) + minimatch: 10.2.6 + transitivePeerDependencies: + - supports-color + + '@eslint/config-helpers@0.7.0': + dependencies: + '@eslint/core': 1.2.1 + + '@eslint/core@1.2.1': + dependencies: + '@types/json-schema': 7.0.15 + + '@eslint/object-schema@3.0.5': {} + + '@eslint/plugin-kit@0.7.3': + dependencies: + '@eslint/core': 1.2.1 + levn: 0.4.1 + + '@floating-ui/core@1.8.0': + dependencies: + '@floating-ui/utils': 0.2.12 + + '@floating-ui/dom@1.8.0': + dependencies: + '@floating-ui/core': 1.8.0 + '@floating-ui/utils': 0.2.12 + + '@floating-ui/react-dom@2.1.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@floating-ui/dom': 1.8.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + + '@floating-ui/react-dom@2.1.9(react-dom@19.3.1(react@19.3.1))(react@19.3.1)': + dependencies: + '@floating-ui/dom': 1.8.0 + react: 19.3.1 + react-dom: 19.3.1(react@19.3.1) + + '@floating-ui/utils@0.2.12': {} + + '@fuma-translate/react@1.0.2(@types/react@19.3.0)(react-dom@19.3.1(react@19.3.1))(react@19.3.1)': + dependencies: + react: 19.3.1 + react-dom: 19.3.1(react@19.3.1) + optionalDependencies: + '@types/react': 19.3.0 + + '@fumadocs/base-ui@16.17.7(@types/mdx@2.0.14)(@types/react@19.3.0)(fumadocs-core@16.17.7(@mdx-js/mdx@3.1.1(supports-color@10.2.2))(@types/estree-jsx@1.0.5)(@types/hast@3.0.5)(@types/mdast@4.0.4)(@types/react@19.3.0)(lucide-react@1.61.0(@types/react@19.3.0)(react@19.3.1))(next@16.4.2(@playwright/test@1.64.1)(@types/node@26.6.5)(react-dom@19.3.1(react@19.3.1))(react@19.3.1))(react-dom@19.3.1(react@19.3.1))(react@19.3.1)(supports-color@10.2.2)(zod@4.6.7))(next@16.4.2(@playwright/test@1.64.1)(@types/node@26.6.5)(react-dom@19.3.1(react@19.3.1))(react@19.3.1))(react-dom@19.3.1(react@19.3.1))(react@19.3.1)(supports-color@10.2.2)(tailwindcss@4.3.3)': + dependencies: + '@base-ui/react': 1.9.0(@types/react@19.3.0)(react-dom@19.3.1(react@19.3.1))(react@19.3.1) + '@fuma-translate/react': 1.0.2(@types/react@19.3.0)(react-dom@19.3.1(react@19.3.1))(react@19.3.1) + '@fumadocs/tailwind': 0.1.4(tailwindcss@4.3.3) + class-variance-authority: 0.7.1 + cn: 0.4.0 + fumadocs-core: 16.17.7(@mdx-js/mdx@3.1.1(supports-color@10.2.2))(@types/estree-jsx@1.0.5)(@types/hast@3.0.5)(@types/mdast@4.0.4)(@types/react@19.3.0)(lucide-react@1.61.0(@types/react@19.3.0)(react@19.3.1))(next@16.4.2(@playwright/test@1.64.1)(@types/node@26.6.5)(react-dom@19.3.1(react@19.3.1))(react@19.3.1))(react-dom@19.3.1(react@19.3.1))(react@19.3.1)(supports-color@10.2.2)(zod@4.6.7) + hast-util-to-jsx-runtime: 2.3.6(supports-color@10.2.2) + lucide-react: 1.61.0(@types/react@19.3.0)(react@19.3.1) + motion: 14.6.0(react-dom@19.3.1(react@19.3.1))(react@19.3.1) + next-themes: 0.4.6(react-dom@19.3.1(react@19.3.1))(react@19.3.1) + react: 19.3.1 + react-dom: 19.3.1(react@19.3.1) + react-remove-scroll: 2.7.2(@types/react@19.3.0)(react@19.3.1) + scroll-into-view-if-needed: 3.1.0 + shiki: 4.5.0 + optionalDependencies: + '@types/mdx': 2.0.14 + '@types/react': 19.3.0 + next: 16.4.2(@playwright/test@1.64.1)(@types/node@26.6.5)(react-dom@19.3.1(react@19.3.1))(react@19.3.1) + transitivePeerDependencies: + - '@date-fns/tz' + - date-fns + - supports-color + - tailwindcss + + '@fumadocs/tailwind@0.1.4(tailwindcss@4.3.3)': + optionalDependencies: + tailwindcss: 4.3.3 - /@esbuild/freebsd-x64@0.28.1: - resolution: {integrity: sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ==} - engines: {node: '>=18'} - cpu: [x64] - os: [freebsd] - requiresBuild: true - optional: true + '@fumari/image-size@0.1.1': {} - /@esbuild/linux-arm64@0.27.7: - resolution: {integrity: sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==} - engines: {node: '>=18'} - cpu: [arm64] - os: [linux] - requiresBuild: true - dev: true - optional: true + '@hookform/resolvers@3.10.0(react-hook-form@7.52.1(react@18.3.1))': + dependencies: + react-hook-form: 7.52.1(react@18.3.1) - /@esbuild/linux-arm64@0.28.1: - resolution: {integrity: sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g==} - engines: {node: '>=18'} - cpu: [arm64] - os: [linux] - requiresBuild: true - optional: true + '@humanfs/core@0.19.2': + dependencies: + '@humanfs/types': 0.15.0 - /@esbuild/linux-arm@0.27.7: - resolution: {integrity: sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==} - engines: {node: '>=18'} - cpu: [arm] - os: [linux] - requiresBuild: true - dev: true - optional: true + '@humanfs/node@0.16.8': + dependencies: + '@humanfs/core': 0.19.2 + '@humanfs/types': 0.15.0 + '@humanwhocodes/retry': 0.4.3 - /@esbuild/linux-arm@0.28.1: - resolution: {integrity: sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ==} - engines: {node: '>=18'} - cpu: [arm] - os: [linux] - requiresBuild: true - optional: true + '@humanfs/types@0.15.0': {} - /@esbuild/linux-ia32@0.27.7: - resolution: {integrity: sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==} - engines: {node: '>=18'} - cpu: [ia32] - os: [linux] - requiresBuild: true - dev: true - optional: true + '@humanwhocodes/module-importer@1.0.1': {} - /@esbuild/linux-ia32@0.28.1: - resolution: {integrity: sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w==} - engines: {node: '>=18'} - cpu: [ia32] - os: [linux] - requiresBuild: true - optional: true + '@humanwhocodes/retry@0.4.3': {} - /@esbuild/linux-loong64@0.27.7: - resolution: {integrity: sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==} - engines: {node: '>=18'} - cpu: [loong64] - os: [linux] - requiresBuild: true - dev: true - optional: true + '@img/colour@1.1.0': {} - /@esbuild/linux-loong64@0.28.1: - resolution: {integrity: sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg==} - engines: {node: '>=18'} - cpu: [loong64] - os: [linux] - requiresBuild: true + '@img/sharp-darwin-arm64@0.35.5': + optionalDependencies: + '@img/sharp-libvips-darwin-arm64': 1.3.4 optional: true - /@esbuild/linux-mips64el@0.27.7: - resolution: {integrity: sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==} - engines: {node: '>=18'} - cpu: [mips64el] - os: [linux] - requiresBuild: true - dev: true + '@img/sharp-darwin-x64@0.35.5': + optionalDependencies: + '@img/sharp-libvips-darwin-x64': 1.3.4 optional: true - /@esbuild/linux-mips64el@0.28.1: - resolution: {integrity: sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ==} - engines: {node: '>=18'} - cpu: [mips64el] - os: [linux] - requiresBuild: true + '@img/sharp-freebsd-wasm32@0.35.5': + dependencies: + '@img/sharp-wasm32': 0.35.5 optional: true - /@esbuild/linux-ppc64@0.27.7: - resolution: {integrity: sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [linux] - requiresBuild: true - dev: true + '@img/sharp-libvips-darwin-arm64@1.3.4': optional: true - /@esbuild/linux-ppc64@0.28.1: - resolution: {integrity: sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [linux] - requiresBuild: true + '@img/sharp-libvips-darwin-x64@1.3.4': optional: true - /@esbuild/linux-riscv64@0.27.7: - resolution: {integrity: sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==} - engines: {node: '>=18'} - cpu: [riscv64] - os: [linux] - requiresBuild: true - dev: true + '@img/sharp-libvips-linux-arm64@1.3.4': optional: true - /@esbuild/linux-riscv64@0.28.1: - resolution: {integrity: sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ==} - engines: {node: '>=18'} - cpu: [riscv64] - os: [linux] - requiresBuild: true + '@img/sharp-libvips-linux-arm@1.3.4': optional: true - /@esbuild/linux-s390x@0.27.7: - resolution: {integrity: sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==} - engines: {node: '>=18'} - cpu: [s390x] - os: [linux] - requiresBuild: true - dev: true + '@img/sharp-libvips-linux-ppc64@1.3.4': optional: true - /@esbuild/linux-s390x@0.28.1: - resolution: {integrity: sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag==} - engines: {node: '>=18'} - cpu: [s390x] - os: [linux] - requiresBuild: true + '@img/sharp-libvips-linux-riscv64@1.3.4': optional: true - /@esbuild/linux-x64@0.27.7: - resolution: {integrity: sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==} - engines: {node: '>=18'} - cpu: [x64] - os: [linux] - requiresBuild: true - dev: true + '@img/sharp-libvips-linux-s390x@1.3.4': optional: true - /@esbuild/linux-x64@0.28.1: - resolution: {integrity: sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA==} - engines: {node: '>=18'} - cpu: [x64] - os: [linux] - requiresBuild: true + '@img/sharp-libvips-linux-x64@1.3.4': optional: true - /@esbuild/netbsd-arm64@0.27.7: - resolution: {integrity: sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==} - engines: {node: '>=18'} - cpu: [arm64] - os: [netbsd] - requiresBuild: true - dev: true + '@img/sharp-libvips-linuxmusl-arm64@1.3.4': optional: true - /@esbuild/netbsd-arm64@0.28.1: - resolution: {integrity: sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw==} - engines: {node: '>=18'} - cpu: [arm64] - os: [netbsd] - requiresBuild: true + '@img/sharp-libvips-linuxmusl-x64@1.3.4': optional: true - /@esbuild/netbsd-x64@0.27.7: - resolution: {integrity: sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==} - engines: {node: '>=18'} - cpu: [x64] - os: [netbsd] - requiresBuild: true - dev: true + '@img/sharp-linux-arm64@0.35.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm64': 1.3.4 optional: true - /@esbuild/netbsd-x64@0.28.1: - resolution: {integrity: sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg==} - engines: {node: '>=18'} - cpu: [x64] - os: [netbsd] - requiresBuild: true + '@img/sharp-linux-arm@0.35.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm': 1.3.4 optional: true - /@esbuild/openbsd-arm64@0.27.7: - resolution: {integrity: sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==} - engines: {node: '>=18'} - cpu: [arm64] - os: [openbsd] - requiresBuild: true - dev: true + '@img/sharp-linux-ppc64@0.35.5': + optionalDependencies: + '@img/sharp-libvips-linux-ppc64': 1.3.4 optional: true - /@esbuild/openbsd-arm64@0.28.1: - resolution: {integrity: sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q==} - engines: {node: '>=18'} - cpu: [arm64] - os: [openbsd] - requiresBuild: true + '@img/sharp-linux-riscv64@0.35.5': + optionalDependencies: + '@img/sharp-libvips-linux-riscv64': 1.3.4 optional: true - /@esbuild/openbsd-x64@0.27.7: - resolution: {integrity: sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==} - engines: {node: '>=18'} - cpu: [x64] - os: [openbsd] - requiresBuild: true - dev: true + '@img/sharp-linux-s390x@0.35.5': + optionalDependencies: + '@img/sharp-libvips-linux-s390x': 1.3.4 optional: true - /@esbuild/openbsd-x64@0.28.1: - resolution: {integrity: sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw==} - engines: {node: '>=18'} - cpu: [x64] - os: [openbsd] - requiresBuild: true + '@img/sharp-linux-x64@0.35.5': + optionalDependencies: + '@img/sharp-libvips-linux-x64': 1.3.4 optional: true - /@esbuild/openharmony-arm64@0.27.7: - resolution: {integrity: sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==} - engines: {node: '>=18'} - cpu: [arm64] - os: [openharmony] - requiresBuild: true - dev: true + '@img/sharp-linuxmusl-arm64@0.35.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-arm64': 1.3.4 optional: true - /@esbuild/openharmony-arm64@0.28.1: - resolution: {integrity: sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [openharmony] - requiresBuild: true + '@img/sharp-linuxmusl-x64@0.35.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-x64': 1.3.4 optional: true - /@esbuild/sunos-x64@0.27.7: - resolution: {integrity: sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==} - engines: {node: '>=18'} - cpu: [x64] - os: [sunos] - requiresBuild: true - dev: true + '@img/sharp-wasm32@0.35.5': + dependencies: + '@emnapi/runtime': 1.11.3 optional: true - /@esbuild/sunos-x64@0.28.1: - resolution: {integrity: sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ==} - engines: {node: '>=18'} - cpu: [x64] - os: [sunos] - requiresBuild: true + '@img/sharp-webcontainers-wasm32@0.35.5': + dependencies: + '@img/sharp-wasm32': 0.35.5 optional: true - /@esbuild/win32-arm64@0.27.7: - resolution: {integrity: sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==} - engines: {node: '>=18'} - cpu: [arm64] - os: [win32] - requiresBuild: true - dev: true + '@img/sharp-win32-arm64@0.35.5': optional: true - /@esbuild/win32-arm64@0.28.1: - resolution: {integrity: sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA==} - engines: {node: '>=18'} - cpu: [arm64] - os: [win32] - requiresBuild: true + '@img/sharp-win32-ia32@0.35.5': optional: true - /@esbuild/win32-ia32@0.27.7: - resolution: {integrity: sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==} - engines: {node: '>=18'} - cpu: [ia32] - os: [win32] - requiresBuild: true - dev: true + '@img/sharp-win32-x64@0.35.5': optional: true - /@esbuild/win32-ia32@0.28.1: - resolution: {integrity: sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg==} - engines: {node: '>=18'} - cpu: [ia32] - os: [win32] - requiresBuild: true - optional: true + '@inquirer/ansi@1.0.2': {} - /@esbuild/win32-x64@0.27.7: - resolution: {integrity: sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==} - engines: {node: '>=18'} - cpu: [x64] - os: [win32] - requiresBuild: true - dev: true - optional: true + '@inquirer/checkbox@4.3.2(@types/node@20.14.11)': + dependencies: + '@inquirer/ansi': 1.0.2 + '@inquirer/core': 10.3.2(@types/node@20.14.11) + '@inquirer/figures': 1.0.15 + '@inquirer/type': 3.0.10(@types/node@20.14.11) + yoctocolors-cjs: 2.1.3 + optionalDependencies: + '@types/node': 20.14.11 - /@esbuild/win32-x64@0.28.1: - resolution: {integrity: sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A==} - engines: {node: '>=18'} - cpu: [x64] - os: [win32] - requiresBuild: true - optional: true + '@inquirer/confirm@5.1.21(@types/node@20.14.11)': + dependencies: + '@inquirer/core': 10.3.2(@types/node@20.14.11) + '@inquirer/type': 3.0.10(@types/node@20.14.11) + optionalDependencies: + '@types/node': 20.14.11 - /@eslint-community/eslint-utils@4.9.1(eslint@9.7.0): - resolution: {integrity: sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + '@inquirer/core@10.3.2(@types/node@20.14.11)': dependencies: - eslint: 9.7.0 - eslint-visitor-keys: 3.4.3 - dev: true + '@inquirer/ansi': 1.0.2 + '@inquirer/figures': 1.0.15 + '@inquirer/type': 3.0.10(@types/node@20.14.11) + cli-width: 4.1.0 + mute-stream: 2.0.0 + signal-exit: 4.1.0 + wrap-ansi: 6.2.0 + yoctocolors-cjs: 2.1.3 + optionalDependencies: + '@types/node': 20.14.11 - /@eslint-community/regexpp@4.12.2: - resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==} - engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - dev: true + '@inquirer/editor@4.2.23(@types/node@20.14.11)': + dependencies: + '@inquirer/core': 10.3.2(@types/node@20.14.11) + '@inquirer/external-editor': 1.0.3(@types/node@20.14.11) + '@inquirer/type': 3.0.10(@types/node@20.14.11) + optionalDependencies: + '@types/node': 20.14.11 - /@eslint/config-array@0.17.1: - resolution: {integrity: sha512-BlYOpej8AQ8Ev9xVqroV7a02JK3SkBAaN9GfMMH9W6Ch8FlQlkjGw4Ir7+FgYwfirivAf4t+GtzuAxqfukmISA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@inquirer/expand@4.0.23(@types/node@20.14.11)': dependencies: - '@eslint/object-schema': 2.1.7 - debug: 4.4.3 - minimatch: 3.1.5 - transitivePeerDependencies: - - supports-color - dev: true + '@inquirer/core': 10.3.2(@types/node@20.14.11) + '@inquirer/type': 3.0.10(@types/node@20.14.11) + yoctocolors-cjs: 2.1.3 + optionalDependencies: + '@types/node': 20.14.11 - /@eslint/eslintrc@3.3.5: - resolution: {integrity: sha512-4IlJx0X0qftVsN5E+/vGujTRIFtwuLbNsVUe7TO6zYPDR1O6nFwvwhIKEKSrl6dZchmYBITazxKoUYOjdtjlRg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@inquirer/external-editor@1.0.3(@types/node@20.14.11)': dependencies: - ajv: 6.15.0 - debug: 4.4.3 - espree: 10.4.0 - globals: 14.0.0 - ignore: 5.3.2 - import-fresh: 3.3.1 - js-yaml: 4.3.0 - minimatch: 3.1.5 - strip-json-comments: 3.1.1 - transitivePeerDependencies: - - supports-color - dev: true + chardet: 2.2.0 + iconv-lite: 0.7.3 + optionalDependencies: + '@types/node': 20.14.11 - /@eslint/js@9.7.0: - resolution: {integrity: sha512-ChuWDQenef8OSFnvuxv0TCVxEwmu3+hPNKvM9B34qpM0rDRbjL8t5QkQeHHeAfsKQjuH9wS82WeCi1J/owatng==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - dev: true + '@inquirer/figures@1.0.15': {} - /@eslint/object-schema@2.1.7: - resolution: {integrity: sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - dev: true + '@inquirer/input@4.3.1(@types/node@20.14.11)': + dependencies: + '@inquirer/core': 10.3.2(@types/node@20.14.11) + '@inquirer/type': 3.0.10(@types/node@20.14.11) + optionalDependencies: + '@types/node': 20.14.11 - /@floating-ui/core@1.7.5: - resolution: {integrity: sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ==} + '@inquirer/number@3.0.23(@types/node@20.14.11)': dependencies: - '@floating-ui/utils': 0.2.11 - dev: false + '@inquirer/core': 10.3.2(@types/node@20.14.11) + '@inquirer/type': 3.0.10(@types/node@20.14.11) + optionalDependencies: + '@types/node': 20.14.11 - /@floating-ui/dom@1.7.6: - resolution: {integrity: sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ==} + '@inquirer/password@4.0.23(@types/node@20.14.11)': dependencies: - '@floating-ui/core': 1.7.5 - '@floating-ui/utils': 0.2.11 - dev: false + '@inquirer/ansi': 1.0.2 + '@inquirer/core': 10.3.2(@types/node@20.14.11) + '@inquirer/type': 3.0.10(@types/node@20.14.11) + optionalDependencies: + '@types/node': 20.14.11 - /@floating-ui/react-dom@2.1.8(react-dom@18.3.1)(react@18.3.1): - resolution: {integrity: sha512-cC52bHwM/n/CxS87FH0yWdngEZrjdtLW/qVruo68qg+prK7ZQ4YGdut2GyDVpoGeAYe/h899rVeOVm6Oi40k2A==} - peerDependencies: - react: '>=16.8.0' - react-dom: '>=16.8.0' + '@inquirer/prompts@7.10.1(@types/node@20.14.11)': + dependencies: + '@inquirer/checkbox': 4.3.2(@types/node@20.14.11) + '@inquirer/confirm': 5.1.21(@types/node@20.14.11) + '@inquirer/editor': 4.2.23(@types/node@20.14.11) + '@inquirer/expand': 4.0.23(@types/node@20.14.11) + '@inquirer/input': 4.3.1(@types/node@20.14.11) + '@inquirer/number': 3.0.23(@types/node@20.14.11) + '@inquirer/password': 4.0.23(@types/node@20.14.11) + '@inquirer/rawlist': 4.1.11(@types/node@20.14.11) + '@inquirer/search': 3.2.2(@types/node@20.14.11) + '@inquirer/select': 4.4.2(@types/node@20.14.11) + optionalDependencies: + '@types/node': 20.14.11 + + '@inquirer/rawlist@4.1.11(@types/node@20.14.11)': dependencies: - '@floating-ui/dom': 1.7.6 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - dev: false + '@inquirer/core': 10.3.2(@types/node@20.14.11) + '@inquirer/type': 3.0.10(@types/node@20.14.11) + yoctocolors-cjs: 2.1.3 + optionalDependencies: + '@types/node': 20.14.11 - /@floating-ui/utils@0.2.11: - resolution: {integrity: sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==} - dev: false + '@inquirer/search@3.2.2(@types/node@20.14.11)': + dependencies: + '@inquirer/core': 10.3.2(@types/node@20.14.11) + '@inquirer/figures': 1.0.15 + '@inquirer/type': 3.0.10(@types/node@20.14.11) + yoctocolors-cjs: 2.1.3 + optionalDependencies: + '@types/node': 20.14.11 - /@hookform/resolvers@3.9.0(react-hook-form@7.52.1): - resolution: {integrity: sha512-bU0Gr4EepJ/EQsH/IwEzYLsT/PEj5C0ynLQ4m+GSHS+xKH4TfSelhluTgOaoc4kA5s7eCsQbM4wvZLzELmWzUg==} - peerDependencies: - react-hook-form: ^7.0.0 + '@inquirer/select@4.4.2(@types/node@20.14.11)': dependencies: - react-hook-form: 7.52.1(react@18.3.1) - dev: false + '@inquirer/ansi': 1.0.2 + '@inquirer/core': 10.3.2(@types/node@20.14.11) + '@inquirer/figures': 1.0.15 + '@inquirer/type': 3.0.10(@types/node@20.14.11) + yoctocolors-cjs: 2.1.3 + optionalDependencies: + '@types/node': 20.14.11 - /@humanwhocodes/module-importer@1.0.1: - resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} - engines: {node: '>=12.22'} - dev: true + '@inquirer/type@3.0.10(@types/node@20.14.11)': + optionalDependencies: + '@types/node': 20.14.11 - /@humanwhocodes/retry@0.3.1: - resolution: {integrity: sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==} - engines: {node: '>=18.18'} - dev: true + '@jridgewell/gen-mapping@0.3.13': + dependencies: + '@jridgewell/sourcemap-codec': 1.6.0 + '@jridgewell/trace-mapping': 0.3.31 - /@inquirer/external-editor@1.0.3(@types/node@20.14.11): - resolution: {integrity: sha512-RWbSrDiYmO4LbejWY7ttpxczuwQyZLBUyygsA9Nsv95hpzUWwnNTVQmAq3xuh7vNwCp07UTmE5i11XAEExx4RA==} - engines: {node: '>=18'} - peerDependencies: - '@types/node': '>=18' - peerDependenciesMeta: - '@types/node': - optional: true + '@jridgewell/remapping@2.3.5': dependencies: - '@types/node': 20.14.11 - chardet: 2.2.0 - iconv-lite: 0.7.3 - dev: true + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 - /@jridgewell/gen-mapping@0.3.13: - resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/source-map@0.3.11': dependencies: - '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/gen-mapping': 0.3.13 '@jridgewell/trace-mapping': 0.3.31 - dev: true - /@jridgewell/resolve-uri@3.1.2: - resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} - engines: {node: '>=6.0.0'} - dev: true + '@jridgewell/sourcemap-codec@1.6.0': {} + + '@jridgewell/trace-mapping@0.3.31': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.6.0 + + '@jridgewell/trace-mapping@0.3.9': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.6.0 + + '@keyv/bigmap@1.3.1(keyv@5.6.0)': + dependencies: + hashery: 1.5.1 + hookified: 1.15.1 + keyv: 5.6.0 - /@jridgewell/sourcemap-codec@1.5.5: - resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + '@keyv/serialize@1.1.1': {} - /@jridgewell/trace-mapping@0.3.31: - resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + '@libsql/client@0.17.4': dependencies: - '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.5.5 - dev: true + '@libsql/core': 0.17.4 + '@libsql/hrana-client': 0.10.0 + js-base64: 3.9.5 + libsql: 0.5.29 + promise-limit: 2.7.0 + transitivePeerDependencies: + - bufferutil + - utf-8-validate - /@jridgewell/trace-mapping@0.3.9: - resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} + '@libsql/core@0.17.4': dependencies: - '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.5.5 - dev: true + js-base64: 3.9.5 - /@libsql/darwin-arm64@0.5.29: - resolution: {integrity: sha512-K+2RIB1OGFPYQbfay48GakLhqf3ArcbHqPFu7EZiaUcRgFcdw8RoltsMyvbj5ix2fY0HV3Q3Ioa/ByvQdaSM0A==} - cpu: [arm64] - os: [darwin] - requiresBuild: true - dev: false + '@libsql/darwin-arm64@0.5.29': optional: true - /@libsql/darwin-x64@0.5.29: - resolution: {integrity: sha512-OtT+KFHsKFy1R5FVadr8FJ2Bb1mghtXTyJkxv0trocq7NuHntSki1eUbxpO5ezJesDvBlqFjnWaYYY516QNLhQ==} - cpu: [x64] - os: [darwin] - requiresBuild: true - dev: false + '@libsql/darwin-x64@0.5.29': optional: true - /@libsql/linux-arm-gnueabihf@0.5.29: - resolution: {integrity: sha512-CD4n4zj7SJTHso4nf5cuMoWoMSS7asn5hHygsDuhRl8jjjCTT3yE+xdUvI4J7zsyb53VO5ISh4cwwOtf6k2UhQ==} - cpu: [arm] - os: [linux] - requiresBuild: true - dev: false + '@libsql/hrana-client@0.10.0': + dependencies: + '@libsql/isomorphic-ws': 0.1.5 + js-base64: 3.9.5 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + + '@libsql/isomorphic-ws@0.1.5': + dependencies: + '@types/ws': 8.18.2 + ws: 8.22.0 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + + '@libsql/kysely-libsql@0.4.1(kysely@0.29.6)': + dependencies: + '@libsql/client': 0.17.4 + kysely: 0.29.6 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + + '@libsql/linux-arm-gnueabihf@0.5.29': optional: true - /@libsql/linux-arm-musleabihf@0.5.29: - resolution: {integrity: sha512-2Z9qBVpEJV7OeflzIR3+l5yAd4uTOLxklScYTwpZnkm2vDSGlC1PRlueLaufc4EFITkLKXK2MWBpexuNJfMVcg==} - cpu: [arm] - os: [linux] - requiresBuild: true - dev: false + '@libsql/linux-arm-musleabihf@0.5.29': optional: true - /@libsql/linux-arm64-gnu@0.5.29: - resolution: {integrity: sha512-gURBqaiXIGGwFNEaUj8Ldk7Hps4STtG+31aEidCk5evMMdtsdfL3HPCpvys+ZF/tkOs2MWlRWoSq7SOuCE9k3w==} - cpu: [arm64] - os: [linux] - requiresBuild: true - dev: false + '@libsql/linux-arm64-gnu@0.5.29': optional: true - /@libsql/linux-arm64-musl@0.5.29: - resolution: {integrity: sha512-fwgYZ0H8mUkyVqXZHF3mT/92iIh1N94Owi/f66cPVNsk9BdGKq5gVpoKO+7UxaNzuEH1roJp2QEwsCZMvBLpqg==} - cpu: [arm64] - os: [linux] - requiresBuild: true - dev: false + '@libsql/linux-arm64-musl@0.5.29': optional: true - /@libsql/linux-x64-gnu@0.5.29: - resolution: {integrity: sha512-y14V0vY0nmMC6G0pHeJcEarcnGU2H6cm21ZceRkacWHvQAEhAG0latQkCtoS2njFOXiYIg+JYPfAoWKbi82rkg==} - cpu: [x64] - os: [linux] - requiresBuild: true - dev: false + '@libsql/linux-x64-gnu@0.5.29': optional: true - /@libsql/linux-x64-musl@0.5.29: - resolution: {integrity: sha512-gquqwA/39tH4pFl+J9n3SOMSymjX+6kZ3kWgY3b94nXFTwac9bnFNMffIomgvlFaC4ArVqMnOZD3nuJ3H3VO1w==} - cpu: [x64] - os: [linux] - requiresBuild: true - dev: false + '@libsql/linux-x64-musl@0.5.29': optional: true - /@libsql/win32-x64-msvc@0.5.29: - resolution: {integrity: sha512-4/0CvEdhi6+KjMxMaVbFM2n2Z44escBRoEYpR+gZg64DdetzGnYm8mcNLcoySaDJZNaBd6wz5DNdgRmcI4hXcg==} - cpu: [x64] - os: [win32] - requiresBuild: true - dev: false + '@libsql/win32-x64-msvc@0.5.29': optional: true - /@mikro-orm/core@7.2.1: - resolution: {integrity: sha512-+gtJoScbin/C3wPItSZkj5vlMTq/LphBLIxHyi5brCbeA6VDcYuoMopiqoFUMQxdhXXrZlKNIHXGrhb8r3biVg==} - engines: {node: '>= 22.17.0'} - peerDependencies: - dataloader: 2.2.3 - peerDependenciesMeta: - dataloader: - optional: true + '@mdx-js/mdx@3.1.1(supports-color@10.2.2)': + dependencies: + '@types/estree': 1.0.9 + '@types/estree-jsx': 1.0.5 + '@types/hast': 3.0.5 + '@types/mdx': 2.0.14 + acorn: 8.19.0 + collapse-white-space: 2.1.0 + devlop: 1.1.0 + estree-util-is-identifier-name: 3.0.0 + estree-util-scope: 1.0.1 + estree-walker: 3.0.3 + hast-util-to-jsx-runtime: 2.3.6(supports-color@10.2.2) + markdown-extensions: 2.0.0 + recma-build-jsx: 1.0.0 + recma-jsx: 1.0.1(acorn@8.19.0) + recma-stringify: 1.0.0 + rehype-recma: 1.0.0(supports-color@10.2.2) + remark-mdx: 3.1.1(supports-color@10.2.2) + remark-parse: 11.0.0(supports-color@10.2.2) + remark-rehype: 11.1.2 + source-map: 0.7.6 + unified: 11.0.5 + unist-util-position-from-estree: 2.0.0 + unist-util-stringify-position: 4.0.0 + unist-util-visit: 5.2.0 + vfile: 6.0.3 + transitivePeerDependencies: + - supports-color - /@mikro-orm/libsql@7.2.1(@mikro-orm/core@7.2.1): - resolution: {integrity: sha512-jXvptoHpbzfj8XUy5V5BvVee2LOsxgI/GnITfmh6Jl42tpIEDJx6Talqbv+z1PNGkHhw8OU5GoHXDJqYpNqo5w==} - engines: {node: '>= 22.17.0'} - peerDependencies: + '@mikro-orm/cli@7.2.1': + dependencies: '@mikro-orm/core': 7.2.1 + mikro-orm: 7.2.1 + yargs: 17.7.2 + transitivePeerDependencies: + - dataloader + + '@mikro-orm/core@7.2.1': {} + + '@mikro-orm/libsql@7.2.1(@mikro-orm/core@7.2.1)': dependencies: '@mikro-orm/core': 7.2.1 '@mikro-orm/sql': 7.2.1(@mikro-orm/core@7.2.1) kysely: 0.29.6 libsql: 0.5.29 - dev: false - /@mikro-orm/migrations@7.2.1(@mikro-orm/core@7.2.1): - resolution: {integrity: sha512-sxGcB7na0AkcREsD5U3xP+Psb/nhQFkx7/eY1Nsqq9MBs67O5RoCL97bn3lmgq6GwKZFbktMuuOGozq42+GaNg==} - engines: {node: '>= 22.17.0'} - peerDependencies: - '@mikro-orm/core': 7.2.1 + '@mikro-orm/migrations@7.2.1(@mikro-orm/core@7.2.1)': dependencies: '@mikro-orm/core': 7.2.1 '@mikro-orm/sql': 7.2.1(@mikro-orm/core@7.2.1) - dev: false - /@mikro-orm/mysql@7.2.1(@mikro-orm/core@7.2.1)(@types/node@22.18.6): - resolution: {integrity: sha512-IxCEnfHUzFcxVkRCVaC0KtGoHRRLogxxgeI+J4Pk7oxtDf/jtvYQuFL4tSbmlrH3qzmLQeYYPyJPuDr+a2F7ag==} - engines: {node: '>= 22.17.0'} - peerDependencies: + '@mikro-orm/mysql@7.2.1(@mikro-orm/core@7.2.1)(@types/node@20.14.11)': + dependencies: '@mikro-orm/core': 7.2.1 + '@mikro-orm/sql': 7.2.1(@mikro-orm/core@7.2.1) + kysely: 0.29.6 + mysql2: 3.24.4(@types/node@20.14.11) + sqlstring: 2.3.3 + transitivePeerDependencies: + - '@types/node' + + '@mikro-orm/mysql@7.2.1(@mikro-orm/core@7.2.1)(@types/node@22.18.6)': dependencies: '@mikro-orm/core': 7.2.1 '@mikro-orm/sql': 7.2.1(@mikro-orm/core@7.2.1) @@ -1952,13 +7730,8 @@ packages: sqlstring: 2.3.3 transitivePeerDependencies: - '@types/node' - dev: false - /@mikro-orm/postgresql@7.2.1(@mikro-orm/core@7.2.1): - resolution: {integrity: sha512-PQ1qe4Bj/hQSHYJjR02l06FfEDwniAvncduwZSCLSKuaCUddHc5AN2Utj3yo4xRIVRY8pOa7DFitEQPBozTMJA==} - engines: {node: '>= 22.17.0'} - peerDependencies: - '@mikro-orm/core': 7.2.1 + '@mikro-orm/postgresql@7.2.1(@mikro-orm/core@7.2.1)': dependencies: '@mikro-orm/core': 7.2.1 '@mikro-orm/sql': 7.2.1(@mikro-orm/core@7.2.1) @@ -1970,1763 +7743,1441 @@ packages: postgres-interval: 4.1.0 transitivePeerDependencies: - pg-native - dev: false - /@mikro-orm/sql@7.2.1(@mikro-orm/core@7.2.1): - resolution: {integrity: sha512-3M9dQeUDLlvAT5VJr/KBGAk9C7xez+psVCnvNkAO4hRhwx2Wm7N1HkuyP4Bwj0MjkHVB6LYvhTw/V6pYsVM8lA==} - engines: {node: '>= 22.17.0'} - peerDependencies: - '@mikro-orm/core': 7.2.1 + '@mikro-orm/sql@7.2.1(@mikro-orm/core@7.2.1)': dependencies: '@mikro-orm/core': 7.2.1 kysely: 0.29.6 - /@mikro-orm/sqlite@7.2.1(@mikro-orm/core@7.2.1): - resolution: {integrity: sha512-+iAPGORAqLl+TcBF+JSLOfRq+PwTQG1NLts+AvN9D8C2czlbDpyjyeaAFSR+5wJlMEZ4wv2rdzt4jSS5T7x3XQ==} - engines: {node: '>= 22.17.0'} - peerDependencies: - '@mikro-orm/core': 7.2.1 + '@mikro-orm/sqlite@7.2.1(@mikro-orm/core@7.2.1)': dependencies: '@mikro-orm/core': 7.2.1 '@mikro-orm/sql': 7.2.1(@mikro-orm/core@7.2.1) better-sqlite3: 13.0.3 kysely: 0.29.6 - /@neon-rs/load@0.0.4: - resolution: {integrity: sha512-kTPhdZyTQxB+2wpiRcFWrDcejc4JI6tkPuS7UZCG4l6Zvc5kU/gGQ/ozvHTh1XR5tS+UlfAfGuPajjzQjCiHCw==} - dev: false + '@napi-rs/lzma-linux-x64-gnu@1.5.1': + optional: true - /@next/env@14.2.35: - resolution: {integrity: sha512-DuhvCtj4t9Gwrx80dmz2F4t/zKQ4ktN8WrMwOuVzkJfBilwAwGr6v16M5eI8yCuZ63H9TTuEU09Iu2HqkzFPVQ==} + '@neon-rs/load@0.0.4': {} - /@next/swc-darwin-arm64@14.2.33: - resolution: {integrity: sha512-HqYnb6pxlsshoSTubdXKu15g3iivcbsMXg4bYpjL2iS/V6aQot+iyF4BUc2qA/J/n55YtvE4PHMKWBKGCF/+wA==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [darwin] - requiresBuild: true + '@next/env@14.2.35': {} + + '@next/env@16.4.2': {} + + '@next/swc-darwin-arm64@14.2.33': optional: true - /@next/swc-darwin-x64@14.2.33: - resolution: {integrity: sha512-8HGBeAE5rX3jzKvF593XTTFg3gxeU4f+UWnswa6JPhzaR6+zblO5+fjltJWIZc4aUalqTclvN2QtTC37LxvZAA==} - engines: {node: '>= 10'} - cpu: [x64] - os: [darwin] - requiresBuild: true + '@next/swc-darwin-arm64@16.4.2': optional: true - /@next/swc-linux-arm64-gnu@14.2.33: - resolution: {integrity: sha512-JXMBka6lNNmqbkvcTtaX8Gu5by9547bukHQvPoLe9VRBx1gHwzf5tdt4AaezW85HAB3pikcvyqBToRTDA4DeLw==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [linux] - requiresBuild: true + '@next/swc-darwin-x64@14.2.33': optional: true - /@next/swc-linux-arm64-musl@14.2.33: - resolution: {integrity: sha512-Bm+QulsAItD/x6Ih8wGIMfRJy4G73tu1HJsrccPW6AfqdZd0Sfm5Imhgkgq2+kly065rYMnCOxTBvmvFY1BKfg==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [linux] - requiresBuild: true + '@next/swc-darwin-x64@16.4.2': optional: true - /@next/swc-linux-x64-gnu@14.2.33: - resolution: {integrity: sha512-FnFn+ZBgsVMbGDsTqo8zsnRzydvsGV8vfiWwUo1LD8FTmPTdV+otGSWKc4LJec0oSexFnCYVO4hX8P8qQKaSlg==} - engines: {node: '>= 10'} - cpu: [x64] - os: [linux] - requiresBuild: true + '@next/swc-linux-arm64-gnu@14.2.33': optional: true - /@next/swc-linux-x64-musl@14.2.33: - resolution: {integrity: sha512-345tsIWMzoXaQndUTDv1qypDRiebFxGYx9pYkhwY4hBRaOLt8UGfiWKr9FSSHs25dFIf8ZqIFaPdy5MljdoawA==} - engines: {node: '>= 10'} - cpu: [x64] - os: [linux] - requiresBuild: true + '@next/swc-linux-arm64-gnu@16.4.2': optional: true - /@next/swc-win32-arm64-msvc@14.2.33: - resolution: {integrity: sha512-nscpt0G6UCTkrT2ppnJnFsYbPDQwmum4GNXYTeoTIdsmMydSKFz9Iny2jpaRupTb+Wl298+Rh82WKzt9LCcqSQ==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [win32] - requiresBuild: true + '@next/swc-linux-arm64-musl@14.2.33': optional: true - /@next/swc-win32-ia32-msvc@14.2.33: - resolution: {integrity: sha512-pc9LpGNKhJ0dXQhZ5QMmYxtARwwmWLpeocFmVG5Z0DzWq5Uf0izcI8tLc+qOpqxO1PWqZ5A7J1blrUIKrIFc7Q==} - engines: {node: '>= 10'} - cpu: [ia32] - os: [win32] - requiresBuild: true + '@next/swc-linux-arm64-musl@16.4.2': optional: true - /@next/swc-win32-x64-msvc@14.2.33: - resolution: {integrity: sha512-nOjfZMy8B94MdisuzZo9/57xuFVLHJaDj5e/xrduJp9CV2/HrfxTRH2fbyLe+K9QT41WBLUd4iXX3R7jBp0EUg==} - engines: {node: '>= 10'} - cpu: [x64] - os: [win32] - requiresBuild: true + '@next/swc-linux-x64-gnu@14.2.33': optional: true - /@noble/ciphers@2.2.0: - resolution: {integrity: sha512-Z6pjIZ/8IJcCGzb2S/0Px5J81yij85xASuk1teLNeg75bfT07MV3a/O2Mtn1I2se43k3lkVEcFaR10N4cgQcZA==} - engines: {node: '>= 20.19.0'} - dev: false + '@next/swc-linux-x64-gnu@16.4.2': + optional: true - /@noble/hashes@2.2.0: - resolution: {integrity: sha512-IYqDGiTXab6FniAgnSdZwgWbomxpy9FtYvLKs7wCUs2a8RkITG+DFGO1DM9cr+E3/RgADRpFjrKVaJ1z6sjtEg==} - engines: {node: '>= 20.19.0'} - dev: false + '@next/swc-linux-x64-musl@14.2.33': + optional: true - /@nodelib/fs.scandir@2.1.5: - resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} - engines: {node: '>= 8'} + '@next/swc-linux-x64-musl@16.4.2': + optional: true + + '@next/swc-win32-arm64-msvc@14.2.33': + optional: true + + '@next/swc-win32-arm64-msvc@16.4.2': + optional: true + + '@next/swc-win32-ia32-msvc@14.2.33': + optional: true + + '@next/swc-win32-x64-msvc@14.2.33': + optional: true + + '@next/swc-win32-x64-msvc@16.4.2': + optional: true + + '@noble/ciphers@2.4.0': {} + + '@noble/hashes@2.4.0': {} + + '@nodelib/fs.scandir@2.1.5': dependencies: '@nodelib/fs.stat': 2.0.5 run-parallel: 1.2.0 - dev: true - /@nodelib/fs.stat@2.0.5: - resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} - engines: {node: '>= 8'} - dev: true + '@nodelib/fs.stat@2.0.5': {} - /@nodelib/fs.walk@1.2.8: - resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} - engines: {node: '>= 8'} + '@nodelib/fs.walk@1.2.8': dependencies: '@nodelib/fs.scandir': 2.1.5 - fastq: 1.20.1 - dev: true + fastq: 1.20.3 - /@opentelemetry/semantic-conventions@1.43.0: - resolution: {integrity: sha512-eSYWTm620tTk45EKSedaUL8MFYI8hW164hIXsgIHyxu3VobUB3fFCu5t0hQby6OoWRPsG1KkKUG2M5UadiLiVg==} - engines: {node: '>=14'} - dev: false + '@opentelemetry/semantic-conventions@1.43.0': {} - /@radix-ui/number@1.0.1: - resolution: {integrity: sha512-T5gIdVO2mmPW3NNhjNgEP3cqMXjXL9UbO0BzWcXfvdBs+BohbQxvd/K5hSVKmn9/lbTdsQVKbUcP5WLCwvUbBg==} + '@oxc-project/types@0.155.0': {} + + '@playwright/test@1.64.1': dependencies: - '@babel/runtime': 7.29.7 - dev: false + playwright: 1.64.1 - /@radix-ui/primitive@1.0.1: - resolution: {integrity: sha512-yQ8oGX2GVsEYMWGxcovu1uGWPCxV5BFfeeYxqPmuAzUyLT9qmaMXSAhXpb0WrspIeqYzdJpkh2vHModJPgRIaw==} + '@poppinss/colors@4.1.6': dependencies: - '@babel/runtime': 7.29.7 - dev: false + kleur: 4.1.5 - /@radix-ui/react-arrow@1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1)(react@18.3.1): - resolution: {integrity: sha512-wSP+pHsB/jQRaL6voubsQ/ZlrGBHHrOjmBnr19hxYgtS0WvAFwZhK2WP/YY5yF9uKECCEEDGxuLxq1NBK51wFA==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 - react-dom: ^16.8 || ^17.0 || ^18.0 - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true + '@poppinss/dumper@0.6.5': dependencies: - '@babel/runtime': 7.29.7 - '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1)(react@18.3.1) - '@types/react': 18.3.3 - '@types/react-dom': 18.3.0 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - dev: false + '@poppinss/colors': 4.1.6 + '@sindresorhus/is': 7.2.0 + supports-color: 10.2.2 - /@radix-ui/react-checkbox@1.0.4(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1)(react@18.3.1): - resolution: {integrity: sha512-CBuGQa52aAYnADZVt/KBQzXrwx6TqnlwtcIPGtVt5JkkzQwMOLJjPukimhfKEr4GQNd43C+djUh5Ikopj8pSLg==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 - react-dom: ^16.8 || ^17.0 || ^18.0 - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true + '@poppinss/exception@1.2.3': {} + + '@radix-ui/number@1.0.1': dependencies: - '@babel/runtime': 7.29.7 - '@radix-ui/primitive': 1.0.1 - '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.3.3)(react@18.3.1) - '@radix-ui/react-context': 1.0.1(@types/react@18.3.3)(react@18.3.1) - '@radix-ui/react-presence': 1.0.1(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.3.3)(react@18.3.1) - '@radix-ui/react-use-previous': 1.0.1(@types/react@18.3.3)(react@18.3.1) - '@radix-ui/react-use-size': 1.0.1(@types/react@18.3.3)(react@18.3.1) + '@babel/runtime': 7.29.10 + + '@radix-ui/primitive@1.0.1': + dependencies: + '@babel/runtime': 7.29.10 + + '@radix-ui/primitive@1.2.0': {} + + '@radix-ui/react-arrow@1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@babel/runtime': 7.29.10 + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + optionalDependencies: '@types/react': 18.3.3 '@types/react-dom': 18.3.0 + + '@radix-ui/react-checkbox@1.4.1(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@radix-ui/primitive': 1.2.0 + '@radix-ui/react-compose-refs': 1.1.5(@types/react@18.3.3)(react@18.3.1) + '@radix-ui/react-context': 1.3.0(@types/react@18.3.3)(react@18.3.1) + '@radix-ui/react-presence': 1.1.11(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-primitive': 2.2.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-use-controllable-state': 1.3.0(@types/react@18.3.3)(react@18.3.1) + '@radix-ui/react-use-size': 1.1.5(@types/react@18.3.3)(react@18.3.1) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - dev: false + optionalDependencies: + '@types/react': 18.3.3 + '@types/react-dom': 18.3.0 - /@radix-ui/react-collection@1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1)(react@18.3.1): - resolution: {integrity: sha512-3SzW+0PW7yBBoQlT8wNcGtaxaD0XSu0uLUFgrtHY08Acx05TaHaOmVLR73c0j/cqpDy53KBMO7s0dx2wmOIDIA==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 - react-dom: ^16.8 || ^17.0 || ^18.0 - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true + '@radix-ui/react-collection@1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@babel/runtime': 7.29.7 + '@babel/runtime': 7.29.10 '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.3.3)(react@18.3.1) '@radix-ui/react-context': 1.0.1(@types/react@18.3.3)(react@18.3.1) - '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-slot': 1.0.2(@types/react@18.3.3)(react@18.3.1) - '@types/react': 18.3.3 - '@types/react-dom': 18.3.0 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - dev: false + optionalDependencies: + '@types/react': 18.3.3 + '@types/react-dom': 18.3.0 - /@radix-ui/react-compose-refs@1.0.1(@types/react@18.3.3)(react@18.3.1): - resolution: {integrity: sha512-fDSBgd44FKHa1FRMU59qBMPFcl2PZE+2nmqunj+BWFyYYjnhIDWL2ItDs3rrbJDQOtzt5nIebLCQc4QRfz6LJw==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 - peerDependenciesMeta: - '@types/react': - optional: true + '@radix-ui/react-compose-refs@1.0.1(@types/react@18.3.3)(react@18.3.1)': dependencies: - '@babel/runtime': 7.29.7 - '@types/react': 18.3.3 + '@babel/runtime': 7.29.10 react: 18.3.1 - dev: false + optionalDependencies: + '@types/react': 18.3.3 - /@radix-ui/react-context@1.0.1(@types/react@18.3.3)(react@18.3.1): - resolution: {integrity: sha512-ebbrdFoYTcuZ0v4wG5tedGnp9tzcV8awzsxYph7gXUyvnNLuTIcCk1q17JEbnVhXAKG9oX3KtchwiMIAYp9NLg==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 - peerDependenciesMeta: - '@types/react': - optional: true + '@radix-ui/react-compose-refs@1.1.5(@types/react@18.3.3)(react@18.3.1)': dependencies: - '@babel/runtime': 7.29.7 + react: 18.3.1 + optionalDependencies: '@types/react': 18.3.3 + + '@radix-ui/react-context@1.0.1(@types/react@18.3.3)(react@18.3.1)': + dependencies: + '@babel/runtime': 7.29.10 react: 18.3.1 - dev: false + optionalDependencies: + '@types/react': 18.3.3 - /@radix-ui/react-direction@1.0.1(@types/react@18.3.3)(react@18.3.1): - resolution: {integrity: sha512-RXcvnXgyvYvBEOhCBuddKecVkoMiI10Jcm5cTI7abJRAHYfFxeu+FBQs/DvdxSYucxR5mna0dNsL6QFlds5TMA==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 - peerDependenciesMeta: - '@types/react': - optional: true + '@radix-ui/react-context@1.3.0(@types/react@18.3.3)(react@18.3.1)': dependencies: - '@babel/runtime': 7.29.7 + react: 18.3.1 + optionalDependencies: '@types/react': 18.3.3 + + '@radix-ui/react-direction@1.0.1(@types/react@18.3.3)(react@18.3.1)': + dependencies: + '@babel/runtime': 7.29.10 react: 18.3.1 - dev: false + optionalDependencies: + '@types/react': 18.3.3 - /@radix-ui/react-dismissable-layer@1.0.4(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1)(react@18.3.1): - resolution: {integrity: sha512-7UpBa/RKMoHJYjie1gkF1DlK8l1fdU/VKDpoS3rCCo8YBJR294GwcEHyxHw72yvphJ7ld0AXEcSLAzY2F/WyCg==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 - react-dom: ^16.8 || ^17.0 || ^18.0 - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true + '@radix-ui/react-dismissable-layer@1.0.4(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@babel/runtime': 7.29.7 + '@babel/runtime': 7.29.10 '@radix-ui/primitive': 1.0.1 '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.3.3)(react@18.3.1) - '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.3.3)(react@18.3.1) '@radix-ui/react-use-escape-keydown': 1.0.3(@types/react@18.3.3)(react@18.3.1) - '@types/react': 18.3.3 - '@types/react-dom': 18.3.0 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - dev: false + optionalDependencies: + '@types/react': 18.3.3 + '@types/react-dom': 18.3.0 - /@radix-ui/react-focus-guards@1.0.1(@types/react@18.3.3)(react@18.3.1): - resolution: {integrity: sha512-Rect2dWbQ8waGzhMavsIbmSVCgYxkXLxxR3ZvCX79JOglzdEy4JXMb98lq4hPxUbLr77nP0UOGf4rcMU+s1pUA==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 - peerDependenciesMeta: - '@types/react': - optional: true + '@radix-ui/react-focus-guards@1.0.1(@types/react@18.3.3)(react@18.3.1)': dependencies: - '@babel/runtime': 7.29.7 - '@types/react': 18.3.3 + '@babel/runtime': 7.29.10 react: 18.3.1 - dev: false + optionalDependencies: + '@types/react': 18.3.3 - /@radix-ui/react-focus-scope@1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1)(react@18.3.1): - resolution: {integrity: sha512-upXdPfqI4islj2CslyfUBNlaJCPybbqRHAi1KER7Isel9Q2AtSJ0zRBZv8mWQiFXD2nyAJ4BhC3yXgZ6kMBSrQ==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 - react-dom: ^16.8 || ^17.0 || ^18.0 - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true + '@radix-ui/react-focus-scope@1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@babel/runtime': 7.29.7 + '@babel/runtime': 7.29.10 '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.3.3)(react@18.3.1) - '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.3.3)(react@18.3.1) - '@types/react': 18.3.3 - '@types/react-dom': 18.3.0 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - dev: false + optionalDependencies: + '@types/react': 18.3.3 + '@types/react-dom': 18.3.0 - /@radix-ui/react-id@1.0.1(@types/react@18.3.3)(react@18.3.1): - resolution: {integrity: sha512-tI7sT/kqYp8p96yGWY1OAnLHrqDgzHefRBKQ2YAkBS5ja7QLcZ9Z/uY7bEjPUatf8RomoXM8/1sMj1IJaE5UzQ==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 - peerDependenciesMeta: - '@types/react': - optional: true + '@radix-ui/react-id@1.0.1(@types/react@18.3.3)(react@18.3.1)': dependencies: - '@babel/runtime': 7.29.7 + '@babel/runtime': 7.29.10 '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.3.3)(react@18.3.1) - '@types/react': 18.3.3 react: 18.3.1 - dev: false + optionalDependencies: + '@types/react': 18.3.3 - /@radix-ui/react-label@2.0.2(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1)(react@18.3.1): - resolution: {integrity: sha512-N5ehvlM7qoTLx7nWPodsPYPgMzA5WM8zZChQg8nyFJKnDO5WHdba1vv5/H6IO5LtJMfD2Q3wh1qHFGNtK0w3bQ==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 - react-dom: ^16.8 || ^17.0 || ^18.0 - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true + '@radix-ui/react-label@2.1.17(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@babel/runtime': 7.29.7 - '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1)(react@18.3.1) - '@types/react': 18.3.3 - '@types/react-dom': 18.3.0 + '@radix-ui/react-primitive': 2.2.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - dev: false + optionalDependencies: + '@types/react': 18.3.3 + '@types/react-dom': 18.3.0 - /@radix-ui/react-popper@1.1.2(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1)(react@18.3.1): - resolution: {integrity: sha512-1CnGGfFi/bbqtJZZ0P/NQY20xdG3E0LALJaLUEoKwPLwl6PPPfbeiCqMVQnhoFRAxjJj4RpBRJzDmUgsex2tSg==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 - react-dom: ^16.8 || ^17.0 || ^18.0 - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true + '@radix-ui/react-popper@1.1.2(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@babel/runtime': 7.29.7 - '@floating-ui/react-dom': 2.1.8(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-arrow': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1)(react@18.3.1) + '@babel/runtime': 7.29.10 + '@floating-ui/react-dom': 2.1.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-arrow': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.3.3)(react@18.3.1) '@radix-ui/react-context': 1.0.1(@types/react@18.3.3)(react@18.3.1) - '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.3.3)(react@18.3.1) '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.3.3)(react@18.3.1) '@radix-ui/react-use-rect': 1.0.1(@types/react@18.3.3)(react@18.3.1) '@radix-ui/react-use-size': 1.0.1(@types/react@18.3.3)(react@18.3.1) '@radix-ui/rect': 1.0.1 - '@types/react': 18.3.3 - '@types/react-dom': 18.3.0 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - dev: false - - /@radix-ui/react-portal@1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1)(react@18.3.1): - resolution: {integrity: sha512-xLYZeHrWoPmA5mEKEfZZevoVRK/Q43GfzRXkWV6qawIWWK8t6ifIiLQdd7rmQ4Vk1bmI21XhqF9BN3jWf+phpA==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 - react-dom: ^16.8 || ^17.0 || ^18.0 - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - dependencies: - '@babel/runtime': 7.29.7 - '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1)(react@18.3.1) + optionalDependencies: '@types/react': 18.3.3 '@types/react-dom': 18.3.0 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - dev: false - /@radix-ui/react-presence@1.0.1(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1)(react@18.3.1): - resolution: {integrity: sha512-UXLW4UAbIY5ZjcvzjfRFo5gxva8QirC9hF7wRE4U5gz+TP0DbRk+//qyuAQ1McDxBt1xNMBTaciFGvEmJvAZCg==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 - react-dom: ^16.8 || ^17.0 || ^18.0 - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true + '@radix-ui/react-portal@1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@babel/runtime': 7.29.7 - '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.3.3)(react@18.3.1) - '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.3.3)(react@18.3.1) + '@babel/runtime': 7.29.10 + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + optionalDependencies: '@types/react': 18.3.3 '@types/react-dom': 18.3.0 + + '@radix-ui/react-presence@1.1.11(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@radix-ui/react-use-layout-effect': 1.1.4(@types/react@18.3.3)(react@18.3.1) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - dev: false + optionalDependencies: + '@types/react': 18.3.3 + '@types/react-dom': 18.3.0 - /@radix-ui/react-primitive@1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1)(react@18.3.1): - resolution: {integrity: sha512-yi58uVyoAcK/Nq1inRY56ZSjKypBNKTa/1mcL8qdl6oJeEaDbOldlzrGn7P6Q3Id5d+SYNGc5AJgc4vGhjs5+g==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 - react-dom: ^16.8 || ^17.0 || ^18.0 - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true + '@radix-ui/react-primitive@1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@babel/runtime': 7.29.7 + '@babel/runtime': 7.29.10 '@radix-ui/react-slot': 1.0.2(@types/react@18.3.3)(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + optionalDependencies: '@types/react': 18.3.3 '@types/react-dom': 18.3.0 + + '@radix-ui/react-primitive@2.2.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@radix-ui/react-slot': 1.5.0(@types/react@18.3.3)(react@18.3.1) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - dev: false + optionalDependencies: + '@types/react': 18.3.3 + '@types/react-dom': 18.3.0 - /@radix-ui/react-select@1.2.2(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1)(react@18.3.1): - resolution: {integrity: sha512-zI7McXr8fNaSrUY9mZe4x/HC0jTLY9fWNhO1oLWYMQGDXuV4UCivIGTxwioSzO0ZCYX9iSLyWmAh/1TOmX3Cnw==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 - react-dom: ^16.8 || ^17.0 || ^18.0 - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true + '@radix-ui/react-select@1.2.2(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@babel/runtime': 7.29.7 + '@babel/runtime': 7.29.10 '@radix-ui/number': 1.0.1 '@radix-ui/primitive': 1.0.1 - '@radix-ui/react-collection': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-collection': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.3.3)(react@18.3.1) '@radix-ui/react-context': 1.0.1(@types/react@18.3.3)(react@18.3.1) '@radix-ui/react-direction': 1.0.1(@types/react@18.3.3)(react@18.3.1) - '@radix-ui/react-dismissable-layer': 1.0.4(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-dismissable-layer': 1.0.4(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-focus-guards': 1.0.1(@types/react@18.3.3)(react@18.3.1) - '@radix-ui/react-focus-scope': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-focus-scope': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-id': 1.0.1(@types/react@18.3.3)(react@18.3.1) - '@radix-ui/react-popper': 1.1.2(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-portal': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-popper': 1.1.2(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-portal': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-slot': 1.0.2(@types/react@18.3.3)(react@18.3.1) '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.3.3)(react@18.3.1) '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.3.3)(react@18.3.1) '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.3.3)(react@18.3.1) '@radix-ui/react-use-previous': 1.0.1(@types/react@18.3.3)(react@18.3.1) - '@radix-ui/react-visually-hidden': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1)(react@18.3.1) - '@types/react': 18.3.3 - '@types/react-dom': 18.3.0 + '@radix-ui/react-visually-hidden': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) aria-hidden: 1.2.6 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) react-remove-scroll: 2.5.5(@types/react@18.3.3)(react@18.3.1) - dev: false + optionalDependencies: + '@types/react': 18.3.3 + '@types/react-dom': 18.3.0 - /@radix-ui/react-slot@1.0.2(@types/react@18.3.3)(react@18.3.1): - resolution: {integrity: sha512-YeTpuq4deV+6DusvVUW4ivBgnkHwECUu0BiN43L5UCDFgdhsRUWAghhTF5MbvNTPzmiFOx90asDSUjWuCNapwg==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 - peerDependenciesMeta: - '@types/react': - optional: true + '@radix-ui/react-slot@1.0.2(@types/react@18.3.3)(react@18.3.1)': dependencies: - '@babel/runtime': 7.29.7 + '@babel/runtime': 7.29.10 '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.3.3)(react@18.3.1) - '@types/react': 18.3.3 react: 18.3.1 - dev: false + optionalDependencies: + '@types/react': 18.3.3 - /@radix-ui/react-use-callback-ref@1.0.1(@types/react@18.3.3)(react@18.3.1): - resolution: {integrity: sha512-D94LjX4Sp0xJFVaoQOd3OO9k7tpBYNOXdVhkltUbGv2Qb9OXdrg/CpsjlZv7ia14Sylv398LswWBVVu5nqKzAQ==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 - peerDependenciesMeta: - '@types/react': - optional: true + '@radix-ui/react-slot@1.5.0(@types/react@18.3.3)(react@18.3.1)': dependencies: - '@babel/runtime': 7.29.7 - '@types/react': 18.3.3 + '@radix-ui/react-compose-refs': 1.1.5(@types/react@18.3.3)(react@18.3.1) react: 18.3.1 - dev: false + optionalDependencies: + '@types/react': 18.3.3 - /@radix-ui/react-use-controllable-state@1.0.1(@types/react@18.3.3)(react@18.3.1): - resolution: {integrity: sha512-Svl5GY5FQeN758fWKrjM6Qb7asvXeiZltlT4U2gVfl8Gx5UAv2sMR0LWo8yhsIZh2oQ0eFdZ59aoOOMV7b47VA==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 - peerDependenciesMeta: - '@types/react': - optional: true + '@radix-ui/react-use-callback-ref@1.0.1(@types/react@18.3.3)(react@18.3.1)': dependencies: - '@babel/runtime': 7.29.7 - '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.3.3)(react@18.3.1) - '@types/react': 18.3.3 + '@babel/runtime': 7.29.10 react: 18.3.1 - dev: false + optionalDependencies: + '@types/react': 18.3.3 - /@radix-ui/react-use-escape-keydown@1.0.3(@types/react@18.3.3)(react@18.3.1): - resolution: {integrity: sha512-vyL82j40hcFicA+M4Ex7hVkB9vHgSse1ZWomAqV2Je3RleKGO5iM8KMOEtfoSB0PnIelMd2lATjTGMYqN5ylTg==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 - peerDependenciesMeta: - '@types/react': - optional: true + '@radix-ui/react-use-controllable-state@1.0.1(@types/react@18.3.3)(react@18.3.1)': dependencies: - '@babel/runtime': 7.29.7 + '@babel/runtime': 7.29.10 '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.3.3)(react@18.3.1) - '@types/react': 18.3.3 react: 18.3.1 - dev: false + optionalDependencies: + '@types/react': 18.3.3 - /@radix-ui/react-use-layout-effect@1.0.1(@types/react@18.3.3)(react@18.3.1): - resolution: {integrity: sha512-v/5RegiJWYdoCvMnITBkNNx6bCj20fiaJnWtRkU18yITptraXjffz5Qbn05uOiQnOvi+dbkznkoaMltz1GnszQ==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 - peerDependenciesMeta: - '@types/react': - optional: true + '@radix-ui/react-use-controllable-state@1.3.0(@types/react@18.3.3)(react@18.3.1)': dependencies: - '@babel/runtime': 7.29.7 - '@types/react': 18.3.3 + '@radix-ui/primitive': 1.2.0 + '@radix-ui/react-use-effect-event': 0.0.5(@types/react@18.3.3)(react@18.3.1) + '@radix-ui/react-use-layout-effect': 1.1.4(@types/react@18.3.3)(react@18.3.1) react: 18.3.1 - dev: false + optionalDependencies: + '@types/react': 18.3.3 - /@radix-ui/react-use-previous@1.0.1(@types/react@18.3.3)(react@18.3.1): - resolution: {integrity: sha512-cV5La9DPwiQ7S0gf/0qiD6YgNqM5Fk97Kdrlc5yBcrF3jyEZQwm7vYFqMo4IfeHgJXsRaMvLABFtd0OVEmZhDw==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 - peerDependenciesMeta: - '@types/react': - optional: true + '@radix-ui/react-use-effect-event@0.0.5(@types/react@18.3.3)(react@18.3.1)': dependencies: - '@babel/runtime': 7.29.7 - '@types/react': 18.3.3 + '@radix-ui/react-use-layout-effect': 1.1.4(@types/react@18.3.3)(react@18.3.1) react: 18.3.1 - dev: false + optionalDependencies: + '@types/react': 18.3.3 - /@radix-ui/react-use-rect@1.0.1(@types/react@18.3.3)(react@18.3.1): - resolution: {integrity: sha512-Cq5DLuSiuYVKNU8orzJMbl15TXilTnJKUCltMVQg53BQOF1/C5toAaGrowkgksdBQ9H+SRL23g0HDmg9tvmxXw==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 - peerDependenciesMeta: - '@types/react': - optional: true + '@radix-ui/react-use-escape-keydown@1.0.3(@types/react@18.3.3)(react@18.3.1)': dependencies: - '@babel/runtime': 7.29.7 - '@radix-ui/rect': 1.0.1 + '@babel/runtime': 7.29.10 + '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.3.3)(react@18.3.1) + react: 18.3.1 + optionalDependencies: '@types/react': 18.3.3 + + '@radix-ui/react-use-layout-effect@1.0.1(@types/react@18.3.3)(react@18.3.1)': + dependencies: + '@babel/runtime': 7.29.10 react: 18.3.1 - dev: false + optionalDependencies: + '@types/react': 18.3.3 - /@radix-ui/react-use-size@1.0.1(@types/react@18.3.3)(react@18.3.1): - resolution: {integrity: sha512-ibay+VqrgcaI6veAojjofPATwledXiSmX+C0KrBk/xgpX9rBzPV3OsfwlhQdUOFbh+LKQorLYT+xTXW9V8yd0g==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 - peerDependenciesMeta: - '@types/react': - optional: true + '@radix-ui/react-use-layout-effect@1.1.4(@types/react@18.3.3)(react@18.3.1)': dependencies: - '@babel/runtime': 7.29.7 - '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.3.3)(react@18.3.1) + react: 18.3.1 + optionalDependencies: '@types/react': 18.3.3 + + '@radix-ui/react-use-previous@1.0.1(@types/react@18.3.3)(react@18.3.1)': + dependencies: + '@babel/runtime': 7.29.10 react: 18.3.1 - dev: false + optionalDependencies: + '@types/react': 18.3.3 - /@radix-ui/react-visually-hidden@1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1)(react@18.3.1): - resolution: {integrity: sha512-D4w41yN5YRKtu464TLnByKzMDG/JlMPHtfZgQAu9v6mNakUqGUI9vUrfQKz8NK41VMm/xbZbh76NUTVtIYqOMA==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 - react-dom: ^16.8 || ^17.0 || ^18.0 - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true + '@radix-ui/react-use-rect@1.0.1(@types/react@18.3.3)(react@18.3.1)': + dependencies: + '@babel/runtime': 7.29.10 + '@radix-ui/rect': 1.0.1 + react: 18.3.1 + optionalDependencies: + '@types/react': 18.3.3 + + '@radix-ui/react-use-size@1.0.1(@types/react@18.3.3)(react@18.3.1)': dependencies: - '@babel/runtime': 7.29.7 - '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1)(react@18.3.1) + '@babel/runtime': 7.29.10 + '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.3.3)(react@18.3.1) + react: 18.3.1 + optionalDependencies: '@types/react': 18.3.3 - '@types/react-dom': 18.3.0 + + '@radix-ui/react-use-size@1.1.5(@types/react@18.3.3)(react@18.3.1)': + dependencies: + '@radix-ui/react-use-layout-effect': 1.1.4(@types/react@18.3.3)(react@18.3.1) + react: 18.3.1 + optionalDependencies: + '@types/react': 18.3.3 + + '@radix-ui/react-visually-hidden@1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@babel/runtime': 7.29.10 + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - dev: false + optionalDependencies: + '@types/react': 18.3.3 + '@types/react-dom': 18.3.0 - /@radix-ui/rect@1.0.1: - resolution: {integrity: sha512-fyrgCaedtvMg9NK3en0pnOYJdtfwxUcNolezkNPUsoX57X8oQk+NkqcvzHXD2uKNij6GXmWU9NDru2IWjrO4BQ==} + '@radix-ui/rect@1.0.1': dependencies: - '@babel/runtime': 7.29.7 - dev: false + '@babel/runtime': 7.29.10 - /@rollup/rollup-android-arm-eabi@4.62.2: - resolution: {integrity: sha512-6o7ZLZK+BeenkZCFNDXqpbjw9bD6nuWonvS/lwQJp7NoVVxm6p3qE7qQ5jGuBjiFsgvqjD8mZAU5oWxTmbOeOg==} - cpu: [arm] - os: [android] - requiresBuild: true + '@resvg/resvg-wasm@2.4.1': {} + + '@rolldown/binding-android-arm-eabi@1.2.15': optional: true - /@rollup/rollup-android-arm64@4.62.2: - resolution: {integrity: sha512-BaH7BllCACHoH1LguOU56UItGfUWjujlO65kS9LAodViaN4bwIKd7oeW/ZHJ/4ljr/7MIiENnNy3HJ0zXv8Zkw==} - cpu: [arm64] - os: [android] - requiresBuild: true + '@rolldown/binding-android-arm64@1.2.15': optional: true - /@rollup/rollup-darwin-arm64@4.62.2: - resolution: {integrity: sha512-v39RCCvj4He82I9sFmk+M1VZ0PLM9sfsLVikjfx2hYBNALhrrOR2D3JjQA6AhlaSOgcR+RzrKY7e1+bT6SUO/A==} - cpu: [arm64] - os: [darwin] - requiresBuild: true + '@rolldown/binding-darwin-arm64@1.2.15': optional: true - /@rollup/rollup-darwin-x64@4.62.2: - resolution: {integrity: sha512-yl0y2vq3S3lHeuXhEdss6TWfKW8vkujImO12tn4ZkG/4oghr09LvdYm2RElVjokTQiUvDUGXLGsYeLqUMCKpGA==} - cpu: [x64] - os: [darwin] - requiresBuild: true + '@rolldown/binding-darwin-x64@1.2.15': optional: true - /@rollup/rollup-freebsd-arm64@4.62.2: - resolution: {integrity: sha512-tT4pvt4qXD+vEoezupCWi+a1F0vvDiksiHc+PxRlYTOH1I6/X4id9jPxTP+Fg+545euaFT1jJVs4CEdHZAU1vw==} - cpu: [arm64] - os: [freebsd] - requiresBuild: true + '@rolldown/binding-freebsd-x64@1.2.15': optional: true - /@rollup/rollup-freebsd-x64@4.62.2: - resolution: {integrity: sha512-6nU5F2wCW+qvCBhTn1pdIU3bzsIoF7EUwsCDRxilWGprQR6yd508YnH9+OKFCwpfS8pjZqDUmnCAr7exax0XCg==} - cpu: [x64] - os: [freebsd] - requiresBuild: true + '@rolldown/binding-linux-arm-gnueabihf@1.2.15': optional: true - /@rollup/rollup-linux-arm-gnueabihf@4.62.2: - resolution: {integrity: sha512-n1GJHPOvpIfhi3TmrCeh6S6URt9BFCt0KQE3qvexyGCTAKpR4Lg+eWvNZEqu7epxwus/8ElT3hacYEucm49SZg==} - cpu: [arm] - os: [linux] - requiresBuild: true + '@rolldown/binding-linux-arm64-gnu@1.2.15': optional: true - /@rollup/rollup-linux-arm-musleabihf@4.62.2: - resolution: {integrity: sha512-JqgflS8wEB+UXV/vS1RpRbifGBeN4D5lz8D8oOFbFZw4vedvdOgCFAjfBmIMdW3yL10XpQQ0Ambepw6MXrhOnA==} - cpu: [arm] - os: [linux] - requiresBuild: true + '@rolldown/binding-linux-arm64-musl@1.2.15': optional: true - /@rollup/rollup-linux-arm64-gnu@4.62.2: - resolution: {integrity: sha512-wnFJkogWvN4jm/hQRF2UBaeUmk20j5+DmHvoyWii2b8HJDyvz1MF2OU/6ynXt2KR63rbZLWkFpoytpdc/yBuSA==} - cpu: [arm64] - os: [linux] - requiresBuild: true + '@rolldown/binding-linux-ppc64-gnu@1.2.15': optional: true - /@rollup/rollup-linux-arm64-musl@4.62.2: - resolution: {integrity: sha512-HVu2bp0zhvJ8xHEV9+UUs7S90VadmBSY3LcIMvozbPo4AuMGDWlz3ymHLHZPX4hR67TKTt8Qp5PJ5RBg/i+RMQ==} - cpu: [arm64] - os: [linux] - requiresBuild: true + '@rolldown/binding-linux-s390x-gnu@1.2.15': optional: true - /@rollup/rollup-linux-loong64-gnu@4.62.2: - resolution: {integrity: sha512-mQqqAV8QaoSgr9I2fKDLY2BAVvmKjWoGiu/cSYQonsLvtqwEn1E4QYfnCOcp5zoEqNhsDYin1s6jx/VJmrxlZg==} - cpu: [loong64] - os: [linux] - requiresBuild: true + '@rolldown/binding-linux-x64-gnu@1.2.15': optional: true - /@rollup/rollup-linux-loong64-musl@4.62.2: - resolution: {integrity: sha512-IxKLoxCQ2IWi6bT2akyDUBGsOImDKB+sPp4EsTmwFQ/fMwpCKm8uLSSgP/Kx/QYUgKis6SEZ5/Nlhup0DIA0PQ==} - cpu: [loong64] - os: [linux] - requiresBuild: true + '@rolldown/binding-linux-x64-musl@1.2.15': optional: true - /@rollup/rollup-linux-ppc64-gnu@4.62.2: - resolution: {integrity: sha512-Mk5ha2RQSgyFfmYYLkBpPnUk8D8FriBxesO1u9O75X0mHgXL1UQcH5Itl2lurWL2tj0RxV9b9tJgipac0hRY9A==} - cpu: [ppc64] - os: [linux] - requiresBuild: true + '@rolldown/binding-openharmony-arm64@1.2.15': optional: true - /@rollup/rollup-linux-ppc64-musl@4.62.2: - resolution: {integrity: sha512-CjvEnqJL/0/TQ3TXX3OPIJ/kmBellrWd4heXUmHeJlTnmwjKpSJzoehLaL6Xk0ZnMHBu9dZuFADNOrtjF4v+2w==} - cpu: [ppc64] - os: [linux] - requiresBuild: true + '@rolldown/binding-win32-arm64-msvc@1.2.15': optional: true - /@rollup/rollup-linux-riscv64-gnu@4.62.2: - resolution: {integrity: sha512-1SiZbzwdkaDURsew/tSOrooKiYy7EQGT6m8ufavAi9NEyQb/6VuIxFXAL1fqa4iZe3g4NbNk4P7J32z2tw5Mgg==} - cpu: [riscv64] - os: [linux] - requiresBuild: true + '@rolldown/binding-win32-x64-msvc@1.2.15': optional: true - /@rollup/rollup-linux-riscv64-musl@4.62.2: - resolution: {integrity: sha512-nQts12zJ3NQRoE6uYljOH89v7szzLDvG2JD/vsX+vGXU8w/At1GowTZ5/7qeFQ8m7L55rpR8Okugnuo5bgjy2Q==} - cpu: [riscv64] - os: [linux] - requiresBuild: true + '@rolldown/pluginutils@1.0.0-rc.7': {} + + '@rolldown/pluginutils@1.0.1': {} + + '@rollup/rollup-android-arm-eabi@4.65.1': optional: true - /@rollup/rollup-linux-s390x-gnu@4.62.2: - resolution: {integrity: sha512-E9/ll019jhPIJgpzfZoIkBGhcz+kKNgVWYRY0zr9srBdPPFVpvOKW8VaJKUbeK+eZXyQF9ltME+Kk6affeaPgg==} - cpu: [s390x] - os: [linux] - requiresBuild: true + '@rollup/rollup-android-arm64@4.65.1': optional: true - /@rollup/rollup-linux-x64-gnu@4.62.2: - resolution: {integrity: sha512-5BqxR/pshjey51iliyzTD5Xi3EN0aLmQ2lZ3lvefVV9c82BvrLo2/6OT55iifpWBufs6kdwWbuOKS841DrmK9A==} - cpu: [x64] - os: [linux] - requiresBuild: true + '@rollup/rollup-darwin-arm64@4.65.1': optional: true - /@rollup/rollup-linux-x64-musl@4.62.2: - resolution: {integrity: sha512-uNN83XxQrRAh/w0/pmAfibcwyb6YWt4gP+dpnQKPVJshAloQ785ii8CT8ZCIxkGg9opVsvAlGhFitSm6D1Jjpg==} - cpu: [x64] - os: [linux] - requiresBuild: true + '@rollup/rollup-darwin-x64@4.65.1': optional: true - /@rollup/rollup-openbsd-x64@4.62.2: - resolution: {integrity: sha512-srjEIxSH3LRnJN6THczDHWQplqEMFiAJrTab0msUryh9kwNpkICf3Ea6q6MN/2cZwRFUNx5w+h6Hpi4QuHS6Zg==} - cpu: [x64] - os: [openbsd] - requiresBuild: true + '@rollup/rollup-freebsd-arm64@4.65.1': optional: true - /@rollup/rollup-openharmony-arm64@4.62.2: - resolution: {integrity: sha512-8hOJnxgbyObnCm5AlRA3A931xX19xq80RjVTKgJOvEKWqJruP/Uf12IbAOaDjjEXYRewwHLfmF0YRIdK3OwKWA==} - cpu: [arm64] - os: [openharmony] - requiresBuild: true + '@rollup/rollup-freebsd-x64@4.65.1': optional: true - /@rollup/rollup-win32-arm64-msvc@4.62.2: - resolution: {integrity: sha512-mmF4AY1i0hG/bLWUctUq59gtmgaSIRa3cu/A3JFRp/sCNEme2bgDEiDS22P9FbnJB8NJNF4jPJiSP5RHQpUTDg==} - cpu: [arm64] - os: [win32] - requiresBuild: true + '@rollup/rollup-linux-arm-gnueabihf@4.65.1': optional: true - /@rollup/rollup-win32-ia32-msvc@4.62.2: - resolution: {integrity: sha512-DZgkknc6jhHrk46V25vbAM0zZkyP0nSDkJB8/dRkLTxv470dOmWDqGoEJl/9A0dFfS7yE3REOwNDxpHwSLSt0Q==} - cpu: [ia32] - os: [win32] - requiresBuild: true + '@rollup/rollup-linux-arm-musleabihf@4.65.1': optional: true - /@rollup/rollup-win32-x64-gnu@4.62.2: - resolution: {integrity: sha512-T6xr6ucWSFto+VGajA8YH26LdpHRuP4YLHEKAtCWvJDOlnmWcDZVCI2Jmjr+IFHDlt2zRaTAKE4tfjTaWLgJBg==} - cpu: [x64] - os: [win32] - requiresBuild: true + '@rollup/rollup-linux-arm64-gnu@4.65.1': optional: true - /@rollup/rollup-win32-x64-msvc@4.62.2: - resolution: {integrity: sha512-BfzEnDJOt9T8M989/lA37EcJgat01wLRnoi5dQf3QzOH7jzpqTAzdDbVfRljVr5r+jzKqpbHeyOfAaXxAd0PAA==} - cpu: [x64] - os: [win32] - requiresBuild: true + '@rollup/rollup-linux-arm64-musl@4.65.1': optional: true - /@smithy/config-resolver@4.6.8: - resolution: {integrity: sha512-jNAgbTd8u1bHkAu9fvIpq2rMVXTVm8DylDM59kUS9J94zBZLcdA7j+Vhc+RYg/8PVlNAPAQTGMjpgPqeYmRzcg==} - engines: {node: '>=18.0.0'} - dependencies: - '@smithy/core': 3.29.3 - tslib: 2.8.1 - dev: false + '@rollup/rollup-linux-loong64-gnu@4.65.1': + optional: true - /@smithy/core@3.29.3: - resolution: {integrity: sha512-L+Ys6ecjk5vwPMAKHBpPKlJ3DkqwNcnfEISXBZIsVvWG/XKXfsAP8mwIYlTeLcd2ElHdesPI8OuOmJSFAPhm6A==} - engines: {node: '>=18.0.0'} - dependencies: - '@smithy/types': 4.16.1 - tslib: 2.8.1 - dev: false + '@rollup/rollup-linux-loong64-musl@4.65.1': + optional: true - /@smithy/credential-provider-imds@4.4.8: - resolution: {integrity: sha512-q9J7JTiXrAhB8sDp4px97uEPT7CwKH61Co78grdNQvU8QZAdiuaSRhP0tUVf2ogy36RZTrlMU1rBmDEH+cnkiA==} - engines: {node: '>=18.0.0'} - dependencies: - '@smithy/core': 3.29.3 - '@smithy/types': 4.16.1 - tslib: 2.8.1 - dev: false + '@rollup/rollup-linux-ppc64-gnu@4.65.1': + optional: true - /@smithy/eventstream-serde-browser@4.4.8: - resolution: {integrity: sha512-2ZZe4NSupcDg2UKLpnsuBEOA9yLbZ9ZmYc64HCYPYbvBHg62P8+FUmzkhvwtXm9uLKM3MoUxHw2WID/QzNOe1Q==} - engines: {node: '>=18.0.0'} - dependencies: - '@smithy/core': 3.29.3 - tslib: 2.8.1 - dev: false + '@rollup/rollup-linux-ppc64-musl@4.65.1': + optional: true - /@smithy/eventstream-serde-config-resolver@4.5.8: - resolution: {integrity: sha512-y08FJiync2Z2r5/srXEjo7GJVVpBHB8iNb5x3nYTaVqbQ9AjnUvU3C/0U00IEE+6g77JQJ66gC6XS+ZrAVLWnQ==} - engines: {node: '>=18.0.0'} - dependencies: - '@smithy/core': 3.29.3 - tslib: 2.8.1 - dev: false + '@rollup/rollup-linux-riscv64-gnu@4.65.1': + optional: true - /@smithy/eventstream-serde-node@4.4.8: - resolution: {integrity: sha512-wm8iDHlXpjmJVL8bcmjsW3mfgn4RVZKh2Wai6Ta1Vp/e+H7n1ZLobeBjFTqcJikbwx9prXz1QJzB5Z1h8YUZWg==} - engines: {node: '>=18.0.0'} - dependencies: - '@smithy/core': 3.29.3 - tslib: 2.8.1 - dev: false + '@rollup/rollup-linux-riscv64-musl@4.65.1': + optional: true - /@smithy/fetch-http-handler@5.6.5: - resolution: {integrity: sha512-SuqeisTyPoiIPtIYru/sGxGyXzmZ+8nnFOhC+qRPglt06Ebd1yH//CDltZB2J/3WBNVhwfUaZ0EtHB3cm2X32g==} - engines: {node: '>=18.0.0'} - dependencies: - '@smithy/core': 3.29.3 - '@smithy/types': 4.16.1 - tslib: 2.8.1 - dev: false + '@rollup/rollup-linux-s390x-gnu@4.65.1': + optional: true - /@smithy/hash-blob-browser@4.4.8: - resolution: {integrity: sha512-2CpwBLTKiO+SDXRET2aCQF4BTA+X7DY9fCk3LE2Vm2HUaRxcIRjfMJWZaUwvPEtPamMQ/ypXZNgSKQhE/geEew==} - engines: {node: '>=18.0.0'} - dependencies: - '@smithy/core': 3.29.3 - tslib: 2.8.1 - dev: false + '@rollup/rollup-linux-x64-gnu@4.65.1': + optional: true - /@smithy/hash-node@4.4.8: - resolution: {integrity: sha512-vJDrMFt3Q02naTTveiv1WFJpI1z6fEs+TH2UdcxNoJhqTFR1YNAz+rhwEDzgKGkqPF/0fhWl6SG6jePB1EgydQ==} - engines: {node: '>=18.0.0'} - dependencies: - '@smithy/core': 3.29.3 - tslib: 2.8.1 - dev: false + '@rollup/rollup-linux-x64-musl@4.65.1': + optional: true - /@smithy/hash-stream-node@4.4.8: - resolution: {integrity: sha512-Ep1oWvzaUI1AcL4uY9WDbCUMhvcuMINIYV/5J1A0LWZyMaitQ/8zX5GD1fAEsEZcX+YSSkEcqhyfYjz394r9Qw==} - engines: {node: '>=18.0.0'} - dependencies: - '@smithy/core': 3.29.3 - tslib: 2.8.1 - dev: false + '@rollup/rollup-openbsd-x64@4.65.1': + optional: true - /@smithy/invalid-dependency@4.4.8: - resolution: {integrity: sha512-xqzcxU2pMl17yQ5bvJbsiiTua/wgt5VluguIOW9kCGCBhBazkwceLj9BlH883K0ASxZAhftvRmp7wTRg1ZbpKg==} - engines: {node: '>=18.0.0'} - dependencies: - '@smithy/core': 3.29.3 - tslib: 2.8.1 - dev: false + '@rollup/rollup-openharmony-arm64@4.65.1': + optional: true - /@smithy/is-array-buffer@2.2.0: - resolution: {integrity: sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==} - engines: {node: '>=14.0.0'} - dependencies: - tslib: 2.8.1 - dev: false + '@rollup/rollup-win32-arm64-msvc@4.65.1': + optional: true - /@smithy/is-array-buffer@4.4.8: - resolution: {integrity: sha512-RoxyFKZVk+UVz51s1PIyjtVUhwTYlAaT78Xpzix7w5gflovJoJO7eqFxWK0Vg3BM3EbPh8NPLlwLPXsiYdBXoA==} - engines: {node: '>=18.0.0'} + '@rollup/rollup-win32-ia32-msvc@4.65.1': + optional: true + + '@rollup/rollup-win32-x64-gnu@4.65.1': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.65.1': + optional: true + + '@shikijs/core@4.5.0': dependencies: - '@smithy/core': 3.29.3 - tslib: 2.8.1 - dev: false + '@shikijs/primitive': 4.5.0 + '@shikijs/types': 4.5.0 + '@shikijs/vscode-textmate': 10.1.0 + '@types/hast': 3.0.5 + hast-util-to-html: 9.0.5 - /@smithy/md5-js@4.4.8: - resolution: {integrity: sha512-fT0Sdjr7cMyb0l13lRr32ItpDiHgMig2w/JFzYqyo7n7MsvXTpCmtCaNXEinm6+xK3Jn9gwiXUVLOkI66xJ9gQ==} - engines: {node: '>=18.0.0'} + '@shikijs/engine-javascript@4.5.0': dependencies: - '@smithy/core': 3.29.3 - tslib: 2.8.1 - dev: false + '@shikijs/types': 4.5.0 + '@shikijs/vscode-textmate': 10.1.0 + oniguruma-to-es: 4.3.6 - /@smithy/middleware-content-length@4.4.8: - resolution: {integrity: sha512-qLNmtCNnB6kdZu5AiC9p7MrPJS9lFOjOKazpuDPkEqAPSAlAKq7ipgoyMLb1CBxi3rzNUcrvjvqo/B0lpsTxIw==} - engines: {node: '>=18.0.0'} + '@shikijs/engine-oniguruma@4.5.0': dependencies: - '@smithy/core': 3.29.3 - tslib: 2.8.1 - dev: false + '@shikijs/types': 4.5.0 + '@shikijs/vscode-textmate': 10.1.0 - /@smithy/middleware-endpoint@4.6.8: - resolution: {integrity: sha512-9tOPEQz4g8Xv1t5UEwL0KmQ6Z4U4WS5Q1EXOSUePGt2pgqOWli7zLxmCFkZtEutZLSsIWtDHwbHyhVfclkMs1Q==} - engines: {node: '>=18.0.0'} + '@shikijs/langs@4.5.0': dependencies: - '@smithy/core': 3.29.3 - tslib: 2.8.1 - dev: false + '@shikijs/types': 4.5.0 - /@smithy/middleware-retry@4.7.8: - resolution: {integrity: sha512-oEPZ4i9E7h5GgtASPr6QoZdt8XCkjcjgj7lhEkWEHnMwUftz9FQ9FGOztek4wnoOuB1LxA6eO+gO1ORAGUeL6A==} - engines: {node: '>=18.0.0'} + '@shikijs/primitive@4.5.0': dependencies: - '@smithy/core': 3.29.3 - tslib: 2.8.1 - dev: false + '@shikijs/types': 4.5.0 + '@shikijs/vscode-textmate': 10.1.0 + '@types/hast': 3.0.5 - /@smithy/middleware-serde@4.4.8: - resolution: {integrity: sha512-qAH6hKorKtjV2lPiEOEB58edF/NvY29twTu1aGOwSQx8lGjhomF+Z7xpBhJH8v4IGUMSP0aUA+N9N4IpE9xpkg==} - engines: {node: '>=18.0.0'} + '@shikijs/themes@4.5.0': dependencies: - '@smithy/core': 3.29.3 - tslib: 2.8.1 - dev: false + '@shikijs/types': 4.5.0 - /@smithy/middleware-stack@4.4.8: - resolution: {integrity: sha512-I8NOxdzliRUdniI4/QTEfXj5jonF2aILJOIGkcV4ZWeqMMP98ySKg4SeiIN1WAnLJUxjHNr7UnMUcPegxFtxMw==} - engines: {node: '>=18.0.0'} + '@shikijs/types@4.5.0': dependencies: - '@smithy/core': 3.29.3 - tslib: 2.8.1 - dev: false + '@shikijs/vscode-textmate': 10.1.0 + '@types/hast': 3.0.5 - /@smithy/node-config-provider@4.5.8: - resolution: {integrity: sha512-Kran9kcysdZdoiVZQ3EXfHTbZ48kJ6Er2sZ4eHaL2LSsqVlucn/8xrgxj36/z9qlrToNGNf+na4u6xp1Nz08KQ==} - engines: {node: '>=18.0.0'} + '@shikijs/vscode-textmate@10.1.0': {} + + '@shuding/opentype.js@1.4.0-beta.0': dependencies: - '@smithy/core': 3.29.3 - tslib: 2.8.1 - dev: false + fflate: 0.7.3 + string.prototype.codepointat: 0.2.1 - /@smithy/node-http-handler@4.9.5: - resolution: {integrity: sha512-bNqdxTQTxmLbomSmlkZFz8L6B/feQ2HHzw4L2zY7Ecp2XffYAZq2uzdWDdxJHJFbEvqd+SRuluJso0P8+xPdbw==} - engines: {node: '>=18.0.0'} + '@sindresorhus/is@7.2.0': {} + + '@smithy/core@3.37.0': dependencies: - '@smithy/core': 3.29.3 - '@smithy/types': 4.16.1 + '@smithy/types': 4.19.0 tslib: 2.8.1 - dev: false - /@smithy/property-provider@4.4.8: - resolution: {integrity: sha512-1K3cVMiSnjiy4ht6+WmmevAOuYVwbrfSvKtIaoaK4brpERrv9B4dediHo1N1upvx2brt+s84e1SmAeCQm8hMqQ==} - engines: {node: '>=18.0.0'} + '@smithy/credential-provider-imds@4.5.2': dependencies: - '@smithy/core': 3.29.3 + '@smithy/core': 3.37.0 + '@smithy/types': 4.19.0 tslib: 2.8.1 - dev: false - /@smithy/protocol-http@5.5.8: - resolution: {integrity: sha512-SyFyL/ajuzJ79W+BpseFFbSz8/Rwj+QGqUlayeZE0jS2aCcjzV5tJBcbHgfypvSHpe7s2JmUHZmfpICaxwEs5g==} - engines: {node: '>=18.0.0'} + '@smithy/fetch-http-handler@5.8.0': dependencies: - '@smithy/core': 3.29.3 + '@smithy/core': 3.37.0 + '@smithy/types': 4.19.0 tslib: 2.8.1 - dev: false - /@smithy/querystring-builder@4.4.8: - resolution: {integrity: sha512-BF7L8ELX66L6g/WGWz0eAocp4i7xx51WbyDEnVffYP/s8q/+uFSCBpcOQlZGIQxpSrrhJnlBbS/xkIxYJKj+hg==} - engines: {node: '>=18.0.0'} + '@smithy/node-http-handler@4.13.0': dependencies: - '@smithy/core': 3.29.3 + '@smithy/core': 3.37.0 + '@smithy/types': 4.19.0 tslib: 2.8.1 - dev: false - /@smithy/shared-ini-file-loader@4.6.8: - resolution: {integrity: sha512-zsd1RYVrnWcByRhYrSYcDKCV9MfU5o33uSaksVkVgaeS6QMm6PMEa1AhKX0zrQrwsFVfpwhIbA3nxnFOLf61CA==} - engines: {node: '>=18.0.0'} + '@smithy/signature-v4@5.7.4': dependencies: - '@smithy/core': 3.29.3 + '@smithy/core': 3.37.0 + '@smithy/types': 4.19.0 tslib: 2.8.1 - dev: false - /@smithy/signature-v4@5.6.4: - resolution: {integrity: sha512-B89bpf2t/y/wia6LZ+4JfHXYQT9PnVftsH05rgJKKIStS7r/4XSs9HOjtPoLtgcA6HCW9jVqX5DBbq7E0PAkiQ==} - engines: {node: '>=18.0.0'} + '@smithy/types@4.19.0': dependencies: - '@smithy/core': 3.29.3 - '@smithy/types': 4.16.1 tslib: 2.8.1 - dev: false - /@smithy/smithy-client@4.14.8: - resolution: {integrity: sha512-hnZ6wFwLHQYL/+wdvT6qD1Fkiclobv7Y3iBB2fyfr+osJcD5n4IMAOPaIFUj7WgxOwU/e13FubyebUigzMLXCQ==} - engines: {node: '>=18.0.0'} + '@speed-highlight/core@1.2.24': {} + + '@standard-schema/spec@1.1.0': {} + + '@swc/counter@0.1.3': {} + + '@swc/helpers@0.5.23': dependencies: - '@smithy/core': 3.29.3 - '@smithy/types': 4.16.1 tslib: 2.8.1 - dev: false - /@smithy/types@4.16.1: - resolution: {integrity: sha512-0JFs3V2y2M9tKW5na/qxe69Zv+uxLMO7QBbhxF/FHu/Gp2NFZAAL9tWl9PU02xxo07pb3G9FTyjNc6D5uZrJIg==} - engines: {node: '>=18.0.0'} + '@swc/helpers@0.5.5': dependencies: + '@swc/counter': 0.1.3 tslib: 2.8.1 - dev: false - /@smithy/url-parser@4.4.8: - resolution: {integrity: sha512-BcniaGClLgBsy5Jf7dfkoId8B4n/8oL3xBzVeF1/I252yZvyrxyKG7ZvcfCGTGEahSigsz40ujf6R/3G1U0kig==} - engines: {node: '>=18.0.0'} + '@tailwindcss/node@4.3.3': dependencies: - '@smithy/core': 3.29.3 - tslib: 2.8.1 - dev: false + '@jridgewell/remapping': 2.3.5 + enhanced-resolve: 5.26.0 + jiti: 2.7.0 + lightningcss: 1.32.0 + magic-string: 0.30.21 + source-map-js: 1.2.2 + tailwindcss: 4.3.3 - /@smithy/util-base64@4.5.8: - resolution: {integrity: sha512-vJ3w2vD2BzEGbnMfaBcrtPXi37IUtG9qQgVasMRiF+Ef+0S5fMgaEFcwBGYg7RkN7wKBAcg2r+ulF/4aj3+VYw==} - engines: {node: '>=18.0.0'} + '@tailwindcss/oxide-android-arm64@4.3.3': + optional: true + + '@tailwindcss/oxide-darwin-arm64@4.3.3': + optional: true + + '@tailwindcss/oxide-darwin-x64@4.3.3': + optional: true + + '@tailwindcss/oxide-freebsd-x64@4.3.3': + optional: true + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.3.3': + optional: true + + '@tailwindcss/oxide-linux-arm64-gnu@4.3.3': + optional: true + + '@tailwindcss/oxide-linux-arm64-musl@4.3.3': + optional: true + + '@tailwindcss/oxide-linux-x64-gnu@4.3.3': + optional: true + + '@tailwindcss/oxide-linux-x64-musl@4.3.3': + optional: true + + '@tailwindcss/oxide-wasm32-wasi@4.3.3': + optional: true + + '@tailwindcss/oxide-win32-arm64-msvc@4.3.3': + optional: true + + '@tailwindcss/oxide-win32-x64-msvc@4.3.3': + optional: true + + '@tailwindcss/oxide@4.3.3': + optionalDependencies: + '@tailwindcss/oxide-android-arm64': 4.3.3 + '@tailwindcss/oxide-darwin-arm64': 4.3.3 + '@tailwindcss/oxide-darwin-x64': 4.3.3 + '@tailwindcss/oxide-freebsd-x64': 4.3.3 + '@tailwindcss/oxide-linux-arm-gnueabihf': 4.3.3 + '@tailwindcss/oxide-linux-arm64-gnu': 4.3.3 + '@tailwindcss/oxide-linux-arm64-musl': 4.3.3 + '@tailwindcss/oxide-linux-x64-gnu': 4.3.3 + '@tailwindcss/oxide-linux-x64-musl': 4.3.3 + '@tailwindcss/oxide-wasm32-wasi': 4.3.3 + '@tailwindcss/oxide-win32-arm64-msvc': 4.3.3 + '@tailwindcss/oxide-win32-x64-msvc': 4.3.3 + + '@tailwindcss/postcss@4.3.3': + dependencies: + '@alloc/quick-lru': 5.3.0 + '@tailwindcss/node': 4.3.3 + '@tailwindcss/oxide': 4.3.3 + postcss: 8.5.32 + tailwindcss: 4.3.3 + + '@turbo/darwin-64@2.11.10': + optional: true + + '@turbo/darwin-arm64@2.11.10': + optional: true + + '@turbo/gen@2.11.10(@types/node@20.14.11)': dependencies: - '@smithy/core': 3.29.3 - tslib: 2.8.1 - dev: false + '@inquirer/prompts': 7.10.1(@types/node@20.14.11) + esbuild: 0.28.2 + transitivePeerDependencies: + - '@types/node' - /@smithy/util-body-length-browser@4.4.8: - resolution: {integrity: sha512-o6rhfnt15hwj2/1KjQ0PsvdEpxG9TYzR8pk6K0XnrtUDCJcWREq6uCSVHboRsOdghdp3zaVY5CfYV+wUvDUdrg==} - engines: {node: '>=18.0.0'} + '@turbo/linux-64@2.11.10': + optional: true + + '@turbo/linux-arm64@2.11.10': + optional: true + + '@turbo/windows-64@2.11.10': + optional: true + + '@turbo/windows-arm64@2.11.10': + optional: true + + '@types/chai@5.2.3': dependencies: - '@smithy/core': 3.29.3 - tslib: 2.8.1 - dev: false + '@types/deep-eql': 4.0.2 + assertion-error: 2.0.1 - /@smithy/util-body-length-node@4.4.8: - resolution: {integrity: sha512-HoShD7ykB2wBA98UyyKGLUUKmsHovubDzGmCmpMemrTCICKHdfMsUyngJFEPEiJ2ujtRDEgpQD04cDOYY9u9rQ==} - engines: {node: '>=18.0.0'} + '@types/debug@4.1.13': dependencies: - '@smithy/core': 3.29.3 - tslib: 2.8.1 - dev: false + '@types/ms': 2.1.0 - /@smithy/util-buffer-from@2.2.0: - resolution: {integrity: sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==} - engines: {node: '>=14.0.0'} + '@types/deep-eql@4.0.2': {} + + '@types/emscripten@1.41.6': {} + + '@types/esrecurse@4.3.1': {} + + '@types/estree-jsx@1.0.5': dependencies: - '@smithy/is-array-buffer': 2.2.0 - tslib: 2.8.1 - dev: false + '@types/estree': 1.0.9 - /@smithy/util-config-provider@4.4.8: - resolution: {integrity: sha512-OjkEu21jGJ5dI0PUoiSRjhmQJwXxnQbk3GDUoNkAADYsJFjx24PahQtIXYZuG+1tE/Y6Qpiqhz3xCz/yhpA4TA==} - engines: {node: '>=18.0.0'} + '@types/estree@1.0.9': {} + + '@types/hast@3.0.5': dependencies: - '@smithy/core': 3.29.3 - tslib: 2.8.1 - dev: false + '@types/unist': 3.0.3 - /@smithy/util-defaults-mode-browser@4.5.8: - resolution: {integrity: sha512-QjnRq1unlnaEq+z8ksNzg8Q6+IozO6z9QxyZXCKcarJquEfbqq4NZ2XQgYlCgQWK8f6GOyCdw84ju9E6GJDj9Q==} - engines: {node: '>=18.0.0'} + '@types/json-schema@7.0.15': {} + + '@types/mdast@4.0.4': dependencies: - '@smithy/core': 3.29.3 - tslib: 2.8.1 - dev: false + '@types/unist': 3.0.3 - /@smithy/util-defaults-mode-node@4.4.8: - resolution: {integrity: sha512-xNA1Wfkpq8yQmICs1RyXze+ZUKrRP1YlTqDXFE9YAMUeDy+rTuTx/Id5NRzWpkTYqW7205VAHcy6lu/13JAEbg==} - engines: {node: '>=18.0.0'} + '@types/mdx@2.0.14': {} + + '@types/ms@2.1.0': {} + + '@types/node@20.14.11': dependencies: - '@smithy/core': 3.29.3 - tslib: 2.8.1 - dev: false + undici-types: 5.26.5 - /@smithy/util-endpoints@3.6.8: - resolution: {integrity: sha512-KbkiYv00N9RbQVMm/k9ftoC9jWqCf+h9NBVN+ekbRKs5B+Dtzzkwhgfe1a+bn6ftaIkTF0V0d5IqGLb2ZL6Cvg==} - engines: {node: '>=18.0.0'} + '@types/node@22.18.6': dependencies: - '@smithy/core': 3.29.3 - tslib: 2.8.1 - dev: false + undici-types: 6.21.0 - /@smithy/util-middleware@4.4.8: - resolution: {integrity: sha512-+N4NUzQgfqSwj9weJMcdnTXc9qEKOm/3XgRApX2G0eLU/fWt22GXdVxEBobZXU20OglTAOMuiUiiyEQoJ693bw==} - engines: {node: '>=18.0.0'} + '@types/node@26.6.5': dependencies: - '@smithy/core': 3.29.3 - tslib: 2.8.1 - dev: false + undici-types: 8.9.0 - /@smithy/util-retry@4.5.8: - resolution: {integrity: sha512-fPHkNhF3rt3mJHarO7aKfBmGLMnu2NNfGlfCPm/EUNHPGkrdzsdIsPXEgjd+RSEt6FpI93wlMH1XdtaG/XdWWQ==} - engines: {node: '>=18.0.0'} + '@types/prop-types@15.7.15': {} + + '@types/react-dom@18.3.0': dependencies: - '@smithy/core': 3.29.3 - tslib: 2.8.1 - dev: false + '@types/react': 19.3.0 - /@smithy/util-stream@4.7.8: - resolution: {integrity: sha512-YmIDkEKLkHEqqYK5AnaBtyS3jCSEIyRaAm9u7sPrYQHUGGQUjfpWT+KdyEBQnKeVpXQnIlG3GKIY2sdpv4xVpA==} - engines: {node: '>=18.0.0'} + '@types/react-dom@19.3.0(@types/react@19.3.0)': dependencies: - '@smithy/core': 3.29.3 - tslib: 2.8.1 - dev: false + '@types/react': 19.3.0 - /@smithy/util-utf8@2.3.0: - resolution: {integrity: sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==} - engines: {node: '>=14.0.0'} + '@types/react@18.3.3': dependencies: - '@smithy/util-buffer-from': 2.2.0 - tslib: 2.8.1 - dev: false + '@types/prop-types': 15.7.15 + csstype: 3.2.3 - /@smithy/util-utf8@4.4.8: - resolution: {integrity: sha512-hwVELJTTRUqwrEvMI73PwsP27cO1HgkAKDoKelhMS3biTd8z5iXj76UF7oemuDba3X5eHZqjedeyBUhJLns+Kg==} - engines: {node: '>=18.0.0'} + '@types/react@19.3.0': dependencies: - '@smithy/core': 3.29.3 - tslib: 2.8.1 - dev: false + csstype: 3.2.3 - /@smithy/util-waiter@4.5.8: - resolution: {integrity: sha512-NIDD7WY1PrRDNvI80N1dBTDZQ4vAiYln8zfbJ5dfZmtlqyP7aJNJqtuaZQXWd5mqy+NZKUvp+FgnEq2Hm4ebXA==} - engines: {node: '>=18.0.0'} + '@types/unist@2.0.11': {} + + '@types/unist@3.0.3': {} + + '@types/ws@8.18.2': dependencies: - '@smithy/core': 3.29.3 - tslib: 2.8.1 - dev: false + '@types/node': 22.18.6 - /@standard-schema/spec@1.1.0: - resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} - dev: false + '@typescript/typescript-aix-ppc64@7.0.2': + optional: true - /@swc/counter@0.1.3: - resolution: {integrity: sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==} + '@typescript/typescript-darwin-arm64@7.0.2': + optional: true + + '@typescript/typescript-darwin-x64@7.0.2': + optional: true + + '@typescript/typescript-freebsd-arm64@7.0.2': + optional: true + + '@typescript/typescript-freebsd-x64@7.0.2': + optional: true + + '@typescript/typescript-linux-arm64@7.0.2': + optional: true - /@swc/helpers@0.5.5: - resolution: {integrity: sha512-KGYxvIOXcceOAbEk4bi/dVLEK9z8sZ0uBB3Il5b1rhfClSpcX0yfRO0KmTkqR2cnQDymwLB+25ZyMzICg/cm/A==} - dependencies: - '@swc/counter': 0.1.3 - tslib: 2.8.1 + '@typescript/typescript-linux-arm@7.0.2': + optional: true - /@tootallnate/quickjs-emscripten@0.23.0: - resolution: {integrity: sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==} - dev: true + '@typescript/typescript-linux-loong64@7.0.2': + optional: true - /@tsconfig/node10@1.0.12: - resolution: {integrity: sha512-UCYBaeFvM11aU2y3YPZ//O5Rhj+xKyzy7mvcIoAjASbigy8mHMryP5cK7dgjlz2hWxh1g5pLw084E0a/wlUSFQ==} - dev: true + '@typescript/typescript-linux-mips64el@7.0.2': + optional: true - /@tsconfig/node12@1.0.11: - resolution: {integrity: sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==} - dev: true + '@typescript/typescript-linux-ppc64@7.0.2': + optional: true - /@tsconfig/node14@1.0.3: - resolution: {integrity: sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==} - dev: true + '@typescript/typescript-linux-riscv64@7.0.2': + optional: true - /@tsconfig/node16@1.0.4: - resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==} - dev: true + '@typescript/typescript-linux-s390x@7.0.2': + optional: true - /@turbo/gen@2.0.9(@types/node@20.14.11)(typescript@5.9.3): - resolution: {integrity: sha512-IVCBa/+qxsO7srAvFpto0AF09Zei+zpDoosUsHSEwgn/22rVuZ6hdcJdxcQ9kHeMafJpxqLK9iHNSdXUctJ0Vw==} - hasBin: true - dependencies: - '@turbo/workspaces': 2.0.9(@types/node@20.14.11) - commander: 10.0.1 - fs-extra: 10.1.0 - inquirer: 8.2.7(@types/node@20.14.11) - minimatch: 9.0.9 - node-plop: 0.26.3 - picocolors: 1.0.1 - proxy-agent: 6.5.0 - ts-node: 10.9.2(@types/node@20.14.11)(typescript@5.9.3) - update-check: 1.5.4 - validate-npm-package-name: 5.0.1 - transitivePeerDependencies: - - '@swc/core' - - '@swc/wasm' - - '@types/node' - - supports-color - - typescript - dev: true + '@typescript/typescript-linux-x64@7.0.2': + optional: true - /@turbo/workspaces@2.0.9(@types/node@20.14.11): - resolution: {integrity: sha512-+OTrQULhuv1qOKE+0DC360sSDB6ad7opEKLGFcLlmLgM7D75qv6UThfnw1Rjh8inIlBSSCCu/co2BaJjgkkpAw==} - hasBin: true - dependencies: - commander: 10.0.1 - execa: 5.1.1 - fast-glob: 3.3.3 - fs-extra: 10.1.0 - gradient-string: 2.0.2 - inquirer: 8.2.7(@types/node@20.14.11) - js-yaml: 4.3.0 - ora: 4.1.1 - picocolors: 1.0.1 - rimraf: 3.0.2 - semver: 7.8.5 - update-check: 1.5.4 - transitivePeerDependencies: - - '@types/node' - dev: true + '@typescript/typescript-netbsd-arm64@7.0.2': + optional: true - /@types/chai@5.2.3: - resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==} - dependencies: - '@types/deep-eql': 4.0.2 - assertion-error: 2.0.1 + '@typescript/typescript-netbsd-x64@7.0.2': + optional: true - /@types/deep-eql@4.0.2: - resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} + '@typescript/typescript-openbsd-arm64@7.0.2': + optional: true - /@types/dom-webcodecs@0.1.11: - resolution: {integrity: sha512-yPEZ3z7EohrmOxbk/QTAa0yonMFkNkjnVXqbGb7D4rMr+F1dGQ8ZUFxXkyLLJuiICPejZ0AZE9Rrk9wUCczx4A==} - dev: false + '@typescript/typescript-openbsd-x64@7.0.2': + optional: true - /@types/emscripten@1.41.5: - resolution: {integrity: sha512-cMQm7pxu6BxtHyqJ7mQZ2kXWV5SLmugybFdHCBbJ5eHzOo6VhBckEgAT3//rP5FwPHNPeEiq4SmQ5ucBwsOo4Q==} - dev: false + '@typescript/typescript-sunos-x64@7.0.2': + optional: true - /@types/estree@1.0.9: - resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==} + '@typescript/typescript-win32-arm64@7.0.2': + optional: true - /@types/glob@7.2.0: - resolution: {integrity: sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==} - dependencies: - '@types/minimatch': 6.0.0 - '@types/node': 22.18.6 - dev: true + '@typescript/typescript-win32-x64@7.0.2': + optional: true - /@types/inquirer@6.5.0: - resolution: {integrity: sha512-rjaYQ9b9y/VFGOpqBEXRavc3jh0a+e6evAbI31tMda8VlPaSy0AZJfXsvmIe3wklc7W6C3zCSfleuMXR7NOyXw==} - dependencies: - '@types/through': 0.0.33 - rxjs: 6.6.7 - dev: true + '@ungap/structured-clone@1.4.0': {} - /@types/minimatch@6.0.0: - resolution: {integrity: sha512-zmPitbQ8+6zNutpwgcQuLcsEpn/Cj54Kbn7L5pX0Os5kdWplB7xPgEh/g+SWOB/qmows2gpuCaPyduq8ZZRnxA==} - deprecated: This is a stub types definition. minimatch provides its own type definitions, so you do not need this installed. + '@unpic/core@1.0.3': dependencies: - minimatch: 9.0.9 - dev: true + unpic: 4.2.2 - /@types/node@20.14.11: - resolution: {integrity: sha512-kprQpL8MMeszbz6ojB5/tU8PLN4kesnN8Gjzw349rDlNgsSzg90lAVj3llK99Dh7JON+t9AuscPPFW6mPbTnSA==} + '@unpic/react@1.0.2(next@14.2.35(@playwright/test@1.64.1)(@types/react@19.3.0)(react-dom@19.3.1(react@19.3.1))(react@19.3.1))(react-dom@19.3.1(react@19.3.1))(react@19.3.1)': dependencies: - undici-types: 5.26.5 - dev: true + '@unpic/core': 1.0.3 + react: 19.3.1 + react-dom: 19.3.1(react@19.3.1) + optionalDependencies: + next: 14.2.35(@playwright/test@1.64.1)(@types/react@19.3.0)(react-dom@19.3.1(react@19.3.1))(react@19.3.1) - /@types/node@22.18.6: - resolution: {integrity: sha512-r8uszLPpeIWbNKtvWRt/DbVi5zbqZyj1PTmhRMqBMvDnaz1QpmSKujUtJLrqGZeoM8v72MfYggDceY4K1itzWQ==} + '@vercel/og@1.0.3(@types/node@22.18.6)': dependencies: - undici-types: 6.21.0 - - /@types/prop-types@15.7.15: - resolution: {integrity: sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==} + '@resvg/resvg-wasm': 2.4.1 + satori: 0.33.5 + optionalDependencies: + sharp: 0.35.5(@types/node@22.18.6) + transitivePeerDependencies: + - '@types/node' - /@types/react-dom@18.3.0: - resolution: {integrity: sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg==} - dependencies: - '@types/react': 18.3.3 + '@vinext/types@1.0.2': {} - /@types/react@18.3.3: - resolution: {integrity: sha512-hti/R0pS0q1/xx+TsI73XIqk26eBsISZ2R0wUijXIngRK9R/e7Xw/cXVxQK7R5JjW+SV4zGcn5hXjudkN/pLIw==} + '@vitejs/plugin-react@6.0.1(vite@8.3.4(@types/node@22.18.6)(esbuild@0.28.2)(jiti@2.4.2)(terser@5.51.2)(yaml@2.9.1))': dependencies: - '@types/prop-types': 15.7.15 - csstype: 3.2.3 + '@rolldown/pluginutils': 1.0.0-rc.7 + vite: 8.3.4(@types/node@22.18.6)(esbuild@0.28.2)(jiti@2.4.2)(terser@5.51.2)(yaml@2.9.1) - /@types/through@0.0.33: - resolution: {integrity: sha512-HsJ+z3QuETzP3cswwtzt2vEIiHBk/dCcHGhbmG5X3ecnwFD/lPrMpliGXxSCg03L9AhrdwA4Oz/qfspkDW+xGQ==} + '@vitejs/plugin-rsc@0.5.38(react-dom@19.3.1(react@19.3.1))(react-server-dom-webpack@19.3.1(react-dom@19.3.1(react@19.3.1))(react@19.3.1)(webpack@5.112.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.4.39)(sharp@0.35.5(@types/node@22.18.6))))(react@19.3.1)(vite@8.3.4(@types/node@22.18.6)(esbuild@0.28.2)(jiti@2.4.2)(terser@5.51.2)(yaml@2.9.1))': dependencies: - '@types/node': 22.18.6 - dev: true - - /@types/tinycolor2@1.4.6: - resolution: {integrity: sha512-iEN8J0BoMnsWBqjVbWH/c0G0Hh7O21lpR2/+PrvAVgWdzL7eexIFm4JN/Wn10PTcmNdtS6U67r499mlWMXOxNw==} - dev: true + '@rolldown/pluginutils': 1.0.1 + es-module-lexer: 3.0.4 + estree-walker: 3.0.3 + magic-string: 1.4.4 + obug: 3.0.0 + react: 19.3.1 + react-dom: 19.3.1(react@19.3.1) + srvx: 1.0.7 + strip-literal: 4.0.0 + turbo-stream: 3.2.1 + vite: 8.3.4(@types/node@22.18.6)(esbuild@0.28.2)(jiti@2.4.2)(terser@5.51.2)(yaml@2.9.1) + vitefu: 1.1.3(vite@8.3.4(@types/node@22.18.6)(esbuild@0.28.2)(jiti@2.4.2)(terser@5.51.2)(yaml@2.9.1)) + optionalDependencies: + react-server-dom-webpack: 19.3.1(react-dom@19.3.1(react@19.3.1))(react@19.3.1)(webpack@5.112.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.4.39)(sharp@0.35.5(@types/node@22.18.6))) - /@vitest/expect@3.2.4: - resolution: {integrity: sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==} + '@vitest/expect@3.2.7': dependencies: '@types/chai': 5.2.3 - '@vitest/spy': 3.2.4 - '@vitest/utils': 3.2.4 + '@vitest/spy': 3.2.7 + '@vitest/utils': 3.2.7 chai: 5.3.3 tinyrainbow: 2.0.0 - /@vitest/mocker@3.2.4(vite@7.3.6): - resolution: {integrity: sha512-46ryTE9RZO/rfDd7pEqFl7etuyzekzEhUbTW3BvmeO/BcCMEgq59BKhek3dXDWgAj4oMK6OZi+vRr1wPW6qjEQ==} - peerDependencies: - msw: ^2.4.9 - vite: ^5.0.0 || ^6.0.0 || ^7.0.0-0 - peerDependenciesMeta: - msw: - optional: true - vite: - optional: true + '@vitest/mocker@3.2.7(vite@7.3.7(@types/node@20.14.11)(jiti@2.7.0)(lightningcss@1.33.0)(terser@5.51.2)(yaml@2.9.1))': dependencies: - '@vitest/spy': 3.2.4 + '@vitest/spy': 3.2.7 estree-walker: 3.0.3 magic-string: 0.30.21 - vite: 7.3.6(@types/node@22.18.6)(jiti@2.4.2) + optionalDependencies: + vite: 7.3.7(@types/node@20.14.11)(jiti@2.7.0)(lightningcss@1.33.0)(terser@5.51.2)(yaml@2.9.1) - /@vitest/pretty-format@3.2.4: - resolution: {integrity: sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==} + '@vitest/mocker@3.2.7(vite@7.3.7(@types/node@22.18.6)(jiti@2.4.2)(lightningcss@1.33.0)(terser@5.51.2)(yaml@2.9.1))': dependencies: - tinyrainbow: 2.0.0 + '@vitest/spy': 3.2.7 + estree-walker: 3.0.3 + magic-string: 0.30.21 + optionalDependencies: + vite: 7.3.7(@types/node@22.18.6)(jiti@2.4.2)(lightningcss@1.33.0)(terser@5.51.2)(yaml@2.9.1) - /@vitest/pretty-format@3.2.7: - resolution: {integrity: sha512-KUHlwqVu0sRlhCdyPdQ/wBoTfRahjUky1MubOmYw9fWfIZy1gNoHpuaaQBPAaMaVYdQYHJLurzj8ECCj5OwTqA==} + '@vitest/mocker@3.2.7(vite@7.3.7(@types/node@22.18.6)(jiti@2.7.0)(lightningcss@1.33.0)(terser@5.51.2)(yaml@2.9.1))': + dependencies: + '@vitest/spy': 3.2.7 + estree-walker: 3.0.3 + magic-string: 0.30.21 + optionalDependencies: + vite: 7.3.7(@types/node@22.18.6)(jiti@2.7.0)(lightningcss@1.33.0)(terser@5.51.2)(yaml@2.9.1) + + '@vitest/pretty-format@3.2.7': dependencies: tinyrainbow: 2.0.0 - /@vitest/runner@3.2.4: - resolution: {integrity: sha512-oukfKT9Mk41LreEW09vt45f8wx7DordoWUZMYdY/cyAk7w5TWkTRCNZYF7sX7n2wB7jyGAl74OxgwhPgKaqDMQ==} + '@vitest/runner@3.2.7': dependencies: - '@vitest/utils': 3.2.4 + '@vitest/utils': 3.2.7 pathe: 2.0.3 strip-literal: 3.1.0 - /@vitest/snapshot@3.2.4: - resolution: {integrity: sha512-dEYtS7qQP2CjU27QBC5oUOxLE/v5eLkGqPE0ZKEIDGMs4vKWe7IjgLOeauHsR0D5YuuycGRO5oSRXnwnmA78fQ==} + '@vitest/snapshot@3.2.7': dependencies: - '@vitest/pretty-format': 3.2.4 + '@vitest/pretty-format': 3.2.7 magic-string: 0.30.21 pathe: 2.0.3 - /@vitest/spy@3.2.4: - resolution: {integrity: sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw==} + '@vitest/spy@3.2.7': dependencies: - tinyspy: 4.0.4 + tinyspy: 4.0.6 - /@vitest/utils@3.2.4: - resolution: {integrity: sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==} + '@vitest/utils@3.2.7': dependencies: - '@vitest/pretty-format': 3.2.4 + '@vitest/pretty-format': 3.2.7 loupe: 3.2.1 tinyrainbow: 2.0.0 - /@yudiel/react-qr-scanner@2.1.0(react-dom@18.3.1)(react@18.3.1): - resolution: {integrity: sha512-O3832Qk8YU+vnLO+tsJalfQcXRZ1pOB9l6WrI3OdwpxkQEzukpT48M6Hc2vUUe1rFE6qapQnV3RGRFNM0S7CHw==} - peerDependencies: - react: ^17 || ^18 || ^19 - react-dom: ^17 || ^18 || ^19 + '@webassemblyjs/ast@1.14.1': dependencies: - barcode-detector: 2.3.1 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - webrtc-adapter: 9.0.1 - dev: false + '@webassemblyjs/helper-numbers': 1.13.2 + '@webassemblyjs/helper-wasm-bytecode': 1.13.2 - /acorn-jsx@5.3.2(acorn@8.17.0): - resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} - peerDependencies: - acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + '@webassemblyjs/floating-point-hex-parser@1.13.2': {} + + '@webassemblyjs/helper-api-error@1.13.2': {} + + '@webassemblyjs/helper-buffer@1.14.1': {} + + '@webassemblyjs/helper-numbers@1.13.2': dependencies: - acorn: 8.17.0 - dev: true + '@webassemblyjs/floating-point-hex-parser': 1.13.2 + '@webassemblyjs/helper-api-error': 1.13.2 + '@xtuc/long': 4.2.2 - /acorn-walk@8.3.5: - resolution: {integrity: sha512-HEHNfbars9v4pgpW6SO1KSPkfoS0xVOM/9UzkJltjlsHZmJasxg8aXkuZa7SMf8vKGIBhpUsPluQSqhJFCqebw==} - engines: {node: '>=0.4.0'} + '@webassemblyjs/helper-wasm-bytecode@1.13.2': {} + + '@webassemblyjs/helper-wasm-section@1.14.1': dependencies: - acorn: 8.17.0 - dev: true + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/helper-buffer': 1.14.1 + '@webassemblyjs/helper-wasm-bytecode': 1.13.2 + '@webassemblyjs/wasm-gen': 1.14.1 - /acorn@8.17.0: - resolution: {integrity: sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg==} - engines: {node: '>=0.4.0'} - hasBin: true - dev: true + '@webassemblyjs/ieee754@1.13.2': + dependencies: + '@xtuc/ieee754': 1.2.0 - /agent-base@7.1.4: - resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} - engines: {node: '>= 14'} - dev: true + '@webassemblyjs/leb128@1.13.2': + dependencies: + '@xtuc/long': 4.2.2 - /aggregate-error@3.1.0: - resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==} - engines: {node: '>=8'} + '@webassemblyjs/utf8@1.13.2': {} + + '@webassemblyjs/wasm-edit@1.14.1': dependencies: - clean-stack: 2.2.0 - indent-string: 4.0.0 - dev: true + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/helper-buffer': 1.14.1 + '@webassemblyjs/helper-wasm-bytecode': 1.13.2 + '@webassemblyjs/helper-wasm-section': 1.14.1 + '@webassemblyjs/wasm-gen': 1.14.1 + '@webassemblyjs/wasm-opt': 1.14.1 + '@webassemblyjs/wasm-parser': 1.14.1 + '@webassemblyjs/wast-printer': 1.14.1 - /ajv@6.15.0: - resolution: {integrity: sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==} + '@webassemblyjs/wasm-gen@1.14.1': dependencies: - fast-deep-equal: 3.1.3 - fast-json-stable-stringify: 2.1.0 - json-schema-traverse: 0.4.1 - uri-js: 4.4.1 - dev: true + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/helper-wasm-bytecode': 1.13.2 + '@webassemblyjs/ieee754': 1.13.2 + '@webassemblyjs/leb128': 1.13.2 + '@webassemblyjs/utf8': 1.13.2 - /ansi-escapes@4.3.2: - resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} - engines: {node: '>=8'} + '@webassemblyjs/wasm-opt@1.14.1': dependencies: - type-fest: 0.21.3 - dev: true + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/helper-buffer': 1.14.1 + '@webassemblyjs/wasm-gen': 1.14.1 + '@webassemblyjs/wasm-parser': 1.14.1 - /ansi-regex@5.0.1: - resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} - engines: {node: '>=8'} - dev: true + '@webassemblyjs/wasm-parser@1.14.1': + dependencies: + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/helper-api-error': 1.13.2 + '@webassemblyjs/helper-wasm-bytecode': 1.13.2 + '@webassemblyjs/ieee754': 1.13.2 + '@webassemblyjs/leb128': 1.13.2 + '@webassemblyjs/utf8': 1.13.2 - /ansi-styles@3.2.1: - resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} - engines: {node: '>=4'} + '@webassemblyjs/wast-printer@1.14.1': dependencies: - color-convert: 1.9.3 - dev: true + '@webassemblyjs/ast': 1.14.1 + '@xtuc/long': 4.2.2 - /ansi-styles@4.3.0: - resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} - engines: {node: '>=8'} + '@xtuc/ieee754@1.2.0': {} + + '@xtuc/long@4.2.2': {} + + '@yudiel/react-qr-scanner@2.6.0(@types/emscripten@1.41.6)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - color-convert: 2.0.1 - dev: true + '@types/react': 18.3.3 + barcode-detector: 3.2.3(@types/emscripten@1.41.6) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + webrtc-adapter: 9.0.6 + transitivePeerDependencies: + - '@types/emscripten' - /any-promise@1.3.0: - resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} - dev: true + '@yuku-core/binding-android-arm64@0.19.0': + optional: true - /anymatch@3.1.3: - resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} - engines: {node: '>= 8'} + '@yuku-core/binding-darwin-arm64@0.19.0': + optional: true + + '@yuku-core/binding-darwin-x64@0.19.0': + optional: true + + '@yuku-core/binding-freebsd-x64@0.19.0': + optional: true + + '@yuku-core/binding-linux-arm-gnu@0.19.0': + optional: true + + '@yuku-core/binding-linux-arm-musl@0.19.0': + optional: true + + '@yuku-core/binding-linux-arm64-gnu@0.19.0': + optional: true + + '@yuku-core/binding-linux-arm64-musl@0.19.0': + optional: true + + '@yuku-core/binding-linux-x64-gnu@0.19.0': + optional: true + + '@yuku-core/binding-linux-x64-musl@0.19.0': + optional: true + + '@yuku-core/binding-win32-arm64@0.19.0': + optional: true + + '@yuku-core/binding-win32-x64@0.19.0': + optional: true + + '@yuku-toolchain/types@0.19.0': {} + + '@zeit/schemas@2.36.0': {} + + acorn-jsx@5.3.2(acorn@8.19.0): dependencies: - normalize-path: 3.0.0 - picomatch: 2.3.2 - dev: true + acorn: 8.19.0 - /arg@4.1.3: - resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} - dev: true + acorn-loose@8.5.2: + dependencies: + acorn: 8.19.0 - /arg@5.0.2: - resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} - dev: true + acorn@8.19.0: {} - /argparse@2.0.1: - resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} - dev: true + ajv-formats@3.0.1: + dependencies: + ajv: 8.20.0 - /aria-hidden@1.2.6: - resolution: {integrity: sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==} - engines: {node: '>=10'} + ajv-keywords@5.1.0(ajv@8.20.0): dependencies: - tslib: 2.8.1 - dev: false + ajv: 8.20.0 + fast-deep-equal: 3.1.3 - /array-union@2.1.0: - resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} - engines: {node: '>=8'} - dev: true + ajv@6.15.0: + dependencies: + fast-deep-equal: 3.1.3 + fast-json-stable-stringify: 2.1.0 + json-schema-traverse: 0.4.1 + uri-js: 4.4.1 - /assertion-error@2.0.1: - resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} - engines: {node: '>=12'} + ajv@8.18.0: + dependencies: + fast-deep-equal: 3.1.3 + fast-uri: 3.1.9 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 - /ast-types@0.13.4: - resolution: {integrity: sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==} - engines: {node: '>=4'} + ajv@8.20.0: dependencies: - tslib: 2.8.1 - dev: true + fast-deep-equal: 3.1.3 + fast-uri: 3.1.9 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 - /autoprefixer@10.4.19(postcss@8.4.39): - resolution: {integrity: sha512-BaENR2+zBZ8xXhM4pUaKUxlVdxZ0EZhjvbopwnXmxRUfqDmwSpC2lAi/QXvx7NRdPCo1WKEcEF6mV64si1z4Ew==} - engines: {node: ^10 || ^12 || >=14} - hasBin: true - peerDependencies: - postcss: ^8.1.0 + ansi-align@3.0.1: dependencies: - browserslist: 4.28.5 - caniuse-lite: 1.0.30001803 - fraction.js: 4.3.7 - normalize-range: 0.1.2 - picocolors: 1.1.1 - postcss: 8.4.39 - postcss-value-parser: 4.2.0 - dev: true + string-width: 4.2.3 - /aws-ssl-profiles@1.1.2: - resolution: {integrity: sha512-NZKeq9AfyQvEeNlN0zSYAaWrmBffJh3IELMZfRpJVWgrpEbtEpnjvzqBPf+mxoI287JohRDoa+/nsfqqiZmF6g==} - engines: {node: '>= 6.0.0'} - dev: false + ansi-regex@5.0.1: {} - /balanced-match@1.0.2: - resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - dev: true + ansi-regex@6.4.0: {} - /barcode-detector@2.3.1: - resolution: {integrity: sha512-D9KEtrquS1tmBZduxBZl8qublIKnRrFqD8TAHDYcLCyrHQBo+vitIxmjMJ61LvXjXyAMalOlO7q0Oh/9Rl2PbQ==} + ansi-styles@4.3.0: dependencies: - '@types/dom-webcodecs': 0.1.11 - zxing-wasm: 1.3.4 - dev: false + color-convert: 2.0.1 - /base64-js@1.5.1: - resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} - dev: true + ansi-styles@6.2.3: {} - /baseline-browser-mapping@2.10.42: - resolution: {integrity: sha512-c/jurFrDLyui7o1J86yLkRu4LMsTYcBohveus7/I2Hzdn9KIP2bdJPTue/lR1KH46enoPbD77GKeSYNdyPoD3Q==} - engines: {node: '>=6.0.0'} - hasBin: true - dev: true + any-promise@1.3.0: {} - /basic-ftp@5.3.1: - resolution: {integrity: sha512-bopVNp6ugyA150DDuZfPFdt1KZ5a94ZDiwX4hMgZDzF+GttD80lEy8kj98kbyhLXnPvhtIo93mdnLIjpCAeeOw==} - engines: {node: '>=10.0.0'} - dev: true + anymatch@3.1.3: + dependencies: + normalize-path: 3.0.0 + picomatch: 2.3.2 - /better-auth@1.7.6(next@14.2.35)(pg@8.23.0)(react-dom@18.3.1)(react@18.3.1)(vitest@3.2.4): - resolution: {integrity: sha512-WTMqOpmTTj+oBoX7zzPOzL85342Upyf+/v0IkH1kvGRA85lV4JGRFIYMIRKqvjZ6ShsuL5VX/c9C13jtoZXcKA==} - peerDependencies: - '@lynx-js/react': '*' - '@prisma/client': ^5.0.0 || ^6.0.0 || ^7.0.0 - '@sveltejs/kit': ^2.0.0 - '@tanstack/react-start': ^1.0.0 - '@tanstack/solid-start': ^1.0.0 - drizzle-kit: '>=0.31.4 || >=1.0.0-beta.1' - drizzle-orm: ^0.45.2 || >=1.0.0-rc.1 <2.0.0 - mongodb: ^6.0.0 || ^7.0.0 - mysql2: ^3.0.0 - next: ^14.0.0 || ^15.0.0 || ^16.0.0 - pg: ^8.0.0 - prisma: ^5.0.0 || ^6.0.0 || ^7.0.0 - react: ^18.0.0 || ^19.0.0 - react-dom: ^18.0.0 || ^19.0.0 - solid-js: ^1.0.0 - svelte: ^4.0.0 || ^5.0.0 - vitest: ^2.0.0 || ^3.0.0 || ^4.0.0 || ^5.0.0 - vue: ^3.0.0 - peerDependenciesMeta: - '@lynx-js/react': - optional: true - '@prisma/client': - optional: true - '@sveltejs/kit': - optional: true - '@tanstack/react-start': - optional: true - '@tanstack/solid-start': - optional: true - drizzle-kit: - optional: true - drizzle-orm: - optional: true - mongodb: - optional: true - mysql2: - optional: true - next: - optional: true - pg: - optional: true - prisma: - optional: true - react: - optional: true - react-dom: - optional: true - solid-js: - optional: true - svelte: - optional: true - vitest: - optional: true - vue: - optional: true + arch@2.2.0: {} + + arg@5.0.2: {} + + aria-hidden@1.2.6: + dependencies: + tslib: 2.8.1 + + assertion-error@2.0.1: {} + + astring@1.9.0: {} + + autoprefixer@10.4.19(postcss@8.4.39): + dependencies: + browserslist: 4.29.5 + caniuse-lite: 1.0.30001819 + fraction.js: 4.3.7 + normalize-range: 0.1.2 + picocolors: 1.1.1 + postcss: 8.4.39 + postcss-value-parser: 4.2.0 + + aws-ssl-profiles@1.1.2: {} + + bail@2.0.2: {} + + balanced-match@1.0.2: {} + + balanced-match@4.0.4: {} + + barcode-detector@3.2.3(@types/emscripten@1.41.6): + dependencies: + zxing-wasm: 3.1.6(@types/emscripten@1.41.6) + transitivePeerDependencies: + - '@types/emscripten' + + base64-js@0.0.8: {} + + baseline-browser-mapping@2.11.33: {} + + better-auth@1.7.6(mysql2@3.24.4(@types/node@20.14.11))(next@16.4.2(@playwright/test@1.64.1)(@types/node@20.14.11)(react-dom@19.3.1(react@19.3.1))(react@19.3.1))(pg@8.23.0)(react-dom@19.3.1(react@19.3.1))(react@19.3.1)(vitest@3.2.7(@types/debug@4.1.13)(@types/node@20.14.11)(jiti@2.7.0)(lightningcss@1.33.0)(supports-color@10.2.2)(terser@5.51.2)(yaml@2.9.1)): + dependencies: + '@better-auth/core': 1.7.6(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@3.25.76))(jose@6.2.13)(kysely@0.29.6)(nanostores@1.5.5) + '@better-auth/drizzle-adapter': 1.7.6(@better-auth/core@1.7.6(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.6.7))(jose@6.2.13)(kysely@0.29.6)(nanostores@1.5.5))(@better-auth/utils@0.4.2) + '@better-auth/kysely-adapter': 1.7.6(@better-auth/core@1.7.6(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.6.7))(jose@6.2.13)(kysely@0.29.6)(nanostores@1.5.5))(@better-auth/utils@0.4.2)(kysely@0.29.6) + '@better-auth/memory-adapter': 1.7.6(@better-auth/core@1.7.6(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.6.7))(jose@6.2.13)(kysely@0.29.6)(nanostores@1.5.5))(@better-auth/utils@0.4.2) + '@better-auth/mongo-adapter': 1.7.6(@better-auth/core@1.7.6(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.6.7))(jose@6.2.13)(kysely@0.29.6)(nanostores@1.5.5))(@better-auth/utils@0.4.2) + '@better-auth/prisma-adapter': 1.7.6(@better-auth/core@1.7.6(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.6.7))(jose@6.2.13)(kysely@0.29.6)(nanostores@1.5.5))(@better-auth/utils@0.4.2) + '@better-auth/telemetry': 1.7.6(@better-auth/core@1.7.6(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.6.7))(jose@6.2.13)(kysely@0.29.6)(nanostores@1.5.5))(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2) + '@better-auth/utils': 0.4.2 + '@better-fetch/fetch': 1.3.2 + '@noble/ciphers': 2.4.0 + '@noble/hashes': 2.4.0 + better-call: 1.4.0(zod@4.6.7) + defu: 6.1.7 + jose: 6.2.13 + kysely: 0.29.6 + nanostores: 1.5.5 + zod: 4.6.7 + optionalDependencies: + mysql2: 3.24.4(@types/node@20.14.11) + next: 16.4.2(@playwright/test@1.64.1)(@types/node@20.14.11)(react-dom@19.3.1(react@19.3.1))(react@19.3.1) + pg: 8.23.0 + react: 19.3.1 + react-dom: 19.3.1(react@19.3.1) + vitest: 3.2.7(@types/debug@4.1.13)(@types/node@20.14.11)(jiti@2.7.0)(lightningcss@1.33.0)(supports-color@10.2.2)(terser@5.51.2)(yaml@2.9.1) + transitivePeerDependencies: + - '@opentelemetry/api' + + better-auth@1.7.6(mysql2@3.24.4(@types/node@22.18.6))(next@14.2.35(@playwright/test@1.64.1)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(pg@8.23.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(vitest@3.2.7(@types/debug@4.1.13)(@types/node@22.18.6)(jiti@2.4.2)(lightningcss@1.33.0)(supports-color@10.2.2)(terser@5.51.2)(yaml@2.9.1)): dependencies: - '@better-auth/core': 1.7.6(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0)(jose@6.2.3)(kysely@0.29.6)(nanostores@1.4.0) - '@better-auth/drizzle-adapter': 1.7.6(@better-auth/core@1.7.6)(@better-auth/utils@0.4.2) - '@better-auth/kysely-adapter': 1.7.6(@better-auth/core@1.7.6)(@better-auth/utils@0.4.2)(kysely@0.29.6) - '@better-auth/memory-adapter': 1.7.6(@better-auth/core@1.7.6)(@better-auth/utils@0.4.2) - '@better-auth/mongo-adapter': 1.7.6(@better-auth/core@1.7.6)(@better-auth/utils@0.4.2) - '@better-auth/prisma-adapter': 1.7.6(@better-auth/core@1.7.6)(@better-auth/utils@0.4.2) - '@better-auth/telemetry': 1.7.6(@better-auth/core@1.7.6)(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2) + '@better-auth/core': 1.7.6(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.6.7))(jose@6.2.13)(kysely@0.29.6)(nanostores@1.5.5) + '@better-auth/drizzle-adapter': 1.7.6(@better-auth/core@1.7.6(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.6.7))(jose@6.2.13)(kysely@0.29.6)(nanostores@1.5.5))(@better-auth/utils@0.4.2) + '@better-auth/kysely-adapter': 1.7.6(@better-auth/core@1.7.6(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.6.7))(jose@6.2.13)(kysely@0.29.6)(nanostores@1.5.5))(@better-auth/utils@0.4.2)(kysely@0.29.6) + '@better-auth/memory-adapter': 1.7.6(@better-auth/core@1.7.6(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.6.7))(jose@6.2.13)(kysely@0.29.6)(nanostores@1.5.5))(@better-auth/utils@0.4.2) + '@better-auth/mongo-adapter': 1.7.6(@better-auth/core@1.7.6(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.6.7))(jose@6.2.13)(kysely@0.29.6)(nanostores@1.5.5))(@better-auth/utils@0.4.2) + '@better-auth/prisma-adapter': 1.7.6(@better-auth/core@1.7.6(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.6.7))(jose@6.2.13)(kysely@0.29.6)(nanostores@1.5.5))(@better-auth/utils@0.4.2) + '@better-auth/telemetry': 1.7.6(@better-auth/core@1.7.6(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.6.7))(jose@6.2.13)(kysely@0.29.6)(nanostores@1.5.5))(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2) '@better-auth/utils': 0.4.2 '@better-fetch/fetch': 1.3.2 - '@noble/ciphers': 2.2.0 - '@noble/hashes': 2.2.0 - better-call: 1.4.0(zod@3.25.67) + '@noble/ciphers': 2.4.0 + '@noble/hashes': 2.4.0 + better-call: 1.4.0(zod@4.6.7) defu: 6.1.7 - jose: 6.2.3 + jose: 6.2.13 kysely: 0.29.6 - nanostores: 1.4.0 - next: 14.2.35(react-dom@18.3.1)(react@18.3.1) + nanostores: 1.5.5 + zod: 4.6.7 + optionalDependencies: + mysql2: 3.24.4(@types/node@22.18.6) + next: 14.2.35(@playwright/test@1.64.1)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) pg: 8.23.0 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - vitest: 3.2.4(@types/node@22.18.6)(jiti@2.4.2) - zod: 4.6.5 + vitest: 3.2.7(@types/debug@4.1.13)(@types/node@22.18.6)(jiti@2.4.2)(lightningcss@1.33.0)(supports-color@10.2.2)(terser@5.51.2)(yaml@2.9.1) transitivePeerDependencies: - '@opentelemetry/api' - dev: false - /better-call@1.4.0(zod@3.25.67): - resolution: {integrity: sha512-bBKOT4vv1kZLDgxVePdilk/Jwkn+dtRRsmi3DzHcDP+WnswyVl6dR59l2HEeP/0cB+bDoopASAesWDPIdd/zZA==} - peerDependencies: - zod: ^4.0.0 - peerDependenciesMeta: - zod: - optional: true + better-auth@1.7.6(mysql2@3.24.4(@types/node@22.18.6))(next@14.2.35(@playwright/test@1.64.1)(@types/react@18.3.3)(react-dom@18.3.1(react@19.3.1))(react@19.3.1))(pg@8.23.0)(react-dom@18.3.1(react@19.3.1))(react@19.3.1)(vitest@3.2.7(@types/debug@4.1.13)(@types/node@22.18.6)(jiti@2.7.0)(lightningcss@1.33.0)(supports-color@10.2.2)(terser@5.51.2)(yaml@2.9.1)): + dependencies: + '@better-auth/core': 1.7.6(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.6.7))(jose@6.2.13)(kysely@0.29.6)(nanostores@1.5.5) + '@better-auth/drizzle-adapter': 1.7.6(@better-auth/core@1.7.6(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.6.7))(jose@6.2.13)(kysely@0.29.6)(nanostores@1.5.5))(@better-auth/utils@0.4.2) + '@better-auth/kysely-adapter': 1.7.6(@better-auth/core@1.7.6(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.6.7))(jose@6.2.13)(kysely@0.29.6)(nanostores@1.5.5))(@better-auth/utils@0.4.2)(kysely@0.29.6) + '@better-auth/memory-adapter': 1.7.6(@better-auth/core@1.7.6(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.6.7))(jose@6.2.13)(kysely@0.29.6)(nanostores@1.5.5))(@better-auth/utils@0.4.2) + '@better-auth/mongo-adapter': 1.7.6(@better-auth/core@1.7.6(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.6.7))(jose@6.2.13)(kysely@0.29.6)(nanostores@1.5.5))(@better-auth/utils@0.4.2) + '@better-auth/prisma-adapter': 1.7.6(@better-auth/core@1.7.6(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.6.7))(jose@6.2.13)(kysely@0.29.6)(nanostores@1.5.5))(@better-auth/utils@0.4.2) + '@better-auth/telemetry': 1.7.6(@better-auth/core@1.7.6(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.6.7))(jose@6.2.13)(kysely@0.29.6)(nanostores@1.5.5))(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2) + '@better-auth/utils': 0.4.2 + '@better-fetch/fetch': 1.3.2 + '@noble/ciphers': 2.4.0 + '@noble/hashes': 2.4.0 + better-call: 1.4.0(zod@4.6.7) + defu: 6.1.7 + jose: 6.2.13 + kysely: 0.29.6 + nanostores: 1.5.5 + zod: 4.6.7 + optionalDependencies: + mysql2: 3.24.4(@types/node@22.18.6) + next: 14.2.35(@playwright/test@1.64.1)(@types/react@18.3.3)(react-dom@18.3.1(react@19.3.1))(react@19.3.1) + pg: 8.23.0 + react: 19.3.1 + react-dom: 18.3.1(react@19.3.1) + vitest: 3.2.7(@types/debug@4.1.13)(@types/node@22.18.6)(jiti@2.7.0)(lightningcss@1.33.0)(supports-color@10.2.2)(terser@5.51.2)(yaml@2.9.1) + transitivePeerDependencies: + - '@opentelemetry/api' + + better-auth@1.7.6(mysql2@3.24.4(@types/node@22.18.6))(next@14.2.35(@playwright/test@1.64.1)(@types/react@19.3.0)(react-dom@19.3.1(react@19.3.1))(react@19.3.1))(pg@8.23.0)(react-dom@19.3.1(react@19.3.1))(react@19.3.1)(vitest@3.2.7(@types/debug@4.1.13)(@types/node@22.18.6)(jiti@2.4.2)(lightningcss@1.33.0)(supports-color@10.2.2)(terser@5.51.2)(yaml@2.9.1)): + dependencies: + '@better-auth/core': 1.7.6(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.6.7))(jose@6.2.13)(kysely@0.29.6)(nanostores@1.5.5) + '@better-auth/drizzle-adapter': 1.7.6(@better-auth/core@1.7.6(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.6.7))(jose@6.2.13)(kysely@0.29.6)(nanostores@1.5.5))(@better-auth/utils@0.4.2) + '@better-auth/kysely-adapter': 1.7.6(@better-auth/core@1.7.6(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.6.7))(jose@6.2.13)(kysely@0.29.6)(nanostores@1.5.5))(@better-auth/utils@0.4.2)(kysely@0.29.6) + '@better-auth/memory-adapter': 1.7.6(@better-auth/core@1.7.6(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.6.7))(jose@6.2.13)(kysely@0.29.6)(nanostores@1.5.5))(@better-auth/utils@0.4.2) + '@better-auth/mongo-adapter': 1.7.6(@better-auth/core@1.7.6(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.6.7))(jose@6.2.13)(kysely@0.29.6)(nanostores@1.5.5))(@better-auth/utils@0.4.2) + '@better-auth/prisma-adapter': 1.7.6(@better-auth/core@1.7.6(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.6.7))(jose@6.2.13)(kysely@0.29.6)(nanostores@1.5.5))(@better-auth/utils@0.4.2) + '@better-auth/telemetry': 1.7.6(@better-auth/core@1.7.6(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.6.7))(jose@6.2.13)(kysely@0.29.6)(nanostores@1.5.5))(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2) + '@better-auth/utils': 0.4.2 + '@better-fetch/fetch': 1.3.2 + '@noble/ciphers': 2.4.0 + '@noble/hashes': 2.4.0 + better-call: 1.4.0(zod@4.6.7) + defu: 6.1.7 + jose: 6.2.13 + kysely: 0.29.6 + nanostores: 1.5.5 + zod: 4.6.7 + optionalDependencies: + mysql2: 3.24.4(@types/node@22.18.6) + next: 14.2.35(@playwright/test@1.64.1)(@types/react@19.3.0)(react-dom@19.3.1(react@19.3.1))(react@19.3.1) + pg: 8.23.0 + react: 19.3.1 + react-dom: 19.3.1(react@19.3.1) + vitest: 3.2.7(@types/debug@4.1.13)(@types/node@22.18.6)(jiti@2.4.2)(lightningcss@1.33.0)(supports-color@10.2.2)(terser@5.51.2)(yaml@2.9.1) + transitivePeerDependencies: + - '@opentelemetry/api' + + better-call@1.4.0(zod@3.25.76): dependencies: - '@better-auth/utils': 0.5.0 + '@better-auth/utils': 0.5.1 '@better-fetch/fetch': 1.3.2 rou3: 0.9.2 - set-cookie-parser: 3.1.2 - zod: 3.25.67 - dev: false + set-cookie-parser: 3.2.1 + optionalDependencies: + zod: 3.25.76 - /better-sqlite3@13.0.3: - resolution: {integrity: sha512-RbOBxmLBG8uvFUc15X9+9SFemKcQ0WBuISBVkpuiaUB2qblC8UWlHEjdWVoZ8AdhSwmoEgsiXKfopX0CQxaACQ==} - engines: {node: '>=22'} - requiresBuild: true + better-call@1.4.0(zod@4.6.7): + dependencies: + '@better-auth/utils': 0.5.1 + '@better-fetch/fetch': 1.3.2 + rou3: 0.9.2 + set-cookie-parser: 3.2.1 + optionalDependencies: + zod: 4.6.7 + + better-sqlite3@13.0.3: dependencies: node-addon-api: 8.9.2 - /binary-extensions@2.3.0: - resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} - engines: {node: '>=8'} - dev: true + binary-extensions@2.3.0: {} - /bl@4.1.0: - resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} - dependencies: - buffer: 5.7.1 - inherits: 2.0.4 - readable-stream: 3.6.2 - dev: true + blake3-wasm@2.1.5: {} - /bowser@2.14.1: - resolution: {integrity: sha512-tzPjzCxygAKWFOJP011oxFHs57HzIhOEracIgAePE4pqB3LikALKnSzUyU4MGs9/iCEUuHlAJTjTc5M+u7YEGg==} - dev: false + bowser@2.15.0: {} - /brace-expansion@1.1.16: - resolution: {integrity: sha512-IDw48K2/2kRkg9LdJxurvq3lV3aBgq0REY89duEqFRthjlPdXHKMj7EnQOXVckxzgisinf3nHfrcE2FufFLXMw==} + boxen@7.0.0: + dependencies: + ansi-align: 3.0.1 + camelcase: 7.0.1 + chalk: 5.0.1 + cli-boxes: 3.0.0 + string-width: 5.1.2 + type-fest: 2.19.0 + widest-line: 4.0.1 + wrap-ansi: 8.1.0 + + brace-expansion@1.1.21: dependencies: balanced-match: 1.0.2 concat-map: 0.0.1 - dev: true - /brace-expansion@2.1.2: - resolution: {integrity: sha512-w5JZcKgdhDOgOwm8H+KgbosopHMuGcl6qbulwjtz3SM7I7P3yW1eAjzMPLrIE+NQ9vjgANKHWeMHnrT0OXW1oA==} + brace-expansion@5.0.12: dependencies: - balanced-match: 1.0.2 - dev: true + balanced-match: 4.0.4 - /braces@3.0.3: - resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} - engines: {node: '>=8'} + braces@3.0.3: dependencies: fill-range: 7.1.1 - dev: true - /browserslist@4.28.5: - resolution: {integrity: sha512-Cu2E6QejHWzuDMTkuwgpABFgDfZrXLQq5V13YOACZx4mFAG4IwGTbTfHPMr4WtxlHoXSM8FIuRwYYCz5XiabaQ==} - engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} - hasBin: true + browserslist@4.29.5: dependencies: - baseline-browser-mapping: 2.10.42 - caniuse-lite: 1.0.30001803 - electron-to-chromium: 1.5.389 - node-releases: 2.0.51 - update-browserslist-db: 1.2.3(browserslist@4.28.5) - dev: true + baseline-browser-mapping: 2.11.33 + caniuse-lite: 1.0.30001819 + electron-to-chromium: 1.5.465 + node-releases: 2.0.60 + update-browserslist-db: 1.3.4(browserslist@4.29.5) - /buffer@5.7.1: - resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} - dependencies: - base64-js: 1.5.1 - ieee754: 1.2.1 - dev: true + buffer-from@1.1.2: {} - /bundle-require@5.1.0(esbuild@0.27.7): - resolution: {integrity: sha512-3WrrOuZiyaaZPWiEt4G3+IffISVC9HYlWueJEBWED4ZH4aIAC2PnkdnuRrR94M+w6yGWn4AglWtJtBI8YqvgoA==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - peerDependencies: - esbuild: '>=0.18' + bundle-require@5.1.0(esbuild@0.27.7): dependencies: esbuild: 0.27.7 load-tsconfig: 0.2.5 - dev: true - /busboy@1.6.0: - resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==} - engines: {node: '>=10.16.0'} + busboy@1.6.0: dependencies: streamsearch: 1.1.0 - /cac@6.7.14: - resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} - engines: {node: '>=8'} + bytes@3.0.0: {} - /callsites@3.1.0: - resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} - engines: {node: '>=6'} - dev: true + bytes@3.1.2: {} + + cac@6.7.14: {} - /camel-case@3.0.0: - resolution: {integrity: sha512-+MbKztAYHXPr1jNTSKQF52VpcFjwY5RkR7fxksV8Doo4KAYc5Fl4UJRgthBbTmEx8C54DqahhbLJkDwjI3PI/w==} + cacheable@2.5.0: dependencies: - no-case: 2.3.2 - upper-case: 1.1.3 - dev: true + '@cacheable/memory': 2.2.0 + '@cacheable/utils': 2.5.0 + hookified: 1.15.1 + keyv: 5.6.0 + qified: 0.10.1 - /camelcase-css@2.0.1: - resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==} - engines: {node: '>= 6'} - dev: true + camelcase-css@2.0.1: {} - /caniuse-lite@1.0.30001803: - resolution: {integrity: sha512-g/uHREV2ZpK9qMalCsWaxmA6ol+DX8GYhuf3T40RKoP+oL7vhRJh8LNt73PCjpnR6l14FzfPrB5Yux4PKm2meg==} + camelcase@7.0.1: {} - /chai@5.3.3: - resolution: {integrity: sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==} - engines: {node: '>=18'} + camelize@1.0.1: {} + + caniuse-lite@1.0.30001819: {} + + ccount@2.0.1: {} + + chai@5.3.3: dependencies: assertion-error: 2.0.1 check-error: 2.1.3 @@ -3734,69 +9185,30 @@ packages: loupe: 3.2.1 pathval: 2.0.1 - /chalk@2.4.2: - resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} - engines: {node: '>=4'} + chalk-template@0.4.0: dependencies: - ansi-styles: 3.2.1 - escape-string-regexp: 1.0.5 - supports-color: 5.5.0 - dev: true + chalk: 4.1.2 - /chalk@3.0.0: - resolution: {integrity: sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==} - engines: {node: '>=8'} + chalk@4.1.2: dependencies: ansi-styles: 4.3.0 supports-color: 7.2.0 - dev: true - /chalk@4.1.2: - resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} - engines: {node: '>=10'} - dependencies: - ansi-styles: 4.3.0 - supports-color: 7.2.0 - dev: true - - /change-case@3.1.0: - resolution: {integrity: sha512-2AZp7uJZbYEzRPsFoa+ijKdvp9zsrnnt6+yFokfwEpeJm0xuJDVoxiRCAaTzyJND8GJkofo2IcKWaUZ/OECVzw==} - dependencies: - camel-case: 3.0.0 - constant-case: 2.0.0 - dot-case: 2.1.1 - header-case: 1.0.1 - is-lower-case: 1.1.3 - is-upper-case: 1.1.2 - lower-case: 1.1.4 - lower-case-first: 1.0.2 - no-case: 2.3.2 - param-case: 2.1.1 - pascal-case: 2.0.1 - path-case: 2.1.1 - sentence-case: 2.1.1 - snake-case: 2.1.0 - swap-case: 1.1.2 - title-case: 2.1.1 - upper-case: 1.1.3 - upper-case-first: 1.1.2 - dev: true - - /chardet@0.7.0: - resolution: {integrity: sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==} - dev: true - - /chardet@2.2.0: - resolution: {integrity: sha512-rddelWYNPRrXq6PtNEN2S3f6t9ILzvqaN5pVgi4kqt9jHQaXIial9PznB5iSPVlQSLNaaH22ItWz3EJtQ10+OA==} - dev: true + chalk@5.0.1: {} - /check-error@2.1.3: - resolution: {integrity: sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA==} - engines: {node: '>= 16'} + character-entities-html4@2.1.0: {} - /chokidar@3.6.0: - resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} - engines: {node: '>= 8.10.0'} + character-entities-legacy@3.0.0: {} + + character-entities@2.0.2: {} + + character-reference-invalid@2.0.1: {} + + chardet@2.2.0: {} + + check-error@2.1.3: {} + + chokidar@3.6.0: dependencies: anymatch: 3.1.3 braces: 3.0.3 @@ -3807,281 +9219,233 @@ packages: readdirp: 3.6.0 optionalDependencies: fsevents: 2.3.3 - dev: true - /chokidar@4.0.3: - resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} - engines: {node: '>= 14.16.0'} + chokidar@4.0.3: dependencies: readdirp: 4.1.2 - dev: true - /class-variance-authority@0.7.0: - resolution: {integrity: sha512-jFI8IQw4hczaL4ALINxqLEXQbWcNjoSkloa4IaufXCJr6QawJyw7tuRysRsrE8w2p/4gGaxKIt/hX3qz/IbD1A==} + chokidar@5.0.0: dependencies: - clsx: 2.0.0 - dev: false + readdirp: 5.1.1 - /clean-stack@2.2.0: - resolution: {integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==} - engines: {node: '>=6'} - dev: true + chrome-trace-event@1.0.4: {} - /cli-cursor@3.1.0: - resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==} - engines: {node: '>=8'} + class-variance-authority@0.7.1: dependencies: - restore-cursor: 3.1.0 - dev: true + clsx: 2.1.1 - /cli-spinners@2.9.2: - resolution: {integrity: sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==} - engines: {node: '>=6'} - dev: true + cli-boxes@3.0.0: {} - /cli-width@3.0.0: - resolution: {integrity: sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==} - engines: {node: '>= 10'} - dev: true + cli-width@4.1.0: {} - /client-only@0.0.1: - resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} + client-only@0.0.1: {} - /clone@1.0.4: - resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==} - engines: {node: '>=0.8'} - dev: true + clipboardy@3.0.0: + dependencies: + arch: 2.2.0 + execa: 5.1.1 + is-wsl: 2.2.0 - /clsx@2.0.0: - resolution: {integrity: sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q==} - engines: {node: '>=6'} - dev: false + cliui@8.0.1: + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 - /clsx@2.1.1: - resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} - engines: {node: '>=6'} - dev: false + clsx@2.1.1: {} - /color-convert@1.9.3: - resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} - dependencies: - color-name: 1.1.3 - dev: true + cn@0.4.0: {} - /color-convert@2.0.1: - resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} - engines: {node: '>=7.0.0'} + cn@0.5.0: {} + + collapse-white-space@2.1.0: {} + + color-convert@2.0.1: dependencies: color-name: 1.1.4 - dev: true - /color-name@1.1.3: - resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} - dev: true + color-name@1.1.4: {} - /color-name@1.1.4: - resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - dev: true + comma-separated-tokens@2.0.3: {} - /commander@10.0.1: - resolution: {integrity: sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==} - engines: {node: '>=14'} - dev: true + commander@12.1.0: {} - /commander@12.1.0: - resolution: {integrity: sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==} - engines: {node: '>=18'} - dev: false + commander@2.20.3: {} - /commander@4.1.1: - resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} - engines: {node: '>= 6'} - dev: true + commander@4.1.1: {} - /concat-map@0.0.1: - resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} - dev: true + compressible@2.0.18: + dependencies: + mime-db: 1.54.0 - /confbox@0.1.8: - resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} - dev: true + compression@1.8.1(supports-color@10.2.2): + dependencies: + bytes: 3.1.2 + compressible: 2.0.18 + debug: 2.6.9(supports-color@10.2.2) + negotiator: 0.6.4 + on-headers: 1.1.0 + safe-buffer: 5.2.1 + vary: 1.1.2 + transitivePeerDependencies: + - supports-color - /consola@3.4.2: - resolution: {integrity: sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==} - engines: {node: ^14.18.0 || >=16.10.0} - dev: true + compute-scroll-into-view@3.1.1: {} - /constant-case@2.0.0: - resolution: {integrity: sha512-eS0N9WwmjTqrOmR3o83F5vW8Z+9R1HnVz3xmzT2PMFug9ly+Au/fxRWlEBSb6LcZwspSsEn9Xs1uw9YgzAg1EQ==} - dependencies: - snake-case: 2.1.0 - upper-case: 1.1.3 - dev: true + concat-map@0.0.1: {} - /core-js-pure@3.49.0: - resolution: {integrity: sha512-XM4RFka59xATyJv/cS3O3Kml72hQXUeGRuuTmMYFxwzc9/7C8OYTaIR/Ji+Yt8DXzsFLNhat15cE/JP15HrCgw==} - requiresBuild: true - dev: true + confbox@0.1.8: {} - /create-require@1.1.1: - resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} - dev: true + consola@3.4.2: {} - /cross-spawn@7.0.6: - resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} - engines: {node: '>= 8'} + content-disposition@0.5.2: {} + + cookie@1.1.1: {} + + cross-spawn@7.0.6: dependencies: path-key: 3.1.1 shebang-command: 2.0.0 which: 2.0.2 - dev: true - /cssesc@3.0.0: - resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} - engines: {node: '>=4'} - hasBin: true - dev: true + css-background-parser@0.1.0: {} - /csstype@3.2.3: - resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} + css-box-shadow@1.0.0-3: {} - /data-uri-to-buffer@6.0.2: - resolution: {integrity: sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==} - engines: {node: '>= 14'} - dev: true + css-color-keywords@1.0.0: {} - /debug@4.4.3: - resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} - engines: {node: '>=6.0'} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - dependencies: - ms: 2.1.3 + css-gradient-parser@0.0.17: {} - /deep-eql@5.0.2: - resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==} - engines: {node: '>=6'} + css-to-react-native@3.2.0: + dependencies: + camelize: 1.0.1 + css-color-keywords: 1.0.0 + postcss-value-parser: 4.2.0 - /deep-extend@0.6.0: - resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==} - engines: {node: '>=4.0.0'} - dev: true + cssesc@3.0.0: {} - /deep-is@0.1.4: - resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} - dev: true + csstype@3.2.3: {} - /defaults@1.0.4: - resolution: {integrity: sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==} + debug@2.6.9(supports-color@10.2.2): dependencies: - clone: 1.0.4 - dev: true - - /defu@6.1.7: - resolution: {integrity: sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ==} - dev: false + ms: 2.0.0 + optionalDependencies: + supports-color: 10.2.2 - /degenerator@5.0.1: - resolution: {integrity: sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==} - engines: {node: '>= 14'} + debug@4.4.3(supports-color@10.2.2): dependencies: - ast-types: 0.13.4 - escodegen: 2.1.0 - esprima: 4.0.1 - dev: true + ms: 2.1.3 + optionalDependencies: + supports-color: 10.2.2 - /del@5.1.0: - resolution: {integrity: sha512-wH9xOVHnczo9jN2IW68BabcecVPxacIA3g/7z6vhSU/4stOKQzeCRK0yD0A24WiAAUJmmVpWqrERcTxnLo3AnA==} - engines: {node: '>=8'} + decode-named-character-reference@1.3.0: dependencies: - globby: 10.0.2 - graceful-fs: 4.2.11 - is-glob: 4.0.3 - is-path-cwd: 2.2.0 - is-path-inside: 3.0.3 - p-map: 3.0.0 - rimraf: 3.0.2 - slash: 3.0.0 - dev: true - - /detect-libc@2.0.2: - resolution: {integrity: sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==} - engines: {node: '>=8'} - dev: false + character-entities: 2.0.2 - /detect-node-es@1.1.0: - resolution: {integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==} - dev: false + deep-eql@5.0.2: {} - /didyoumean@1.2.2: - resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==} - dev: true + deep-extend@0.6.0: {} - /diff@4.0.4: - resolution: {integrity: sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ==} - engines: {node: '>=0.3.1'} - dev: true + deep-is@0.1.4: {} - /dir-glob@3.0.1: - resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} - engines: {node: '>=8'} - dependencies: - path-type: 4.0.0 - dev: true + defu@6.1.7: {} - /dlv@1.1.3: - resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==} - dev: true + dequal@2.0.3: {} + + detect-libc@2.0.2: {} + + detect-libc@2.1.2: {} + + detect-node-es@1.1.0: {} - /dot-case@2.1.1: - resolution: {integrity: sha512-HnM6ZlFqcajLsyudHq7LeeLDr2rFAVYtDv/hV5qchQEidSck8j9OPUsXY9KwJv/lHMtYlX4DjRQqwFYa+0r8Ug==} + devlop@1.1.0: dependencies: - no-case: 2.3.2 - dev: true + dequal: 2.0.3 - /dotenv-cli@7.4.2: - resolution: {integrity: sha512-SbUj8l61zIbzyhIbg0FwPJq6+wjbzdn9oEtozQpZ6kW2ihCcapKVZj49oCT3oPM+mgQm+itgvUQcG5szxVrZTA==} - hasBin: true + didyoumean@1.2.2: {} + + dlv@1.1.3: {} + + dotenv-cli@7.4.4: dependencies: cross-spawn: 7.0.6 dotenv: 16.6.1 dotenv-expand: 10.0.0 minimist: 1.2.8 - dev: true - /dotenv-expand@10.0.0: - resolution: {integrity: sha512-GopVGCpVS1UKH75VKHGuQFqS1Gusej0z4FyQkPdwjil2gNIv+LNsqBlboOzpJFZKVT95GkCyWJbBSdFEFUWI2A==} - engines: {node: '>=12'} - dev: true + dotenv-expand@10.0.0: {} - /dotenv@16.6.1: - resolution: {integrity: sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==} - engines: {node: '>=12'} + dotenv@16.6.1: {} - /electron-to-chromium@1.5.389: - resolution: {integrity: sha512-cEto7aeOqBfU1D+c5py5pE+ooscKE75JifxLBdFUZsqAxRS6y7kebtxAZvICszSl05gPjYHDTjY+lXpyGvpJbg==} - dev: true + eastasianwidth@0.2.0: {} - /emoji-regex@8.0.0: - resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} - dev: true + electron-to-chromium@1.5.465: {} - /es-errors@1.3.0: - resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} - engines: {node: '>= 0.4'} - dev: true + emoji-regex-xs@2.0.1: {} - /es-module-lexer@1.7.0: - resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} + emoji-regex@8.0.0: {} - /esbuild@0.27.7: - resolution: {integrity: sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==} - engines: {node: '>=18'} - hasBin: true - requiresBuild: true + emoji-regex@9.2.2: {} + + enhanced-resolve@5.26.0: + dependencies: + graceful-fs: 4.2.11 + tapable: 2.3.3 + + error-stack-parser-es@1.0.5: {} + + es-errors@1.3.0: {} + + es-module-lexer@1.7.0: {} + + es-module-lexer@2.3.2: {} + + es-module-lexer@3.0.4: {} + + esast-util-from-estree@2.0.0: + dependencies: + '@types/estree-jsx': 1.0.5 + devlop: 1.1.0 + estree-util-visit: 2.0.0 + unist-util-position-from-estree: 2.0.0 + + esast-util-from-js@2.0.1: + dependencies: + '@types/estree-jsx': 1.0.5 + acorn: 8.19.0 + esast-util-from-estree: 2.0.0 + vfile-message: 4.0.3 + + esbuild@0.25.12: + optionalDependencies: + '@esbuild/aix-ppc64': 0.25.12 + '@esbuild/android-arm': 0.25.12 + '@esbuild/android-arm64': 0.25.12 + '@esbuild/android-x64': 0.25.12 + '@esbuild/darwin-arm64': 0.25.12 + '@esbuild/darwin-x64': 0.25.12 + '@esbuild/freebsd-arm64': 0.25.12 + '@esbuild/freebsd-x64': 0.25.12 + '@esbuild/linux-arm': 0.25.12 + '@esbuild/linux-arm64': 0.25.12 + '@esbuild/linux-ia32': 0.25.12 + '@esbuild/linux-loong64': 0.25.12 + '@esbuild/linux-mips64el': 0.25.12 + '@esbuild/linux-ppc64': 0.25.12 + '@esbuild/linux-riscv64': 0.25.12 + '@esbuild/linux-s390x': 0.25.12 + '@esbuild/linux-x64': 0.25.12 + '@esbuild/netbsd-arm64': 0.25.12 + '@esbuild/netbsd-x64': 0.25.12 + '@esbuild/openbsd-arm64': 0.25.12 + '@esbuild/openbsd-x64': 0.25.12 + '@esbuild/openharmony-arm64': 0.25.12 + '@esbuild/sunos-x64': 0.25.12 + '@esbuild/win32-arm64': 0.25.12 + '@esbuild/win32-ia32': 0.25.12 + '@esbuild/win32-x64': 0.25.12 + + esbuild@0.27.7: optionalDependencies: '@esbuild/aix-ppc64': 0.27.7 '@esbuild/android-arm': 0.27.7 @@ -4109,176 +9473,150 @@ packages: '@esbuild/win32-arm64': 0.27.7 '@esbuild/win32-ia32': 0.27.7 '@esbuild/win32-x64': 0.27.7 - dev: true - - /esbuild@0.28.1: - resolution: {integrity: sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw==} - engines: {node: '>=18'} - hasBin: true - requiresBuild: true - optionalDependencies: - '@esbuild/aix-ppc64': 0.28.1 - '@esbuild/android-arm': 0.28.1 - '@esbuild/android-arm64': 0.28.1 - '@esbuild/android-x64': 0.28.1 - '@esbuild/darwin-arm64': 0.28.1 - '@esbuild/darwin-x64': 0.28.1 - '@esbuild/freebsd-arm64': 0.28.1 - '@esbuild/freebsd-x64': 0.28.1 - '@esbuild/linux-arm': 0.28.1 - '@esbuild/linux-arm64': 0.28.1 - '@esbuild/linux-ia32': 0.28.1 - '@esbuild/linux-loong64': 0.28.1 - '@esbuild/linux-mips64el': 0.28.1 - '@esbuild/linux-ppc64': 0.28.1 - '@esbuild/linux-riscv64': 0.28.1 - '@esbuild/linux-s390x': 0.28.1 - '@esbuild/linux-x64': 0.28.1 - '@esbuild/netbsd-arm64': 0.28.1 - '@esbuild/netbsd-x64': 0.28.1 - '@esbuild/openbsd-arm64': 0.28.1 - '@esbuild/openbsd-x64': 0.28.1 - '@esbuild/openharmony-arm64': 0.28.1 - '@esbuild/sunos-x64': 0.28.1 - '@esbuild/win32-arm64': 0.28.1 - '@esbuild/win32-ia32': 0.28.1 - '@esbuild/win32-x64': 0.28.1 - - /escalade@3.2.0: - resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} - engines: {node: '>=6'} - dev: true - - /escape-string-regexp@1.0.5: - resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} - engines: {node: '>=0.8.0'} - dev: true - - /escape-string-regexp@4.0.0: - resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} - engines: {node: '>=10'} - dev: true - /escodegen@2.1.0: - resolution: {integrity: sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==} - engines: {node: '>=6.0'} - hasBin: true - dependencies: - esprima: 4.0.1 - estraverse: 5.3.0 - esutils: 2.0.3 + esbuild@0.28.2: optionalDependencies: - source-map: 0.6.1 - dev: true - - /eslint-scope@8.4.0: - resolution: {integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - dependencies: + '@esbuild/aix-ppc64': 0.28.2 + '@esbuild/android-arm': 0.28.2 + '@esbuild/android-arm64': 0.28.2 + '@esbuild/android-x64': 0.28.2 + '@esbuild/darwin-arm64': 0.28.2 + '@esbuild/darwin-x64': 0.28.2 + '@esbuild/freebsd-arm64': 0.28.2 + '@esbuild/freebsd-x64': 0.28.2 + '@esbuild/linux-arm': 0.28.2 + '@esbuild/linux-arm64': 0.28.2 + '@esbuild/linux-ia32': 0.28.2 + '@esbuild/linux-loong64': 0.28.2 + '@esbuild/linux-mips64el': 0.28.2 + '@esbuild/linux-ppc64': 0.28.2 + '@esbuild/linux-riscv64': 0.28.2 + '@esbuild/linux-s390x': 0.28.2 + '@esbuild/linux-x64': 0.28.2 + '@esbuild/netbsd-arm64': 0.28.2 + '@esbuild/netbsd-x64': 0.28.2 + '@esbuild/openbsd-arm64': 0.28.2 + '@esbuild/openbsd-x64': 0.28.2 + '@esbuild/openharmony-arm64': 0.28.2 + '@esbuild/sunos-x64': 0.28.2 + '@esbuild/win32-arm64': 0.28.2 + '@esbuild/win32-ia32': 0.28.2 + '@esbuild/win32-x64': 0.28.2 + + escalade@3.2.0: {} + + escape-html@1.0.3: {} + + escape-string-regexp@4.0.0: {} + + escape-string-regexp@5.0.0: {} + + eslint-scope@9.1.2: + dependencies: + '@types/esrecurse': 4.3.1 + '@types/estree': 1.0.9 esrecurse: 4.3.0 estraverse: 5.3.0 - dev: true - /eslint-visitor-keys@3.4.3: - resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - dev: true + eslint-visitor-keys@3.4.3: {} - /eslint-visitor-keys@4.2.1: - resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - dev: true + eslint-visitor-keys@5.0.1: {} - /eslint@9.7.0: - resolution: {integrity: sha512-FzJ9D/0nGiCGBf8UXO/IGLTgLVzIxze1zpfA8Ton2mjLovXdAPlYDv+MQDcqj3TmrhAGYfOpz9RfR+ent0AgAw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - hasBin: true + eslint@10.13.0(jiti@2.7.0)(supports-color@10.2.2): dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@9.7.0) + '@eslint-community/eslint-utils': 4.10.1(eslint@10.13.0(jiti@2.7.0)(supports-color@10.2.2)) '@eslint-community/regexpp': 4.12.2 - '@eslint/config-array': 0.17.1 - '@eslint/eslintrc': 3.3.5 - '@eslint/js': 9.7.0 + '@eslint/config-array': 0.23.5(supports-color@10.2.2) + '@eslint/config-helpers': 0.7.0 + '@eslint/core': 1.2.1 + '@eslint/plugin-kit': 0.7.3 + '@humanfs/node': 0.16.8 '@humanwhocodes/module-importer': 1.0.1 - '@humanwhocodes/retry': 0.3.1 - '@nodelib/fs.walk': 1.2.8 + '@humanwhocodes/retry': 0.4.3 + '@types/estree': 1.0.9 ajv: 6.15.0 - chalk: 4.1.2 cross-spawn: 7.0.6 - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) escape-string-regexp: 4.0.0 - eslint-scope: 8.4.0 - eslint-visitor-keys: 4.2.1 - espree: 10.4.0 + eslint-scope: 9.1.2 + eslint-visitor-keys: 5.0.1 + espree: 11.2.0 esquery: 1.7.0 esutils: 2.0.3 fast-deep-equal: 3.1.3 - file-entry-cache: 8.0.0 + file-entry-cache: 11.1.5 find-up: 5.0.0 glob-parent: 6.0.2 ignore: 5.3.2 imurmurhash: 0.1.4 is-glob: 4.0.3 - is-path-inside: 3.0.3 json-stable-stringify-without-jsonify: 1.0.1 - levn: 0.4.1 - lodash.merge: 4.6.2 - minimatch: 3.1.5 + minimatch: 10.2.6 natural-compare: 1.4.0 optionator: 0.9.4 - strip-ansi: 6.0.1 - text-table: 0.2.0 + optionalDependencies: + jiti: 2.7.0 transitivePeerDependencies: - supports-color - dev: true - /espree@10.4.0: - resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + espree@11.2.0: + dependencies: + acorn: 8.19.0 + acorn-jsx: 5.3.2(acorn@8.19.0) + eslint-visitor-keys: 5.0.1 + + esquery@1.7.0: + dependencies: + estraverse: 5.3.0 + + esrecurse@4.3.0: + dependencies: + estraverse: 5.3.0 + + estraverse@5.3.0: {} + + estree-util-attach-comments@3.0.0: dependencies: - acorn: 8.17.0 - acorn-jsx: 5.3.2(acorn@8.17.0) - eslint-visitor-keys: 4.2.1 - dev: true + '@types/estree': 1.0.9 - /esprima@4.0.1: - resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} - engines: {node: '>=4'} - hasBin: true - dev: true + estree-util-build-jsx@3.0.1: + dependencies: + '@types/estree-jsx': 1.0.5 + devlop: 1.1.0 + estree-util-is-identifier-name: 3.0.0 + estree-walker: 3.0.3 - /esquery@1.7.0: - resolution: {integrity: sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==} - engines: {node: '>=0.10'} + estree-util-is-identifier-name@3.0.0: {} + + estree-util-scope@1.0.1: dependencies: - estraverse: 5.3.0 - dev: true + '@types/estree': 1.0.9 + devlop: 1.1.0 - /esrecurse@4.3.0: - resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} - engines: {node: '>=4.0'} + estree-util-to-js@2.0.0: dependencies: - estraverse: 5.3.0 - dev: true + '@types/estree-jsx': 1.0.5 + astring: 1.9.0 + source-map: 0.7.6 - /estraverse@5.3.0: - resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} - engines: {node: '>=4.0'} - dev: true + estree-util-value-to-estree@3.5.0: + dependencies: + '@types/estree': 1.0.9 - /estree-walker@3.0.3: - resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} + estree-util-visit@2.0.0: + dependencies: + '@types/estree-jsx': 1.0.5 + '@types/unist': 3.0.3 + + estree-walker@3.0.3: dependencies: '@types/estree': 1.0.9 - /esutils@2.0.3: - resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} - engines: {node: '>=0.10.0'} - dev: true + esutils@2.0.3: {} - /execa@5.1.1: - resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} - engines: {node: '>=10'} + events@3.3.0: {} + + execa@5.1.1: dependencies: cross-spawn: 7.0.6 get-stream: 6.0.1 @@ -4289,735 +9627,1088 @@ packages: onetime: 5.1.2 signal-exit: 3.0.7 strip-final-newline: 2.0.0 - dev: true - /expect-type@1.4.0: - resolution: {integrity: sha512-KfYbmpRm0VbLjEvVa9yGwCi9GI34xvi7A/HXYWQO65CSD2u3MczUJSuwXKFIxlGsgBQizV9q5J9NHj4VG0n+pA==} - engines: {node: '>=12.0.0'} + expect-type@1.4.0: {} - /external-editor@3.1.0: - resolution: {integrity: sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==} - engines: {node: '>=4'} - dependencies: - chardet: 0.7.0 - iconv-lite: 0.4.24 - tmp: 0.0.33 - dev: true + extend@3.0.2: {} - /fast-deep-equal@3.1.3: - resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} - dev: true + fast-deep-equal@3.1.3: {} - /fast-glob@3.3.3: - resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} - engines: {node: '>=8.6.0'} + fast-glob@3.3.3: dependencies: '@nodelib/fs.stat': 2.0.5 '@nodelib/fs.walk': 1.2.8 glob-parent: 5.1.2 merge2: 1.4.1 micromatch: 4.0.8 - dev: true - /fast-json-stable-stringify@2.1.0: - resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} - dev: true + fast-json-stable-stringify@2.1.0: {} - /fast-levenshtein@2.0.6: - resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} - dev: true + fast-levenshtein@2.0.6: {} - /fast-xml-parser@4.4.1: - resolution: {integrity: sha512-xkjOecfnKGkSsOwtZ5Pz7Us/T6mrbPQrq0nh+aCO5V9nk5NLWmasAHumTKjiPJPWANe+kAZ84Jc8ooJkzZ88Sw==} - hasBin: true - dependencies: - strnum: 1.1.2 - dev: false + fast-uri@3.1.9: {} - /fastq@1.20.1: - resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==} + fastq@1.20.3: dependencies: reusify: 1.1.0 - dev: true - /fdir@6.5.0(picomatch@4.0.5): - resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} - engines: {node: '>=12.0.0'} - peerDependencies: - picomatch: ^3 || ^4 - peerDependenciesMeta: - picomatch: - optional: true - dependencies: - picomatch: 4.0.5 + fdir@6.5.0(picomatch@4.0.7): + optionalDependencies: + picomatch: 4.0.7 - /figures@3.2.0: - resolution: {integrity: sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==} - engines: {node: '>=8'} - dependencies: - escape-string-regexp: 1.0.5 - dev: true + fflate@0.7.3: {} - /file-entry-cache@8.0.0: - resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} - engines: {node: '>=16.0.0'} + file-entry-cache@11.1.5: dependencies: - flat-cache: 4.0.1 - dev: true + flat-cache: 6.1.23 - /fill-range@7.1.1: - resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} - engines: {node: '>=8'} + fill-range@7.1.1: dependencies: to-regex-range: 5.0.1 - dev: true - /find-up@5.0.0: - resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} - engines: {node: '>=10'} + find-up@5.0.0: dependencies: locate-path: 6.0.0 path-exists: 4.0.0 - dev: true - /fix-dts-default-cjs-exports@1.0.1: - resolution: {integrity: sha512-pVIECanWFC61Hzl2+oOCtoJ3F17kglZC/6N94eRWycFgBH35hHx0Li604ZIzhseh97mf2p0cv7vVrOZGoqhlEg==} + fix-dts-default-cjs-exports@1.0.1: dependencies: magic-string: 0.30.21 mlly: 1.8.2 - rollup: 4.62.2 - dev: true + rollup: 4.65.1 - /flat-cache@4.0.1: - resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} - engines: {node: '>=16'} + flat-cache@6.1.23: dependencies: - flatted: 3.4.2 - keyv: 4.5.4 - dev: true + cacheable: 2.5.0 + flatted: 3.4.4 + hookified: 1.15.1 - /flatted@3.4.2: - resolution: {integrity: sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==} - dev: true + flatted@3.4.4: {} - /fraction.js@4.3.7: - resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==} - dev: true + fraction.js@4.3.7: {} - /fs-extra@10.1.0: - resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==} - engines: {node: '>=12'} + framer-motion@14.6.0(react-dom@19.3.1(react@19.3.1))(react@19.3.1): dependencies: - graceful-fs: 4.2.11 - jsonfile: 6.2.1 - universalify: 2.0.1 - dev: true - - /fs.realpath@1.0.0: - resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} - dev: true + motion-dom: 14.6.0 + motion-utils: 14.6.0 + tslib: 2.8.1 + optionalDependencies: + react: 19.3.1 + react-dom: 19.3.1(react@19.3.1) - /fsevents@2.3.3: - resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} - engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} - os: [darwin] - requiresBuild: true + fsevents@2.3.3: optional: true - /function-bind@1.1.2: - resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} - dev: true + fumadocs-core@16.17.7(@mdx-js/mdx@3.1.1(supports-color@10.2.2))(@types/estree-jsx@1.0.5)(@types/hast@3.0.5)(@types/mdast@4.0.4)(@types/react@19.3.0)(lucide-react@1.61.0(@types/react@19.3.0)(react@19.3.1))(next@16.4.2(@playwright/test@1.64.1)(@types/node@26.6.5)(react-dom@19.3.1(react@19.3.1))(react@19.3.1))(react-dom@19.3.1(react@19.3.1))(react@19.3.1)(supports-color@10.2.2)(zod@4.6.7): + dependencies: + '@fumari/image-size': 0.1.1 + estree-util-value-to-estree: 3.5.0 + github-slugger: 2.0.0 + hast-util-from-dom: 5.0.1 + hast-util-to-estree: 3.1.3(supports-color@10.2.2) + hast-util-to-jsx-runtime: 2.3.6(supports-color@10.2.2) + mdast-util-mdx: 3.0.0(supports-color@10.2.2) + micromark: 4.0.3(supports-color@10.2.2) + micromark-extension-gfm-table: 2.1.2 + npm-to-yarn: 3.2.0 + remark: 15.0.1(supports-color@10.2.2) + remark-gfm: 4.0.1(supports-color@10.2.2) + remark-rehype: 11.1.2 + scroll-into-view-if-needed: 3.1.0 + shiki: 4.5.0 + tinyglobby: 0.2.17 + unified: 11.0.5 + vfile: 6.0.3 + yaml: 2.9.1 + zbsearch: 4.0.1 + optionalDependencies: + '@mdx-js/mdx': 3.1.1(supports-color@10.2.2) + '@types/estree-jsx': 1.0.5 + '@types/hast': 3.0.5 + '@types/mdast': 4.0.4 + '@types/react': 19.3.0 + lucide-react: 1.61.0(@types/react@19.3.0)(react@19.3.1) + next: 16.4.2(@playwright/test@1.64.1)(@types/node@26.6.5)(react-dom@19.3.1(react@19.3.1))(react@19.3.1) + react: 19.3.1 + react-dom: 19.3.1(react@19.3.1) + zod: 4.6.7 + transitivePeerDependencies: + - supports-color - /generate-function@2.3.1: - resolution: {integrity: sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==} + fumadocs-mdx@15.4.9(@types/mdast@4.0.4)(@types/mdx@2.0.14)(@types/react@19.3.0)(fumadocs-core@16.17.7(@mdx-js/mdx@3.1.1(supports-color@10.2.2))(@types/estree-jsx@1.0.5)(@types/hast@3.0.5)(@types/mdast@4.0.4)(@types/react@19.3.0)(lucide-react@1.61.0(@types/react@19.3.0)(react@19.3.1))(next@16.4.2(@playwright/test@1.64.1)(@types/node@26.6.5)(react-dom@19.3.1(react@19.3.1))(react@19.3.1))(react-dom@19.3.1(react@19.3.1))(react@19.3.1)(supports-color@10.2.2)(zod@4.6.7))(next@16.4.2(@playwright/test@1.64.1)(@types/node@26.6.5)(react-dom@19.3.1(react@19.3.1))(react@19.3.1))(react@19.3.1)(rolldown@1.2.15)(supports-color@10.2.2)(vite@8.3.4(@types/node@26.6.5)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1)): + dependencies: + '@mdx-js/mdx': 3.1.1(supports-color@10.2.2) + '@standard-schema/spec': 1.1.0 + chokidar: 5.0.0 + esbuild: 0.28.2 + estree-util-value-to-estree: 3.5.0 + fumadocs-core: 16.17.7(@mdx-js/mdx@3.1.1(supports-color@10.2.2))(@types/estree-jsx@1.0.5)(@types/hast@3.0.5)(@types/mdast@4.0.4)(@types/react@19.3.0)(lucide-react@1.61.0(@types/react@19.3.0)(react@19.3.1))(next@16.4.2(@playwright/test@1.64.1)(@types/node@26.6.5)(react-dom@19.3.1(react@19.3.1))(react@19.3.1))(react-dom@19.3.1(react@19.3.1))(react@19.3.1)(supports-color@10.2.2)(zod@4.6.7) + github-slugger: 2.0.0 + magic-string: 1.4.4 + mdast-util-mdx: 3.0.0(supports-color@10.2.2) + picocolors: 1.1.1 + picomatch: 4.0.7 + tinyexec: 1.3.1 + tinyglobby: 0.2.17 + unified: 11.0.5 + unist-util-remove-position: 5.0.0 + vfile: 6.0.3 + yaml: 2.9.1 + yuku-analyzer: 0.19.0 + zod: 4.6.7 + optionalDependencies: + '@types/mdast': 4.0.4 + '@types/mdx': 2.0.14 + '@types/react': 19.3.0 + next: 16.4.2(@playwright/test@1.64.1)(@types/node@26.6.5)(react-dom@19.3.1(react@19.3.1))(react@19.3.1) + react: 19.3.1 + rolldown: 1.2.15 + vite: 8.3.4(@types/node@26.6.5)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1) + transitivePeerDependencies: + - supports-color + + function-bind@1.1.2: {} + + generate-function@2.3.1: dependencies: is-property: 1.0.2 - dev: false - /get-nonce@1.0.1: - resolution: {integrity: sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==} - engines: {node: '>=6'} - dev: false + get-caller-file@2.0.5: {} - /get-stream@6.0.1: - resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} - engines: {node: '>=10'} - dev: true + get-nonce@1.0.1: {} - /get-uri@6.0.5: - resolution: {integrity: sha512-b1O07XYq8eRuVzBNgJLstU6FYc1tS6wnMtF1I1D9lE8LxZSOGZ7LhxN54yPP6mGw5f2CkXY2BQUL9Fx41qvcIg==} - engines: {node: '>= 14'} + get-stream@6.0.1: {} + + github-slugger@2.0.0: {} + + glob-parent@5.1.2: + dependencies: + is-glob: 4.0.3 + + glob-parent@6.0.2: + dependencies: + is-glob: 4.0.3 + + graceful-fs@4.2.11: {} + + harfbuzzjs@0.10.0: {} + + has-flag@4.0.0: {} + + hashery@1.5.1: dependencies: - basic-ftp: 5.3.1 - data-uri-to-buffer: 6.0.2 - debug: 4.4.3 + hookified: 1.15.1 + + hasown@2.0.4: + dependencies: + function-bind: 1.1.2 + + hast-util-from-dom@5.0.1: + dependencies: + '@types/hast': 3.0.5 + hastscript: 9.0.1 + web-namespaces: 2.0.1 + + hast-util-parse-selector@4.0.0: + dependencies: + '@types/hast': 3.0.5 + + hast-util-to-estree@3.1.3(supports-color@10.2.2): + dependencies: + '@types/estree': 1.0.9 + '@types/estree-jsx': 1.0.5 + '@types/hast': 3.0.5 + comma-separated-tokens: 2.0.3 + devlop: 1.1.0 + estree-util-attach-comments: 3.0.0 + estree-util-is-identifier-name: 3.0.0 + hast-util-whitespace: 3.0.0 + mdast-util-mdx-expression: 2.0.1(supports-color@10.2.2) + mdast-util-mdx-jsx: 3.2.0(supports-color@10.2.2) + mdast-util-mdxjs-esm: 2.0.1(supports-color@10.2.2) + property-information: 7.2.0 + space-separated-tokens: 2.0.2 + style-to-js: 1.1.21 + unist-util-position: 5.0.0 + zwitch: 2.0.4 transitivePeerDependencies: - supports-color - dev: true - /glob-parent@5.1.2: - resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} - engines: {node: '>= 6'} + hast-util-to-html@9.0.5: dependencies: - is-glob: 4.0.3 - dev: true + '@types/hast': 3.0.5 + '@types/unist': 3.0.3 + ccount: 2.0.1 + comma-separated-tokens: 2.0.3 + hast-util-whitespace: 3.0.0 + html-void-elements: 3.0.0 + mdast-util-to-hast: 13.2.1 + property-information: 7.2.0 + space-separated-tokens: 2.0.2 + stringify-entities: 4.0.4 + zwitch: 2.0.4 - /glob-parent@6.0.2: - resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} - engines: {node: '>=10.13.0'} + hast-util-to-jsx-runtime@2.3.6(supports-color@10.2.2): dependencies: - is-glob: 4.0.3 - dev: true + '@types/estree': 1.0.9 + '@types/hast': 3.0.5 + '@types/unist': 3.0.3 + comma-separated-tokens: 2.0.3 + devlop: 1.1.0 + estree-util-is-identifier-name: 3.0.0 + hast-util-whitespace: 3.0.0 + mdast-util-mdx-expression: 2.0.1(supports-color@10.2.2) + mdast-util-mdx-jsx: 3.2.0(supports-color@10.2.2) + mdast-util-mdxjs-esm: 2.0.1(supports-color@10.2.2) + property-information: 7.2.0 + space-separated-tokens: 2.0.2 + style-to-js: 1.1.21 + unist-util-position: 5.0.0 + vfile-message: 4.0.3 + transitivePeerDependencies: + - supports-color - /glob@7.2.3: - resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} - deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me + hast-util-whitespace@3.0.0: dependencies: - fs.realpath: 1.0.0 - inflight: 1.0.6 - inherits: 2.0.4 - minimatch: 3.1.5 - once: 1.4.0 - path-is-absolute: 1.0.1 - dev: true + '@types/hast': 3.0.5 - /globals@14.0.0: - resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} - engines: {node: '>=18'} - dev: true + hastscript@9.0.1: + dependencies: + '@types/hast': 3.0.5 + comma-separated-tokens: 2.0.3 + hast-util-parse-selector: 4.0.0 + property-information: 7.2.0 + space-separated-tokens: 2.0.2 - /globby@10.0.2: - resolution: {integrity: sha512-7dUi7RvCoT/xast/o/dLN53oqND4yk0nsHkhRgn9w65C4PofCLOoJ39iSOg+qVDdWQPIEj+eszMHQ+aLVwwQSg==} - engines: {node: '>=8'} + hex-rgb@4.3.0: {} + + hookified@1.15.1: {} + + hookified@2.2.0: {} + + html-void-elements@3.0.0: {} + + human-signals@2.1.0: {} + + iconv-lite@0.7.3: dependencies: - '@types/glob': 7.2.0 - array-union: 2.1.0 - dir-glob: 3.0.1 - fast-glob: 3.3.3 - glob: 7.2.3 - ignore: 5.3.2 - merge2: 1.4.1 - slash: 3.0.0 - dev: true + safer-buffer: 2.1.2 - /graceful-fs@4.2.11: - resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + ignore@5.3.2: {} - /gradient-string@2.0.2: - resolution: {integrity: sha512-rEDCuqUQ4tbD78TpzsMtt5OIf0cBCSDWSJtUDaF6JsAh+k0v9r++NzxNEG87oDZx9ZwGhD8DaezR2L/yrw0Jdw==} - engines: {node: '>=10'} + imurmurhash@0.1.4: {} + + ini@1.3.8: {} + + inline-style-parser@0.2.7: {} + + ipaddr.js@2.5.0: {} + + is-alphabetical@2.0.1: {} + + is-alphanumerical@2.0.1: dependencies: - chalk: 4.1.2 - tinygradient: 1.1.5 - dev: true + is-alphabetical: 2.0.1 + is-decimal: 2.0.1 - /handlebars@4.7.9: - resolution: {integrity: sha512-4E71E0rpOaQuJR2A3xDZ+GM1HyWYv1clR58tC8emQNeQe3RH7MAzSbat+V0wG78LQBo6m6bzSG/L4pBuCsgnUQ==} - engines: {node: '>=0.4.7'} - hasBin: true + is-binary-path@2.1.0: dependencies: - minimist: 1.2.8 - neo-async: 2.6.2 - source-map: 0.6.1 - wordwrap: 1.0.0 - optionalDependencies: - uglify-js: 3.19.3 - dev: true + binary-extensions: 2.3.0 - /has-flag@3.0.0: - resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} - engines: {node: '>=4'} - dev: true + is-core-module@2.17.0: + dependencies: + hasown: 2.0.4 - /has-flag@4.0.0: - resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} - engines: {node: '>=8'} - dev: true + is-decimal@2.0.1: {} - /hasown@2.0.4: - resolution: {integrity: sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==} - engines: {node: '>= 0.4'} + is-docker@2.2.1: {} + + is-extglob@2.1.1: {} + + is-fullwidth-code-point@3.0.0: {} + + is-glob@4.0.3: dependencies: - function-bind: 1.1.2 - dev: true + is-extglob: 2.1.1 + + is-hexadecimal@2.0.1: {} + + is-number@7.0.0: {} + + is-plain-obj@4.1.0: {} + + is-port-reachable@4.0.0: {} + + is-property@1.0.2: {} + + is-stream@2.0.1: {} - /header-case@1.0.1: - resolution: {integrity: sha512-i0q9mkOeSuhXw6bGgiQCCBgY/jlZuV/7dZXyZ9c6LcBrqwvT8eT719E9uxE5LiZftdl+z81Ugbg/VvXV4OJOeQ==} + is-wsl@2.2.0: dependencies: - no-case: 2.3.2 - upper-case: 1.1.3 - dev: true + is-docker: 2.2.1 - /http-proxy-agent@7.0.2: - resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==} - engines: {node: '>= 14'} + isexe@2.0.0: {} + + jest-worker@27.5.1: dependencies: - agent-base: 7.1.4 - debug: 4.4.3 - transitivePeerDependencies: - - supports-color - dev: true + '@types/node': 26.6.5 + merge-stream: 2.0.0 + supports-color: 8.1.1 - /https-proxy-agent@7.0.6: - resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} - engines: {node: '>= 14'} + jiti@1.21.7: {} + + jiti@2.4.2: {} + + jiti@2.7.0: {} + + jose@6.2.13: {} + + joycon@3.1.1: {} + + js-base64@3.9.5: {} + + js-tokens@10.0.0: {} + + js-tokens@4.0.0: {} + + js-tokens@9.0.1: {} + + json-schema-traverse@0.4.1: {} + + json-schema-traverse@1.0.0: {} + + json-stable-stringify-without-jsonify@1.0.1: {} + + keyv@5.6.0: dependencies: - agent-base: 7.1.4 - debug: 4.4.3 - transitivePeerDependencies: - - supports-color - dev: true + '@keyv/serialize': 1.1.1 - /human-signals@2.1.0: - resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} - engines: {node: '>=10.17.0'} - dev: true + kleur@4.1.5: {} - /iconv-lite@0.4.24: - resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} - engines: {node: '>=0.10.0'} + kysely@0.29.6: {} + + levn@0.4.1: dependencies: - safer-buffer: 2.1.2 - dev: true + prelude-ls: 1.2.1 + type-check: 0.4.0 - /iconv-lite@0.7.3: - resolution: {integrity: sha512-IKXpvIzjnC9XTAUbVBcMfGS0EPaIXtW6v+zr+RRp+hqULEpo0owZax6wyRwPOJbWbzjYspQwusTsfVr0ifh4uQ==} - engines: {node: '>=0.10.0'} + libsql@0.5.29: dependencies: - safer-buffer: 2.1.2 + '@neon-rs/load': 0.0.4 + detect-libc: 2.0.2 + optionalDependencies: + '@libsql/darwin-arm64': 0.5.29 + '@libsql/darwin-x64': 0.5.29 + '@libsql/linux-arm-gnueabihf': 0.5.29 + '@libsql/linux-arm-musleabihf': 0.5.29 + '@libsql/linux-arm64-gnu': 0.5.29 + '@libsql/linux-arm64-musl': 0.5.29 + '@libsql/linux-x64-gnu': 0.5.29 + '@libsql/linux-x64-musl': 0.5.29 + '@libsql/win32-x64-msvc': 0.5.29 - /ieee754@1.2.1: - resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} - dev: true + lightningcss-android-arm64@1.32.0: + optional: true - /ignore@5.3.2: - resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} - engines: {node: '>= 4'} - dev: true + lightningcss-android-arm64@1.33.0: + optional: true - /import-fresh@3.3.1: - resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} - engines: {node: '>=6'} + lightningcss-darwin-arm64@1.32.0: + optional: true + + lightningcss-darwin-arm64@1.33.0: + optional: true + + lightningcss-darwin-x64@1.32.0: + optional: true + + lightningcss-darwin-x64@1.33.0: + optional: true + + lightningcss-freebsd-x64@1.32.0: + optional: true + + lightningcss-freebsd-x64@1.33.0: + optional: true + + lightningcss-linux-arm-gnueabihf@1.32.0: + optional: true + + lightningcss-linux-arm-gnueabihf@1.33.0: + optional: true + + lightningcss-linux-arm64-gnu@1.32.0: + optional: true + + lightningcss-linux-arm64-gnu@1.33.0: + optional: true + + lightningcss-linux-arm64-musl@1.32.0: + optional: true + + lightningcss-linux-arm64-musl@1.33.0: + optional: true + + lightningcss-linux-x64-gnu@1.32.0: + optional: true + + lightningcss-linux-x64-gnu@1.33.0: + optional: true + + lightningcss-linux-x64-musl@1.32.0: + optional: true + + lightningcss-linux-x64-musl@1.33.0: + optional: true + + lightningcss-win32-arm64-msvc@1.32.0: + optional: true + + lightningcss-win32-arm64-msvc@1.33.0: + optional: true + + lightningcss-win32-x64-msvc@1.32.0: + optional: true + + lightningcss-win32-x64-msvc@1.33.0: + optional: true + + lightningcss@1.32.0: + dependencies: + detect-libc: 2.1.2 + 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 + + lightningcss@1.33.0: + dependencies: + detect-libc: 2.1.2 + optionalDependencies: + lightningcss-android-arm64: 1.33.0 + lightningcss-darwin-arm64: 1.33.0 + lightningcss-darwin-x64: 1.33.0 + lightningcss-freebsd-x64: 1.33.0 + lightningcss-linux-arm-gnueabihf: 1.33.0 + lightningcss-linux-arm64-gnu: 1.33.0 + lightningcss-linux-arm64-musl: 1.33.0 + lightningcss-linux-x64-gnu: 1.33.0 + lightningcss-linux-x64-musl: 1.33.0 + lightningcss-win32-arm64-msvc: 1.33.0 + lightningcss-win32-x64-msvc: 1.33.0 + + lilconfig@2.1.0: {} + + lilconfig@3.1.4: {} + + linebreak@1.1.0: dependencies: - parent-module: 1.0.1 - resolve-from: 4.0.0 - dev: true + base64-js: 0.0.8 + unicode-trie: 2.0.0 - /imurmurhash@0.1.4: - resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} - engines: {node: '>=0.8.19'} - dev: true + lines-and-columns@1.2.4: {} - /indent-string@4.0.0: - resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} - engines: {node: '>=8'} - dev: true + load-tsconfig@0.2.5: {} - /inflight@1.0.6: - resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} - deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. + locate-path@6.0.0: dependencies: - once: 1.4.0 - wrappy: 1.0.2 - dev: true + p-locate: 5.0.0 - /inherits@2.0.4: - resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} - dev: true + long@5.3.2: {} - /ini@1.3.8: - resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} - dev: true + longest-streak@3.1.0: {} - /inquirer@7.3.3: - resolution: {integrity: sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA==} - engines: {node: '>=8.0.0'} + loose-envify@1.4.0: dependencies: - ansi-escapes: 4.3.2 - chalk: 4.1.2 - cli-cursor: 3.1.0 - cli-width: 3.0.0 - external-editor: 3.1.0 - figures: 3.2.0 - lodash: 4.18.1 - mute-stream: 0.0.8 - run-async: 2.4.1 - rxjs: 6.6.7 - string-width: 4.2.3 - strip-ansi: 6.0.1 - through: 2.3.8 - dev: true + js-tokens: 4.0.0 - /inquirer@8.2.7(@types/node@20.14.11): - resolution: {integrity: sha512-UjOaSel/iddGZJ5xP/Eixh6dY1XghiBw4XK13rCCIJcJfyhhoul/7KhLLUGtebEj6GDYM6Vnx/mVsjx2L/mFIA==} - engines: {node: '>=12.0.0'} - dependencies: - '@inquirer/external-editor': 1.0.3(@types/node@20.14.11) - ansi-escapes: 4.3.2 - chalk: 4.1.2 - cli-cursor: 3.1.0 - cli-width: 3.0.0 - figures: 3.2.0 - lodash: 4.18.1 - mute-stream: 0.0.8 - ora: 5.4.1 - run-async: 2.4.1 - rxjs: 7.8.2 - string-width: 4.2.3 - strip-ansi: 6.0.1 - through: 2.3.8 - wrap-ansi: 6.2.0 - transitivePeerDependencies: - - '@types/node' - dev: true + loupe@3.2.1: {} - /ip-address@10.2.0: - resolution: {integrity: sha512-/+S6j4E9AHvW9SWMSEY9Xfy66O5PWvVEJ08O0y5JGyEKQpojb0K0GKpz/v5HJ/G0vi3D2sjGK78119oXZeE0qA==} - engines: {node: '>= 12'} - dev: true + lru.min@1.1.5: {} - /is-binary-path@2.1.0: - resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} - engines: {node: '>=8'} + lucide-react@1.61.0(@types/react@19.3.0)(react@19.3.1): dependencies: - binary-extensions: 2.3.0 - dev: true + react: 19.3.1 + optionalDependencies: + '@types/react': 19.3.0 - /is-core-module@2.16.2: - resolution: {integrity: sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==} - engines: {node: '>= 0.4'} + magic-string@0.30.21: dependencies: - hasown: 2.0.4 - dev: true + '@jridgewell/sourcemap-codec': 1.6.0 - /is-extglob@2.1.1: - resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} - engines: {node: '>=0.10.0'} - dev: true + magic-string@1.4.4: + dependencies: + '@jridgewell/sourcemap-codec': 1.6.0 - /is-fullwidth-code-point@3.0.0: - resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} - engines: {node: '>=8'} - dev: true + markdown-extensions@2.0.0: {} - /is-glob@4.0.3: - resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} - engines: {node: '>=0.10.0'} - dependencies: - is-extglob: 2.1.1 - dev: true + markdown-table@3.0.4: {} - /is-interactive@1.0.0: - resolution: {integrity: sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==} - engines: {node: '>=8'} - dev: true + mdast-util-find-and-replace@3.0.4: + dependencies: + '@types/mdast': 4.0.4 + escape-string-regexp: 5.0.0 + unist-util-is: 6.0.1 + unist-util-visit-parents: 6.1.0 - /is-lower-case@1.1.3: - resolution: {integrity: sha512-+5A1e/WJpLLXZEDlgz4G//WYSHyQBD32qa4Jd3Lw06qQlv3fJHnp3YIHjTQSGzHMgzmVKz2ZP3rBxTHkPw/lxA==} + mdast-util-from-markdown@2.1.0(supports-color@10.2.2): dependencies: - lower-case: 1.1.4 - dev: true + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + decode-named-character-reference: 1.3.0 + devlop: 1.1.0 + mdast-util-to-string: 4.0.0 + micromark: 4.0.3(supports-color@10.2.2) + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-decode-string: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.3 + unist-util-stringify-position: 4.0.0 + transitivePeerDependencies: + - supports-color - /is-number@7.0.0: - resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} - engines: {node: '>=0.12.0'} - dev: true + mdast-util-gfm-autolink-literal@2.0.1: + dependencies: + '@types/mdast': 4.0.4 + ccount: 2.0.1 + devlop: 1.1.0 + mdast-util-find-and-replace: 3.0.4 + micromark-util-character: 2.1.1 - /is-path-cwd@2.2.0: - resolution: {integrity: sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==} - engines: {node: '>=6'} - dev: true + mdast-util-gfm-footnote@2.1.0(supports-color@10.2.2): + dependencies: + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.1.0(supports-color@10.2.2) + mdast-util-to-markdown: 2.2.0 + micromark-util-normalize-identifier: 2.0.1 + transitivePeerDependencies: + - supports-color - /is-path-inside@3.0.3: - resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} - engines: {node: '>=8'} - dev: true + mdast-util-gfm-strikethrough@2.0.1(supports-color@10.2.2): + dependencies: + '@types/mdast': 4.0.4 + mdast-util-from-markdown: 2.1.0(supports-color@10.2.2) + mdast-util-to-markdown: 2.2.0 + transitivePeerDependencies: + - supports-color - /is-property@1.0.2: - resolution: {integrity: sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==} - dev: false + mdast-util-gfm-table@2.0.0(supports-color@10.2.2): + dependencies: + '@types/mdast': 4.0.4 + devlop: 1.1.0 + markdown-table: 3.0.4 + mdast-util-from-markdown: 2.1.0(supports-color@10.2.2) + mdast-util-to-markdown: 2.2.0 + transitivePeerDependencies: + - supports-color - /is-stream@2.0.1: - resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} - engines: {node: '>=8'} - dev: true + mdast-util-gfm-task-list-item@2.0.0(supports-color@10.2.2): + dependencies: + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.1.0(supports-color@10.2.2) + mdast-util-to-markdown: 2.2.0 + transitivePeerDependencies: + - supports-color - /is-unicode-supported@0.1.0: - resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} - engines: {node: '>=10'} - dev: true + mdast-util-gfm@3.1.0(supports-color@10.2.2): + dependencies: + mdast-util-from-markdown: 2.1.0(supports-color@10.2.2) + mdast-util-gfm-autolink-literal: 2.0.1 + mdast-util-gfm-footnote: 2.1.0(supports-color@10.2.2) + mdast-util-gfm-strikethrough: 2.0.1(supports-color@10.2.2) + mdast-util-gfm-table: 2.0.0(supports-color@10.2.2) + mdast-util-gfm-task-list-item: 2.0.0(supports-color@10.2.2) + mdast-util-to-markdown: 2.2.0 + transitivePeerDependencies: + - supports-color - /is-upper-case@1.1.2: - resolution: {integrity: sha512-GQYSJMgfeAmVwh9ixyk888l7OIhNAGKtY6QA+IrWlu9MDTCaXmeozOZ2S9Knj7bQwBO/H6J2kb+pbyTUiMNbsw==} + mdast-util-mdx-expression@2.0.1(supports-color@10.2.2): dependencies: - upper-case: 1.1.3 - dev: true + '@types/estree-jsx': 1.0.5 + '@types/hast': 3.0.5 + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.1.0(supports-color@10.2.2) + mdast-util-to-markdown: 2.2.0 + transitivePeerDependencies: + - supports-color - /isbinaryfile@4.0.10: - resolution: {integrity: sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw==} - engines: {node: '>= 8.0.0'} - dev: true + mdast-util-mdx-jsx@3.2.0(supports-color@10.2.2): + dependencies: + '@types/estree-jsx': 1.0.5 + '@types/hast': 3.0.5 + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + ccount: 2.0.1 + devlop: 1.1.0 + mdast-util-from-markdown: 2.1.0(supports-color@10.2.2) + mdast-util-to-markdown: 2.2.0 + parse-entities: 4.0.2 + stringify-entities: 4.0.4 + unist-util-stringify-position: 4.0.0 + vfile-message: 4.0.3 + transitivePeerDependencies: + - supports-color - /isexe@2.0.0: - resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - dev: true + mdast-util-mdx@3.0.0(supports-color@10.2.2): + dependencies: + mdast-util-from-markdown: 2.1.0(supports-color@10.2.2) + mdast-util-mdx-expression: 2.0.1(supports-color@10.2.2) + mdast-util-mdx-jsx: 3.2.0(supports-color@10.2.2) + mdast-util-mdxjs-esm: 2.0.1(supports-color@10.2.2) + mdast-util-to-markdown: 2.2.0 + transitivePeerDependencies: + - supports-color - /jiti@1.21.7: - resolution: {integrity: sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==} - hasBin: true - dev: true + mdast-util-mdxjs-esm@2.0.1(supports-color@10.2.2): + dependencies: + '@types/estree-jsx': 1.0.5 + '@types/hast': 3.0.5 + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.1.0(supports-color@10.2.2) + mdast-util-to-markdown: 2.2.0 + transitivePeerDependencies: + - supports-color - /jiti@2.4.2: - resolution: {integrity: sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==} - hasBin: true + mdast-util-phrasing@4.1.0: + dependencies: + '@types/mdast': 4.0.4 + unist-util-is: 6.0.1 + + mdast-util-to-hast@13.2.1: + dependencies: + '@types/hast': 3.0.5 + '@types/mdast': 4.0.4 + '@ungap/structured-clone': 1.4.0 + devlop: 1.1.0 + micromark-util-sanitize-uri: 2.0.1 + trim-lines: 3.0.1 + unist-util-position: 5.0.0 + unist-util-visit: 5.2.0 + vfile: 6.0.3 + + mdast-util-to-markdown@2.2.0: + dependencies: + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + longest-streak: 3.1.0 + mdast-util-phrasing: 4.1.0 + mdast-util-to-string: 4.0.0 + micromark-util-character: 2.1.1 + micromark-util-classify-character: 2.0.1 + micromark-util-decode-string: 2.0.1 + micromark-util-html-tag-name: 2.0.1 + unist-util-visit: 5.2.0 + zwitch: 2.0.4 + + mdast-util-to-string@4.0.0: + dependencies: + '@types/mdast': 4.0.4 + + merge-stream@2.0.0: {} + + merge2@1.4.1: {} + + micromark-core-commonmark@2.0.4: + dependencies: + decode-named-character-reference: 1.3.0 + devlop: 1.1.0 + micromark-factory-destination: 2.0.1 + micromark-factory-label: 2.0.1 + micromark-factory-space: 2.1.0 + micromark-factory-title: 2.0.1 + micromark-factory-whitespace: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-chunked: 2.0.1 + micromark-util-classify-character: 2.0.1 + micromark-util-edit-map: 1.0.0 + micromark-util-html-tag-name: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-subtokenize: 2.1.0 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.3 + + micromark-extension-gfm-autolink-literal@2.1.0: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.3 + + micromark-extension-gfm-footnote@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-core-commonmark: 2.0.4 + micromark-factory-space: 2.1.0 + micromark-util-character: 2.1.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.3 + + micromark-extension-gfm-strikethrough@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-util-chunked: 2.0.1 + micromark-util-classify-character: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.3 + + micromark-extension-gfm-table@2.1.2: + dependencies: + devlop: 1.1.0 + micromark-factory-space: 2.1.0 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.3 + + micromark-extension-gfm-tagfilter@2.0.0: + dependencies: + micromark-util-types: 2.0.3 + + micromark-extension-gfm-task-list-item@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-factory-space: 2.1.0 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.3 + + micromark-extension-gfm@3.0.0: + dependencies: + micromark-extension-gfm-autolink-literal: 2.1.0 + micromark-extension-gfm-footnote: 2.1.0 + micromark-extension-gfm-strikethrough: 2.1.0 + micromark-extension-gfm-table: 2.1.2 + micromark-extension-gfm-tagfilter: 2.0.0 + micromark-extension-gfm-task-list-item: 2.1.0 + micromark-util-combine-extensions: 2.0.1 + micromark-util-types: 2.0.3 + + micromark-extension-mdx-expression@3.0.1: + dependencies: + '@types/estree': 1.0.9 + devlop: 1.1.0 + micromark-factory-mdx-expression: 2.0.3 + micromark-factory-space: 2.1.0 + micromark-util-character: 2.1.1 + micromark-util-events-to-acorn: 2.0.3 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.3 - /jiti@2.7.0: - resolution: {integrity: sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==} - hasBin: true - dev: false + micromark-extension-mdx-jsx@3.0.2: + dependencies: + '@types/estree': 1.0.9 + devlop: 1.1.0 + estree-util-is-identifier-name: 3.0.0 + micromark-factory-mdx-expression: 2.0.3 + micromark-factory-space: 2.1.0 + micromark-util-character: 2.1.1 + micromark-util-events-to-acorn: 2.0.3 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.3 + vfile-message: 4.0.3 - /jose@6.2.3: - resolution: {integrity: sha512-YYVDInQKFJfR/xa3ojUTl8c2KoTwiL1R5Wg9YCydwH0x0B9grbzlg5HC7mMjCtUJjbQ/YnGEZIhI5tCgfTb4Hw==} - dev: false + micromark-extension-mdx-md@2.0.0: + dependencies: + micromark-util-types: 2.0.3 - /joycon@3.1.1: - resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==} - engines: {node: '>=10'} - dev: true + micromark-extension-mdxjs-esm@3.0.0: + dependencies: + '@types/estree': 1.0.9 + devlop: 1.1.0 + micromark-core-commonmark: 2.0.4 + micromark-util-character: 2.1.1 + micromark-util-events-to-acorn: 2.0.3 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.3 + unist-util-position-from-estree: 2.0.0 + vfile-message: 4.0.3 - /js-tokens@4.0.0: - resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + micromark-extension-mdxjs@3.0.0: + dependencies: + acorn: 8.19.0 + acorn-jsx: 5.3.2(acorn@8.19.0) + micromark-extension-mdx-expression: 3.0.1 + micromark-extension-mdx-jsx: 3.0.2 + micromark-extension-mdx-md: 2.0.0 + micromark-extension-mdxjs-esm: 3.0.0 + micromark-util-combine-extensions: 2.0.1 + micromark-util-types: 2.0.3 - /js-tokens@9.0.1: - resolution: {integrity: sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==} + micromark-factory-destination@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.3 - /js-yaml@4.3.0: - resolution: {integrity: sha512-1td788aAnnZ5qs7V2QIRl1owjtYpbKt749Y3xauqQgwIIGF/xXWz1wMTEBx5O3LK3lXLVuqXPdPxj2BoFHaW9Q==} - hasBin: true + micromark-factory-label@2.0.1: dependencies: - argparse: 2.0.1 - dev: true + devlop: 1.1.0 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.3 - /json-buffer@3.0.1: - resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} - dev: true + micromark-factory-mdx-expression@2.0.3: + dependencies: + '@types/estree': 1.0.9 + devlop: 1.1.0 + micromark-factory-space: 2.1.0 + micromark-util-character: 2.1.1 + micromark-util-events-to-acorn: 2.0.3 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.3 + unist-util-position-from-estree: 2.0.0 + vfile-message: 4.0.3 - /json-schema-traverse@0.4.1: - resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} - dev: true + micromark-factory-space@2.1.0: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-types: 2.0.3 - /json-stable-stringify-without-jsonify@1.0.1: - resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} - dev: true + micromark-factory-title@2.0.1: + dependencies: + micromark-factory-space: 2.1.0 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.3 - /jsonfile@6.2.1: - resolution: {integrity: sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==} + micromark-factory-whitespace@2.0.1: dependencies: - universalify: 2.0.1 - optionalDependencies: - graceful-fs: 4.2.11 - dev: true + micromark-factory-space: 2.1.0 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.3 - /keyv@4.5.4: - resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + micromark-util-character@2.1.1: dependencies: - json-buffer: 3.0.1 - dev: true + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.3 - /kysely@0.29.6: - resolution: {integrity: sha512-hHaB8C/rfzDDtr/t8YZwxAuPJTT0zHyaPoVzcXwDYhYNAgH/4sIfVhi/XLLIY+bL/FqaIJnjATDbi8ObSELmxg==} - engines: {node: '>=22.0.0'} + micromark-util-chunked@2.0.1: + dependencies: + micromark-util-symbol: 2.0.1 - /levn@0.4.1: - resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} - engines: {node: '>= 0.8.0'} + micromark-util-classify-character@2.0.1: dependencies: - prelude-ls: 1.2.1 - type-check: 0.4.0 - dev: true + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.3 - /libsql@0.5.29: - resolution: {integrity: sha512-8lMP8iMgiBzzoNbAPQ59qdVcj6UaE/Vnm+fiwX4doX4Narook0a4GPKWBEv+CR8a1OwbfkgL18uBfBjWdF0Fzg==} - cpu: [x64, arm64, wasm32, arm] - os: [darwin, linux, win32] + micromark-util-combine-extensions@2.0.1: dependencies: - '@neon-rs/load': 0.0.4 - detect-libc: 2.0.2 - optionalDependencies: - '@libsql/darwin-arm64': 0.5.29 - '@libsql/darwin-x64': 0.5.29 - '@libsql/linux-arm-gnueabihf': 0.5.29 - '@libsql/linux-arm-musleabihf': 0.5.29 - '@libsql/linux-arm64-gnu': 0.5.29 - '@libsql/linux-arm64-musl': 0.5.29 - '@libsql/linux-x64-gnu': 0.5.29 - '@libsql/linux-x64-musl': 0.5.29 - '@libsql/win32-x64-msvc': 0.5.29 - dev: false + micromark-util-chunked: 2.0.1 + micromark-util-types: 2.0.3 - /lilconfig@2.1.0: - resolution: {integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==} - engines: {node: '>=10'} - dev: true + micromark-util-decode-numeric-character-reference@2.0.2: + dependencies: + micromark-util-symbol: 2.0.1 - /lilconfig@3.1.3: - resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==} - engines: {node: '>=14'} - dev: true + micromark-util-decode-string@2.0.1: + dependencies: + decode-named-character-reference: 1.3.0 + micromark-util-character: 2.1.1 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-symbol: 2.0.1 - /lines-and-columns@1.2.4: - resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} - dev: true + micromark-util-edit-map@1.0.0: + dependencies: + micromark-util-types: 2.0.3 - /load-tsconfig@0.2.5: - resolution: {integrity: sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - dev: true + micromark-util-encode@2.0.1: {} - /locate-path@6.0.0: - resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} - engines: {node: '>=10'} + micromark-util-events-to-acorn@2.0.3: dependencies: - p-locate: 5.0.0 - dev: true + '@types/estree': 1.0.9 + '@types/unist': 3.0.3 + devlop: 1.1.0 + estree-util-visit: 2.0.0 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.3 + vfile-message: 4.0.3 - /lodash.get@4.4.2: - resolution: {integrity: sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==} - deprecated: This package is deprecated. Use the optional chaining (?.) operator instead. - dev: true + micromark-util-html-tag-name@2.0.1: {} - /lodash.merge@4.6.2: - resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} - dev: true + micromark-util-normalize-identifier@2.0.1: + dependencies: + micromark-util-symbol: 2.0.1 - /lodash@4.18.1: - resolution: {integrity: sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==} - dev: true + micromark-util-resolve-all@2.0.1: + dependencies: + micromark-util-types: 2.0.3 - /log-symbols@3.0.0: - resolution: {integrity: sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ==} - engines: {node: '>=8'} + micromark-util-sanitize-uri@2.0.1: dependencies: - chalk: 2.4.2 - dev: true + micromark-util-character: 2.1.1 + micromark-util-encode: 2.0.1 + micromark-util-symbol: 2.0.1 - /log-symbols@4.1.0: - resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} - engines: {node: '>=10'} + micromark-util-subtokenize@2.1.0: dependencies: - chalk: 4.1.2 - is-unicode-supported: 0.1.0 - dev: true + devlop: 1.1.0 + micromark-util-chunked: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.3 - /long@5.3.2: - resolution: {integrity: sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==} - dev: false + micromark-util-symbol@2.0.1: {} - /loose-envify@1.4.0: - resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} - hasBin: true - dependencies: - js-tokens: 4.0.0 + micromark-util-types@2.0.3: {} - /loupe@3.2.1: - resolution: {integrity: sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==} + micromark@4.0.3(supports-color@10.2.2): + dependencies: + '@types/debug': 4.1.13 + debug: 4.4.3(supports-color@10.2.2) + decode-named-character-reference: 1.3.0 + devlop: 1.1.0 + micromark-core-commonmark: 2.0.4 + micromark-factory-space: 2.1.0 + micromark-util-character: 2.1.1 + micromark-util-chunked: 2.0.1 + micromark-util-combine-extensions: 2.0.1 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-edit-map: 1.0.0 + micromark-util-encode: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-subtokenize: 2.1.0 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.3 + transitivePeerDependencies: + - supports-color - /lower-case-first@1.0.2: - resolution: {integrity: sha512-UuxaYakO7XeONbKrZf5FEgkantPf5DUqDayzP5VXZrtRPdH86s4kN47I8B3TW10S4QKiE3ziHNf3kRN//okHjA==} + micromatch@4.0.8: dependencies: - lower-case: 1.1.4 - dev: true + braces: 3.0.3 + picomatch: 2.3.2 - /lower-case@1.1.4: - resolution: {integrity: sha512-2Fgx1Ycm599x+WGpIYwJOvsjmXFzTSc34IwDWALRA/8AopUKAVPwfJ+h5+f85BCp0PWmmJcWzEpxOpoXycMpdA==} - dev: true + mikro-orm@7.2.1: {} - /lru-cache@7.18.3: - resolution: {integrity: sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==} - engines: {node: '>=12'} - dev: true + mime-db@1.33.0: {} - /lru.min@1.1.5: - resolution: {integrity: sha512-5J9ysMYUpYIg9RF2vJpy9SinEmSviFSe0GyPpCQ4L5QSkLAgeLXlTAOu2ZwWUU5m+0SBl6gUU1R1ZQB3aKypfA==} - engines: {bun: '>=1.0.0', deno: '>=1.30.0', node: '>=8.0.0'} - dev: false + mime-db@1.54.0: {} - /magic-string@0.30.21: - resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + mime-types@2.1.18: dependencies: - '@jridgewell/sourcemap-codec': 1.5.5 - - /make-error@1.3.6: - resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} - dev: true + mime-db: 1.33.0 - /merge-stream@2.0.0: - resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} - dev: true + mimic-fn@2.1.0: {} - /merge2@1.4.1: - resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} - engines: {node: '>= 8'} - dev: true + miniflare@5.20261012.0-beta(@types/node@22.18.6): + dependencies: + '@cspotcode/source-map-support': 0.8.1 + sharp: 0.35.5(@types/node@22.18.6) + undici: 7.29.1 + workerd: 1.20261012.1 + ws: 8.21.0 + youch: 4.1.0-beta.10 + transitivePeerDependencies: + - '@types/node' + - bufferutil + - utf-8-validate - /micromatch@4.0.8: - resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} - engines: {node: '>=8.6'} + miniflare@5.20261019.1-beta(@types/node@22.18.6): dependencies: - braces: 3.0.3 - picomatch: 2.3.2 - dev: true + '@cspotcode/source-map-support': 0.8.1 + sharp: 0.35.5(@types/node@22.18.6) + undici: 7.29.1 + workerd: 1.20261019.1 + ws: 8.21.0 + youch: 4.1.0-beta.10 + transitivePeerDependencies: + - '@types/node' + - bufferutil + - utf-8-validate - /mimic-fn@2.1.0: - resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} - engines: {node: '>=6'} - dev: true + miniflare@5.20261019.1-beta(@types/node@26.6.5): + dependencies: + '@cspotcode/source-map-support': 0.8.1 + sharp: 0.35.5(@types/node@26.6.5) + undici: 7.29.1 + workerd: 1.20261019.1 + ws: 8.21.0 + youch: 4.1.0-beta.10 + transitivePeerDependencies: + - '@types/node' + - bufferutil + - utf-8-validate - /minimatch@3.1.5: - resolution: {integrity: sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==} + minimatch@10.2.6: dependencies: - brace-expansion: 1.1.16 - dev: true + brace-expansion: 5.0.12 - /minimatch@9.0.9: - resolution: {integrity: sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==} - engines: {node: '>=16 || 14 >=14.17'} + minimatch@3.1.5: dependencies: - brace-expansion: 2.1.2 - dev: true + brace-expansion: 1.1.21 - /minimist@1.2.8: - resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} - dev: true + minimist@1.2.8: {} - /mkdirp@0.5.6: - resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==} - hasBin: true + minimizer-webpack-plugin@5.13.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.4.39)(sharp@0.35.5(@types/node@22.18.6))(webpack@5.112.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.4.39)(sharp@0.35.5(@types/node@22.18.6))): dependencies: - minimist: 1.2.8 - dev: true + '@jridgewell/trace-mapping': 0.3.31 + jest-worker: 27.5.1 + schema-utils: 4.8.1(webpack@5.112.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.4.39)(sharp@0.35.5(@types/node@22.18.6))) + terser: 5.51.2 + webpack: 5.112.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.4.39)(sharp@0.35.5(@types/node@22.18.6)) + optionalDependencies: + esbuild: 0.28.2 + lightningcss: 1.33.0 + postcss: 8.4.39 + sharp: 0.35.5(@types/node@22.18.6) - /mlly@1.8.2: - resolution: {integrity: sha512-d+ObxMQFmbt10sretNDytwt85VrbkhhUA/JBGm1MPaWJ65Cl4wOgLaB1NYvJSZ0Ef03MMEU/0xpPMXUIQ29UfA==} + mlly@1.8.2: dependencies: - acorn: 8.17.0 + acorn: 8.19.0 pathe: 2.0.3 pkg-types: 1.3.1 ufo: 1.6.4 - dev: true - /ms@2.1.3: - resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + motion-dom@14.6.0: + dependencies: + motion-utils: 14.6.0 - /mute-stream@0.0.8: - resolution: {integrity: sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==} - dev: true + motion-utils@14.6.0: {} - /mysql2@3.24.4(@types/node@22.18.6): - resolution: {integrity: sha512-A2olluVlj0mvgyIRRISMEzXc51m+21mRtcMVjJyIpt2GG98+XrC9m9HzsqcMsX2LcnfccJvY5NB22g8fENBnOA==} - engines: {node: '>= 8.0'} - peerDependencies: - '@types/node': '>= 8' + motion@14.6.0(react-dom@19.3.1(react@19.3.1))(react@19.3.1): + dependencies: + framer-motion: 14.6.0(react-dom@19.3.1(react@19.3.1))(react@19.3.1) + tslib: 2.8.1 + optionalDependencies: + react: 19.3.1 + react-dom: 19.3.1(react@19.3.1) + + ms@2.0.0: {} + + ms@2.1.3: {} + + mute-stream@2.0.0: {} + + mysql2@3.24.4(@types/node@20.14.11): + dependencies: + '@types/node': 20.14.11 + aws-ssl-profiles: 1.1.2 + generate-function: 2.3.1 + iconv-lite: 0.7.3 + long: 5.3.2 + lru.min: 1.1.5 + named-placeholders: 1.1.6 + sql-escaper: 1.5.2 + + mysql2@3.24.4(@types/node@22.18.6): dependencies: '@types/node': 22.18.6 aws-ssl-profiles: 1.1.2 @@ -5027,73 +10718,98 @@ packages: lru.min: 1.1.5 named-placeholders: 1.1.6 sql-escaper: 1.5.2 - dev: false - /mz@2.7.0: - resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} + mz@2.7.0: dependencies: any-promise: 1.3.0 object-assign: 4.1.1 thenify-all: 1.6.0 - dev: true - /named-placeholders@1.1.6: - resolution: {integrity: sha512-Tz09sEL2EEuv5fFowm419c1+a/jSMiBjI9gHxVLrVdbUkkNUUfjsVYs9pVZu5oCon/kmRh9TfLEObFtkVxmY0w==} - engines: {node: '>=8.0.0'} + named-placeholders@1.1.6: dependencies: lru.min: 1.1.5 - dev: false - /nanoid@3.3.15: - resolution: {integrity: sha512-y7Wygv/7mEOvxTuEQDB8StXdMRBWf1kR/tlhAzBRUFkB2jfcLOAxO/SHmOO2zgz1pVgK29/kyupn059/bCHdjA==} - engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} - hasBin: true + nanoid@3.3.20: {} - /nanostores@1.4.0: - resolution: {integrity: sha512-i0tloweeudshAEuddpDxcg9Ik6pkPfVsHIgKyf143JrgG7/MOh0+q7BypdLXZPoOP7fOYt1eTcwGkyiVmhJFkA==} - engines: {node: ^20.0.0 || >=22.0.0} - dev: false + nanostores@1.5.5: {} - /natural-compare@1.4.0: - resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} - dev: true + natural-compare@1.4.0: {} - /neo-async@2.6.2: - resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} - dev: true + negotiator@0.6.4: {} + + neo-async@2.6.2: {} + + next-themes@0.4.6(react-dom@19.3.1(react@19.3.1))(react@19.3.1): + dependencies: + react: 19.3.1 + react-dom: 19.3.1(react@19.3.1) + + next@14.2.35(@playwright/test@1.64.1)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + dependencies: + '@next/env': 14.2.35 + '@swc/helpers': 0.5.5 + '@types/react': 18.3.3 + busboy: 1.6.0 + caniuse-lite: 1.0.30001819 + graceful-fs: 4.2.11 + postcss: 8.4.31 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + styled-jsx: 5.1.1(react@18.3.1) + optionalDependencies: + '@next/swc-darwin-arm64': 14.2.33 + '@next/swc-darwin-x64': 14.2.33 + '@next/swc-linux-arm64-gnu': 14.2.33 + '@next/swc-linux-arm64-musl': 14.2.33 + '@next/swc-linux-x64-gnu': 14.2.33 + '@next/swc-linux-x64-musl': 14.2.33 + '@next/swc-win32-arm64-msvc': 14.2.33 + '@next/swc-win32-ia32-msvc': 14.2.33 + '@next/swc-win32-x64-msvc': 14.2.33 + '@playwright/test': 1.64.1 + transitivePeerDependencies: + - '@babel/core' + - babel-plugin-macros - /netmask@2.1.1: - resolution: {integrity: sha512-eonl3sLUha+S1GzTPxychyhnUzKyeQkZ7jLjKrBagJgPla13F+uQ71HgpFefyHgqrjEbCPkDArxYsjY8/+gLKA==} - engines: {node: '>= 0.4.0'} - dev: true + next@14.2.35(@playwright/test@1.64.1)(@types/react@18.3.3)(react-dom@18.3.1(react@19.3.1))(react@19.3.1): + dependencies: + '@next/env': 14.2.35 + '@swc/helpers': 0.5.5 + '@types/react': 18.3.3 + busboy: 1.6.0 + caniuse-lite: 1.0.30001819 + graceful-fs: 4.2.11 + postcss: 8.4.31 + react: 19.3.1 + react-dom: 18.3.1(react@19.3.1) + styled-jsx: 5.1.1(react@19.3.1) + optionalDependencies: + '@next/swc-darwin-arm64': 14.2.33 + '@next/swc-darwin-x64': 14.2.33 + '@next/swc-linux-arm64-gnu': 14.2.33 + '@next/swc-linux-arm64-musl': 14.2.33 + '@next/swc-linux-x64-gnu': 14.2.33 + '@next/swc-linux-x64-musl': 14.2.33 + '@next/swc-win32-arm64-msvc': 14.2.33 + '@next/swc-win32-ia32-msvc': 14.2.33 + '@next/swc-win32-x64-msvc': 14.2.33 + '@playwright/test': 1.64.1 + transitivePeerDependencies: + - '@babel/core' + - babel-plugin-macros - /next@14.2.35(react-dom@18.3.1)(react@18.3.1): - resolution: {integrity: sha512-KhYd2Hjt/O1/1aZVX3dCwGXM1QmOV4eNM2UTacK5gipDdPN/oHHK/4oVGy7X8GMfPMsUTUEmGlsy0EY1YGAkig==} - engines: {node: '>=18.17.0'} - hasBin: true - peerDependencies: - '@opentelemetry/api': ^1.1.0 - '@playwright/test': ^1.41.2 - react: ^18.2.0 - react-dom: ^18.2.0 - sass: ^1.3.0 - peerDependenciesMeta: - '@opentelemetry/api': - optional: true - '@playwright/test': - optional: true - sass: - optional: true + next@14.2.35(@playwright/test@1.64.1)(@types/react@19.3.0)(react-dom@19.3.1(react@19.3.1))(react@19.3.1): dependencies: '@next/env': 14.2.35 '@swc/helpers': 0.5.5 + '@types/react': 19.3.0 busboy: 1.6.0 - caniuse-lite: 1.0.30001803 + caniuse-lite: 1.0.30001819 graceful-fs: 4.2.11 postcss: 8.4.31 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - styled-jsx: 5.1.1(react@18.3.1) + react: 19.3.1 + react-dom: 19.3.1(react@19.3.1) + styled-jsx: 5.1.1(react@19.3.1) optionalDependencies: '@next/swc-darwin-arm64': 14.2.33 '@next/swc-darwin-x64': 14.2.33 @@ -5104,85 +10820,98 @@ packages: '@next/swc-win32-arm64-msvc': 14.2.33 '@next/swc-win32-ia32-msvc': 14.2.33 '@next/swc-win32-x64-msvc': 14.2.33 + '@playwright/test': 1.64.1 transitivePeerDependencies: - '@babel/core' - babel-plugin-macros - /no-case@2.3.2: - resolution: {integrity: sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==} + next@16.4.2(@playwright/test@1.64.1)(@types/node@20.14.11)(react-dom@19.3.1(react@19.3.1))(react@19.3.1): dependencies: - lower-case: 1.1.4 - dev: true + '@next/env': 16.4.2 + '@swc/helpers': 0.5.23 + baseline-browser-mapping: 2.11.33 + caniuse-lite: 1.0.30001819 + postcss: 8.5.23 + react: 19.3.1 + react-dom: 19.3.1(react@19.3.1) + styled-jsx: 5.1.6(react@19.3.1) + optionalDependencies: + '@next/swc-darwin-arm64': 16.4.2 + '@next/swc-darwin-x64': 16.4.2 + '@next/swc-linux-arm64-gnu': 16.4.2 + '@next/swc-linux-arm64-musl': 16.4.2 + '@next/swc-linux-x64-gnu': 16.4.2 + '@next/swc-linux-x64-musl': 16.4.2 + '@next/swc-win32-arm64-msvc': 16.4.2 + '@next/swc-win32-x64-msvc': 16.4.2 + '@playwright/test': 1.64.1 + sharp: 0.35.5(@types/node@20.14.11) + transitivePeerDependencies: + - '@babel/core' + - '@types/node' + - babel-plugin-macros - /node-addon-api@8.9.2: - resolution: {integrity: sha512-VijLXbi3UACN69I0JVXJsX4tjACjNoQDgv2gTF6sx2wWEi8tkSg2eX8p5gSIFi8z2+DL3oHmY6OyKce38SDolg==} - engines: {node: ^18 || ^20 || >= 21} + next@16.4.2(@playwright/test@1.64.1)(@types/node@26.6.5)(react-dom@19.3.1(react@19.3.1))(react@19.3.1): + dependencies: + '@next/env': 16.4.2 + '@swc/helpers': 0.5.23 + baseline-browser-mapping: 2.11.33 + caniuse-lite: 1.0.30001819 + postcss: 8.5.23 + react: 19.3.1 + react-dom: 19.3.1(react@19.3.1) + styled-jsx: 5.1.6(react@19.3.1) + optionalDependencies: + '@next/swc-darwin-arm64': 16.4.2 + '@next/swc-darwin-x64': 16.4.2 + '@next/swc-linux-arm64-gnu': 16.4.2 + '@next/swc-linux-arm64-musl': 16.4.2 + '@next/swc-linux-x64-gnu': 16.4.2 + '@next/swc-linux-x64-musl': 16.4.2 + '@next/swc-win32-arm64-msvc': 16.4.2 + '@next/swc-win32-x64-msvc': 16.4.2 + '@playwright/test': 1.64.1 + sharp: 0.35.5(@types/node@26.6.5) + transitivePeerDependencies: + - '@babel/core' + - '@types/node' + - babel-plugin-macros - /node-plop@0.26.3: - resolution: {integrity: sha512-Cov028YhBZ5aB7MdMWJEmwyBig43aGL5WT4vdoB28Oitau1zZAcHUn8Sgfk9HM33TqhtLJ9PlM/O0Mv+QpV/4Q==} - engines: {node: '>=8.9.4'} - dependencies: - '@babel/runtime-corejs3': 7.29.7 - '@types/inquirer': 6.5.0 - change-case: 3.1.0 - del: 5.1.0 - globby: 10.0.2 - handlebars: 4.7.9 - inquirer: 7.3.3 - isbinaryfile: 4.0.10 - lodash.get: 4.4.2 - mkdirp: 0.5.6 - resolve: 1.22.12 - dev: true - - /node-releases@2.0.51: - resolution: {integrity: sha512-wRNIrw4DmVLKQlbgOMdkMx27Wrpzes2hh5Jtbi2bjPd+4wJstWIqP5A+lscnqbm0xxmT5Bpg8Lec5ItEBwx6BQ==} - engines: {node: '>=18'} - dev: true + node-addon-api@8.9.2: {} - /normalize-path@3.0.0: - resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} - engines: {node: '>=0.10.0'} - dev: true + node-releases@2.0.60: {} - /normalize-range@0.1.2: - resolution: {integrity: sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==} - engines: {node: '>=0.10.0'} - dev: true + normalize-path@3.0.0: {} - /npm-run-path@4.0.1: - resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} - engines: {node: '>=8'} + normalize-range@0.1.2: {} + + npm-run-path@4.0.1: dependencies: path-key: 3.1.1 - dev: true - /object-assign@4.1.1: - resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} - engines: {node: '>=0.10.0'} - dev: true + npm-to-yarn@3.2.0: {} - /object-hash@3.0.0: - resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==} - engines: {node: '>= 6'} - dev: true + object-assign@4.1.1: {} - /once@1.4.0: - resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} - dependencies: - wrappy: 1.0.2 - dev: true + object-hash@3.0.0: {} - /onetime@5.1.2: - resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} - engines: {node: '>=6'} + obug@3.0.0: {} + + on-headers@1.1.0: {} + + onetime@5.1.2: dependencies: mimic-fn: 2.1.0 - dev: true - /optionator@0.9.4: - resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} - engines: {node: '>= 0.8.0'} + oniguruma-parser@0.12.2: {} + + oniguruma-to-es@4.3.6: + dependencies: + oniguruma-parser: 0.12.2 + regex: 6.1.0 + regex-recursion: 6.0.2 + + optionator@0.9.4: dependencies: deep-is: 0.1.4 fast-levenshtein: 2.0.6 @@ -5190,927 +10919,812 @@ packages: prelude-ls: 1.2.1 type-check: 0.4.0 word-wrap: 1.2.5 - dev: true - - /ora@4.1.1: - resolution: {integrity: sha512-sjYP8QyVWBpBZWD6Vr1M/KwknSw6kJOz41tvGMlwWeClHBtYKTbHMki1PsLZnxKpXMPbTKv9b3pjQu3REib96A==} - engines: {node: '>=8'} - dependencies: - chalk: 3.0.0 - cli-cursor: 3.1.0 - cli-spinners: 2.9.2 - is-interactive: 1.0.0 - log-symbols: 3.0.0 - mute-stream: 0.0.8 - strip-ansi: 6.0.1 - wcwidth: 1.0.1 - dev: true - - /ora@5.4.1: - resolution: {integrity: sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==} - engines: {node: '>=10'} - dependencies: - bl: 4.1.0 - chalk: 4.1.2 - cli-cursor: 3.1.0 - cli-spinners: 2.9.2 - is-interactive: 1.0.0 - is-unicode-supported: 0.1.0 - log-symbols: 4.1.0 - strip-ansi: 6.0.1 - wcwidth: 1.0.1 - dev: true - - /os-tmpdir@1.0.2: - resolution: {integrity: sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==} - engines: {node: '>=0.10.0'} - dev: true - /p-limit@3.1.0: - resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} - engines: {node: '>=10'} + p-limit@3.1.0: dependencies: yocto-queue: 0.1.0 - dev: true - /p-locate@5.0.0: - resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} - engines: {node: '>=10'} + p-locate@5.0.0: dependencies: p-limit: 3.1.0 - dev: true - - /p-map@3.0.0: - resolution: {integrity: sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==} - engines: {node: '>=8'} - dependencies: - aggregate-error: 3.1.0 - dev: true - - /pac-proxy-agent@7.2.0: - resolution: {integrity: sha512-TEB8ESquiLMc0lV8vcd5Ql/JAKAoyzHFXaStwjkzpOpC5Yv+pIzLfHvjTSdf3vpa2bMiUQrg9i6276yn8666aA==} - engines: {node: '>= 14'} - dependencies: - '@tootallnate/quickjs-emscripten': 0.23.0 - agent-base: 7.1.4 - debug: 4.4.3 - get-uri: 6.0.5 - http-proxy-agent: 7.0.2 - https-proxy-agent: 7.0.6 - pac-resolver: 7.0.1 - socks-proxy-agent: 8.0.5 - transitivePeerDependencies: - - supports-color - dev: true - /pac-resolver@7.0.1: - resolution: {integrity: sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==} - engines: {node: '>= 14'} - dependencies: - degenerator: 5.0.1 - netmask: 2.1.1 - dev: true - - /param-case@2.1.1: - resolution: {integrity: sha512-eQE845L6ot89sk2N8liD8HAuH4ca6Vvr7VWAWwt7+kvvG5aBcPmmphQ68JsEG2qa9n1TykS2DLeMt363AAH8/w==} - dependencies: - no-case: 2.3.2 - dev: true + pako@0.2.9: {} - /parent-module@1.0.1: - resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} - engines: {node: '>=6'} + parse-css-color@0.2.1: dependencies: - callsites: 3.1.0 - dev: true + color-name: 1.1.4 + hex-rgb: 4.3.0 - /pascal-case@2.0.1: - resolution: {integrity: sha512-qjS4s8rBOJa2Xm0jmxXiyh1+OFf6ekCWOvUaRgAQSktzlTbMotS0nmG9gyYAybCWBcuP4fsBeRCKNwGBnMe2OQ==} + parse-entities@4.0.2: dependencies: - camel-case: 3.0.0 - upper-case-first: 1.1.2 - dev: true + '@types/unist': 2.0.11 + character-entities-legacy: 3.0.0 + character-reference-invalid: 2.0.1 + decode-named-character-reference: 1.3.0 + is-alphanumerical: 2.0.1 + is-decimal: 2.0.1 + is-hexadecimal: 2.0.1 - /path-case@2.1.1: - resolution: {integrity: sha512-Ou0N05MioItesaLr9q8TtHVWmJ6fxWdqKB2RohFmNWVyJ+2zeKIeDNWAN6B/Pe7wpzWChhZX6nONYmOnMeJQ/Q==} - dependencies: - no-case: 2.3.2 - dev: true + path-exists@4.0.0: {} - /path-exists@4.0.0: - resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} - engines: {node: '>=8'} - dev: true + path-is-inside@1.0.2: {} - /path-is-absolute@1.0.1: - resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} - engines: {node: '>=0.10.0'} - dev: true + path-key@3.1.1: {} - /path-key@3.1.1: - resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} - engines: {node: '>=8'} - dev: true + path-parse@1.0.7: {} - /path-parse@1.0.7: - resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} - dev: true + path-to-regexp@3.3.0: {} - /path-type@4.0.0: - resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} - engines: {node: '>=8'} - dev: true + path-to-regexp@6.3.0: {} - /pathe@2.0.3: - resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} + pathe@2.0.3: {} - /pathval@2.0.1: - resolution: {integrity: sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==} - engines: {node: '>= 14.16'} + pathval@2.0.1: {} - /pg-cloudflare@1.4.0: - resolution: {integrity: sha512-Vo7z/6rrQYxpNRylp4Tlob2elzbh+N/MOQbxFVWCxS7oEx6jF53GTJFxK2WWpKuBRkmiin4Mt+xofFDjx09R0A==} - requiresBuild: true - dev: false + pg-cloudflare@1.4.1: optional: true - /pg-connection-string@2.14.0: - resolution: {integrity: sha512-XwWDGcLRGCXAR8F/AM5bG7Q+A3Wm2s6QeEjlOKZLlH3UYcguiqCWKyWXVag5TLTIjR7oOJUY8kcADaZgWPyLeg==} - dev: false + pg-connection-string@2.14.1: {} - /pg-cursor@2.22.0(pg@8.23.0): - resolution: {integrity: sha512-knzXLKqarTjOvb3qDSW0JiGsazmxwEKXrqHfWRte7XUsOYccQRafn3BLnQobWwInkzFJSyOej8y8cQRh2z3kGw==} - peerDependencies: - pg: ^8 + pg-cursor@2.22.0(pg@8.23.0): dependencies: pg: 8.23.0 - dev: false - /pg-int8@1.0.1: - resolution: {integrity: sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==} - engines: {node: '>=4.0.0'} - dev: false + pg-int8@1.0.1: {} - /pg-pool@3.14.0(pg@8.23.0): - resolution: {integrity: sha512-gKtPkFdQPU3DksooVLi9LsjZxrsBUZIpa+7aVx+LV5pNh0KzP4Zleud2po+ConrxbuXGBJ6Hfer6hdgpIBpBaw==} - peerDependencies: - pg: '>=8.0' + pg-pool@3.14.0(pg@8.23.0): dependencies: pg: 8.23.0 - dev: false - /pg-protocol@1.16.0: - resolution: {integrity: sha512-sILXutLVjCLjcDuOmvhX5e2Z4cS5qG/6Bu3VkpFwdf/633ElGLpEh9bgmuI5I4sqKqkifQiGyiCcx1HdtrK7tg==} - dev: false + pg-protocol@1.16.1: {} - /pg-types@2.2.0: - resolution: {integrity: sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==} - engines: {node: '>=4'} + pg-types@2.2.0: dependencies: pg-int8: 1.0.1 postgres-array: 2.0.0 postgres-bytea: 1.0.1 postgres-date: 1.0.7 postgres-interval: 1.2.0 - dev: false - /pg@8.23.0: - resolution: {integrity: sha512-Ip2EQCngowJLGOfCwkFhPXU7/ljlhn6Rxlmy4XYfL2Y+vyRM59+8uR2xqRWKdYmbXmxCFOAmKxBuSUCdF34qLg==} - engines: {node: '>= 16.0.0'} - peerDependencies: - pg-native: '>=3.0.1' - peerDependenciesMeta: - pg-native: - optional: true + pg@8.23.0: dependencies: - pg-connection-string: 2.14.0 + pg-connection-string: 2.14.1 pg-pool: 3.14.0(pg@8.23.0) - pg-protocol: 1.16.0 + pg-protocol: 1.16.1 pg-types: 2.2.0 pgpass: 1.0.5 optionalDependencies: - pg-cloudflare: 1.4.0 - dev: false + pg-cloudflare: 1.4.1 - /pgpass@1.0.5: - resolution: {integrity: sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==} + pgpass@1.0.5: dependencies: split2: 4.2.0 - dev: false - - /picocolors@1.0.1: - resolution: {integrity: sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==} - dev: true - /picocolors@1.1.1: - resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} - - /picomatch@2.3.2: - resolution: {integrity: sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==} - engines: {node: '>=8.6'} - dev: true + picocolors@1.1.1: {} - /picomatch@4.0.5: - resolution: {integrity: sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==} - engines: {node: '>=12'} + picomatch@2.3.2: {} - /pify@2.3.0: - resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==} - engines: {node: '>=0.10.0'} - dev: true + picomatch@4.0.7: {} - /pirates@4.0.7: - resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==} - engines: {node: '>= 6'} - dev: true + pirates@4.0.7: {} - /pkg-types@1.3.1: - resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} + pkg-types@1.3.1: dependencies: confbox: 0.1.8 mlly: 1.8.2 pathe: 2.0.3 - dev: true - /postcss-import@15.1.0(postcss@8.4.39): - resolution: {integrity: sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==} - engines: {node: '>=14.0.0'} - peerDependencies: - postcss: ^8.0.0 + playwright-core@1.64.1: {} + + playwright@1.64.1: + dependencies: + playwright-core: 1.64.1 + + postcss-import@15.1.0(postcss@8.4.39): dependencies: postcss: 8.4.39 postcss-value-parser: 4.2.0 - read-cache: 1.0.0 - resolve: 1.22.12 - dev: true + read-cache: 1.0.2 + resolve: 1.22.13 - /postcss-js@4.1.0(postcss@8.4.39): - resolution: {integrity: sha512-oIAOTqgIo7q2EOwbhb8UalYePMvYoIeRY2YKntdpFQXNosSu3vLrniGgmH9OKs/qAkfoj5oB3le/7mINW1LCfw==} - engines: {node: ^12 || ^14 || >= 16} - peerDependencies: - postcss: ^8.4.21 + postcss-js@4.1.0(postcss@8.4.39): dependencies: camelcase-css: 2.0.1 postcss: 8.4.39 - dev: true - /postcss-load-config@4.0.2(postcss@8.4.39): - resolution: {integrity: sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==} - engines: {node: '>= 14'} - peerDependencies: - postcss: '>=8.0.9' - ts-node: '>=9.0.0' - peerDependenciesMeta: - postcss: - optional: true - ts-node: - optional: true + postcss-load-config@4.0.2(postcss@8.4.39): dependencies: - lilconfig: 3.1.3 + lilconfig: 3.1.4 + yaml: 2.9.1 + optionalDependencies: postcss: 8.4.39 - yaml: 2.9.0 - dev: true - /postcss-load-config@6.0.1(jiti@2.4.2): - resolution: {integrity: sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==} - engines: {node: '>= 18'} - peerDependencies: - jiti: '>=1.21.0' - postcss: '>=8.0.9' - tsx: ^4.8.1 - yaml: ^2.4.2 - peerDependenciesMeta: - jiti: - optional: true - postcss: - optional: true - tsx: - optional: true - yaml: - optional: true + postcss-load-config@6.0.1(jiti@2.4.2)(postcss@8.5.32)(yaml@2.9.1): dependencies: + lilconfig: 3.1.4 + optionalDependencies: jiti: 2.4.2 - lilconfig: 3.1.3 - dev: true + postcss: 8.5.32 + yaml: 2.9.1 - /postcss-nested@6.2.0(postcss@8.4.39): - resolution: {integrity: sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==} - engines: {node: '>=12.0'} - peerDependencies: - postcss: ^8.2.14 + postcss-load-config@6.0.1(jiti@2.7.0)(postcss@8.5.32)(yaml@2.9.1): + dependencies: + lilconfig: 3.1.4 + optionalDependencies: + jiti: 2.7.0 + postcss: 8.5.32 + yaml: 2.9.1 + + postcss-nested@6.2.0(postcss@8.4.39): dependencies: postcss: 8.4.39 - postcss-selector-parser: 6.1.4 - dev: true + postcss-selector-parser: 6.1.5 - /postcss-selector-parser@6.1.4: - resolution: {integrity: sha512-bIoJLOmjCO1S9XdY/DcnR5hJxvrDir1PbGChrzXG3vw0/FOliy/fA3dmdhQ441kah4gKv+TwckGzex6wNS5cnQ==} - engines: {node: '>=4'} + postcss-selector-parser@6.1.5: dependencies: cssesc: 3.0.0 util-deprecate: 1.0.2 - dev: true - /postcss-value-parser@4.2.0: - resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} - dev: true + postcss-value-parser@4.2.0: {} - /postcss@8.4.31: - resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==} - engines: {node: ^10 || ^12 || >=14} + postcss@8.4.31: dependencies: - nanoid: 3.3.15 + nanoid: 3.3.20 picocolors: 1.1.1 - source-map-js: 1.2.1 + source-map-js: 1.2.2 - /postcss@8.4.39: - resolution: {integrity: sha512-0vzE+lAiG7hZl1/9I8yzKLx3aR9Xbof3fBHKunvMfOCYAtMhrsnccJY2iTURb9EZd5+pLuiNV9/c/GZJOHsgIw==} - engines: {node: ^10 || ^12 || >=14} + postcss@8.4.39: dependencies: - nanoid: 3.3.15 + nanoid: 3.3.20 picocolors: 1.1.1 - source-map-js: 1.2.1 - dev: true + source-map-js: 1.2.2 - /postcss@8.5.16: - resolution: {integrity: sha512-vuwillviilfKZsg0VGj5R/YwwcHx4SLsIOI/7K6mQkWx+l5cUHTjj5g0AasTBcyXsbfTgrwsUNmVUb5xVwyPwg==} - engines: {node: ^10 || ^12 || >=14} + postcss@8.5.23: dependencies: - nanoid: 3.3.15 + nanoid: 3.3.20 picocolors: 1.1.1 - source-map-js: 1.2.1 - - /postgres-array@2.0.0: - resolution: {integrity: sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==} - engines: {node: '>=4'} - dev: false - - /postgres-array@3.0.4: - resolution: {integrity: sha512-nAUSGfSDGOaOAEGwqsRY27GPOea7CNipJPOA7lPbdEpx5Kg3qzdP0AaWC5MlhTWV9s4hFX39nomVZ+C4tnGOJQ==} - engines: {node: '>=12'} - dev: false - - /postgres-bytea@1.0.1: - resolution: {integrity: sha512-5+5HqXnsZPE65IJZSMkZtURARZelel2oXUEO8rH83VS/hxH5vv1uHquPg5wZs8yMAfdv971IU+kcPUczi7NVBQ==} - engines: {node: '>=0.10.0'} - dev: false + source-map-js: 1.2.2 - /postgres-date@1.0.7: - resolution: {integrity: sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==} - engines: {node: '>=0.10.0'} - dev: false - - /postgres-date@2.1.0: - resolution: {integrity: sha512-K7Juri8gtgXVcDfZttFKVmhglp7epKb1K4pgrkLxehjqkrgPhfG6OO8LHLkfaqkbpjNRnra018XwAr1yQFWGcA==} - engines: {node: '>=12'} - dev: false - - /postgres-interval@1.2.0: - resolution: {integrity: sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==} - engines: {node: '>=0.10.0'} + postcss@8.5.32: dependencies: - xtend: 4.0.2 - dev: false - - /postgres-interval@4.1.0: - resolution: {integrity: sha512-nJLACcOHi2iyRuMJeW6CuIA0Dc0i1YEpRr26XDyHAfxPjYUJOFxwZjmOc5oFFctTTh/OlRAMlnlXEJvr170fJg==} - engines: {node: '>=12'} - dev: false - - /prelude-ls@1.2.1: - resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} - engines: {node: '>= 0.8.0'} - dev: true - - /prettier-plugin-tailwindcss@0.6.5(prettier@3.3.3): - resolution: {integrity: sha512-axfeOArc/RiGHjOIy9HytehlC0ZLeMaqY09mm8YCkMzznKiDkwFzOpBvtuhuv3xG5qB73+Mj7OCe2j/L1ryfuQ==} - engines: {node: '>=14.21.3'} - peerDependencies: - '@ianvs/prettier-plugin-sort-imports': '*' - '@prettier/plugin-pug': '*' - '@shopify/prettier-plugin-liquid': '*' - '@trivago/prettier-plugin-sort-imports': '*' - '@zackad/prettier-plugin-twig-melody': '*' - prettier: ^3.0 - prettier-plugin-astro: '*' - prettier-plugin-css-order: '*' - prettier-plugin-import-sort: '*' - prettier-plugin-jsdoc: '*' - prettier-plugin-marko: '*' - prettier-plugin-organize-attributes: '*' - prettier-plugin-organize-imports: '*' - prettier-plugin-sort-imports: '*' - prettier-plugin-style-order: '*' - prettier-plugin-svelte: '*' - peerDependenciesMeta: - '@ianvs/prettier-plugin-sort-imports': - optional: true - '@prettier/plugin-pug': - optional: true - '@shopify/prettier-plugin-liquid': - optional: true - '@trivago/prettier-plugin-sort-imports': - optional: true - '@zackad/prettier-plugin-twig-melody': - optional: true - prettier-plugin-astro: - optional: true - prettier-plugin-css-order: - optional: true - prettier-plugin-import-sort: - optional: true - prettier-plugin-jsdoc: - optional: true - prettier-plugin-marko: - optional: true - prettier-plugin-organize-attributes: - optional: true - prettier-plugin-organize-imports: - optional: true - prettier-plugin-sort-imports: - optional: true - prettier-plugin-style-order: - optional: true - prettier-plugin-svelte: - optional: true + nanoid: 3.3.20 + picocolors: 1.1.1 + source-map-js: 1.2.2 + + postgres-array@2.0.0: {} + + postgres-array@3.0.4: {} + + postgres-bytea@1.0.1: {} + + postgres-date@1.0.7: {} + + postgres-date@2.1.0: {} + + postgres-interval@1.2.0: dependencies: - prettier: 3.3.3 - dev: false + xtend: 4.0.2 - /prettier@3.3.3: - resolution: {integrity: sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==} - engines: {node: '>=14'} - hasBin: true + postgres-interval@4.1.0: {} - /proxy-agent@6.5.0: - resolution: {integrity: sha512-TmatMXdr2KlRiA2CyDu8GqR8EjahTG3aY3nXjdzFyoZbmB8hrBsTyMezhULIXKnC0jpfjlmiZ3+EaCzoInSu/A==} - engines: {node: '>= 14'} + prelude-ls@1.2.1: {} + + prettier-plugin-tailwindcss@0.6.14(prettier@3.9.10): dependencies: - agent-base: 7.1.4 - debug: 4.4.3 - http-proxy-agent: 7.0.2 - https-proxy-agent: 7.0.6 - lru-cache: 7.18.3 - pac-proxy-agent: 7.2.0 - proxy-from-env: 1.1.0 - socks-proxy-agent: 8.0.5 - transitivePeerDependencies: - - supports-color - dev: true + prettier: 3.9.10 - /proxy-from-env@1.1.0: - resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} - dev: true + prettier@3.9.10: {} - /punycode@2.3.1: - resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} - engines: {node: '>=6'} - dev: true + promise-limit@2.7.0: {} - /qrcode.react@4.2.0(react@18.3.1): - resolution: {integrity: sha512-QpgqWi8rD9DsS9EP3z7BT+5lY5SFhsqGjpgW5DY/i3mK4M9DTBNz3ErMi8BWYEfI3L0d8GIbGmcdFAS1uIRGjA==} - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + property-information@7.2.0: {} + + punycode@2.3.1: {} + + qified@0.10.1: dependencies: + hookified: 2.2.0 + + qrcode.react@4.2.0(@types/react@18.3.3)(react@18.3.1): + dependencies: + '@types/react': 18.3.3 react: 18.3.1 - dev: false - /queue-microtask@1.2.3: - resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} - dev: true + queue-microtask@1.2.3: {} - /rc@1.2.8: - resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} - hasBin: true + range-parser@1.2.0: {} + + rc@1.2.8: dependencies: deep-extend: 0.6.0 ini: 1.3.8 minimist: 1.2.8 strip-json-comments: 2.0.1 - dev: true - /react-dom@18.3.1(react@18.3.1): - resolution: {integrity: sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==} - peerDependencies: - react: ^18.3.1 + react-dom@18.3.1(react@18.3.1): dependencies: loose-envify: 1.4.0 react: 18.3.1 scheduler: 0.23.2 - /react-hook-form@7.52.1(react@18.3.1): - resolution: {integrity: sha512-uNKIhaoICJ5KQALYZ4TOaOLElyM+xipord+Ha3crEFhTntdLvWZqVY49Wqd/0GiVCA/f9NjemLeiNPjG7Hpurg==} - engines: {node: '>=12.22.0'} - peerDependencies: - react: ^16.8.0 || ^17 || ^18 || ^19 + react-dom@18.3.1(react@19.3.1): + dependencies: + loose-envify: 1.4.0 + react: 19.3.1 + scheduler: 0.23.2 + + react-dom@19.3.1(react@19.3.1): + dependencies: + react: 19.3.1 + scheduler: 0.28.0 + + react-hook-form@7.52.1(react@18.3.1): dependencies: react: 18.3.1 - dev: false - /react-remove-scroll-bar@2.3.8(@types/react@18.3.3)(react@18.3.1): - resolution: {integrity: sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==} - engines: {node: '>=10'} - peerDependencies: - '@types/react': '*' - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - peerDependenciesMeta: - '@types/react': - optional: true + react-remove-scroll-bar@2.3.8(@types/react@18.3.3)(react@18.3.1): dependencies: - '@types/react': 18.3.3 react: 18.3.1 react-style-singleton: 2.2.3(@types/react@18.3.3)(react@18.3.1) tslib: 2.8.1 - dev: false + optionalDependencies: + '@types/react': 18.3.3 - /react-remove-scroll@2.5.5(@types/react@18.3.3)(react@18.3.1): - resolution: {integrity: sha512-ImKhrzJJsyXJfBZ4bzu8Bwpka14c/fQt0k+cyFp/PBhTfyDnU5hjOtM4AG/0AMyy8oKzOTR0lDgJIM7pYXI0kw==} - engines: {node: '>=10'} - peerDependencies: - '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0 - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - peerDependenciesMeta: - '@types/react': - optional: true + react-remove-scroll-bar@2.3.8(@types/react@19.3.0)(react@19.3.1): + dependencies: + react: 19.3.1 + react-style-singleton: 2.2.3(@types/react@19.3.0)(react@19.3.1) + tslib: 2.8.1 + optionalDependencies: + '@types/react': 19.3.0 + + react-remove-scroll@2.5.5(@types/react@18.3.3)(react@18.3.1): dependencies: - '@types/react': 18.3.3 react: 18.3.1 react-remove-scroll-bar: 2.3.8(@types/react@18.3.3)(react@18.3.1) react-style-singleton: 2.2.3(@types/react@18.3.3)(react@18.3.1) tslib: 2.8.1 use-callback-ref: 1.3.3(@types/react@18.3.3)(react@18.3.1) use-sidecar: 1.1.3(@types/react@18.3.3)(react@18.3.1) - dev: false + optionalDependencies: + '@types/react': 18.3.3 - /react-style-singleton@2.2.3(@types/react@18.3.3)(react@18.3.1): - resolution: {integrity: sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==} - engines: {node: '>=10'} - peerDependencies: - '@types/react': '*' - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true + react-remove-scroll@2.7.2(@types/react@19.3.0)(react@19.3.1): + dependencies: + react: 19.3.1 + react-remove-scroll-bar: 2.3.8(@types/react@19.3.0)(react@19.3.1) + react-style-singleton: 2.2.3(@types/react@19.3.0)(react@19.3.1) + tslib: 2.8.1 + use-callback-ref: 1.3.3(@types/react@19.3.0)(react@19.3.1) + use-sidecar: 1.1.3(@types/react@19.3.0)(react@19.3.1) + optionalDependencies: + '@types/react': 19.3.0 + + react-server-dom-webpack@19.3.1(react-dom@19.3.1(react@19.3.1))(react@19.3.1)(webpack@5.112.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.4.39)(sharp@0.35.5(@types/node@22.18.6))): + dependencies: + acorn-loose: 8.5.2 + neo-async: 2.6.2 + react: 19.3.1 + react-dom: 19.3.1(react@19.3.1) + webpack: 5.112.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.4.39)(sharp@0.35.5(@types/node@22.18.6)) + webpack-sources: 3.6.0 + + react-style-singleton@2.2.3(@types/react@18.3.3)(react@18.3.1): dependencies: - '@types/react': 18.3.3 get-nonce: 1.0.1 react: 18.3.1 tslib: 2.8.1 - dev: false + optionalDependencies: + '@types/react': 18.3.3 - /react@18.3.1: - resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==} - engines: {node: '>=0.10.0'} + react-style-singleton@2.2.3(@types/react@19.3.0)(react@19.3.1): + dependencies: + get-nonce: 1.0.1 + react: 19.3.1 + tslib: 2.8.1 + optionalDependencies: + '@types/react': 19.3.0 + + react@18.3.1: dependencies: loose-envify: 1.4.0 - /read-cache@1.0.0: - resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==} + react@19.3.1: {} + + read-cache@1.0.2: {} + + readdirp@3.6.0: dependencies: - pify: 2.3.0 - dev: true + picomatch: 2.3.2 - /readable-stream@3.6.2: - resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} - engines: {node: '>= 6'} + readdirp@4.1.2: {} + + readdirp@5.1.1: {} + + recma-build-jsx@1.0.0: dependencies: - inherits: 2.0.4 - string_decoder: 1.3.0 - util-deprecate: 1.0.2 - dev: true + '@types/estree': 1.0.9 + estree-util-build-jsx: 3.0.1 + vfile: 6.0.3 - /readdirp@3.6.0: - resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} - engines: {node: '>=8.10.0'} + recma-jsx@1.0.1(acorn@8.19.0): dependencies: - picomatch: 2.3.2 - dev: true + acorn: 8.19.0 + acorn-jsx: 5.3.2(acorn@8.19.0) + estree-util-to-js: 2.0.0 + recma-parse: 1.0.0 + recma-stringify: 1.0.0 + unified: 11.0.5 - /readdirp@4.1.2: - resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} - engines: {node: '>= 14.18.0'} - dev: true + recma-parse@1.0.0: + dependencies: + '@types/estree': 1.0.9 + esast-util-from-js: 2.0.1 + unified: 11.0.5 + vfile: 6.0.3 - /registry-auth-token@3.3.2: - resolution: {integrity: sha512-JL39c60XlzCVgNrO+qq68FoNb56w/m7JYvGR2jT5iR1xBrUA3Mfx5Twk5rqTThPmQKMWydGmq8oFtDlxfrmxnQ==} + recma-stringify@1.0.0: + dependencies: + '@types/estree': 1.0.9 + estree-util-to-js: 2.0.0 + unified: 11.0.5 + vfile: 6.0.3 + + regex-recursion@6.0.2: + dependencies: + regex-utilities: 2.3.0 + + regex-utilities@2.3.0: {} + + regex@6.1.0: + dependencies: + regex-utilities: 2.3.0 + + registry-auth-token@3.3.2: dependencies: rc: 1.2.8 safe-buffer: 5.2.1 - dev: true - /registry-url@3.1.0: - resolution: {integrity: sha512-ZbgR5aZEdf4UKZVBPYIgaglBmSF2Hi94s2PcIHhRGFjKYu+chjJdYfHn4rt3hB6eCKLJ8giVIIfgMa1ehDfZKA==} - engines: {node: '>=0.10.0'} + registry-url@3.1.0: dependencies: rc: 1.2.8 - dev: true - /resolve-from@4.0.0: - resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} - engines: {node: '>=4'} - dev: true + rehype-recma@1.0.0(supports-color@10.2.2): + dependencies: + '@types/estree': 1.0.9 + '@types/hast': 3.0.5 + hast-util-to-estree: 3.1.3(supports-color@10.2.2) + transitivePeerDependencies: + - supports-color - /resolve-from@5.0.0: - resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} - engines: {node: '>=8'} - dev: true + remark-gfm@4.0.1(supports-color@10.2.2): + dependencies: + '@types/mdast': 4.0.4 + mdast-util-gfm: 3.1.0(supports-color@10.2.2) + micromark-extension-gfm: 3.0.0 + remark-parse: 11.0.0(supports-color@10.2.2) + remark-stringify: 11.0.0 + unified: 11.0.5 + transitivePeerDependencies: + - supports-color - /resolve@1.22.12: - resolution: {integrity: sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==} - engines: {node: '>= 0.4'} - hasBin: true + remark-mdx@3.1.1(supports-color@10.2.2): dependencies: - es-errors: 1.3.0 - is-core-module: 2.16.2 - path-parse: 1.0.7 - supports-preserve-symlinks-flag: 1.0.0 - dev: true + mdast-util-mdx: 3.0.0(supports-color@10.2.2) + micromark-extension-mdxjs: 3.0.0 + transitivePeerDependencies: + - supports-color - /restore-cursor@3.1.0: - resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==} - engines: {node: '>=8'} + remark-parse@11.0.0(supports-color@10.2.2): dependencies: - onetime: 5.1.2 - signal-exit: 3.0.7 - dev: true + '@types/mdast': 4.0.4 + mdast-util-from-markdown: 2.1.0(supports-color@10.2.2) + micromark-util-types: 2.0.3 + unified: 11.0.5 + transitivePeerDependencies: + - supports-color - /reusify@1.1.0: - resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} - engines: {iojs: '>=1.0.0', node: '>=0.10.0'} - dev: true + remark-rehype@11.1.2: + dependencies: + '@types/hast': 3.0.5 + '@types/mdast': 4.0.4 + mdast-util-to-hast: 13.2.1 + unified: 11.0.5 + vfile: 6.0.3 - /rimraf@3.0.2: - resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} - deprecated: Rimraf versions prior to v4 are no longer supported - hasBin: true + remark-stringify@11.0.0: dependencies: - glob: 7.2.3 - dev: true + '@types/mdast': 4.0.4 + mdast-util-to-markdown: 2.2.0 + unified: 11.0.5 - /rollup@4.62.2: - resolution: {integrity: sha512-RFnrW4lhXA3s3eqHDZvN654g8OTjzRfqpIRJYczCGB6HzphckVAi/Qh4tbPUbRuDi7s1Llv8g/NspLkttY3gTA==} - engines: {node: '>=18.0.0', npm: '>=8.0.0'} - hasBin: true + remark@15.0.1(supports-color@10.2.2): + dependencies: + '@types/mdast': 4.0.4 + remark-parse: 11.0.0(supports-color@10.2.2) + remark-stringify: 11.0.0 + unified: 11.0.5 + transitivePeerDependencies: + - supports-color + + require-directory@2.1.1: {} + + require-from-string@2.0.2: {} + + reselect@5.3.0: {} + + resolve-from@5.0.0: {} + + resolve@1.22.13: + dependencies: + es-errors: 1.3.0 + is-core-module: 2.17.0 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + + reusify@1.1.0: {} + + rolldown@1.2.15: + dependencies: + '@oxc-project/types': 0.155.0 + '@rolldown/pluginutils': 1.0.1 + optionalDependencies: + '@rolldown/binding-android-arm-eabi': 1.2.15 + '@rolldown/binding-android-arm64': 1.2.15 + '@rolldown/binding-darwin-arm64': 1.2.15 + '@rolldown/binding-darwin-x64': 1.2.15 + '@rolldown/binding-freebsd-x64': 1.2.15 + '@rolldown/binding-linux-arm-gnueabihf': 1.2.15 + '@rolldown/binding-linux-arm64-gnu': 1.2.15 + '@rolldown/binding-linux-arm64-musl': 1.2.15 + '@rolldown/binding-linux-ppc64-gnu': 1.2.15 + '@rolldown/binding-linux-s390x-gnu': 1.2.15 + '@rolldown/binding-linux-x64-gnu': 1.2.15 + '@rolldown/binding-linux-x64-musl': 1.2.15 + '@rolldown/binding-openharmony-arm64': 1.2.15 + '@rolldown/binding-win32-arm64-msvc': 1.2.15 + '@rolldown/binding-win32-x64-msvc': 1.2.15 + + rollup@4.65.1: dependencies: '@types/estree': 1.0.9 optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.62.2 - '@rollup/rollup-android-arm64': 4.62.2 - '@rollup/rollup-darwin-arm64': 4.62.2 - '@rollup/rollup-darwin-x64': 4.62.2 - '@rollup/rollup-freebsd-arm64': 4.62.2 - '@rollup/rollup-freebsd-x64': 4.62.2 - '@rollup/rollup-linux-arm-gnueabihf': 4.62.2 - '@rollup/rollup-linux-arm-musleabihf': 4.62.2 - '@rollup/rollup-linux-arm64-gnu': 4.62.2 - '@rollup/rollup-linux-arm64-musl': 4.62.2 - '@rollup/rollup-linux-loong64-gnu': 4.62.2 - '@rollup/rollup-linux-loong64-musl': 4.62.2 - '@rollup/rollup-linux-ppc64-gnu': 4.62.2 - '@rollup/rollup-linux-ppc64-musl': 4.62.2 - '@rollup/rollup-linux-riscv64-gnu': 4.62.2 - '@rollup/rollup-linux-riscv64-musl': 4.62.2 - '@rollup/rollup-linux-s390x-gnu': 4.62.2 - '@rollup/rollup-linux-x64-gnu': 4.62.2 - '@rollup/rollup-linux-x64-musl': 4.62.2 - '@rollup/rollup-openbsd-x64': 4.62.2 - '@rollup/rollup-openharmony-arm64': 4.62.2 - '@rollup/rollup-win32-arm64-msvc': 4.62.2 - '@rollup/rollup-win32-ia32-msvc': 4.62.2 - '@rollup/rollup-win32-x64-gnu': 4.62.2 - '@rollup/rollup-win32-x64-msvc': 4.62.2 + '@napi-rs/lzma-linux-x64-gnu': 1.5.1 + '@rollup/rollup-android-arm-eabi': 4.65.1 + '@rollup/rollup-android-arm64': 4.65.1 + '@rollup/rollup-darwin-arm64': 4.65.1 + '@rollup/rollup-darwin-x64': 4.65.1 + '@rollup/rollup-freebsd-arm64': 4.65.1 + '@rollup/rollup-freebsd-x64': 4.65.1 + '@rollup/rollup-linux-arm-gnueabihf': 4.65.1 + '@rollup/rollup-linux-arm-musleabihf': 4.65.1 + '@rollup/rollup-linux-arm64-gnu': 4.65.1 + '@rollup/rollup-linux-arm64-musl': 4.65.1 + '@rollup/rollup-linux-loong64-gnu': 4.65.1 + '@rollup/rollup-linux-loong64-musl': 4.65.1 + '@rollup/rollup-linux-ppc64-gnu': 4.65.1 + '@rollup/rollup-linux-ppc64-musl': 4.65.1 + '@rollup/rollup-linux-riscv64-gnu': 4.65.1 + '@rollup/rollup-linux-riscv64-musl': 4.65.1 + '@rollup/rollup-linux-s390x-gnu': 4.65.1 + '@rollup/rollup-linux-x64-gnu': 4.65.1 + '@rollup/rollup-linux-x64-musl': 4.65.1 + '@rollup/rollup-openbsd-x64': 4.65.1 + '@rollup/rollup-openharmony-arm64': 4.65.1 + '@rollup/rollup-win32-arm64-msvc': 4.65.1 + '@rollup/rollup-win32-ia32-msvc': 4.65.1 + '@rollup/rollup-win32-x64-gnu': 4.65.1 + '@rollup/rollup-win32-x64-msvc': 4.65.1 fsevents: 2.3.3 - /rou3@0.9.2: - resolution: {integrity: sha512-3SOzvaAg8rkHrXtRjpCvCvbyO5to9oOO27Z/XqHEYXfMRVSw/qMIVdmaOk9W2lcRLtR6dlqTjo9hDeJk70QBYQ==} - dev: false - - /run-async@2.4.1: - resolution: {integrity: sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==} - engines: {node: '>=0.12.0'} - dev: true + rou3@0.9.2: {} - /run-parallel@1.2.0: - resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + run-parallel@1.2.0: dependencies: queue-microtask: 1.2.3 - dev: true - /rxjs@6.6.7: - resolution: {integrity: sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==} - engines: {npm: '>=2.0.0'} + safe-buffer@5.2.1: {} + + safer-buffer@2.1.2: {} + + satori@0.33.5: dependencies: - tslib: 1.14.1 - dev: true + '@shuding/opentype.js': 1.4.0-beta.0 + css-background-parser: 0.1.0 + css-box-shadow: 1.0.0-3 + css-gradient-parser: 0.0.17 + css-to-react-native: 3.2.0 + emoji-regex-xs: 2.0.1 + escape-html: 1.0.3 + fflate: 0.7.3 + harfbuzzjs: 0.10.0 + linebreak: 1.1.0 + parse-css-color: 0.2.1 + postcss-value-parser: 4.2.0 + yoga-layout: 3.2.1 - /rxjs@7.8.2: - resolution: {integrity: sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==} + scheduler@0.23.2: dependencies: - tslib: 2.8.1 - dev: true + loose-envify: 1.4.0 - /safe-buffer@5.2.1: - resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} - dev: true + scheduler@0.28.0: {} - /safer-buffer@2.1.2: - resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + schema-utils@4.8.1(webpack@5.112.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.4.39)(sharp@0.35.5(@types/node@22.18.6))): + dependencies: + '@types/json-schema': 7.0.15 + ajv: 8.20.0 + ajv-formats: 3.0.1 + ajv-keywords: 5.1.0(ajv@8.20.0) + optionalDependencies: + webpack: 5.112.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.4.39)(sharp@0.35.5(@types/node@22.18.6)) - /scheduler@0.23.2: - resolution: {integrity: sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==} + scroll-into-view-if-needed@3.1.0: dependencies: - loose-envify: 1.4.0 + compute-scroll-into-view: 3.1.1 - /sdp@3.2.2: - resolution: {integrity: sha512-xZocWwfyp4hkbN4hLWxMjmv2Q8aNa9MhmOZ7L9aCZPT+dZsgRr6wZRrSYE3HTdyk/2pZKPSgqI7ns7Een1xMSA==} - dev: false + sdp@3.2.2: {} - /semver@7.8.5: - resolution: {integrity: sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==} - engines: {node: '>=10'} - hasBin: true - dev: true + semver@7.8.5: {} - /sentence-case@2.1.1: - resolution: {integrity: sha512-ENl7cYHaK/Ktwk5OTD+aDbQ3uC8IByu/6Bkg+HDv8Mm+XnBnppVNalcfJTNsp1ibstKh030/JKQQWglDvtKwEQ==} + serve-handler@6.1.7: dependencies: - no-case: 2.3.2 - upper-case-first: 1.1.2 - dev: true + bytes: 3.0.0 + content-disposition: 0.5.2 + mime-types: 2.1.18 + minimatch: 3.1.5 + path-is-inside: 1.0.2 + path-to-regexp: 3.3.0 + range-parser: 1.2.0 + + serve@14.2.6(supports-color@10.2.2): + dependencies: + '@zeit/schemas': 2.36.0 + ajv: 8.18.0 + arg: 5.0.2 + boxen: 7.0.0 + chalk: 5.0.1 + chalk-template: 0.4.0 + clipboardy: 3.0.0 + compression: 1.8.1(supports-color@10.2.2) + is-port-reachable: 4.0.0 + serve-handler: 6.1.7 + update-check: 1.5.4 + transitivePeerDependencies: + - supports-color - /set-cookie-parser@3.1.2: - resolution: {integrity: sha512-5/r/lTwbJ3zQ+qwdUFZYeRNqda7P5HD8zQKqlSjdGt1/S0cjLAphHusj4Y58ahDtWn/g32xrIS58/ikOvwl0Lw==} - dev: false + set-cookie-parser@3.2.1: {} - /shebang-command@2.0.0: - resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} - engines: {node: '>=8'} + sharp@0.35.5(@types/node@20.14.11): + dependencies: + '@img/colour': 1.1.0 + detect-libc: 2.1.2 + semver: 7.8.5 + optionalDependencies: + '@img/sharp-darwin-arm64': 0.35.5 + '@img/sharp-darwin-x64': 0.35.5 + '@img/sharp-freebsd-wasm32': 0.35.5 + '@img/sharp-libvips-darwin-arm64': 1.3.4 + '@img/sharp-libvips-darwin-x64': 1.3.4 + '@img/sharp-libvips-linux-arm': 1.3.4 + '@img/sharp-libvips-linux-arm64': 1.3.4 + '@img/sharp-libvips-linux-ppc64': 1.3.4 + '@img/sharp-libvips-linux-riscv64': 1.3.4 + '@img/sharp-libvips-linux-s390x': 1.3.4 + '@img/sharp-libvips-linux-x64': 1.3.4 + '@img/sharp-libvips-linuxmusl-arm64': 1.3.4 + '@img/sharp-libvips-linuxmusl-x64': 1.3.4 + '@img/sharp-linux-arm': 0.35.5 + '@img/sharp-linux-arm64': 0.35.5 + '@img/sharp-linux-ppc64': 0.35.5 + '@img/sharp-linux-riscv64': 0.35.5 + '@img/sharp-linux-s390x': 0.35.5 + '@img/sharp-linux-x64': 0.35.5 + '@img/sharp-linuxmusl-arm64': 0.35.5 + '@img/sharp-linuxmusl-x64': 0.35.5 + '@img/sharp-webcontainers-wasm32': 0.35.5 + '@img/sharp-win32-arm64': 0.35.5 + '@img/sharp-win32-ia32': 0.35.5 + '@img/sharp-win32-x64': 0.35.5 + '@types/node': 20.14.11 + optional: true + + sharp@0.35.5(@types/node@22.18.6): + dependencies: + '@img/colour': 1.1.0 + detect-libc: 2.1.2 + semver: 7.8.5 + optionalDependencies: + '@img/sharp-darwin-arm64': 0.35.5 + '@img/sharp-darwin-x64': 0.35.5 + '@img/sharp-freebsd-wasm32': 0.35.5 + '@img/sharp-libvips-darwin-arm64': 1.3.4 + '@img/sharp-libvips-darwin-x64': 1.3.4 + '@img/sharp-libvips-linux-arm': 1.3.4 + '@img/sharp-libvips-linux-arm64': 1.3.4 + '@img/sharp-libvips-linux-ppc64': 1.3.4 + '@img/sharp-libvips-linux-riscv64': 1.3.4 + '@img/sharp-libvips-linux-s390x': 1.3.4 + '@img/sharp-libvips-linux-x64': 1.3.4 + '@img/sharp-libvips-linuxmusl-arm64': 1.3.4 + '@img/sharp-libvips-linuxmusl-x64': 1.3.4 + '@img/sharp-linux-arm': 0.35.5 + '@img/sharp-linux-arm64': 0.35.5 + '@img/sharp-linux-ppc64': 0.35.5 + '@img/sharp-linux-riscv64': 0.35.5 + '@img/sharp-linux-s390x': 0.35.5 + '@img/sharp-linux-x64': 0.35.5 + '@img/sharp-linuxmusl-arm64': 0.35.5 + '@img/sharp-linuxmusl-x64': 0.35.5 + '@img/sharp-webcontainers-wasm32': 0.35.5 + '@img/sharp-win32-arm64': 0.35.5 + '@img/sharp-win32-ia32': 0.35.5 + '@img/sharp-win32-x64': 0.35.5 + '@types/node': 22.18.6 + + sharp@0.35.5(@types/node@26.6.5): + dependencies: + '@img/colour': 1.1.0 + detect-libc: 2.1.2 + semver: 7.8.5 + optionalDependencies: + '@img/sharp-darwin-arm64': 0.35.5 + '@img/sharp-darwin-x64': 0.35.5 + '@img/sharp-freebsd-wasm32': 0.35.5 + '@img/sharp-libvips-darwin-arm64': 1.3.4 + '@img/sharp-libvips-darwin-x64': 1.3.4 + '@img/sharp-libvips-linux-arm': 1.3.4 + '@img/sharp-libvips-linux-arm64': 1.3.4 + '@img/sharp-libvips-linux-ppc64': 1.3.4 + '@img/sharp-libvips-linux-riscv64': 1.3.4 + '@img/sharp-libvips-linux-s390x': 1.3.4 + '@img/sharp-libvips-linux-x64': 1.3.4 + '@img/sharp-libvips-linuxmusl-arm64': 1.3.4 + '@img/sharp-libvips-linuxmusl-x64': 1.3.4 + '@img/sharp-linux-arm': 0.35.5 + '@img/sharp-linux-arm64': 0.35.5 + '@img/sharp-linux-ppc64': 0.35.5 + '@img/sharp-linux-riscv64': 0.35.5 + '@img/sharp-linux-s390x': 0.35.5 + '@img/sharp-linux-x64': 0.35.5 + '@img/sharp-linuxmusl-arm64': 0.35.5 + '@img/sharp-linuxmusl-x64': 0.35.5 + '@img/sharp-webcontainers-wasm32': 0.35.5 + '@img/sharp-win32-arm64': 0.35.5 + '@img/sharp-win32-ia32': 0.35.5 + '@img/sharp-win32-x64': 0.35.5 + '@types/node': 26.6.5 + + shebang-command@2.0.0: dependencies: shebang-regex: 3.0.0 - dev: true - /shebang-regex@3.0.0: - resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} - engines: {node: '>=8'} - dev: true + shebang-regex@3.0.0: {} - /siginfo@2.0.0: - resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} + shiki@4.5.0: + dependencies: + '@shikijs/core': 4.5.0 + '@shikijs/engine-javascript': 4.5.0 + '@shikijs/engine-oniguruma': 4.5.0 + '@shikijs/langs': 4.5.0 + '@shikijs/themes': 4.5.0 + '@shikijs/types': 4.5.0 + '@shikijs/vscode-textmate': 10.1.0 + '@types/hast': 3.0.5 - /signal-exit@3.0.7: - resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} - dev: true + siginfo@2.0.0: {} - /slash@3.0.0: - resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} - engines: {node: '>=8'} - dev: true + signal-exit@3.0.7: {} - /smart-buffer@4.2.0: - resolution: {integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==} - engines: {node: '>= 6.0.0', npm: '>= 3.0.0'} - dev: true + signal-exit@4.1.0: {} - /snake-case@2.1.0: - resolution: {integrity: sha512-FMR5YoPFwOLuh4rRz92dywJjyKYZNLpMn1R5ujVpIYkbA9p01fq8RMg0FkO4M+Yobt4MjHeLTJVm5xFFBHSV2Q==} + sonner@1.7.4(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: - no-case: 2.3.2 - dev: true + '@types/react': 18.3.3 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) - /socks-proxy-agent@8.0.5: - resolution: {integrity: sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==} - engines: {node: '>= 14'} + sonner@1.7.4(@types/react@18.3.3)(react-dom@19.3.1(react@19.3.1))(react@19.3.1): dependencies: - agent-base: 7.1.4 - debug: 4.4.3 - socks: 2.8.9 - transitivePeerDependencies: - - supports-color - dev: true + '@types/react': 18.3.3 + react: 19.3.1 + react-dom: 19.3.1(react@19.3.1) - /socks@2.8.9: - resolution: {integrity: sha512-LJhUYUvItdQ0LkJTmPeaEObWXAqFyfmP85x0tch/ez9cahmhlBBLbIqDFnvBnUJGagb0JbIQrkBs1wJ+yRYpEw==} - engines: {node: '>= 10.0.0', npm: '>= 3.0.0'} + sonner@1.7.4(@types/react@19.3.0)(react-dom@19.3.1(react@19.3.1))(react@19.3.1): dependencies: - ip-address: 10.2.0 - smart-buffer: 4.2.0 - dev: true + '@types/react': 19.3.0 + react: 19.3.1 + react-dom: 19.3.1(react@19.3.1) - /sonner@1.5.0(react-dom@18.3.1)(react@18.3.1): - resolution: {integrity: sha512-FBjhG/gnnbN6FY0jaNnqZOMmB73R+5IiyYAw8yBj7L54ER7HB3fOSE5OFiQiE2iXWxeXKvg6fIP4LtVppHEdJA==} - peerDependencies: - react: ^18.0.0 - react-dom: ^18.0.0 + source-map-js@1.2.2: {} + + source-map-support@0.5.21: dependencies: - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - dev: false + buffer-from: 1.1.2 + source-map: 0.6.1 - /source-map-js@1.2.1: - resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} - engines: {node: '>=0.10.0'} + source-map@0.6.1: {} - /source-map@0.6.1: - resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} - engines: {node: '>=0.10.0'} - dev: true + source-map@0.7.6: {} - /source-map@0.7.6: - resolution: {integrity: sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==} - engines: {node: '>= 12'} - dev: true + space-separated-tokens@2.0.2: {} - /split2@4.2.0: - resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} - engines: {node: '>= 10.x'} - dev: false + split2@4.2.0: {} - /sql-escaper@1.5.2: - resolution: {integrity: sha512-6CKD38c31SENivxOADeMNLdukOnUxUcflKtzVWzace7Riv1v7cAEym5Cx9Q7gYZ3ezIJI7ZpqecQq8cqNeSSFg==} - engines: {bun: '>=1.0.0', deno: '>=2.0.0', node: '>=12.0.0'} - dev: false + sql-escaper@1.5.2: {} - /sqlstring@2.3.3: - resolution: {integrity: sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg==} - engines: {node: '>= 0.6'} - dev: false + sqlstring@2.3.3: {} - /stackback@0.0.2: - resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} + srvx@1.0.7: {} - /std-env@3.10.0: - resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==} + stackback@0.0.2: {} - /streamsearch@1.1.0: - resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==} - engines: {node: '>=10.0.0'} + std-env@3.10.0: {} - /string-width@4.2.3: - resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} - engines: {node: '>=8'} + streamsearch@1.1.0: {} + + string-width@4.2.3: dependencies: emoji-regex: 8.0.0 is-fullwidth-code-point: 3.0.0 strip-ansi: 6.0.1 - dev: true - /string_decoder@1.3.0: - resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + string-width@5.1.2: dependencies: - safe-buffer: 5.2.1 - dev: true + eastasianwidth: 0.2.0 + emoji-regex: 9.2.2 + strip-ansi: 7.2.0 - /strip-ansi@6.0.1: - resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} - engines: {node: '>=8'} + string.prototype.codepointat@0.2.1: {} + + stringify-entities@4.0.4: + dependencies: + character-entities-html4: 2.1.0 + character-entities-legacy: 3.0.0 + + strip-ansi@6.0.1: dependencies: ansi-regex: 5.0.1 - dev: true - /strip-final-newline@2.0.0: - resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} - engines: {node: '>=6'} - dev: true + strip-ansi@7.2.0: + dependencies: + ansi-regex: 6.4.0 - /strip-json-comments@2.0.1: - resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==} - engines: {node: '>=0.10.0'} - dev: true + strip-final-newline@2.0.0: {} - /strip-json-comments@3.1.1: - resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} - engines: {node: '>=8'} - dev: true + strip-json-comments@2.0.1: {} + + strip-literal@3.1.0: + dependencies: + js-tokens: 9.0.1 + + strip-literal@4.0.0: + dependencies: + js-tokens: 10.0.0 - /strip-literal@3.1.0: - resolution: {integrity: sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==} + style-to-js@1.1.21: dependencies: - js-tokens: 9.0.1 + style-to-object: 1.0.14 - /strnum@1.1.2: - resolution: {integrity: sha512-vrN+B7DBIoTTZjnPNewwhx6cBA/H+IS7rfW68n7XxC1y7uoiGQBxaKzqucGUgavX15dJgiGztLJ8vxuEzwqBdA==} - dev: false + style-to-object@1.0.14: + dependencies: + inline-style-parser: 0.2.7 - /styled-jsx@5.1.1(react@18.3.1): - resolution: {integrity: sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==} - engines: {node: '>= 12.0.0'} - peerDependencies: - '@babel/core': '*' - babel-plugin-macros: '*' - react: '>= 16.8.0 || 17.x.x || ^18.0.0-0' - peerDependenciesMeta: - '@babel/core': - optional: true - babel-plugin-macros: - optional: true + styled-jsx@5.1.1(react@18.3.1): dependencies: client-only: 0.0.1 react: 18.3.1 - /sucrase@3.35.1: - resolution: {integrity: sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==} - engines: {node: '>=16 || 14 >=14.17'} - hasBin: true + styled-jsx@5.1.1(react@19.3.1): + dependencies: + client-only: 0.0.1 + react: 19.3.1 + + styled-jsx@5.1.6(react@19.3.1): + dependencies: + client-only: 0.0.1 + react: 19.3.1 + + sucrase@3.35.1: dependencies: '@jridgewell/gen-mapping': 0.3.13 commander: 4.1.1 @@ -6119,52 +11733,30 @@ packages: pirates: 4.0.7 tinyglobby: 0.2.17 ts-interface-checker: 0.1.13 - dev: true - /supports-color@5.5.0: - resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} - engines: {node: '>=4'} + supports-color@10.2.2: {} + + supports-color@7.2.0: dependencies: - has-flag: 3.0.0 - dev: true + has-flag: 4.0.0 - /supports-color@7.2.0: - resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} - engines: {node: '>=8'} + supports-color@8.1.1: dependencies: has-flag: 4.0.0 - dev: true - /supports-preserve-symlinks-flag@1.0.0: - resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} - engines: {node: '>= 0.4'} - dev: true + supports-preserve-symlinks-flag@1.0.0: {} - /swap-case@1.1.2: - resolution: {integrity: sha512-BAmWG6/bx8syfc6qXPprof3Mn5vQgf5dwdUNJhsNqU9WdPt5P+ES/wQ5bxfijy8zwZgZZHslC3iAsxsuQMCzJQ==} - dependencies: - lower-case: 1.1.4 - upper-case: 1.1.3 - dev: true + tagged-tag@1.0.0: {} - /tailwind-merge@2.4.0: - resolution: {integrity: sha512-49AwoOQNKdqKPd9CViyH5wJoSKsCDjUlzL8DxuGp3P1FsGY36NJDAa18jLZcaHAUUuTj+JB8IAo8zWgBNvBF7A==} - dev: false + tailwind-merge@2.6.1: {} - /tailwindcss-animate@1.0.7(tailwindcss@3.4.6): - resolution: {integrity: sha512-bl6mpH3T7I3UFxuvDEXLxy/VuFxBk5bbzplh7tXI68mwMokNYd1t9qPBHlnyTwfa4JGC4zP516I1hYYtQ/vspA==} - peerDependencies: - tailwindcss: '>=3.0.0 || insiders' + tailwindcss-animate@1.0.7(tailwindcss@3.4.6): dependencies: tailwindcss: 3.4.6 - dev: true - /tailwindcss@3.4.6: - resolution: {integrity: sha512-1uRHzPB+Vzu57ocybfZ4jh5Q3SdlH7XW23J5sQoM9LhE9eIOlzxer/3XPSsycvih3rboRsvt0QCmzSrqyOYUIA==} - engines: {node: '>=14.0.0'} - hasBin: true + tailwindcss@3.4.6: dependencies: - '@alloc/quick-lru': 5.2.0 + '@alloc/quick-lru': 5.3.0 arg: 5.0.2 chokidar: 3.6.0 didyoumean: 1.2.2 @@ -6183,376 +11775,504 @@ packages: postcss-js: 4.1.0(postcss@8.4.39) postcss-load-config: 4.0.2(postcss@8.4.39) postcss-nested: 6.2.0(postcss@8.4.39) - postcss-selector-parser: 6.1.4 - resolve: 1.22.12 + postcss-selector-parser: 6.1.5 + resolve: 1.22.13 sucrase: 3.35.1 transitivePeerDependencies: - ts-node - dev: true - /text-table@0.2.0: - resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} - dev: true + tailwindcss@4.3.3: {} - /thenify-all@1.6.0: - resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} - engines: {node: '>=0.8'} + tapable@2.3.3: {} + + terser@5.51.2: + dependencies: + '@jridgewell/source-map': 0.3.11 + acorn: 8.19.0 + commander: 2.20.3 + source-map-support: 0.5.21 + + thenify-all@1.6.0: dependencies: thenify: 3.3.1 - dev: true - /thenify@3.3.1: - resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} + thenify@3.3.1: dependencies: any-promise: 1.3.0 - dev: true - - /through@2.3.8: - resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} - dev: true - /tinybench@2.9.0: - resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} + tiny-inflate@1.0.3: {} - /tinycolor2@1.6.0: - resolution: {integrity: sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==} - dev: true + tinybench@2.9.0: {} - /tinyexec@0.3.2: - resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} + tinyexec@0.3.2: {} - /tinyglobby@0.2.17: - resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==} - engines: {node: '>=12.0.0'} - dependencies: - fdir: 6.5.0(picomatch@4.0.5) - picomatch: 4.0.5 + tinyexec@1.3.1: {} - /tinygradient@1.1.5: - resolution: {integrity: sha512-8nIfc2vgQ4TeLnk2lFj4tRLvvJwEfQuabdsmvDdQPT0xlk9TaNtpGd6nNRxXoK6vQhN6RSzj+Cnp5tTQmpxmbw==} + tinyglobby@0.2.17: dependencies: - '@types/tinycolor2': 1.4.6 - tinycolor2: 1.6.0 - dev: true + fdir: 6.5.0(picomatch@4.0.7) + picomatch: 4.0.7 - /tinypool@1.1.1: - resolution: {integrity: sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==} - engines: {node: ^18.0.0 || >=20.0.0} + tinypool@1.1.1: {} - /tinyrainbow@2.0.0: - resolution: {integrity: sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==} - engines: {node: '>=14.0.0'} + tinyrainbow@2.0.0: {} - /tinyspy@4.0.4: - resolution: {integrity: sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q==} - engines: {node: '>=14.0.0'} + tinyspy@4.0.6: {} - /title-case@2.1.1: - resolution: {integrity: sha512-EkJoZ2O3zdCz3zJsYCsxyq2OC5hrxR9mfdd5I+w8h/tmFfeOxJ+vvkxsKxdmN0WtS9zLdHEgfgVOiMVgv+Po4Q==} + to-regex-range@5.0.1: dependencies: - no-case: 2.3.2 - upper-case: 1.1.3 - dev: true + is-number: 7.0.0 - /tmp@0.0.33: - resolution: {integrity: sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==} - engines: {node: '>=0.6.0'} - dependencies: - os-tmpdir: 1.0.2 - dev: true + tree-kill@1.2.2: {} - /to-regex-range@5.0.1: - resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} - engines: {node: '>=8.0'} - dependencies: - is-number: 7.0.0 - dev: true + trim-lines@3.0.1: {} - /tree-kill@1.2.2: - resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} - hasBin: true - dev: true + trough@2.2.0: {} - /ts-interface-checker@0.1.13: - resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} - dev: true + ts-interface-checker@0.1.13: {} - /ts-node@10.9.2(@types/node@20.14.11)(typescript@5.9.3): - resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==} - hasBin: true - peerDependencies: - '@swc/core': '>=1.2.50' - '@swc/wasm': '>=1.2.50' - '@types/node': '*' - typescript: '>=2.7' - peerDependenciesMeta: - '@swc/core': - optional: true - '@swc/wasm': - optional: true + tslib@2.8.1: {} + + tsup@8.5.1(jiti@2.4.2)(postcss@8.5.32)(supports-color@10.2.2)(typescript@5.9.3)(yaml@2.9.1): dependencies: - '@cspotcode/source-map-support': 0.8.1 - '@tsconfig/node10': 1.0.12 - '@tsconfig/node12': 1.0.11 - '@tsconfig/node14': 1.0.3 - '@tsconfig/node16': 1.0.4 - '@types/node': 20.14.11 - acorn: 8.17.0 - acorn-walk: 8.3.5 - arg: 4.1.3 - create-require: 1.1.1 - diff: 4.0.4 - make-error: 1.3.6 + bundle-require: 5.1.0(esbuild@0.27.7) + cac: 6.7.14 + chokidar: 4.0.3 + consola: 3.4.2 + debug: 4.4.3(supports-color@10.2.2) + esbuild: 0.27.7 + fix-dts-default-cjs-exports: 1.0.1 + joycon: 3.1.1 + picocolors: 1.1.1 + postcss-load-config: 6.0.1(jiti@2.4.2)(postcss@8.5.32)(yaml@2.9.1) + resolve-from: 5.0.0 + rollup: 4.65.1 + source-map: 0.7.6 + sucrase: 3.35.1 + tinyexec: 0.3.2 + tinyglobby: 0.2.17 + tree-kill: 1.2.2 + optionalDependencies: + postcss: 8.5.32 typescript: 5.9.3 - v8-compile-cache-lib: 3.0.1 - yn: 3.1.1 - dev: true - - /tslib@1.14.1: - resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} - dev: true - - /tslib@2.8.1: - resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + transitivePeerDependencies: + - jiti + - supports-color + - tsx + - yaml - /tsup@8.5.1(jiti@2.4.2)(typescript@5.9.3): - resolution: {integrity: sha512-xtgkqwdhpKWr3tKPmCkvYmS9xnQK3m3XgxZHwSUjvfTjp7YfXe5tT3GgWi0F2N+ZSMsOeWeZFh7ZZFg5iPhing==} - engines: {node: '>=18'} - hasBin: true - peerDependencies: - '@microsoft/api-extractor': ^7.36.0 - '@swc/core': ^1 - postcss: ^8.4.12 - typescript: '>=4.5.0' - peerDependenciesMeta: - '@microsoft/api-extractor': - optional: true - '@swc/core': - optional: true - postcss: - optional: true - typescript: - optional: true + tsup@8.5.1(jiti@2.7.0)(postcss@8.5.32)(supports-color@10.2.2)(typescript@5.9.3)(yaml@2.9.1): dependencies: bundle-require: 5.1.0(esbuild@0.27.7) cac: 6.7.14 chokidar: 4.0.3 consola: 3.4.2 - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) esbuild: 0.27.7 fix-dts-default-cjs-exports: 1.0.1 joycon: 3.1.1 picocolors: 1.1.1 - postcss-load-config: 6.0.1(jiti@2.4.2) + postcss-load-config: 6.0.1(jiti@2.7.0)(postcss@8.5.32)(yaml@2.9.1) resolve-from: 5.0.0 - rollup: 4.62.2 + rollup: 4.65.1 source-map: 0.7.6 sucrase: 3.35.1 tinyexec: 0.3.2 tinyglobby: 0.2.17 tree-kill: 1.2.2 + optionalDependencies: + postcss: 8.5.32 typescript: 5.9.3 transitivePeerDependencies: - jiti - supports-color - tsx - yaml - dev: true - /turbo-darwin-64@2.0.9: - resolution: {integrity: sha512-owlGsOaExuVGBUfrnJwjkL1BWlvefjSKczEAcpLx4BI7Oh6ttakOi+JyomkPkFlYElRpjbvlR2gP8WIn6M/+xQ==} - cpu: [x64] - os: [darwin] - requiresBuild: true - dev: true - optional: true + turbo-stream@3.2.1: {} - /turbo-darwin-arm64@2.0.9: - resolution: {integrity: sha512-XAXkKkePth5ZPPE/9G9tTnPQx0C8UTkGWmNGYkpmGgRr8NedW+HrPsi9N0HcjzzIH9A4TpNYvtiV+WcwdaEjKA==} - cpu: [arm64] - os: [darwin] - requiresBuild: true - dev: true - optional: true + turbo@2.11.10: + optionalDependencies: + '@turbo/darwin-64': 2.11.10 + '@turbo/darwin-arm64': 2.11.10 + '@turbo/linux-64': 2.11.10 + '@turbo/linux-arm64': 2.11.10 + '@turbo/windows-64': 2.11.10 + '@turbo/windows-arm64': 2.11.10 - /turbo-linux-64@2.0.9: - resolution: {integrity: sha512-l9wSgEjrCFM1aG16zItBsZ206ZlhSSx1owB8Cgskfv0XyIXRGHRkluihiaxkp+UeU5WoEfz4EN5toc+ICA0q0w==} - cpu: [x64] - os: [linux] - requiresBuild: true - dev: true - optional: true + type-check@0.4.0: + dependencies: + prelude-ls: 1.2.1 - /turbo-linux-arm64@2.0.9: - resolution: {integrity: sha512-gRnjxXRne18B27SwxXMqL3fJu7jw/8kBrOBTBNRSmZZiG1Uu3nbnP7b4lgrA/bCku6C0Wligwqurvtpq6+nFHA==} - cpu: [arm64] - os: [linux] - requiresBuild: true - dev: true - optional: true + type-fest@2.19.0: {} - /turbo-windows-64@2.0.9: - resolution: {integrity: sha512-ZVo0apxUvaRq4Vm1qhsfqKKhtRgReYlBVf9MQvVU1O9AoyydEQvLDO1ryqpXDZWpcHoFxHAQc9msjAMtE5K2lA==} - cpu: [x64] - os: [win32] - requiresBuild: true - dev: true - optional: true + type-fest@5.10.0: + dependencies: + tagged-tag: 1.0.0 - /turbo-windows-arm64@2.0.9: - resolution: {integrity: sha512-sGRz7c5Pey6y7y9OKi8ypbWNuIRPF9y8xcMqL56OZifSUSo+X2EOsOleR9MKxQXVaqHPGOUKWsE6y8hxBi9pag==} - cpu: [arm64] - os: [win32] - requiresBuild: true - dev: true - optional: true + typescript@5.9.3: {} - /turbo@2.0.9: - resolution: {integrity: sha512-QaLaUL1CqblSKKPgLrFW3lZWkWG4pGBQNW+q1ScJB5v1D/nFWtsrD/yZljW/bdawg90ihi4/ftQJ3h6fz1FamA==} - hasBin: true + typescript@7.0.2: optionalDependencies: - turbo-darwin-64: 2.0.9 - turbo-darwin-arm64: 2.0.9 - turbo-linux-64: 2.0.9 - turbo-linux-arm64: 2.0.9 - turbo-windows-64: 2.0.9 - turbo-windows-arm64: 2.0.9 - dev: true + '@typescript/typescript-aix-ppc64': 7.0.2 + '@typescript/typescript-darwin-arm64': 7.0.2 + '@typescript/typescript-darwin-x64': 7.0.2 + '@typescript/typescript-freebsd-arm64': 7.0.2 + '@typescript/typescript-freebsd-x64': 7.0.2 + '@typescript/typescript-linux-arm': 7.0.2 + '@typescript/typescript-linux-arm64': 7.0.2 + '@typescript/typescript-linux-loong64': 7.0.2 + '@typescript/typescript-linux-mips64el': 7.0.2 + '@typescript/typescript-linux-ppc64': 7.0.2 + '@typescript/typescript-linux-riscv64': 7.0.2 + '@typescript/typescript-linux-s390x': 7.0.2 + '@typescript/typescript-linux-x64': 7.0.2 + '@typescript/typescript-netbsd-arm64': 7.0.2 + '@typescript/typescript-netbsd-x64': 7.0.2 + '@typescript/typescript-openbsd-arm64': 7.0.2 + '@typescript/typescript-openbsd-x64': 7.0.2 + '@typescript/typescript-sunos-x64': 7.0.2 + '@typescript/typescript-win32-arm64': 7.0.2 + '@typescript/typescript-win32-x64': 7.0.2 + + ufo@1.6.4: {} + + undici-types@5.26.5: {} + + undici-types@6.21.0: {} + + undici-types@8.9.0: {} + + undici@7.29.1: {} + + unenv@2.0.0-rc.24: + dependencies: + pathe: 2.0.3 - /type-check@0.4.0: - resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} - engines: {node: '>= 0.8.0'} + unicode-trie@2.0.0: dependencies: - prelude-ls: 1.2.1 - dev: true + pako: 0.2.9 + tiny-inflate: 1.0.3 - /type-fest@0.21.3: - resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} - engines: {node: '>=10'} - dev: true + unified@11.0.5: + dependencies: + '@types/unist': 3.0.3 + bail: 2.0.2 + devlop: 1.1.0 + extend: 3.0.2 + is-plain-obj: 4.1.0 + trough: 2.2.0 + vfile: 6.0.3 - /typescript@5.9.3: - resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} - engines: {node: '>=14.17'} - hasBin: true + unist-util-is@6.0.1: + dependencies: + '@types/unist': 3.0.3 - /ufo@1.6.4: - resolution: {integrity: sha512-JFNbkD1Svwe0KvGi8GOeLcP4kAWQ609twvCdcHxq1oSL8svv39ZuSvajcD8B+5D0eL4+s1Is2D/O6KN3qcTeRA==} - dev: true + unist-util-position-from-estree@2.0.0: + dependencies: + '@types/unist': 3.0.3 - /uglify-js@3.19.3: - resolution: {integrity: sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==} - engines: {node: '>=0.8.0'} - hasBin: true - requiresBuild: true - dev: true - optional: true + unist-util-position@5.0.0: + dependencies: + '@types/unist': 3.0.3 - /undici-types@5.26.5: - resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} - dev: true + unist-util-remove-position@5.0.0: + dependencies: + '@types/unist': 3.0.3 + unist-util-visit: 5.2.0 - /undici-types@6.21.0: - resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} + unist-util-stringify-position@4.0.0: + dependencies: + '@types/unist': 3.0.3 + + unist-util-visit-parents@6.1.0: + dependencies: + '@types/unist': 3.0.3 + unist-util-is: 6.0.1 + + unist-util-visit@5.2.0: + dependencies: + '@types/unist': 3.0.3 + unist-util-is: 6.0.1 + unist-util-visit-parents: 6.1.0 + + unpic@4.2.2: {} + + update-browserslist-db@1.3.4(browserslist@4.29.5): + dependencies: + browserslist: 4.29.5 + escalade: 3.2.0 + picocolors: 1.1.1 + + update-check@1.5.4: + dependencies: + registry-auth-token: 3.3.2 + registry-url: 3.1.0 + + uri-js@4.4.1: + dependencies: + punycode: 2.3.1 + + use-callback-ref@1.3.3(@types/react@18.3.3)(react@18.3.1): + dependencies: + react: 18.3.1 + tslib: 2.8.1 + optionalDependencies: + '@types/react': 18.3.3 + + use-callback-ref@1.3.3(@types/react@19.3.0)(react@19.3.1): + dependencies: + react: 19.3.1 + tslib: 2.8.1 + optionalDependencies: + '@types/react': 19.3.0 + + use-sidecar@1.1.3(@types/react@18.3.3)(react@18.3.1): + dependencies: + detect-node-es: 1.1.0 + react: 18.3.1 + tslib: 2.8.1 + optionalDependencies: + '@types/react': 18.3.3 + + use-sidecar@1.1.3(@types/react@19.3.0)(react@19.3.1): + dependencies: + detect-node-es: 1.1.0 + react: 19.3.1 + tslib: 2.8.1 + optionalDependencies: + '@types/react': 19.3.0 + + use-sync-external-store@1.7.0(react@19.3.1): + dependencies: + react: 19.3.1 + + util-deprecate@1.0.2: {} + + vary@1.1.2: {} + + vfile-message@4.0.3: + dependencies: + '@types/unist': 3.0.3 + unist-util-stringify-position: 4.0.0 + + vfile@6.0.3: + dependencies: + '@types/unist': 3.0.3 + vfile-message: 4.0.3 + + vinext@1.2.1(@types/node@22.18.6)(@vitejs/plugin-react@6.0.1(vite@8.3.4(@types/node@22.18.6)(esbuild@0.28.2)(jiti@2.4.2)(terser@5.51.2)(yaml@2.9.1)))(@vitejs/plugin-rsc@0.5.38(react-dom@19.3.1(react@19.3.1))(react-server-dom-webpack@19.3.1(react-dom@19.3.1(react@19.3.1))(react@19.3.1)(webpack@5.112.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.4.39)(sharp@0.35.5(@types/node@22.18.6))))(react@19.3.1)(vite@8.3.4(@types/node@22.18.6)(esbuild@0.28.2)(jiti@2.4.2)(terser@5.51.2)(yaml@2.9.1)))(next@14.2.35(@playwright/test@1.64.1)(@types/react@19.3.0)(react-dom@19.3.1(react@19.3.1))(react@19.3.1))(react-dom@19.3.1(react@19.3.1))(react-server-dom-webpack@19.3.1(react-dom@19.3.1(react@19.3.1))(react@19.3.1)(webpack@5.112.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.4.39)(sharp@0.35.5(@types/node@22.18.6))))(react@19.3.1)(vite@8.3.4(@types/node@22.18.6)(esbuild@0.28.2)(jiti@2.4.2)(terser@5.51.2)(yaml@2.9.1)): + dependencies: + '@unpic/react': 1.0.2(next@14.2.35(@playwright/test@1.64.1)(@types/react@19.3.0)(react-dom@19.3.1(react@19.3.1))(react@19.3.1))(react-dom@19.3.1(react@19.3.1))(react@19.3.1) + '@vercel/og': 1.0.3(@types/node@22.18.6) + '@vinext/types': 1.0.2 + '@vitejs/plugin-react': 6.0.1(vite@8.3.4(@types/node@22.18.6)(esbuild@0.28.2)(jiti@2.4.2)(terser@5.51.2)(yaml@2.9.1)) + ipaddr.js: 2.5.0 + magic-string: 0.30.21 + react: 19.3.1 + react-dom: 19.3.1(react@19.3.1) + vite: 8.3.4(@types/node@22.18.6)(esbuild@0.28.2)(jiti@2.4.2)(terser@5.51.2)(yaml@2.9.1) + vite-plugin-commonjs: 0.10.4 + web-vitals: 4.2.4 + optionalDependencies: + '@vitejs/plugin-rsc': 0.5.38(react-dom@19.3.1(react@19.3.1))(react-server-dom-webpack@19.3.1(react-dom@19.3.1(react@19.3.1))(react@19.3.1)(webpack@5.112.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.4.39)(sharp@0.35.5(@types/node@22.18.6))))(react@19.3.1)(vite@8.3.4(@types/node@22.18.6)(esbuild@0.28.2)(jiti@2.4.2)(terser@5.51.2)(yaml@2.9.1)) + react-server-dom-webpack: 19.3.1(react-dom@19.3.1(react@19.3.1))(react@19.3.1)(webpack@5.112.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.4.39)(sharp@0.35.5(@types/node@22.18.6))) + transitivePeerDependencies: + - '@types/node' + - next + + vite-node@3.2.4(@types/node@20.14.11)(jiti@2.7.0)(lightningcss@1.33.0)(supports-color@10.2.2)(terser@5.51.2)(yaml@2.9.1): + dependencies: + cac: 6.7.14 + debug: 4.4.3(supports-color@10.2.2) + es-module-lexer: 1.7.0 + pathe: 2.0.3 + vite: 7.3.7(@types/node@20.14.11)(jiti@2.7.0)(lightningcss@1.33.0)(terser@5.51.2)(yaml@2.9.1) + transitivePeerDependencies: + - '@types/node' + - jiti + - less + - lightningcss + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + - tsx + - yaml + + vite-node@3.2.4(@types/node@22.18.6)(jiti@2.4.2)(lightningcss@1.33.0)(supports-color@10.2.2)(terser@5.51.2)(yaml@2.9.1): + dependencies: + cac: 6.7.14 + debug: 4.4.3(supports-color@10.2.2) + es-module-lexer: 1.7.0 + pathe: 2.0.3 + vite: 7.3.7(@types/node@22.18.6)(jiti@2.4.2)(lightningcss@1.33.0)(terser@5.51.2)(yaml@2.9.1) + transitivePeerDependencies: + - '@types/node' + - jiti + - less + - lightningcss + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + - tsx + - yaml - /universalify@2.0.1: - resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} - engines: {node: '>= 10.0.0'} - dev: true + vite-node@3.2.4(@types/node@22.18.6)(jiti@2.7.0)(lightningcss@1.33.0)(supports-color@10.2.2)(terser@5.51.2)(yaml@2.9.1): + dependencies: + cac: 6.7.14 + debug: 4.4.3(supports-color@10.2.2) + es-module-lexer: 1.7.0 + pathe: 2.0.3 + vite: 7.3.7(@types/node@22.18.6)(jiti@2.7.0)(lightningcss@1.33.0)(terser@5.51.2)(yaml@2.9.1) + transitivePeerDependencies: + - '@types/node' + - jiti + - less + - lightningcss + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + - tsx + - yaml - /update-browserslist-db@1.2.3(browserslist@4.28.5): - resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} - hasBin: true - peerDependencies: - browserslist: '>= 4.21.0' + vite-plugin-commonjs@0.10.4: dependencies: - browserslist: 4.28.5 - escalade: 3.2.0 - picocolors: 1.1.1 - dev: true + acorn: 8.19.0 + magic-string: 0.30.21 + vite-plugin-dynamic-import: 1.6.0 - /update-check@1.5.4: - resolution: {integrity: sha512-5YHsflzHP4t1G+8WGPlvKbJEbAJGCgw+Em+dGR1KmBUbr1J36SJBqlHLjR7oob7sco5hWHGQVcr9B2poIVDDTQ==} + vite-plugin-dynamic-import@1.6.0: dependencies: - registry-auth-token: 3.3.2 - registry-url: 3.1.0 - dev: true + acorn: 8.19.0 + es-module-lexer: 1.7.0 + fast-glob: 3.3.3 + magic-string: 0.30.21 - /upper-case-first@1.1.2: - resolution: {integrity: sha512-wINKYvI3Db8dtjikdAqoBbZoP6Q+PZUyfMR7pmwHzjC2quzSkUq5DmPrTtPEqHaz8AGtmsB4TqwapMTM1QAQOQ==} + vite@7.3.7(@types/node@20.14.11)(jiti@2.7.0)(lightningcss@1.33.0)(terser@5.51.2)(yaml@2.9.1): dependencies: - upper-case: 1.1.3 - dev: true - - /upper-case@1.1.3: - resolution: {integrity: sha512-WRbjgmYzgXkCV7zNVpy5YgrHgbBv126rMALQQMrmzOVC4GM2waQ9x7xtm8VU+1yF2kWyPzI9zbZ48n4vSxwfSA==} - dev: true + esbuild: 0.28.2 + fdir: 6.5.0(picomatch@4.0.7) + picomatch: 4.0.7 + postcss: 8.5.32 + rollup: 4.65.1 + tinyglobby: 0.2.17 + optionalDependencies: + '@types/node': 20.14.11 + fsevents: 2.3.3 + jiti: 2.7.0 + lightningcss: 1.33.0 + terser: 5.51.2 + yaml: 2.9.1 - /uri-js@4.4.1: - resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + vite@7.3.7(@types/node@22.18.6)(jiti@2.4.2)(lightningcss@1.33.0)(terser@5.51.2)(yaml@2.9.1): dependencies: - punycode: 2.3.1 - dev: true + esbuild: 0.28.2 + fdir: 6.5.0(picomatch@4.0.7) + picomatch: 4.0.7 + postcss: 8.5.32 + rollup: 4.65.1 + tinyglobby: 0.2.17 + optionalDependencies: + '@types/node': 22.18.6 + fsevents: 2.3.3 + jiti: 2.4.2 + lightningcss: 1.33.0 + terser: 5.51.2 + yaml: 2.9.1 - /use-callback-ref@1.3.3(@types/react@18.3.3)(react@18.3.1): - resolution: {integrity: sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==} - engines: {node: '>=10'} - peerDependencies: - '@types/react': '*' - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true + vite@7.3.7(@types/node@22.18.6)(jiti@2.7.0)(lightningcss@1.33.0)(terser@5.51.2)(yaml@2.9.1): dependencies: - '@types/react': 18.3.3 - react: 18.3.1 - tslib: 2.8.1 - dev: false + esbuild: 0.28.2 + fdir: 6.5.0(picomatch@4.0.7) + picomatch: 4.0.7 + postcss: 8.5.32 + rollup: 4.65.1 + tinyglobby: 0.2.17 + optionalDependencies: + '@types/node': 22.18.6 + fsevents: 2.3.3 + jiti: 2.7.0 + lightningcss: 1.33.0 + terser: 5.51.2 + yaml: 2.9.1 - /use-sidecar@1.1.3(@types/react@18.3.3)(react@18.3.1): - resolution: {integrity: sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==} - engines: {node: '>=10'} - peerDependencies: - '@types/react': '*' - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true + vite@8.3.4(@types/node@22.18.6)(esbuild@0.28.2)(jiti@2.4.2)(terser@5.51.2)(yaml@2.9.1): dependencies: - '@types/react': 18.3.3 - detect-node-es: 1.1.0 - react: 18.3.1 - tslib: 2.8.1 - dev: false - - /util-deprecate@1.0.2: - resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} - dev: true + lightningcss: 1.33.0 + picomatch: 4.0.7 + postcss: 8.5.32 + rolldown: 1.2.15 + tinyglobby: 0.2.17 + optionalDependencies: + '@types/node': 22.18.6 + esbuild: 0.28.2 + fsevents: 2.3.3 + jiti: 2.4.2 + terser: 5.51.2 + yaml: 2.9.1 - /v8-compile-cache-lib@3.0.1: - resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} - dev: true + vite@8.3.4(@types/node@26.6.5)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1): + dependencies: + lightningcss: 1.33.0 + picomatch: 4.0.7 + postcss: 8.5.32 + rolldown: 1.2.15 + tinyglobby: 0.2.17 + optionalDependencies: + '@types/node': 26.6.5 + esbuild: 0.28.2 + fsevents: 2.3.3 + jiti: 2.7.0 + terser: 5.51.2 + yaml: 2.9.1 + optional: true - /validate-npm-package-name@5.0.1: - resolution: {integrity: sha512-OljLrQ9SQdOUqTaQxqL5dEfZWrXExyyWsozYlAWFawPVNuD83igl7uJD2RTkNMbniIYgt8l81eCJGIdQF7avLQ==} - engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} - dev: true + vitefu@1.1.3(vite@8.3.4(@types/node@22.18.6)(esbuild@0.28.2)(jiti@2.4.2)(terser@5.51.2)(yaml@2.9.1)): + optionalDependencies: + vite: 8.3.4(@types/node@22.18.6)(esbuild@0.28.2)(jiti@2.4.2)(terser@5.51.2)(yaml@2.9.1) - /vite-node@3.2.4(@types/node@22.18.6)(jiti@2.4.2): - resolution: {integrity: sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==} - engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} - hasBin: true + vitest@3.2.7(@types/debug@4.1.13)(@types/node@20.14.11)(jiti@2.7.0)(lightningcss@1.33.0)(supports-color@10.2.2)(terser@5.51.2)(yaml@2.9.1): dependencies: - cac: 6.7.14 - debug: 4.4.3 - es-module-lexer: 1.7.0 + '@types/chai': 5.2.3 + '@vitest/expect': 3.2.7 + '@vitest/mocker': 3.2.7(vite@7.3.7(@types/node@20.14.11)(jiti@2.7.0)(lightningcss@1.33.0)(terser@5.51.2)(yaml@2.9.1)) + '@vitest/pretty-format': 3.2.7 + '@vitest/runner': 3.2.7 + '@vitest/snapshot': 3.2.7 + '@vitest/spy': 3.2.7 + '@vitest/utils': 3.2.7 + chai: 5.3.3 + debug: 4.4.3(supports-color@10.2.2) + expect-type: 1.4.0 + magic-string: 0.30.21 pathe: 2.0.3 - vite: 7.3.6(@types/node@22.18.6)(jiti@2.4.2) + picomatch: 4.0.7 + std-env: 3.10.0 + tinybench: 2.9.0 + tinyexec: 0.3.2 + tinyglobby: 0.2.17 + tinypool: 1.1.1 + tinyrainbow: 2.0.0 + vite: 7.3.7(@types/node@20.14.11)(jiti@2.7.0)(lightningcss@1.33.0)(terser@5.51.2)(yaml@2.9.1) + vite-node: 3.2.4(@types/node@20.14.11)(jiti@2.7.0)(lightningcss@1.33.0)(supports-color@10.2.2)(terser@5.51.2)(yaml@2.9.1) + why-is-node-running: 2.3.0 + optionalDependencies: + '@types/debug': 4.1.13 + '@types/node': 20.14.11 transitivePeerDependencies: - - '@types/node' - jiti - less - lightningcss + - msw - sass - sass-embedded - stylus @@ -6562,109 +12282,76 @@ packages: - tsx - yaml - /vite@7.3.6(@types/node@22.18.6)(jiti@2.4.2): - resolution: {integrity: sha512-4XP60spRGjSZFf1qYH+dJIkK2znL3zQfl9KkOV9MkkRR/3Dls0dxaBsQPTloEc5BLXWPL9vsOxopxyKoMmDueg==} - engines: {node: ^20.19.0 || >=22.12.0} - hasBin: true - peerDependencies: - '@types/node': ^20.19.0 || >=22.12.0 - jiti: '>=1.21.0' - less: ^4.0.0 - lightningcss: ^1.21.0 - sass: ^1.70.0 - sass-embedded: ^1.70.0 - stylus: '>=0.54.8' - sugarss: ^5.0.0 - terser: ^5.16.0 - tsx: ^4.8.1 - yaml: ^2.4.2 - peerDependenciesMeta: - '@types/node': - optional: true - jiti: - optional: true - less: - optional: true - lightningcss: - optional: true - sass: - optional: true - sass-embedded: - optional: true - stylus: - optional: true - sugarss: - optional: true - terser: - optional: true - tsx: - optional: true - yaml: - optional: true + vitest@3.2.7(@types/debug@4.1.13)(@types/node@22.18.6)(jiti@2.4.2)(lightningcss@1.33.0)(supports-color@10.2.2)(terser@5.51.2)(yaml@2.9.1): dependencies: - '@types/node': 22.18.6 - esbuild: 0.28.1 - fdir: 6.5.0(picomatch@4.0.5) - jiti: 2.4.2 - picomatch: 4.0.5 - postcss: 8.5.16 - rollup: 4.62.2 + '@types/chai': 5.2.3 + '@vitest/expect': 3.2.7 + '@vitest/mocker': 3.2.7(vite@7.3.7(@types/node@22.18.6)(jiti@2.4.2)(lightningcss@1.33.0)(terser@5.51.2)(yaml@2.9.1)) + '@vitest/pretty-format': 3.2.7 + '@vitest/runner': 3.2.7 + '@vitest/snapshot': 3.2.7 + '@vitest/spy': 3.2.7 + '@vitest/utils': 3.2.7 + chai: 5.3.3 + debug: 4.4.3(supports-color@10.2.2) + expect-type: 1.4.0 + magic-string: 0.30.21 + pathe: 2.0.3 + picomatch: 4.0.7 + std-env: 3.10.0 + tinybench: 2.9.0 + tinyexec: 0.3.2 tinyglobby: 0.2.17 + tinypool: 1.1.1 + tinyrainbow: 2.0.0 + vite: 7.3.7(@types/node@22.18.6)(jiti@2.4.2)(lightningcss@1.33.0)(terser@5.51.2)(yaml@2.9.1) + vite-node: 3.2.4(@types/node@22.18.6)(jiti@2.4.2)(lightningcss@1.33.0)(supports-color@10.2.2)(terser@5.51.2)(yaml@2.9.1) + why-is-node-running: 2.3.0 optionalDependencies: - fsevents: 2.3.3 + '@types/debug': 4.1.13 + '@types/node': 22.18.6 + transitivePeerDependencies: + - jiti + - less + - lightningcss + - msw + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + - tsx + - yaml - /vitest@3.2.4(@types/node@22.18.6)(jiti@2.4.2): - resolution: {integrity: sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==} - engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} - hasBin: true - peerDependencies: - '@edge-runtime/vm': '*' - '@types/debug': ^4.1.12 - '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 - '@vitest/browser': 3.2.4 - '@vitest/ui': 3.2.4 - happy-dom: '*' - jsdom: '*' - peerDependenciesMeta: - '@edge-runtime/vm': - optional: true - '@types/debug': - optional: true - '@types/node': - optional: true - '@vitest/browser': - optional: true - '@vitest/ui': - optional: true - happy-dom: - optional: true - jsdom: - optional: true + vitest@3.2.7(@types/debug@4.1.13)(@types/node@22.18.6)(jiti@2.7.0)(lightningcss@1.33.0)(supports-color@10.2.2)(terser@5.51.2)(yaml@2.9.1): dependencies: '@types/chai': 5.2.3 - '@types/node': 22.18.6 - '@vitest/expect': 3.2.4 - '@vitest/mocker': 3.2.4(vite@7.3.6) + '@vitest/expect': 3.2.7 + '@vitest/mocker': 3.2.7(vite@7.3.7(@types/node@22.18.6)(jiti@2.7.0)(lightningcss@1.33.0)(terser@5.51.2)(yaml@2.9.1)) '@vitest/pretty-format': 3.2.7 - '@vitest/runner': 3.2.4 - '@vitest/snapshot': 3.2.4 - '@vitest/spy': 3.2.4 - '@vitest/utils': 3.2.4 + '@vitest/runner': 3.2.7 + '@vitest/snapshot': 3.2.7 + '@vitest/spy': 3.2.7 + '@vitest/utils': 3.2.7 chai: 5.3.3 - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) expect-type: 1.4.0 magic-string: 0.30.21 pathe: 2.0.3 - picomatch: 4.0.5 + picomatch: 4.0.7 std-env: 3.10.0 tinybench: 2.9.0 tinyexec: 0.3.2 tinyglobby: 0.2.17 tinypool: 1.1.1 tinyrainbow: 2.0.0 - vite: 7.3.6(@types/node@22.18.6)(jiti@2.4.2) - vite-node: 3.2.4(@types/node@22.18.6)(jiti@2.4.2) + vite: 7.3.7(@types/node@22.18.6)(jiti@2.7.0)(lightningcss@1.33.0)(terser@5.51.2)(yaml@2.9.1) + vite-node: 3.2.4(@types/node@22.18.6)(jiti@2.7.0)(lightningcss@1.33.0)(supports-color@10.2.2)(terser@5.51.2)(yaml@2.9.1) why-is-node-running: 2.3.0 + optionalDependencies: + '@types/debug': 4.1.13 + '@types/node': 22.18.6 transitivePeerDependencies: - jiti - less @@ -6679,88 +12366,219 @@ packages: - tsx - yaml - /wcwidth@1.0.1: - resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==} + watchpack@2.6.3: dependencies: - defaults: 1.0.4 - dev: true + graceful-fs: 4.2.11 - /webrtc-adapter@9.0.1: - resolution: {integrity: sha512-1AQO+d4ElfVSXyzNVTOewgGT/tAomwwztX/6e3totvyyzXPvXIIuUUjAmyZGbKBKbZOXauuJooZm3g6IuFuiNQ==} - engines: {node: '>=6.0.0', npm: '>=3.10.0'} + web-namespaces@2.0.1: {} + + web-vitals@4.2.4: {} + + webpack-sources@3.6.0: {} + + webpack@5.112.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.4.39)(sharp@0.35.5(@types/node@22.18.6)): + dependencies: + '@types/estree': 1.0.9 + '@types/json-schema': 7.0.15 + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/wasm-edit': 1.14.1 + '@webassemblyjs/wasm-parser': 1.14.1 + browserslist: 4.29.5 + chrome-trace-event: 1.0.4 + enhanced-resolve: 5.26.0 + es-module-lexer: 2.3.2 + events: 3.3.0 + graceful-fs: 4.2.11 + mime-db: 1.54.0 + minimizer-webpack-plugin: 5.13.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.4.39)(sharp@0.35.5(@types/node@22.18.6))(webpack@5.112.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.4.39)(sharp@0.35.5(@types/node@22.18.6))) + schema-utils: 4.8.1(webpack@5.112.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.4.39)(sharp@0.35.5(@types/node@22.18.6))) + tapable: 2.3.3 + watchpack: 2.6.3 + webpack-sources: 3.6.0 + transitivePeerDependencies: + - '@minify-html/node' + - '@napi-rs/image' + - '@swc/core' + - '@swc/css' + - '@swc/html' + - clean-css + - cssnano + - csso + - esbuild + - html-minifier-terser + - imagemin + - lightningcss + - postcss + - sharp + - svgo + - uglify-js + + webrtc-adapter@9.0.6: dependencies: sdp: 3.2.2 - dev: false - /which@2.0.2: - resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} - engines: {node: '>= 8'} - hasBin: true + which@2.0.2: dependencies: isexe: 2.0.0 - dev: true - /why-is-node-running@2.3.0: - resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} - engines: {node: '>=8'} - hasBin: true + why-is-node-running@2.3.0: dependencies: siginfo: 2.0.0 stackback: 0.0.2 - /word-wrap@1.2.5: - resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} - engines: {node: '>=0.10.0'} - dev: true + widest-line@4.0.1: + dependencies: + string-width: 5.1.2 - /wordwrap@1.0.0: - resolution: {integrity: sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==} - dev: true + word-wrap@1.2.5: {} - /wrap-ansi@6.2.0: - resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} - engines: {node: '>=8'} + workerd@1.20261012.1: + optionalDependencies: + '@cloudflare/workerd-darwin-64': 1.20261012.1 + '@cloudflare/workerd-darwin-arm64': 1.20261012.1 + '@cloudflare/workerd-linux-64': 1.20261012.1 + '@cloudflare/workerd-linux-arm64': 1.20261012.1 + '@cloudflare/workerd-windows-64': 1.20261012.1 + + workerd@1.20261019.1: + optionalDependencies: + '@cloudflare/workerd-darwin-64': 1.20261019.1 + '@cloudflare/workerd-darwin-arm64': 1.20261019.1 + '@cloudflare/workerd-linux-64': 1.20261019.1 + '@cloudflare/workerd-linux-arm64': 1.20261019.1 + '@cloudflare/workerd-windows-64': 1.20261019.1 + + wrangler@4.151.3(@cloudflare/workers-types@5.20261019.1)(@types/node@22.18.6): + dependencies: + '@cloudflare/kv-asset-handler': 0.5.0 + '@cloudflare/unenv-preset': 2.16.2(unenv@2.0.0-rc.24)(workerd@1.20261019.1) + blake3-wasm: 2.1.5 + esbuild: 0.28.2 + miniflare: 5.20261019.1-beta(@types/node@22.18.6) + path-to-regexp: 6.3.0 + unenv: 2.0.0-rc.24 + workerd: 1.20261019.1 + optionalDependencies: + '@cloudflare/workers-types': 5.20261019.1 + fsevents: 2.3.3 + transitivePeerDependencies: + - '@types/node' + - bufferutil + - utf-8-validate + + wrangler@4.151.3(@cloudflare/workers-types@5.20261019.1)(@types/node@26.6.5): + dependencies: + '@cloudflare/kv-asset-handler': 0.5.0 + '@cloudflare/unenv-preset': 2.16.2(unenv@2.0.0-rc.24)(workerd@1.20261019.1) + blake3-wasm: 2.1.5 + esbuild: 0.28.2 + miniflare: 5.20261019.1-beta(@types/node@26.6.5) + path-to-regexp: 6.3.0 + unenv: 2.0.0-rc.24 + workerd: 1.20261019.1 + optionalDependencies: + '@cloudflare/workers-types': 5.20261019.1 + fsevents: 2.3.3 + transitivePeerDependencies: + - '@types/node' + - bufferutil + - utf-8-validate + + wrap-ansi@6.2.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + + wrap-ansi@7.0.0: dependencies: ansi-styles: 4.3.0 string-width: 4.2.3 strip-ansi: 6.0.1 - dev: true - /wrappy@1.0.2: - resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - dev: true + wrap-ansi@8.1.0: + dependencies: + ansi-styles: 6.2.3 + string-width: 5.1.2 + strip-ansi: 7.2.0 - /xtend@4.0.2: - resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} - engines: {node: '>=0.4'} - dev: false + ws@8.21.0: {} - /yaml@2.9.0: - resolution: {integrity: sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==} - engines: {node: '>= 14.6'} - hasBin: true - dev: true + ws@8.22.0: {} - /yn@3.1.1: - resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==} - engines: {node: '>=6'} - dev: true + xtend@4.0.2: {} - /yocto-queue@0.1.0: - resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} - engines: {node: '>=10'} - dev: true + y18n@5.0.8: {} + + yaml@2.9.1: {} + + yargs-parser@21.1.1: {} + + yargs@17.7.2: + dependencies: + cliui: 8.0.1 + escalade: 3.2.0 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 21.1.1 + + yocto-queue@0.1.0: {} + + yoctocolors-cjs@2.1.3: {} + + yoga-layout@3.2.1: {} + + youch-core@0.3.3: + dependencies: + '@poppinss/exception': 1.2.3 + error-stack-parser-es: 1.0.5 + + youch@4.1.0-beta.10: + dependencies: + '@poppinss/colors': 4.1.6 + '@poppinss/dumper': 0.6.5 + '@speed-highlight/core': 1.2.24 + cookie: 1.1.1 + youch-core: 0.3.3 + + yuku-analyzer@0.19.0: + dependencies: + '@yuku-toolchain/types': 0.19.0 + yuku-ast: 0.19.0 + yuku-core: 0.19.0 + + yuku-ast@0.19.0: + dependencies: + '@yuku-toolchain/types': 0.19.0 + + yuku-core@0.19.0: + dependencies: + '@yuku-toolchain/types': 0.19.0 + optionalDependencies: + '@yuku-core/binding-android-arm64': 0.19.0 + '@yuku-core/binding-darwin-arm64': 0.19.0 + '@yuku-core/binding-darwin-x64': 0.19.0 + '@yuku-core/binding-freebsd-x64': 0.19.0 + '@yuku-core/binding-linux-arm-gnu': 0.19.0 + '@yuku-core/binding-linux-arm-musl': 0.19.0 + '@yuku-core/binding-linux-arm64-gnu': 0.19.0 + '@yuku-core/binding-linux-arm64-musl': 0.19.0 + '@yuku-core/binding-linux-x64-gnu': 0.19.0 + '@yuku-core/binding-linux-x64-musl': 0.19.0 + '@yuku-core/binding-win32-arm64': 0.19.0 + '@yuku-core/binding-win32-x64': 0.19.0 + + zbsearch@4.0.1: {} + + zod@3.25.76: {} - /zod@3.25.67: - resolution: {integrity: sha512-idA2YXwpCdqUSKRCACDE6ItZD9TZzy3OZMtpfLoh6oPR47lipysRrJfjzMqFxQ3uJuUPyUeWe1r9vLH33xO/Qw==} - dev: false + zod@4.6.7: {} - /zod@4.6.5: - resolution: {integrity: sha512-v5l/aFXZQeai4awLbOpSoHecE9UiMrnfx75tEXLjNonXVARxQ5mOeipTjROUchszUNCqnE+hqAMujRsRHsut2Q==} - dev: false + zwitch@2.0.4: {} - /zxing-wasm@1.3.4: - resolution: {integrity: sha512-9l0QymyATF19FmI92QHe7Dayb+BUN7P7zFAt5iDgTnUf0dFWokz6GVA/W9EepjW5q8s3e89fIE/7uxpX27yqEQ==} + zxing-wasm@3.1.6(@types/emscripten@1.41.6): dependencies: - '@types/emscripten': 1.41.5 - dev: false + '@types/emscripten': 1.41.6 + type-fest: 5.10.0 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 3ff5faaaf..9e47213c8 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -1,3 +1,23 @@ packages: - "apps/*" + - "templates/*" - "packages/*" + - "e2e" +allowBuilds: + esbuild: true + workerd: true +overrides: + "@libsql/kysely-libsql>@libsql/client": "0.17.4" +packageExtensions: + "next@14.2.35": + peerDependencies: + "@types/react": "*" + "qrcode.react@4.2.0": + peerDependencies: + "@types/react": "*" + "@yudiel/react-qr-scanner@2.6.0": + peerDependencies: + "@types/react": "*" + "sonner@1.7.4": + peerDependencies: + "@types/react": "*" diff --git a/templates/nextjs-full/.env.example b/templates/nextjs-full/.env.example new file mode 100644 index 000000000..f2ede0f5b --- /dev/null +++ b/templates/nextjs-full/.env.example @@ -0,0 +1,64 @@ +# Copy this file to .env. Keep real secrets in ignored environment files. +# Local development works with an empty .env using these defaults. +DATABASE_URL=file:.data/web.db +NEXT_PUBLIC_APP_URL=http://localhost:3000 + +# Required in production: set a unique secret with at least 32 characters. +# Generate one with: node -e "console.log(require('node:crypto').randomBytes(32).toString('hex'))" +BETTER_AUTH_SECRET= + +# Required for full-template production: replace NEXT_PUBLIC_APP_URL with your +# deployment URL, configure persistent database storage, and set the S3 and +# Discord variables below. Production requires S3 even when developing locally +# with filesystem uploads. Set either the Discord participant role ID or name. +# HACKKIT_BLOB_ADAPTER=s3 +# HACKKIT_S3_BUCKET= +# HACKKIT_S3_REGION=us-east-1 +# HACKKIT_S3_ACCESS_KEY_ID= +# HACKKIT_S3_SECRET_ACCESS_KEY= +# DISCORD_GUILD_ID= +# DISCORD_BOT_API_URL= +# DISCORD_INTERNAL_AUTH_KEY= +# DISCORD_PARTICIPANT_ROLE_ID= +# DISCORD_PARTICIPANT_ROLE_NAME= + +# Optional: auth URL defaults to NEXT_PUBLIC_APP_URL. +# BETTER_AUTH_URL=http://localhost:3000 +# Optional: comma-separated additional trusted origins. +# BETTER_AUTH_TRUSTED_ORIGINS=https://another-origin.example.com + +# Optional: database dialect is inferred from DATABASE_URL. Set libsql explicitly +# for a local libSQL file; supported values are sqlite, libsql, postgresql, mysql. +# HACKKIT_DATABASE_DIALECT=sqlite +# Optional: required only for authenticated remote libSQL / Turso databases. +# TURSO_AUTH_TOKEN= + +# Optional: local development storage defaults to these values. +# HACKKIT_BLOB_ADAPTER=local +# HACKKIT_LOCAL_BLOB_BASE_DIR=.data/uploads +# Optional: custom endpoint for S3-compatible stores such as R2. +# HACKKIT_S3_ENDPOINT= +# Optional: verification links default to NEXT_PUBLIC_APP_URL. +# DISCORD_VERIFICATION_BASE_URL=http://localhost:3000 + +# Optional: OAuth providers. Enable a provider by setting both its ID and secret. +# GITHUB_CLIENT_ID= +# GITHUB_CLIENT_SECRET= +# GOOGLE_CLIENT_ID= +# GOOGLE_CLIENT_SECRET= + +# Optional: email defaults to none. For Resend, configure: +# HACKKIT_EMAIL_PROVIDER=resend +# RESEND_API_KEY= +# HACKKIT_EMAIL_FROM="HackKit " +# HACKKIT_EMAIL_REPLY_TO= + +# Optional: use SMTP instead of Resend by configuring: +# HACKKIT_EMAIL_PROVIDER=smtp +# SMTP_HOST= +# SMTP_PORT=587 +# SMTP_SECURE=false +# SMTP_USERNAME= +# SMTP_PASSWORD= +# HACKKIT_EMAIL_FROM="HackKit " +# HACKKIT_EMAIL_REPLY_TO= diff --git a/apps/web/README.md b/templates/nextjs-full/README.md similarity index 67% rename from apps/web/README.md rename to templates/nextjs-full/README.md index 6d1ace8d7..c13d287fa 100644 --- a/apps/web/README.md +++ b/templates/nextjs-full/README.md @@ -4,20 +4,22 @@ Next.js app using MikroORM, Core-owned Better Auth, HackKit UI, Teams, Discord v ## Local setup -Use Node.js 22.17 or newer and pnpm 8.3.1. Run these commands from the repository root: +Use Node.js 22.17 or newer and the repository-pinned pnpm 12.15.0. Run these commands from the repository root: 1. Install dependencies with `pnpm install`. -2. Build workspace packages with `pnpm exec turbo run build --filter=web^...`. -3. Sync plugin routes with `pnpm --filter web sync`. -4. Apply committed migrations with `pnpm --filter web db:migrate`. -5. Insert configured roles with `pnpm --filter web db:seed`. -6. Start Next.js with `pnpm --filter web dev`. +2. Build workspace packages with `pnpm exec turbo run build --filter=@hackkit/template-nextjs-full^...`. +3. Sync plugin routes with `pnpm --filter @hackkit/template-nextjs-full sync`. +4. Apply committed migrations with `pnpm --filter @hackkit/template-nextjs-full db:migrate`. +5. Insert configured roles with `pnpm --filter @hackkit/template-nextjs-full db:seed`. +6. Start Next.js with `pnpm --filter @hackkit/template-nextjs-full dev`. -Development defaults use `http://localhost:3000`, SQLite at `apps/web/.data/web.db`, and local blob storage. OAuth, email, and Discord providers are optional locally. The runtime does not migrate or seed on startup. Plugin sync only updates routes and `hackkit.lock`. +The local `.env` starts empty and is ignored by Git. On a fresh checkout, copy [`.env.example`](.env.example) to `.env` to configure this template. The example lists production requirements and comments out optional integrations. An empty `.env` uses local development defaults. Never commit populated environment files. + +Development defaults use `http://localhost:3000`, SQLite at `templates/nextjs-full/.data/web.db`, and local blob storage. OAuth, email, and Discord providers are optional locally. The runtime does not migrate or seed on startup. Plugin sync only updates routes and `hackkit.lock`. After signup, bootstrap an owner explicitly by assigning `core.owner` to that user's `role_id` in `core_user`, selected by `id`. Better Auth's `user.id` is the canonical ID. The runtime does not infer ownership from email. -`pnpm --filter web db:reset` drops registered tables and migration history in the selected local SQLite database, then migrates and seeds. It refuses production and non-SQLite drivers. Never use it for data you need to retain. +`pnpm --filter @hackkit/template-nextjs-full db:reset` drops registered tables and migration history in the selected local SQLite database, then migrates and seeds. It refuses production and non-SQLite drivers. Never use it for data you need to retain. ## Database selection @@ -38,9 +40,9 @@ Core, Better Auth, installed plugins (including disabled plugins), and applicati Migrations and snapshots are committed under `db/migrations/postgresql`, `db/migrations/mysql`, and `db/migrations/sqlite`. libSQL uses the SQLite chain. After changing entities: 1. Select a disposable development database for the dialect using the variables above. -2. Run `pnpm --filter web db:generate --name describe-change`. +2. Run `pnpm --filter @hackkit/template-nextjs-full db:generate --name describe-change`. 3. Review the generated TypeScript migration and snapshot. Repeat generation for the other dialects. -4. Apply with `pnpm --filter web db:migrate` and validate against fresh databases. +4. Apply with `pnpm --filter @hackkit/template-nextjs-full db:migrate` and validate against fresh databases. 5. Commit every dialect's reviewed migration and snapshot. Set `enabled: false` on a registered plugin to disable behavior while keeping its schema and data. Removing it can generate table drops. Review data retention before applying them. `db:seed` only inserts missing configured role IDs; it does not update existing roles or assign them to users. @@ -65,16 +67,13 @@ See [env.ts](env.ts) for exact variable names. Database storage must persist acr ## Validation -Build dependencies before tests. Run `pnpm --filter web test` for committed migrations, auth, and existing-data upgrade/replay checks with SQLite/local libSQL. `pnpm --filter web test:db-workflow` verifies that sync does not connect and reset affects only its selected file. `pnpm --filter web verify` syncs generated files, typechecks, and builds Next.js. After building, `pnpm --filter web test:runtime` starts the production server on loopback port 33017 with an isolated temporary SQLite database, verifies HTTP auth and access control, then stops the server and removes its test data. +Integration tests now live in [E2E](../../e2e/README.md). From the repository root, run `corepack pnpm test:e2e:db` for database workflows and the configured driver matrix, `corepack pnpm test:e2e:http` for production HTTP checks, or `corepack pnpm test:e2e:browser` for browser journeys. `corepack pnpm test:e2e` runs all suites. Every run uses disposable storage. CI requires PostgreSQL, MySQL, and HTTP libSQL in addition to SQLite and local libSQL. -`pnpm --filter web test:db-matrix` always runs SQLite and local libSQL. For the complete matrix, supply URLs for **empty, disposable** databases: +Package behavior tests remain beside their packages and run through `corepack pnpm test`. The template's `verify` command syncs plugin files, typechecks, and builds after dependencies and production configuration are ready. -- `HACKKIT_TEST_POSTGRESQL_URL` -- `HACKKIT_TEST_MYSQL_URL` -- `HACKKIT_TEST_LIBSQL_URL` (a real HTTP/libSQL server) -- `HACKKIT_REQUIRE_DATABASE_MATRIX=1` to fail if any URL is missing. +## Distribution -The matrix writes test accounts and domain records; it never drops the target database. Use fresh databases for every run. CI requires all five targets, checks schema agreement and existing-data upgrades, runs package tests, typechecks, and builds Next.js. External OAuth, hosted Turso credentials/TLS, and real email/Discord delivery require deployment-specific validation. +This is a runnable workspace example. Packages remain private and use workspace dependencies. [Standalone distribution and CLI init](../../docs/plans/template-distribution.md) are deferred. The [minimal template](../nextjs-minimal/README.md) provides Core registration and basic administration with SQLite and local uploads. ## Architecture diff --git a/templates/nextjs-full/app/admin/check-in/page.tsx b/templates/nextjs-full/app/admin/check-in/page.tsx new file mode 100644 index 000000000..871705bf6 --- /dev/null +++ b/templates/nextjs-full/app/admin/check-in/page.tsx @@ -0,0 +1,30 @@ +import { CheckInScanner } from "@hackkit/ui"; +import { CorePermission } from "@hackkit/core"; +import Link from "next/link"; +import { getPageGuards } from "@/lib/runtime"; + +export const dynamic = "force-dynamic"; + +export default async function CheckInPage() { + const pageGuards = await getPageGuards(); + await pageGuards.requirePermission(CorePermission.UsersCheckIn); + + return ( +
+
+
+

+ Hackathon check-in +

+ + Dashboard + +
+ +
+
+ ); +} diff --git a/templates/nextjs-full/app/admin/events/[id]/edit/page.tsx b/templates/nextjs-full/app/admin/events/[id]/edit/page.tsx new file mode 100644 index 000000000..92443ebe8 --- /dev/null +++ b/templates/nextjs-full/app/admin/events/[id]/edit/page.tsx @@ -0,0 +1,49 @@ +import { notFound } from "next/navigation"; +import { EventAdminForm, toDateTimeLocalValue } from "@hackkit/ui"; +import { CorePermission } from "@hackkit/core"; +import { getHackkit, getPageGuards } from "@/lib/runtime"; + +export const dynamic = "force-dynamic"; + +export default async function EditEventPage({ + params, +}: { + params: { id: string }; +}) { + const pageGuards = await getPageGuards(); + const principal = await pageGuards.requirePermission( + CorePermission.EventsUpdate, + ); + const hackkit = await getHackkit(); + const event = await hackkit.events.getEvent({ + eventId: params.id, + actorAuthId: principal.user.id, + }); + + if (!event) notFound(); + + return ( +
+
+

+ Edit event +

+ +
+
+ ); +} diff --git a/templates/nextjs-full/app/admin/events/new/page.tsx b/templates/nextjs-full/app/admin/events/new/page.tsx new file mode 100644 index 000000000..04b7ff5c2 --- /dev/null +++ b/templates/nextjs-full/app/admin/events/new/page.tsx @@ -0,0 +1,29 @@ +import { EventAdminForm, toDateTimeLocalValue } from "@hackkit/ui"; +import { CorePermission } from "@hackkit/core"; +import { getHackkit, getPageGuards } from "@/lib/runtime"; + +export const dynamic = "force-dynamic"; + +export default async function NewEventPage() { + const pageGuards = await getPageGuards(); + await pageGuards.requirePermission(CorePermission.EventsCreate); + const hackkit = await getHackkit(); + + return ( +
+
+

New event

+ +
+
+ ); +} diff --git a/templates/nextjs-full/app/admin/events/page.tsx b/templates/nextjs-full/app/admin/events/page.tsx new file mode 100644 index 000000000..d21b075bc --- /dev/null +++ b/templates/nextjs-full/app/admin/events/page.tsx @@ -0,0 +1,44 @@ +import Link from "next/link"; +import { EventAdminList } from "@hackkit/ui"; +import { CorePermission } from "@hackkit/core"; +import { getHackkit, getPageGuards } from "@/lib/runtime"; + +export const dynamic = "force-dynamic"; + +export default async function AdminEventsPage() { + const pageGuards = await getPageGuards(); + const principal = await pageGuards.requirePermission( + CorePermission.EventsView, + ); + const hackkit = await getHackkit(); + const events = await hackkit.events.listEvents({ + actorAuthId: principal.user.id, + }); + + return ( +
+
+
+
+

+ Events +

+

+ Manage the hackathon schedule. +

+
+ + New event + +
+ +
+
+ ); +} diff --git a/templates/nextjs-full/app/admin/layout.tsx b/templates/nextjs-full/app/admin/layout.tsx new file mode 100644 index 000000000..cb5b2a9df --- /dev/null +++ b/templates/nextjs-full/app/admin/layout.tsx @@ -0,0 +1,50 @@ +import type * as React from "react"; +import { CorePermission } from "@hackkit/core"; +import Link from "next/link"; +import { getPageGuards } from "@/lib/runtime"; + +export const dynamic = "force-dynamic"; + +export default async function AdminLayout({ + children, +}: { + children: React.ReactNode; +}) { + const guards = await getPageGuards(); + await guards.requireNotBanned(); + await guards.requirePermission(CorePermission.Admin); + + const navItems = [ + { href: "/admin", label: "Overview" }, + { href: "/admin/users", label: "Users" }, + { href: "/admin/roles", label: "Roles" }, + { href: "/admin/events", label: "Events" }, + { href: "/admin/check-in", label: "Check-in" }, + { href: "/admin/settings", label: "Settings" }, + ]; + + return ( +
+ +
{children}
+
+ ); +} diff --git a/templates/nextjs-full/app/admin/page.tsx b/templates/nextjs-full/app/admin/page.tsx new file mode 100644 index 000000000..c439891b1 --- /dev/null +++ b/templates/nextjs-full/app/admin/page.tsx @@ -0,0 +1,24 @@ +import { AdminOverviewPanel } from "@hackkit/ui"; +import { getRuntime } from "@/lib/runtime"; + +export const dynamic = "force-dynamic"; + +export default async function AdminOverviewPage() { + const runtime = await getRuntime(); + const actorAuthId = await runtime.getAuthId(); + const overview = await runtime.hackkit.admin.getOverview({ actorAuthId }); + + return ( +
+
+

+ Admin Overview +

+

+ Registration, approval, suspension, and check-in summary. +

+
+ +
+ ); +} diff --git a/templates/nextjs-full/app/admin/roles/page.tsx b/templates/nextjs-full/app/admin/roles/page.tsx new file mode 100644 index 000000000..77ef4780f --- /dev/null +++ b/templates/nextjs-full/app/admin/roles/page.tsx @@ -0,0 +1,26 @@ +import { CorePermission } from "@hackkit/core"; +import { AdminRolesPanel } from "@hackkit/ui"; +import { getRuntime } from "@/lib/runtime"; + +export const dynamic = "force-dynamic"; + +export default async function AdminRolesPage() { + const runtime = await getRuntime(); + const actorAuthId = await runtime.getAuthId(); + const roles = await runtime.hackkit.roles.listRoles({ actorAuthId }); + + return ( +
+
+

Roles

+

+ Manage admin roles and permissions. +

+
+ +
+ ); +} diff --git a/templates/nextjs-full/app/admin/scanner/[eventId]/page.tsx b/templates/nextjs-full/app/admin/scanner/[eventId]/page.tsx new file mode 100644 index 000000000..288d61d68 --- /dev/null +++ b/templates/nextjs-full/app/admin/scanner/[eventId]/page.tsx @@ -0,0 +1,44 @@ +import Link from "next/link"; +import { notFound } from "next/navigation"; +import { EventScanner } from "@hackkit/ui"; +import { CorePermission } from "@hackkit/core"; +import { getHackkit, getPageGuards } from "@/lib/runtime"; + +export const dynamic = "force-dynamic"; + +export default async function EventScannerPage({ + params, +}: { + params: { eventId: string }; +}) { + const pageGuards = await getPageGuards(); + const principal = await pageGuards.requirePermission( + CorePermission.EventsScan, + ); + const hackkit = await getHackkit(); + const event = await hackkit.events.getEvent({ + eventId: params.eventId, + actorAuthId: principal.user.id, + }); + + if (!event) notFound(); + + return ( +
+
+
+

+ Event scanner +

+ + Back to events + +
+ +
+
+ ); +} diff --git a/templates/nextjs-full/app/admin/settings/page.tsx b/templates/nextjs-full/app/admin/settings/page.tsx new file mode 100644 index 000000000..5f3d4935f --- /dev/null +++ b/templates/nextjs-full/app/admin/settings/page.tsx @@ -0,0 +1,28 @@ +import { CorePermission } from "@hackkit/core"; +import { HackathonSettingsForm } from "@hackkit/ui"; +import { getPageGuards, getRuntime } from "@/lib/runtime"; + +export const dynamic = "force-dynamic"; + +export default async function AdminSettingsPage() { + const guards = await getPageGuards(); + const principal = await guards.requirePermission( + CorePermission.SettingsManage, + ); + const { hackkit } = await getRuntime(); + const settings = await hackkit.settings.list({ + actorAuthId: principal.user.id, + }); + + return ( +
+
+

Hackathon Settings

+

+ Manage live hackathon policy settings. +

+
+ +
+ ); +} diff --git a/templates/nextjs-full/app/admin/users/[authId]/page.tsx b/templates/nextjs-full/app/admin/users/[authId]/page.tsx new file mode 100644 index 000000000..03d390f9e --- /dev/null +++ b/templates/nextjs-full/app/admin/users/[authId]/page.tsx @@ -0,0 +1,36 @@ +import { notFound } from "next/navigation"; +import { AdminUserDetail } from "@hackkit/ui"; +import { getRuntime } from "@/lib/runtime"; + +export const dynamic = "force-dynamic"; + +export default async function AdminUserDetailPage({ + params, +}: { + params: { authId: string }; +}) { + const runtime = await getRuntime(); + const actorAuthId = await runtime.getAuthId(); + const targetAuthId = decodeURIComponent(params.authId); + const [record, roles] = await Promise.all([ + runtime.hackkit.admin.getUser({ actorAuthId, targetAuthId }), + runtime.hackkit.roles.listRoles({ actorAuthId }), + ]); + + if (!record) notFound(); + + return ( +
+
+

+ User Detail +

+

+ Account, registration, approval, suspension, and role + details. +

+
+ +
+ ); +} diff --git a/templates/nextjs-full/app/admin/users/page.tsx b/templates/nextjs-full/app/admin/users/page.tsx new file mode 100644 index 000000000..da56a8791 --- /dev/null +++ b/templates/nextjs-full/app/admin/users/page.tsx @@ -0,0 +1,23 @@ +import { AdminUsersTable } from "@hackkit/ui"; +import { getRuntime } from "@/lib/runtime"; + +export const dynamic = "force-dynamic"; + +export default async function AdminUsersPage() { + const runtime = await getRuntime(); + const actorAuthId = await runtime.getAuthId(); + const users = await runtime.hackkit.admin.listUsers({ actorAuthId }); + + return ( +
+
+

Users

+

+ Review registrations, approvals, roles, suspensions, and + check-ins. +

+
+ +
+ ); +} diff --git a/templates/nextjs-full/app/api/admin/export/route.ts b/templates/nextjs-full/app/api/admin/export/route.ts new file mode 100644 index 000000000..3ffa24d73 --- /dev/null +++ b/templates/nextjs-full/app/api/admin/export/route.ts @@ -0,0 +1,57 @@ +import { HackKitError } from "@hackkit/core"; +import { NextResponse } from "next/server"; +import { getAuthSession } from "@/lib/auth"; +import { getRuntime } from "@/lib/runtime"; + +function escapeCsv(value: unknown): string { + if (value === null || value === undefined) return ""; + const stringValue = + value instanceof Date + ? value.toISOString() + : typeof value === "string" + ? value + : String(value); + if (/[",\n\r]/.test(stringValue)) { + return `"${stringValue.replaceAll('"', '""')}"`; + } + return stringValue; +} + +function toCsv(rows: Record[]): string { + if (rows.length === 0) return ""; + const headers = Object.keys(rows[0] ?? {}); + const body = rows.map((row) => + headers.map((header) => escapeCsv(row[header])).join(","), + ); + return [headers.join(","), ...body].join("\r\n"); +} + +export async function GET() { + const session = await getAuthSession(); + if (!session) { + return NextResponse.json({ error: "Unauthorized" }, { status: 401 }); + } + + const runtime = await getRuntime(); + const actor = await runtime.getCurrentUser(); + const rows = await runtime.hackkit.admin + .exportUsers({ + actorAuthId: actor.id, + }) + .catch((error: unknown) => { + if (error instanceof HackKitError && error.code === "FORBIDDEN") + return null; + throw error; + }); + if (!rows) + return NextResponse.json({ error: "Forbidden" }, { status: 403 }); + const csv = toCsv(rows); + const timestamp = new Date().toISOString().replaceAll(":", "-"); + + return new NextResponse(csv, { + headers: { + "Content-Type": "text/csv; charset=utf-8", + "Content-Disposition": `attachment; filename="hackkit-users-${timestamp}.csv"`, + }, + }); +} diff --git a/templates/nextjs-full/app/api/auth/[...all]/route.ts b/templates/nextjs-full/app/api/auth/[...all]/route.ts new file mode 100644 index 000000000..ac24ae8cf --- /dev/null +++ b/templates/nextjs-full/app/api/auth/[...all]/route.ts @@ -0,0 +1,9 @@ +import { getAuth } from "@/lib/auth"; + +export async function GET(request: Request) { + return (await getAuth()).handler(request); +} + +export async function POST(request: Request) { + return (await getAuth()).handler(request); +} diff --git a/apps/web/app/api/files/register/route.ts b/templates/nextjs-full/app/api/files/register/route.ts similarity index 100% rename from apps/web/app/api/files/register/route.ts rename to templates/nextjs-full/app/api/files/register/route.ts diff --git a/apps/web/app/api/files/upload/route.ts b/templates/nextjs-full/app/api/files/upload/route.ts similarity index 100% rename from apps/web/app/api/files/upload/route.ts rename to templates/nextjs-full/app/api/files/upload/route.ts diff --git a/apps/web/app/api/files/view/route.ts b/templates/nextjs-full/app/api/files/view/route.ts similarity index 100% rename from apps/web/app/api/files/view/route.ts rename to templates/nextjs-full/app/api/files/view/route.ts diff --git a/templates/nextjs-full/app/api/hackkit/[...path]/route.ts b/templates/nextjs-full/app/api/hackkit/[...path]/route.ts new file mode 100644 index 000000000..7584eab06 --- /dev/null +++ b/templates/nextjs-full/app/api/hackkit/[...path]/route.ts @@ -0,0 +1,4 @@ +import { handleHackkitRequest } from "@/lib/runtime"; +export const runtime = "nodejs"; +export const dynamic = "force-dynamic"; +export const POST = handleHackkitRequest; diff --git a/templates/nextjs-full/app/app-bar.tsx b/templates/nextjs-full/app/app-bar.tsx new file mode 100644 index 000000000..55c9035d9 --- /dev/null +++ b/templates/nextjs-full/app/app-bar.tsx @@ -0,0 +1,80 @@ +import Link from "next/link"; +import { CorePermission } from "@hackkit/core"; +import { getAuthSession } from "@/lib/auth"; +import { getCurrentUser, getRuntime } from "@/lib/runtime"; +import { publicSiteConfig } from "@/lib/public-site-config"; +import { getEnabledSiteLinks } from "@/lib/plugin-navigation"; +import { ProfileMenu } from "./profile-menu"; + +async function getIsAdmin(authId: string) { + const runtime = await getRuntime(); + return runtime.hackkit.accessControl.hasPermission( + authId, + CorePermission.Admin, + ); +} + +export async function AppBar() { + const session = await getAuthSession(); + const currentUser = session ? await getCurrentUser() : null; + const isAdmin = currentUser ? await getIsAdmin(currentUser.id) : false; + + return ( +
+
+ + {publicSiteConfig.brand.shortName} + + {session ? ( + + ) : ( +
+ {publicSiteConfig.nav.public.map((item) => ( + + {item.label} + + ))} + + Sign in + + + {publicSiteConfig.landing.primaryAction.label} + +
+ )} +
+
+ ); +} diff --git a/templates/nextjs-full/app/contact/page.tsx b/templates/nextjs-full/app/contact/page.tsx new file mode 100644 index 000000000..dbc3d35d1 --- /dev/null +++ b/templates/nextjs-full/app/contact/page.tsx @@ -0,0 +1 @@ +export { default } from "../help/page"; diff --git a/templates/nextjs-full/app/dashboard/layout.tsx b/templates/nextjs-full/app/dashboard/layout.tsx new file mode 100644 index 000000000..fb92bcda9 --- /dev/null +++ b/templates/nextjs-full/app/dashboard/layout.tsx @@ -0,0 +1 @@ +export { default, dynamic } from "../participant-layout"; diff --git a/templates/nextjs-full/app/dashboard/page.tsx b/templates/nextjs-full/app/dashboard/page.tsx new file mode 100644 index 000000000..973ef0d12 --- /dev/null +++ b/templates/nextjs-full/app/dashboard/page.tsx @@ -0,0 +1,71 @@ +import { + CompetitorOnboardingProgress, + ParticipantDashboard, +} from "@hackkit/ui"; +import { publicSiteConfig } from "@/lib/public-site-config"; +import { getEnabledSiteLinks } from "@/lib/plugin-navigation"; +import { getHackkit } from "@/lib/runtime"; +import { + getCompetitorOnboardingState, + getRequireApproval, +} from "@/lib/onboarding"; + +export const dynamic = "force-dynamic"; + +export default async function DashboardPage() { + const { + steps, + nextHref, + user: currentUser, + userData, + hacker, + } = await getCompetitorOnboardingState("/dashboard"); + const [hackkit, requireApproval] = await Promise.all([ + getHackkit(), + getRequireApproval(), + ]); + const role = currentUser.roleId + ? await hackkit.roles.getRole(currentUser.roleId) + : null; + const participantName = + currentUser.name || currentUser.hackTag || "participant"; + + return ( + + ), + } + : undefined + } + /> + ); +} diff --git a/apps/web/app/discord/page.tsx b/templates/nextjs-full/app/discord/page.tsx similarity index 100% rename from apps/web/app/discord/page.tsx rename to templates/nextjs-full/app/discord/page.tsx diff --git a/apps/web/app/discord/verify/page.tsx b/templates/nextjs-full/app/discord/verify/page.tsx similarity index 100% rename from apps/web/app/discord/verify/page.tsx rename to templates/nextjs-full/app/discord/verify/page.tsx diff --git a/templates/nextjs-full/app/globals.css b/templates/nextjs-full/app/globals.css new file mode 100644 index 000000000..e0ea2ecce --- /dev/null +++ b/templates/nextjs-full/app/globals.css @@ -0,0 +1,58 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +@layer base { + :root { + --background: 0 0% 100%; + --foreground: 222.2 84% 4.9%; + --card: 0 0% 100%; + --card-foreground: 222.2 84% 4.9%; + --popover: 0 0% 100%; + --popover-foreground: 222.2 84% 4.9%; + --primary: 221.2 83.2% 53.3%; + --primary-foreground: 210 40% 98%; + --secondary: 210 40% 96.1%; + --secondary-foreground: 222.2 47.4% 11.2%; + --muted: 210 40% 96.1%; + --muted-foreground: 215.4 16.3% 46.9%; + --accent: 210 40% 96.1%; + --accent-foreground: 222.2 47.4% 11.2%; + --destructive: 0 84.2% 60.2%; + --destructive-foreground: 210 40% 98%; + --border: 214.3 31.8% 91.4%; + --input: 214.3 31.8% 91.4%; + --ring: 221.2 83.2% 53.3%; + --radius: 0.5rem; + } + + .dark { + --background: 222.2 84% 4.9%; + --foreground: 210 40% 98%; + --card: 222.2 84% 4.9%; + --card-foreground: 210 40% 98%; + --popover: 222.2 84% 4.9%; + --popover-foreground: 210 40% 98%; + --primary: 217.2 91.2% 59.8%; + --primary-foreground: 222.2 47.4% 11.2%; + --secondary: 217.2 32.6% 17.5%; + --secondary-foreground: 210 40% 98%; + --muted: 217.2 32.6% 17.5%; + --muted-foreground: 215 20.2% 65.1%; + --accent: 217.2 32.6% 17.5%; + --accent-foreground: 210 40% 98%; + --destructive: 0 62.8% 30.6%; + --destructive-foreground: 210 40% 98%; + --border: 217.2 32.6% 17.5%; + --input: 217.2 32.6% 17.5%; + --ring: 224.3 76.3% 48%; + } + + * { + @apply border-border; + } + + body { + @apply bg-background text-foreground; + } +} diff --git a/templates/nextjs-full/app/help/page.tsx b/templates/nextjs-full/app/help/page.tsx new file mode 100644 index 000000000..4876f845d --- /dev/null +++ b/templates/nextjs-full/app/help/page.tsx @@ -0,0 +1,13 @@ +import { PublicHelpPage } from "@hackkit/ui"; +import { publicSiteConfig } from "@/lib/public-site-config"; + +export default function HelpPage() { + return ( + + ); +} diff --git a/templates/nextjs-full/app/i/approval/layout.tsx b/templates/nextjs-full/app/i/approval/layout.tsx new file mode 100644 index 000000000..6e9c3af0d --- /dev/null +++ b/templates/nextjs-full/app/i/approval/layout.tsx @@ -0,0 +1,14 @@ +import type * as React from "react"; +import { getPageGuards } from "@/lib/runtime"; + +export const dynamic = "force-dynamic"; + +export default async function ApprovalLayout({ + children, +}: { + children: React.ReactNode; +}) { + const guards = await getPageGuards(); + await guards.requireApprovalPendingAccess(); + return children; +} diff --git a/templates/nextjs-full/app/i/approval/page.tsx b/templates/nextjs-full/app/i/approval/page.tsx new file mode 100644 index 000000000..8a4c460c6 --- /dev/null +++ b/templates/nextjs-full/app/i/approval/page.tsx @@ -0,0 +1,27 @@ +import Link from "next/link"; + +export default function ApprovalPendingPage() { + return ( +
+
+

+ Registration received +

+

+ Your account is awaiting approval. +

+

+ Organizers are reviewing your registration. Once approved, + you can access participant features like your Event Pass, + teams, and RSVP. +

+ + Back to dashboard + +
+
+ ); +} diff --git a/templates/nextjs-full/app/invites/layout.tsx b/templates/nextjs-full/app/invites/layout.tsx new file mode 100644 index 000000000..fb92bcda9 --- /dev/null +++ b/templates/nextjs-full/app/invites/layout.tsx @@ -0,0 +1 @@ +export { default, dynamic } from "../participant-layout"; diff --git a/templates/nextjs-full/app/invites/page.tsx b/templates/nextjs-full/app/invites/page.tsx new file mode 100644 index 000000000..0e48306e9 --- /dev/null +++ b/templates/nextjs-full/app/invites/page.tsx @@ -0,0 +1,4 @@ +// @hackkit-generated — do not edit +// Owner: teams@0.0.0 +export * from "@hackkit/plugin-teams/app/invites/page"; +export { default } from "@hackkit/plugin-teams/app/invites/page"; diff --git a/apps/web/app/layout.tsx b/templates/nextjs-full/app/layout.tsx similarity index 100% rename from apps/web/app/layout.tsx rename to templates/nextjs-full/app/layout.tsx diff --git a/templates/nextjs-full/app/onboarding/hacker/hacker-form-defaults.ts b/templates/nextjs-full/app/onboarding/hacker/hacker-form-defaults.ts new file mode 100644 index 000000000..edd46c9ef --- /dev/null +++ b/templates/nextjs-full/app/onboarding/hacker/hacker-form-defaults.ts @@ -0,0 +1,18 @@ +import type { Hacker } from "@hackkit/core"; + +export function toHackerFormDefaults(hacker: Hacker | null) { + if (!hacker) return undefined; + return { + university: hacker.university, + major: hacker.major, + schoolId: hacker.schoolId ?? undefined, + levelOfStudy: hacker.levelOfStudy, + hackathonsAttended: hacker.hackathonsAttended, + softwareExperience: hacker.softwareExperience, + heardFrom: hacker.heardFrom ?? undefined, + githubUrl: hacker.githubUrl ?? undefined, + linkedInUrl: hacker.linkedInUrl ?? undefined, + personalWebsiteUrl: hacker.personalWebsiteUrl ?? undefined, + resumeUrl: hacker.resumeUrl ?? undefined, + }; +} diff --git a/templates/nextjs-full/app/onboarding/hacker/hacker-registration-client.tsx b/templates/nextjs-full/app/onboarding/hacker/hacker-registration-client.tsx new file mode 100644 index 000000000..1cb6ab6fb --- /dev/null +++ b/templates/nextjs-full/app/onboarding/hacker/hacker-registration-client.tsx @@ -0,0 +1,45 @@ +"use client"; + +import { HackerRegistrationForm } from "@hackkit/ui"; +import type { User } from "@hackkit/core"; +import type { HackerRegistrationOptions } from "@hackkit/config"; +import { uploadResumeFile } from "@/lib/upload-resume"; + +export function HackerRegistrationClient({ + currentUser, + defaultValues, + registrationOptions, + successRedirectTo = "/dashboard", +}: { + currentUser: User; + defaultValues?: Partial<{ + university: string; + major: string; + schoolId?: string; + levelOfStudy: string; + hackathonsAttended: number; + softwareExperience: string; + heardFrom?: string; + githubUrl?: string; + linkedInUrl?: string; + personalWebsiteUrl?: string; + resumeUrl?: string; + }>; + registrationOptions?: HackerRegistrationOptions; + successRedirectTo?: string; +}) { + return ( + + ); +} diff --git a/templates/nextjs-full/app/onboarding/hacker/page.tsx b/templates/nextjs-full/app/onboarding/hacker/page.tsx new file mode 100644 index 000000000..c05b57516 --- /dev/null +++ b/templates/nextjs-full/app/onboarding/hacker/page.tsx @@ -0,0 +1,40 @@ +import { redirect } from "next/navigation"; +import { getCurrentUser, getHackkit, getPageGuards } from "@/lib/runtime"; +import { appConfig } from "@/lib/app-config"; +import { getOnboardingSteps } from "@/lib/onboarding"; +import { OnboardingShell } from "../onboarding-shell"; +import { HackerRegistrationClient } from "./hacker-registration-client"; +import { toHackerFormDefaults } from "./hacker-form-defaults"; + +export const dynamic = "force-dynamic"; + +export default async function HackerOnboardingPage() { + await (await getPageGuards()).requireHackerRegistrationOpenForNewHacker(); + const currentUser = await getCurrentUser(); + if (!currentUser.hackTag) { + redirect("/onboarding/hacktag"); + } + + const hackkit = await getHackkit(); + const userData = await hackkit.userData.getUserData(currentUser.id); + if (!userData) { + redirect("/onboarding/user-data"); + } + + const hacker = await hackkit.hackers.getHacker(currentUser.id); + const steps = await getOnboardingSteps("/onboarding/hacker"); + + return ( + + + + ); +} diff --git a/templates/nextjs-full/app/onboarding/hacktag/page.tsx b/templates/nextjs-full/app/onboarding/hacktag/page.tsx new file mode 100644 index 000000000..7c98a15d4 --- /dev/null +++ b/templates/nextjs-full/app/onboarding/hacktag/page.tsx @@ -0,0 +1,30 @@ +import { HackTagForm } from "@hackkit/ui"; +import { getCurrentUser } from "@/lib/runtime"; +import { getOnboardingSteps } from "@/lib/onboarding"; +import { OnboardingShell } from "../onboarding-shell"; + +export const dynamic = "force-dynamic"; + +export default async function HackTagOnboardingPage() { + const currentUser = await getCurrentUser(); + const steps = await getOnboardingSteps("/onboarding/hacktag"); + + return ( + + + + ); +} diff --git a/templates/nextjs-full/app/onboarding/layout.tsx b/templates/nextjs-full/app/onboarding/layout.tsx new file mode 100644 index 000000000..b2898f3bb --- /dev/null +++ b/templates/nextjs-full/app/onboarding/layout.tsx @@ -0,0 +1,14 @@ +import type * as React from "react"; +import { getPageGuards } from "@/lib/runtime"; + +export const dynamic = "force-dynamic"; + +export default async function OnboardingLayout({ + children, +}: { + children: React.ReactNode; +}) { + const guards = await getPageGuards(); + await guards.requireOnboardingAccess(); + return children; +} diff --git a/templates/nextjs-full/app/onboarding/onboarding-shell.tsx b/templates/nextjs-full/app/onboarding/onboarding-shell.tsx new file mode 100644 index 000000000..5196fa8aa --- /dev/null +++ b/templates/nextjs-full/app/onboarding/onboarding-shell.tsx @@ -0,0 +1,35 @@ +import { + CompetitorOnboardingProgress, + type CompetitorOnboardingStep, +} from "@hackkit/ui"; +import type * as React from "react"; + +export function OnboardingShell({ + steps, + title, + description, + children, +}: { + steps: CompetitorOnboardingStep[]; + title: string; + description: string; + children: React.ReactNode; +}) { + return ( +
+
+
+

+ Competitor onboarding +

+

+ {title} +

+

{description}

+
+ + {children} +
+
+ ); +} diff --git a/templates/nextjs-full/app/onboarding/user-data/page.tsx b/templates/nextjs-full/app/onboarding/user-data/page.tsx new file mode 100644 index 000000000..394f5136b --- /dev/null +++ b/templates/nextjs-full/app/onboarding/user-data/page.tsx @@ -0,0 +1,38 @@ +import { UserDataForm, toUserDataFormDefaultValues } from "@hackkit/ui"; +import { redirect } from "next/navigation"; +import { getCurrentUser, getHackkit } from "@/lib/runtime"; +import { getOnboardingSteps } from "@/lib/onboarding"; +import { OnboardingShell } from "../onboarding-shell"; + +export const dynamic = "force-dynamic"; + +export default async function UserDataOnboardingPage() { + const currentUser = await getCurrentUser(); + if (!currentUser.hackTag) { + redirect("/onboarding/hacktag"); + } + + const hackkit = await getHackkit(); + const existingUserData = await hackkit.userData.getUserData(currentUser.id); + const steps = await getOnboardingSteps("/onboarding/user-data"); + + return ( + + + + ); +} diff --git a/apps/web/app/page.tsx b/templates/nextjs-full/app/page.tsx similarity index 100% rename from apps/web/app/page.tsx rename to templates/nextjs-full/app/page.tsx diff --git a/templates/nextjs-full/app/participant-layout.tsx b/templates/nextjs-full/app/participant-layout.tsx new file mode 100644 index 000000000..09ccadc7a --- /dev/null +++ b/templates/nextjs-full/app/participant-layout.tsx @@ -0,0 +1,14 @@ +import type * as React from "react"; +import { getPageGuards } from "@/lib/runtime"; + +export const dynamic = "force-dynamic"; + +export default async function ParticipantLayout({ + children, +}: { + children: React.ReactNode; +}) { + const guards = await getPageGuards(); + await guards.requireParticipantAccess(); + return children; +} diff --git a/templates/nextjs-full/app/pass/event-pass-shell.tsx b/templates/nextjs-full/app/pass/event-pass-shell.tsx new file mode 100644 index 000000000..64f3d7168 --- /dev/null +++ b/templates/nextjs-full/app/pass/event-pass-shell.tsx @@ -0,0 +1,42 @@ +"use client"; + +import { createEventPassQrPayload } from "@hackkit/ui"; +import type { User } from "@hackkit/core"; +import { EventPass } from "@hackkit/ui"; +import * as React from "react"; + +export function EventPassShell({ + user, + eventPassQrTtlMs, +}: { + user: User; + eventPassQrTtlMs: number; +}) { + const [issuedAt, setIssuedAt] = React.useState(() => new Date()); + const qrPayload = React.useMemo( + () => createEventPassQrPayload(user.id, issuedAt), + [user.id, issuedAt], + ); + + React.useEffect(() => { + const expiresAt = issuedAt.getTime() + eventPassQrTtlMs; + const msUntilExpiry = expiresAt - Date.now(); + const refresh = () => setIssuedAt(new Date()); + + if (msUntilExpiry <= 0) { + refresh(); + return; + } + + const timeoutId = window.setTimeout(refresh, msUntilExpiry); + return () => window.clearTimeout(timeoutId); + }, [issuedAt, eventPassQrTtlMs]); + + return ( + setIssuedAt(new Date())} + /> + ); +} diff --git a/templates/nextjs-full/app/pass/layout.tsx b/templates/nextjs-full/app/pass/layout.tsx new file mode 100644 index 000000000..fb92bcda9 --- /dev/null +++ b/templates/nextjs-full/app/pass/layout.tsx @@ -0,0 +1 @@ +export { default, dynamic } from "../participant-layout"; diff --git a/templates/nextjs-full/app/pass/page.tsx b/templates/nextjs-full/app/pass/page.tsx new file mode 100644 index 000000000..6a616afad --- /dev/null +++ b/templates/nextjs-full/app/pass/page.tsx @@ -0,0 +1,22 @@ +import { CoreSetting } from "@hackkit/core"; +import { getCurrentUser, getRuntime } from "@/lib/runtime"; +import { EventPassShell } from "./event-pass-shell"; + +export const dynamic = "force-dynamic"; + +export default async function PassPage() { + const user = await getCurrentUser(); + const runtime = await getRuntime(); + const eventPassQrTtlMs = await runtime.getSettingValue( + CoreSetting.EventPassQrTtlMs, + ); + + return ( +
+ +
+ ); +} diff --git a/templates/nextjs-full/app/profile-menu.tsx b/templates/nextjs-full/app/profile-menu.tsx new file mode 100644 index 000000000..25c01ee34 --- /dev/null +++ b/templates/nextjs-full/app/profile-menu.tsx @@ -0,0 +1,116 @@ +"use client"; + +import { useState } from "react"; +import Link from "next/link"; +import { useRouter } from "next/navigation"; +import { authClient } from "@/lib/auth-client"; + +export function ProfileMenu({ + name, + email, + image, + isAdmin = false, +}: { + name: string; + email: string; + image?: string | null; + isAdmin?: boolean; +}) { + const router = useRouter(); + const [isOpen, setIsOpen] = useState(false); + const [isSigningOut, setIsSigningOut] = useState(false); + const initials = + name + .split(/\s+/) + .filter(Boolean) + .slice(0, 2) + .map((part) => part[0]?.toUpperCase()) + .join("") || "U"; + + async function signOut() { + setIsSigningOut(true); + await authClient.signOut(); + router.push("/sign-in"); + router.refresh(); + } + + return ( +
+ + + {isOpen ? ( +
+
+

{name}

+

+ {email} +

+
+
+ setIsOpen(false)} + className="block rounded-md px-3 py-2 text-sm hover:bg-muted" + > + Settings + + setIsOpen(false)} + className="block rounded-md px-3 py-2 text-sm hover:bg-muted" + > + Registration + + {isAdmin ? ( + setIsOpen(false)} + className="block rounded-md px-3 py-2 text-sm text-accent-foreground hover:bg-muted" + > + Admin + + ) : null} + +
+
+ ) : null} +
+ ); +} diff --git a/templates/nextjs-full/app/providers.tsx b/templates/nextjs-full/app/providers.tsx new file mode 100644 index 000000000..35d6da071 --- /dev/null +++ b/templates/nextjs-full/app/providers.tsx @@ -0,0 +1,12 @@ +"use client"; +import { HackKitUIProvider } from "@hackkit/ui"; +import { createHackkitClient } from "@hackkit/core/http/client"; +import type * as React from "react"; + +const hackkitClient = createHackkitClient(); + +export function Providers({ children }: { children: React.ReactNode }) { + return ( + {children} + ); +} diff --git a/templates/nextjs-full/app/register/page.tsx b/templates/nextjs-full/app/register/page.tsx new file mode 100644 index 000000000..ad808fca8 --- /dev/null +++ b/templates/nextjs-full/app/register/page.tsx @@ -0,0 +1,5 @@ +import { redirect } from "next/navigation"; + +export default function RegisterRedirectPage() { + redirect("/onboarding/user-data"); +} diff --git a/templates/nextjs-full/app/registration-closed/page.tsx b/templates/nextjs-full/app/registration-closed/page.tsx new file mode 100644 index 000000000..c11572fac --- /dev/null +++ b/templates/nextjs-full/app/registration-closed/page.tsx @@ -0,0 +1,26 @@ +import Link from "next/link"; + +export default function RegistrationClosedPage() { + return ( +
+
+

+ Registration closed +

+

+ New hacker registrations are closed. +

+

+ If you have already started registration, sign in to check + your current status or contact the organizing team. +

+ + Go to dashboard + +
+
+ ); +} diff --git a/templates/nextjs-full/app/rsvp/layout.tsx b/templates/nextjs-full/app/rsvp/layout.tsx new file mode 100644 index 000000000..fb92bcda9 --- /dev/null +++ b/templates/nextjs-full/app/rsvp/layout.tsx @@ -0,0 +1 @@ +export { default, dynamic } from "../participant-layout"; diff --git a/templates/nextjs-full/app/rsvp/page.tsx b/templates/nextjs-full/app/rsvp/page.tsx new file mode 100644 index 000000000..055b84fd1 --- /dev/null +++ b/templates/nextjs-full/app/rsvp/page.tsx @@ -0,0 +1,19 @@ +import { RsvpConfirmation } from "@hackkit/ui"; +import { getRuntime } from "@/lib/runtime"; + +export const dynamic = "force-dynamic"; + +export default async function RsvpPage() { + const runtime = await getRuntime(); + const authId = await runtime.getAuthId(); + const [rsvp, summary] = await Promise.all([ + runtime.hackkit.rsvp.getRsvp(authId), + runtime.hackkit.rsvp.getSummary(), + ]); + + return ( +
+ +
+ ); +} diff --git a/templates/nextjs-full/app/schedule/[eventId]/page.tsx b/templates/nextjs-full/app/schedule/[eventId]/page.tsx new file mode 100644 index 000000000..1716bf638 --- /dev/null +++ b/templates/nextjs-full/app/schedule/[eventId]/page.tsx @@ -0,0 +1,37 @@ +import { notFound } from "next/navigation"; +import { ScheduleDetail } from "@hackkit/ui"; +import { getHackkit } from "@/lib/runtime"; + +export const dynamic = "force-dynamic"; + +type ScheduleEventPageProps = { + params: { + eventId: string; + }; +}; + +export default async function ScheduleEventPage({ + params, +}: ScheduleEventPageProps) { + const hackkit = await getHackkit(); + const event = await hackkit.events.getEvent({ eventId: params.eventId }); + + if (!event) notFound(); + + const eventType = hackkit.events.options.find( + (option) => option.value === event.type, + ); + + return ( + + ); +} diff --git a/templates/nextjs-full/app/schedule/page.tsx b/templates/nextjs-full/app/schedule/page.tsx new file mode 100644 index 000000000..7a1304fae --- /dev/null +++ b/templates/nextjs-full/app/schedule/page.tsx @@ -0,0 +1,29 @@ +import { ScheduleList } from "@hackkit/ui"; +import { getHackkit } from "@/lib/runtime"; + +export const dynamic = "force-dynamic"; + +export default async function SchedulePage() { + const hackkit = await getHackkit(); + const events = await hackkit.events.listEvents(); + + return ( +
+
+
+

+ Schedule +

+

+ Public agenda for the hackathon. +

+
+ `/schedule/${event.id}`} + /> +
+
+ ); +} diff --git a/templates/nextjs-full/app/settings/layout.tsx b/templates/nextjs-full/app/settings/layout.tsx new file mode 100644 index 000000000..fb92bcda9 --- /dev/null +++ b/templates/nextjs-full/app/settings/layout.tsx @@ -0,0 +1 @@ +export { default, dynamic } from "../participant-layout"; diff --git a/templates/nextjs-full/app/settings/page.tsx b/templates/nextjs-full/app/settings/page.tsx new file mode 100644 index 000000000..dd5cccc10 --- /dev/null +++ b/templates/nextjs-full/app/settings/page.tsx @@ -0,0 +1,53 @@ +import Link from "next/link"; +import { getCurrentUser, getHackkit } from "@/lib/runtime"; +import { ProfileSettingsClient } from "./profile-settings-client"; + +export const dynamic = "force-dynamic"; + +export default async function SettingsPage() { + const currentUser = await getCurrentUser(); + const hackkit = await getHackkit(); + + return ( +
+
+

Settings

+

+ Manage your account profile and public HackKit profile. +

+
+ + + + {hackkit.isPluginEnabled("discord") ? ( +
+

Discord

+

+ Link Discord and sync participant, organiser role, and + Group roles for the event server. +

+ + Manage Discord + +
+ ) : null} + +
+

Registration

+

+ You can update your demographic, logistics, school, + experience, and resume information after registration. +

+ + Edit registration + +
+
+ ); +} diff --git a/templates/nextjs-full/app/settings/profile-settings-client.tsx b/templates/nextjs-full/app/settings/profile-settings-client.tsx new file mode 100644 index 000000000..f75f12c06 --- /dev/null +++ b/templates/nextjs-full/app/settings/profile-settings-client.tsx @@ -0,0 +1,14 @@ +"use client"; + +import { UserProfileSettingsForm } from "@hackkit/ui"; +import type { User } from "@hackkit/core"; +import { uploadProfilePhotoFile } from "@/lib/upload-profile-photo"; + +export function ProfileSettingsClient({ currentUser }: { currentUser: User }) { + return ( + + ); +} diff --git a/templates/nextjs-full/app/settings/registration/page.tsx b/templates/nextjs-full/app/settings/registration/page.tsx new file mode 100644 index 000000000..f72c69355 --- /dev/null +++ b/templates/nextjs-full/app/settings/registration/page.tsx @@ -0,0 +1,54 @@ +import Link from "next/link"; +import { UserDataForm, toUserDataFormDefaultValues } from "@hackkit/ui"; +import { getCurrentUser, getHackkit } from "@/lib/runtime"; +import { appConfig } from "@/lib/app-config"; +import { toHackerFormDefaults } from "@/app/onboarding/hacker/hacker-form-defaults"; +import { HackerRegistrationClient } from "@/app/onboarding/hacker/hacker-registration-client"; + +export const dynamic = "force-dynamic"; + +export default async function RegistrationSettingsPage() { + const currentUser = await getCurrentUser(); + const hackkit = await getHackkit(); + const [userData, hacker] = await Promise.all([ + hackkit.userData.getUserData(currentUser.id), + hackkit.hackers.getHacker(currentUser.id), + ]); + + return ( +
+
+ + Back to settings + +

+ Registration Settings +

+

+ Update registration details that organizers use for + logistics and participant review. +

+
+ + + + +
+ ); +} diff --git a/templates/nextjs-full/app/sign-in/auth-form.tsx b/templates/nextjs-full/app/sign-in/auth-form.tsx new file mode 100644 index 000000000..aad59d2f0 --- /dev/null +++ b/templates/nextjs-full/app/sign-in/auth-form.tsx @@ -0,0 +1,100 @@ +"use client"; + +import { useState, type FormEvent } from "react"; +import Link from "next/link"; +import { useRouter } from "next/navigation"; +import { authClient } from "@/lib/auth-client"; + +type AuthMode = "sign-in" | "sign-up"; + +export function AuthForm({ mode }: { mode: AuthMode }) { + const router = useRouter(); + const [error, setError] = useState(null); + const [isPending, setIsPending] = useState(false); + const isSignUp = mode === "sign-up"; + + async function onSubmit(event: FormEvent) { + event.preventDefault(); + setError(null); + setIsPending(true); + + const form = new FormData(event.currentTarget); + const email = String(form.get("email") ?? ""); + const password = String(form.get("password") ?? ""); + const name = String(form.get("name") ?? email); + + const result = isSignUp + ? await authClient.signUp.email({ email, password, name }) + : await authClient.signIn.email({ email, password }); + + setIsPending(false); + + if (result.error) { + setError(result.error.message ?? "Authentication failed."); + return; + } + + router.push(isSignUp ? "/register" : "/"); + router.refresh(); + } + + return ( +
+ {isSignUp ? ( + + ) : null} + + + {error ?

{error}

: null} + + + {isSignUp + ? "Have an account? Sign in" + : "Need an account? Sign up"} + +
+ ); +} diff --git a/templates/nextjs-full/app/sign-in/page.tsx b/templates/nextjs-full/app/sign-in/page.tsx new file mode 100644 index 000000000..03f759629 --- /dev/null +++ b/templates/nextjs-full/app/sign-in/page.tsx @@ -0,0 +1,24 @@ +import { redirect } from "next/navigation"; +import { getAuthSession } from "@/lib/auth"; +import { AuthForm } from "./auth-form"; + +export const dynamic = "force-dynamic"; + +export default async function SignInPage() { + const session = await getAuthSession(); + if (session) redirect("/"); + + return ( +
+
+
+

HackKit

+

+ Sign in +

+
+ +
+
+ ); +} diff --git a/templates/nextjs-full/app/sign-up/page.tsx b/templates/nextjs-full/app/sign-up/page.tsx new file mode 100644 index 000000000..d43a22eeb --- /dev/null +++ b/templates/nextjs-full/app/sign-up/page.tsx @@ -0,0 +1,27 @@ +import { redirect } from "next/navigation"; +import { getAuthSession } from "@/lib/auth"; +import { AuthForm } from "../sign-in/auth-form"; + +export const dynamic = "force-dynamic"; + +export default async function SignUpPage() { + const session = await getAuthSession(); + if (session) redirect("/onboarding/hacktag"); + + return ( +
+
+
+

HackKit

+

+ Sign up +

+

+ Create an account, then complete registration. +

+
+ +
+
+ ); +} diff --git a/templates/nextjs-full/app/suspended/page.tsx b/templates/nextjs-full/app/suspended/page.tsx new file mode 100644 index 000000000..694e510f8 --- /dev/null +++ b/templates/nextjs-full/app/suspended/page.tsx @@ -0,0 +1,18 @@ +export default function SuspendedPage() { + return ( +
+
+

+ Account suspended +

+

+ Your access to this HackKit app is suspended. +

+

+ If you think this is a mistake, contact the organizing team + for help. +

+
+
+ ); +} diff --git a/templates/nextjs-full/app/teams/layout.tsx b/templates/nextjs-full/app/teams/layout.tsx new file mode 100644 index 000000000..fb92bcda9 --- /dev/null +++ b/templates/nextjs-full/app/teams/layout.tsx @@ -0,0 +1 @@ +export { default, dynamic } from "../participant-layout"; diff --git a/templates/nextjs-full/app/teams/page.tsx b/templates/nextjs-full/app/teams/page.tsx new file mode 100644 index 000000000..6aad72fe7 --- /dev/null +++ b/templates/nextjs-full/app/teams/page.tsx @@ -0,0 +1,4 @@ +// @hackkit-generated — do not edit +// Owner: teams@0.0.0 +export * from "@hackkit/plugin-teams/app/teams/page"; +export { default } from "@hackkit/plugin-teams/app/teams/page"; diff --git a/templates/nextjs-full/app/user/[tag]/page.tsx b/templates/nextjs-full/app/user/[tag]/page.tsx new file mode 100644 index 000000000..7777572a7 --- /dev/null +++ b/templates/nextjs-full/app/user/[tag]/page.tsx @@ -0,0 +1,23 @@ +import { notFound } from "next/navigation"; +import { PublicProfileCard } from "@hackkit/ui"; +import { getHackkit } from "@/lib/runtime"; + +export const dynamic = "force-dynamic"; + +export default async function PublicUserProfilePage({ + params, +}: { + params: { tag: string }; +}) { + const tag = decodeURIComponent(params.tag); + const profile = await ( + await getHackkit() + ).users.getPublicProfileByHackTag(tag); + if (!profile) notFound(); + + return ( +
+ +
+ ); +} diff --git a/apps/web/db/migrations/mysql/.snapshot.json b/templates/nextjs-full/db/migrations/mysql/.snapshot.json similarity index 100% rename from apps/web/db/migrations/mysql/.snapshot.json rename to templates/nextjs-full/db/migrations/mysql/.snapshot.json diff --git a/apps/web/db/migrations/mysql/Migration20260927180400_initial.ts b/templates/nextjs-full/db/migrations/mysql/Migration20260927180400_initial.ts similarity index 100% rename from apps/web/db/migrations/mysql/Migration20260927180400_initial.ts rename to templates/nextjs-full/db/migrations/mysql/Migration20260927180400_initial.ts diff --git a/apps/web/db/migrations/postgresql/.snapshot.json b/templates/nextjs-full/db/migrations/postgresql/.snapshot.json similarity index 100% rename from apps/web/db/migrations/postgresql/.snapshot.json rename to templates/nextjs-full/db/migrations/postgresql/.snapshot.json diff --git a/apps/web/db/migrations/postgresql/Migration20260927180400_initial.ts b/templates/nextjs-full/db/migrations/postgresql/Migration20260927180400_initial.ts similarity index 100% rename from apps/web/db/migrations/postgresql/Migration20260927180400_initial.ts rename to templates/nextjs-full/db/migrations/postgresql/Migration20260927180400_initial.ts diff --git a/apps/web/db/migrations/sqlite/.snapshot.json b/templates/nextjs-full/db/migrations/sqlite/.snapshot.json similarity index 100% rename from apps/web/db/migrations/sqlite/.snapshot.json rename to templates/nextjs-full/db/migrations/sqlite/.snapshot.json diff --git a/apps/web/db/migrations/sqlite/Migration20260927180400_initial.ts b/templates/nextjs-full/db/migrations/sqlite/Migration20260927180400_initial.ts similarity index 100% rename from apps/web/db/migrations/sqlite/Migration20260927180400_initial.ts rename to templates/nextjs-full/db/migrations/sqlite/Migration20260927180400_initial.ts diff --git a/apps/web/env.ts b/templates/nextjs-full/env.ts similarity index 100% rename from apps/web/env.ts rename to templates/nextjs-full/env.ts diff --git a/apps/web/hackkit.config.ts b/templates/nextjs-full/hackkit.config.ts similarity index 100% rename from apps/web/hackkit.config.ts rename to templates/nextjs-full/hackkit.config.ts diff --git a/apps/web/hackkit.lock b/templates/nextjs-full/hackkit.lock similarity index 100% rename from apps/web/hackkit.lock rename to templates/nextjs-full/hackkit.lock diff --git a/apps/web/lib/app-config.ts b/templates/nextjs-full/lib/app-config.ts similarity index 100% rename from apps/web/lib/app-config.ts rename to templates/nextjs-full/lib/app-config.ts diff --git a/templates/nextjs-full/lib/auth-client.ts b/templates/nextjs-full/lib/auth-client.ts new file mode 100644 index 000000000..2f75fd48b --- /dev/null +++ b/templates/nextjs-full/lib/auth-client.ts @@ -0,0 +1,5 @@ +"use client"; + +import { createAuthClient } from "better-auth/react"; + +export const authClient = createAuthClient(); diff --git a/apps/web/lib/auth-options.ts b/templates/nextjs-full/lib/auth-options.ts similarity index 100% rename from apps/web/lib/auth-options.ts rename to templates/nextjs-full/lib/auth-options.ts diff --git a/templates/nextjs-full/lib/auth.ts b/templates/nextjs-full/lib/auth.ts new file mode 100644 index 000000000..66b0565a1 --- /dev/null +++ b/templates/nextjs-full/lib/auth.ts @@ -0,0 +1,11 @@ +import "server-only"; +import { headers } from "next/headers"; +import { getCoreRuntime } from "./runtime"; + +export async function getAuth() { + return (await getCoreRuntime()).auth; +} + +export async function getAuthSession() { + return (await getAuth()).api.getSession({ headers: await headers() }); +} diff --git a/apps/web/lib/blob.ts b/templates/nextjs-full/lib/blob.ts similarity index 100% rename from apps/web/lib/blob.ts rename to templates/nextjs-full/lib/blob.ts diff --git a/apps/web/lib/database-config.ts b/templates/nextjs-full/lib/database-config.ts similarity index 100% rename from apps/web/lib/database-config.ts rename to templates/nextjs-full/lib/database-config.ts diff --git a/templates/nextjs-full/lib/hackkit-ui-routes.ts b/templates/nextjs-full/lib/hackkit-ui-routes.ts new file mode 100644 index 000000000..afca1c43b --- /dev/null +++ b/templates/nextjs-full/lib/hackkit-ui-routes.ts @@ -0,0 +1,7 @@ +import { DEFAULT_HACKKIT_UI_ROUTES, type HackKitUIRoutes } from "@hackkit/ui"; + +/** + * Single place for HackKit UI route policy in this HackKit Web App. + * Passed to HackKitUIProvider and buildCompetitorOnboardingSteps. + */ +export const hackKitUIRoutes: HackKitUIRoutes = DEFAULT_HACKKIT_UI_ROUTES; diff --git a/templates/nextjs-full/lib/logger.ts b/templates/nextjs-full/lib/logger.ts new file mode 100644 index 000000000..18b9b02c4 --- /dev/null +++ b/templates/nextjs-full/lib/logger.ts @@ -0,0 +1,11 @@ +import { createLogger, type HackKitLogger } from "@hackkit/core"; +import { appConfig } from "./app-config"; + +let logger: HackKitLogger | null = null; + +export function getAppLogger(): HackKitLogger { + if (!logger) { + logger = createLogger(appConfig.logger); + } + return logger; +} diff --git a/templates/nextjs-full/lib/onboarding.ts b/templates/nextjs-full/lib/onboarding.ts new file mode 100644 index 000000000..d876e88ff --- /dev/null +++ b/templates/nextjs-full/lib/onboarding.ts @@ -0,0 +1,54 @@ +import "server-only"; + +import { + buildCompetitorOnboardingSteps, + getNextOnboardingStepHref, + type CompetitorOnboardingStep, +} from "@hackkit/ui"; +import { CoreSetting } from "@hackkit/core"; +import { hackKitUIRoutes } from "./hackkit-ui-routes"; +import { getCurrentUser, getHackkit, getRuntime } from "./runtime"; + +async function loadCompetitorOnboardingInput(currentPath: string) { + const user = await getCurrentUser(); + const hackkit = await getHackkit(); + const runtime = await getRuntime(); + const [userData, hacker, requireApproval] = await Promise.all([ + hackkit.userData.getUserData(user.id), + hackkit.hackers.getHacker(user.id), + runtime.getSettingValue(CoreSetting.RequireApproval), + ]); + return { + user, + userData, + hacker, + requireApproval: Boolean(requireApproval), + currentPath, + routes: hackKitUIRoutes, + }; +} + +export async function getOnboardingSteps( + currentPath: string, +): Promise { + const input = await loadCompetitorOnboardingInput(currentPath); + return buildCompetitorOnboardingSteps(input); +} + +export async function getCompetitorOnboardingState(currentPath: string) { + const input = await loadCompetitorOnboardingInput(currentPath); + const steps = buildCompetitorOnboardingSteps(input); + return { + steps, + nextHref: getNextOnboardingStepHref(steps), + user: input.user, + userData: input.userData, + hacker: input.hacker, + }; +} + +export async function getRequireApproval(): Promise { + return Boolean( + await (await getRuntime()).getSettingValue(CoreSetting.RequireApproval), + ); +} diff --git a/templates/nextjs-full/lib/plugin-navigation.ts b/templates/nextjs-full/lib/plugin-navigation.ts new file mode 100644 index 000000000..4d32b273e --- /dev/null +++ b/templates/nextjs-full/lib/plugin-navigation.ts @@ -0,0 +1,20 @@ +import "server-only"; +import type { PublicShellLink } from "@hackkit/ui"; +import { appConfig } from "./app-config"; + +// Route ownership belongs to the application, including custom navigation. +const pluginRoutes: Record = { + "/teams": "teams", + "/invites": "teams", + "/discord": "discord", +}; + +export function getEnabledSiteLinks(links: readonly PublicShellLink[]) { + return links.filter((link) => { + const pluginId = pluginRoutes[link.href]; + if (!pluginId) return true; + return appConfig.plugins.some( + (plugin) => plugin.id === pluginId && plugin.enabled !== false, + ); + }); +} diff --git a/apps/web/lib/public-site-config.ts b/templates/nextjs-full/lib/public-site-config.ts similarity index 100% rename from apps/web/lib/public-site-config.ts rename to templates/nextjs-full/lib/public-site-config.ts diff --git a/apps/web/lib/runtime.ts b/templates/nextjs-full/lib/runtime.ts similarity index 100% rename from apps/web/lib/runtime.ts rename to templates/nextjs-full/lib/runtime.ts diff --git a/templates/nextjs-full/lib/upload-profile-photo.ts b/templates/nextjs-full/lib/upload-profile-photo.ts new file mode 100644 index 000000000..2c6b14b87 --- /dev/null +++ b/templates/nextjs-full/lib/upload-profile-photo.ts @@ -0,0 +1,34 @@ +export async function uploadProfilePhotoFile(file: File): Promise { + const registerResponse = await fetch("/api/files/register", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + location: "profile-photos", + fileName: file.name, + }), + }); + + if (!registerResponse.ok) { + throw new Error("Could not prepare profile photo upload."); + } + + const { uploadUrl, storedFileReference } = + (await registerResponse.json()) as { + uploadUrl: string; + storedFileReference: string; + }; + + const uploadResponse = await fetch(uploadUrl, { + method: "PUT", + body: file, + headers: { + "Content-Type": file.type || "application/octet-stream", + }, + }); + + if (!uploadResponse.ok) { + throw new Error("Could not upload profile photo."); + } + + return storedFileReference; +} diff --git a/templates/nextjs-full/lib/upload-resume.ts b/templates/nextjs-full/lib/upload-resume.ts new file mode 100644 index 000000000..d8767b1ec --- /dev/null +++ b/templates/nextjs-full/lib/upload-resume.ts @@ -0,0 +1,59 @@ +async function responseError( + response: Response, + fallback: string, +): Promise { + try { + const body = (await response.json()) as { error?: string }; + if (body.error) return new Error(body.error); + } catch { + // Use the actionable fallback when the server did not return JSON. + } + return new Error(fallback); +} + +export async function uploadResumeFile(file: File): Promise { + if (file.type && file.type !== "application/pdf") { + throw new Error( + "Choose a PDF resume before submitting your registration.", + ); + } + + const registerResponse = await fetch("/api/files/register", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + location: "resumes", + fileName: file.name, + }), + }); + + if (!registerResponse.ok) { + throw await responseError( + registerResponse, + "Could not prepare your resume upload. Please sign in again and retry.", + ); + } + + const { uploadUrl, storedFileReference } = + (await registerResponse.json()) as { + uploadUrl: string; + storedFileReference: string; + }; + + const uploadResponse = await fetch(uploadUrl, { + method: "PUT", + body: file, + headers: { + "Content-Type": file.type || "application/pdf", + }, + }); + + if (!uploadResponse.ok) { + throw await responseError( + uploadResponse, + "Could not upload your resume. Check your connection and retry.", + ); + } + + return storedFileReference; +} diff --git a/templates/nextjs-full/middleware.ts b/templates/nextjs-full/middleware.ts new file mode 100644 index 000000000..c5e2110a8 --- /dev/null +++ b/templates/nextjs-full/middleware.ts @@ -0,0 +1,72 @@ +import { NextResponse, type NextRequest } from "next/server"; + +const AUTH_ROUTE_PATHS = new Set(["/sign-in", "/sign-up"]); +const PUBLIC_ROUTE_PATHS = new Set([ + "/", + "/favicon.ico", + "/registration-closed", + "/suspended", +]); +const PUBLIC_ROUTE_PREFIXES = ["/api/", "/i/approval", "/schedule", "/user/"]; +const PROTECTED_ROUTE_PREFIXES = [ + "/admin", + "/dashboard", + "/invites", + "/onboarding", + "/pass", + "/register", + "/rsvp", + "/settings", + "/teams", +]; + +function hasAuthSessionCookie(request: NextRequest): boolean { + return request.cookies + .getAll() + .some((cookie) => cookie.name.includes("better-auth.session_token")); +} + +function isPublicRoute(pathname: string): boolean { + return ( + PUBLIC_ROUTE_PATHS.has(pathname) || + AUTH_ROUTE_PATHS.has(pathname) || + PUBLIC_ROUTE_PREFIXES.some((prefix) => pathname.startsWith(prefix)) + ); +} + +function isProtectedRoute(pathname: string): boolean { + return PROTECTED_ROUTE_PREFIXES.some( + (prefix) => pathname === prefix || pathname.startsWith(`${prefix}/`), + ); +} + +export function middleware(request: NextRequest) { + const { pathname } = request.nextUrl; + const hasSession = hasAuthSessionCookie(request); + + if (pathname.startsWith("/@")) { + const tag = pathname.slice(2).split("/")[0]; + if (tag) { + return NextResponse.rewrite(new URL(`/user/${tag}`, request.url)); + } + } + + if (AUTH_ROUTE_PATHS.has(pathname) && hasSession) { + return NextResponse.redirect(new URL("/", request.url)); + } + + if (!hasSession && isProtectedRoute(pathname) && !isPublicRoute(pathname)) { + const signInUrl = new URL("/sign-in", request.url); + signInUrl.searchParams.set( + "next", + `${pathname}${request.nextUrl.search}`, + ); + return NextResponse.redirect(signInUrl); + } + + return NextResponse.next(); +} + +export const config = { + matcher: ["/((?!_next/static|_next/image|favicon.ico|.*\\..*).*)"], +}; diff --git a/apps/web/next-env.d.ts b/templates/nextjs-full/next-env.d.ts similarity index 100% rename from apps/web/next-env.d.ts rename to templates/nextjs-full/next-env.d.ts diff --git a/apps/web/next.config.mjs b/templates/nextjs-full/next.config.mjs similarity index 100% rename from apps/web/next.config.mjs rename to templates/nextjs-full/next.config.mjs diff --git a/apps/web/package.json b/templates/nextjs-full/package.json similarity index 77% rename from apps/web/package.json rename to templates/nextjs-full/package.json index aa3dd8bbc..f8f1ce0cf 100644 --- a/apps/web/package.json +++ b/templates/nextjs-full/package.json @@ -1,5 +1,5 @@ { - "name": "web", + "name": "@hackkit/template-nextjs-full", "version": "0.0.0", "private": true, "type": "module", @@ -9,17 +9,12 @@ "db:migrate": "node scripts/db.mjs migrate", "db:seed": "node scripts/db.mjs seed", "db:reset": "node scripts/db.mjs reset", - "test": "vitest run db/__tests__/database-workflow.test.ts db/__tests__/migration-workflow.test.ts", - "test:db-workflow": "bash scripts/test-db-workflow.sh", "sync": "pnpm plugin:sync", - "predev": "turbo run build --filter=web^...", "dev": "next dev -p 3000", "build": "next build", "verify": "pnpm sync && pnpm typecheck && pnpm build", "start": "next start", - "typecheck": "turbo run build --filter=@hackkit/cli && tsc -p tsconfig.json --noEmit", - "test:db-matrix": "vitest run db/__tests__/dialects.test.ts", - "test:runtime": "node scripts/test-runtime.mjs", + "typecheck": "tsc -p tsconfig.json --noEmit", "db:status": "node scripts/db.mjs status", "db:check": "node scripts/db.mjs check", "db:rollback": "node scripts/db.mjs rollback" @@ -57,7 +52,6 @@ "autoprefixer": "10.4.19", "postcss": "8.4.39", "tailwindcss": "3.4.6", - "tailwindcss-animate": "1.0.7", - "vitest": "^3.2.4" + "tailwindcss-animate": "1.0.7" } } diff --git a/templates/nextjs-full/postcss.config.cjs b/templates/nextjs-full/postcss.config.cjs new file mode 100644 index 000000000..e873f1a4f --- /dev/null +++ b/templates/nextjs-full/postcss.config.cjs @@ -0,0 +1,6 @@ +module.exports = { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +}; diff --git a/apps/web/scripts/database.ts b/templates/nextjs-full/scripts/database.ts similarity index 100% rename from apps/web/scripts/database.ts rename to templates/nextjs-full/scripts/database.ts diff --git a/apps/web/scripts/db.mjs b/templates/nextjs-full/scripts/db.mjs similarity index 100% rename from apps/web/scripts/db.mjs rename to templates/nextjs-full/scripts/db.mjs diff --git a/templates/nextjs-full/tailwind.config.ts b/templates/nextjs-full/tailwind.config.ts new file mode 100644 index 000000000..cff883b9f --- /dev/null +++ b/templates/nextjs-full/tailwind.config.ts @@ -0,0 +1,60 @@ +import type { Config } from "tailwindcss"; + +const config = { + darkMode: ["class"], + content: [ + "./app/**/*.{ts,tsx}", + "./components/**/*.{ts,tsx}", + "./lib/**/*.{ts,tsx}", + "../../packages/ui/src/**/*.{ts,tsx}", + "../../packages/plugin-*/src/**/*.{ts,tsx}", + "../../packages/plugin-*/app/**/*.{ts,tsx}", + ], + theme: { + extend: { + colors: { + border: "hsl(var(--border))", + input: "hsl(var(--input))", + ring: "hsl(var(--ring))", + background: "hsl(var(--background))", + foreground: "hsl(var(--foreground))", + primary: { + DEFAULT: "hsl(var(--primary))", + foreground: "hsl(var(--primary-foreground))", + }, + secondary: { + DEFAULT: "hsl(var(--secondary))", + foreground: "hsl(var(--secondary-foreground))", + }, + destructive: { + DEFAULT: "hsl(var(--destructive))", + foreground: "hsl(var(--destructive-foreground))", + }, + muted: { + DEFAULT: "hsl(var(--muted))", + foreground: "hsl(var(--muted-foreground))", + }, + accent: { + DEFAULT: "hsl(var(--accent))", + foreground: "hsl(var(--accent-foreground))", + }, + popover: { + DEFAULT: "hsl(var(--popover))", + foreground: "hsl(var(--popover-foreground))", + }, + card: { + DEFAULT: "hsl(var(--card))", + foreground: "hsl(var(--card-foreground))", + }, + }, + borderRadius: { + lg: "var(--radius)", + md: "calc(var(--radius) - 2px)", + sm: "calc(var(--radius) - 4px)", + }, + }, + }, + plugins: [require("tailwindcss-animate")], +} satisfies Config; + +export default config; diff --git a/apps/web/tsconfig.json b/templates/nextjs-full/tsconfig.json similarity index 100% rename from apps/web/tsconfig.json rename to templates/nextjs-full/tsconfig.json diff --git a/templates/nextjs-minimal/.env.example b/templates/nextjs-minimal/.env.example new file mode 100644 index 000000000..1fa06f751 --- /dev/null +++ b/templates/nextjs-minimal/.env.example @@ -0,0 +1,18 @@ +# Copy this file to .env. Keep real secrets in ignored environment files. +# Local development works with an empty .env using these defaults. +DATABASE_URL=file:.data/web.db +NEXT_PUBLIC_APP_URL=http://localhost:3000 + +# Required in production: set a unique secret with at least 32 characters. +# Generate one with: node -e "console.log(require('node:crypto').randomBytes(32).toString('hex'))" +BETTER_AUTH_SECRET= + +# Production: replace NEXT_PUBLIC_APP_URL with your deployment URL and use +# persistent disk paths for DATABASE_URL and HACKKIT_LOCAL_BLOB_BASE_DIR. + +# Optional: auth URL defaults to NEXT_PUBLIC_APP_URL. +# BETTER_AUTH_URL=http://localhost:3000 +# Optional: comma-separated additional trusted origins. +# BETTER_AUTH_TRUSTED_ORIGINS=https://another-origin.example.com +# Optional: local upload directory, relative to this template or absolute. +# HACKKIT_LOCAL_BLOB_BASE_DIR=.data/uploads diff --git a/templates/nextjs-minimal/README.md b/templates/nextjs-minimal/README.md new file mode 100644 index 000000000..916df9b1d --- /dev/null +++ b/templates/nextjs-minimal/README.md @@ -0,0 +1,38 @@ +# HackKit minimal Next.js template + +A runnable workspace example for hackathon registration and basic administration. It uses Core, Better Auth, HackKit UI, SQLite, and local file storage. It registers no plugins and needs no cloud-provider credentials. + +## Setup + +Use Node.js 22.17 or newer and the repository-pinned pnpm 12.15.0. From the repository root: + +1. Run `corepack pnpm install`. +2. Build dependencies with `corepack pnpm exec turbo run build --filter=@hackkit/template-nextjs-minimal^...`. +3. Run `corepack pnpm --filter @hackkit/template-nextjs-minimal sync`. +4. Run `corepack pnpm --filter @hackkit/template-nextjs-minimal db:migrate`. +5. Run `corepack pnpm --filter @hackkit/template-nextjs-minimal db:seed`. +6. Run `corepack pnpm dev:minimal` and open `http://localhost:3000`. + +The local `.env` starts empty and is ignored by Git. On a fresh checkout, copy [`.env.example`](.env.example) to `.env` to configure this template. The example lists production requirements and comments out optional integrations. An empty `.env` uses local development defaults. Never commit populated environment files. + +Configuration belongs to this folder. Optional local overrides go in `.env.local`. Defaults use `.data/web.db` and `.data/uploads` relative to this template. Starting the app never migrates or seeds its database. Start either template individually; both development servers use port 3000. + +Sign up and complete HackTag, user data, and hacker registration. Organizers can then manage users, roles, approvals, settings, and CSV exports. Owner bootstrap is explicit: assign `core.owner` to the intended user's `core_user.role_id`, selected by the canonical Better Auth `user.id`. No account becomes an owner automatically. + +## Database commands + +Run `corepack pnpm --filter @hackkit/template-nextjs-minimal db:` from the repository root. Commands are `generate`, `migrate`, `seed`, `status`, `check`, `rollback`, and `reset`. Arguments are forwarded, for example `db:generate --name add_field` or `db:rollback --to MigrationName`. + +Reviewed SQLite migrations and snapshots belong to this app. `db:check` fails on pending migrations or schema drift. `db:reset` drops the selected database's registered tables and migration history, then migrates and seeds; it is restricted to local SQLite in development/tests. Use only disposable data for reset. + +## Production + +Set `NEXT_PUBLIC_APP_URL` or `BETTER_AUTH_URL` and a `BETTER_AUTH_SECRET` with at least 32 characters. `DATABASE_URL` must be a local SQLite path, such as `file:/persistent/hackkit/web.db`. Set `HACKKIT_LOCAL_BLOB_BASE_DIR=/persistent/hackkit/uploads` for uploads. Both locations must persist across application restarts. This template requires a Node server with persistent disk storage. + +After building dependencies, run this template's `typecheck` and `build`, apply reviewed migrations and seed explicitly, then run its `start` command. Cloud services and plugins are configured only in the [full template](../nextjs-full/README.md). + +## Validation and distribution + +Repository integration tests live in [E2E](../../e2e/README.md) and execute this template's real configuration, commands, and production build against temporary storage. `corepack pnpm test:e2e` validates both templates. + +This is a workspace example. Keep it inside a clone of the repository while dependencies use `workspace:*`. Standalone distribution and CLI initialization are a [later milestone](../../docs/plans/template-distribution.md). diff --git a/templates/nextjs-minimal/app/admin/layout.tsx b/templates/nextjs-minimal/app/admin/layout.tsx new file mode 100644 index 000000000..4c3ac90f3 --- /dev/null +++ b/templates/nextjs-minimal/app/admin/layout.tsx @@ -0,0 +1,48 @@ +import type * as React from "react"; +import { CorePermission } from "@hackkit/core"; +import Link from "next/link"; +import { getPageGuards } from "@/lib/runtime"; + +export const dynamic = "force-dynamic"; + +export default async function AdminLayout({ + children, +}: { + children: React.ReactNode; +}) { + const guards = await getPageGuards(); + await guards.requireNotBanned(); + await guards.requirePermission(CorePermission.Admin); + + const navItems = [ + { href: "/admin", label: "Overview" }, + { href: "/admin/users", label: "Users" }, + { href: "/admin/roles", label: "Roles" }, + { href: "/admin/settings", label: "Settings" }, + ]; + + return ( +
+ +
{children}
+
+ ); +} diff --git a/templates/nextjs-minimal/app/admin/page.tsx b/templates/nextjs-minimal/app/admin/page.tsx new file mode 100644 index 000000000..341549aa2 --- /dev/null +++ b/templates/nextjs-minimal/app/admin/page.tsx @@ -0,0 +1,27 @@ +import { AdminOverviewPanel } from "@hackkit/ui"; +import { getRuntime } from "@/lib/runtime"; + +export const dynamic = "force-dynamic"; + +export default async function AdminOverviewPage() { + const runtime = await getRuntime(); + const actorAuthId = await runtime.getAuthId(); + const overview = await runtime.hackkit.admin.getOverview({ actorAuthId }); + + return ( +
+
+

+ Admin Overview +

+

+ Registration, approval, and suspension summary. +

+
+ +
+ ); +} diff --git a/templates/nextjs-minimal/app/admin/roles/page.tsx b/templates/nextjs-minimal/app/admin/roles/page.tsx new file mode 100644 index 000000000..77ef4780f --- /dev/null +++ b/templates/nextjs-minimal/app/admin/roles/page.tsx @@ -0,0 +1,26 @@ +import { CorePermission } from "@hackkit/core"; +import { AdminRolesPanel } from "@hackkit/ui"; +import { getRuntime } from "@/lib/runtime"; + +export const dynamic = "force-dynamic"; + +export default async function AdminRolesPage() { + const runtime = await getRuntime(); + const actorAuthId = await runtime.getAuthId(); + const roles = await runtime.hackkit.roles.listRoles({ actorAuthId }); + + return ( +
+
+

Roles

+

+ Manage admin roles and permissions. +

+
+ +
+ ); +} diff --git a/templates/nextjs-minimal/app/admin/settings/page.tsx b/templates/nextjs-minimal/app/admin/settings/page.tsx new file mode 100644 index 000000000..122466338 --- /dev/null +++ b/templates/nextjs-minimal/app/admin/settings/page.tsx @@ -0,0 +1,38 @@ +import { CorePermission, CoreSetting } from "@hackkit/core"; +import { HackathonSettingsForm } from "@hackkit/ui"; +import { getPageGuards, getRuntime } from "@/lib/runtime"; + +export const dynamic = "force-dynamic"; +const registrationSettings = new Set([ + CoreSetting.RegistrationOpen, + CoreSetting.RequireApproval, + CoreSetting.MaximumRegistrations, + CoreSetting.HackathonCapacity, +]); + +export default async function AdminSettingsPage() { + const guards = await getPageGuards(); + const principal = await guards.requirePermission( + CorePermission.SettingsManage, + ); + const { hackkit } = await getRuntime(); + const settings = await hackkit.settings.list({ + actorAuthId: principal.user.id, + }); + + return ( +
+
+

Hackathon Settings

+

+ Manage live hackathon policy settings. +

+
+ + registrationSettings.has(setting.key), + )} + /> +
+ ); +} diff --git a/templates/nextjs-minimal/app/admin/users/[authId]/page.tsx b/templates/nextjs-minimal/app/admin/users/[authId]/page.tsx new file mode 100644 index 000000000..4088acacc --- /dev/null +++ b/templates/nextjs-minimal/app/admin/users/[authId]/page.tsx @@ -0,0 +1,40 @@ +import { notFound } from "next/navigation"; +import { AdminUserDetail } from "@hackkit/ui"; +import { getRuntime } from "@/lib/runtime"; + +export const dynamic = "force-dynamic"; + +export default async function AdminUserDetailPage({ + params, +}: { + params: { authId: string }; +}) { + const runtime = await getRuntime(); + const actorAuthId = await runtime.getAuthId(); + const targetAuthId = decodeURIComponent(params.authId); + const [record, roles] = await Promise.all([ + runtime.hackkit.admin.getUser({ actorAuthId, targetAuthId }), + runtime.hackkit.roles.listRoles({ actorAuthId }), + ]); + + if (!record) notFound(); + + return ( +
+
+

+ User Detail +

+

+ Account, registration, approval, suspension, and role + details. +

+
+ +
+ ); +} diff --git a/templates/nextjs-minimal/app/admin/users/page.tsx b/templates/nextjs-minimal/app/admin/users/page.tsx new file mode 100644 index 000000000..c78ecd013 --- /dev/null +++ b/templates/nextjs-minimal/app/admin/users/page.tsx @@ -0,0 +1,26 @@ +import { AdminUsersTable } from "@hackkit/ui"; +import { getRuntime } from "@/lib/runtime"; + +export const dynamic = "force-dynamic"; + +export default async function AdminUsersPage() { + const runtime = await getRuntime(); + const actorAuthId = await runtime.getAuthId(); + const users = await runtime.hackkit.admin.listUsers({ actorAuthId }); + + return ( +
+
+

Users

+

+ Review registrations, approvals, roles, and suspensions. +

+
+ +
+ ); +} diff --git a/templates/nextjs-minimal/app/api/admin/export/route.ts b/templates/nextjs-minimal/app/api/admin/export/route.ts new file mode 100644 index 000000000..3ffa24d73 --- /dev/null +++ b/templates/nextjs-minimal/app/api/admin/export/route.ts @@ -0,0 +1,57 @@ +import { HackKitError } from "@hackkit/core"; +import { NextResponse } from "next/server"; +import { getAuthSession } from "@/lib/auth"; +import { getRuntime } from "@/lib/runtime"; + +function escapeCsv(value: unknown): string { + if (value === null || value === undefined) return ""; + const stringValue = + value instanceof Date + ? value.toISOString() + : typeof value === "string" + ? value + : String(value); + if (/[",\n\r]/.test(stringValue)) { + return `"${stringValue.replaceAll('"', '""')}"`; + } + return stringValue; +} + +function toCsv(rows: Record[]): string { + if (rows.length === 0) return ""; + const headers = Object.keys(rows[0] ?? {}); + const body = rows.map((row) => + headers.map((header) => escapeCsv(row[header])).join(","), + ); + return [headers.join(","), ...body].join("\r\n"); +} + +export async function GET() { + const session = await getAuthSession(); + if (!session) { + return NextResponse.json({ error: "Unauthorized" }, { status: 401 }); + } + + const runtime = await getRuntime(); + const actor = await runtime.getCurrentUser(); + const rows = await runtime.hackkit.admin + .exportUsers({ + actorAuthId: actor.id, + }) + .catch((error: unknown) => { + if (error instanceof HackKitError && error.code === "FORBIDDEN") + return null; + throw error; + }); + if (!rows) + return NextResponse.json({ error: "Forbidden" }, { status: 403 }); + const csv = toCsv(rows); + const timestamp = new Date().toISOString().replaceAll(":", "-"); + + return new NextResponse(csv, { + headers: { + "Content-Type": "text/csv; charset=utf-8", + "Content-Disposition": `attachment; filename="hackkit-users-${timestamp}.csv"`, + }, + }); +} diff --git a/templates/nextjs-minimal/app/api/auth/[...all]/route.ts b/templates/nextjs-minimal/app/api/auth/[...all]/route.ts new file mode 100644 index 000000000..ac24ae8cf --- /dev/null +++ b/templates/nextjs-minimal/app/api/auth/[...all]/route.ts @@ -0,0 +1,9 @@ +import { getAuth } from "@/lib/auth"; + +export async function GET(request: Request) { + return (await getAuth()).handler(request); +} + +export async function POST(request: Request) { + return (await getAuth()).handler(request); +} diff --git a/templates/nextjs-minimal/app/api/files/register/route.ts b/templates/nextjs-minimal/app/api/files/register/route.ts new file mode 100644 index 000000000..16d935a0c --- /dev/null +++ b/templates/nextjs-minimal/app/api/files/register/route.ts @@ -0,0 +1,41 @@ +import { NextResponse } from "next/server"; +import { getAuthSession } from "@/lib/auth"; +import { getBlobStorage } from "@/lib/blob"; + +export async function POST(request: Request): Promise { + const session = await getAuthSession(); + if (!session) { + return NextResponse.json({ error: "Unauthorized" }, { status: 401 }); + } + + try { + const body = (await request.json()) as { + location?: string; + fileName?: string; + }; + if (!body.location || !body.fileName) { + return NextResponse.json( + { error: "location and fileName are required" }, + { status: 400 }, + ); + } + if (!["resumes", "profile-photos"].includes(body.location)) { + return NextResponse.json( + { error: "Unsupported upload location." }, + { status: 400 }, + ); + } + + const target = await getBlobStorage().getUploadTarget({ + location: body.location, + fileName: body.fileName, + }); + + return NextResponse.json(target); + } catch (error) { + return NextResponse.json( + { error: error instanceof Error ? error.message : "Bad request" }, + { status: 400 }, + ); + } +} diff --git a/templates/nextjs-minimal/app/api/files/upload/route.ts b/templates/nextjs-minimal/app/api/files/upload/route.ts new file mode 100644 index 000000000..fad7b0999 --- /dev/null +++ b/templates/nextjs-minimal/app/api/files/upload/route.ts @@ -0,0 +1,30 @@ +import { writeFile } from "node:fs/promises"; +import { NextResponse } from "next/server"; +import { getAuthSession } from "@/lib/auth"; +import { getBlobStorage } from "@/lib/blob"; + +export async function PUT(request: Request): Promise { + const session = await getAuthSession(); + if (!session) { + return NextResponse.json({ error: "Unauthorized" }, { status: 401 }); + } + + const url = new URL(request.url); + const key = url.searchParams.get("key"); + if (!key) { + return NextResponse.json({ error: "key is required" }, { status: 400 }); + } + if (!key.startsWith("resumes/") && !key.startsWith("profile-photos/")) { + return NextResponse.json( + { error: "Unsupported upload key." }, + { status: 400 }, + ); + } + + const storage = getBlobStorage(); + const filePath = await storage.ensureDirectoryForKey(key); + const body = new Uint8Array(await request.arrayBuffer()); + await writeFile(filePath, body); + + return new NextResponse(null, { status: 204 }); +} diff --git a/templates/nextjs-minimal/app/api/files/view/route.ts b/templates/nextjs-minimal/app/api/files/view/route.ts new file mode 100644 index 000000000..82568f986 --- /dev/null +++ b/templates/nextjs-minimal/app/api/files/view/route.ts @@ -0,0 +1,55 @@ +import { NextResponse } from "next/server"; +import { CorePermission } from "@hackkit/core"; +import { getAuthSession } from "@/lib/auth"; +import { getBlobStorage } from "@/lib/blob"; +import { getRuntime } from "@/lib/runtime"; + +function storedFileReferenceForKey(key: string): string { + return `/api/files/view?key=${encodeURIComponent(key)}`; +} + +async function canViewFile(key: string): Promise { + if (key.startsWith("profile-photos/")) return true; + + const session = await getAuthSession(); + if (!session) return false; + + const runtime = await getRuntime(); + const currentUser = await runtime.getCurrentUser(); + const hacker = await runtime.hackkit.hackers.getHacker(currentUser.id); + if (hacker?.resumeUrl === storedFileReferenceForKey(key)) return true; + + return runtime.hackkit.accessControl.hasPermission( + currentUser.id, + CorePermission.HackersView, + ); +} + +export async function GET(request: Request): Promise { + const url = new URL(request.url); + const key = url.searchParams.get("key"); + if (!key) { + return NextResponse.json({ error: "key is required" }, { status: 400 }); + } + if (!key.startsWith("resumes/") && !key.startsWith("profile-photos/")) { + return NextResponse.json({ error: "Not found" }, { status: 404 }); + } + if (!(await canViewFile(key))) { + return NextResponse.json({ error: "Unauthorized" }, { status: 401 }); + } + + const storage = getBlobStorage(); + + const result = await storage.readObject({ key }); + if (!result) + return NextResponse.json({ error: "Not found" }, { status: 404 }); + const body = + result.body instanceof Uint8Array + ? Uint8Array.from(result.body).buffer + : await new Response(result.body).arrayBuffer(); + return new NextResponse(body, { + headers: { + "Content-Type": result.contentType ?? "application/octet-stream", + }, + }); +} diff --git a/templates/nextjs-minimal/app/api/hackkit/[...path]/route.ts b/templates/nextjs-minimal/app/api/hackkit/[...path]/route.ts new file mode 100644 index 000000000..7584eab06 --- /dev/null +++ b/templates/nextjs-minimal/app/api/hackkit/[...path]/route.ts @@ -0,0 +1,4 @@ +import { handleHackkitRequest } from "@/lib/runtime"; +export const runtime = "nodejs"; +export const dynamic = "force-dynamic"; +export const POST = handleHackkitRequest; diff --git a/templates/nextjs-minimal/app/app-bar.tsx b/templates/nextjs-minimal/app/app-bar.tsx new file mode 100644 index 000000000..8586046f1 --- /dev/null +++ b/templates/nextjs-minimal/app/app-bar.tsx @@ -0,0 +1,79 @@ +import Link from "next/link"; +import { CorePermission } from "@hackkit/core"; +import { getAuthSession } from "@/lib/auth"; +import { getCurrentUser, getRuntime } from "@/lib/runtime"; +import { publicSiteConfig } from "@/lib/public-site-config"; +import { ProfileMenu } from "./profile-menu"; + +async function getIsAdmin(authId: string) { + const runtime = await getRuntime(); + return runtime.hackkit.accessControl.hasPermission( + authId, + CorePermission.Admin, + ); +} + +export async function AppBar() { + const session = await getAuthSession(); + const currentUser = session ? await getCurrentUser() : null; + const isAdmin = currentUser ? await getIsAdmin(currentUser.id) : false; + + return ( +
+
+ + {publicSiteConfig.brand.shortName} + + {session ? ( + + ) : ( +
+ {publicSiteConfig.nav.public.map((item) => ( + + {item.label} + + ))} + + Sign in + + + {publicSiteConfig.landing.primaryAction.label} + +
+ )} +
+
+ ); +} diff --git a/templates/nextjs-minimal/app/contact/page.tsx b/templates/nextjs-minimal/app/contact/page.tsx new file mode 100644 index 000000000..dbc3d35d1 --- /dev/null +++ b/templates/nextjs-minimal/app/contact/page.tsx @@ -0,0 +1 @@ +export { default } from "../help/page"; diff --git a/templates/nextjs-minimal/app/dashboard/layout.tsx b/templates/nextjs-minimal/app/dashboard/layout.tsx new file mode 100644 index 000000000..fb92bcda9 --- /dev/null +++ b/templates/nextjs-minimal/app/dashboard/layout.tsx @@ -0,0 +1 @@ +export { default, dynamic } from "../participant-layout"; diff --git a/templates/nextjs-minimal/app/dashboard/page.tsx b/templates/nextjs-minimal/app/dashboard/page.tsx new file mode 100644 index 000000000..15ec73fe2 --- /dev/null +++ b/templates/nextjs-minimal/app/dashboard/page.tsx @@ -0,0 +1,68 @@ +import { + CompetitorOnboardingProgress, + ParticipantDashboard, +} from "@hackkit/ui"; +import { publicSiteConfig } from "@/lib/public-site-config"; +import { getHackkit } from "@/lib/runtime"; +import { + getCompetitorOnboardingState, + getRequireApproval, +} from "@/lib/onboarding"; + +export const dynamic = "force-dynamic"; + +export default async function DashboardPage() { + const { + steps, + nextHref, + user: currentUser, + userData, + hacker, + } = await getCompetitorOnboardingState("/dashboard"); + const [hackkit, requireApproval] = await Promise.all([ + getHackkit(), + getRequireApproval(), + ]); + const role = currentUser.roleId + ? await hackkit.roles.getRole(currentUser.roleId) + : null; + const participantName = + currentUser.name || currentUser.hackTag || "participant"; + + return ( + + ), + } + : undefined + } + /> + ); +} diff --git a/templates/nextjs-minimal/app/globals.css b/templates/nextjs-minimal/app/globals.css new file mode 100644 index 000000000..e0ea2ecce --- /dev/null +++ b/templates/nextjs-minimal/app/globals.css @@ -0,0 +1,58 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +@layer base { + :root { + --background: 0 0% 100%; + --foreground: 222.2 84% 4.9%; + --card: 0 0% 100%; + --card-foreground: 222.2 84% 4.9%; + --popover: 0 0% 100%; + --popover-foreground: 222.2 84% 4.9%; + --primary: 221.2 83.2% 53.3%; + --primary-foreground: 210 40% 98%; + --secondary: 210 40% 96.1%; + --secondary-foreground: 222.2 47.4% 11.2%; + --muted: 210 40% 96.1%; + --muted-foreground: 215.4 16.3% 46.9%; + --accent: 210 40% 96.1%; + --accent-foreground: 222.2 47.4% 11.2%; + --destructive: 0 84.2% 60.2%; + --destructive-foreground: 210 40% 98%; + --border: 214.3 31.8% 91.4%; + --input: 214.3 31.8% 91.4%; + --ring: 221.2 83.2% 53.3%; + --radius: 0.5rem; + } + + .dark { + --background: 222.2 84% 4.9%; + --foreground: 210 40% 98%; + --card: 222.2 84% 4.9%; + --card-foreground: 210 40% 98%; + --popover: 222.2 84% 4.9%; + --popover-foreground: 210 40% 98%; + --primary: 217.2 91.2% 59.8%; + --primary-foreground: 222.2 47.4% 11.2%; + --secondary: 217.2 32.6% 17.5%; + --secondary-foreground: 210 40% 98%; + --muted: 217.2 32.6% 17.5%; + --muted-foreground: 215 20.2% 65.1%; + --accent: 217.2 32.6% 17.5%; + --accent-foreground: 210 40% 98%; + --destructive: 0 62.8% 30.6%; + --destructive-foreground: 210 40% 98%; + --border: 217.2 32.6% 17.5%; + --input: 217.2 32.6% 17.5%; + --ring: 224.3 76.3% 48%; + } + + * { + @apply border-border; + } + + body { + @apply bg-background text-foreground; + } +} diff --git a/templates/nextjs-minimal/app/help/page.tsx b/templates/nextjs-minimal/app/help/page.tsx new file mode 100644 index 000000000..4876f845d --- /dev/null +++ b/templates/nextjs-minimal/app/help/page.tsx @@ -0,0 +1,13 @@ +import { PublicHelpPage } from "@hackkit/ui"; +import { publicSiteConfig } from "@/lib/public-site-config"; + +export default function HelpPage() { + return ( + + ); +} diff --git a/templates/nextjs-minimal/app/i/approval/layout.tsx b/templates/nextjs-minimal/app/i/approval/layout.tsx new file mode 100644 index 000000000..6e9c3af0d --- /dev/null +++ b/templates/nextjs-minimal/app/i/approval/layout.tsx @@ -0,0 +1,14 @@ +import type * as React from "react"; +import { getPageGuards } from "@/lib/runtime"; + +export const dynamic = "force-dynamic"; + +export default async function ApprovalLayout({ + children, +}: { + children: React.ReactNode; +}) { + const guards = await getPageGuards(); + await guards.requireApprovalPendingAccess(); + return children; +} diff --git a/templates/nextjs-minimal/app/i/approval/page.tsx b/templates/nextjs-minimal/app/i/approval/page.tsx new file mode 100644 index 000000000..d17b19d1b --- /dev/null +++ b/templates/nextjs-minimal/app/i/approval/page.tsx @@ -0,0 +1,26 @@ +import Link from "next/link"; + +export default function ApprovalPendingPage() { + return ( +
+
+

+ Registration received +

+

+ Your account is awaiting approval. +

+

+ Organizers are reviewing your registration. Once approved, + you can access participant dashboard and profile settings. +

+ + Back to dashboard + +
+
+ ); +} diff --git a/templates/nextjs-minimal/app/layout.tsx b/templates/nextjs-minimal/app/layout.tsx new file mode 100644 index 000000000..526d48b13 --- /dev/null +++ b/templates/nextjs-minimal/app/layout.tsx @@ -0,0 +1,38 @@ +import type * as React from "react"; +import type { Metadata } from "next"; +import { PublicSiteFooter } from "@hackkit/ui"; +import { + getPublicThemeStyle, + publicSiteConfig, +} from "@/lib/public-site-config"; +import "./globals.css"; +import { AppBar } from "./app-bar"; +import { Providers } from "./providers"; + +export const metadata: Metadata = { + title: publicSiteConfig.brand.name, + description: publicSiteConfig.brand.description, +}; + +export default function RootLayout({ + children, +}: { + children: React.ReactNode; +}) { + return ( + + + + + {children} + + + + + ); +} diff --git a/templates/nextjs-minimal/app/onboarding/hacker/hacker-form-defaults.ts b/templates/nextjs-minimal/app/onboarding/hacker/hacker-form-defaults.ts new file mode 100644 index 000000000..edd46c9ef --- /dev/null +++ b/templates/nextjs-minimal/app/onboarding/hacker/hacker-form-defaults.ts @@ -0,0 +1,18 @@ +import type { Hacker } from "@hackkit/core"; + +export function toHackerFormDefaults(hacker: Hacker | null) { + if (!hacker) return undefined; + return { + university: hacker.university, + major: hacker.major, + schoolId: hacker.schoolId ?? undefined, + levelOfStudy: hacker.levelOfStudy, + hackathonsAttended: hacker.hackathonsAttended, + softwareExperience: hacker.softwareExperience, + heardFrom: hacker.heardFrom ?? undefined, + githubUrl: hacker.githubUrl ?? undefined, + linkedInUrl: hacker.linkedInUrl ?? undefined, + personalWebsiteUrl: hacker.personalWebsiteUrl ?? undefined, + resumeUrl: hacker.resumeUrl ?? undefined, + }; +} diff --git a/templates/nextjs-minimal/app/onboarding/hacker/hacker-registration-client.tsx b/templates/nextjs-minimal/app/onboarding/hacker/hacker-registration-client.tsx new file mode 100644 index 000000000..1cb6ab6fb --- /dev/null +++ b/templates/nextjs-minimal/app/onboarding/hacker/hacker-registration-client.tsx @@ -0,0 +1,45 @@ +"use client"; + +import { HackerRegistrationForm } from "@hackkit/ui"; +import type { User } from "@hackkit/core"; +import type { HackerRegistrationOptions } from "@hackkit/config"; +import { uploadResumeFile } from "@/lib/upload-resume"; + +export function HackerRegistrationClient({ + currentUser, + defaultValues, + registrationOptions, + successRedirectTo = "/dashboard", +}: { + currentUser: User; + defaultValues?: Partial<{ + university: string; + major: string; + schoolId?: string; + levelOfStudy: string; + hackathonsAttended: number; + softwareExperience: string; + heardFrom?: string; + githubUrl?: string; + linkedInUrl?: string; + personalWebsiteUrl?: string; + resumeUrl?: string; + }>; + registrationOptions?: HackerRegistrationOptions; + successRedirectTo?: string; +}) { + return ( + + ); +} diff --git a/templates/nextjs-minimal/app/onboarding/hacker/page.tsx b/templates/nextjs-minimal/app/onboarding/hacker/page.tsx new file mode 100644 index 000000000..c05b57516 --- /dev/null +++ b/templates/nextjs-minimal/app/onboarding/hacker/page.tsx @@ -0,0 +1,40 @@ +import { redirect } from "next/navigation"; +import { getCurrentUser, getHackkit, getPageGuards } from "@/lib/runtime"; +import { appConfig } from "@/lib/app-config"; +import { getOnboardingSteps } from "@/lib/onboarding"; +import { OnboardingShell } from "../onboarding-shell"; +import { HackerRegistrationClient } from "./hacker-registration-client"; +import { toHackerFormDefaults } from "./hacker-form-defaults"; + +export const dynamic = "force-dynamic"; + +export default async function HackerOnboardingPage() { + await (await getPageGuards()).requireHackerRegistrationOpenForNewHacker(); + const currentUser = await getCurrentUser(); + if (!currentUser.hackTag) { + redirect("/onboarding/hacktag"); + } + + const hackkit = await getHackkit(); + const userData = await hackkit.userData.getUserData(currentUser.id); + if (!userData) { + redirect("/onboarding/user-data"); + } + + const hacker = await hackkit.hackers.getHacker(currentUser.id); + const steps = await getOnboardingSteps("/onboarding/hacker"); + + return ( + + + + ); +} diff --git a/templates/nextjs-minimal/app/onboarding/hacktag/page.tsx b/templates/nextjs-minimal/app/onboarding/hacktag/page.tsx new file mode 100644 index 000000000..7c98a15d4 --- /dev/null +++ b/templates/nextjs-minimal/app/onboarding/hacktag/page.tsx @@ -0,0 +1,30 @@ +import { HackTagForm } from "@hackkit/ui"; +import { getCurrentUser } from "@/lib/runtime"; +import { getOnboardingSteps } from "@/lib/onboarding"; +import { OnboardingShell } from "../onboarding-shell"; + +export const dynamic = "force-dynamic"; + +export default async function HackTagOnboardingPage() { + const currentUser = await getCurrentUser(); + const steps = await getOnboardingSteps("/onboarding/hacktag"); + + return ( + + + + ); +} diff --git a/templates/nextjs-minimal/app/onboarding/layout.tsx b/templates/nextjs-minimal/app/onboarding/layout.tsx new file mode 100644 index 000000000..b2898f3bb --- /dev/null +++ b/templates/nextjs-minimal/app/onboarding/layout.tsx @@ -0,0 +1,14 @@ +import type * as React from "react"; +import { getPageGuards } from "@/lib/runtime"; + +export const dynamic = "force-dynamic"; + +export default async function OnboardingLayout({ + children, +}: { + children: React.ReactNode; +}) { + const guards = await getPageGuards(); + await guards.requireOnboardingAccess(); + return children; +} diff --git a/templates/nextjs-minimal/app/onboarding/onboarding-shell.tsx b/templates/nextjs-minimal/app/onboarding/onboarding-shell.tsx new file mode 100644 index 000000000..5196fa8aa --- /dev/null +++ b/templates/nextjs-minimal/app/onboarding/onboarding-shell.tsx @@ -0,0 +1,35 @@ +import { + CompetitorOnboardingProgress, + type CompetitorOnboardingStep, +} from "@hackkit/ui"; +import type * as React from "react"; + +export function OnboardingShell({ + steps, + title, + description, + children, +}: { + steps: CompetitorOnboardingStep[]; + title: string; + description: string; + children: React.ReactNode; +}) { + return ( +
+
+
+

+ Competitor onboarding +

+

+ {title} +

+

{description}

+
+ + {children} +
+
+ ); +} diff --git a/templates/nextjs-minimal/app/onboarding/user-data/page.tsx b/templates/nextjs-minimal/app/onboarding/user-data/page.tsx new file mode 100644 index 000000000..394f5136b --- /dev/null +++ b/templates/nextjs-minimal/app/onboarding/user-data/page.tsx @@ -0,0 +1,38 @@ +import { UserDataForm, toUserDataFormDefaultValues } from "@hackkit/ui"; +import { redirect } from "next/navigation"; +import { getCurrentUser, getHackkit } from "@/lib/runtime"; +import { getOnboardingSteps } from "@/lib/onboarding"; +import { OnboardingShell } from "../onboarding-shell"; + +export const dynamic = "force-dynamic"; + +export default async function UserDataOnboardingPage() { + const currentUser = await getCurrentUser(); + if (!currentUser.hackTag) { + redirect("/onboarding/hacktag"); + } + + const hackkit = await getHackkit(); + const existingUserData = await hackkit.userData.getUserData(currentUser.id); + const steps = await getOnboardingSteps("/onboarding/user-data"); + + return ( + + + + ); +} diff --git a/templates/nextjs-minimal/app/page.tsx b/templates/nextjs-minimal/app/page.tsx new file mode 100644 index 000000000..a5682ee66 --- /dev/null +++ b/templates/nextjs-minimal/app/page.tsx @@ -0,0 +1,17 @@ +import { PublicLandingPage } from "@hackkit/ui"; +import { getAuthSession } from "@/lib/auth"; +import { publicSiteConfig } from "@/lib/public-site-config"; + +export const dynamic = "force-dynamic"; + +export default async function HomePage() { + const session = await getAuthSession(); + const { signedInAction, ...landing } = publicSiteConfig.landing; + + return ( + + ); +} diff --git a/templates/nextjs-minimal/app/participant-layout.tsx b/templates/nextjs-minimal/app/participant-layout.tsx new file mode 100644 index 000000000..09ccadc7a --- /dev/null +++ b/templates/nextjs-minimal/app/participant-layout.tsx @@ -0,0 +1,14 @@ +import type * as React from "react"; +import { getPageGuards } from "@/lib/runtime"; + +export const dynamic = "force-dynamic"; + +export default async function ParticipantLayout({ + children, +}: { + children: React.ReactNode; +}) { + const guards = await getPageGuards(); + await guards.requireParticipantAccess(); + return children; +} diff --git a/templates/nextjs-minimal/app/profile-menu.tsx b/templates/nextjs-minimal/app/profile-menu.tsx new file mode 100644 index 000000000..25c01ee34 --- /dev/null +++ b/templates/nextjs-minimal/app/profile-menu.tsx @@ -0,0 +1,116 @@ +"use client"; + +import { useState } from "react"; +import Link from "next/link"; +import { useRouter } from "next/navigation"; +import { authClient } from "@/lib/auth-client"; + +export function ProfileMenu({ + name, + email, + image, + isAdmin = false, +}: { + name: string; + email: string; + image?: string | null; + isAdmin?: boolean; +}) { + const router = useRouter(); + const [isOpen, setIsOpen] = useState(false); + const [isSigningOut, setIsSigningOut] = useState(false); + const initials = + name + .split(/\s+/) + .filter(Boolean) + .slice(0, 2) + .map((part) => part[0]?.toUpperCase()) + .join("") || "U"; + + async function signOut() { + setIsSigningOut(true); + await authClient.signOut(); + router.push("/sign-in"); + router.refresh(); + } + + return ( +
+ + + {isOpen ? ( +
+
+

{name}

+

+ {email} +

+
+
+ setIsOpen(false)} + className="block rounded-md px-3 py-2 text-sm hover:bg-muted" + > + Settings + + setIsOpen(false)} + className="block rounded-md px-3 py-2 text-sm hover:bg-muted" + > + Registration + + {isAdmin ? ( + setIsOpen(false)} + className="block rounded-md px-3 py-2 text-sm text-accent-foreground hover:bg-muted" + > + Admin + + ) : null} + +
+
+ ) : null} +
+ ); +} diff --git a/templates/nextjs-minimal/app/providers.tsx b/templates/nextjs-minimal/app/providers.tsx new file mode 100644 index 000000000..35d6da071 --- /dev/null +++ b/templates/nextjs-minimal/app/providers.tsx @@ -0,0 +1,12 @@ +"use client"; +import { HackKitUIProvider } from "@hackkit/ui"; +import { createHackkitClient } from "@hackkit/core/http/client"; +import type * as React from "react"; + +const hackkitClient = createHackkitClient(); + +export function Providers({ children }: { children: React.ReactNode }) { + return ( + {children} + ); +} diff --git a/templates/nextjs-minimal/app/register/page.tsx b/templates/nextjs-minimal/app/register/page.tsx new file mode 100644 index 000000000..ad808fca8 --- /dev/null +++ b/templates/nextjs-minimal/app/register/page.tsx @@ -0,0 +1,5 @@ +import { redirect } from "next/navigation"; + +export default function RegisterRedirectPage() { + redirect("/onboarding/user-data"); +} diff --git a/templates/nextjs-minimal/app/registration-closed/page.tsx b/templates/nextjs-minimal/app/registration-closed/page.tsx new file mode 100644 index 000000000..c11572fac --- /dev/null +++ b/templates/nextjs-minimal/app/registration-closed/page.tsx @@ -0,0 +1,26 @@ +import Link from "next/link"; + +export default function RegistrationClosedPage() { + return ( +
+
+

+ Registration closed +

+

+ New hacker registrations are closed. +

+

+ If you have already started registration, sign in to check + your current status or contact the organizing team. +

+ + Go to dashboard + +
+
+ ); +} diff --git a/templates/nextjs-minimal/app/settings/layout.tsx b/templates/nextjs-minimal/app/settings/layout.tsx new file mode 100644 index 000000000..fb92bcda9 --- /dev/null +++ b/templates/nextjs-minimal/app/settings/layout.tsx @@ -0,0 +1 @@ +export { default, dynamic } from "../participant-layout"; diff --git a/templates/nextjs-minimal/app/settings/page.tsx b/templates/nextjs-minimal/app/settings/page.tsx new file mode 100644 index 000000000..a2c9193e7 --- /dev/null +++ b/templates/nextjs-minimal/app/settings/page.tsx @@ -0,0 +1,36 @@ +import Link from "next/link"; +import { getCurrentUser } from "@/lib/runtime"; +import { ProfileSettingsClient } from "./profile-settings-client"; + +export const dynamic = "force-dynamic"; + +export default async function SettingsPage() { + const currentUser = await getCurrentUser(); + + return ( +
+
+

Settings

+

+ Manage your account profile and public HackKit profile. +

+
+ + + +
+

Registration

+

+ You can update your demographic, logistics, school, + experience, and resume information after registration. +

+ + Edit registration + +
+
+ ); +} diff --git a/templates/nextjs-minimal/app/settings/profile-settings-client.tsx b/templates/nextjs-minimal/app/settings/profile-settings-client.tsx new file mode 100644 index 000000000..12e089aa4 --- /dev/null +++ b/templates/nextjs-minimal/app/settings/profile-settings-client.tsx @@ -0,0 +1,15 @@ +"use client"; + +import { UserProfileSettingsForm } from "@hackkit/ui"; +import type { User } from "@hackkit/core"; +import { uploadProfilePhotoFile } from "@/lib/upload-profile-photo"; + +export function ProfileSettingsClient({ currentUser }: { currentUser: User }) { + return ( + + ); +} diff --git a/templates/nextjs-minimal/app/settings/registration/page.tsx b/templates/nextjs-minimal/app/settings/registration/page.tsx new file mode 100644 index 000000000..f72c69355 --- /dev/null +++ b/templates/nextjs-minimal/app/settings/registration/page.tsx @@ -0,0 +1,54 @@ +import Link from "next/link"; +import { UserDataForm, toUserDataFormDefaultValues } from "@hackkit/ui"; +import { getCurrentUser, getHackkit } from "@/lib/runtime"; +import { appConfig } from "@/lib/app-config"; +import { toHackerFormDefaults } from "@/app/onboarding/hacker/hacker-form-defaults"; +import { HackerRegistrationClient } from "@/app/onboarding/hacker/hacker-registration-client"; + +export const dynamic = "force-dynamic"; + +export default async function RegistrationSettingsPage() { + const currentUser = await getCurrentUser(); + const hackkit = await getHackkit(); + const [userData, hacker] = await Promise.all([ + hackkit.userData.getUserData(currentUser.id), + hackkit.hackers.getHacker(currentUser.id), + ]); + + return ( +
+
+ + Back to settings + +

+ Registration Settings +

+

+ Update registration details that organizers use for + logistics and participant review. +

+
+ + + + +
+ ); +} diff --git a/templates/nextjs-minimal/app/sign-in/auth-form.tsx b/templates/nextjs-minimal/app/sign-in/auth-form.tsx new file mode 100644 index 000000000..aad59d2f0 --- /dev/null +++ b/templates/nextjs-minimal/app/sign-in/auth-form.tsx @@ -0,0 +1,100 @@ +"use client"; + +import { useState, type FormEvent } from "react"; +import Link from "next/link"; +import { useRouter } from "next/navigation"; +import { authClient } from "@/lib/auth-client"; + +type AuthMode = "sign-in" | "sign-up"; + +export function AuthForm({ mode }: { mode: AuthMode }) { + const router = useRouter(); + const [error, setError] = useState(null); + const [isPending, setIsPending] = useState(false); + const isSignUp = mode === "sign-up"; + + async function onSubmit(event: FormEvent) { + event.preventDefault(); + setError(null); + setIsPending(true); + + const form = new FormData(event.currentTarget); + const email = String(form.get("email") ?? ""); + const password = String(form.get("password") ?? ""); + const name = String(form.get("name") ?? email); + + const result = isSignUp + ? await authClient.signUp.email({ email, password, name }) + : await authClient.signIn.email({ email, password }); + + setIsPending(false); + + if (result.error) { + setError(result.error.message ?? "Authentication failed."); + return; + } + + router.push(isSignUp ? "/register" : "/"); + router.refresh(); + } + + return ( +
+ {isSignUp ? ( + + ) : null} + + + {error ?

{error}

: null} + + + {isSignUp + ? "Have an account? Sign in" + : "Need an account? Sign up"} + +
+ ); +} diff --git a/templates/nextjs-minimal/app/sign-in/page.tsx b/templates/nextjs-minimal/app/sign-in/page.tsx new file mode 100644 index 000000000..03f759629 --- /dev/null +++ b/templates/nextjs-minimal/app/sign-in/page.tsx @@ -0,0 +1,24 @@ +import { redirect } from "next/navigation"; +import { getAuthSession } from "@/lib/auth"; +import { AuthForm } from "./auth-form"; + +export const dynamic = "force-dynamic"; + +export default async function SignInPage() { + const session = await getAuthSession(); + if (session) redirect("/"); + + return ( +
+
+
+

HackKit

+

+ Sign in +

+
+ +
+
+ ); +} diff --git a/templates/nextjs-minimal/app/sign-up/page.tsx b/templates/nextjs-minimal/app/sign-up/page.tsx new file mode 100644 index 000000000..d43a22eeb --- /dev/null +++ b/templates/nextjs-minimal/app/sign-up/page.tsx @@ -0,0 +1,27 @@ +import { redirect } from "next/navigation"; +import { getAuthSession } from "@/lib/auth"; +import { AuthForm } from "../sign-in/auth-form"; + +export const dynamic = "force-dynamic"; + +export default async function SignUpPage() { + const session = await getAuthSession(); + if (session) redirect("/onboarding/hacktag"); + + return ( +
+
+
+

HackKit

+

+ Sign up +

+

+ Create an account, then complete registration. +

+
+ +
+
+ ); +} diff --git a/templates/nextjs-minimal/app/suspended/page.tsx b/templates/nextjs-minimal/app/suspended/page.tsx new file mode 100644 index 000000000..694e510f8 --- /dev/null +++ b/templates/nextjs-minimal/app/suspended/page.tsx @@ -0,0 +1,18 @@ +export default function SuspendedPage() { + return ( +
+
+

+ Account suspended +

+

+ Your access to this HackKit app is suspended. +

+

+ If you think this is a mistake, contact the organizing team + for help. +

+
+
+ ); +} diff --git a/templates/nextjs-minimal/app/user/[tag]/page.tsx b/templates/nextjs-minimal/app/user/[tag]/page.tsx new file mode 100644 index 000000000..7777572a7 --- /dev/null +++ b/templates/nextjs-minimal/app/user/[tag]/page.tsx @@ -0,0 +1,23 @@ +import { notFound } from "next/navigation"; +import { PublicProfileCard } from "@hackkit/ui"; +import { getHackkit } from "@/lib/runtime"; + +export const dynamic = "force-dynamic"; + +export default async function PublicUserProfilePage({ + params, +}: { + params: { tag: string }; +}) { + const tag = decodeURIComponent(params.tag); + const profile = await ( + await getHackkit() + ).users.getPublicProfileByHackTag(tag); + if (!profile) notFound(); + + return ( +
+ +
+ ); +} diff --git a/templates/nextjs-minimal/db/migrations/sqlite/.snapshot.json b/templates/nextjs-minimal/db/migrations/sqlite/.snapshot.json new file mode 100644 index 000000000..371c01ff6 --- /dev/null +++ b/templates/nextjs-minimal/db/migrations/sqlite/.snapshot.json @@ -0,0 +1,3334 @@ +{ + "namespaces": [], + "tables": [ + { + "name": "account", + "columns": { + "access_token": { + "name": "access_token", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "access_token_expires_at": { + "name": "access_token_expires_at", + "type": "datetime", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "datetime" + }, + "account_id": { + "name": "account_id", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "created_at": { + "name": "created_at", + "type": "datetime", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "datetime" + }, + "id": { + "name": "id", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": true, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "id_token": { + "name": "id_token", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "password": { + "name": "password", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "provider_id": { + "name": "provider_id", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "refresh_token": { + "name": "refresh_token", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "refresh_token_expires_at": { + "name": "refresh_token_expires_at", + "type": "datetime", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "datetime" + }, + "scope": { + "name": "scope", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "updated_at": { + "name": "updated_at", + "type": "datetime", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "datetime" + }, + "user_id": { + "name": "user_id", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + } + }, + "indexes": [ + { + "columnNames": [ + "user_id" + ], + "composite": false, + "constraint": false, + "keyName": "account_user_id_index", + "primary": false, + "unique": false + }, + { + "columnNames": [ + "id" + ], + "composite": false, + "constraint": true, + "keyName": "primary", + "primary": true, + "unique": true + } + ], + "checks": [], + "triggers": [], + "foreignKeys": { + "account_user_id_foreign": { + "columnNames": [ + "user_id" + ], + "constraintName": "account_user_id_foreign", + "localTableName": "account", + "referencedColumnNames": [ + "id" + ], + "referencedTableName": "core_user", + "deleteRule": "cascade" + } + }, + "comment": null + }, + { + "name": "core_event", + "columns": { + "created_at": { + "name": "created_at", + "type": "datetime", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "datetime" + }, + "description": { + "name": "description", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "end_time": { + "name": "end_time", + "type": "datetime", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "datetime" + }, + "hidden": { + "name": "hidden", + "type": "integer", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": "false", + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "integer" + }, + "host": { + "name": "host", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "id": { + "name": "id", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": true, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "location": { + "name": "location", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": "'TBD'", + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "start_time": { + "name": "start_time", + "type": "datetime", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "datetime" + }, + "title": { + "name": "title", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "type": { + "name": "type", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "updated_at": { + "name": "updated_at", + "type": "datetime", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "datetime" + } + }, + "indexes": [ + { + "columnNames": [ + "hidden" + ], + "composite": false, + "constraint": false, + "keyName": "core_event_hidden_index", + "primary": false, + "unique": false + }, + { + "columnNames": [ + "start_time" + ], + "composite": false, + "constraint": false, + "keyName": "core_event_start_time_index", + "primary": false, + "unique": false + }, + { + "columnNames": [ + "type" + ], + "composite": false, + "constraint": false, + "keyName": "core_event_type_index", + "primary": false, + "unique": false + }, + { + "columnNames": [ + "id" + ], + "composite": false, + "constraint": true, + "keyName": "primary", + "primary": true, + "unique": true + } + ], + "checks": [], + "triggers": [], + "foreignKeys": {}, + "comment": null + }, + { + "name": "core_event_scan", + "columns": { + "auth_id": { + "name": "auth_id", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "event_id": { + "name": "event_id", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "id": { + "name": "id", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": true, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "scanned_at": { + "name": "scanned_at", + "type": "datetime", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "datetime" + }, + "scanned_by_auth_id": { + "name": "scanned_by_auth_id", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + } + }, + "indexes": [ + { + "columnNames": [ + "auth_id" + ], + "composite": false, + "constraint": false, + "keyName": "core_event_scan_auth_id_index", + "primary": false, + "unique": false + }, + { + "columnNames": [ + "event_id", + "auth_id" + ], + "composite": true, + "constraint": false, + "keyName": "core_event_scan_event_id_auth_id_index", + "primary": false, + "unique": false + }, + { + "columnNames": [ + "event_id" + ], + "composite": false, + "constraint": false, + "keyName": "core_event_scan_event_id_index", + "primary": false, + "unique": false + }, + { + "columnNames": [ + "scanned_at" + ], + "composite": false, + "constraint": false, + "keyName": "core_event_scan_scanned_at_index", + "primary": false, + "unique": false + }, + { + "columnNames": [ + "scanned_by_auth_id" + ], + "composite": false, + "constraint": false, + "keyName": "core_event_scan_scanned_by_auth_id_index", + "primary": false, + "unique": false + }, + { + "columnNames": [ + "id" + ], + "composite": false, + "constraint": true, + "keyName": "primary", + "primary": true, + "unique": true + } + ], + "checks": [], + "triggers": [], + "foreignKeys": { + "core_event_scan_auth_id_foreign": { + "columnNames": [ + "auth_id" + ], + "constraintName": "core_event_scan_auth_id_foreign", + "localTableName": "core_event_scan", + "referencedColumnNames": [ + "id" + ], + "referencedTableName": "core_user", + "deleteRule": "cascade" + }, + "core_event_scan_event_id_foreign": { + "columnNames": [ + "event_id" + ], + "constraintName": "core_event_scan_event_id_foreign", + "localTableName": "core_event_scan", + "referencedColumnNames": [ + "id" + ], + "referencedTableName": "core_event", + "deleteRule": "cascade" + }, + "core_event_scan_scanned_by_auth_id_foreign": { + "columnNames": [ + "scanned_by_auth_id" + ], + "constraintName": "core_event_scan_scanned_by_auth_id_foreign", + "localTableName": "core_event_scan", + "referencedColumnNames": [ + "id" + ], + "referencedTableName": "core_user" + } + }, + "comment": null + }, + { + "name": "core_hacker", + "columns": { + "auth_id": { + "name": "auth_id", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": true, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "github_url": { + "name": "github_url", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "group": { + "name": "group", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "hackathons_attended": { + "name": "hackathons_attended", + "type": "integer", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "integer" + }, + "heard_from": { + "name": "heard_from", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "level_of_study": { + "name": "level_of_study", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "linked_in_url": { + "name": "linked_in_url", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "major": { + "name": "major", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "personal_website_url": { + "name": "personal_website_url", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "registered_at": { + "name": "registered_at", + "type": "datetime", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "datetime" + }, + "resume_url": { + "name": "resume_url", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "school_id": { + "name": "school_id", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "software_experience": { + "name": "software_experience", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "university": { + "name": "university", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "updated_at": { + "name": "updated_at", + "type": "datetime", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "datetime" + } + }, + "indexes": [ + { + "columnNames": [ + "auth_id" + ], + "composite": false, + "constraint": false, + "keyName": "core_hacker_auth_id_index", + "primary": false, + "unique": false + }, + { + "columnNames": [ + "registered_at" + ], + "composite": false, + "constraint": false, + "keyName": "core_hacker_registered_at_index", + "primary": false, + "unique": false + }, + { + "columnNames": [ + "auth_id" + ], + "composite": false, + "constraint": true, + "keyName": "primary", + "primary": true, + "unique": true + } + ], + "checks": [], + "triggers": [], + "foreignKeys": { + "core_hacker_auth_id_foreign": { + "columnNames": [ + "auth_id" + ], + "constraintName": "core_hacker_auth_id_foreign", + "localTableName": "core_hacker", + "referencedColumnNames": [ + "id" + ], + "referencedTableName": "core_user", + "updateRule": "cascade", + "deleteRule": "cascade" + } + }, + "comment": null + }, + { + "name": "core_notification_delivery_attempt", + "columns": { + "attempted_at": { + "name": "attempted_at", + "type": "datetime", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "datetime" + }, + "channel": { + "name": "channel", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "error": { + "name": "error", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "external_id": { + "name": "external_id", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "id": { + "name": "id", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": true, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "intent_id": { + "name": "intent_id", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "metadata": { + "name": "metadata", + "type": "json", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "json" + }, + "provider": { + "name": "provider", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "recipient": { + "name": "recipient", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "status": { + "name": "status", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [ + "delivered", + "failed", + "skipped" + ], + "mappedType": "enum" + } + }, + "indexes": [ + { + "columnNames": [ + "attempted_at" + ], + "composite": false, + "constraint": false, + "keyName": "core_notification_delivery_attempt_attempted_at_index", + "primary": false, + "unique": false + }, + { + "columnNames": [ + "channel" + ], + "composite": false, + "constraint": false, + "keyName": "core_notification_delivery_attempt_channel_index", + "primary": false, + "unique": false + }, + { + "columnNames": [ + "intent_id" + ], + "composite": false, + "constraint": false, + "keyName": "core_notification_delivery_attempt_intent_id_index", + "primary": false, + "unique": false + }, + { + "columnNames": [ + "status" + ], + "composite": false, + "constraint": false, + "keyName": "core_notification_delivery_attempt_status_index", + "primary": false, + "unique": false + }, + { + "columnNames": [ + "id" + ], + "composite": false, + "constraint": true, + "keyName": "primary", + "primary": true, + "unique": true + } + ], + "checks": [ + { + "name": "core_notification_delivery_attempt_status_check", + "expression": "`status` in ('delivered', 'failed', 'skipped')", + "definition": "check (`status` in ('delivered', 'failed', 'skipped'))", + "columnName": "status" + } + ], + "triggers": [], + "foreignKeys": { + "core_notification_delivery_attempt_intent_id_foreign": { + "columnNames": [ + "intent_id" + ], + "constraintName": "core_notification_delivery_attempt_intent_id_foreign", + "localTableName": "core_notification_delivery_attempt", + "referencedColumnNames": [ + "id" + ], + "referencedTableName": "core_notification_intent", + "deleteRule": "cascade" + } + }, + "comment": null + }, + { + "name": "core_notification_intent", + "columns": { + "created_at": { + "name": "created_at", + "type": "datetime", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "datetime" + }, + "id": { + "name": "id", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": true, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "idempotency_key": { + "name": "idempotency_key", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "unique": true, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "kind": { + "name": "kind", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "payload": { + "name": "payload", + "type": "json", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "json" + }, + "recipient_auth_id": { + "name": "recipient_auth_id", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "status": { + "name": "status", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": "'pending'", + "comment": null, + "collation": null, + "enumItems": [ + "pending", + "processing", + "delivered", + "failed", + "skipped" + ], + "mappedType": "enum" + }, + "updated_at": { + "name": "updated_at", + "type": "datetime", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "datetime" + } + }, + "indexes": [ + { + "columnNames": [ + "created_at" + ], + "composite": false, + "constraint": false, + "keyName": "core_notification_intent_created_at_index", + "primary": false, + "unique": false + }, + { + "columnNames": [ + "idempotency_key" + ], + "composite": false, + "constraint": true, + "keyName": "core_notification_intent_idempotency_key_unique", + "primary": false, + "unique": true + }, + { + "columnNames": [ + "kind" + ], + "composite": false, + "constraint": false, + "keyName": "core_notification_intent_kind_index", + "primary": false, + "unique": false + }, + { + "columnNames": [ + "recipient_auth_id" + ], + "composite": false, + "constraint": false, + "keyName": "core_notification_intent_recipient_auth_id_index", + "primary": false, + "unique": false + }, + { + "columnNames": [ + "status" + ], + "composite": false, + "constraint": false, + "keyName": "core_notification_intent_status_index", + "primary": false, + "unique": false + }, + { + "columnNames": [ + "id" + ], + "composite": false, + "constraint": true, + "keyName": "primary", + "primary": true, + "unique": true + } + ], + "checks": [ + { + "name": "core_notification_intent_status_check", + "expression": "`status` in ('pending', 'processing', 'delivered', 'failed', 'skipped')", + "definition": "check (`status` in ('pending', 'processing', 'delivered', 'failed', 'skipped'))", + "columnName": "status" + } + ], + "triggers": [], + "foreignKeys": { + "core_notification_intent_recipient_auth_id_foreign": { + "columnNames": [ + "recipient_auth_id" + ], + "constraintName": "core_notification_intent_recipient_auth_id_foreign", + "localTableName": "core_notification_intent", + "referencedColumnNames": [ + "id" + ], + "referencedTableName": "core_user", + "deleteRule": "set null" + } + }, + "comment": null + }, + { + "name": "core_operation_lock", + "columns": { + "key": { + "name": "key", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": true, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "token": { + "name": "token", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + } + }, + "indexes": [ + { + "columnNames": [ + "key" + ], + "composite": false, + "constraint": true, + "keyName": "primary", + "primary": true, + "unique": true + } + ], + "checks": [], + "triggers": [], + "foreignKeys": {}, + "comment": null + }, + { + "name": "core_role", + "columns": { + "color": { + "name": "color", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "created_at": { + "name": "created_at", + "type": "datetime", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "datetime" + }, + "id": { + "name": "id", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": true, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "name": { + "name": "name", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": true, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "permissions": { + "name": "permissions", + "type": "json", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": "'[]'", + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "json" + }, + "position": { + "name": "position", + "type": "integer", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "integer" + }, + "updated_at": { + "name": "updated_at", + "type": "datetime", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "datetime" + } + }, + "indexes": [ + { + "columnNames": [ + "name" + ], + "composite": false, + "constraint": true, + "keyName": "core_role_name_unique", + "primary": false, + "unique": true + }, + { + "columnNames": [ + "position" + ], + "composite": false, + "constraint": false, + "keyName": "core_role_position_index", + "primary": false, + "unique": false + }, + { + "columnNames": [ + "id" + ], + "composite": false, + "constraint": true, + "keyName": "primary", + "primary": true, + "unique": true + } + ], + "checks": [], + "triggers": [], + "foreignKeys": {}, + "comment": null + }, + { + "name": "core_rsvp", + "columns": { + "auth_id": { + "name": "auth_id", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": true, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "cancelled_at": { + "name": "cancelled_at", + "type": "datetime", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "datetime" + }, + "cancelled_by_auth_id": { + "name": "cancelled_by_auth_id", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "confirmed_at": { + "name": "confirmed_at", + "type": "datetime", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "datetime" + }, + "created_at": { + "name": "created_at", + "type": "datetime", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "datetime" + }, + "promoted_at": { + "name": "promoted_at", + "type": "datetime", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "datetime" + }, + "promoted_by_auth_id": { + "name": "promoted_by_auth_id", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "status": { + "name": "status", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [ + "confirmed", + "waitlisted", + "cancelled" + ], + "mappedType": "enum" + }, + "updated_at": { + "name": "updated_at", + "type": "datetime", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "datetime" + }, + "waitlist_position": { + "name": "waitlist_position", + "type": "integer", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "integer" + }, + "waitlisted_at": { + "name": "waitlisted_at", + "type": "datetime", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "datetime" + } + }, + "indexes": [ + { + "columnNames": [ + "auth_id" + ], + "composite": false, + "constraint": false, + "keyName": "core_rsvp_auth_id_index", + "primary": false, + "unique": false + }, + { + "columnNames": [ + "cancelled_by_auth_id" + ], + "composite": false, + "constraint": false, + "keyName": "core_rsvp_cancelled_by_auth_id_index", + "primary": false, + "unique": false + }, + { + "columnNames": [ + "created_at" + ], + "composite": false, + "constraint": false, + "keyName": "core_rsvp_created_at_index", + "primary": false, + "unique": false + }, + { + "columnNames": [ + "promoted_by_auth_id" + ], + "composite": false, + "constraint": false, + "keyName": "core_rsvp_promoted_by_auth_id_index", + "primary": false, + "unique": false + }, + { + "columnNames": [ + "status" + ], + "composite": false, + "constraint": false, + "keyName": "core_rsvp_status_index", + "primary": false, + "unique": false + }, + { + "columnNames": [ + "updated_at" + ], + "composite": false, + "constraint": false, + "keyName": "core_rsvp_updated_at_index", + "primary": false, + "unique": false + }, + { + "columnNames": [ + "waitlist_position" + ], + "composite": false, + "constraint": false, + "keyName": "core_rsvp_waitlist_position_index", + "primary": false, + "unique": false + }, + { + "columnNames": [ + "auth_id" + ], + "composite": false, + "constraint": true, + "keyName": "primary", + "primary": true, + "unique": true + } + ], + "checks": [ + { + "name": "core_rsvp_status_check", + "expression": "`status` in ('confirmed', 'waitlisted', 'cancelled')", + "definition": "check (`status` in ('confirmed', 'waitlisted', 'cancelled'))", + "columnName": "status" + } + ], + "triggers": [], + "foreignKeys": { + "core_rsvp_auth_id_foreign": { + "columnNames": [ + "auth_id" + ], + "constraintName": "core_rsvp_auth_id_foreign", + "localTableName": "core_rsvp", + "referencedColumnNames": [ + "id" + ], + "referencedTableName": "core_user", + "updateRule": "cascade", + "deleteRule": "cascade" + }, + "core_rsvp_cancelled_by_auth_id_foreign": { + "columnNames": [ + "cancelled_by_auth_id" + ], + "constraintName": "core_rsvp_cancelled_by_auth_id_foreign", + "localTableName": "core_rsvp", + "referencedColumnNames": [ + "id" + ], + "referencedTableName": "core_user", + "deleteRule": "set null" + }, + "core_rsvp_promoted_by_auth_id_foreign": { + "columnNames": [ + "promoted_by_auth_id" + ], + "constraintName": "core_rsvp_promoted_by_auth_id_foreign", + "localTableName": "core_rsvp", + "referencedColumnNames": [ + "id" + ], + "referencedTableName": "core_user", + "deleteRule": "set null" + } + }, + "comment": null + }, + { + "name": "core_setting", + "columns": { + "created_at": { + "name": "created_at", + "type": "datetime", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "datetime" + }, + "created_by_auth_id": { + "name": "created_by_auth_id", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "key": { + "name": "key", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": true, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "updated_at": { + "name": "updated_at", + "type": "datetime", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "datetime" + }, + "updated_by_auth_id": { + "name": "updated_by_auth_id", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "value": { + "name": "value", + "type": "json", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "json" + } + }, + "indexes": [ + { + "columnNames": [ + "created_by_auth_id" + ], + "composite": false, + "constraint": false, + "keyName": "core_setting_created_by_auth_id_index", + "primary": false, + "unique": false + }, + { + "columnNames": [ + "updated_at" + ], + "composite": false, + "constraint": false, + "keyName": "core_setting_updated_at_index", + "primary": false, + "unique": false + }, + { + "columnNames": [ + "updated_by_auth_id" + ], + "composite": false, + "constraint": false, + "keyName": "core_setting_updated_by_auth_id_index", + "primary": false, + "unique": false + }, + { + "columnNames": [ + "key" + ], + "composite": false, + "constraint": true, + "keyName": "primary", + "primary": true, + "unique": true + } + ], + "checks": [], + "triggers": [], + "foreignKeys": { + "core_setting_created_by_auth_id_foreign": { + "columnNames": [ + "created_by_auth_id" + ], + "constraintName": "core_setting_created_by_auth_id_foreign", + "localTableName": "core_setting", + "referencedColumnNames": [ + "id" + ], + "referencedTableName": "core_user", + "deleteRule": "set null" + }, + "core_setting_updated_by_auth_id_foreign": { + "columnNames": [ + "updated_by_auth_id" + ], + "constraintName": "core_setting_updated_by_auth_id_foreign", + "localTableName": "core_setting", + "referencedColumnNames": [ + "id" + ], + "referencedTableName": "core_user", + "deleteRule": "set null" + } + }, + "comment": null + }, + { + "name": "core_user", + "columns": { + "bio": { + "name": "bio", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "checked_in_at": { + "name": "checked_in_at", + "type": "datetime", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "datetime" + }, + "created_at": { + "name": "created_at", + "type": "datetime", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "datetime" + }, + "discord_display_handle": { + "name": "discord_display_handle", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "email": { + "name": "email", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": true, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "email_verified": { + "name": "email_verified", + "type": "integer", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": "false", + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "integer" + }, + "hack_tag": { + "name": "hack_tag", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "unique": true, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "id": { + "name": "id", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": true, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "is_approved": { + "name": "is_approved", + "type": "integer", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": "false", + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "integer" + }, + "is_profile_searchable": { + "name": "is_profile_searchable", + "type": "integer", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": "true", + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "integer" + }, + "name": { + "name": "name", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "profile_photo_url": { + "name": "profile_photo_url", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "pronouns": { + "name": "pronouns", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "role_id": { + "name": "role_id", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "skills": { + "name": "skills", + "type": "json", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": "'[]'", + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "json" + }, + "updated_at": { + "name": "updated_at", + "type": "datetime", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "datetime" + } + }, + "indexes": [ + { + "columnNames": [ + "created_at" + ], + "composite": false, + "constraint": false, + "keyName": "core_user_created_at_index", + "primary": false, + "unique": false + }, + { + "columnNames": [ + "email" + ], + "composite": false, + "constraint": true, + "keyName": "core_user_email_unique", + "primary": false, + "unique": true + }, + { + "columnNames": [ + "hack_tag" + ], + "composite": false, + "constraint": false, + "keyName": "core_user_hack_tag_index", + "primary": false, + "unique": false + }, + { + "columnNames": [ + "hack_tag" + ], + "composite": false, + "constraint": true, + "keyName": "core_user_hack_tag_unique", + "primary": false, + "unique": true + }, + { + "columnNames": [ + "role_id" + ], + "composite": false, + "constraint": false, + "keyName": "core_user_role_id_index", + "primary": false, + "unique": false + }, + { + "columnNames": [ + "id" + ], + "composite": false, + "constraint": true, + "keyName": "primary", + "primary": true, + "unique": true + } + ], + "checks": [], + "triggers": [], + "foreignKeys": { + "core_user_role_id_foreign": { + "columnNames": [ + "role_id" + ], + "constraintName": "core_user_role_id_foreign", + "localTableName": "core_user", + "referencedColumnNames": [ + "id" + ], + "referencedTableName": "core_role", + "deleteRule": "set null" + } + }, + "comment": null + }, + { + "name": "core_user_ban", + "columns": { + "auth_id": { + "name": "auth_id", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": true, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "banned_by_auth_id": { + "name": "banned_by_auth_id", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "created_at": { + "name": "created_at", + "type": "datetime", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "datetime" + }, + "reason": { + "name": "reason", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + } + }, + "indexes": [ + { + "columnNames": [ + "auth_id" + ], + "composite": false, + "constraint": false, + "keyName": "core_user_ban_auth_id_index", + "primary": false, + "unique": false + }, + { + "columnNames": [ + "banned_by_auth_id" + ], + "composite": false, + "constraint": false, + "keyName": "core_user_ban_banned_by_auth_id_index", + "primary": false, + "unique": false + }, + { + "columnNames": [ + "auth_id" + ], + "composite": false, + "constraint": true, + "keyName": "primary", + "primary": true, + "unique": true + } + ], + "checks": [], + "triggers": [], + "foreignKeys": { + "core_user_ban_auth_id_foreign": { + "columnNames": [ + "auth_id" + ], + "constraintName": "core_user_ban_auth_id_foreign", + "localTableName": "core_user_ban", + "referencedColumnNames": [ + "id" + ], + "referencedTableName": "core_user", + "updateRule": "cascade", + "deleteRule": "cascade" + }, + "core_user_ban_banned_by_auth_id_foreign": { + "columnNames": [ + "banned_by_auth_id" + ], + "constraintName": "core_user_ban_banned_by_auth_id_foreign", + "localTableName": "core_user_ban", + "referencedColumnNames": [ + "id" + ], + "referencedTableName": "core_user" + } + }, + "comment": null + }, + { + "name": "core_user_data", + "columns": { + "accommodation_note": { + "name": "accommodation_note", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "age": { + "name": "age", + "type": "integer", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "integer" + }, + "auth_id": { + "name": "auth_id", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": true, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "completed_at": { + "name": "completed_at", + "type": "datetime", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "datetime" + }, + "country_of_residence": { + "name": "country_of_residence", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "dietary_restrictions": { + "name": "dietary_restrictions", + "type": "json", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": "'[]'", + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "json" + }, + "ethnicity": { + "name": "ethnicity", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "gender": { + "name": "gender", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "has_accepted_mlhcode_of_conduct": { + "name": "has_accepted_mlhcode_of_conduct", + "type": "integer", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "integer" + }, + "has_shared_data_with_mlh": { + "name": "has_shared_data_with_mlh", + "type": "integer", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "integer" + }, + "is_emailable": { + "name": "is_emailable", + "type": "integer", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "integer" + }, + "phone_number": { + "name": "phone_number", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "race": { + "name": "race", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "shirt_size": { + "name": "shirt_size", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "updated_at": { + "name": "updated_at", + "type": "datetime", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "datetime" + } + }, + "indexes": [ + { + "columnNames": [ + "auth_id" + ], + "composite": false, + "constraint": false, + "keyName": "core_user_data_auth_id_index", + "primary": false, + "unique": false + }, + { + "columnNames": [ + "auth_id" + ], + "composite": false, + "constraint": true, + "keyName": "primary", + "primary": true, + "unique": true + } + ], + "checks": [], + "triggers": [], + "foreignKeys": { + "core_user_data_auth_id_foreign": { + "columnNames": [ + "auth_id" + ], + "constraintName": "core_user_data_auth_id_foreign", + "localTableName": "core_user_data", + "referencedColumnNames": [ + "id" + ], + "referencedTableName": "core_user", + "updateRule": "cascade", + "deleteRule": "cascade" + } + }, + "comment": null + }, + { + "name": "session", + "columns": { + "created_at": { + "name": "created_at", + "type": "datetime", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "datetime" + }, + "expires_at": { + "name": "expires_at", + "type": "datetime", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "datetime" + }, + "id": { + "name": "id", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": true, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "ip_address": { + "name": "ip_address", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "token": { + "name": "token", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": true, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "updated_at": { + "name": "updated_at", + "type": "datetime", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "datetime" + }, + "user_agent": { + "name": "user_agent", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "user_id": { + "name": "user_id", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + } + }, + "indexes": [ + { + "columnNames": [ + "id" + ], + "composite": false, + "constraint": true, + "keyName": "primary", + "primary": true, + "unique": true + }, + { + "columnNames": [ + "token" + ], + "composite": false, + "constraint": true, + "keyName": "session_token_unique", + "primary": false, + "unique": true + }, + { + "columnNames": [ + "user_id" + ], + "composite": false, + "constraint": false, + "keyName": "session_user_id_index", + "primary": false, + "unique": false + } + ], + "checks": [], + "triggers": [], + "foreignKeys": { + "session_user_id_foreign": { + "columnNames": [ + "user_id" + ], + "constraintName": "session_user_id_foreign", + "localTableName": "session", + "referencedColumnNames": [ + "id" + ], + "referencedTableName": "core_user", + "deleteRule": "cascade" + } + }, + "comment": null + }, + { + "name": "verification", + "columns": { + "created_at": { + "name": "created_at", + "type": "datetime", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "datetime" + }, + "expires_at": { + "name": "expires_at", + "type": "datetime", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "datetime" + }, + "id": { + "name": "id", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": true, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "identifier": { + "name": "identifier", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + }, + "updated_at": { + "name": "updated_at", + "type": "datetime", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "datetime" + }, + "value": { + "name": "value", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "collation": null, + "enumItems": [], + "mappedType": "text" + } + }, + "indexes": [ + { + "columnNames": [ + "id" + ], + "composite": false, + "constraint": true, + "keyName": "primary", + "primary": true, + "unique": true + }, + { + "columnNames": [ + "identifier" + ], + "composite": false, + "constraint": false, + "keyName": "verification_identifier_index", + "primary": false, + "unique": false + } + ], + "checks": [], + "triggers": [], + "foreignKeys": {}, + "comment": null + } + ], + "views": [], + "nativeEnums": {} +} \ No newline at end of file diff --git a/templates/nextjs-minimal/db/migrations/sqlite/Migration20261020200349_initial.ts b/templates/nextjs-minimal/db/migrations/sqlite/Migration20261020200349_initial.ts new file mode 100644 index 000000000..cacf644bf --- /dev/null +++ b/templates/nextjs-minimal/db/migrations/sqlite/Migration20261020200349_initial.ts @@ -0,0 +1,101 @@ +import { Migration } from '@mikro-orm/migrations'; + +export class Migration20261020200349_initial extends Migration { + + override name = 'Migration20261020200349_initial'; + + override up(): void | Promise { + this.addSql(`create table \`verification\` (\`id\` text not null primary key, \`identifier\` text not null, \`value\` text not null, \`expires_at\` datetime not null, \`created_at\` datetime null, \`updated_at\` datetime null);`); + this.addSql(`create index \`verification_identifier_index\` on \`verification\` (\`identifier\`);`); + + this.addSql(`create table \`core_event\` (\`id\` text not null primary key, \`title\` text not null, \`start_time\` datetime not null, \`end_time\` datetime not null, \`location\` text not null default 'TBD', \`description\` text not null, \`type\` text not null, \`host\` text null, \`hidden\` integer not null default false, \`created_at\` datetime not null, \`updated_at\` datetime not null);`); + this.addSql(`create index \`core_event_start_time_index\` on \`core_event\` (\`start_time\`);`); + this.addSql(`create index \`core_event_type_index\` on \`core_event\` (\`type\`);`); + this.addSql(`create index \`core_event_hidden_index\` on \`core_event\` (\`hidden\`);`); + + this.addSql(`create table \`core_operation_lock\` (\`key\` text not null primary key, \`token\` text not null);`); + + this.addSql(`create table \`core_role\` (\`id\` text not null primary key, \`name\` text not null, \`position\` integer not null, \`permissions\` json not null default '[]', \`color\` text null, \`created_at\` datetime not null, \`updated_at\` datetime not null);`); + this.addSql(`create unique index \`core_role_name_unique\` on \`core_role\` (\`name\`);`); + this.addSql(`create index \`core_role_position_index\` on \`core_role\` (\`position\`);`); + + this.addSql(`create table \`core_user\` (\`id\` text not null primary key, \`name\` text not null, \`email\` text not null, \`email_verified\` integer not null default false, \`profile_photo_url\` text null, \`hack_tag\` text null, \`bio\` text null, \`pronouns\` text null, \`skills\` json not null default '[]', \`is_profile_searchable\` integer not null default true, \`discord_display_handle\` text null, \`role_id\` text null, \`is_approved\` integer not null default false, \`checked_in_at\` datetime null, \`created_at\` datetime not null, \`updated_at\` datetime not null, constraint \`core_user_role_id_foreign\` foreign key (\`role_id\`) references \`core_role\` (\`id\`) on delete set null);`); + this.addSql(`create unique index \`core_user_email_unique\` on \`core_user\` (\`email\`);`); + this.addSql(`create unique index \`core_user_hack_tag_unique\` on \`core_user\` (\`hack_tag\`);`); + this.addSql(`create index \`core_user_hack_tag_index\` on \`core_user\` (\`hack_tag\`);`); + this.addSql(`create index \`core_user_role_id_index\` on \`core_user\` (\`role_id\`);`); + this.addSql(`create index \`core_user_created_at_index\` on \`core_user\` (\`created_at\`);`); + + this.addSql(`create table \`core_user_data\` (\`auth_id\` text not null primary key, \`age\` integer not null, \`gender\` text not null, \`race\` text not null, \`ethnicity\` text not null, \`shirt_size\` text not null, \`dietary_restrictions\` json not null default '[]', \`accommodation_note\` text null, \`phone_number\` text null, \`country_of_residence\` text null, \`has_accepted_mlhcode_of_conduct\` integer not null, \`has_shared_data_with_mlh\` integer not null, \`is_emailable\` integer not null, \`completed_at\` datetime not null, \`updated_at\` datetime not null, constraint \`core_user_data_auth_id_foreign\` foreign key (\`auth_id\`) references \`core_user\` (\`id\`) on update cascade on delete cascade);`); + this.addSql(`create index \`core_user_data_auth_id_index\` on \`core_user_data\` (\`auth_id\`);`); + + this.addSql(`create table \`core_user_ban\` (\`auth_id\` text not null primary key, \`reason\` text null, \`banned_by_auth_id\` text not null, \`created_at\` datetime not null, constraint \`core_user_ban_auth_id_foreign\` foreign key (\`auth_id\`) references \`core_user\` (\`id\`) on update cascade on delete cascade, constraint \`core_user_ban_banned_by_auth_id_foreign\` foreign key (\`banned_by_auth_id\`) references \`core_user\` (\`id\`));`); + this.addSql(`create index \`core_user_ban_auth_id_index\` on \`core_user_ban\` (\`auth_id\`);`); + this.addSql(`create index \`core_user_ban_banned_by_auth_id_index\` on \`core_user_ban\` (\`banned_by_auth_id\`);`); + + this.addSql(`create table \`core_setting\` (\`key\` text not null primary key, \`value\` json not null, \`created_at\` datetime not null, \`created_by_auth_id\` text null, \`updated_at\` datetime not null, \`updated_by_auth_id\` text null, constraint \`core_setting_created_by_auth_id_foreign\` foreign key (\`created_by_auth_id\`) references \`core_user\` (\`id\`) on delete set null, constraint \`core_setting_updated_by_auth_id_foreign\` foreign key (\`updated_by_auth_id\`) references \`core_user\` (\`id\`) on delete set null);`); + this.addSql(`create index \`core_setting_created_by_auth_id_index\` on \`core_setting\` (\`created_by_auth_id\`);`); + this.addSql(`create index \`core_setting_updated_at_index\` on \`core_setting\` (\`updated_at\`);`); + this.addSql(`create index \`core_setting_updated_by_auth_id_index\` on \`core_setting\` (\`updated_by_auth_id\`);`); + + this.addSql(`create table \`core_rsvp\` (\`auth_id\` text not null primary key, \`status\` text check (\`status\` in ('confirmed', 'waitlisted', 'cancelled')) not null, \`waitlist_position\` integer null, \`created_at\` datetime not null, \`updated_at\` datetime not null, \`confirmed_at\` datetime null, \`waitlisted_at\` datetime null, \`cancelled_at\` datetime null, \`cancelled_by_auth_id\` text null, \`promoted_at\` datetime null, \`promoted_by_auth_id\` text null, constraint \`core_rsvp_auth_id_foreign\` foreign key (\`auth_id\`) references \`core_user\` (\`id\`) on update cascade on delete cascade, constraint \`core_rsvp_cancelled_by_auth_id_foreign\` foreign key (\`cancelled_by_auth_id\`) references \`core_user\` (\`id\`) on delete set null, constraint \`core_rsvp_promoted_by_auth_id_foreign\` foreign key (\`promoted_by_auth_id\`) references \`core_user\` (\`id\`) on delete set null);`); + this.addSql(`create index \`core_rsvp_auth_id_index\` on \`core_rsvp\` (\`auth_id\`);`); + this.addSql(`create index \`core_rsvp_cancelled_by_auth_id_index\` on \`core_rsvp\` (\`cancelled_by_auth_id\`);`); + this.addSql(`create index \`core_rsvp_promoted_by_auth_id_index\` on \`core_rsvp\` (\`promoted_by_auth_id\`);`); + this.addSql(`create index \`core_rsvp_status_index\` on \`core_rsvp\` (\`status\`);`); + this.addSql(`create index \`core_rsvp_waitlist_position_index\` on \`core_rsvp\` (\`waitlist_position\`);`); + this.addSql(`create index \`core_rsvp_created_at_index\` on \`core_rsvp\` (\`created_at\`);`); + this.addSql(`create index \`core_rsvp_updated_at_index\` on \`core_rsvp\` (\`updated_at\`);`); + + this.addSql(`create table \`core_notification_intent\` (\`id\` text not null primary key, \`kind\` text not null, \`recipient_auth_id\` text null, \`payload\` json not null, \`status\` text check (\`status\` in ('pending', 'processing', 'delivered', 'failed', 'skipped')) not null default 'pending', \`idempotency_key\` text null, \`created_at\` datetime not null, \`updated_at\` datetime not null, constraint \`core_notification_intent_recipient_auth_id_foreign\` foreign key (\`recipient_auth_id\`) references \`core_user\` (\`id\`) on delete set null);`); + this.addSql(`create unique index \`core_notification_intent_idempotency_key_unique\` on \`core_notification_intent\` (\`idempotency_key\`);`); + this.addSql(`create index \`core_notification_intent_kind_index\` on \`core_notification_intent\` (\`kind\`);`); + this.addSql(`create index \`core_notification_intent_recipient_auth_id_index\` on \`core_notification_intent\` (\`recipient_auth_id\`);`); + this.addSql(`create index \`core_notification_intent_status_index\` on \`core_notification_intent\` (\`status\`);`); + this.addSql(`create index \`core_notification_intent_created_at_index\` on \`core_notification_intent\` (\`created_at\`);`); + + this.addSql(`create table \`core_notification_delivery_attempt\` (\`id\` text not null primary key, \`intent_id\` text not null, \`channel\` text not null, \`provider\` text null, \`status\` text check (\`status\` in ('delivered', 'failed', 'skipped')) not null, \`recipient\` text null, \`external_id\` text null, \`error\` text null, \`metadata\` json not null, \`attempted_at\` datetime not null, constraint \`core_notification_delivery_attempt_intent_id_foreign\` foreign key (\`intent_id\`) references \`core_notification_intent\` (\`id\`) on delete cascade);`); + this.addSql(`create index \`core_notification_delivery_attempt_intent_id_index\` on \`core_notification_delivery_attempt\` (\`intent_id\`);`); + this.addSql(`create index \`core_notification_delivery_attempt_channel_index\` on \`core_notification_delivery_attempt\` (\`channel\`);`); + this.addSql(`create index \`core_notification_delivery_attempt_status_index\` on \`core_notification_delivery_attempt\` (\`status\`);`); + this.addSql(`create index \`core_notification_delivery_attempt_attempted_at_index\` on \`core_notification_delivery_attempt\` (\`attempted_at\`);`); + + this.addSql(`create table \`core_hacker\` (\`auth_id\` text not null primary key, \`university\` text not null, \`major\` text not null, \`school_id\` text null, \`level_of_study\` text not null, \`hackathons_attended\` integer not null, \`software_experience\` text not null, \`heard_from\` text null, \`github_url\` text null, \`linked_in_url\` text null, \`personal_website_url\` text null, \`resume_url\` text null, \`group\` text null, \`registered_at\` datetime not null, \`updated_at\` datetime not null, constraint \`core_hacker_auth_id_foreign\` foreign key (\`auth_id\`) references \`core_user\` (\`id\`) on update cascade on delete cascade);`); + this.addSql(`create index \`core_hacker_auth_id_index\` on \`core_hacker\` (\`auth_id\`);`); + this.addSql(`create index \`core_hacker_registered_at_index\` on \`core_hacker\` (\`registered_at\`);`); + + this.addSql(`create table \`core_event_scan\` (\`id\` text not null primary key, \`event_id\` text not null, \`auth_id\` text not null, \`scanned_by_auth_id\` text not null, \`scanned_at\` datetime not null, constraint \`core_event_scan_event_id_foreign\` foreign key (\`event_id\`) references \`core_event\` (\`id\`) on delete cascade, constraint \`core_event_scan_auth_id_foreign\` foreign key (\`auth_id\`) references \`core_user\` (\`id\`) on delete cascade, constraint \`core_event_scan_scanned_by_auth_id_foreign\` foreign key (\`scanned_by_auth_id\`) references \`core_user\` (\`id\`));`); + this.addSql(`create index \`core_event_scan_scanned_by_auth_id_index\` on \`core_event_scan\` (\`scanned_by_auth_id\`);`); + this.addSql(`create index \`core_event_scan_event_id_index\` on \`core_event_scan\` (\`event_id\`);`); + this.addSql(`create index \`core_event_scan_auth_id_index\` on \`core_event_scan\` (\`auth_id\`);`); + this.addSql(`create index \`core_event_scan_event_id_auth_id_index\` on \`core_event_scan\` (\`event_id\`, \`auth_id\`);`); + this.addSql(`create index \`core_event_scan_scanned_at_index\` on \`core_event_scan\` (\`scanned_at\`);`); + + this.addSql(`create table \`session\` (\`id\` text not null primary key, \`expires_at\` datetime not null, \`token\` text not null, \`created_at\` datetime not null, \`updated_at\` datetime not null, \`ip_address\` text null, \`user_agent\` text null, \`user_id\` text not null, constraint \`session_user_id_foreign\` foreign key (\`user_id\`) references \`core_user\` (\`id\`) on delete cascade);`); + this.addSql(`create unique index \`session_token_unique\` on \`session\` (\`token\`);`); + this.addSql(`create index \`session_user_id_index\` on \`session\` (\`user_id\`);`); + + this.addSql(`create table \`account\` (\`id\` text not null primary key, \`account_id\` text not null, \`provider_id\` text not null, \`user_id\` text not null, \`access_token\` text null, \`refresh_token\` text null, \`id_token\` text null, \`access_token_expires_at\` datetime null, \`refresh_token_expires_at\` datetime null, \`scope\` text null, \`password\` text null, \`created_at\` datetime not null, \`updated_at\` datetime not null, constraint \`account_user_id_foreign\` foreign key (\`user_id\`) references \`core_user\` (\`id\`) on delete cascade);`); + this.addSql(`create index \`account_user_id_index\` on \`account\` (\`user_id\`);`); + } + + override down(): void | Promise { + + this.addSql(`drop table if exists \`verification\`;`); + this.addSql(`drop table if exists \`core_event\`;`); + this.addSql(`drop table if exists \`core_operation_lock\`;`); + this.addSql(`drop table if exists \`core_role\`;`); + this.addSql(`drop table if exists \`core_user\`;`); + this.addSql(`drop table if exists \`core_user_data\`;`); + this.addSql(`drop table if exists \`core_user_ban\`;`); + this.addSql(`drop table if exists \`core_setting\`;`); + this.addSql(`drop table if exists \`core_rsvp\`;`); + this.addSql(`drop table if exists \`core_notification_intent\`;`); + this.addSql(`drop table if exists \`core_notification_delivery_attempt\`;`); + this.addSql(`drop table if exists \`core_hacker\`;`); + this.addSql(`drop table if exists \`core_event_scan\`;`); + this.addSql(`drop table if exists \`session\`;`); + this.addSql(`drop table if exists \`account\`;`); + } + +} diff --git a/templates/nextjs-minimal/env.ts b/templates/nextjs-minimal/env.ts new file mode 100644 index 000000000..3811d9ef0 --- /dev/null +++ b/templates/nextjs-minimal/env.ts @@ -0,0 +1,49 @@ +function read(name: string) { + const value = process.env[name]?.trim(); + return value || undefined; +} + +export function resolveTemplateEnv() { + const production = process.env.NODE_ENV === "production"; + const appUrl = + read("NEXT_PUBLIC_APP_URL") ?? + read("BETTER_AUTH_URL") ?? + "http://localhost:3000"; + const betterAuthSecret = + read("BETTER_AUTH_SECRET") ?? + "minimal-development-secret-change-me-please"; + if (production) { + if (!read("NEXT_PUBLIC_APP_URL") && !read("BETTER_AUTH_URL")) + throw new Error( + "Set NEXT_PUBLIC_APP_URL or BETTER_AUTH_URL in production.", + ); + if (!read("BETTER_AUTH_SECRET") || betterAuthSecret.length < 32) + throw new Error( + "Set BETTER_AUTH_SECRET to at least 32 characters in production.", + ); + } + const databaseUrl = read("DATABASE_URL") ?? "file:.data/web.db"; + if ( + /^[a-z][a-z\d+.-]*:/i.test(databaseUrl) && + !databaseUrl.startsWith("file:") && + databaseUrl !== ":memory:" + ) + throw new Error( + "The minimal template requires a local SQLite DATABASE_URL.", + ); + return { + nodeEnv: production ? "production" : "development", + appUrl, + betterAuthUrl: read("BETTER_AUTH_URL") ?? appUrl, + betterAuthSecret, + betterAuthTrustedOrigins: + read("BETTER_AUTH_TRUSTED_ORIGINS") + ?.split(",") + .map((value) => value.trim()) + .filter(Boolean) ?? [], + databaseUrl, + localBlobBaseDir: + read("HACKKIT_LOCAL_BLOB_BASE_DIR") ?? ".data/uploads", + }; +} +export const env = resolveTemplateEnv(); diff --git a/templates/nextjs-minimal/hackkit.config.ts b/templates/nextjs-minimal/hackkit.config.ts new file mode 100644 index 000000000..e1ae2b121 --- /dev/null +++ b/templates/nextjs-minimal/hackkit.config.ts @@ -0,0 +1,105 @@ +import { defineHackkitConfig } from "@hackkit/config"; +import { CorePermission } from "@hackkit/core"; +import { databaseOptions } from "./lib/database-config"; +import { authOptions } from "./lib/auth-options"; +import { env } from "./env"; +const shirtSizeOptions = [ + { value: "s", label: "Small" }, + { value: "m", label: "Medium" }, + { value: "l", label: "Large" }, + { value: "xl", label: "Extra large" }, + { value: "2xl", label: "2XL" }, + { value: "3xl", label: "3XL" }, +]; + +const countryOptions = [ + { value: "us", label: "United States" }, + { value: "ca", label: "Canada" }, + { value: "mx", label: "Mexico" }, + { value: "gb", label: "United Kingdom" }, + { value: "other", label: "Other" }, +]; + +const schoolOptions = [ + { + value: "University of Texas at San Antonio", + label: "University of Texas at San Antonio", + }, + { + value: "University of Texas at Austin", + label: "University of Texas at Austin", + }, + { value: "Texas A&M University", label: "Texas A&M University" }, + { value: "Rice University", label: "Rice University" }, + { value: "other", label: "Other" }, +]; + +const majorOptions = [ + { value: "Computer Science", label: "Computer Science" }, + { value: "Computer Engineering", label: "Computer Engineering" }, + { value: "Electrical Engineering", label: "Electrical Engineering" }, + { value: "Data Science", label: "Data Science" }, + { value: "Design", label: "Design" }, + { value: "Business", label: "Business" }, + { value: "other", label: "Other" }, +]; + +const levelsOfStudy = [ + { value: "Freshman", label: "Freshman" }, + { value: "Sophomore", label: "Sophomore" }, + { value: "Junior", label: "Junior" }, + { value: "Senior", label: "Senior" }, + { value: "Graduate", label: "Graduate" }, + { value: "Recent Grad", label: "Recent Grad" }, + { value: "Other", label: "Other" }, +]; + +const softwareExperienceOptions = [ + { value: "Beginner", label: "Beginner" }, + { value: "Intermediate", label: "Intermediate" }, + { value: "Advanced", label: "Advanced" }, + { value: "Expert", label: "Expert" }, +]; + +const heardFromOptions = [ + { value: "Instagram", label: "Instagram" }, + { value: "Class Presentation", label: "Class presentation" }, + { value: "Twitter", label: "Twitter" }, + { value: "Event Site", label: "Event site" }, + { value: "Friend", label: "Friend" }, + { value: "Other", label: "Other" }, +]; + +export default defineHackkitConfig({ + database: databaseOptions, + auth: authOptions, + defaultCompetitorRoleId: "core.participant", + seedRoles: [ + { + id: "core.participant", + name: "Participant", + position: 10, + permissions: [], + }, + { + id: "core.owner", + name: "Owner", + position: 0, + permissions: Object.values(CorePermission), + }, + ], + blob: { adapter: "local", baseDir: env.localBlobBaseDir }, + logger: { level: env.nodeEnv === "production" ? "warn" : "debug" }, + plugins: [], + userDataOptions: { + shirtSize: shirtSizeOptions, + countryOfResidence: countryOptions, + }, + hackerRegistrationOptions: { + schools: schoolOptions, + majors: majorOptions, + levelsOfStudy, + softwareExperience: softwareExperienceOptions, + heardFrom: heardFromOptions, + }, +}); diff --git a/templates/nextjs-minimal/hackkit.lock b/templates/nextjs-minimal/hackkit.lock new file mode 100644 index 000000000..2e7bed4e6 --- /dev/null +++ b/templates/nextjs-minimal/hackkit.lock @@ -0,0 +1,4 @@ +{ + "version": 1, + "plugins": [] +} diff --git a/templates/nextjs-minimal/lib/app-config.ts b/templates/nextjs-minimal/lib/app-config.ts new file mode 100644 index 000000000..31a9a0e16 --- /dev/null +++ b/templates/nextjs-minimal/lib/app-config.ts @@ -0,0 +1,11 @@ +import "server-only"; + +import { resolveHackkitConfig } from "@hackkit/config"; +import hackkitConfig from "../hackkit.config"; +import { env } from "../env"; + +export const appConfig = resolveHackkitConfig(hackkitConfig); + +export function resolveAppBaseUrl(): string { + return env.appUrl; +} diff --git a/templates/nextjs-minimal/lib/auth-client.ts b/templates/nextjs-minimal/lib/auth-client.ts new file mode 100644 index 000000000..2f75fd48b --- /dev/null +++ b/templates/nextjs-minimal/lib/auth-client.ts @@ -0,0 +1,5 @@ +"use client"; + +import { createAuthClient } from "better-auth/react"; + +export const authClient = createAuthClient(); diff --git a/templates/nextjs-minimal/lib/auth-options.ts b/templates/nextjs-minimal/lib/auth-options.ts new file mode 100644 index 000000000..8ba418753 --- /dev/null +++ b/templates/nextjs-minimal/lib/auth-options.ts @@ -0,0 +1,8 @@ +import type { HackKitAuthOptions } from "@hackkit/core"; +import { env } from "../env"; +export const authOptions = { + baseURL: env.betterAuthUrl, + secret: env.betterAuthSecret, + trustedOrigins: env.betterAuthTrustedOrigins, + emailAndPassword: { enabled: true }, +} satisfies HackKitAuthOptions; diff --git a/templates/nextjs-minimal/lib/auth.ts b/templates/nextjs-minimal/lib/auth.ts new file mode 100644 index 000000000..66b0565a1 --- /dev/null +++ b/templates/nextjs-minimal/lib/auth.ts @@ -0,0 +1,11 @@ +import "server-only"; +import { headers } from "next/headers"; +import { getCoreRuntime } from "./runtime"; + +export async function getAuth() { + return (await getCoreRuntime()).auth; +} + +export async function getAuthSession() { + return (await getAuth()).api.getSession({ headers: await headers() }); +} diff --git a/templates/nextjs-minimal/lib/blob.ts b/templates/nextjs-minimal/lib/blob.ts new file mode 100644 index 000000000..4a7883040 --- /dev/null +++ b/templates/nextjs-minimal/lib/blob.ts @@ -0,0 +1,11 @@ +import "server-only"; +import { createLocalBlobStorage } from "@hackkit/blob-local"; +import { env } from "../env"; +let storage: ReturnType | undefined; +export function getBlobStorage() { + return (storage ??= createLocalBlobStorage({ + baseDir: env.localBlobBaseDir, + appBaseUrl: env.appUrl, + filesRoutePrefix: "/api/files", + })); +} diff --git a/templates/nextjs-minimal/lib/database-config.ts b/templates/nextjs-minimal/lib/database-config.ts new file mode 100644 index 000000000..9f94a44c9 --- /dev/null +++ b/templates/nextjs-minimal/lib/database-config.ts @@ -0,0 +1,19 @@ +import { resolve } from "node:path"; +import { SqliteDriver } from "@mikro-orm/sqlite"; +import { env } from "../env"; + +// Application commands and Next run from this template's directory. +export const databaseOptions = { + driver: SqliteDriver, + dbName: + env.databaseUrl === ":memory:" + ? ":memory:" + : resolve(env.databaseUrl.replace(/^file:/, "")), + migrations: { + path: resolve("db/migrations/sqlite"), + emit: "ts" as const, + snapshot: true, + snapshotName: ".snapshot", + snapshotOnMigrate: false, + }, +}; diff --git a/templates/nextjs-minimal/lib/hackkit-ui-routes.ts b/templates/nextjs-minimal/lib/hackkit-ui-routes.ts new file mode 100644 index 000000000..afca1c43b --- /dev/null +++ b/templates/nextjs-minimal/lib/hackkit-ui-routes.ts @@ -0,0 +1,7 @@ +import { DEFAULT_HACKKIT_UI_ROUTES, type HackKitUIRoutes } from "@hackkit/ui"; + +/** + * Single place for HackKit UI route policy in this HackKit Web App. + * Passed to HackKitUIProvider and buildCompetitorOnboardingSteps. + */ +export const hackKitUIRoutes: HackKitUIRoutes = DEFAULT_HACKKIT_UI_ROUTES; diff --git a/templates/nextjs-minimal/lib/logger.ts b/templates/nextjs-minimal/lib/logger.ts new file mode 100644 index 000000000..18b9b02c4 --- /dev/null +++ b/templates/nextjs-minimal/lib/logger.ts @@ -0,0 +1,11 @@ +import { createLogger, type HackKitLogger } from "@hackkit/core"; +import { appConfig } from "./app-config"; + +let logger: HackKitLogger | null = null; + +export function getAppLogger(): HackKitLogger { + if (!logger) { + logger = createLogger(appConfig.logger); + } + return logger; +} diff --git a/templates/nextjs-minimal/lib/onboarding.ts b/templates/nextjs-minimal/lib/onboarding.ts new file mode 100644 index 000000000..d876e88ff --- /dev/null +++ b/templates/nextjs-minimal/lib/onboarding.ts @@ -0,0 +1,54 @@ +import "server-only"; + +import { + buildCompetitorOnboardingSteps, + getNextOnboardingStepHref, + type CompetitorOnboardingStep, +} from "@hackkit/ui"; +import { CoreSetting } from "@hackkit/core"; +import { hackKitUIRoutes } from "./hackkit-ui-routes"; +import { getCurrentUser, getHackkit, getRuntime } from "./runtime"; + +async function loadCompetitorOnboardingInput(currentPath: string) { + const user = await getCurrentUser(); + const hackkit = await getHackkit(); + const runtime = await getRuntime(); + const [userData, hacker, requireApproval] = await Promise.all([ + hackkit.userData.getUserData(user.id), + hackkit.hackers.getHacker(user.id), + runtime.getSettingValue(CoreSetting.RequireApproval), + ]); + return { + user, + userData, + hacker, + requireApproval: Boolean(requireApproval), + currentPath, + routes: hackKitUIRoutes, + }; +} + +export async function getOnboardingSteps( + currentPath: string, +): Promise { + const input = await loadCompetitorOnboardingInput(currentPath); + return buildCompetitorOnboardingSteps(input); +} + +export async function getCompetitorOnboardingState(currentPath: string) { + const input = await loadCompetitorOnboardingInput(currentPath); + const steps = buildCompetitorOnboardingSteps(input); + return { + steps, + nextHref: getNextOnboardingStepHref(steps), + user: input.user, + userData: input.userData, + hacker: input.hacker, + }; +} + +export async function getRequireApproval(): Promise { + return Boolean( + await (await getRuntime()).getSettingValue(CoreSetting.RequireApproval), + ); +} diff --git a/templates/nextjs-minimal/lib/public-site-config.ts b/templates/nextjs-minimal/lib/public-site-config.ts new file mode 100644 index 000000000..1d7f368e2 --- /dev/null +++ b/templates/nextjs-minimal/lib/public-site-config.ts @@ -0,0 +1,122 @@ +import type { CSSProperties } from "react"; +import type { + PublicLandingPageProps, + PublicShellLink, + PublicSiteFooterGroup, +} from "@hackkit/ui"; + +export type PublicSiteConfig = { + brand: { + name: string; + shortName: string; + description: string; + }; + event: { + name: string; + dates: string; + location: string; + timezone: string; + }; + theme: { + primary: string; + ring: string; + }; + nav: { + public: PublicShellLink[]; + participant: PublicShellLink[]; + }; + landing: Omit< + PublicLandingPageProps, + "primaryAction" | "secondaryAction" + > & { + primaryAction: PublicShellLink; + secondaryAction: PublicShellLink; + signedInAction: PublicShellLink; + }; + help: { + title: string; + description: string; + contacts: PublicShellLink[]; + resources: PublicShellLink[]; + }; + dashboard: { + primaryActions: PublicShellLink[]; + resourceLinks: PublicShellLink[]; + }; + footer: { + linkGroups: PublicSiteFooterGroup[]; + }; +}; + +export const publicSiteConfig = { + brand: { + name: "HackKit", + shortName: "HackKit", + description: "Hackathon registration and participant management.", + }, + event: { + name: "Your hackathon", + dates: "Dates to be announced", + location: "Location to be announced", + timezone: "America/Chicago", + }, + theme: { primary: "221.2 83.2% 53.3%", ring: "221.2 83.2% 53.3%" }, + nav: { + public: [{ label: "Help", href: "/help" }], + participant: [ + { label: "Dashboard", href: "/dashboard" }, + { label: "Settings", href: "/settings" }, + ], + }, + landing: { + eyebrow: "HackKit", + title: "Register for your next hackathon.", + description: + "Create an account, complete registration, and manage your participant profile.", + primaryAction: { label: "Apply now", href: "/sign-up" }, + secondaryAction: { label: "Get help", href: "/help" }, + signedInAction: { label: "Open dashboard", href: "/dashboard" }, + highlights: [], + sections: [], + stats: [], + }, + help: { + title: "Contact and help", + description: "Contact the organizing team for registration help.", + contacts: [ + { + label: "Organizer support", + href: "mailto:organizers@example.com", + }, + ], + resources: [ + { label: "Dashboard", href: "/dashboard" }, + { label: "Registration", href: "/settings/registration" }, + ], + }, + dashboard: { + primaryActions: [ + { label: "Edit registration", href: "/settings/registration" }, + { label: "Profile settings", href: "/settings" }, + ], + resourceLinks: [{ label: "Help", href: "/help" }], + }, + footer: { + linkGroups: [ + { + title: "HackKit", + links: [ + { label: "Help", href: "/help" }, + { label: "Apply", href: "/sign-up" }, + { label: "Dashboard", href: "/dashboard" }, + ], + }, + ], + }, +} satisfies PublicSiteConfig; +export function getPublicThemeStyle(): CSSProperties { + return { + "--primary": publicSiteConfig.theme.primary, + "--ring": publicSiteConfig.theme.ring, + } as CSSProperties; +} diff --git a/templates/nextjs-minimal/lib/runtime.ts b/templates/nextjs-minimal/lib/runtime.ts new file mode 100644 index 000000000..27d87c0df --- /dev/null +++ b/templates/nextjs-minimal/lib/runtime.ts @@ -0,0 +1,35 @@ +import "server-only"; + +import { + createHackkitRuntimeFromConfig, + setHackkitRuntime, +} from "@hackkit/next"; +import { appConfig } from "./app-config"; + +const host = createHackkitRuntimeFromConfig({ + config: appConfig, +}); + +setHackkitRuntime(host.getRuntime); + +export async function getRuntime() { + return host.getRuntime(); +} + +export async function getCurrentUser() { + return (await getRuntime()).getCurrentUser(); +} + +export async function getHackkit() { + return (await getRuntime()).hackkit; +} + +export async function getPageGuards() { + return (await getRuntime()).pageGuards; +} + +export function getCoreRuntime() { + return host.core; +} + +export const handleHackkitRequest = host.handler; diff --git a/templates/nextjs-minimal/lib/upload-profile-photo.ts b/templates/nextjs-minimal/lib/upload-profile-photo.ts new file mode 100644 index 000000000..2c6b14b87 --- /dev/null +++ b/templates/nextjs-minimal/lib/upload-profile-photo.ts @@ -0,0 +1,34 @@ +export async function uploadProfilePhotoFile(file: File): Promise { + const registerResponse = await fetch("/api/files/register", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + location: "profile-photos", + fileName: file.name, + }), + }); + + if (!registerResponse.ok) { + throw new Error("Could not prepare profile photo upload."); + } + + const { uploadUrl, storedFileReference } = + (await registerResponse.json()) as { + uploadUrl: string; + storedFileReference: string; + }; + + const uploadResponse = await fetch(uploadUrl, { + method: "PUT", + body: file, + headers: { + "Content-Type": file.type || "application/octet-stream", + }, + }); + + if (!uploadResponse.ok) { + throw new Error("Could not upload profile photo."); + } + + return storedFileReference; +} diff --git a/templates/nextjs-minimal/lib/upload-resume.ts b/templates/nextjs-minimal/lib/upload-resume.ts new file mode 100644 index 000000000..d8767b1ec --- /dev/null +++ b/templates/nextjs-minimal/lib/upload-resume.ts @@ -0,0 +1,59 @@ +async function responseError( + response: Response, + fallback: string, +): Promise { + try { + const body = (await response.json()) as { error?: string }; + if (body.error) return new Error(body.error); + } catch { + // Use the actionable fallback when the server did not return JSON. + } + return new Error(fallback); +} + +export async function uploadResumeFile(file: File): Promise { + if (file.type && file.type !== "application/pdf") { + throw new Error( + "Choose a PDF resume before submitting your registration.", + ); + } + + const registerResponse = await fetch("/api/files/register", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + location: "resumes", + fileName: file.name, + }), + }); + + if (!registerResponse.ok) { + throw await responseError( + registerResponse, + "Could not prepare your resume upload. Please sign in again and retry.", + ); + } + + const { uploadUrl, storedFileReference } = + (await registerResponse.json()) as { + uploadUrl: string; + storedFileReference: string; + }; + + const uploadResponse = await fetch(uploadUrl, { + method: "PUT", + body: file, + headers: { + "Content-Type": file.type || "application/pdf", + }, + }); + + if (!uploadResponse.ok) { + throw await responseError( + uploadResponse, + "Could not upload your resume. Check your connection and retry.", + ); + } + + return storedFileReference; +} diff --git a/templates/nextjs-minimal/middleware.ts b/templates/nextjs-minimal/middleware.ts new file mode 100644 index 000000000..b95da4afd --- /dev/null +++ b/templates/nextjs-minimal/middleware.ts @@ -0,0 +1,68 @@ +import { NextResponse, type NextRequest } from "next/server"; + +const AUTH_ROUTE_PATHS = new Set(["/sign-in", "/sign-up"]); +const PUBLIC_ROUTE_PATHS = new Set([ + "/", + "/favicon.ico", + "/registration-closed", + "/suspended", +]); +const PUBLIC_ROUTE_PREFIXES = ["/api/", "/i/approval", "/user/"]; +const PROTECTED_ROUTE_PREFIXES = [ + "/admin", + "/dashboard", + "/onboarding", + "/register", + "/settings", +]; + +function hasAuthSessionCookie(request: NextRequest): boolean { + return request.cookies + .getAll() + .some((cookie) => cookie.name.includes("better-auth.session_token")); +} + +function isPublicRoute(pathname: string): boolean { + return ( + PUBLIC_ROUTE_PATHS.has(pathname) || + AUTH_ROUTE_PATHS.has(pathname) || + PUBLIC_ROUTE_PREFIXES.some((prefix) => pathname.startsWith(prefix)) + ); +} + +function isProtectedRoute(pathname: string): boolean { + return PROTECTED_ROUTE_PREFIXES.some( + (prefix) => pathname === prefix || pathname.startsWith(`${prefix}/`), + ); +} + +export function middleware(request: NextRequest) { + const { pathname } = request.nextUrl; + const hasSession = hasAuthSessionCookie(request); + + if (pathname.startsWith("/@")) { + const tag = pathname.slice(2).split("/")[0]; + if (tag) { + return NextResponse.rewrite(new URL(`/user/${tag}`, request.url)); + } + } + + if (AUTH_ROUTE_PATHS.has(pathname) && hasSession) { + return NextResponse.redirect(new URL("/", request.url)); + } + + if (!hasSession && isProtectedRoute(pathname) && !isPublicRoute(pathname)) { + const signInUrl = new URL("/sign-in", request.url); + signInUrl.searchParams.set( + "next", + `${pathname}${request.nextUrl.search}`, + ); + return NextResponse.redirect(signInUrl); + } + + return NextResponse.next(); +} + +export const config = { + matcher: ["/((?!_next/static|_next/image|favicon.ico|.*\\..*).*)"], +}; diff --git a/templates/nextjs-minimal/next-env.d.ts b/templates/nextjs-minimal/next-env.d.ts new file mode 100644 index 000000000..40c3d6809 --- /dev/null +++ b/templates/nextjs-minimal/next-env.d.ts @@ -0,0 +1,5 @@ +/// +/// + +// NOTE: This file should not be edited +// see https://nextjs.org/docs/app/building-your-application/configuring/typescript for more information. diff --git a/templates/nextjs-minimal/next.config.mjs b/templates/nextjs-minimal/next.config.mjs new file mode 100644 index 000000000..29986317f --- /dev/null +++ b/templates/nextjs-minimal/next.config.mjs @@ -0,0 +1,20 @@ +/** @type {import('next').NextConfig} */ +const nextConfig = { + experimental: { + // SQL drivers load native modules and must execute through Node. + serverComponentsExternalPackages: [ + "@hackkit/core", + "@mikro-orm/core", + "@mikro-orm/sql", + "@mikro-orm/sqlite", + "@mikro-orm/libsql", + "@mikro-orm/mysql", + "@mikro-orm/postgresql", + "@mikro-orm/migrations", + "@a77ay/better-auth-mikro-orm", + ], + }, + transpilePackages: ["@hackkit/ui", "@hackkit/next"], +}; + +export default nextConfig; diff --git a/templates/nextjs-minimal/package.json b/templates/nextjs-minimal/package.json new file mode 100644 index 000000000..cad6293be --- /dev/null +++ b/templates/nextjs-minimal/package.json @@ -0,0 +1,50 @@ +{ + "name": "@hackkit/template-nextjs-minimal", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "plugin:sync": "hackkit plugin sync", + "db:generate": "node scripts/db.mjs generate", + "db:migrate": "node scripts/db.mjs migrate", + "db:seed": "node scripts/db.mjs seed", + "db:reset": "node scripts/db.mjs reset", + "sync": "pnpm plugin:sync", + "dev": "next dev -p 3000", + "build": "next build", + "verify": "pnpm sync && pnpm typecheck && pnpm build", + "start": "next start", + "typecheck": "tsc -p tsconfig.json --noEmit", + "db:status": "node scripts/db.mjs status", + "db:check": "node scripts/db.mjs check", + "db:rollback": "node scripts/db.mjs rollback" + }, + "dependencies": { + "@hackkit/blob-local": "workspace:*", + "@hackkit/cli": "workspace:*", + "@hackkit/config": "workspace:*", + "@hackkit/core": "workspace:*", + "@hackkit/next": "workspace:*", + "@hackkit/ui": "workspace:*", + "better-auth": "1.7.6", + "next": "14.2.35", + "react": "18.3.1", + "react-dom": "18.3.1", + "sonner": "^1.5.0", + "typescript": "5.9.3", + "@mikro-orm/sqlite": "7.2.1", + "@mikro-orm/migrations": "7.2.1", + "@mikro-orm/core": "7.2.1", + "jiti": "2.4.2", + "@next/env": "14.2.35" + }, + "devDependencies": { + "@types/node": "22.18.6", + "@types/react": "18.3.3", + "@types/react-dom": "18.3.0", + "autoprefixer": "10.4.19", + "postcss": "8.4.39", + "tailwindcss": "3.4.6", + "tailwindcss-animate": "1.0.7" + } +} diff --git a/templates/nextjs-minimal/postcss.config.cjs b/templates/nextjs-minimal/postcss.config.cjs new file mode 100644 index 000000000..e873f1a4f --- /dev/null +++ b/templates/nextjs-minimal/postcss.config.cjs @@ -0,0 +1,6 @@ +module.exports = { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +}; diff --git a/templates/nextjs-minimal/scripts/database.ts b/templates/nextjs-minimal/scripts/database.ts new file mode 100644 index 000000000..54e692d76 --- /dev/null +++ b/templates/nextjs-minimal/scripts/database.ts @@ -0,0 +1,146 @@ +import { mkdir } from "node:fs/promises"; +import { dirname } from "node:path"; +import { resolveHackkitConfig, type HackkitConfig } from "@hackkit/config"; +import { createOrmOptions, seedRoles } from "@hackkit/core"; +import { MikroORM } from "@mikro-orm/core"; +import { SqliteDriver } from "@mikro-orm/sqlite"; +import { createJiti } from "jiti"; + +const jiti = createJiti(import.meta.url); + +export type DatabaseCommand = + | { command: "generate"; name?: string; blank?: boolean } + | { command: "status" | "check" | "seed" | "reset" } + | { command: "migrate"; to?: string } + | { command: "rollback"; to?: string }; + +/** Runs an explicit database operation. App startup never calls this function. */ +export async function runDatabaseCommand( + input: HackkitConfig, + request: DatabaseCommand, +) { + const config = resolveHackkitConfig(input); + if (request.command === "reset") { + if ( + !["development", "test"].includes( + process.env.NODE_ENV ?? "development", + ) + ) { + throw new Error( + "db:reset is only available in development or tests.", + ); + } + if ( + config.database.driver !== SqliteDriver || + !config.database.dbName + ) { + throw new Error("db:reset requires a local SQLite database."); + } + if ( + /^[a-z][a-z\d+.-]*:/i.test(config.database.dbName) && + config.database.dbName !== ":memory:" + ) { + throw new Error("db:reset requires a local SQLite path."); + } + } + if ( + config.database.driver === SqliteDriver && + config.database.dbName !== ":memory:" && + config.database.dbName + ) { + await mkdir(dirname(config.database.dbName), { recursive: true }); + } + const orm = await MikroORM.init({ + ...createOrmOptions(config), + dynamicImportProvider: (id) => jiti.import(id), + }); + try { + // MikroORM 7 initializes lazily. History operations must establish a + // connection first: native getPending can otherwise report all files + // as pending when a snapshot exists but the database is unreachable. + if (request.command !== "generate") await orm.connect(); + const migrator = orm.migrator; + switch (request.command) { + case "generate": { + const migration = await migrator.create( + undefined, + request.blank, + false, + request.name, + ); + return { + command: "generate" as const, + migration, + // SQLite table rebuilding also contains DROP TABLE. Review the + // complete migration; this list is a warning, not an SQL parser. + destructiveStatements: migration.diff.up.filter((sql) => + /\bdrop\s+(?:table|column|schema)\b|\btruncate\b/i.test( + sql, + ), + ), + }; + } + case "status": + case "check": { + // Native migrator history calls ensure its tracking table exists. + const executed = await migrator.getExecuted(); + const pending = await migrator.getPending(); + if (request.command === "status") + return { command: "status" as const, executed, pending }; + // checkSchema compares entities to the committed snapshot. Separately + // compare the live database so a clean snapshot cannot hide drift. + const needsMigration = await migrator.checkSchema(); + const schemaSql = await orm.schema.getUpdateSchemaSQL({ + wrap: false, + }); + return { + command: "check" as const, + executed, + pending, + needsMigration, + schemaSql, + ok: + !needsMigration && + pending.length === 0 && + schemaSql.trim() === "", + }; + } + case "migrate": + return { + command: "migrate" as const, + migrations: await migrator.up( + request.to ? { to: request.to } : undefined, + ), + }; + case "rollback": + return { + command: "rollback" as const, + migrations: await migrator.down( + request.to + ? { to: request.to === "0" ? 0 : request.to } + : undefined, + ), + }; + case "reset": + await orm.schema.drop({ dropMigrationsTable: true }); + await migrator.up(); + return { + command: "reset" as const, + seed: await seedRoles({ + em: orm.em.fork(), + roles: config.seedRoles, + }), + }; + case "seed": + return { + command: "seed" as const, + seed: await seedRoles({ + em: orm.em.fork(), + roles: config.seedRoles, + }), + }; + } + } finally { + await orm.close(); + } +} diff --git a/templates/nextjs-minimal/scripts/db.mjs b/templates/nextjs-minimal/scripts/db.mjs new file mode 100644 index 000000000..ea42a00ac --- /dev/null +++ b/templates/nextjs-minimal/scripts/db.mjs @@ -0,0 +1,66 @@ +import { parseArgs } from "node:util"; +import { writeFile } from "node:fs/promises"; +import { fileURLToPath } from "node:url"; +import { createJiti } from "jiti"; +import nextEnv from "@next/env"; +import { loadHackkitConfig } from "@hackkit/config"; + +// Match Next's environment loading before evaluating hackkit.config.ts. +nextEnv.loadEnvConfig( + process.cwd(), + process.env.NODE_ENV !== "production", + console, + true, +); +const jiti = createJiti(fileURLToPath(import.meta.url)); +const { runDatabaseCommand } = await jiti.import("./database.ts"); + +try { + const { values, positionals } = parseArgs({ + allowPositionals: true, + options: { + config: { type: "string", default: "hackkit.config.ts" }, + output: { type: "string" }, + name: { type: "string" }, + blank: { type: "boolean", default: false }, + to: { type: "string" }, + }, + }); + const [command] = positionals; + const commands = [ + "generate", + "status", + "check", + "migrate", + "rollback", + "reset", + "seed", + ]; + if (positionals.length !== 1 || !commands.includes(command)) { + throw new Error(`Choose a database command: ${commands.join(", ")}.`); + } + if ((values.name !== undefined || values.blank) && command !== "generate") { + throw new Error("--name and --blank are only supported by generate."); + } + if (values.to !== undefined && !["migrate", "rollback"].includes(command)) { + throw new Error("--to is only supported by migrate and rollback."); + } + if (values.to !== undefined && !values.to.trim()) { + throw new Error("--to requires a migration name (or 0 for rollback)."); + } + const config = await loadHackkitConfig(values.config); + const result = await runDatabaseCommand(config, { command, ...values }); + // Native drivers can write diagnostics to stdout. A separate result file + // gives release jobs structured output without parsing their logs. + if (values.output) { + await writeFile(values.output, `${JSON.stringify(result, null, 2)}\n`); + } + console.log(JSON.stringify(result, null, 2)); + if (result.command === "check" && !result.ok) process.exitCode = 1; +} catch (error) { + // Print the operation's error without printing the config or connection URL. + console.error( + error instanceof Error ? error.message : "Database command failed.", + ); + process.exitCode = 1; +} diff --git a/apps/web/tailwind.config.ts b/templates/nextjs-minimal/tailwind.config.ts similarity index 100% rename from apps/web/tailwind.config.ts rename to templates/nextjs-minimal/tailwind.config.ts diff --git a/templates/nextjs-minimal/tsconfig.json b/templates/nextjs-minimal/tsconfig.json new file mode 100644 index 000000000..9fbd168e5 --- /dev/null +++ b/templates/nextjs-minimal/tsconfig.json @@ -0,0 +1,23 @@ +{ + "compilerOptions": { + "target": "ESNext", + "lib": ["dom", "dom.iterable", "esnext"], + "allowJs": true, + "skipLibCheck": true, + "strict": true, + "noEmit": true, + "esModuleInterop": true, + "module": "esnext", + "moduleResolution": "bundler", + "resolveJsonModule": true, + "isolatedModules": true, + "jsx": "preserve", + "incremental": true, + "plugins": [{ "name": "next" }], + "paths": { + "@/*": ["./*"] + } + }, + "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], + "exclude": ["node_modules"] +} diff --git a/tooling/check-client-bundle.mjs b/tooling/check-client-bundle.mjs index 83cc3c0e7..3f459a734 100644 --- a/tooling/check-client-bundle.mjs +++ b/tooling/check-client-bundle.mjs @@ -1,34 +1,40 @@ import assert from "node:assert/strict"; import { createRequire } from "node:module"; import { resolve } from "node:path"; -const require = createRequire(resolve("packages/core/package.json")); -const vitestRequire = createRequire(require.resolve("vitest")); -const { build } = createRequire(vitestRequire.resolve("vite"))("esbuild"); -const result = await build({ - entryPoints: ["apps/web/app/providers.tsx"], - bundle: true, - platform: "browser", - format: "esm", - minify: true, - write: false, - metafile: true, - logLevel: "silent", -}); -const files = Object.keys(result.metafile.inputs); -const forbidden = files.filter((file) => - /(?:@mikro-orm|better-auth|\/core\/(?:src|dist)\/(?:mikro|models|hackkit|plugins)|\/(?:endpoints|api|http-server|handler)\.js$)/.test( - file, - ), -); -assert.deepEqual( - forbidden, - [], - "Server implementations entered the browser client bundle.", -); -console.log( - JSON.stringify({ - browserBundleBytes: result.outputFiles[0].contents.length, - modules: files.length, - serverModules: forbidden.length, - }), -); +const require = createRequire(resolve("e2e/package.json")); +const { build } = require("esbuild"); +for (const template of [ + "templates/nextjs-full", + "templates/nextjs-minimal", + "apps/demo", +]) { + const result = await build({ + entryPoints: [`${template}/app/providers.tsx`], + bundle: true, + platform: "browser", + format: "esm", + minify: true, + write: false, + metafile: true, + logLevel: "silent", + }); + const files = Object.keys(result.metafile.inputs); + const forbidden = files.filter((file) => + /(?:@mikro-orm|better-auth|\/core\/(?:src|dist)\/(?:mikro|models|hackkit|plugins)|\/(?:endpoints|api|http-server|handler)\.js$)/.test( + file, + ), + ); + assert.deepEqual( + forbidden, + [], + "Server implementations entered the browser client bundle.", + ); + console.log( + JSON.stringify({ + template, + browserBundleBytes: result.outputFiles[0].contents.length, + modules: files.length, + serverModules: forbidden.length, + }), + ); +} diff --git a/turbo.json b/turbo.json index 3e4c602db..e7e1fc478 100644 --- a/turbo.json +++ b/turbo.json @@ -1,86 +1,123 @@ { - "$schema": "https://turbo.build/schema.json", - "globalDependencies": ["**/.env.*local"], - "globalEnv": [ - "AWS_ACCESS_KEY_ID", - "AWS_REGION", - "AWS_S3_BUCKET", - "AWS_S3_ENDPOINT", - "AWS_S3_REGION", - "AWS_SECRET_ACCESS_KEY", - "AWS_SES_ACCESS_KEY", - "AWS_SES_EMAIL_FROM", - "AWS_SES_SECRET_ACCESS_KEY", - "BACKUP_CRON_SCHEDULE", - "BACKUP_DATABASE_URL", - "BETTER_AUTH_SECRET", - "BETTER_AUTH_TRUSTED_ORIGINS", - "BETTER_AUTH_URL", - "BOT_API_URL", - "CLERK_SECRET_KEY", - "DATABASE_URL", - "DISCORD_CLIENT_ID", - "DISCORD_DEV_SERVER_ID", - "DISCORD_DEV_VERIFY_CHANNEL_ID", - "DISCORD_PROD_SERVER_ID", - "DISCORD_PROD_VERIFY_CHANNEL_ID", - "DISCORD_SECRET_TOKEN", - "NODE_ENV", - "INTERNAL_AUTH_KEY", - "NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY", - "NEXT_PUBLIC_CLERK_SIGN_IN_URL", - "NEXT_PUBLIC_CLERK_SIGN_UP_URL", - "NEXT_PUBLIC_APP_URL", - "GITHUB_CLIENT_ID", - "GITHUB_CLIENT_SECRET", - "GOOGLE_CLIENT_ID", - "GOOGLE_CLIENT_SECRET", - "HACKKIT_BLOB_ADAPTER", - "HACKKIT_EMAIL_FROM", - "HACKKIT_EMAIL_PROVIDER", - "HACKKIT_EMAIL_REPLY_TO", - "HACKKIT_LOCAL_BLOB_BASE_DIR", - "HACKKIT_S3_ACCESS_KEY_ID", - "HACKKIT_S3_BUCKET", - "HACKKIT_S3_ENDPOINT", - "HACKKIT_S3_REGION", - "HACKKIT_S3_SECRET_ACCESS_KEY", - "S3_ACCESS_KEY_ID", - "S3_BUCKET", - "S3_ENDPOINT", - "S3_REGION", - "S3_SECRET_ACCESS_KEY", - "RESEND_API_KEY", - "SMTP_HOST", - "SMTP_PASSWORD", - "SMTP_PORT", - "SMTP_SECURE", - "SMTP_USERNAME", - "UPSTASH_REDIS_REST_TOKEN", - "UPSTASH_REDIS_REST_URL", - "TURSO_AUTH_TOKEN", - "TURSO_DATABASE_URL" + "$schema": "https://turbo.build/schema.json", + "globalDependencies": [ + "**/.env.*local" + ], + "globalEnv": [ + "AWS_ACCESS_KEY_ID", + "AWS_REGION", + "AWS_S3_BUCKET", + "AWS_S3_ENDPOINT", + "AWS_S3_REGION", + "AWS_SECRET_ACCESS_KEY", + "AWS_SES_ACCESS_KEY", + "AWS_SES_EMAIL_FROM", + "AWS_SES_SECRET_ACCESS_KEY", + "BACKUP_CRON_SCHEDULE", + "BACKUP_DATABASE_URL", + "BETTER_AUTH_SECRET", + "BETTER_AUTH_TRUSTED_ORIGINS", + "BETTER_AUTH_URL", + "BOT_API_URL", + "CLERK_SECRET_KEY", + "DATABASE_URL", + "DISCORD_CLIENT_ID", + "DISCORD_DEV_SERVER_ID", + "DISCORD_DEV_VERIFY_CHANNEL_ID", + "DISCORD_PROD_SERVER_ID", + "DISCORD_PROD_VERIFY_CHANNEL_ID", + "DISCORD_SECRET_TOKEN", + "NODE_ENV", + "INTERNAL_AUTH_KEY", + "NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY", + "NEXT_PUBLIC_CLERK_SIGN_IN_URL", + "NEXT_PUBLIC_CLERK_SIGN_UP_URL", + "NEXT_PUBLIC_APP_URL", + "GITHUB_CLIENT_ID", + "GITHUB_CLIENT_SECRET", + "GOOGLE_CLIENT_ID", + "GOOGLE_CLIENT_SECRET", + "HACKKIT_BLOB_ADAPTER", + "HACKKIT_EMAIL_FROM", + "HACKKIT_EMAIL_PROVIDER", + "HACKKIT_EMAIL_REPLY_TO", + "HACKKIT_LOCAL_BLOB_BASE_DIR", + "HACKKIT_S3_ACCESS_KEY_ID", + "HACKKIT_S3_BUCKET", + "HACKKIT_S3_ENDPOINT", + "HACKKIT_S3_REGION", + "HACKKIT_S3_SECRET_ACCESS_KEY", + "S3_ACCESS_KEY_ID", + "S3_BUCKET", + "S3_ENDPOINT", + "S3_REGION", + "S3_SECRET_ACCESS_KEY", + "RESEND_API_KEY", + "SMTP_HOST", + "SMTP_PASSWORD", + "SMTP_PORT", + "SMTP_SECURE", + "SMTP_USERNAME", + "UPSTASH_REDIS_REST_TOKEN", + "UPSTASH_REDIS_REST_URL", + "TURSO_AUTH_TOKEN", + "TURSO_DATABASE_URL" + ], + "tasks": { + "build": { + "dependsOn": [ + "^build" ], - "tasks": { - "build": { - "dependsOn": ["^build"], - "outputs": ["dist/**", ".next/**", "!.next/cache/**"], - "cache": true - }, - "test": { - "cache": true, - "dependsOn": ["^build"] - }, - "lint": {}, - "start": { - "cache": false, - "persistent": true, - "dependsOn": ["^build"] - }, - "dev": { - "dependsOn": ["^build"], - "cache": false, - "persistent": true - } - } + "outputs": [ + "dist/**", + ".next/**", + "!.next/cache/**", + "out/**", + "!dist/**/.dev.vars*", + "!dist/**/.env*" + ], + "cache": true + }, + "test": { + "cache": true, + "dependsOn": [ + "^build" + ] + }, + "lint": {}, + "start": { + "cache": false, + "persistent": true, + "dependsOn": [ + "^build" + ] + }, + "dev": { + "dependsOn": [ + "^build" + ], + "cache": false, + "persistent": true + }, + "typecheck": { + "dependsOn": [ + "^build" + ], + "outputs": [] + }, + "@hackkit/e2e#test": { + "cache": false + }, + "@hackkit/demo#build": { + "dependsOn": [ + "^build" + ], + "outputs": [ + "dist/**", + "!dist/**/.dev.vars*", + "!dist/**/.env*" + ], + "cache": false + } + } } From 1b0a0cd86d7dfe5ee0bd654b143aea62917e547f Mon Sep 17 00:00:00 2001 From: joshuasilva414 Date: Wed, 28 Oct 2026 12:21:51 -0500 Subject: [PATCH 2/5] ORM Changes - Templates don't come with migrations - Execution time ORM optimizations --- .tours/01-repository-map.tour | 4 +- .tours/02-core-startup.tour | 12 +- .tours/08-verification.tour | 12 +- .tours/README.md | 20 +- README.md | 22 +- apps/demo/.dev.vars.example | 2 +- apps/demo/app/app-bar.tsx | 2 +- apps/demo/db/migrations/sqlite/.snapshot.json | 4 +- .../Migration20261028120000_user_image.ts | 13 + apps/demo/vite.config.ts | 10 + apps/docs/content/docs/database.mdx | 8 +- apps/docs/content/docs/getting-started.mdx | 3 + apps/docs/content/docs/templates.mdx | 2 +- apps/docs/content/docs/testing.mdx | 2 +- docs/adr/0013-mikroorm-and-core-auth.md | 6 +- docs/guides/database-migrations.md | 12 +- docs/plans/template-distribution.md | 12 +- e2e/README.md | 18 +- e2e/database/database-workflow.test.ts | 12 +- e2e/database/dialects.test.ts | 18 +- e2e/database/migration-workflow.test.ts | 21 +- e2e/database/migration-workflow.ts | 14 +- e2e/database/templates.test.ts | 48 +- e2e/support/migrations.mjs | 17 + e2e/support/run.mjs | 6 +- e2e/support/server.mjs | 4 +- e2e/support/templates.mjs | 1 + .../core/src/__tests__/public-profile.test.ts | 2 +- packages/core/src/functions/events.ts | 23 +- packages/core/src/functions/users.ts | 4 +- packages/core/src/hackkit.ts | 661 +-- .../core/src/mikro/auth-lifecycle.test.ts | 4 +- packages/core/src/mikro/auth.ts | 3 +- packages/core/src/models.ts | 2 +- packages/core/src/runtime.test.ts | 74 + packages/core/src/runtime.ts | 21 +- packages/core/src/schemas.ts | 2 +- packages/core/src/testing.ts | 4 +- packages/core/src/types.ts | 2 +- .../ui/src/components/public-profile-card.tsx | 4 +- .../components/user-profile-settings-form.tsx | 10 +- packages/ui/src/types.ts | 2 +- templates/nextjs-full/.env.example | 3 + templates/nextjs-full/README.md | 32 +- templates/nextjs-full/app/app-bar.tsx | 2 +- .../db/migrations/mysql/.snapshot.json | 4483 ---------------- .../mysql/Migration20260927180400_initial.ts | 171 - .../db/migrations/postgresql/.snapshot.json | 4449 ---------------- .../Migration20260927180400_initial.ts | 167 - .../db/migrations/sqlite/.snapshot.json | 4525 ----------------- .../sqlite/Migration20260927180400_initial.ts | 119 - templates/nextjs-full/env.ts | 2 + templates/nextjs-full/lib/database-config.ts | 4 +- templates/nextjs-minimal/.env.example | 3 + templates/nextjs-minimal/README.md | 12 +- templates/nextjs-minimal/app/app-bar.tsx | 2 +- .../db/migrations/sqlite/.snapshot.json | 3334 ------------ .../sqlite/Migration20261020200349_initial.ts | 101 - templates/nextjs-minimal/env.ts | 1 + .../nextjs-minimal/lib/database-config.ts | 2 +- turbo.json | 1 + 61 files changed, 728 insertions(+), 17808 deletions(-) create mode 100644 apps/demo/db/migrations/sqlite/Migration20261028120000_user_image.ts create mode 100644 e2e/support/migrations.mjs delete mode 100644 templates/nextjs-full/db/migrations/mysql/.snapshot.json delete mode 100644 templates/nextjs-full/db/migrations/mysql/Migration20260927180400_initial.ts delete mode 100644 templates/nextjs-full/db/migrations/postgresql/.snapshot.json delete mode 100644 templates/nextjs-full/db/migrations/postgresql/Migration20260927180400_initial.ts delete mode 100644 templates/nextjs-full/db/migrations/sqlite/.snapshot.json delete mode 100644 templates/nextjs-full/db/migrations/sqlite/Migration20260927180400_initial.ts delete mode 100644 templates/nextjs-minimal/db/migrations/sqlite/.snapshot.json delete mode 100644 templates/nextjs-minimal/db/migrations/sqlite/Migration20261020200349_initial.ts diff --git a/.tours/01-repository-map.tour b/.tours/01-repository-map.tour index 799588472..aff33ebec 100644 --- a/.tours/01-repository-map.tour +++ b/.tours/01-repository-map.tour @@ -4,7 +4,7 @@ "steps": [ { "title": "What you will learn", - "description": "Start here with the repository root open in VS Code. These linked chapters explain the `templates-and-testing` working tree, including the template/E2E split. They use current files rather than a pinned commit, because the split includes uncommitted changes.\n\nFollow a participant who signs up, completes registration, creates a team, and receives event access. You will trace configuration into Core, then follow browser requests back to domain operations and persistence. Later chapters cover route generation, integrations, deployed apps, and verification.\n\nPrerequisites: TypeScript and basic React knowledge. An EntityManager is MikroORM's object for querying and tracking database records. A scope is one execution's EntityManager plus APIs that use it. Reading these tours does not start services, run migrations, or send external requests." + "description": "Start here with the repository root open in VS Code. These linked chapters explain the `templates-and-testing` working tree, including the template/E2E split. They use current files rather than a pinned commit. Recheck the relevant descriptions after changing schema or runtime behavior.\n\nFollow a participant who signs up, completes registration, creates a team, and receives event access. You will trace configuration into Core, then follow browser requests back to domain operations and persistence. Later chapters cover route generation, integrations, deployed apps, and verification.\n\nPrerequisites: TypeScript and basic React knowledge. An EntityManager is MikroORM's object for querying and tracking database records. A scope is one execution's EntityManager plus APIs that use it. Reading these tours does not start services, run migrations, or send external requests." }, { "file": "pnpm-workspace.yaml", @@ -52,7 +52,7 @@ "file": "templates/nextjs-minimal/hackkit.config.ts", "pattern": "export default defineHackkitConfig\\(\\{", "title": "Compare the minimal consumer", - "description": "The minimal template demonstrates Core registration, profiles, and administration without the full template's plugin set. Read its actual `plugins`, database, blob, and role configuration beside the full template.\n\nCore and Better Auth still need tables and migrations even when no feature plugins are enabled. The minimal template therefore has its own committed SQLite migration. Removing optional plugins does not remove the Core/auth lifecycle." + "description": "The minimal template demonstrates Core registration, profiles, and administration without the full template's plugin set. Read its actual plugins, database, blob, and role configuration beside the full template.\n\nCore and Better Auth still need tables when no feature plugins are enabled. Templates ship without migration history or snapshots. After selecting the database and plugins, a new application generates its own initial migration, reviews and applies it, and commits that history. Later clones apply the committed migrations. Removing optional plugins does not remove the Core/auth lifecycle." }, { "file": "packages/config/src/index.ts", diff --git a/.tours/02-core-startup.tour b/.tours/02-core-startup.tour index b63899bb9..a8d7c6e52 100644 --- a/.tours/02-core-startup.tour +++ b/.tours/02-core-startup.tour @@ -34,7 +34,7 @@ "file": "packages/core/src/mikro/auth.ts", "pattern": "export function resolveHackKitAuthOptions", "title": "Map Better Auth onto Core's user table", - "description": "The application provides auth settings, but Core forces the user model to `core_user` and maps Better Auth's `image` field to `profilePhotoUrl`. Core creates the MikroORM database adapter in `createHackKitAuth`.\n\nThis avoids a second application profile row that would need synchronization with the auth user. Credentials, session policy, and providers still come from host options. Domain privileges stay behind Core APIs." + "description": "The application provides auth settings, but Core forces the user model to `core_user`. Better Auth and Core both use `image` for the profile photo. Core creates the MikroORM database adapter in `createHackKitAuth`.\n\nThis avoids a second application profile row that would need synchronization with the auth user. Credentials, session policy, and providers still come from host options. Domain privileges stay behind Core APIs." }, { "file": "packages/core/src/mikro/auth.ts", @@ -46,25 +46,25 @@ "file": "packages/core/src/runtime.ts", "pattern": "function createScope\\(actorAuthId\\?: string\\)", "title": "Fork the EntityManager and construct scoped APIs", - "description": "Each call forks `orm.em` with context support and calls `createHackkit` using the fork, the shared registry, and the optional actor ID. A fork has its own identity map, the set of managed entity instances used by that execution.\n\nThe resulting scope contains `em` and `hackkit`. Plugin setup receives this same EntityManager. Do not retain this scoped API object as a global singleton. A later request must create its own scope." + "description": "Runtime initialization prepares configuration, validation schemas, and the registry once. Each call forks `orm.em` with context support and binds scoped APIs to the fork and optional actor ID. A fork has its own identity map, the set of managed entity instances used by that execution.\n\nThe resulting scope contains `em` and `hackkit`. Plugin setup receives this same EntityManager. Do not retain this scoped API object as a global singleton. A later request must create its own scope." }, { "file": "packages/core/src/runtime.ts", - "pattern": "return RequestContext\\.create\\(scope\\.em, \\(\\) => operation\\(scope\\)\\);", + "pattern": "return RequestContext\\.create\\(orm\\.em,", "title": "Run a non-render operation in an ORM context", - "description": "`run` creates a scope, then executes the callback inside MikroORM's RequestContext. The callback receives the scope and returns a promise whose result becomes the result of `run`.\n\nThe HTTP handler uses this path after resolving a session. Context-aware ORM operations can resolve the correct manager during async work. Creating a request context is not a transaction around the whole request; domain operations create transactions where required." + "description": "`run` lets MikroORM's RequestContext create one fork, then binds the scoped APIs to that active EntityManager before executing the callback. The callback receives the scope and returns a promise whose result becomes the result of `run`.\n\nThe HTTP handler uses this path after resolving a session. Context-aware ORM operations can resolve the correct manager during async work. Creating a request context is not a transaction around the whole request; domain operations create transactions where required." }, { "file": "packages/core/src/hackkit.ts", "pattern": "export function createHackkit", "title": "Assemble Core around explicit dependencies", - "description": "`createHackkit` accepts an existing EntityManager. It resolves clock, ID generator, registration choices, event types, groups, and logger. It creates access control, settings, notifications, plugin APIs, and the domain API groups.\n\nThe function returns methods, not a listening server. Tests can inject time and ID functions. HTTP and Next integrations decide how to obtain the actor and invoke these methods. Keep transport details out of this composition function." + "description": "`createHackkit` accepts an existing EntityManager. It prepares configuration through `createHackkitFactory`, then binds access control, settings, notifications, plugin APIs, and the domain API groups to that EntityManager. Runtime initialization reuses the factory across executions so configuration and validation schemas are prepared only once.\n\nThe function returns methods, not a listening server. Tests can inject time and ID functions. HTTP and Next integrations decide how to obtain the actor and invoke these methods. Keep transport details out of this composition function." }, { "file": "templates/nextjs-full/scripts/database.ts", "pattern": "export async function runDatabaseCommand", "title": "Keep schema changes explicit and application-owned", - "description": "The template's database command runner owns generate, migrate, rollback, status, check, seed, and reset operations. It uses `createOrmOptions`, so it sees Core/auth/plugin/app entities, and always closes the ORM in `finally`.\n\n`check` examines pending migration history, entity-versus-snapshot differences, and live schema SQL. `reset` is destructive and restricted to a local SQLite database in development or tests. Reading this tour does not invoke it. Migration directories remain in the template that owns the deployed database." + "description": "The template database runner owns generate, migrate, rollback, status, check, seed, and reset. It uses createOrmOptions so discovery includes Core/auth/plugin/app entities, and closes the ORM in finally.\n\nA new project first runs db:generate --name initial against an empty development database. It reviews, applies, and commits the generated migration and snapshot. Templates contain no baseline history. Existing application clones apply their committed history without regenerating it.\n\nThe check operation compares pending history, entities against the snapshot, and live schema SQL. Reset drops local SQLite tables in development or tests and replays the existing application history. Startup does not generate or apply migrations." }, { "file": "packages/core/src/seed.ts", diff --git a/.tours/08-verification.tour b/.tours/08-verification.tour index e5bd0a109..cebd5a64f 100644 --- a/.tours/08-verification.tour +++ b/.tours/08-verification.tour @@ -16,25 +16,25 @@ "file": "e2e/support/templates.mjs", "pattern": "export const templates = \\{", "title": "Point integration tests at the real templates", - "description": "The manifest names the full and minimal workspace packages, absolute directories, fixed ports, origins, and database dialect lists. Full targets SQLite/libSQL/PostgreSQL/MySQL; minimal targets SQLite.\n\nHelpers use these absolute locations rather than assuming the repository root is an application. This is the main architectural effect of the testing split: tests orchestrate real consumers and their committed migrations." + "description": "The manifest names the full and minimal workspace packages, absolute directories, fixed ports, origins, and database dialect lists. Full targets SQLite/libSQL/PostgreSQL/MySQL; minimal targets SQLite.\n\nHelpers use these absolute locations rather than assuming the repository root is an application. This is the main architectural effect of the testing split: tests orchestrate real consumers and generate migrations from each configured registry." }, { "file": "e2e/support/templates.mjs", "pattern": "export function testEnvironment", "title": "Build explicit disposable test configuration", - "description": "The helper constructs a limited environment with fresh database/upload paths, template-specific origins, and a test auth secret. Full-template external-service settings use disabled or non-service test values so Next's dotenv loading cannot silently select developer services.\n\nRead which variables are intentionally inherited and which are replaced. Test isolation depends on the actual environment passed to each subprocess, not just a temporary directory name." + "description": "The helper constructs a limited environment with fresh database/upload paths, template-specific origins, and a test auth secret. Full-template external-service settings use disabled or non-service test values so Next's dotenv loading cannot silently select developer services.\n\nRead which variables are intentionally inherited and which are replaced. Test isolation depends on the actual environment passed to each subprocess, not just a temporary directory name.\n\nHACKKIT_MIGRATIONS_PATH points to a temporary history alongside the database. It overrides the template default without changing host source files or copying template migrations. This lets each test exercise the same first-generation setup that a new application uses." }, { "file": "e2e/support/run.mjs", "pattern": "const suite = process\\.argv\\[2\\] \\?\\? \"all\";", "title": "Prepare dependencies before choosing integration suites", - "description": "The runner accepts all, db, http, or browser. It builds dependency packages, snapshots generated route files and lockfiles, runs plugin sync, and asserts no generated drift. It then typechecks both templates and E2E and invokes the client-bundle guard.\n\nHTTP/browser runs also migrate and seed disposable build databases and create real production template builds. Finally it runs the selected Vitest or Playwright suites. Running one E2E invocation at a time avoids collisions in fixed ports and template output directories." + "description": "The runner accepts all, db, http, or browser. It builds dependency packages, snapshots generated route files and lockfiles, runs plugin sync, and asserts no generated drift. It then typechecks both templates and E2E and invokes the client-bundle guard.\n\nHTTP/browser runs generate initial migrations into temporary directories, apply them, check schema agreement, and seed disposable build databases and create real production template builds. Finally it runs the selected Vitest or Playwright suites. Running one E2E invocation at a time avoids collisions in fixed ports and template output directories." }, { "file": "e2e/support/server.mjs", "pattern": "export async function startTemplate", "title": "Start production Next with fresh storage", - "description": "The helper rejects an occupied port, creates a temporary runtime directory, and runs migrations and seeding with the template as cwd. It starts `next start`, captures logs, and polls the auth session endpoint for readiness.\n\nIt never treats an arbitrary process on the same port as the test application. The returned close function stops the child and removes temporary storage. Startup failure also performs cleanup and includes captured output in its error." + "description": "The helper rejects an occupied port, creates a temporary runtime directory, and generates a fresh migration history, applies it, checks the schema, and seeds roles with the template as cwd. It starts `next start`, captures logs, and polls the auth session endpoint for readiness.\n\nIt never treats an arbitrary process on the same port as the test application. The returned close function stops the child and removes temporary storage. Startup failure also performs cleanup and includes captured output in its error." }, { "file": "e2e/playwright.config.ts", @@ -62,9 +62,9 @@ }, { "file": "e2e/database/templates.test.ts", - "pattern": "it\\(\"minimal: real config and committed migrations initialize Core/auth without plugins\"", + "pattern": "it\\(\"minimal: generates and replays a Core/auth baseline without plugins\"", "title": "Validate the minimal schema without feature plugins", - "description": "This test loads the real minimal config and committed migrations, then initializes Core/auth without feature plugins. It checks the split at the application/configuration boundary.\n\nThe parameterized test above covers storage isolation, sync without connecting, and reset restrictions. Other files in e2e/database cover dialect and migration workflows. Inspect matrix environment requirements before treating skipped network dialect tests as verified coverage." + "description": "This test loads the real minimal config, generates a Core/auth baseline into a temporary history, applies it, and initializes Core/auth without feature plugins. It verifies signup and schema agreement, then replays the same history into another empty database without regenerating it.\n\nThe parameterized test above validates both templates' first-generation command flow. It inspects generated Core/plugin SQL and snapshot creation, confirms generation has not applied the tables, and checks that unchanged generation after setup produces no migration. Existing upgrade tests continue to exercise data transformations, rollback, and history replay." }, { "file": ".github/workflows/integration.yml", diff --git a/.tours/README.md b/.tours/README.md index b9f3e36d2..3d6d64efc 100644 --- a/.tours/README.md +++ b/.tours/README.md @@ -2,18 +2,18 @@ Open the repository root in VS Code with the CodeTour extension enabled. In the Explorer's CodeTour view, start **01. Repository map and composition**. It is the primary tour. Each chapter names the next tour, and linked tour titles let you jump between topics. -These tours describe the `templates-and-testing` working tree, including its uncommitted template/E2E split. They do not pin a Git ref. Paths and regex anchors refer to the current files. Read them with the repository root as the workspace folder. +These tours describe the `templates-and-testing` working tree and its template/E2E split. They do not pin a Git ref. Paths and regex anchors refer to the current files. Read them with the repository root as the workspace folder. The walkthrough has 8 chapters and 117 steps. Each step explains the role of the selected code, its inputs and outputs, important checks, and the next boundary where relevant. No step runs a command or edits source automatically. -- [01. Repository map and composition](01-repository-map.tour) (11 steps) -- [02. Core startup and persistence](02-core-startup.tour) (13 steps) -- [03. Core domain behavior](03-core-domain.tour) (19 steps) -- [04. Plugin contracts and Teams](04-plugin-system.tour) (16 steps) -- [05. CLI and plugin page installation](05-cli-route-sync.tour) (9 steps) -- [06. HTTP, Next integration, and browser UI](06-request-flow.tour) (18 steps) -- [07. Notifications, Discord, storage, and deployed apps](07-integrations-apps.tour) (17 steps) -- [08. Verification and change guide](08-verification.tour) (14 steps) +- [01. Repository map and composition](01-repository-map.tour) (11 steps) +- [02. Core startup and persistence](02-core-startup.tour) (13 steps) +- [03. Core domain behavior](03-core-domain.tour) (19 steps) +- [04. Plugin contracts and Teams](04-plugin-system.tour) (16 steps) +- [05. CLI and plugin page installation](05-cli-route-sync.tour) (9 steps) +- [06. HTTP, Next integration, and browser UI](06-request-flow.tour) (18 steps) +- [07. Notifications, Discord, storage, and deployed apps](07-integrations-apps.tour) (17 steps) +- [08. Verification and change guide](08-verification.tour) (14 steps) The Core chapters explain shared initialization, per-execution EntityManagers, canonical auth users, registration, role hierarchy, settings, RSVP, check-in, groups, and transaction locking. The plugin chapter follows Teams through declarations, inferred API types, scoped setup, persistence, endpoints, forms, and server pages. Later chapters explain CLI route sync, request handling, notifications, Discord, storage, the demo Worker, docs, and the test suites. @@ -23,4 +23,4 @@ For a focused first pass on the plugin system, read chapters 01, 02, 04, 05, and The CodeTour anchor checker verifies all local files and unique regex matches. Additional checks verify tour sequencing, tour-title links, local Markdown links, and the installed extension's JSON schema. Source review checks descriptions against implementation. Editor playback has not been exercised, so discovery, comment placement, and rendered links still need a VS Code playback check. -Application tests are described as evidence to inspect. They were not run for this documentation-only change. Creating the tours does not verify current service credentials, deployment state, or hosted behavior. The tours do not install an extension or change workspace trust. +Application tests are described as evidence to inspect. Tour anchor checks do not execute those suites; consult the verification report for the code change being reviewed. Creating the tours does not verify current service credentials, deployment state, or hosted behavior. The tours do not install an extension or change workspace trust. diff --git a/README.md b/README.md index e5d438b40..ccf2a1fee 100644 --- a/README.md +++ b/README.md @@ -10,16 +10,16 @@ ## Technologies Used -- TypeScript -- Next.js -- MikroORM -- Better Auth -- Tailwind CSS +- TypeScript +- Next.js +- MikroORM +- Better Auth +- Tailwind CSS ## Demo and documentation -- [Interactive demo](https://hackkit-demo.acm-utsa.workers.dev): explore a shared fictional event as a participant or organizer. [Deployment and local setup](apps/demo/README.md). -- [Documentation](https://hackkit-docs.acm-utsa.workers.dev): setup, templates, architecture, plugins, operations, and testing. [Contributing to the docs](apps/docs/README.md). +- [Interactive demo](https://hackkit-demo.acm-utsa.workers.dev): explore a shared fictional event as a participant or organizer. [Deployment and local setup](apps/demo/README.md). +- [Documentation](https://hackkit-docs.acm-utsa.workers.dev): setup, templates, architecture, plugins, operations, and testing. [Contributing to the docs](apps/docs/README.md). Configure the demo’s Turso credentials in `apps/demo/.dev.vars` and run its explicit database setup first; see [demo setup](apps/demo/README.md). `corepack pnpm dev:demo` then starts the demo on port 3001. `corepack pnpm dev:docs` starts Fumadocs on port 3002. The deployed apps live under `apps`; runnable workspace examples remain under `templates`. @@ -27,11 +27,11 @@ Configure the demo’s Turso credentials in `apps/demo/.dev.vars` and run its ex Use Node.js 22.17+ and the repository-pinned pnpm 12.15.0 through Corepack. Run `corepack pnpm install` from this directory. -- [Full Next.js template](templates/nextjs-full/README.md): the existing app with Teams, Discord, email notifications, and configurable storage. -- [Minimal Next.js template](templates/nextjs-minimal/README.md): Core registration, participant profiles, and basic administration with local SQLite and uploads. -- [E2E validation](e2e/README.md): database, production HTTP, and browser integration checks against these templates. +- [Full Next.js template](templates/nextjs-full/README.md): the existing app with Teams, Discord, email notifications, and configurable storage. +- [Minimal Next.js template](templates/nextjs-minimal/README.md): Core registration, participant profiles, and basic administration with local SQLite and uploads. +- [E2E validation](e2e/README.md): database, production HTTP, and browser integration checks against these templates. -`corepack pnpm dev` and `corepack pnpm dev:full` start the full template. `corepack pnpm dev:minimal` starts the minimal template. Root `db:*` commands target the full template. Select the minimal package explicitly for its database commands. Each template's README covers migrations, seeding, owner bootstrap, and production configuration. +`corepack pnpm dev` and `corepack pnpm dev:full` start the full template. `corepack pnpm dev:minimal` starts the minimal template. Root `db:*` commands target the full template. Select the minimal package explicitly for its database commands. For a new project, configure the database and plugins, generate an initial migration with `db:generate --name initial`, review and apply it, then seed roles. Commit the generated migration and snapshot to your application repository. Templates ship without baseline migrations; later clones of an initialized application apply its committed history. Each template's README covers setup, owner bootstrap, and production configuration. `corepack pnpm build` builds libraries, templates, demo, and docs; configure each template for production first. `corepack pnpm test` runs package tests. `corepack pnpm test:e2e` prepares isolated configurations and runs all integration suites. Run one E2E invocation at a time because tests use fixed ports and each template's production output. diff --git a/apps/demo/.dev.vars.example b/apps/demo/.dev.vars.example index 91f98c179..6167600b2 100644 --- a/apps/demo/.dev.vars.example +++ b/apps/demo/.dev.vars.example @@ -3,4 +3,4 @@ TURSO_DATABASE_URL=libsql://your-database.turso.io TURSO_AUTH_TOKEN= BETTER_AUTH_SECRET= # Local application origin. The deployed origin lives in wrangler.jsonc. -BETTER_AUTH_URL=http://localhost:3001 +BETTER_AUTH_URL=http://localhost:3001 \ No newline at end of file diff --git a/apps/demo/app/app-bar.tsx b/apps/demo/app/app-bar.tsx index 55c9035d9..f30f080dc 100644 --- a/apps/demo/app/app-bar.tsx +++ b/apps/demo/app/app-bar.tsx @@ -43,7 +43,7 @@ export async function AppBar() { name={session.user.name} email={session.user.email} image={ - currentUser?.profilePhotoUrl ?? + currentUser?.image ?? session.user.image } isAdmin={isAdmin} diff --git a/apps/demo/db/migrations/sqlite/.snapshot.json b/apps/demo/db/migrations/sqlite/.snapshot.json index 07e423cd6..362f4d909 100644 --- a/apps/demo/db/migrations/sqlite/.snapshot.json +++ b/apps/demo/db/migrations/sqlite/.snapshot.json @@ -2405,8 +2405,8 @@ "enumItems": [], "mappedType": "text" }, - "profile_photo_url": { - "name": "profile_photo_url", + "image": { + "name": "image", "type": "text", "unsigned": false, "autoincrement": false, diff --git a/apps/demo/db/migrations/sqlite/Migration20261028120000_user_image.ts b/apps/demo/db/migrations/sqlite/Migration20261028120000_user_image.ts new file mode 100644 index 000000000..17a095666 --- /dev/null +++ b/apps/demo/db/migrations/sqlite/Migration20261028120000_user_image.ts @@ -0,0 +1,13 @@ +import { Migration } from "@mikro-orm/migrations"; + +export class Migration20261028120000_user_image extends Migration { + override name = "Migration20261028120000_user_image"; + + override up(): void { + this.addSql("alter table `core_user` rename column `profile_photo_url` to `image`;"); + } + + override down(): void { + this.addSql("alter table `core_user` rename column `image` to `profile_photo_url`;"); + } +} diff --git a/apps/demo/vite.config.ts b/apps/demo/vite.config.ts index 2003b30b5..e8479eff5 100644 --- a/apps/demo/vite.config.ts +++ b/apps/demo/vite.config.ts @@ -3,6 +3,16 @@ import vinext from "vinext"; import { cloudflare } from "@cloudflare/vite-plugin"; export default defineConfig({ + optimizeDeps: { + // Zod 3 in HackKit and Zod 4 in Better Auth must resolve per importer. + // MikroORM's optional filesystem imports cannot be prebundled for Workers. + exclude: [ + "zod", + "@mikro-orm/core", + "@mikro-orm/sql", + "@mikro-orm/migrations", + ], + }, plugins: [ vinext(), cloudflare({ diff --git a/apps/docs/content/docs/database.mdx b/apps/docs/content/docs/database.mdx index 8a9ac251f..5025c6868 100644 --- a/apps/docs/content/docs/database.mdx +++ b/apps/docs/content/docs/database.mdx @@ -5,6 +5,12 @@ description: "Use reviewed migrations and explicit administrative commands." Core uses MikroORM's native entity registry. Migration files and snapshots belong to the application because its plugin registry determines its schema. +## First setup + +Templates ship without migrations or snapshots. Configure an empty development database and select the plugins before running the selected application's `db:generate --name initial`. Review and apply the generated migration, seed roles, then commit the migration and snapshot to your application repository. + +Run initial generation once for a new project. Later clones and deployments apply its committed history. Existing applications, including the demo, keep their history. Initial generation does not replace an upgrade or data migration. + ## Routine commands From the repository root, `corepack pnpm db:migrate` and `corepack pnpm db:seed` target full. Seed creates configured roles and does not assign an owner. @@ -28,4 +34,4 @@ After changing registered entities, run `db:generate` in the selected applicatio ## Drivers -Full supports SQLite, libSQL, PostgreSQL, and MySQL. Integration coverage includes both local and HTTP libSQL. Minimal intentionally uses SQLite. Each template has its own migrations. Do not copy full's plugin tables into minimal. +Full supports SQLite, libSQL, PostgreSQL, and MySQL. Integration coverage includes both local and HTTP libSQL. Minimal intentionally uses SQLite. Each application generates and maintains the history for its own selected database and plugins. `HACKKIT_MIGRATIONS_PATH` optionally overrides the default directory. Do not copy full's plugin tables into minimal. diff --git a/apps/docs/content/docs/getting-started.mdx b/apps/docs/content/docs/getting-started.mdx index 42c2f2bff..ed2fb0a7a 100644 --- a/apps/docs/content/docs/getting-started.mdx +++ b/apps/docs/content/docs/getting-started.mdx @@ -18,11 +18,14 @@ corepack pnpm exec turbo run build --filter='./packages/*' ```sh cp templates/nextjs-minimal/.env.example templates/nextjs-minimal/.env corepack pnpm --filter @hackkit/template-nextjs-minimal plugin:sync +corepack pnpm --filter @hackkit/template-nextjs-minimal db:generate --name initial corepack pnpm --filter @hackkit/template-nextjs-minimal db:migrate corepack pnpm --filter @hackkit/template-nextjs-minimal db:seed corepack pnpm dev:minimal ``` +Review the generated migration before applying it. Commit the migration and snapshot to your application repository. Templates ship without migration history. Generate the initial baseline only for a new project; later clones apply the existing history. + Open [localhost:3000](http://localhost:3000). Create an account and complete HackTag, user data, and hacker registration. No cloud credentials are needed for local development. The committed `.env.example` documents the variables. The local `.env` is empty until you configure it and is ignored by Git. diff --git a/apps/docs/content/docs/templates.mdx b/apps/docs/content/docs/templates.mdx index fb99abbaa..46b192781 100644 --- a/apps/docs/content/docs/templates.mdx +++ b/apps/docs/content/docs/templates.mdx @@ -14,7 +14,7 @@ description: "Choose a starting point without changing the shared libraries." | Schedule, RSVP, passes, scanners | No | Yes | | Production S3 adapter | No | Yes | -The examples live at `templates/nextjs-minimal` and `templates/nextjs-full`. Each owns its pages, configuration, database scripts, and migrations. Neither imports the other or E2E support. +The examples live at `templates/nextjs-minimal` and `templates/nextjs-full`. Each provides pages, configuration, and database scripts. A new application generates its own initial migration and snapshot after selecting a database and plugins, then commits and maintains that history. Templates ship without pre-generated migrations. Neither imports the other or E2E support. Minimal registers no plugins. It seeds participant and owner roles with Core permissions. Full registers Teams, Discord, and email notifications, with provider choices in its configuration. diff --git a/apps/docs/content/docs/testing.mdx b/apps/docs/content/docs/testing.mdx index ab26edb1f..d5b6ac8d9 100644 --- a/apps/docs/content/docs/testing.mdx +++ b/apps/docs/content/docs/testing.mdx @@ -19,7 +19,7 @@ corepack pnpm --filter @hackkit/e2e exec playwright install chromium corepack pnpm test:e2e ``` -The runner builds libraries, synchronizes plugins, checks generated-file drift, typechecks, prepares disposable build databases, and builds both templates once. Runtime fixtures use fresh databases and uploads. They do not reuse developer `.env` values or databases. +The runner builds libraries, synchronizes plugins, checks generated-file drift, typechecks, generates temporary migration histories, prepares and checks disposable build databases, and builds both templates once. Runtime fixtures use fresh databases and uploads. They do not reuse developer `.env` values or databases. Use `test:e2e:db`, `test:e2e:http`, or `test:e2e:browser` for a selected suite. Browser and HTTP checks use one Playwright worker, no automatic retries, and ports 33017 and 33018. An occupied port fails instead of attaching to another server. diff --git a/docs/adr/0013-mikroorm-and-core-auth.md b/docs/adr/0013-mikroorm-and-core-auth.md index 5b6f33112..be91e6972 100644 --- a/docs/adr/0013-mikroorm-and-core-auth.md +++ b/docs/adr/0013-mikroorm-and-core-auth.md @@ -10,13 +10,13 @@ Core and server plugins use native MikroORM `defineEntity` definitions and `Enti Core's `src/runtime.ts` owns HackKit initialization, shared authentication, logging, and execution scopes. `src/mikro/options.ts` owns native ORM options and driver types. Both remain available through the `@hackkit/core` package entrypoint. -One ORM owns shared connections. Each request, action, job, or CLI operation gets a fresh EntityManager. `runtime.createScope(actorAuthId)` binds domain and plugin APIs; `runtime.run(callback, actorAuthId)` also provides MikroORM RequestContext. Transactions use a fresh identity map and clear the parent map on completion. Domain responses are plain DTOs; managed entities and authentication secrets stay on the server. Browser code imports `@hackkit/core/client`. +One ORM owns shared connections. Runtime initialization prepares domain configuration, validation schemas, and the logger once. Scoped APIs reuse that preparation while binding an execution-specific EntityManager and actor ID. Each request, action, job, or CLI operation gets a fresh EntityManager. `runtime.createScope(actorAuthId)` binds domain and plugin APIs; `runtime.run(callback, actorAuthId)` also provides MikroORM RequestContext and binds APIs directly to its single fork. Transactions use a fresh identity map and clear the parent map on completion. Domain responses are plain DTOs; managed entities and authentication secrets stay on the server. Browser code imports `@hackkit/core/client`. ## Authentication Core constructs Better Auth with `@a77ay/better-auth-mikro-orm`. Better Auth still declares its own unused Drizzle adapter as an upstream dependency; HackKit does not import it, and `drizzle-orm` is absent from the resolved dependency graph. This community MikroORM adapter is pinned alongside Better Auth and MikroORM and covered by real database tests. Apps provide secrets, providers, trusted origins, email behavior, and optional auth plugins. Next owns request headers, cookies, redirects, and auth route handlers. -`HackKitUser` is the canonical native entity in `core_user`. It stores the Better Auth identity fields and HackKit profile, role, approval, and check-in fields in one row. Better Auth maps its user model to `core_user` and its `image` field to `profilePhotoUrl`. The primary key is `id`; Core's inferred user DTO, public profiles, and admin exports expose this same property through native serialization. Sessions, accounts, and all domain/plugin user foreign keys reference this row. +`HackKitUser` is the canonical native entity in `core_user`. It stores the Better Auth identity fields and HackKit profile, role, approval, and check-in fields in one row. Better Auth maps its user model to `core_user`. Its `image` field uses the same name in the native entity and Core APIs. The primary key is `id`; Core's inferred user DTO, public profiles, and admin exports expose this same property through native serialization. Sessions, accounts, and all domain/plugin user foreign keys reference this row. Consumers of the former user DTO must replace `user.authId` with `user.id`. The admin CSV identifier column is now `id`. Hacker records and the `registerHacker` input use `userId`, which references the same user primary key. The hacker entity retains its mapping to the committed `auth_id` database column. Other operation inputs such as `authId`, `actorAuthId`, and `targetAuthId` still accept the user ID. These contract changes require no database migration. @@ -44,7 +44,7 @@ The [migration guide](../guides/database-migrations.md) specifies staged upgrade ## Validation -The app database matrix applies committed migrations and tests real SQLite, local libSQL, PostgreSQL, MySQL, and HTTP libSQL. It checks schema agreement, signup/session/profile behavior, native JSON/date/boolean/null values, rollback, concurrent registration capacity, teams, uniqueness, and foreign-key cleanup. Package tests cover domain authorization, request isolation, notification claims, and membership conflicts. CI requires external service URLs so those cases cannot silently skip. +The app database matrix generates a baseline from the configured entity registry, applies it, and tests real SQLite, local libSQL, PostgreSQL, MySQL, and HTTP libSQL. It checks schema agreement, signup/session/profile behavior, native JSON/date/boolean/null values, rollback, concurrent registration capacity, teams, uniqueness, and foreign-key cleanup. Package tests cover domain authorization, request isolation, notification claims, and membership conflicts. CI requires external service URLs so those cases cannot silently skip. Use Node.js 22.17 or newer and TypeScript 5.9.3. Production validation must also cover the deployment's credentials, TLS, OAuth providers, and external email/Discord services. diff --git a/docs/guides/database-migrations.md b/docs/guides/database-migrations.md index d61aa100d..d79499cdc 100644 --- a/docs/guides/database-migrations.md +++ b/docs/guides/database-migrations.md @@ -4,6 +4,14 @@ The application owns one ordered migration history for Core, Better Auth, instal The scripts live in `templates/nextjs-full/scripts/database.ts`, with `scripts/db.mjs` as the Node entry point. They use MikroORM's native migrator and its `mikro_orm_migrations` history table. They do not call the HackKit CLI. Plugin route/action synchronization continues to use the existing CLI. +## Initialize a new application + +Templates ship without migration files or schema snapshots. After configuring the database, plugins, and application entities, select an empty development database and run the selected template's `db:generate --name initial`. Review the generated TypeScript migration and snapshot, apply it with `db:migrate`, and insert roles with `db:seed`. Commit the migration and snapshot to the consuming application's repository. + +Generation proposes SQL; it does not apply the application tables. Without a snapshot it needs a reachable database to inspect the starting schema. Use an empty database for the initial baseline. Do not use this new-project procedure to replace an existing application's migration history or adopt an already-populated database. + +After the first setup, other developers and deployment jobs apply the committed history with `db:migrate`. Generate again only when registered entities change. The deployed demo is an existing application and retains its committed history. + ## Commands Run from the repository root after installing dependencies and building workspace packages: @@ -23,7 +31,7 @@ Run from the repository root after installing dependencies and building workspac Every command accepts `--config path/to/hackkit.config.ts` and optional `--output path/to/result.json`. The output file contains the command result separately from driver diagnostics; a failed `check` still writes its result and exits with status 1. The entry point loads `.env` files with Next's environment precedence before loading the config. Explicit shell environment variables take precedence. Configuration paths and relative database paths are resolved from the application directory. -The selected dialect determines the migration directory. PostgreSQL, MySQL, and SQLite have separate histories in `templates/nextjs-full/db/migrations`; libSQL uses the SQLite history. Generate and test each supported history when changing a shared entity. A generated migration for one dialect is not a replacement for the other dialects' histories. +The selected dialect determines the default migration directory under `db/migrations`: `postgresql`, `mysql`, or `sqlite`; libSQL uses the SQLite dialect directory. These directories and snapshots are created during generation. `HACKKIT_MIGRATIONS_PATH` overrides the path, relative to the application or absolute. E2E uses this override for temporary histories. An application maintains only the dialects it supports. If it supports several, generate and test each history; SQL generated for one dialect does not replace another dialect's history. `status` and `check` use native migration history APIs. These APIs may create the tracking table if it does not exist. They do not apply application migrations or seed data. A database connection failure is an error, not a successful status check. Generation can use a committed snapshot without connecting; without a snapshot, MikroORM needs a database for its starting schema. @@ -90,7 +98,7 @@ Reset rejects production and all non-SQLite drivers, including local libSQL. It ## Validation -`corepack pnpm test:e2e:db` exercises the app scripts against SQLite/local libSQL. It checks existing-data expansion/backfill/contraction, staged migration, plugin upgrade, rollback/reapply, live drift, disabled-schema retention, destructive uninstall proposals, fresh replay, and reset/seed behavior. +`corepack pnpm test:e2e:db` generates a fresh baseline from each selected configuration and exercises the app scripts against SQLite/local libSQL. Generated histories and snapshots stay in temporary directories. It verifies generation without applying tables, schema agreement after migration, unchanged generation as a no-op, and fresh replay of the application history. It checks existing-data expansion/backfill/contraction, staged migration, plugin upgrade, rollback/reapply, live drift, disabled-schema retention, destructive uninstall proposals, fresh replay, and reset/seed behavior. `corepack pnpm test:e2e:db` runs the same upgrade flow after auth/domain validation on each configured target. CI requires PostgreSQL, MySQL, and HTTP libSQL URLs; missing local targets are reported as skipped. Test URLs must name empty, disposable databases. The native libSQL client can hang when repeatedly creating and destroying ORM instances in one Node process. The HTTP upgrade test uses one Node process per command, matching the utility scripts’ release-job lifecycle. Do not run a sequence of these commands inside a long-lived application process. Hosted Turso authentication/TLS and deployment-specific runtime behavior need separate validation. diff --git a/docs/plans/template-distribution.md b/docs/plans/template-distribution.md index ffdfeb3f7..08b847f18 100644 --- a/docs/plans/template-distribution.md +++ b/docs/plans/template-distribution.md @@ -6,11 +6,11 @@ The next distribution milestone will add `hackkit init --template mi Required work: -- Establish public package metadata, dependency versions, release versioning, and npm scope access before publication. -- Include distributable template assets with the CLI and substitute released package versions for workspace references. -- Make application scripts and Tailwind content discovery work without monorepo source paths. -- Keep each template's configuration, database commands, reviewed migrations, and setup documentation inside the generated project. -- Validate packed packages and both generated projects outside the monorepo. Verify initialization, dependency installation, plugin synchronization, migrations, seeding, typechecking, and production builds without workspace symlinks. -- Review the release artifacts before publishing. Define the first release version, registry ownership, authentication, and publishing workflow as part of that milestone. +- Establish public package metadata, dependency versions, release versioning, and npm scope access before publication. +- Include distributable template assets with the CLI and substitute released package versions for workspace references. +- Make application scripts and Tailwind content discovery work without monorepo source paths. +- Include each template's configuration, database commands, and setup documentation. After database/plugin selection, generate the new application's initial migration and snapshot against an empty development database. Do not distribute a pre-generated template migration history. The application commits its generated history and maintains future migrations. +- Validate packed packages and both generated projects outside the monorepo. Verify initialization, dependency installation, plugin synchronization, migrations, seeding, typechecking, and production builds without workspace symlinks. +- Review the release artifacts before publishing. Define the first release version, registry ownership, authentication, and publishing workflow as part of that milestone. Acceptance requires a working fresh project from the distributed CLI for each template. An in-workspace build alone does not establish standalone readiness. diff --git a/e2e/README.md b/e2e/README.md index f89acf35a..2efd6b0a1 100644 --- a/e2e/README.md +++ b/e2e/README.md @@ -10,15 +10,15 @@ From the repository root, use Node.js 22.17+ and pinned pnpm 12.15.0: 2. Install Chromium with `corepack pnpm --filter @hackkit/e2e exec playwright install chromium`. On Linux CI, add `--with-deps`. 3. Run `corepack pnpm test:e2e`. -Choose `test:e2e:db`, `test:e2e:http`, or `test:e2e:browser` to run a focused suite. The runner builds library dependencies, checks plugin sync for changes, typechecks templates and E2E, and checks both browser bundles. HTTP/browser suites also migrate and seed temporary build databases and build both production apps once. Runtime databases are separate from build databases. +Choose `test:e2e:db`, `test:e2e:http`, or `test:e2e:browser` to run a focused suite. The runner builds library dependencies, checks plugin sync for changes, typechecks templates and E2E, and checks both browser bundles. HTTP/browser suites also generate initial migrations, migrate and check the schema, seed temporary build databases and build both production apps once. Runtime databases are separate from build databases. -Stop template development servers before testing, and run one E2E invocation at a time. The fixtures use loopback ports 33017 for full and 33018 for minimal, refuse occupied ports, and never reuse an existing server. Each worker gets a new temporary database and upload directory. Application commands run from the selected template's directory using explicit test configuration. No developer database or uploads are selected. One Chromium worker runs without retries; browser sessions and accounts are independent. Each test supplies a distinct simulated proxy client IP so production authentication rate limits remain enabled without sharing one test-client bucket. +Stop template development servers before testing, and run one E2E invocation at a time. The fixtures use loopback ports 33017 for full and 33018 for minimal, refuse occupied ports, and never reuse an existing server. Each worker gets a new temporary database, migration history, snapshot, and upload directory. Generated migrations resolve dependencies through a temporary node_modules link. No test writes migration files into the templates. Application commands run from the selected template's directory using explicit test configuration. No developer database or uploads are selected. One Chromium worker runs without retries; browser sessions and accounts are independent. Each test supplies a distinct simulated proxy client IP so production authentication rate limits remain enabled without sharing one test-client bucket. ## Coverage -- `database`: committed migrations, auth/domain integration, schema upgrades, drift, rollback/reapply, plugin retention, concurrency, and real application command isolation. -- `http`: production cookies/sessions, access control, Core and plugin mutations, actor rejection, and JSON serialization. Playwright API tests do not launch a browser. -- `browser`: signup and complete onboarding, persisted registration, signout/signin, participant/admin guards, approval state, owner access, and full-template team invitations across sessions. +- `database`: initial generation, snapshot creation, migration replay, auth/domain integration, schema upgrades, drift, rollback/reapply, plugin retention, concurrency, and real application command isolation. +- `http`: production cookies/sessions, access control, Core and plugin mutations, actor rejection, and JSON serialization. Playwright API tests do not launch a browser. +- `browser`: signup and complete onboarding, persisted registration, signout/signin, participant/admin guards, approval state, owner access, and full-template team invitations across sessions. E2E-only database helpers promote known test user IDs and configure approval. Applications expose no testing or bootstrap endpoints. Tests that change approval settings restore them in teardown. External OAuth, hosted Turso authentication/TLS, email delivery, Discord role synchronization, and S3 operations require separate deployment validation. @@ -26,11 +26,11 @@ E2E-only database helpers promote known test user IDs and configure approval. Ap SQLite and local libSQL run locally. Supply URLs for empty, disposable external databases to add: -- `HACKKIT_TEST_POSTGRESQL_URL` -- `HACKKIT_TEST_MYSQL_URL` -- `HACKKIT_TEST_LIBSQL_URL` +- `HACKKIT_TEST_POSTGRESQL_URL` +- `HACKKIT_TEST_MYSQL_URL` +- `HACKKIT_TEST_LIBSQL_URL` -Set `HACKKIT_REQUIRE_DATABASE_MATRIX=1` to fail if any URL is missing. CI requires all five targets. The full template runs the multi-driver migration/upgrade suite; the minimal template uses its own SQLite schema. HTTP libSQL migration commands retain one Node process per operation to avoid native-client lifecycle hangs. +Set `HACKKIT_REQUIRE_DATABASE_MATRIX=1` to fail if any URL is missing. CI requires all five targets. The full template runs the multi-driver migration/upgrade suite; the minimal template generates its own Core/auth SQLite baseline. HTTP libSQL migration commands retain one Node process per operation to avoid native-client lifecycle hangs. ## Diagnostics diff --git a/e2e/database/database-workflow.test.ts b/e2e/database/database-workflow.test.ts index d8b673eec..8325a3e0c 100644 --- a/e2e/database/database-workflow.test.ts +++ b/e2e/database/database-workflow.test.ts @@ -1,4 +1,4 @@ -import { templates } from "../support/templates.mjs"; +import { prepareMigrationDirectory } from "../support/migrations.mjs"; import { mkdtemp, rm } from "node:fs/promises"; import { join } from "node:path"; import { tmpdir } from "node:os"; @@ -8,7 +8,7 @@ import { SqliteDriver } from "@mikro-orm/sqlite"; import { expect, it } from "vitest"; import appConfig from "../../templates/nextjs-full/hackkit.config"; -it("runs Core, plugins, and Better Auth against committed app migrations", async () => { +it("generates an application baseline and runs Core, plugins, and Better Auth", async () => { const directory = await mkdtemp(join(tmpdir(), "hackkit-web-db-")); const config = { ...appConfig, @@ -18,7 +18,9 @@ it("runs Core, plugins, and Better Auth against committed app migrations", async dbName: join(directory, "web.db"), clientUrl: undefined, migrations: { - path: join(templates.full.directory, "db/migrations/sqlite"), + path: await prepareMigrationDirectory(directory), + emit: "ts" as const, + snapshotName: ".snapshot", snapshotOnMigrate: false, }, }, @@ -30,6 +32,10 @@ it("runs Core, plugins, and Better Auth against committed app migrations", async logger: { disabled: true }, }; try { + await runDatabaseCommand(config, { + command: "generate", + name: "initial", + }); await runDatabaseCommand(config, { command: "migrate" }); await runDatabaseCommand(config, { command: "seed" }); const core = await initializeHackkit(config); diff --git a/e2e/database/dialects.test.ts b/e2e/database/dialects.test.ts index 6f4c9d7d8..da015c0a8 100644 --- a/e2e/database/dialects.test.ts +++ b/e2e/database/dialects.test.ts @@ -1,4 +1,4 @@ -import { templates } from "../support/templates.mjs"; +import { prepareMigrationDirectory } from "../support/migrations.mjs"; import { mkdtemp, rm } from "node:fs/promises"; import { tmpdir } from "node:os"; import { join } from "node:path"; @@ -81,11 +81,9 @@ for (const target of targets) { ? { dbName: target.url! } : { clientUrl: target.url! }), migrations: { - path: join( - templates.full.directory, - "db/migrations", - target.dialect, - ), + path: await prepareMigrationDirectory(directory), + emit: "ts" as const, + snapshotName: ".snapshot", snapshotOnMigrate: false, ...(target.driver === MySqlDriver ? { transactional: false, allOrNothing: false } @@ -104,6 +102,10 @@ for (const target of targets) { logger: { disabled: true }, }; try { + await runDatabaseCommand(config, { + command: "generate", + name: "initial", + }); await runDatabaseCommand(config, { command: "migrate" }); await runDatabaseCommand(config, { command: "seed" }); const core = await initializeHackkit(config); @@ -263,7 +265,7 @@ for (const target of targets) { await participant.hackkit.users.updateProfile({ authId: hacker.userId, name: "Edited Name", - profilePhotoUrl: "/api/files/view/photo.png", + image: "/api/files/view/photo.png", }); expect( (await core.auth.api.getSession({ headers }))?.user, @@ -285,7 +287,7 @@ for (const target of targets) { .hackkit.users.getUser(hacker.userId), ).toMatchObject({ name: "Auth Edit", - profilePhotoUrl: "https://example.com/photo.png", + image: "https://example.com/photo.png", roleId: "core.participant", isApproved: true, }); diff --git a/e2e/database/migration-workflow.test.ts b/e2e/database/migration-workflow.test.ts index 29ab6fe80..23b4aff3e 100644 --- a/e2e/database/migration-workflow.test.ts +++ b/e2e/database/migration-workflow.test.ts @@ -1,4 +1,4 @@ -import { templates } from "../support/templates.mjs"; +import { prepareMigrationDirectory } from "../support/migrations.mjs"; import { mkdtemp, rm } from "node:fs/promises"; import { tmpdir } from "node:os"; import { join } from "node:path"; @@ -22,14 +22,17 @@ for (const driver of [SqliteDriver, LibSqlDriver]) { driver, dbName: join(directory, "upgrade.db"), migrations: { - path: join( - templates.full.directory, - "db/migrations/sqlite", - ), + path: await prepareMigrationDirectory(directory), + emit: "ts" as const, + snapshotName: ".snapshot", snapshotOnMigrate: false, }, }, }; + await runDatabaseCommand(config, { + command: "generate", + name: "initial", + }); await runDatabaseCommand(config, { command: "migrate" }); await runDatabaseCommand(config, { command: "seed" }); const upgrade = await verifyMigrationUpgrade(config, directory); @@ -71,7 +74,9 @@ it("limits reset to development SQLite and seeds missing roles without changing driver: SqliteDriver, dbName: join(directory, "reset.db"), migrations: { - path: join(templates.full.directory, "db/migrations/sqlite"), + path: await prepareMigrationDirectory(directory), + emit: "ts" as const, + snapshotName: ".snapshot", snapshotOnMigrate: false, }, }, @@ -95,6 +100,10 @@ it("limits reset to development SQLite and seeds missing roles without changing { command: "reset" }, ), ).rejects.toThrow("local SQLite"); + await runDatabaseCommand(config, { + command: "generate", + name: "initial", + }); await runDatabaseCommand(config, { command: "reset" }); expect( await runDatabaseCommand(config, { command: "check" }), diff --git a/e2e/database/migration-workflow.ts b/e2e/database/migration-workflow.ts index eff3a4027..78a1cf1bf 100644 --- a/e2e/database/migration-workflow.ts +++ b/e2e/database/migration-workflow.ts @@ -36,7 +36,7 @@ import { promisify } from "node:util"; const runProcess = promisify(execFile); -/** Runs on the caller's disposable database after its committed initial migration. */ +/** Runs on the caller's disposable database after generating and applying its baseline. */ export async function verifyMigrationUpgrade( input: HackkitConfig, directory: string, @@ -78,13 +78,11 @@ export async function verifyMigrationUpgrade( join(directory, "node_modules"), "dir", ).catch((error: unknown) => { - if ( - !( - error instanceof Error && - "code" in error && - error.code === "EEXIST" - ) - ) + if (!( + error instanceof Error && + "code" in error && + error.code === "EEXIST" + )) throw error; }); await writeFile( diff --git a/e2e/database/templates.test.ts b/e2e/database/templates.test.ts index a2289a99a..d2e755a47 100644 --- a/e2e/database/templates.test.ts +++ b/e2e/database/templates.test.ts @@ -5,6 +5,7 @@ import { join } from "node:path"; import { tmpdir } from "node:os"; import { expect, it } from "vitest"; import { templates, testEnvironment } from "../support/templates.mjs"; +import { prepareMigrationDirectory } from "../support/migrations.mjs"; import { loadHackkitConfig } from "@hackkit/config"; import { initializeHackkit } from "@hackkit/core"; import { SqliteDriver } from "@mikro-orm/sqlite"; @@ -29,6 +30,7 @@ for (const template of Object.values(templates)) { const command = (name: string, overrides: NodeJS.ProcessEnv = {}) => run(["scripts/db.mjs", name], overrides); try { + await prepareMigrationDirectory(directory); const syncDatabase = join(directory, "sync-must-not-connect.db"); await run( ["node_modules/@hackkit/cli/bin/hackkit.mjs", "plugin", "sync"], @@ -37,6 +39,22 @@ for (const template of Object.values(templates)) { await expect(access(syncDatabase)).rejects.toMatchObject({ code: "ENOENT", }); + const generated: unknown = JSON.parse( + (await command("generate")).stdout, + ); + expect(generated).toMatchObject({ + command: "generate", + migration: { code: expect.stringContaining("core_user") }, + }); + expect(generated).toMatchObject({ + migration: { + code: + template.id === "full" + ? expect.stringContaining("teams_team") + : expect.not.stringContaining("teams_team"), + }, + }); + await access(join(directory, "migrations/.snapshot.json")); const status = await command("status"); expect(JSON.parse(status.stdout)).toMatchObject({ executed: [], @@ -64,6 +82,11 @@ for (const template of Object.values(templates)) { const untouched = join(directory, "untouched.db"); await writeFile(untouched, "leave me alone\n"); await command("reset"); + expect( + JSON.parse((await command("generate")).stdout), + ).toMatchObject({ + migration: { fileName: "", diff: { up: [] } }, + }); expect(JSON.parse((await command("check")).stdout)).toMatchObject({ ok: true, }); @@ -80,7 +103,7 @@ for (const template of Object.values(templates)) { }); } -it("minimal: real config and committed migrations initialize Core/auth without plugins", async () => { +it("minimal: generates and replays a Core/auth baseline without plugins", async () => { const directory = await mkdtemp(join(tmpdir(), "hackkit-minimal-db-")); try { const input = await loadHackkitConfig("hackkit.config.ts", { @@ -97,10 +120,9 @@ it("minimal: real config and committed migrations initialize Core/auth without p driver: SqliteDriver, dbName: join(directory, "web.db"), migrations: { - path: join( - templates.minimal.directory, - "db/migrations/sqlite", - ), + path: await prepareMigrationDirectory(directory), + emit: "ts" as const, + snapshotName: ".snapshot", snapshotOnMigrate: false, }, }, @@ -111,6 +133,10 @@ it("minimal: real config and committed migrations initialize Core/auth without p }, logger: { disabled: true }, }; + await runDatabaseCommand(config, { + command: "generate", + name: "initial", + }); await runDatabaseCommand(config, { command: "migrate" }); await runDatabaseCommand(config, { command: "seed" }); expect( @@ -132,6 +158,18 @@ it("minimal: real config and committed migrations initialize Core/auth without p } finally { await core.orm.close(); } + // Replaying the application's history initializes another clone without regenerating it. + const fresh = { + ...config, + database: { + ...config.database, + dbName: join(directory, "fresh.db"), + }, + }; + await runDatabaseCommand(fresh, { command: "migrate" }); + expect( + await runDatabaseCommand(fresh, { command: "check" }), + ).toMatchObject({ ok: true }); } finally { await rm(directory, { recursive: true, force: true }); } diff --git a/e2e/support/migrations.mjs b/e2e/support/migrations.mjs new file mode 100644 index 000000000..7efbd0294 --- /dev/null +++ b/e2e/support/migrations.mjs @@ -0,0 +1,17 @@ +import { mkdir, symlink } from "node:fs/promises"; +import { join } from "node:path"; +import { e2eDirectory } from "./templates.mjs"; + +/** Give generated TypeScript migrations an isolated history and resolvable imports. + * @param {string} directory + */ +export async function prepareMigrationDirectory(directory) { + const path = join(directory, "migrations"); + await mkdir(directory, { recursive: true }); + await symlink( + join(e2eDirectory, "node_modules"), + join(directory, "node_modules"), + "dir", + ); + return path; +} diff --git a/e2e/support/run.mjs b/e2e/support/run.mjs index fc4b51681..be0e7218d 100644 --- a/e2e/support/run.mjs +++ b/e2e/support/run.mjs @@ -10,6 +10,7 @@ import { testEnvironment, } from "./templates.mjs"; import { runCommand } from "./processes.mjs"; +import { prepareMigrationDirectory } from "./migrations.mjs"; const suite = process.argv[2] ?? "all"; assert.ok( @@ -77,8 +78,11 @@ try { cwd: repositoryRoot, }); if (suite !== "db") { - for (const { options } of targets) { + for (const { template, options } of targets) { + await prepareMigrationDirectory(join(buildDirectory, template.id)); + await pnpm(["db:generate", "--name", "initial"], options); await pnpm(["db:migrate"], options); + await pnpm(["db:check"], options); await pnpm(["db:seed"], options); await pnpm(["build"], options); } diff --git a/e2e/support/server.mjs b/e2e/support/server.mjs index d48e982b9..03bd321f4 100644 --- a/e2e/support/server.mjs +++ b/e2e/support/server.mjs @@ -7,6 +7,7 @@ import { tmpdir } from "node:os"; import { setTimeout as delay } from "node:timers/promises"; import { runCommand, stopServer } from "./processes.mjs"; import { testEnvironment } from "./templates.mjs"; +import { prepareMigrationDirectory } from "./migrations.mjs"; async function assertPortAvailable(port) { const probe = createServer(); @@ -32,7 +33,8 @@ export async function startTemplate(template) { let server; let output = ""; try { - for (const command of ["migrate", "seed"]) + await prepareMigrationDirectory(directory); + for (const command of ["generate", "migrate", "check", "seed"]) await runCommand(process.execPath, ["scripts/db.mjs", command], { cwd: template.directory, env, diff --git a/e2e/support/templates.mjs b/e2e/support/templates.mjs index 95941b044..9592fd6fb 100644 --- a/e2e/support/templates.mjs +++ b/e2e/support/templates.mjs @@ -33,6 +33,7 @@ export function testEnvironment(template, directory) { NEXT_TELEMETRY_DISABLED: "1", DATABASE_URL: `file:${join(directory, "web.db")}`, HACKKIT_DATABASE_DIALECT: "sqlite", + HACKKIT_MIGRATIONS_PATH: join(directory, "migrations"), HACKKIT_LOCAL_BLOB_BASE_DIR: join(directory, "uploads"), NEXT_PUBLIC_APP_URL: template.origin, BETTER_AUTH_URL: template.origin, diff --git a/packages/core/src/__tests__/public-profile.test.ts b/packages/core/src/__tests__/public-profile.test.ts index 098470500..bd40ece2b 100644 --- a/packages/core/src/__tests__/public-profile.test.ts +++ b/packages/core/src/__tests__/public-profile.test.ts @@ -46,7 +46,7 @@ describe("public profiles", () => { pronouns: "they/them", skills: ["TypeScript", "Design"], discordDisplayHandle: "hacker", - profilePhotoUrl: "/api/files/view?key=profile-photos%2Favatar.png", + image: "/api/files/view?key=profile-photos%2Favatar.png", isProfileSearchable: true, }); diff --git a/packages/core/src/functions/events.ts b/packages/core/src/functions/events.ts index 538de3b57..93690e0fc 100644 --- a/packages/core/src/functions/events.ts +++ b/packages/core/src/functions/events.ts @@ -1,6 +1,6 @@ import { serialize } from "@mikro-orm/core"; import type { HackkitRuntimeContext } from "../hackkit-context"; -import { eventTypeValueSchema } from "../event-types"; +import { eventTypeValueSchema, type EventTypes } from "../event-types"; import { HackKitError, parseInput } from "../errors"; import { withDomainLog } from "../domain-log"; import { coreModels } from "../models"; @@ -45,13 +45,20 @@ function filterVisibleEvents(events: Event[], includeHidden: boolean): Event[] { return events.filter((event) => !event.hidden); } -export function createEventsApi(context: EventsApiContext) { - const createEventSchema = createEventSchemaFactory( - eventTypeValueSchema(context.eventTypes), - ); - const updateEventSchema = updateEventSchemaFactory( - eventTypeValueSchema(context.eventTypes), - ); +/** Compile event validation once for a runtime's configured event types. */ +export function createEventSchemas(eventTypes: EventTypes) { + const typeSchema = eventTypeValueSchema(eventTypes); + return { + createEventSchema: createEventSchemaFactory(typeSchema), + updateEventSchema: updateEventSchemaFactory(typeSchema), + }; +} + +export function createEventsApi( + context: EventsApiContext, + schemas = createEventSchemas(context.eventTypes), +) { + const { createEventSchema, updateEventSchema } = schemas; const { em, now, id, logger, getUserOrThrow, requirePermission } = context; diff --git a/packages/core/src/functions/users.ts b/packages/core/src/functions/users.ts index 6e0080596..4928b02bc 100644 --- a/packages/core/src/functions/users.ts +++ b/packages/core/src/functions/users.ts @@ -73,7 +73,7 @@ export function createUsersApi(context: UsersApiContext) { user: { id: user.id, name: user.name, - profilePhotoUrl: user.profilePhotoUrl, + image: user.image, hackTag: user.hackTag, bio: user.bio, pronouns: user.pronouns, @@ -186,7 +186,7 @@ export function createUsersApi(context: UsersApiContext) { updated, { name: parsed.name, - profilePhotoUrl: parsed.profilePhotoUrl, + image: parsed.image, hackTag: parsed.hackTag, bio: parsed.bio, pronouns: parsed.pronouns, diff --git a/packages/core/src/hackkit.ts b/packages/core/src/hackkit.ts index 37f306286..e9cf45867 100644 --- a/packages/core/src/hackkit.ts +++ b/packages/core/src/hackkit.ts @@ -31,7 +31,7 @@ import type { UserId, } from "./types"; import { createUsersApi } from "./functions/users"; -import { createEventsApi } from "./functions/events"; +import { createEventsApi, createEventSchemas } from "./functions/events"; import { createSettingsApi } from "./functions/settings"; import { createAdminApi } from "./functions/admin"; import { createCompetitorRegistrationPolicy } from "./functions/registration-policy"; @@ -70,366 +70,407 @@ const defaultId = () => export function createHackkit< const TPlugins extends readonly HackKitPlugin[] = [], >(options: CreateHackkitOptions) { + return createHackkitFactory(options)( + options.em, + options.actorAuthId, + ); +} + +/** Prepare shared configuration once; bind a fresh EntityManager for each execution. */ +export function createHackkitFactory< + const TPlugins extends readonly HackKitPlugin[] = [], +>(options: Omit, "em" | "actorAuthId">) { const plugins = options.plugins ?? ([] as unknown as TPlugins); const registry = options.registry ?? createPluginRegistry(plugins); const now = options.clock ?? (() => new Date()); const id = options.id ?? defaultId; - const em = options.em; const userDataOptions = resolveUserDataOptions(options.userDataOptions); const eventTypes = resolveEventTypes(options.eventTypes); + const eventSchemas = createEventSchemas(eventTypes); const groups = resolveGroups(options.groups); const completeUserDataSchema = createCompleteUserDataSchema(userDataOptions); const logger = createLogger(options.logger); const defaultCompetitorRoleId = options.defaultCompetitorRoleId; - const notificationsApi = createNotificationsApi({ em, now }); - async function getUserOrThrow(authId: AuthId): Promise { - const user = await readUser(em, { id: authId }); - if (!user) throw new HackKitError("NOT_FOUND", "User not found."); - return user; - } + return function createScopedHackkit( + em: EntityManager, + actorAuthId?: string, + ) { + const notificationsApi = createNotificationsApi({ em, now }); - async function getRoleOrThrow(roleId: RoleId): Promise { - const role = await em.findOne(coreModels.role, { id: roleId }); - if (!role) throw new HackKitError("NOT_FOUND", "Role not found."); - return serialize(role); - } + async function getUserOrThrow(authId: AuthId): Promise { + const user = await readUser(em, { id: authId }); + if (!user) throw new HackKitError("NOT_FOUND", "User not found."); + return user; + } - const accessControl = createAccessControl({ - getUserOrThrow, - getRoleOrThrow, - }); - const settingsApi = createSettingsApi({ - em, - now, - logger, - settings: registry.settings, - requirePermission: accessControl.requirePermission, - }); - const pluginApis = setupPluginApis(plugins, { - em, - actorAuthId: options.actorAuthId, - getUser: (authId) => readUser(em, { id: authId }), - registry, - getSettingValue: settingsApi.getValue, - notifications: notificationsApi, - groups, - }); + async function getRoleOrThrow(roleId: RoleId): Promise { + const role = await em.findOne(coreModels.role, { id: roleId }); + if (!role) throw new HackKitError("NOT_FOUND", "Role not found."); + return serialize(role); + } - const runtimeContext: HackkitRuntimeContext = { - em, - now, - id, - logger, - defaultCompetitorRoleId, - getSettingValue: settingsApi.getValue, - eventTypes, - userDataOptions, - groups, - getUserOrThrow, - getRoleOrThrow, - requirePermission: accessControl.requirePermission, - assertCanManageRole: accessControl.assertCanManageRole, - accessControl, - notifications: notificationsApi, - }; + const accessControl = createAccessControl({ + getUserOrThrow, + getRoleOrThrow, + }); + const settingsApi = createSettingsApi({ + em, + now, + logger, + settings: registry.settings, + requirePermission: accessControl.requirePermission, + }); + const pluginApis = setupPluginApis(plugins, { + em, + actorAuthId, + getUser: (authId) => readUser(em, { id: authId }), + registry, + getSettingValue: settingsApi.getValue, + notifications: notificationsApi, + groups, + }); - const registrationPolicy = - createCompetitorRegistrationPolicy(runtimeContext); - const rsvpApi = createRsvpApi(runtimeContext); - const groupsApi = createGroupsApi(runtimeContext); + const runtimeContext: HackkitRuntimeContext = { + em, + now, + id, + logger, + defaultCompetitorRoleId, + getSettingValue: settingsApi.getValue, + eventTypes, + userDataOptions, + groups, + getUserOrThrow, + getRoleOrThrow, + requirePermission: accessControl.requirePermission, + assertCanManageRole: accessControl.assertCanManageRole, + accessControl, + notifications: notificationsApi, + }; - async function registerHacker(input: unknown): Promise { - return withOperationLock(em, "registration", async () => { - const parsed = parseInput(registerHackerSchema, input); - return withDomainLog( - logger, - "hackers.register", - { targetAuthId: parsed.userId }, - async () => { - await getUserOrThrow(parsed.userId); - const userData = await em.findOne(coreModels.userData, { - authId: parsed.userId, - }); - if (!userData) - throw new HackKitError( - "INVALID_OPERATION", - "User Data must be completed before registering as a Hacker.", - ); - const existing = await em.findOne(coreModels.hacker, { - userId: parsed.userId, - }); - const timestamp = now(); - const value: Hacker = { - ...parsed, - registeredAt: existing?.registeredAt ?? timestamp, - updatedAt: timestamp, - }; + const registrationPolicy = + createCompetitorRegistrationPolicy(runtimeContext); + const rsvpApi = createRsvpApi(runtimeContext); + const groupsApi = createGroupsApi(runtimeContext); + + async function registerHacker(input: unknown): Promise { + return withOperationLock(em, "registration", async () => { + const parsed = parseInput(registerHackerSchema, input); + return withDomainLog( + logger, + "hackers.register", + { targetAuthId: parsed.userId }, + async () => { + await getUserOrThrow(parsed.userId); + const userData = await em.findOne(coreModels.userData, { + authId: parsed.userId, + }); + if (!userData) + throw new HackKitError( + "INVALID_OPERATION", + "User Data must be completed before registering as a Hacker.", + ); + const existing = await em.findOne(coreModels.hacker, { + userId: parsed.userId, + }); + const timestamp = now(); + const value: Hacker = { + ...parsed, + registeredAt: existing?.registeredAt ?? timestamp, + updatedAt: timestamp, + }; - if (existing) { - em.assign(existing, value, { ignoreUndefined: true }); + if (existing) { + em.assign(existing, value, { + ignoreUndefined: true, + }); + await em.flush(); + return serialize(existing); + } + const { requireApproval } = + await registrationPolicy.assertCanRegisterNewHacker(); + const hacker = em.create(coreModels.hacker, value); + const profile = await em.findOneOrFail( + coreModels.user, + { + id: parsed.userId, + }, + ); + if (defaultCompetitorRoleId) { + await getRoleOrThrow(defaultCompetitorRoleId); + profile.roleId = defaultCompetitorRoleId; + profile.isApproved = !requireApproval; + } else if (!requireApproval) { + profile.isApproved = true; + } + profile.updatedAt = timestamp; await em.flush(); - return serialize(existing); - } - const { requireApproval } = - await registrationPolicy.assertCanRegisterNewHacker(); - const hacker = em.create(coreModels.hacker, value); - const profile = await em.findOneOrFail(coreModels.user, { - id: parsed.userId, - }); - if (defaultCompetitorRoleId) { - await getRoleOrThrow(defaultCompetitorRoleId); - profile.roleId = defaultCompetitorRoleId; - profile.isApproved = !requireApproval; - } else if (!requireApproval) { - profile.isApproved = true; - } - profile.updatedAt = timestamp; - await em.flush(); - return serialize(hacker); - }, - ); - }); - } + return serialize(hacker); + }, + ); + }); + } - const hackkit = { - models: coreModels, - permissions: CorePermission, - registry, - plugins: pluginApis, - isPluginEnabled(pluginId: string): boolean { - const plugin = registry.plugins[pluginId]; - return ( - Object.hasOwn(registry.plugins, pluginId) && - plugin.enabled !== false - ); - }, - accessControl, - settings: settingsApi, - notifications: notificationsApi, - users: createUsersApi({ - ...runtimeContext, - registrationPolicy, + const hackkit = { + models: coreModels, + permissions: CorePermission, + registry, + plugins: pluginApis, + isPluginEnabled(pluginId: string): boolean { + const plugin = registry.plugins[pluginId]; + return ( + Object.hasOwn(registry.plugins, pluginId) && + plugin.enabled !== false + ); + }, + accessControl, + settings: settingsApi, + notifications: notificationsApi, + users: createUsersApi({ + ...runtimeContext, + registrationPolicy, + groups: groupsApi, + }), + rsvp: rsvpApi, groups: groupsApi, - }), - rsvp: rsvpApi, - groups: groupsApi, - events: createEventsApi(runtimeContext), - admin: createAdminApi(runtimeContext), + events: createEventsApi(runtimeContext, eventSchemas), + admin: createAdminApi(runtimeContext), - userData: { - options: userDataOptions, + userData: { + options: userDataOptions, - async getUserData(authId: AuthId): Promise { - const record = await em.findOne(coreModels.userData, { - authId, - }); - return record ? serialize(record) : null; - }, + async getUserData(authId: AuthId): Promise { + const record = await em.findOne(coreModels.userData, { + authId, + }); + return record ? serialize(record) : null; + }, - async completeUserData(input: unknown): Promise { - return withOperationLock(em, "user-data", async () => { - const parsed = parseInput(completeUserDataSchema, input); - await getUserOrThrow(parsed.authId); - const existing = await em.findOne(coreModels.userData, { - authId: parsed.authId, + async completeUserData(input: unknown): Promise { + return withOperationLock(em, "user-data", async () => { + const parsed = parseInput( + completeUserDataSchema, + input, + ); + await getUserOrThrow(parsed.authId); + const existing = await em.findOne(coreModels.userData, { + authId: parsed.authId, + }); + const timestamp = now(); + const value: UserData = { + ...parsed, + completedAt: existing?.completedAt ?? timestamp, + updatedAt: timestamp, + }; + const record = existing + ? em.assign(existing, value, { + ignoreUndefined: true, + }) + : em.create(coreModels.userData, value); + await em.flush(); + return serialize(record); }); - const timestamp = now(); - const value: UserData = { - ...parsed, - completedAt: existing?.completedAt ?? timestamp, - updatedAt: timestamp, - }; - const record = existing - ? em.assign(existing, value, { ignoreUndefined: true }) - : em.create(coreModels.userData, value); - await em.flush(); - return serialize(record); - }); + }, }, - }, - hackers: { - registerHacker, + hackers: { + registerHacker, - async getHacker(userId: UserId): Promise { - const record = await em.findOne(coreModels.hacker, { userId }); - return record ? serialize(record) : null; + async getHacker(userId: UserId): Promise { + const record = await em.findOne(coreModels.hacker, { + userId, + }); + return record ? serialize(record) : null; + }, }, - }, - roles: { - async listRoles(input?: { actorAuthId?: AuthId }): Promise { - if (input?.actorAuthId) - await accessControl.requirePermission( - input.actorAuthId, - CorePermission.RolesView, + roles: { + async listRoles(input?: { + actorAuthId?: AuthId; + }): Promise { + if (input?.actorAuthId) + await accessControl.requirePermission( + input.actorAuthId, + CorePermission.RolesView, + ); + return serialize( + await em.find( + coreModels.role, + {}, + { orderBy: { position: "asc" } }, + ), ); - return serialize( - await em.find( - coreModels.role, - {}, - { orderBy: { position: "asc" } }, - ), - ); - }, - - async getRole(roleId: RoleId): Promise { - const record = await em.findOne(coreModels.role, { - id: roleId, - }); - return record ? serialize(record) : null; - }, + }, - async createRole(input: unknown): Promise { - return withOperationLock(em, "roles", async () => { - const parsed = parseInput(createRoleSchema, input); - const principal = await accessControl.requirePermission( - parsed.actorAuthId, - CorePermission.RolesCreate, - ); - const rolePosition = { - ...principal.role, - position: parsed.position, - }; - accessControl.assertCanManageRole(principal, rolePosition); - accessControl.assertCanGrantPermissions( - principal, - parsed.permissions as PermissionKey[], - ); - const existingName = await em.findOne(coreModels.role, { - name: parsed.name, + async getRole(roleId: RoleId): Promise { + const record = await em.findOne(coreModels.role, { + id: roleId, }); - if (existingName) - throw new HackKitError( - "CONFLICT", - "Role name already exists.", - ); - const timestamp = now(); - { - const created = em.create(coreModels.role, { - id: parsed.id ?? id(), - name: parsed.name, - position: parsed.position, - permissions: parsed.permissions as PermissionKey[], - color: parsed.color, - createdAt: timestamp, - updatedAt: timestamp, - }); - await em.flush(); - return serialize(created); - } - }); - }, + return record ? serialize(record) : null; + }, - async updateRole(input: unknown): Promise { - return withOperationLock(em, "roles", async () => { - const parsed = parseInput(updateRoleSchema, input); - const principal = await accessControl.requirePermission( - parsed.actorAuthId, - CorePermission.RolesUpdate, - ); - const role = await getRoleOrThrow(parsed.roleId); - accessControl.assertCanManageRole(principal, role); - if (parsed.position !== undefined) - accessControl.assertCanManageRole(principal, { - ...role, + async createRole(input: unknown): Promise { + return withOperationLock(em, "roles", async () => { + const parsed = parseInput(createRoleSchema, input); + const principal = await accessControl.requirePermission( + parsed.actorAuthId, + CorePermission.RolesCreate, + ); + const rolePosition = { + ...principal.role, position: parsed.position, - }); - if (parsed.permissions) + }; + accessControl.assertCanManageRole( + principal, + rolePosition, + ); accessControl.assertCanGrantPermissions( principal, parsed.permissions as PermissionKey[], ); - const updated = await em.findOne(coreModels.role, { - id: parsed.roleId, - }); - if (updated) { - em.assign( - updated, - { + const existingName = await em.findOne(coreModels.role, { + name: parsed.name, + }); + if (existingName) + throw new HackKitError( + "CONFLICT", + "Role name already exists.", + ); + const timestamp = now(); + { + const created = em.create(coreModels.role, { + id: parsed.id ?? id(), name: parsed.name, position: parsed.position, - permissions: parsed.permissions as - | PermissionKey[] - | undefined, + permissions: + parsed.permissions as PermissionKey[], color: parsed.color, - updatedAt: now(), - }, - { ignoreUndefined: true }, - ); - await em.flush(); - } - if (!updated) - throw new HackKitError("NOT_FOUND", "Role not found."); - return serialize(updated); - }); - }, + createdAt: timestamp, + updatedAt: timestamp, + }); + await em.flush(); + return serialize(created); + } + }); + }, - async deleteRole(input: unknown): Promise { - return withOperationLock(em, "roles", async () => { - const parsed = parseInput(deleteRoleSchema, input); - const principal = await accessControl.requirePermission( - parsed.actorAuthId, - CorePermission.RolesDelete, - ); - const role = await getRoleOrThrow(parsed.roleId); - accessControl.assertCanManageRole(principal, role); - const usersWithRole = await em.find( - coreModels.user, - { roleId: parsed.roleId }, - { limit: 1 }, - ); - if (usersWithRole.length > 0) - throw new HackKitError( - "INVALID_OPERATION", - "Cannot delete a role assigned to users.", + async updateRole(input: unknown): Promise { + return withOperationLock(em, "roles", async () => { + const parsed = parseInput(updateRoleSchema, input); + const principal = await accessControl.requirePermission( + parsed.actorAuthId, + CorePermission.RolesUpdate, ); - await em.nativeDelete(coreModels.role, { - id: parsed.roleId, + const role = await getRoleOrThrow(parsed.roleId); + accessControl.assertCanManageRole(principal, role); + if (parsed.position !== undefined) + accessControl.assertCanManageRole(principal, { + ...role, + position: parsed.position, + }); + if (parsed.permissions) + accessControl.assertCanGrantPermissions( + principal, + parsed.permissions as PermissionKey[], + ); + const updated = await em.findOne(coreModels.role, { + id: parsed.roleId, + }); + if (updated) { + em.assign( + updated, + { + name: parsed.name, + position: parsed.position, + permissions: parsed.permissions as + PermissionKey[] | undefined, + color: parsed.color, + updatedAt: now(), + }, + { ignoreUndefined: true }, + ); + await em.flush(); + } + if (!updated) + throw new HackKitError( + "NOT_FOUND", + "Role not found.", + ); + return serialize(updated); }); - }); - }, + }, - async assignRoleToUser(input: unknown): Promise { - return withOperationLock(em, "roles", async () => { - const parsed = parseInput(assignRoleSchema, input); - const principal = await accessControl.requirePermission( - parsed.actorAuthId, - CorePermission.RolesAssign, - ); - const target = await getUserOrThrow(parsed.targetAuthId); - const nextRole = await getRoleOrThrow(parsed.roleId); - accessControl.assertCanManageRole(principal, nextRole); - if (target.roleId) - accessControl.assertCanManageRole( - principal, - await getRoleOrThrow(target.roleId), + async deleteRole(input: unknown): Promise { + return withOperationLock(em, "roles", async () => { + const parsed = parseInput(deleteRoleSchema, input); + const principal = await accessControl.requirePermission( + parsed.actorAuthId, + CorePermission.RolesDelete, + ); + const role = await getRoleOrThrow(parsed.roleId); + accessControl.assertCanManageRole(principal, role); + const usersWithRole = await em.find( + coreModels.user, + { roleId: parsed.roleId }, + { limit: 1 }, ); - const updated = await em.findOne(coreModels.user, { - id: parsed.targetAuthId, + if (usersWithRole.length > 0) + throw new HackKitError( + "INVALID_OPERATION", + "Cannot delete a role assigned to users.", + ); + await em.nativeDelete(coreModels.role, { + id: parsed.roleId, + }); }); - if (updated) { - em.assign( - updated, - { - roleId: parsed.roleId, - updatedAt: now(), - }, - { ignoreUndefined: true }, + }, + + async assignRoleToUser(input: unknown): Promise { + return withOperationLock(em, "roles", async () => { + const parsed = parseInput(assignRoleSchema, input); + const principal = await accessControl.requirePermission( + parsed.actorAuthId, + CorePermission.RolesAssign, ); - await em.flush(); - } - if (!updated) - throw new HackKitError("NOT_FOUND", "User not found."); - return getUserOrThrow(parsed.targetAuthId); - }); + const target = await getUserOrThrow( + parsed.targetAuthId, + ); + const nextRole = await getRoleOrThrow(parsed.roleId); + accessControl.assertCanManageRole(principal, nextRole); + if (target.roleId) + accessControl.assertCanManageRole( + principal, + await getRoleOrThrow(target.roleId), + ); + const updated = await em.findOne(coreModels.user, { + id: parsed.targetAuthId, + }); + if (updated) { + em.assign( + updated, + { + roleId: parsed.roleId, + updatedAt: now(), + }, + { ignoreUndefined: true }, + ); + await em.flush(); + } + if (!updated) + throw new HackKitError( + "NOT_FOUND", + "User not found.", + ); + return getUserOrThrow(parsed.targetAuthId); + }); + }, }, - }, - }; + }; - return hackkit as typeof hackkit & { plugins: PluginApiMap }; + return hackkit as typeof hackkit & { plugins: PluginApiMap }; + }; } export type HackKit = ReturnType; diff --git a/packages/core/src/mikro/auth-lifecycle.test.ts b/packages/core/src/mikro/auth-lifecycle.test.ts index bf929057b..193ccc90a 100644 --- a/packages/core/src/mikro/auth-lifecycle.test.ts +++ b/packages/core/src/mikro/auth-lifecycle.test.ts @@ -92,7 +92,7 @@ describe("Core auth lifecycle", () => { await hackkit.users.updateProfile({ authId: id, name: "Joshua Silva", - profilePhotoUrl: "/api/files/view/avatar.png", + image: "/api/files/view/avatar.png", bio: "Hello", }); expect( @@ -114,7 +114,7 @@ describe("Core auth lifecycle", () => { ).toMatchObject({ id, name: "Josh", - profilePhotoUrl: "https://example.com/avatar.png", + image: "https://example.com/avatar.png", bio: "Hello", }); const signin = await auth.api.signInEmail({ diff --git a/packages/core/src/mikro/auth.ts b/packages/core/src/mikro/auth.ts index 4e1b7c1aa..5779ac345 100644 --- a/packages/core/src/mikro/auth.ts +++ b/packages/core/src/mikro/auth.ts @@ -15,7 +15,7 @@ const authUserProperties = new Set([ "name", "email", "emailVerified", - "profilePhotoUrl", + "image", "createdAt", "updatedAt", ]); @@ -34,7 +34,6 @@ export function resolveHackKitAuthOptions< user: { ...options.user, modelName: "core_user", - fields: { image: "profilePhotoUrl" }, }, }; } diff --git a/packages/core/src/models.ts b/packages/core/src/models.ts index 32dd1a9b4..23e4ff3f8 100644 --- a/packages/core/src/models.ts +++ b/packages/core/src/models.ts @@ -29,7 +29,7 @@ export const HackKitUser = defineEntity({ name: p.string(), email: p.string().unique(), emailVerified: p.boolean().default(false), - profilePhotoUrl: p.text().nullable(), + image: p.text().nullable(), hackTag: p.string().nullable().unique(), bio: p.text().nullable(), pronouns: p.string().nullable(), diff --git a/packages/core/src/runtime.test.ts b/packages/core/src/runtime.test.ts index 56fb90000..00a157d93 100644 --- a/packages/core/src/runtime.test.ts +++ b/packages/core/src/runtime.test.ts @@ -1,6 +1,9 @@ import { SqliteDriver } from "@mikro-orm/sqlite"; +import { RequestContext } from "@mikro-orm/core"; import { expect, it } from "vitest"; import { initializeHackkit } from "./runtime"; +import { coreModels } from "./models"; +import type { HackKitPlugin } from "./plugins"; it("shares auth and connections while isolating domain execution scopes", async () => { const runtime = await initializeHackkit({ @@ -43,3 +46,74 @@ it("shares auth and connections while isolating domain execution scopes", async await runtime.orm.close(); } }); + +it("shares prepared configuration while isolating concurrent actors and managed entities", async () => { + const plugins = [ + { id: "probe", setup: (context) => context }, + ] as const satisfies readonly HackKitPlugin[]; + const runtime = await initializeHackkit({ + database: { driver: SqliteDriver, dbName: ":memory:" }, + auth: { secret: "local-test-secret-with-at-least-32-characters" }, + logger: { disabled: true }, + groups: ["builders"], + plugins, + }); + try { + await runtime.orm.schema.create(); + const first = runtime.createScope("first"); + const second = runtime.createScope("second"); + expect(first.hackkit.events.options).toBe( + second.hackkit.events.options, + ); + expect(first.hackkit.userData.options).toBe( + second.hackkit.userData.options, + ); + expect(first.hackkit.plugins.probe.groups).toBe( + second.hackkit.plugins.probe.groups, + ); + expect(first.hackkit.plugins.probe.em).toBe(first.em); + expect(second.hackkit.plugins.probe.em).toBe(second.em); + first.em.create(coreModels.user, { + id: "participant", + name: "Participant", + email: "participant@example.com", + }); + await first.em.flush(); + + let arrive = () => {}; + const bothStarted = new Promise((resolve) => { + arrive = resolve; + }); + let started = 0; + const results = await Promise.all( + ["first", "second"].map((actor) => + runtime.run(async ({ em, hackkit }) => { + if (++started === 2) arrive(); + await bothStarted; + expect(RequestContext.getEntityManager()).toBe(em); + expect(em.getContext()).toBe(em); + expect(hackkit.plugins.probe.em).toBe(em); + expect(hackkit.plugins.probe.actorAuthId).toBe(actor); + const user = await em.findOneOrFail(coreModels.user, { + id: "participant", + }); + user.name = actor; + await Promise.resolve(); + expect(user.name).toBe(actor); + return { em, user }; + }, actor), + ), + ); + expect(results[0]?.em).not.toBe(results[1]?.em); + expect(results[0]?.user).not.toBe(results[1]?.user); + expect( + ( + await second.em.findOneOrFail(coreModels.user, { + id: "participant", + }) + ).name, + ).toBe("Participant"); + } finally { + await runtime.orm.close(); + } +}); diff --git a/packages/core/src/runtime.ts b/packages/core/src/runtime.ts index 9c881d9b6..1e73cf5bb 100644 --- a/packages/core/src/runtime.ts +++ b/packages/core/src/runtime.ts @@ -1,6 +1,10 @@ import { MikroORM, RequestContext, type EntityManager } from "@mikro-orm/core"; import { createLogger } from "./adapters/logger"; -import { createHackkit, type CreateHackkitOptions } from "./hackkit"; +import { + createHackkitFactory, + type createHackkit, + type CreateHackkitOptions, +} from "./hackkit"; import { createPluginRegistry, type HackKitPlugin, @@ -45,6 +49,10 @@ export async function initializeHackkit< options: InitializeHackkitOptions, ): Promise> { const registry = createPluginRegistry(options.plugins, options.entities); + const createScopedHackkit = createHackkitFactory({ + ...options, + registry, + }); const orm = await MikroORM.init(createOrmOptions(options)); let auth: ReturnType; try { @@ -66,15 +74,20 @@ export async function initializeHackkit< const em = orm.em.fork({ useContext: true }); return { em, - hackkit: createHackkit({ ...options, em, registry, actorAuthId }), + hackkit: createScopedHackkit(em, actorAuthId), }; } function run( operation: (scope: ReturnType) => Promise, actorAuthId?: string, ) { - const scope = createScope(actorAuthId); - return RequestContext.create(scope.em, () => operation(scope)); + return RequestContext.create(orm.em, () => { + const em = orm.em.getContext(); + return operation({ + em, + hackkit: createScopedHackkit(em, actorAuthId), + }); + }); } return { orm, auth, registry, createScope, run }; } diff --git a/packages/core/src/schemas.ts b/packages/core/src/schemas.ts index 463ab5dd2..c4106c6e5 100644 --- a/packages/core/src/schemas.ts +++ b/packages/core/src/schemas.ts @@ -19,7 +19,7 @@ export const hackTagSchema = z export const updateUserProfileSchema = z.object({ authId: authIdSchema, name: z.string().trim().min(1).max(200).optional(), - profilePhotoUrl: z + image: z .union([ z.string().url(), z diff --git a/packages/core/src/testing.ts b/packages/core/src/testing.ts index d2357241f..9ff504342 100644 --- a/packages/core/src/testing.ts +++ b/packages/core/src/testing.ts @@ -49,14 +49,14 @@ export async function createTestUser( authId: string; email: string; name: string; - profilePhotoUrl?: string; + image?: string; }, ) { context.em.create(HackKitUser, { id: input.authId, email: input.email, name: input.name, - profilePhotoUrl: input.profilePhotoUrl, + image: input.image, createdAt: new Date("2026-05-24T12:00:00.000Z"), updatedAt: new Date("2026-05-24T12:00:00.000Z"), }); diff --git a/packages/core/src/types.ts b/packages/core/src/types.ts index cbbc018a9..81f490c78 100644 --- a/packages/core/src/types.ts +++ b/packages/core/src/types.ts @@ -38,7 +38,7 @@ export type PublicUserProfile = { User, | "id" | "name" - | "profilePhotoUrl" + | "image" | "hackTag" | "bio" | "pronouns" diff --git a/packages/ui/src/components/public-profile-card.tsx b/packages/ui/src/components/public-profile-card.tsx index f0be53447..5b829a10a 100644 --- a/packages/ui/src/components/public-profile-card.tsx +++ b/packages/ui/src/components/public-profile-card.tsx @@ -35,10 +35,10 @@ export function PublicProfileCard({ return ( - {user.profilePhotoUrl ? ( + {user.image ? ( // eslint-disable-next-line @next/next/no-img-element diff --git a/packages/ui/src/components/user-profile-settings-form.tsx b/packages/ui/src/components/user-profile-settings-form.tsx index c63d56306..9cf6c3997 100644 --- a/packages/ui/src/components/user-profile-settings-form.tsx +++ b/packages/ui/src/components/user-profile-settings-form.tsx @@ -68,7 +68,7 @@ function userToFormValues(user: User | Wire): FormValues { skillsText: skillsToText(user.skills), isProfileSearchable: user.isProfileSearchable ?? true, discordDisplayHandle: user.discordDisplayHandle ?? "", - profilePhotoUrl: user.profilePhotoUrl ?? undefined, + image: user.image ?? undefined, }; } @@ -92,7 +92,7 @@ export function UserProfileSettingsForm({ }, [currentUser, form]); const previewPhoto = profilePhotoFile ? URL.createObjectURL(profilePhotoFile) - : currentUser.profilePhotoUrl; + : currentUser.image; React.useEffect(() => { if (!profilePhotoFile) return; @@ -103,10 +103,10 @@ export function UserProfileSettingsForm({ }, [profilePhotoFile, previewPhoto]); async function onSubmit(values: FormValues) { - let profilePhotoUrl = values.profilePhotoUrl; + let image = values.image; if (profilePhotoFile && uploadProfilePhoto) { try { - profilePhotoUrl = await uploadProfilePhoto(profilePhotoFile); + image = await uploadProfilePhoto(profilePhotoFile); } catch (error) { toast.error( error instanceof Error @@ -125,7 +125,7 @@ export function UserProfileSettingsForm({ skills: textToSkills(values.skillsText), isProfileSearchable: values.isProfileSearchable ?? true, discordDisplayHandle: values.discordDisplayHandle, - profilePhotoUrl, + image, }; let result; try { diff --git a/packages/ui/src/types.ts b/packages/ui/src/types.ts index 598dd697a..8410cbdfb 100644 --- a/packages/ui/src/types.ts +++ b/packages/ui/src/types.ts @@ -44,7 +44,7 @@ export type UserProfileFormValues = { skills: string[]; isProfileSearchable: boolean; discordDisplayHandle?: string; - profilePhotoUrl?: string; + image?: string; }; export type HackerRegistrationFormValues = { diff --git a/templates/nextjs-full/.env.example b/templates/nextjs-full/.env.example index f2ede0f5b..7a8d94a30 100644 --- a/templates/nextjs-full/.env.example +++ b/templates/nextjs-full/.env.example @@ -62,3 +62,6 @@ BETTER_AUTH_SECRET= # SMTP_PASSWORD= # HACKKIT_EMAIL_FROM="HackKit " # HACKKIT_EMAIL_REPLY_TO= + +# Optional: migration history directory, relative to this template or absolute. +# HACKKIT_MIGRATIONS_PATH=db/migrations/sqlite diff --git a/templates/nextjs-full/README.md b/templates/nextjs-full/README.md index c13d287fa..0c2f8edda 100644 --- a/templates/nextjs-full/README.md +++ b/templates/nextjs-full/README.md @@ -1,6 +1,6 @@ # HackKit reference web app -Next.js app using MikroORM, Core-owned Better Auth, HackKit UI, Teams, Discord verification, and notifications. This migration targets a fresh database. Existing databases and user accounts are not converted. +Next.js app using MikroORM, Core-owned Better Auth, HackKit UI, Teams, Discord verification, and notifications. ## Local setup @@ -9,9 +9,11 @@ Use Node.js 22.17 or newer and the repository-pinned pnpm 12.15.0. Run these com 1. Install dependencies with `pnpm install`. 2. Build workspace packages with `pnpm exec turbo run build --filter=@hackkit/template-nextjs-full^...`. 3. Sync plugin routes with `pnpm --filter @hackkit/template-nextjs-full sync`. -4. Apply committed migrations with `pnpm --filter @hackkit/template-nextjs-full db:migrate`. -5. Insert configured roles with `pnpm --filter @hackkit/template-nextjs-full db:seed`. -6. Start Next.js with `pnpm --filter @hackkit/template-nextjs-full dev`. +4. Configure the database and plugins in `hackkit.config.ts` and the environment files. Use an empty development database. +5. Generate your initial migration with `pnpm --filter @hackkit/template-nextjs-full db:generate --name initial`. +6. Review the generated migration and snapshot, then apply with `pnpm --filter @hackkit/template-nextjs-full db:migrate`. +7. Insert configured roles with `pnpm --filter @hackkit/template-nextjs-full db:seed`. +8. Commit the migration and snapshot to your application repository, then start Next.js with `pnpm --filter @hackkit/template-nextjs-full dev`. The local `.env` starts empty and is ignored by Git. On a fresh checkout, copy [`.env.example`](.env.example) to `.env` to configure this template. The example lists production requirements and comments out optional integrations. An empty `.env` uses local development defaults. Never commit populated environment files. @@ -37,13 +39,15 @@ Set `TURSO_AUTH_TOKEN` when the libSQL endpoint requires authentication. Driver Core, Better Auth, installed plugins (including disabled plugins), and application entities form one native MikroORM registry. Add app-owned `defineEntity` definitions through `entities` in `hackkit.config.ts`; plugins expose an `entities` array. Runtime and app migration scripts use the same registry. Auth plugins requiring extra tables or fields must declare them before initialization; undeclared schema fails early. -Migrations and snapshots are committed under `db/migrations/postgresql`, `db/migrations/mysql`, and `db/migrations/sqlite`. libSQL uses the SQLite chain. After changing entities: +The template ships without migration history or schema snapshots. First setup generates a baseline for your configured database and entity registry. Commit it in your application repository. Later clones of that application apply its existing migrations; they do not generate another baseline. Existing databases must retain the migration history that created them. + +The selected dialect uses `db/migrations/postgresql`, `db/migrations/mysql`, or `db/migrations/sqlite`. libSQL uses the SQLite dialect directory. `HACKKIT_MIGRATIONS_PATH` optionally overrides the directory, relative to this application or absolute. Maintain the history for the dialect your application uses. If your application supports several dialects, maintain and test each of those histories. After changing entities: 1. Select a disposable development database for the dialect using the variables above. 2. Run `pnpm --filter @hackkit/template-nextjs-full db:generate --name describe-change`. -3. Review the generated TypeScript migration and snapshot. Repeat generation for the other dialects. +3. Review the generated TypeScript migration and snapshot. Generate for other dialects only if your application supports them. 4. Apply with `pnpm --filter @hackkit/template-nextjs-full db:migrate` and validate against fresh databases. -5. Commit every dialect's reviewed migration and snapshot. +5. Commit each supported dialect's reviewed migration and snapshot. Set `enabled: false` on a registered plugin to disable behavior while keeping its schema and data. Removing it can generate table drops. Review data retention before applying them. `db:seed` only inserts missing configured role IDs; it does not update existing roles or assign them to users. @@ -59,9 +63,9 @@ The database commands now use application-owned utility scripts, independently o Set explicit `DATABASE_URL`, `NEXT_PUBLIC_APP_URL`, `BETTER_AUTH_URL`, and `BETTER_AUTH_SECRET` (at least 32 characters). Configure `BETTER_AUTH_TRUSTED_ORIGINS` as a comma-separated list when needed. The app's production checks also require: -- `HACKKIT_BLOB_ADAPTER=s3`, bucket, region, access key, and secret key; set `HACKKIT_S3_ENDPOINT` for compatible stores. -- `DISCORD_GUILD_ID`, `DISCORD_BOT_API_URL`, `DISCORD_INTERNAL_AUTH_KEY`, and `DISCORD_PARTICIPANT_ROLE_ID` (or role name). -- Optional email through `HACKKIT_EMAIL_PROVIDER=resend` plus `RESEND_API_KEY`, or `smtp` plus SMTP settings. +- `HACKKIT_BLOB_ADAPTER=s3`, bucket, region, access key, and secret key; set `HACKKIT_S3_ENDPOINT` for compatible stores. +- `DISCORD_GUILD_ID`, `DISCORD_BOT_API_URL`, `DISCORD_INTERNAL_AUTH_KEY`, and `DISCORD_PARTICIPANT_ROLE_ID` (or role name). +- Optional email through `HACKKIT_EMAIL_PROVIDER=resend` plus `RESEND_API_KEY`, or `smtp` plus SMTP settings. See [env.ts](env.ts) for exact variable names. Database storage must persist across application restarts. Apply migrations and seed as explicit release steps. Builds must have valid configuration but do not apply schema changes. @@ -77,9 +81,9 @@ This is a runnable workspace example. Packages remain private and use workspace ## Architecture -- [Next integration guide](../../docs/guides/next-integration.md) -- [MikroORM and Core auth decision](../../docs/adr/0013-mikroorm-and-core-auth.md) -- [hackkit.config.ts](hackkit.config.ts): plugins, database, auth, settings, and seed roles. -- [db/migrations](db/migrations): reviewed app-owned migrations. +- [Next integration guide](../../docs/guides/next-integration.md) +- [MikroORM and Core auth decision](../../docs/adr/0013-mikroorm-and-core-auth.md) +- [hackkit.config.ts](hackkit.config.ts): plugins, database, auth, settings, and seed roles. +- [Database migration guide](../../docs/guides/database-migrations.md): initial generation and application-owned history. The UI provider receives a typed better-call path client created at module scope in `app/providers.tsx`. Plugin components bind their endpoint types using the provider's HTTP settings. `hackkit plugin sync` installs page reexports and updates `hackkit.lock`; it generates no client metadata. The single `/api/hackkit/[...path]` route forwards POST to the host handler. No app-level action wrappers or action maps are needed. diff --git a/templates/nextjs-full/app/app-bar.tsx b/templates/nextjs-full/app/app-bar.tsx index 55c9035d9..f30f080dc 100644 --- a/templates/nextjs-full/app/app-bar.tsx +++ b/templates/nextjs-full/app/app-bar.tsx @@ -43,7 +43,7 @@ export async function AppBar() { name={session.user.name} email={session.user.email} image={ - currentUser?.profilePhotoUrl ?? + currentUser?.image ?? session.user.image } isAdmin={isAdmin} diff --git a/templates/nextjs-full/db/migrations/mysql/.snapshot.json b/templates/nextjs-full/db/migrations/mysql/.snapshot.json deleted file mode 100644 index 55491d32b..000000000 --- a/templates/nextjs-full/db/migrations/mysql/.snapshot.json +++ /dev/null @@ -1,4483 +0,0 @@ -{ - "namespaces": [], - "tables": [ - { - "name": "account", - "columns": { - "access_token": { - "name": "access_token", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "access_token_expires_at": { - "name": "access_token_expires_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "account_id": { - "name": "account_id", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "created_at": { - "name": "created_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "id": { - "name": "id", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": true, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "id_token": { - "name": "id_token", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "password": { - "name": "password", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "provider_id": { - "name": "provider_id", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "refresh_token": { - "name": "refresh_token", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "refresh_token_expires_at": { - "name": "refresh_token_expires_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "scope": { - "name": "scope", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "updated_at": { - "name": "updated_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "user_id": { - "name": "user_id", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - } - }, - "indexes": [ - { - "columnNames": [ - "id" - ], - "composite": false, - "constraint": true, - "keyName": "PRIMARY", - "primary": true, - "unique": true - }, - { - "columnNames": [ - "user_id" - ], - "composite": false, - "constraint": false, - "keyName": "account_user_id_index", - "primary": false, - "unique": false - } - ], - "checks": [], - "triggers": [], - "foreignKeys": { - "account_user_id_foreign": { - "columnNames": [ - "user_id" - ], - "constraintName": "account_user_id_foreign", - "localTableName": "account", - "referencedColumnNames": [ - "id" - ], - "referencedTableName": "core_user", - "deleteRule": "cascade" - } - }, - "comment": null - }, - { - "name": "core_event", - "columns": { - "created_at": { - "name": "created_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "description": { - "name": "description", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "end_time": { - "name": "end_time", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "hidden": { - "name": "hidden", - "type": "tinyint(1)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": "false", - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "boolean" - }, - "host": { - "name": "host", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "id": { - "name": "id", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": true, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "location": { - "name": "location", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": "'TBD'", - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "start_time": { - "name": "start_time", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "title": { - "name": "title", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "type": { - "name": "type", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "updated_at": { - "name": "updated_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - } - }, - "indexes": [ - { - "columnNames": [ - "id" - ], - "composite": false, - "constraint": true, - "keyName": "PRIMARY", - "primary": true, - "unique": true - }, - { - "columnNames": [ - "hidden" - ], - "composite": false, - "constraint": false, - "keyName": "core_event_hidden_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "start_time" - ], - "composite": false, - "constraint": false, - "keyName": "core_event_start_time_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "type" - ], - "composite": false, - "constraint": false, - "keyName": "core_event_type_index", - "primary": false, - "unique": false - } - ], - "checks": [], - "triggers": [], - "foreignKeys": {}, - "comment": null - }, - { - "name": "core_event_scan", - "columns": { - "auth_id": { - "name": "auth_id", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "event_id": { - "name": "event_id", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "id": { - "name": "id", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": true, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "scanned_at": { - "name": "scanned_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "scanned_by_auth_id": { - "name": "scanned_by_auth_id", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - } - }, - "indexes": [ - { - "columnNames": [ - "id" - ], - "composite": false, - "constraint": true, - "keyName": "PRIMARY", - "primary": true, - "unique": true - }, - { - "columnNames": [ - "auth_id" - ], - "composite": false, - "constraint": false, - "keyName": "core_event_scan_auth_id_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "event_id", - "auth_id" - ], - "composite": true, - "constraint": false, - "keyName": "core_event_scan_event_id_auth_id_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "event_id" - ], - "composite": false, - "constraint": false, - "keyName": "core_event_scan_event_id_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "scanned_at" - ], - "composite": false, - "constraint": false, - "keyName": "core_event_scan_scanned_at_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "scanned_by_auth_id" - ], - "composite": false, - "constraint": false, - "keyName": "core_event_scan_scanned_by_auth_id_index", - "primary": false, - "unique": false - } - ], - "checks": [], - "triggers": [], - "foreignKeys": { - "core_event_scan_auth_id_foreign": { - "columnNames": [ - "auth_id" - ], - "constraintName": "core_event_scan_auth_id_foreign", - "localTableName": "core_event_scan", - "referencedColumnNames": [ - "id" - ], - "referencedTableName": "core_user", - "deleteRule": "cascade" - }, - "core_event_scan_event_id_foreign": { - "columnNames": [ - "event_id" - ], - "constraintName": "core_event_scan_event_id_foreign", - "localTableName": "core_event_scan", - "referencedColumnNames": [ - "id" - ], - "referencedTableName": "core_event", - "deleteRule": "cascade" - }, - "core_event_scan_scanned_by_auth_id_foreign": { - "columnNames": [ - "scanned_by_auth_id" - ], - "constraintName": "core_event_scan_scanned_by_auth_id_foreign", - "localTableName": "core_event_scan", - "referencedColumnNames": [ - "id" - ], - "referencedTableName": "core_user" - } - }, - "comment": null - }, - { - "name": "core_hacker", - "columns": { - "auth_id": { - "name": "auth_id", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": true, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "github_url": { - "name": "github_url", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "group": { - "name": "group", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "hackathons_attended": { - "name": "hackathons_attended", - "type": "int", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "integer" - }, - "heard_from": { - "name": "heard_from", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "level_of_study": { - "name": "level_of_study", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "linked_in_url": { - "name": "linked_in_url", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "major": { - "name": "major", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "personal_website_url": { - "name": "personal_website_url", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "registered_at": { - "name": "registered_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "resume_url": { - "name": "resume_url", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "school_id": { - "name": "school_id", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "software_experience": { - "name": "software_experience", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "university": { - "name": "university", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "updated_at": { - "name": "updated_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - } - }, - "indexes": [ - { - "columnNames": [ - "auth_id" - ], - "composite": false, - "constraint": true, - "keyName": "PRIMARY", - "primary": true, - "unique": true - }, - { - "columnNames": [ - "auth_id" - ], - "composite": false, - "constraint": false, - "keyName": "core_hacker_auth_id_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "registered_at" - ], - "composite": false, - "constraint": false, - "keyName": "core_hacker_registered_at_index", - "primary": false, - "unique": false - } - ], - "checks": [], - "triggers": [], - "foreignKeys": { - "core_hacker_auth_id_foreign": { - "columnNames": [ - "auth_id" - ], - "constraintName": "core_hacker_auth_id_foreign", - "localTableName": "core_hacker", - "referencedColumnNames": [ - "id" - ], - "referencedTableName": "core_user", - "updateRule": "cascade", - "deleteRule": "cascade" - } - }, - "comment": null - }, - { - "name": "core_notification_delivery_attempt", - "columns": { - "attempted_at": { - "name": "attempted_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "channel": { - "name": "channel", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "error": { - "name": "error", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "external_id": { - "name": "external_id", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "id": { - "name": "id", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": true, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "intent_id": { - "name": "intent_id", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "metadata": { - "name": "metadata", - "type": "json", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "json" - }, - "provider": { - "name": "provider", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "recipient": { - "name": "recipient", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "status": { - "name": "status", - "type": "enum('delivered','failed','skipped')", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [ - "delivered", - "failed", - "skipped" - ], - "mappedType": "enum" - } - }, - "indexes": [ - { - "columnNames": [ - "id" - ], - "composite": false, - "constraint": true, - "keyName": "PRIMARY", - "primary": true, - "unique": true - }, - { - "columnNames": [ - "attempted_at" - ], - "composite": false, - "constraint": false, - "keyName": "core_notification_delivery_attempt_attempted_at_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "channel" - ], - "composite": false, - "constraint": false, - "keyName": "core_notification_delivery_attempt_channel_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "intent_id" - ], - "composite": false, - "constraint": false, - "keyName": "core_notification_delivery_attempt_intent_id_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "status" - ], - "composite": false, - "constraint": false, - "keyName": "core_notification_delivery_attempt_status_index", - "primary": false, - "unique": false - } - ], - "checks": [], - "triggers": [], - "foreignKeys": { - "core_notification_delivery_attempt_intent_id_foreign": { - "columnNames": [ - "intent_id" - ], - "constraintName": "core_notification_delivery_attempt_intent_id_foreign", - "localTableName": "core_notification_delivery_attempt", - "referencedColumnNames": [ - "id" - ], - "referencedTableName": "core_notification_intent", - "deleteRule": "cascade" - } - }, - "comment": null - }, - { - "name": "core_notification_intent", - "columns": { - "created_at": { - "name": "created_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "id": { - "name": "id", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": true, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "idempotency_key": { - "name": "idempotency_key", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": true, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "kind": { - "name": "kind", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "payload": { - "name": "payload", - "type": "json", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "json" - }, - "recipient_auth_id": { - "name": "recipient_auth_id", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "status": { - "name": "status", - "type": "enum('pending','processing','delivered','failed','skipped')", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": "'pending'", - "comment": null, - "collation": null, - "enumItems": [ - "pending", - "processing", - "delivered", - "failed", - "skipped" - ], - "mappedType": "enum" - }, - "updated_at": { - "name": "updated_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - } - }, - "indexes": [ - { - "columnNames": [ - "id" - ], - "composite": false, - "constraint": true, - "keyName": "PRIMARY", - "primary": true, - "unique": true - }, - { - "columnNames": [ - "created_at" - ], - "composite": false, - "constraint": false, - "keyName": "core_notification_intent_created_at_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "idempotency_key" - ], - "composite": false, - "constraint": true, - "keyName": "core_notification_intent_idempotency_key_unique", - "primary": false, - "unique": true - }, - { - "columnNames": [ - "kind" - ], - "composite": false, - "constraint": false, - "keyName": "core_notification_intent_kind_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "recipient_auth_id" - ], - "composite": false, - "constraint": false, - "keyName": "core_notification_intent_recipient_auth_id_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "status" - ], - "composite": false, - "constraint": false, - "keyName": "core_notification_intent_status_index", - "primary": false, - "unique": false - } - ], - "checks": [], - "triggers": [], - "foreignKeys": { - "core_notification_intent_recipient_auth_id_foreign": { - "columnNames": [ - "recipient_auth_id" - ], - "constraintName": "core_notification_intent_recipient_auth_id_foreign", - "localTableName": "core_notification_intent", - "referencedColumnNames": [ - "id" - ], - "referencedTableName": "core_user", - "deleteRule": "set null" - } - }, - "comment": null - }, - { - "name": "core_operation_lock", - "columns": { - "key": { - "name": "key", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": true, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "token": { - "name": "token", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - } - }, - "indexes": [ - { - "columnNames": [ - "key" - ], - "composite": false, - "constraint": true, - "keyName": "PRIMARY", - "primary": true, - "unique": true - } - ], - "checks": [], - "triggers": [], - "foreignKeys": {}, - "comment": null - }, - { - "name": "core_role", - "columns": { - "color": { - "name": "color", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "created_at": { - "name": "created_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "id": { - "name": "id", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": true, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "name": { - "name": "name", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": true, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "permissions": { - "name": "permissions", - "type": "json", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": "'[]'", - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "json" - }, - "position": { - "name": "position", - "type": "int", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "integer" - }, - "updated_at": { - "name": "updated_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - } - }, - "indexes": [ - { - "columnNames": [ - "id" - ], - "composite": false, - "constraint": true, - "keyName": "PRIMARY", - "primary": true, - "unique": true - }, - { - "columnNames": [ - "name" - ], - "composite": false, - "constraint": true, - "keyName": "core_role_name_unique", - "primary": false, - "unique": true - }, - { - "columnNames": [ - "position" - ], - "composite": false, - "constraint": false, - "keyName": "core_role_position_index", - "primary": false, - "unique": false - } - ], - "checks": [], - "triggers": [], - "foreignKeys": {}, - "comment": null - }, - { - "name": "core_rsvp", - "columns": { - "auth_id": { - "name": "auth_id", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": true, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "cancelled_at": { - "name": "cancelled_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "cancelled_by_auth_id": { - "name": "cancelled_by_auth_id", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "confirmed_at": { - "name": "confirmed_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "created_at": { - "name": "created_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "promoted_at": { - "name": "promoted_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "promoted_by_auth_id": { - "name": "promoted_by_auth_id", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "status": { - "name": "status", - "type": "enum('confirmed','waitlisted','cancelled')", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [ - "confirmed", - "waitlisted", - "cancelled" - ], - "mappedType": "enum" - }, - "updated_at": { - "name": "updated_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "waitlist_position": { - "name": "waitlist_position", - "type": "int", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "integer" - }, - "waitlisted_at": { - "name": "waitlisted_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - } - }, - "indexes": [ - { - "columnNames": [ - "auth_id" - ], - "composite": false, - "constraint": true, - "keyName": "PRIMARY", - "primary": true, - "unique": true - }, - { - "columnNames": [ - "auth_id" - ], - "composite": false, - "constraint": false, - "keyName": "core_rsvp_auth_id_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "cancelled_by_auth_id" - ], - "composite": false, - "constraint": false, - "keyName": "core_rsvp_cancelled_by_auth_id_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "created_at" - ], - "composite": false, - "constraint": false, - "keyName": "core_rsvp_created_at_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "promoted_by_auth_id" - ], - "composite": false, - "constraint": false, - "keyName": "core_rsvp_promoted_by_auth_id_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "status" - ], - "composite": false, - "constraint": false, - "keyName": "core_rsvp_status_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "updated_at" - ], - "composite": false, - "constraint": false, - "keyName": "core_rsvp_updated_at_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "waitlist_position" - ], - "composite": false, - "constraint": false, - "keyName": "core_rsvp_waitlist_position_index", - "primary": false, - "unique": false - } - ], - "checks": [], - "triggers": [], - "foreignKeys": { - "core_rsvp_auth_id_foreign": { - "columnNames": [ - "auth_id" - ], - "constraintName": "core_rsvp_auth_id_foreign", - "localTableName": "core_rsvp", - "referencedColumnNames": [ - "id" - ], - "referencedTableName": "core_user", - "updateRule": "cascade", - "deleteRule": "cascade" - }, - "core_rsvp_cancelled_by_auth_id_foreign": { - "columnNames": [ - "cancelled_by_auth_id" - ], - "constraintName": "core_rsvp_cancelled_by_auth_id_foreign", - "localTableName": "core_rsvp", - "referencedColumnNames": [ - "id" - ], - "referencedTableName": "core_user", - "deleteRule": "set null" - }, - "core_rsvp_promoted_by_auth_id_foreign": { - "columnNames": [ - "promoted_by_auth_id" - ], - "constraintName": "core_rsvp_promoted_by_auth_id_foreign", - "localTableName": "core_rsvp", - "referencedColumnNames": [ - "id" - ], - "referencedTableName": "core_user", - "deleteRule": "set null" - } - }, - "comment": null - }, - { - "name": "core_setting", - "columns": { - "created_at": { - "name": "created_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "created_by_auth_id": { - "name": "created_by_auth_id", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "key": { - "name": "key", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": true, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "updated_at": { - "name": "updated_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "updated_by_auth_id": { - "name": "updated_by_auth_id", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "value": { - "name": "value", - "type": "json", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "json" - } - }, - "indexes": [ - { - "columnNames": [ - "key" - ], - "composite": false, - "constraint": true, - "keyName": "PRIMARY", - "primary": true, - "unique": true - }, - { - "columnNames": [ - "created_by_auth_id" - ], - "composite": false, - "constraint": false, - "keyName": "core_setting_created_by_auth_id_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "updated_at" - ], - "composite": false, - "constraint": false, - "keyName": "core_setting_updated_at_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "updated_by_auth_id" - ], - "composite": false, - "constraint": false, - "keyName": "core_setting_updated_by_auth_id_index", - "primary": false, - "unique": false - } - ], - "checks": [], - "triggers": [], - "foreignKeys": { - "core_setting_created_by_auth_id_foreign": { - "columnNames": [ - "created_by_auth_id" - ], - "constraintName": "core_setting_created_by_auth_id_foreign", - "localTableName": "core_setting", - "referencedColumnNames": [ - "id" - ], - "referencedTableName": "core_user", - "deleteRule": "set null" - }, - "core_setting_updated_by_auth_id_foreign": { - "columnNames": [ - "updated_by_auth_id" - ], - "constraintName": "core_setting_updated_by_auth_id_foreign", - "localTableName": "core_setting", - "referencedColumnNames": [ - "id" - ], - "referencedTableName": "core_user", - "deleteRule": "set null" - } - }, - "comment": null - }, - { - "name": "core_user", - "columns": { - "bio": { - "name": "bio", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "checked_in_at": { - "name": "checked_in_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "created_at": { - "name": "created_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "discord_display_handle": { - "name": "discord_display_handle", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "email": { - "name": "email", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": true, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "email_verified": { - "name": "email_verified", - "type": "tinyint(1)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": "false", - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "boolean" - }, - "hack_tag": { - "name": "hack_tag", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": true, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "id": { - "name": "id", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": true, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "is_approved": { - "name": "is_approved", - "type": "tinyint(1)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": "false", - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "boolean" - }, - "is_profile_searchable": { - "name": "is_profile_searchable", - "type": "tinyint(1)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": "true", - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "boolean" - }, - "name": { - "name": "name", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "profile_photo_url": { - "name": "profile_photo_url", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "pronouns": { - "name": "pronouns", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "role_id": { - "name": "role_id", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "skills": { - "name": "skills", - "type": "json", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": "'[]'", - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "json" - }, - "updated_at": { - "name": "updated_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - } - }, - "indexes": [ - { - "columnNames": [ - "id" - ], - "composite": false, - "constraint": true, - "keyName": "PRIMARY", - "primary": true, - "unique": true - }, - { - "columnNames": [ - "created_at" - ], - "composite": false, - "constraint": false, - "keyName": "core_user_created_at_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "email" - ], - "composite": false, - "constraint": true, - "keyName": "core_user_email_unique", - "primary": false, - "unique": true - }, - { - "columnNames": [ - "hack_tag" - ], - "composite": false, - "constraint": false, - "keyName": "core_user_hack_tag_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "hack_tag" - ], - "composite": false, - "constraint": true, - "keyName": "core_user_hack_tag_unique", - "primary": false, - "unique": true - }, - { - "columnNames": [ - "role_id" - ], - "composite": false, - "constraint": false, - "keyName": "core_user_role_id_index", - "primary": false, - "unique": false - } - ], - "checks": [], - "triggers": [], - "foreignKeys": { - "core_user_role_id_foreign": { - "columnNames": [ - "role_id" - ], - "constraintName": "core_user_role_id_foreign", - "localTableName": "core_user", - "referencedColumnNames": [ - "id" - ], - "referencedTableName": "core_role", - "deleteRule": "set null" - } - }, - "comment": null - }, - { - "name": "core_user_ban", - "columns": { - "auth_id": { - "name": "auth_id", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": true, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "banned_by_auth_id": { - "name": "banned_by_auth_id", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "created_at": { - "name": "created_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "reason": { - "name": "reason", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - } - }, - "indexes": [ - { - "columnNames": [ - "auth_id" - ], - "composite": false, - "constraint": true, - "keyName": "PRIMARY", - "primary": true, - "unique": true - }, - { - "columnNames": [ - "auth_id" - ], - "composite": false, - "constraint": false, - "keyName": "core_user_ban_auth_id_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "banned_by_auth_id" - ], - "composite": false, - "constraint": false, - "keyName": "core_user_ban_banned_by_auth_id_index", - "primary": false, - "unique": false - } - ], - "checks": [], - "triggers": [], - "foreignKeys": { - "core_user_ban_auth_id_foreign": { - "columnNames": [ - "auth_id" - ], - "constraintName": "core_user_ban_auth_id_foreign", - "localTableName": "core_user_ban", - "referencedColumnNames": [ - "id" - ], - "referencedTableName": "core_user", - "updateRule": "cascade", - "deleteRule": "cascade" - }, - "core_user_ban_banned_by_auth_id_foreign": { - "columnNames": [ - "banned_by_auth_id" - ], - "constraintName": "core_user_ban_banned_by_auth_id_foreign", - "localTableName": "core_user_ban", - "referencedColumnNames": [ - "id" - ], - "referencedTableName": "core_user" - } - }, - "comment": null - }, - { - "name": "core_user_data", - "columns": { - "accommodation_note": { - "name": "accommodation_note", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "age": { - "name": "age", - "type": "int", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "integer" - }, - "auth_id": { - "name": "auth_id", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": true, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "completed_at": { - "name": "completed_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "country_of_residence": { - "name": "country_of_residence", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "dietary_restrictions": { - "name": "dietary_restrictions", - "type": "json", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": "'[]'", - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "json" - }, - "ethnicity": { - "name": "ethnicity", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "gender": { - "name": "gender", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "has_accepted_mlhcode_of_conduct": { - "name": "has_accepted_mlhcode_of_conduct", - "type": "tinyint(1)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "boolean" - }, - "has_shared_data_with_mlh": { - "name": "has_shared_data_with_mlh", - "type": "tinyint(1)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "boolean" - }, - "is_emailable": { - "name": "is_emailable", - "type": "tinyint(1)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "boolean" - }, - "phone_number": { - "name": "phone_number", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "race": { - "name": "race", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "shirt_size": { - "name": "shirt_size", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "updated_at": { - "name": "updated_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - } - }, - "indexes": [ - { - "columnNames": [ - "auth_id" - ], - "composite": false, - "constraint": true, - "keyName": "PRIMARY", - "primary": true, - "unique": true - }, - { - "columnNames": [ - "auth_id" - ], - "composite": false, - "constraint": false, - "keyName": "core_user_data_auth_id_index", - "primary": false, - "unique": false - } - ], - "checks": [], - "triggers": [], - "foreignKeys": { - "core_user_data_auth_id_foreign": { - "columnNames": [ - "auth_id" - ], - "constraintName": "core_user_data_auth_id_foreign", - "localTableName": "core_user_data", - "referencedColumnNames": [ - "id" - ], - "referencedTableName": "core_user", - "updateRule": "cascade", - "deleteRule": "cascade" - } - }, - "comment": null - }, - { - "name": "discord_member", - "columns": { - "auth_id": { - "name": "auth_id", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": true, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "avatar_hash": { - "name": "avatar_hash", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "discord_user_id": { - "name": "discord_user_id", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": true, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "guild_id": { - "name": "guild_id", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "last_role_sync_at": { - "name": "last_role_sync_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "updated_at": { - "name": "updated_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "username": { - "name": "username", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "verified_at": { - "name": "verified_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - } - }, - "indexes": [ - { - "columnNames": [ - "auth_id" - ], - "composite": false, - "constraint": true, - "keyName": "PRIMARY", - "primary": true, - "unique": true - }, - { - "columnNames": [ - "auth_id" - ], - "composite": false, - "constraint": false, - "keyName": "discord_member_auth_id_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "discord_user_id" - ], - "composite": false, - "constraint": false, - "keyName": "discord_member_discord_user_id_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "discord_user_id" - ], - "composite": false, - "constraint": true, - "keyName": "discord_member_discord_user_id_unique", - "primary": false, - "unique": true - }, - { - "columnNames": [ - "guild_id" - ], - "composite": false, - "constraint": false, - "keyName": "discord_member_guild_id_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "updated_at" - ], - "composite": false, - "constraint": false, - "keyName": "discord_member_updated_at_index", - "primary": false, - "unique": false - } - ], - "checks": [], - "triggers": [], - "foreignKeys": { - "discord_member_auth_id_foreign": { - "columnNames": [ - "auth_id" - ], - "constraintName": "discord_member_auth_id_foreign", - "localTableName": "discord_member", - "referencedColumnNames": [ - "id" - ], - "referencedTableName": "core_user", - "updateRule": "cascade", - "deleteRule": "cascade" - } - }, - "comment": null - }, - { - "name": "discord_role_sync_attempt", - "columns": { - "auth_id": { - "name": "auth_id", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "created_at": { - "name": "created_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "discord_user_id": { - "name": "discord_user_id", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "error": { - "name": "error", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "guild_id": { - "name": "guild_id", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "id": { - "name": "id", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": true, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "role_ids": { - "name": "role_ids", - "type": "json", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": "'[]'", - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "json" - }, - "role_names": { - "name": "role_names", - "type": "json", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": "'[]'", - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "json" - }, - "status": { - "name": "status", - "type": "enum('synced','failed','skipped')", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [ - "synced", - "failed", - "skipped" - ], - "mappedType": "enum" - } - }, - "indexes": [ - { - "columnNames": [ - "id" - ], - "composite": false, - "constraint": true, - "keyName": "PRIMARY", - "primary": true, - "unique": true - }, - { - "columnNames": [ - "auth_id" - ], - "composite": false, - "constraint": false, - "keyName": "discord_role_sync_attempt_auth_id_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "created_at" - ], - "composite": false, - "constraint": false, - "keyName": "discord_role_sync_attempt_created_at_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "discord_user_id" - ], - "composite": false, - "constraint": false, - "keyName": "discord_role_sync_attempt_discord_user_id_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "status" - ], - "composite": false, - "constraint": false, - "keyName": "discord_role_sync_attempt_status_index", - "primary": false, - "unique": false - } - ], - "checks": [], - "triggers": [], - "foreignKeys": { - "discord_role_sync_attempt_auth_id_foreign": { - "columnNames": [ - "auth_id" - ], - "constraintName": "discord_role_sync_attempt_auth_id_foreign", - "localTableName": "discord_role_sync_attempt", - "referencedColumnNames": [ - "id" - ], - "referencedTableName": "core_user", - "deleteRule": "cascade" - } - }, - "comment": null - }, - { - "name": "discord_verification", - "columns": { - "accepted_at": { - "name": "accepted_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "auth_id": { - "name": "auth_id", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "avatar_hash": { - "name": "avatar_hash", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "code": { - "name": "code", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": true, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "created_at": { - "name": "created_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "discord_user_id": { - "name": "discord_user_id", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "expires_at": { - "name": "expires_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "guild_id": { - "name": "guild_id", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "status": { - "name": "status", - "type": "enum('pending','accepted','rejected','expired')", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": "'pending'", - "comment": null, - "collation": null, - "enumItems": [ - "pending", - "accepted", - "rejected", - "expired" - ], - "mappedType": "enum" - }, - "username": { - "name": "username", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - } - }, - "indexes": [ - { - "columnNames": [ - "code" - ], - "composite": false, - "constraint": true, - "keyName": "PRIMARY", - "primary": true, - "unique": true - }, - { - "columnNames": [ - "auth_id" - ], - "composite": false, - "constraint": false, - "keyName": "discord_verification_auth_id_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "created_at" - ], - "composite": false, - "constraint": false, - "keyName": "discord_verification_created_at_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "discord_user_id" - ], - "composite": false, - "constraint": false, - "keyName": "discord_verification_discord_user_id_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "guild_id" - ], - "composite": false, - "constraint": false, - "keyName": "discord_verification_guild_id_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "status" - ], - "composite": false, - "constraint": false, - "keyName": "discord_verification_status_index", - "primary": false, - "unique": false - } - ], - "checks": [], - "triggers": [], - "foreignKeys": { - "discord_verification_auth_id_foreign": { - "columnNames": [ - "auth_id" - ], - "constraintName": "discord_verification_auth_id_foreign", - "localTableName": "discord_verification", - "referencedColumnNames": [ - "id" - ], - "referencedTableName": "core_user", - "deleteRule": "set null" - } - }, - "comment": null - }, - { - "name": "session", - "columns": { - "created_at": { - "name": "created_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "expires_at": { - "name": "expires_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "id": { - "name": "id", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": true, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "ip_address": { - "name": "ip_address", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "token": { - "name": "token", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": true, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "updated_at": { - "name": "updated_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "user_agent": { - "name": "user_agent", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "user_id": { - "name": "user_id", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - } - }, - "indexes": [ - { - "columnNames": [ - "id" - ], - "composite": false, - "constraint": true, - "keyName": "PRIMARY", - "primary": true, - "unique": true - }, - { - "columnNames": [ - "token" - ], - "composite": false, - "constraint": true, - "keyName": "session_token_unique", - "primary": false, - "unique": true - }, - { - "columnNames": [ - "user_id" - ], - "composite": false, - "constraint": false, - "keyName": "session_user_id_index", - "primary": false, - "unique": false - } - ], - "checks": [], - "triggers": [], - "foreignKeys": { - "session_user_id_foreign": { - "columnNames": [ - "user_id" - ], - "constraintName": "session_user_id_foreign", - "localTableName": "session", - "referencedColumnNames": [ - "id" - ], - "referencedTableName": "core_user", - "deleteRule": "cascade" - } - }, - "comment": null - }, - { - "name": "teams_invite", - "columns": { - "created_at": { - "name": "created_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "id": { - "name": "id", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": true, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "invitee_auth_id": { - "name": "invitee_auth_id", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "status": { - "name": "status", - "type": "enum('pending','accepted','declined')", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": "'pending'", - "comment": null, - "collation": null, - "enumItems": [ - "pending", - "accepted", - "declined" - ], - "mappedType": "enum" - }, - "team_id": { - "name": "team_id", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - } - }, - "indexes": [ - { - "columnNames": [ - "id" - ], - "composite": false, - "constraint": true, - "keyName": "PRIMARY", - "primary": true, - "unique": true - }, - { - "columnNames": [ - "invitee_auth_id" - ], - "composite": false, - "constraint": false, - "keyName": "teams_invite_invitee_auth_id_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "team_id" - ], - "composite": false, - "constraint": false, - "keyName": "teams_invite_team_id_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "team_id", - "invitee_auth_id" - ], - "composite": true, - "constraint": false, - "keyName": "teams_invite_team_id_invitee_auth_id_index", - "primary": false, - "unique": false - } - ], - "checks": [], - "triggers": [], - "foreignKeys": { - "teams_invite_invitee_auth_id_foreign": { - "columnNames": [ - "invitee_auth_id" - ], - "constraintName": "teams_invite_invitee_auth_id_foreign", - "localTableName": "teams_invite", - "referencedColumnNames": [ - "id" - ], - "referencedTableName": "core_user", - "deleteRule": "cascade" - }, - "teams_invite_team_id_foreign": { - "columnNames": [ - "team_id" - ], - "constraintName": "teams_invite_team_id_foreign", - "localTableName": "teams_invite", - "referencedColumnNames": [ - "id" - ], - "referencedTableName": "teams_team", - "deleteRule": "cascade" - } - }, - "comment": null - }, - { - "name": "teams_member", - "columns": { - "auth_id": { - "name": "auth_id", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": true, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "id": { - "name": "id", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": true, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "joined_at": { - "name": "joined_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "team_id": { - "name": "team_id", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - } - }, - "indexes": [ - { - "columnNames": [ - "id" - ], - "composite": false, - "constraint": true, - "keyName": "PRIMARY", - "primary": true, - "unique": true - }, - { - "columnNames": [ - "auth_id" - ], - "composite": false, - "constraint": false, - "keyName": "teams_member_auth_id_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "auth_id" - ], - "composite": false, - "constraint": true, - "keyName": "teams_member_auth_id_unique", - "primary": false, - "unique": true - }, - { - "columnNames": [ - "team_id" - ], - "composite": false, - "constraint": false, - "keyName": "teams_member_team_id_index", - "primary": false, - "unique": false - } - ], - "checks": [], - "triggers": [], - "foreignKeys": { - "teams_member_auth_id_foreign": { - "columnNames": [ - "auth_id" - ], - "constraintName": "teams_member_auth_id_foreign", - "localTableName": "teams_member", - "referencedColumnNames": [ - "id" - ], - "referencedTableName": "core_user", - "deleteRule": "cascade" - }, - "teams_member_team_id_foreign": { - "columnNames": [ - "team_id" - ], - "constraintName": "teams_member_team_id_foreign", - "localTableName": "teams_member", - "referencedColumnNames": [ - "id" - ], - "referencedTableName": "teams_team", - "deleteRule": "cascade" - } - }, - "comment": null - }, - { - "name": "teams_team", - "columns": { - "created_at": { - "name": "created_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "id": { - "name": "id", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": true, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "name": { - "name": "name", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "owner_auth_id": { - "name": "owner_auth_id", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "tag": { - "name": "tag", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": true, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - } - }, - "indexes": [ - { - "columnNames": [ - "id" - ], - "composite": false, - "constraint": true, - "keyName": "PRIMARY", - "primary": true, - "unique": true - }, - { - "columnNames": [ - "owner_auth_id" - ], - "composite": false, - "constraint": false, - "keyName": "teams_team_owner_auth_id_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "tag" - ], - "composite": false, - "constraint": false, - "keyName": "teams_team_tag_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "tag" - ], - "composite": false, - "constraint": true, - "keyName": "teams_team_tag_unique", - "primary": false, - "unique": true - } - ], - "checks": [], - "triggers": [], - "foreignKeys": { - "teams_team_owner_auth_id_foreign": { - "columnNames": [ - "owner_auth_id" - ], - "constraintName": "teams_team_owner_auth_id_foreign", - "localTableName": "teams_team", - "referencedColumnNames": [ - "id" - ], - "referencedTableName": "core_user", - "deleteRule": "cascade" - } - }, - "comment": null - }, - { - "name": "verification", - "columns": { - "created_at": { - "name": "created_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "expires_at": { - "name": "expires_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "id": { - "name": "id", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": true, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "identifier": { - "name": "identifier", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "updated_at": { - "name": "updated_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "value": { - "name": "value", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - } - }, - "indexes": [ - { - "columnNames": [ - "id" - ], - "composite": false, - "constraint": true, - "keyName": "PRIMARY", - "primary": true, - "unique": true - }, - { - "columnNames": [ - "identifier" - ], - "composite": false, - "constraint": false, - "keyName": "verification_identifier_index", - "primary": false, - "unique": false - } - ], - "checks": [], - "triggers": [], - "foreignKeys": {}, - "comment": null - } - ], - "views": [], - "nativeEnums": {} -} \ No newline at end of file diff --git a/templates/nextjs-full/db/migrations/mysql/Migration20260927180400_initial.ts b/templates/nextjs-full/db/migrations/mysql/Migration20260927180400_initial.ts deleted file mode 100644 index 9160bcbf2..000000000 --- a/templates/nextjs-full/db/migrations/mysql/Migration20260927180400_initial.ts +++ /dev/null @@ -1,171 +0,0 @@ -import { Migration } from "@mikro-orm/migrations"; - -export class Migration20260927180400_initial extends Migration { - override name = "Migration20260927180400_initial"; - - override up(): void { - this.addSql("create table `verification` (`id` varchar(255) not null, `identifier` varchar(255) not null, `value` text not null, `expires_at` datetime not null, `created_at` datetime null, `updated_at` datetime null, primary key (`id`)) default character set utf8mb4 engine = InnoDB;"); - this.addSql("alter table `verification` add index `verification_identifier_index` (`identifier`);"); - this.addSql("create table `core_event` (`id` varchar(255) not null, `title` varchar(255) not null, `start_time` datetime not null, `end_time` datetime not null, `location` varchar(255) not null default 'TBD', `description` text not null, `type` varchar(255) not null, `host` varchar(255) null, `hidden` tinyint(1) not null default false, `created_at` datetime not null, `updated_at` datetime not null, primary key (`id`)) default character set utf8mb4 engine = InnoDB;"); - this.addSql("alter table `core_event` add index `core_event_start_time_index` (`start_time`);"); - this.addSql("alter table `core_event` add index `core_event_type_index` (`type`);"); - this.addSql("alter table `core_event` add index `core_event_hidden_index` (`hidden`);"); - this.addSql("create table `core_operation_lock` (`key` varchar(255) not null, `token` varchar(255) not null, primary key (`key`)) default character set utf8mb4 engine = InnoDB;"); - this.addSql("create table `core_role` (`id` varchar(255) not null, `name` varchar(255) not null, `position` int not null, `permissions` json not null default ('[]'), `color` varchar(255) null, `created_at` datetime not null, `updated_at` datetime not null, primary key (`id`)) default character set utf8mb4 engine = InnoDB;"); - this.addSql("alter table `core_role` add unique `core_role_name_unique` (`name`);"); - this.addSql("alter table `core_role` add index `core_role_position_index` (`position`);"); - this.addSql("create table `core_user` (`id` varchar(255) not null, `name` varchar(255) not null, `email` varchar(255) not null, `email_verified` tinyint(1) not null default false, `profile_photo_url` text null, `hack_tag` varchar(255) null, `bio` text null, `pronouns` varchar(255) null, `skills` json not null default ('[]'), `is_profile_searchable` tinyint(1) not null default true, `discord_display_handle` varchar(255) null, `role_id` varchar(255) null, `is_approved` tinyint(1) not null default false, `checked_in_at` datetime null, `created_at` datetime not null, `updated_at` datetime not null, primary key (`id`)) default character set utf8mb4 engine = InnoDB;"); - this.addSql("alter table `core_user` add unique `core_user_email_unique` (`email`);"); - this.addSql("alter table `core_user` add unique `core_user_hack_tag_unique` (`hack_tag`);"); - this.addSql("alter table `core_user` add index `core_user_hack_tag_index` (`hack_tag`);"); - this.addSql("alter table `core_user` add index `core_user_role_id_index` (`role_id`);"); - this.addSql("alter table `core_user` add index `core_user_created_at_index` (`created_at`);"); - this.addSql("create table `discord_verification` (`code` varchar(255) not null, `discord_user_id` varchar(255) not null, `guild_id` varchar(255) not null, `username` varchar(255) not null, `avatar_hash` varchar(255) null, `auth_id` varchar(255) null, `status` enum('pending','accepted','rejected','expired') not null default 'pending', `expires_at` datetime not null, `created_at` datetime not null, `accepted_at` datetime null, primary key (`code`)) default character set utf8mb4 engine = InnoDB;"); - this.addSql("alter table `discord_verification` add index `discord_verification_discord_user_id_index` (`discord_user_id`);"); - this.addSql("alter table `discord_verification` add index `discord_verification_guild_id_index` (`guild_id`);"); - this.addSql("alter table `discord_verification` add index `discord_verification_auth_id_index` (`auth_id`);"); - this.addSql("alter table `discord_verification` add index `discord_verification_status_index` (`status`);"); - this.addSql("alter table `discord_verification` add index `discord_verification_created_at_index` (`created_at`);"); - this.addSql("create table `discord_role_sync_attempt` (`id` varchar(255) not null, `auth_id` varchar(255) not null, `discord_user_id` varchar(255) not null, `guild_id` varchar(255) not null, `status` enum('synced','failed','skipped') not null, `role_ids` json not null default ('[]'), `role_names` json not null default ('[]'), `error` text null, `created_at` datetime not null, primary key (`id`)) default character set utf8mb4 engine = InnoDB;"); - this.addSql("alter table `discord_role_sync_attempt` add index `discord_role_sync_attempt_auth_id_index` (`auth_id`);"); - this.addSql("alter table `discord_role_sync_attempt` add index `discord_role_sync_attempt_discord_user_id_index` (`discord_user_id`);"); - this.addSql("alter table `discord_role_sync_attempt` add index `discord_role_sync_attempt_status_index` (`status`);"); - this.addSql("alter table `discord_role_sync_attempt` add index `discord_role_sync_attempt_created_at_index` (`created_at`);"); - this.addSql("create table `discord_member` (`auth_id` varchar(255) not null, `discord_user_id` varchar(255) not null, `guild_id` varchar(255) not null, `username` varchar(255) not null, `avatar_hash` varchar(255) null, `verified_at` datetime not null, `updated_at` datetime not null, `last_role_sync_at` datetime null, primary key (`auth_id`)) default character set utf8mb4 engine = InnoDB;"); - this.addSql("alter table `discord_member` add index `discord_member_auth_id_index` (`auth_id`);"); - this.addSql("alter table `discord_member` add unique `discord_member_discord_user_id_unique` (`discord_user_id`);"); - this.addSql("alter table `discord_member` add index `discord_member_discord_user_id_index` (`discord_user_id`);"); - this.addSql("alter table `discord_member` add index `discord_member_guild_id_index` (`guild_id`);"); - this.addSql("alter table `discord_member` add index `discord_member_updated_at_index` (`updated_at`);"); - this.addSql("create table `core_user_data` (`auth_id` varchar(255) not null, `age` int not null, `gender` varchar(255) not null, `race` varchar(255) not null, `ethnicity` varchar(255) not null, `shirt_size` varchar(255) not null, `dietary_restrictions` json not null default ('[]'), `accommodation_note` text null, `phone_number` varchar(255) null, `country_of_residence` varchar(255) null, `has_accepted_mlhcode_of_conduct` tinyint(1) not null, `has_shared_data_with_mlh` tinyint(1) not null, `is_emailable` tinyint(1) not null, `completed_at` datetime not null, `updated_at` datetime not null, primary key (`auth_id`)) default character set utf8mb4 engine = InnoDB;"); - this.addSql("alter table `core_user_data` add index `core_user_data_auth_id_index` (`auth_id`);"); - this.addSql("create table `core_user_ban` (`auth_id` varchar(255) not null, `reason` varchar(255) null, `banned_by_auth_id` varchar(255) not null, `created_at` datetime not null, primary key (`auth_id`)) default character set utf8mb4 engine = InnoDB;"); - this.addSql("alter table `core_user_ban` add index `core_user_ban_auth_id_index` (`auth_id`);"); - this.addSql("alter table `core_user_ban` add index `core_user_ban_banned_by_auth_id_index` (`banned_by_auth_id`);"); - this.addSql("create table `core_setting` (`key` varchar(255) not null, `value` json not null, `created_at` datetime not null, `created_by_auth_id` varchar(255) null, `updated_at` datetime not null, `updated_by_auth_id` varchar(255) null, primary key (`key`)) default character set utf8mb4 engine = InnoDB;"); - this.addSql("alter table `core_setting` add index `core_setting_created_by_auth_id_index` (`created_by_auth_id`);"); - this.addSql("alter table `core_setting` add index `core_setting_updated_at_index` (`updated_at`);"); - this.addSql("alter table `core_setting` add index `core_setting_updated_by_auth_id_index` (`updated_by_auth_id`);"); - this.addSql("create table `core_rsvp` (`auth_id` varchar(255) not null, `status` enum('confirmed','waitlisted','cancelled') not null, `waitlist_position` int null, `created_at` datetime not null, `updated_at` datetime not null, `confirmed_at` datetime null, `waitlisted_at` datetime null, `cancelled_at` datetime null, `cancelled_by_auth_id` varchar(255) null, `promoted_at` datetime null, `promoted_by_auth_id` varchar(255) null, primary key (`auth_id`)) default character set utf8mb4 engine = InnoDB;"); - this.addSql("alter table `core_rsvp` add index `core_rsvp_auth_id_index` (`auth_id`);"); - this.addSql("alter table `core_rsvp` add index `core_rsvp_cancelled_by_auth_id_index` (`cancelled_by_auth_id`);"); - this.addSql("alter table `core_rsvp` add index `core_rsvp_promoted_by_auth_id_index` (`promoted_by_auth_id`);"); - this.addSql("alter table `core_rsvp` add index `core_rsvp_status_index` (`status`);"); - this.addSql("alter table `core_rsvp` add index `core_rsvp_waitlist_position_index` (`waitlist_position`);"); - this.addSql("alter table `core_rsvp` add index `core_rsvp_created_at_index` (`created_at`);"); - this.addSql("alter table `core_rsvp` add index `core_rsvp_updated_at_index` (`updated_at`);"); - this.addSql("create table `core_notification_intent` (`id` varchar(255) not null, `kind` varchar(255) not null, `recipient_auth_id` varchar(255) null, `payload` json not null, `status` enum('pending','processing','delivered','failed','skipped') not null default 'pending', `idempotency_key` varchar(255) null, `created_at` datetime not null, `updated_at` datetime not null, primary key (`id`)) default character set utf8mb4 engine = InnoDB;"); - this.addSql("alter table `core_notification_intent` add unique `core_notification_intent_idempotency_key_unique` (`idempotency_key`);"); - this.addSql("alter table `core_notification_intent` add index `core_notification_intent_kind_index` (`kind`);"); - this.addSql("alter table `core_notification_intent` add index `core_notification_intent_recipient_auth_id_index` (`recipient_auth_id`);"); - this.addSql("alter table `core_notification_intent` add index `core_notification_intent_status_index` (`status`);"); - this.addSql("alter table `core_notification_intent` add index `core_notification_intent_created_at_index` (`created_at`);"); - this.addSql("create table `core_notification_delivery_attempt` (`id` varchar(255) not null, `intent_id` varchar(255) not null, `channel` varchar(255) not null, `provider` varchar(255) null, `status` enum('delivered','failed','skipped') not null, `recipient` varchar(255) null, `external_id` varchar(255) null, `error` text null, `metadata` json not null, `attempted_at` datetime not null, primary key (`id`)) default character set utf8mb4 engine = InnoDB;"); - this.addSql("alter table `core_notification_delivery_attempt` add index `core_notification_delivery_attempt_intent_id_index` (`intent_id`);"); - this.addSql("alter table `core_notification_delivery_attempt` add index `core_notification_delivery_attempt_channel_index` (`channel`);"); - this.addSql("alter table `core_notification_delivery_attempt` add index `core_notification_delivery_attempt_status_index` (`status`);"); - this.addSql("alter table `core_notification_delivery_attempt` add index `core_notification_delivery_attempt_attempted_at_index` (`attempted_at`);"); - this.addSql("create table `core_hacker` (`auth_id` varchar(255) not null, `university` varchar(255) not null, `major` varchar(255) not null, `school_id` varchar(255) null, `level_of_study` varchar(255) not null, `hackathons_attended` int not null, `software_experience` varchar(255) not null, `heard_from` varchar(255) null, `github_url` text null, `linked_in_url` text null, `personal_website_url` text null, `resume_url` text null, `group` varchar(255) null, `registered_at` datetime not null, `updated_at` datetime not null, primary key (`auth_id`)) default character set utf8mb4 engine = InnoDB;"); - this.addSql("alter table `core_hacker` add index `core_hacker_auth_id_index` (`auth_id`);"); - this.addSql("alter table `core_hacker` add index `core_hacker_registered_at_index` (`registered_at`);"); - this.addSql("create table `core_event_scan` (`id` varchar(255) not null, `event_id` varchar(255) not null, `auth_id` varchar(255) not null, `scanned_by_auth_id` varchar(255) not null, `scanned_at` datetime not null, primary key (`id`)) default character set utf8mb4 engine = InnoDB;"); - this.addSql("alter table `core_event_scan` add index `core_event_scan_scanned_by_auth_id_index` (`scanned_by_auth_id`);"); - this.addSql("alter table `core_event_scan` add index `core_event_scan_event_id_index` (`event_id`);"); - this.addSql("alter table `core_event_scan` add index `core_event_scan_auth_id_index` (`auth_id`);"); - this.addSql("alter table `core_event_scan` add index `core_event_scan_event_id_auth_id_index` (`event_id`, `auth_id`);"); - this.addSql("alter table `core_event_scan` add index `core_event_scan_scanned_at_index` (`scanned_at`);"); - this.addSql("create table `session` (`id` varchar(255) not null, `expires_at` datetime not null, `token` varchar(255) not null, `created_at` datetime not null, `updated_at` datetime not null, `ip_address` varchar(255) null, `user_agent` text null, `user_id` varchar(255) not null, primary key (`id`)) default character set utf8mb4 engine = InnoDB;"); - this.addSql("alter table `session` add unique `session_token_unique` (`token`);"); - this.addSql("alter table `session` add index `session_user_id_index` (`user_id`);"); - this.addSql("create table `account` (`id` varchar(255) not null, `account_id` varchar(255) not null, `provider_id` varchar(255) not null, `user_id` varchar(255) not null, `access_token` text null, `refresh_token` text null, `id_token` text null, `access_token_expires_at` datetime null, `refresh_token_expires_at` datetime null, `scope` text null, `password` varchar(255) null, `created_at` datetime not null, `updated_at` datetime not null, primary key (`id`)) default character set utf8mb4 engine = InnoDB;"); - this.addSql("alter table `account` add index `account_user_id_index` (`user_id`);"); - this.addSql("create table `teams_team` (`id` varchar(255) not null, `name` varchar(255) not null, `tag` varchar(255) not null, `owner_auth_id` varchar(255) not null, `created_at` datetime not null, primary key (`id`)) default character set utf8mb4 engine = InnoDB;"); - this.addSql("alter table `teams_team` add unique `teams_team_tag_unique` (`tag`);"); - this.addSql("alter table `teams_team` add index `teams_team_tag_index` (`tag`);"); - this.addSql("alter table `teams_team` add index `teams_team_owner_auth_id_index` (`owner_auth_id`);"); - this.addSql("create table `teams_member` (`id` varchar(255) not null, `team_id` varchar(255) not null, `auth_id` varchar(255) not null, `joined_at` datetime not null, primary key (`id`)) default character set utf8mb4 engine = InnoDB;"); - this.addSql("alter table `teams_member` add unique `teams_member_auth_id_unique` (`auth_id`);"); - this.addSql("alter table `teams_member` add index `teams_member_team_id_index` (`team_id`);"); - this.addSql("alter table `teams_member` add index `teams_member_auth_id_index` (`auth_id`);"); - this.addSql("create table `teams_invite` (`id` varchar(255) not null, `team_id` varchar(255) not null, `invitee_auth_id` varchar(255) not null, `status` enum('pending','accepted','declined') not null default 'pending', `created_at` datetime not null, primary key (`id`)) default character set utf8mb4 engine = InnoDB;"); - this.addSql("alter table `teams_invite` add index `teams_invite_team_id_index` (`team_id`);"); - this.addSql("alter table `teams_invite` add index `teams_invite_invitee_auth_id_index` (`invitee_auth_id`);"); - this.addSql("alter table `teams_invite` add index `teams_invite_team_id_invitee_auth_id_index` (`team_id`, `invitee_auth_id`);"); - this.addSql("alter table `core_user` add constraint `core_user_role_id_foreign` foreign key (`role_id`) references `core_role` (`id`) on delete set null;"); - this.addSql("alter table `discord_verification` add constraint `discord_verification_auth_id_foreign` foreign key (`auth_id`) references `core_user` (`id`) on delete set null;"); - this.addSql("alter table `discord_role_sync_attempt` add constraint `discord_role_sync_attempt_auth_id_foreign` foreign key (`auth_id`) references `core_user` (`id`) on delete cascade;"); - this.addSql("alter table `discord_member` add constraint `discord_member_auth_id_foreign` foreign key (`auth_id`) references `core_user` (`id`) on update cascade on delete cascade;"); - this.addSql("alter table `core_user_data` add constraint `core_user_data_auth_id_foreign` foreign key (`auth_id`) references `core_user` (`id`) on update cascade on delete cascade;"); - this.addSql("alter table `core_user_ban` add constraint `core_user_ban_auth_id_foreign` foreign key (`auth_id`) references `core_user` (`id`) on update cascade on delete cascade;"); - this.addSql("alter table `core_user_ban` add constraint `core_user_ban_banned_by_auth_id_foreign` foreign key (`banned_by_auth_id`) references `core_user` (`id`);"); - this.addSql("alter table `core_setting` add constraint `core_setting_created_by_auth_id_foreign` foreign key (`created_by_auth_id`) references `core_user` (`id`) on delete set null;"); - this.addSql("alter table `core_setting` add constraint `core_setting_updated_by_auth_id_foreign` foreign key (`updated_by_auth_id`) references `core_user` (`id`) on delete set null;"); - this.addSql("alter table `core_rsvp` add constraint `core_rsvp_auth_id_foreign` foreign key (`auth_id`) references `core_user` (`id`) on update cascade on delete cascade;"); - this.addSql("alter table `core_rsvp` add constraint `core_rsvp_cancelled_by_auth_id_foreign` foreign key (`cancelled_by_auth_id`) references `core_user` (`id`) on delete set null;"); - this.addSql("alter table `core_rsvp` add constraint `core_rsvp_promoted_by_auth_id_foreign` foreign key (`promoted_by_auth_id`) references `core_user` (`id`) on delete set null;"); - this.addSql("alter table `core_notification_intent` add constraint `core_notification_intent_recipient_auth_id_foreign` foreign key (`recipient_auth_id`) references `core_user` (`id`) on delete set null;"); - this.addSql("alter table `core_notification_delivery_attempt` add constraint `core_notification_delivery_attempt_intent_id_foreign` foreign key (`intent_id`) references `core_notification_intent` (`id`) on delete cascade;"); - this.addSql("alter table `core_hacker` add constraint `core_hacker_auth_id_foreign` foreign key (`auth_id`) references `core_user` (`id`) on update cascade on delete cascade;"); - this.addSql("alter table `core_event_scan` add constraint `core_event_scan_event_id_foreign` foreign key (`event_id`) references `core_event` (`id`) on delete cascade;"); - this.addSql("alter table `core_event_scan` add constraint `core_event_scan_auth_id_foreign` foreign key (`auth_id`) references `core_user` (`id`) on delete cascade;"); - this.addSql("alter table `core_event_scan` add constraint `core_event_scan_scanned_by_auth_id_foreign` foreign key (`scanned_by_auth_id`) references `core_user` (`id`);"); - this.addSql("alter table `session` add constraint `session_user_id_foreign` foreign key (`user_id`) references `core_user` (`id`) on delete cascade;"); - this.addSql("alter table `account` add constraint `account_user_id_foreign` foreign key (`user_id`) references `core_user` (`id`) on delete cascade;"); - this.addSql("alter table `teams_team` add constraint `teams_team_owner_auth_id_foreign` foreign key (`owner_auth_id`) references `core_user` (`id`) on delete cascade;"); - this.addSql("alter table `teams_member` add constraint `teams_member_team_id_foreign` foreign key (`team_id`) references `teams_team` (`id`) on delete cascade;"); - this.addSql("alter table `teams_member` add constraint `teams_member_auth_id_foreign` foreign key (`auth_id`) references `core_user` (`id`) on delete cascade;"); - this.addSql("alter table `teams_invite` add constraint `teams_invite_team_id_foreign` foreign key (`team_id`) references `teams_team` (`id`) on delete cascade;"); - this.addSql("alter table `teams_invite` add constraint `teams_invite_invitee_auth_id_foreign` foreign key (`invitee_auth_id`) references `core_user` (`id`) on delete cascade;"); - } - - override down(): void | Promise { - this.addSql(`alter table \`session\` drop foreign key \`session_user_id_foreign\`;`); - this.addSql(`alter table \`account\` drop foreign key \`account_user_id_foreign\`;`); - this.addSql(`alter table \`core_event_scan\` drop foreign key \`core_event_scan_event_id_foreign\`;`); - this.addSql(`alter table \`core_user\` drop foreign key \`core_user_role_id_foreign\`;`); - this.addSql(`alter table \`discord_verification\` drop foreign key \`discord_verification_auth_id_foreign\`;`); - this.addSql(`alter table \`discord_role_sync_attempt\` drop foreign key \`discord_role_sync_attempt_auth_id_foreign\`;`); - this.addSql(`alter table \`discord_member\` drop foreign key \`discord_member_auth_id_foreign\`;`); - this.addSql(`alter table \`core_user_data\` drop foreign key \`core_user_data_auth_id_foreign\`;`); - this.addSql(`alter table \`core_user_ban\` drop foreign key \`core_user_ban_auth_id_foreign\`;`); - this.addSql(`alter table \`core_user_ban\` drop foreign key \`core_user_ban_banned_by_auth_id_foreign\`;`); - this.addSql(`alter table \`core_setting\` drop foreign key \`core_setting_created_by_auth_id_foreign\`;`); - this.addSql(`alter table \`core_setting\` drop foreign key \`core_setting_updated_by_auth_id_foreign\`;`); - this.addSql(`alter table \`core_rsvp\` drop foreign key \`core_rsvp_auth_id_foreign\`;`); - this.addSql(`alter table \`core_rsvp\` drop foreign key \`core_rsvp_cancelled_by_auth_id_foreign\`;`); - this.addSql(`alter table \`core_rsvp\` drop foreign key \`core_rsvp_promoted_by_auth_id_foreign\`;`); - this.addSql(`alter table \`core_notification_intent\` drop foreign key \`core_notification_intent_recipient_auth_id_foreign\`;`); - this.addSql(`alter table \`core_hacker\` drop foreign key \`core_hacker_auth_id_foreign\`;`); - this.addSql(`alter table \`core_event_scan\` drop foreign key \`core_event_scan_auth_id_foreign\`;`); - this.addSql(`alter table \`core_event_scan\` drop foreign key \`core_event_scan_scanned_by_auth_id_foreign\`;`); - this.addSql(`alter table \`teams_team\` drop foreign key \`teams_team_owner_auth_id_foreign\`;`); - this.addSql(`alter table \`teams_member\` drop foreign key \`teams_member_auth_id_foreign\`;`); - this.addSql(`alter table \`teams_invite\` drop foreign key \`teams_invite_invitee_auth_id_foreign\`;`); - this.addSql(`alter table \`core_notification_delivery_attempt\` drop foreign key \`core_notification_delivery_attempt_intent_id_foreign\`;`); - this.addSql(`alter table \`teams_member\` drop foreign key \`teams_member_team_id_foreign\`;`); - this.addSql(`alter table \`teams_invite\` drop foreign key \`teams_invite_team_id_foreign\`;`); - - this.addSql(`drop table if exists \`session\`;`); - this.addSql(`drop table if exists \`account\`;`); - this.addSql(`drop table if exists \`verification\`;`); - this.addSql(`drop table if exists \`core_event\`;`); - this.addSql(`drop table if exists \`core_operation_lock\`;`); - this.addSql(`drop table if exists \`core_role\`;`); - this.addSql(`drop table if exists \`core_user\`;`); - this.addSql(`drop table if exists \`discord_verification\`;`); - this.addSql(`drop table if exists \`discord_role_sync_attempt\`;`); - this.addSql(`drop table if exists \`discord_member\`;`); - this.addSql(`drop table if exists \`core_user_data\`;`); - this.addSql(`drop table if exists \`core_user_ban\`;`); - this.addSql(`drop table if exists \`core_setting\`;`); - this.addSql(`drop table if exists \`core_rsvp\`;`); - this.addSql(`drop table if exists \`core_notification_intent\`;`); - this.addSql(`drop table if exists \`core_notification_delivery_attempt\`;`); - this.addSql(`drop table if exists \`core_hacker\`;`); - this.addSql(`drop table if exists \`core_event_scan\`;`); - this.addSql(`drop table if exists \`teams_team\`;`); - this.addSql(`drop table if exists \`teams_member\`;`); - this.addSql(`drop table if exists \`teams_invite\`;`); - } - -} diff --git a/templates/nextjs-full/db/migrations/postgresql/.snapshot.json b/templates/nextjs-full/db/migrations/postgresql/.snapshot.json deleted file mode 100644 index e4b304873..000000000 --- a/templates/nextjs-full/db/migrations/postgresql/.snapshot.json +++ /dev/null @@ -1,4449 +0,0 @@ -{ - "name": "public", - "namespaces": [ - "public" - ], - "tables": [ - { - "name": "account", - "schema": "public", - "columns": { - "access_token": { - "name": "access_token", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "access_token_expires_at": { - "name": "access_token_expires_at", - "type": "timestamptz(6)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": 6, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "account_id": { - "name": "account_id", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "created_at": { - "name": "created_at", - "type": "timestamptz(6)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 6, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "id": { - "name": "id", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": true, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "id_token": { - "name": "id_token", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "password": { - "name": "password", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "provider_id": { - "name": "provider_id", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "refresh_token": { - "name": "refresh_token", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "refresh_token_expires_at": { - "name": "refresh_token_expires_at", - "type": "timestamptz(6)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": 6, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "scope": { - "name": "scope", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "updated_at": { - "name": "updated_at", - "type": "timestamptz(6)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 6, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "user_id": { - "name": "user_id", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - } - }, - "indexes": [ - { - "columnNames": [ - "id" - ], - "composite": false, - "constraint": true, - "keyName": "account_pkey", - "primary": true, - "unique": true - }, - { - "columnNames": [ - "user_id" - ], - "composite": false, - "constraint": false, - "keyName": "account_user_id_index", - "primary": false, - "unique": false - } - ], - "checks": [], - "triggers": [], - "foreignKeys": { - "account_user_id_foreign": { - "columnNames": [ - "user_id" - ], - "constraintName": "account_user_id_foreign", - "localTableName": "public.account", - "referencedColumnNames": [ - "id" - ], - "referencedTableName": "public.core_user", - "deleteRule": "cascade" - } - }, - "comment": null - }, - { - "name": "core_event", - "schema": "public", - "columns": { - "created_at": { - "name": "created_at", - "type": "timestamptz(6)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 6, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "description": { - "name": "description", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "end_time": { - "name": "end_time", - "type": "timestamptz(6)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 6, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "hidden": { - "name": "hidden", - "type": "boolean", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": "false", - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "boolean" - }, - "host": { - "name": "host", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "id": { - "name": "id", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": true, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "location": { - "name": "location", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": "'TBD'", - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "start_time": { - "name": "start_time", - "type": "timestamptz(6)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 6, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "title": { - "name": "title", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "type": { - "name": "type", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "updated_at": { - "name": "updated_at", - "type": "timestamptz(6)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 6, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - } - }, - "indexes": [ - { - "columnNames": [ - "hidden" - ], - "composite": false, - "constraint": false, - "keyName": "core_event_hidden_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "id" - ], - "composite": false, - "constraint": true, - "keyName": "core_event_pkey", - "primary": true, - "unique": true - }, - { - "columnNames": [ - "start_time" - ], - "composite": false, - "constraint": false, - "keyName": "core_event_start_time_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "type" - ], - "composite": false, - "constraint": false, - "keyName": "core_event_type_index", - "primary": false, - "unique": false - } - ], - "checks": [], - "triggers": [], - "foreignKeys": {}, - "comment": null - }, - { - "name": "core_event_scan", - "schema": "public", - "columns": { - "auth_id": { - "name": "auth_id", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "event_id": { - "name": "event_id", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "id": { - "name": "id", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": true, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "scanned_at": { - "name": "scanned_at", - "type": "timestamptz(6)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 6, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "scanned_by_auth_id": { - "name": "scanned_by_auth_id", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - } - }, - "indexes": [ - { - "columnNames": [ - "auth_id" - ], - "composite": false, - "constraint": false, - "keyName": "core_event_scan_auth_id_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "event_id", - "auth_id" - ], - "composite": true, - "constraint": false, - "keyName": "core_event_scan_event_id_auth_id_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "event_id" - ], - "composite": false, - "constraint": false, - "keyName": "core_event_scan_event_id_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "id" - ], - "composite": false, - "constraint": true, - "keyName": "core_event_scan_pkey", - "primary": true, - "unique": true - }, - { - "columnNames": [ - "scanned_at" - ], - "composite": false, - "constraint": false, - "keyName": "core_event_scan_scanned_at_index", - "primary": false, - "unique": false - } - ], - "checks": [], - "triggers": [], - "foreignKeys": { - "core_event_scan_auth_id_foreign": { - "columnNames": [ - "auth_id" - ], - "constraintName": "core_event_scan_auth_id_foreign", - "localTableName": "public.core_event_scan", - "referencedColumnNames": [ - "id" - ], - "referencedTableName": "public.core_user", - "deleteRule": "cascade" - }, - "core_event_scan_event_id_foreign": { - "columnNames": [ - "event_id" - ], - "constraintName": "core_event_scan_event_id_foreign", - "localTableName": "public.core_event_scan", - "referencedColumnNames": [ - "id" - ], - "referencedTableName": "public.core_event", - "deleteRule": "cascade" - }, - "core_event_scan_scanned_by_auth_id_foreign": { - "columnNames": [ - "scanned_by_auth_id" - ], - "constraintName": "core_event_scan_scanned_by_auth_id_foreign", - "localTableName": "public.core_event_scan", - "referencedColumnNames": [ - "id" - ], - "referencedTableName": "public.core_user" - } - }, - "comment": null - }, - { - "name": "core_hacker", - "schema": "public", - "columns": { - "auth_id": { - "name": "auth_id", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": true, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "github_url": { - "name": "github_url", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "group": { - "name": "group", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "hackathons_attended": { - "name": "hackathons_attended", - "type": "int", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "integer" - }, - "heard_from": { - "name": "heard_from", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "level_of_study": { - "name": "level_of_study", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "linked_in_url": { - "name": "linked_in_url", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "major": { - "name": "major", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "personal_website_url": { - "name": "personal_website_url", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "registered_at": { - "name": "registered_at", - "type": "timestamptz(6)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 6, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "resume_url": { - "name": "resume_url", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "school_id": { - "name": "school_id", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "software_experience": { - "name": "software_experience", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "university": { - "name": "university", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "updated_at": { - "name": "updated_at", - "type": "timestamptz(6)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 6, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - } - }, - "indexes": [ - { - "columnNames": [ - "auth_id" - ], - "composite": false, - "constraint": true, - "keyName": "core_hacker_pkey", - "primary": true, - "unique": true - }, - { - "columnNames": [ - "registered_at" - ], - "composite": false, - "constraint": false, - "keyName": "core_hacker_registered_at_index", - "primary": false, - "unique": false - } - ], - "checks": [], - "triggers": [], - "foreignKeys": { - "core_hacker_auth_id_foreign": { - "columnNames": [ - "auth_id" - ], - "constraintName": "core_hacker_auth_id_foreign", - "localTableName": "public.core_hacker", - "referencedColumnNames": [ - "id" - ], - "referencedTableName": "public.core_user", - "updateRule": "cascade", - "deleteRule": "cascade" - } - }, - "comment": null - }, - { - "name": "core_notification_delivery_attempt", - "schema": "public", - "columns": { - "attempted_at": { - "name": "attempted_at", - "type": "timestamptz(6)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 6, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "channel": { - "name": "channel", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "error": { - "name": "error", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "external_id": { - "name": "external_id", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "id": { - "name": "id", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": true, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "intent_id": { - "name": "intent_id", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "metadata": { - "name": "metadata", - "type": "jsonb", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "json" - }, - "provider": { - "name": "provider", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "recipient": { - "name": "recipient", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "status": { - "name": "status", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [ - "delivered", - "failed", - "skipped" - ], - "mappedType": "enum" - } - }, - "indexes": [ - { - "columnNames": [ - "attempted_at" - ], - "composite": false, - "constraint": false, - "keyName": "core_notification_delivery_attempt_attempted_at_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "channel" - ], - "composite": false, - "constraint": false, - "keyName": "core_notification_delivery_attempt_channel_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "intent_id" - ], - "composite": false, - "constraint": false, - "keyName": "core_notification_delivery_attempt_intent_id_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "id" - ], - "composite": false, - "constraint": true, - "keyName": "core_notification_delivery_attempt_pkey", - "primary": true, - "unique": true - }, - { - "columnNames": [ - "status" - ], - "composite": false, - "constraint": false, - "keyName": "core_notification_delivery_attempt_status_index", - "primary": false, - "unique": false - } - ], - "checks": [ - { - "name": "core_notification_delivery_attempt_status_check", - "expression": "\"status\" in ('delivered', 'failed', 'skipped')", - "definition": "check (\"status\" in ('delivered', 'failed', 'skipped'))", - "columnName": "status" - } - ], - "triggers": [], - "foreignKeys": { - "core_notification_delivery_attempt_intent_id_foreign": { - "columnNames": [ - "intent_id" - ], - "constraintName": "core_notification_delivery_attempt_intent_id_foreign", - "localTableName": "public.core_notification_delivery_attempt", - "referencedColumnNames": [ - "id" - ], - "referencedTableName": "public.core_notification_intent", - "deleteRule": "cascade" - } - }, - "comment": null - }, - { - "name": "core_notification_intent", - "schema": "public", - "columns": { - "created_at": { - "name": "created_at", - "type": "timestamptz(6)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 6, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "id": { - "name": "id", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": true, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "idempotency_key": { - "name": "idempotency_key", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": true, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "kind": { - "name": "kind", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "payload": { - "name": "payload", - "type": "jsonb", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "json" - }, - "recipient_auth_id": { - "name": "recipient_auth_id", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "status": { - "name": "status", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": "'pending'", - "comment": null, - "collation": null, - "enumItems": [ - "pending", - "processing", - "delivered", - "failed", - "skipped" - ], - "mappedType": "enum" - }, - "updated_at": { - "name": "updated_at", - "type": "timestamptz(6)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 6, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - } - }, - "indexes": [ - { - "columnNames": [ - "created_at" - ], - "composite": false, - "constraint": false, - "keyName": "core_notification_intent_created_at_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "idempotency_key" - ], - "composite": false, - "constraint": true, - "keyName": "core_notification_intent_idempotency_key_unique", - "primary": false, - "unique": true - }, - { - "columnNames": [ - "kind" - ], - "composite": false, - "constraint": false, - "keyName": "core_notification_intent_kind_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "id" - ], - "composite": false, - "constraint": true, - "keyName": "core_notification_intent_pkey", - "primary": true, - "unique": true - }, - { - "columnNames": [ - "recipient_auth_id" - ], - "composite": false, - "constraint": false, - "keyName": "core_notification_intent_recipient_auth_id_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "status" - ], - "composite": false, - "constraint": false, - "keyName": "core_notification_intent_status_index", - "primary": false, - "unique": false - } - ], - "checks": [ - { - "name": "core_notification_intent_status_check", - "expression": "\"status\" in ('pending', 'processing', 'delivered', 'failed', 'skipped')", - "definition": "check (\"status\" in ('pending', 'processing', 'delivered', 'failed', 'skipped'))", - "columnName": "status" - } - ], - "triggers": [], - "foreignKeys": { - "core_notification_intent_recipient_auth_id_foreign": { - "columnNames": [ - "recipient_auth_id" - ], - "constraintName": "core_notification_intent_recipient_auth_id_foreign", - "localTableName": "public.core_notification_intent", - "referencedColumnNames": [ - "id" - ], - "referencedTableName": "public.core_user", - "deleteRule": "set null" - } - }, - "comment": null - }, - { - "name": "core_operation_lock", - "schema": "public", - "columns": { - "key": { - "name": "key", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": true, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "token": { - "name": "token", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - } - }, - "indexes": [ - { - "columnNames": [ - "key" - ], - "composite": false, - "constraint": true, - "keyName": "core_operation_lock_pkey", - "primary": true, - "unique": true - } - ], - "checks": [], - "triggers": [], - "foreignKeys": {}, - "comment": null - }, - { - "name": "core_role", - "schema": "public", - "columns": { - "color": { - "name": "color", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "created_at": { - "name": "created_at", - "type": "timestamptz(6)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 6, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "id": { - "name": "id", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": true, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "name": { - "name": "name", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": true, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "permissions": { - "name": "permissions", - "type": "jsonb", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": "'[]'", - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "json" - }, - "position": { - "name": "position", - "type": "int", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "integer" - }, - "updated_at": { - "name": "updated_at", - "type": "timestamptz(6)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 6, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - } - }, - "indexes": [ - { - "columnNames": [ - "name" - ], - "composite": false, - "constraint": true, - "keyName": "core_role_name_unique", - "primary": false, - "unique": true - }, - { - "columnNames": [ - "id" - ], - "composite": false, - "constraint": true, - "keyName": "core_role_pkey", - "primary": true, - "unique": true - }, - { - "columnNames": [ - "position" - ], - "composite": false, - "constraint": false, - "keyName": "core_role_position_index", - "primary": false, - "unique": false - } - ], - "checks": [], - "triggers": [], - "foreignKeys": {}, - "comment": null - }, - { - "name": "core_rsvp", - "schema": "public", - "columns": { - "auth_id": { - "name": "auth_id", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": true, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "cancelled_at": { - "name": "cancelled_at", - "type": "timestamptz(6)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": 6, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "cancelled_by_auth_id": { - "name": "cancelled_by_auth_id", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "confirmed_at": { - "name": "confirmed_at", - "type": "timestamptz(6)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": 6, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "created_at": { - "name": "created_at", - "type": "timestamptz(6)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 6, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "promoted_at": { - "name": "promoted_at", - "type": "timestamptz(6)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": 6, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "promoted_by_auth_id": { - "name": "promoted_by_auth_id", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "status": { - "name": "status", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [ - "confirmed", - "waitlisted", - "cancelled" - ], - "mappedType": "enum" - }, - "updated_at": { - "name": "updated_at", - "type": "timestamptz(6)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 6, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "waitlist_position": { - "name": "waitlist_position", - "type": "int", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "integer" - }, - "waitlisted_at": { - "name": "waitlisted_at", - "type": "timestamptz(6)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": 6, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - } - }, - "indexes": [ - { - "columnNames": [ - "created_at" - ], - "composite": false, - "constraint": false, - "keyName": "core_rsvp_created_at_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "auth_id" - ], - "composite": false, - "constraint": true, - "keyName": "core_rsvp_pkey", - "primary": true, - "unique": true - }, - { - "columnNames": [ - "status" - ], - "composite": false, - "constraint": false, - "keyName": "core_rsvp_status_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "updated_at" - ], - "composite": false, - "constraint": false, - "keyName": "core_rsvp_updated_at_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "waitlist_position" - ], - "composite": false, - "constraint": false, - "keyName": "core_rsvp_waitlist_position_index", - "primary": false, - "unique": false - } - ], - "checks": [ - { - "name": "core_rsvp_status_check", - "expression": "\"status\" in ('confirmed', 'waitlisted', 'cancelled')", - "definition": "check (\"status\" in ('confirmed', 'waitlisted', 'cancelled'))", - "columnName": "status" - } - ], - "triggers": [], - "foreignKeys": { - "core_rsvp_auth_id_foreign": { - "columnNames": [ - "auth_id" - ], - "constraintName": "core_rsvp_auth_id_foreign", - "localTableName": "public.core_rsvp", - "referencedColumnNames": [ - "id" - ], - "referencedTableName": "public.core_user", - "updateRule": "cascade", - "deleteRule": "cascade" - }, - "core_rsvp_cancelled_by_auth_id_foreign": { - "columnNames": [ - "cancelled_by_auth_id" - ], - "constraintName": "core_rsvp_cancelled_by_auth_id_foreign", - "localTableName": "public.core_rsvp", - "referencedColumnNames": [ - "id" - ], - "referencedTableName": "public.core_user", - "deleteRule": "set null" - }, - "core_rsvp_promoted_by_auth_id_foreign": { - "columnNames": [ - "promoted_by_auth_id" - ], - "constraintName": "core_rsvp_promoted_by_auth_id_foreign", - "localTableName": "public.core_rsvp", - "referencedColumnNames": [ - "id" - ], - "referencedTableName": "public.core_user", - "deleteRule": "set null" - } - }, - "comment": null - }, - { - "name": "core_setting", - "schema": "public", - "columns": { - "created_at": { - "name": "created_at", - "type": "timestamptz(6)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 6, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "created_by_auth_id": { - "name": "created_by_auth_id", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "key": { - "name": "key", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": true, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "updated_at": { - "name": "updated_at", - "type": "timestamptz(6)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 6, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "updated_by_auth_id": { - "name": "updated_by_auth_id", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "value": { - "name": "value", - "type": "jsonb", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "json" - } - }, - "indexes": [ - { - "columnNames": [ - "key" - ], - "composite": false, - "constraint": true, - "keyName": "core_setting_pkey", - "primary": true, - "unique": true - }, - { - "columnNames": [ - "updated_at" - ], - "composite": false, - "constraint": false, - "keyName": "core_setting_updated_at_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "updated_by_auth_id" - ], - "composite": false, - "constraint": false, - "keyName": "core_setting_updated_by_auth_id_index", - "primary": false, - "unique": false - } - ], - "checks": [], - "triggers": [], - "foreignKeys": { - "core_setting_created_by_auth_id_foreign": { - "columnNames": [ - "created_by_auth_id" - ], - "constraintName": "core_setting_created_by_auth_id_foreign", - "localTableName": "public.core_setting", - "referencedColumnNames": [ - "id" - ], - "referencedTableName": "public.core_user", - "deleteRule": "set null" - }, - "core_setting_updated_by_auth_id_foreign": { - "columnNames": [ - "updated_by_auth_id" - ], - "constraintName": "core_setting_updated_by_auth_id_foreign", - "localTableName": "public.core_setting", - "referencedColumnNames": [ - "id" - ], - "referencedTableName": "public.core_user", - "deleteRule": "set null" - } - }, - "comment": null - }, - { - "name": "core_user", - "schema": "public", - "columns": { - "bio": { - "name": "bio", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "checked_in_at": { - "name": "checked_in_at", - "type": "timestamptz(6)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": 6, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "created_at": { - "name": "created_at", - "type": "timestamptz(6)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 6, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "discord_display_handle": { - "name": "discord_display_handle", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "email": { - "name": "email", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": true, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "email_verified": { - "name": "email_verified", - "type": "boolean", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": "false", - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "boolean" - }, - "hack_tag": { - "name": "hack_tag", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": true, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "id": { - "name": "id", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": true, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "is_approved": { - "name": "is_approved", - "type": "boolean", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": "false", - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "boolean" - }, - "is_profile_searchable": { - "name": "is_profile_searchable", - "type": "boolean", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": "true", - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "boolean" - }, - "name": { - "name": "name", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "profile_photo_url": { - "name": "profile_photo_url", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "pronouns": { - "name": "pronouns", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "role_id": { - "name": "role_id", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "skills": { - "name": "skills", - "type": "jsonb", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": "'[]'", - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "json" - }, - "updated_at": { - "name": "updated_at", - "type": "timestamptz(6)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 6, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - } - }, - "indexes": [ - { - "columnNames": [ - "created_at" - ], - "composite": false, - "constraint": false, - "keyName": "core_user_created_at_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "email" - ], - "composite": false, - "constraint": true, - "keyName": "core_user_email_unique", - "primary": false, - "unique": true - }, - { - "columnNames": [ - "hack_tag" - ], - "composite": false, - "constraint": false, - "keyName": "core_user_hack_tag_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "hack_tag" - ], - "composite": false, - "constraint": true, - "keyName": "core_user_hack_tag_unique", - "primary": false, - "unique": true - }, - { - "columnNames": [ - "id" - ], - "composite": false, - "constraint": true, - "keyName": "core_user_pkey", - "primary": true, - "unique": true - }, - { - "columnNames": [ - "role_id" - ], - "composite": false, - "constraint": false, - "keyName": "core_user_role_id_index", - "primary": false, - "unique": false - } - ], - "checks": [], - "triggers": [], - "foreignKeys": { - "core_user_role_id_foreign": { - "columnNames": [ - "role_id" - ], - "constraintName": "core_user_role_id_foreign", - "localTableName": "public.core_user", - "referencedColumnNames": [ - "id" - ], - "referencedTableName": "public.core_role", - "deleteRule": "set null" - } - }, - "comment": null - }, - { - "name": "core_user_ban", - "schema": "public", - "columns": { - "auth_id": { - "name": "auth_id", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": true, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "banned_by_auth_id": { - "name": "banned_by_auth_id", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "created_at": { - "name": "created_at", - "type": "timestamptz(6)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 6, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "reason": { - "name": "reason", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - } - }, - "indexes": [ - { - "columnNames": [ - "auth_id" - ], - "composite": false, - "constraint": true, - "keyName": "core_user_ban_pkey", - "primary": true, - "unique": true - } - ], - "checks": [], - "triggers": [], - "foreignKeys": { - "core_user_ban_auth_id_foreign": { - "columnNames": [ - "auth_id" - ], - "constraintName": "core_user_ban_auth_id_foreign", - "localTableName": "public.core_user_ban", - "referencedColumnNames": [ - "id" - ], - "referencedTableName": "public.core_user", - "updateRule": "cascade", - "deleteRule": "cascade" - }, - "core_user_ban_banned_by_auth_id_foreign": { - "columnNames": [ - "banned_by_auth_id" - ], - "constraintName": "core_user_ban_banned_by_auth_id_foreign", - "localTableName": "public.core_user_ban", - "referencedColumnNames": [ - "id" - ], - "referencedTableName": "public.core_user" - } - }, - "comment": null - }, - { - "name": "core_user_data", - "schema": "public", - "columns": { - "accommodation_note": { - "name": "accommodation_note", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "age": { - "name": "age", - "type": "int", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "integer" - }, - "auth_id": { - "name": "auth_id", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": true, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "completed_at": { - "name": "completed_at", - "type": "timestamptz(6)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 6, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "country_of_residence": { - "name": "country_of_residence", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "dietary_restrictions": { - "name": "dietary_restrictions", - "type": "jsonb", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": "'[]'", - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "json" - }, - "ethnicity": { - "name": "ethnicity", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "gender": { - "name": "gender", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "has_accepted_mlhcode_of_conduct": { - "name": "has_accepted_mlhcode_of_conduct", - "type": "boolean", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "boolean" - }, - "has_shared_data_with_mlh": { - "name": "has_shared_data_with_mlh", - "type": "boolean", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "boolean" - }, - "is_emailable": { - "name": "is_emailable", - "type": "boolean", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "boolean" - }, - "phone_number": { - "name": "phone_number", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "race": { - "name": "race", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "shirt_size": { - "name": "shirt_size", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "updated_at": { - "name": "updated_at", - "type": "timestamptz(6)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 6, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - } - }, - "indexes": [ - { - "columnNames": [ - "auth_id" - ], - "composite": false, - "constraint": true, - "keyName": "core_user_data_pkey", - "primary": true, - "unique": true - } - ], - "checks": [], - "triggers": [], - "foreignKeys": { - "core_user_data_auth_id_foreign": { - "columnNames": [ - "auth_id" - ], - "constraintName": "core_user_data_auth_id_foreign", - "localTableName": "public.core_user_data", - "referencedColumnNames": [ - "id" - ], - "referencedTableName": "public.core_user", - "updateRule": "cascade", - "deleteRule": "cascade" - } - }, - "comment": null - }, - { - "name": "discord_member", - "schema": "public", - "columns": { - "auth_id": { - "name": "auth_id", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": true, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "avatar_hash": { - "name": "avatar_hash", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "discord_user_id": { - "name": "discord_user_id", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": true, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "guild_id": { - "name": "guild_id", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "last_role_sync_at": { - "name": "last_role_sync_at", - "type": "timestamptz(6)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": 6, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "updated_at": { - "name": "updated_at", - "type": "timestamptz(6)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 6, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "username": { - "name": "username", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "verified_at": { - "name": "verified_at", - "type": "timestamptz(6)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 6, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - } - }, - "indexes": [ - { - "columnNames": [ - "discord_user_id" - ], - "composite": false, - "constraint": false, - "keyName": "discord_member_discord_user_id_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "discord_user_id" - ], - "composite": false, - "constraint": true, - "keyName": "discord_member_discord_user_id_unique", - "primary": false, - "unique": true - }, - { - "columnNames": [ - "guild_id" - ], - "composite": false, - "constraint": false, - "keyName": "discord_member_guild_id_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "auth_id" - ], - "composite": false, - "constraint": true, - "keyName": "discord_member_pkey", - "primary": true, - "unique": true - }, - { - "columnNames": [ - "updated_at" - ], - "composite": false, - "constraint": false, - "keyName": "discord_member_updated_at_index", - "primary": false, - "unique": false - } - ], - "checks": [], - "triggers": [], - "foreignKeys": { - "discord_member_auth_id_foreign": { - "columnNames": [ - "auth_id" - ], - "constraintName": "discord_member_auth_id_foreign", - "localTableName": "public.discord_member", - "referencedColumnNames": [ - "id" - ], - "referencedTableName": "public.core_user", - "updateRule": "cascade", - "deleteRule": "cascade" - } - }, - "comment": null - }, - { - "name": "discord_role_sync_attempt", - "schema": "public", - "columns": { - "auth_id": { - "name": "auth_id", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "created_at": { - "name": "created_at", - "type": "timestamptz(6)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 6, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "discord_user_id": { - "name": "discord_user_id", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "error": { - "name": "error", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "guild_id": { - "name": "guild_id", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "id": { - "name": "id", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": true, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "role_ids": { - "name": "role_ids", - "type": "jsonb", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": "'[]'", - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "json" - }, - "role_names": { - "name": "role_names", - "type": "jsonb", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": "'[]'", - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "json" - }, - "status": { - "name": "status", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [ - "synced", - "failed", - "skipped" - ], - "mappedType": "enum" - } - }, - "indexes": [ - { - "columnNames": [ - "auth_id" - ], - "composite": false, - "constraint": false, - "keyName": "discord_role_sync_attempt_auth_id_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "created_at" - ], - "composite": false, - "constraint": false, - "keyName": "discord_role_sync_attempt_created_at_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "discord_user_id" - ], - "composite": false, - "constraint": false, - "keyName": "discord_role_sync_attempt_discord_user_id_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "id" - ], - "composite": false, - "constraint": true, - "keyName": "discord_role_sync_attempt_pkey", - "primary": true, - "unique": true - }, - { - "columnNames": [ - "status" - ], - "composite": false, - "constraint": false, - "keyName": "discord_role_sync_attempt_status_index", - "primary": false, - "unique": false - } - ], - "checks": [ - { - "name": "discord_role_sync_attempt_status_check", - "expression": "\"status\" in ('synced', 'failed', 'skipped')", - "definition": "check (\"status\" in ('synced', 'failed', 'skipped'))", - "columnName": "status" - } - ], - "triggers": [], - "foreignKeys": { - "discord_role_sync_attempt_auth_id_foreign": { - "columnNames": [ - "auth_id" - ], - "constraintName": "discord_role_sync_attempt_auth_id_foreign", - "localTableName": "public.discord_role_sync_attempt", - "referencedColumnNames": [ - "id" - ], - "referencedTableName": "public.core_user", - "deleteRule": "cascade" - } - }, - "comment": null - }, - { - "name": "discord_verification", - "schema": "public", - "columns": { - "accepted_at": { - "name": "accepted_at", - "type": "timestamptz(6)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": 6, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "auth_id": { - "name": "auth_id", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "avatar_hash": { - "name": "avatar_hash", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "code": { - "name": "code", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": true, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "created_at": { - "name": "created_at", - "type": "timestamptz(6)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 6, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "discord_user_id": { - "name": "discord_user_id", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "expires_at": { - "name": "expires_at", - "type": "timestamptz(6)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 6, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "guild_id": { - "name": "guild_id", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "status": { - "name": "status", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": "'pending'", - "comment": null, - "collation": null, - "enumItems": [ - "pending", - "accepted", - "rejected", - "expired" - ], - "mappedType": "enum" - }, - "username": { - "name": "username", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - } - }, - "indexes": [ - { - "columnNames": [ - "auth_id" - ], - "composite": false, - "constraint": false, - "keyName": "discord_verification_auth_id_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "created_at" - ], - "composite": false, - "constraint": false, - "keyName": "discord_verification_created_at_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "discord_user_id" - ], - "composite": false, - "constraint": false, - "keyName": "discord_verification_discord_user_id_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "guild_id" - ], - "composite": false, - "constraint": false, - "keyName": "discord_verification_guild_id_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "code" - ], - "composite": false, - "constraint": true, - "keyName": "discord_verification_pkey", - "primary": true, - "unique": true - }, - { - "columnNames": [ - "status" - ], - "composite": false, - "constraint": false, - "keyName": "discord_verification_status_index", - "primary": false, - "unique": false - } - ], - "checks": [ - { - "name": "discord_verification_status_check", - "expression": "\"status\" in ('pending', 'accepted', 'rejected', 'expired')", - "definition": "check (\"status\" in ('pending', 'accepted', 'rejected', 'expired'))", - "columnName": "status" - } - ], - "triggers": [], - "foreignKeys": { - "discord_verification_auth_id_foreign": { - "columnNames": [ - "auth_id" - ], - "constraintName": "discord_verification_auth_id_foreign", - "localTableName": "public.discord_verification", - "referencedColumnNames": [ - "id" - ], - "referencedTableName": "public.core_user", - "deleteRule": "set null" - } - }, - "comment": null - }, - { - "name": "session", - "schema": "public", - "columns": { - "created_at": { - "name": "created_at", - "type": "timestamptz(6)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 6, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "expires_at": { - "name": "expires_at", - "type": "timestamptz(6)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 6, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "id": { - "name": "id", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": true, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "ip_address": { - "name": "ip_address", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "token": { - "name": "token", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": true, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "updated_at": { - "name": "updated_at", - "type": "timestamptz(6)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 6, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "user_agent": { - "name": "user_agent", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "user_id": { - "name": "user_id", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - } - }, - "indexes": [ - { - "columnNames": [ - "id" - ], - "composite": false, - "constraint": true, - "keyName": "session_pkey", - "primary": true, - "unique": true - }, - { - "columnNames": [ - "token" - ], - "composite": false, - "constraint": true, - "keyName": "session_token_unique", - "primary": false, - "unique": true - }, - { - "columnNames": [ - "user_id" - ], - "composite": false, - "constraint": false, - "keyName": "session_user_id_index", - "primary": false, - "unique": false - } - ], - "checks": [], - "triggers": [], - "foreignKeys": { - "session_user_id_foreign": { - "columnNames": [ - "user_id" - ], - "constraintName": "session_user_id_foreign", - "localTableName": "public.session", - "referencedColumnNames": [ - "id" - ], - "referencedTableName": "public.core_user", - "deleteRule": "cascade" - } - }, - "comment": null - }, - { - "name": "teams_invite", - "schema": "public", - "columns": { - "created_at": { - "name": "created_at", - "type": "timestamptz(6)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 6, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "id": { - "name": "id", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": true, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "invitee_auth_id": { - "name": "invitee_auth_id", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "status": { - "name": "status", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": "'pending'", - "comment": null, - "collation": null, - "enumItems": [ - "pending", - "accepted", - "declined" - ], - "mappedType": "enum" - }, - "team_id": { - "name": "team_id", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - } - }, - "indexes": [ - { - "columnNames": [ - "invitee_auth_id" - ], - "composite": false, - "constraint": false, - "keyName": "teams_invite_invitee_auth_id_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "id" - ], - "composite": false, - "constraint": true, - "keyName": "teams_invite_pkey", - "primary": true, - "unique": true - }, - { - "columnNames": [ - "team_id" - ], - "composite": false, - "constraint": false, - "keyName": "teams_invite_team_id_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "team_id", - "invitee_auth_id" - ], - "composite": true, - "constraint": false, - "keyName": "teams_invite_team_id_invitee_auth_id_index", - "primary": false, - "unique": false - } - ], - "checks": [ - { - "name": "teams_invite_status_check", - "expression": "\"status\" in ('pending', 'accepted', 'declined')", - "definition": "check (\"status\" in ('pending', 'accepted', 'declined'))", - "columnName": "status" - } - ], - "triggers": [], - "foreignKeys": { - "teams_invite_invitee_auth_id_foreign": { - "columnNames": [ - "invitee_auth_id" - ], - "constraintName": "teams_invite_invitee_auth_id_foreign", - "localTableName": "public.teams_invite", - "referencedColumnNames": [ - "id" - ], - "referencedTableName": "public.core_user", - "deleteRule": "cascade" - }, - "teams_invite_team_id_foreign": { - "columnNames": [ - "team_id" - ], - "constraintName": "teams_invite_team_id_foreign", - "localTableName": "public.teams_invite", - "referencedColumnNames": [ - "id" - ], - "referencedTableName": "public.teams_team", - "deleteRule": "cascade" - } - }, - "comment": null - }, - { - "name": "teams_member", - "schema": "public", - "columns": { - "auth_id": { - "name": "auth_id", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": true, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "id": { - "name": "id", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": true, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "joined_at": { - "name": "joined_at", - "type": "timestamptz(6)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 6, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "team_id": { - "name": "team_id", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - } - }, - "indexes": [ - { - "columnNames": [ - "auth_id" - ], - "composite": false, - "constraint": false, - "keyName": "teams_member_auth_id_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "auth_id" - ], - "composite": false, - "constraint": true, - "keyName": "teams_member_auth_id_unique", - "primary": false, - "unique": true - }, - { - "columnNames": [ - "id" - ], - "composite": false, - "constraint": true, - "keyName": "teams_member_pkey", - "primary": true, - "unique": true - }, - { - "columnNames": [ - "team_id" - ], - "composite": false, - "constraint": false, - "keyName": "teams_member_team_id_index", - "primary": false, - "unique": false - } - ], - "checks": [], - "triggers": [], - "foreignKeys": { - "teams_member_auth_id_foreign": { - "columnNames": [ - "auth_id" - ], - "constraintName": "teams_member_auth_id_foreign", - "localTableName": "public.teams_member", - "referencedColumnNames": [ - "id" - ], - "referencedTableName": "public.core_user", - "deleteRule": "cascade" - }, - "teams_member_team_id_foreign": { - "columnNames": [ - "team_id" - ], - "constraintName": "teams_member_team_id_foreign", - "localTableName": "public.teams_member", - "referencedColumnNames": [ - "id" - ], - "referencedTableName": "public.teams_team", - "deleteRule": "cascade" - } - }, - "comment": null - }, - { - "name": "teams_team", - "schema": "public", - "columns": { - "created_at": { - "name": "created_at", - "type": "timestamptz(6)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 6, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "id": { - "name": "id", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": true, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "name": { - "name": "name", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "owner_auth_id": { - "name": "owner_auth_id", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "tag": { - "name": "tag", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": true, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - } - }, - "indexes": [ - { - "columnNames": [ - "owner_auth_id" - ], - "composite": false, - "constraint": false, - "keyName": "teams_team_owner_auth_id_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "id" - ], - "composite": false, - "constraint": true, - "keyName": "teams_team_pkey", - "primary": true, - "unique": true - }, - { - "columnNames": [ - "tag" - ], - "composite": false, - "constraint": false, - "keyName": "teams_team_tag_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "tag" - ], - "composite": false, - "constraint": true, - "keyName": "teams_team_tag_unique", - "primary": false, - "unique": true - } - ], - "checks": [], - "triggers": [], - "foreignKeys": { - "teams_team_owner_auth_id_foreign": { - "columnNames": [ - "owner_auth_id" - ], - "constraintName": "teams_team_owner_auth_id_foreign", - "localTableName": "public.teams_team", - "referencedColumnNames": [ - "id" - ], - "referencedTableName": "public.core_user", - "deleteRule": "cascade" - } - }, - "comment": null - }, - { - "name": "verification", - "schema": "public", - "columns": { - "created_at": { - "name": "created_at", - "type": "timestamptz(6)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": 6, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "expires_at": { - "name": "expires_at", - "type": "timestamptz(6)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 6, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "id": { - "name": "id", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": true, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "identifier": { - "name": "identifier", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": 255, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "string" - }, - "updated_at": { - "name": "updated_at", - "type": "timestamptz(6)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": 6, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "value": { - "name": "value", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - } - }, - "indexes": [ - { - "columnNames": [ - "identifier" - ], - "composite": false, - "constraint": false, - "keyName": "verification_identifier_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "id" - ], - "composite": false, - "constraint": true, - "keyName": "verification_pkey", - "primary": true, - "unique": true - } - ], - "checks": [], - "triggers": [], - "foreignKeys": {}, - "comment": null - } - ], - "views": [], - "nativeEnums": {} -} \ No newline at end of file diff --git a/templates/nextjs-full/db/migrations/postgresql/Migration20260927180400_initial.ts b/templates/nextjs-full/db/migrations/postgresql/Migration20260927180400_initial.ts deleted file mode 100644 index 02ac9c298..000000000 --- a/templates/nextjs-full/db/migrations/postgresql/Migration20260927180400_initial.ts +++ /dev/null @@ -1,167 +0,0 @@ -import { Migration } from "@mikro-orm/migrations"; - -export class Migration20260927180400_initial extends Migration { - override name = "Migration20260927180400_initial"; - - override up(): void { - this.addSql("create table \"verification\" (\"id\" varchar(255) not null, \"identifier\" varchar(255) not null, \"value\" text not null, \"expires_at\" timestamptz not null, \"created_at\" timestamptz null, \"updated_at\" timestamptz null, primary key (\"id\"));"); - this.addSql("create index \"verification_identifier_index\" on \"verification\" (\"identifier\");"); - this.addSql("create table \"core_event\" (\"id\" varchar(255) not null, \"title\" varchar(255) not null, \"start_time\" timestamptz not null, \"end_time\" timestamptz not null, \"location\" varchar(255) not null default 'TBD', \"description\" text not null, \"type\" varchar(255) not null, \"host\" varchar(255) null, \"hidden\" boolean not null default false, \"created_at\" timestamptz not null, \"updated_at\" timestamptz not null, primary key (\"id\"));"); - this.addSql("create index \"core_event_start_time_index\" on \"core_event\" (\"start_time\");"); - this.addSql("create index \"core_event_type_index\" on \"core_event\" (\"type\");"); - this.addSql("create index \"core_event_hidden_index\" on \"core_event\" (\"hidden\");"); - this.addSql("create table \"core_operation_lock\" (\"key\" varchar(255) not null, \"token\" varchar(255) not null, primary key (\"key\"));"); - this.addSql("create table \"core_role\" (\"id\" varchar(255) not null, \"name\" varchar(255) not null, \"position\" int not null, \"permissions\" jsonb not null default '[]', \"color\" varchar(255) null, \"created_at\" timestamptz not null, \"updated_at\" timestamptz not null, primary key (\"id\"));"); - this.addSql("alter table \"core_role\" add constraint \"core_role_name_unique\" unique (\"name\");"); - this.addSql("create index \"core_role_position_index\" on \"core_role\" (\"position\");"); - this.addSql("create table \"core_user\" (\"id\" varchar(255) not null, \"name\" varchar(255) not null, \"email\" varchar(255) not null, \"email_verified\" boolean not null default false, \"profile_photo_url\" text null, \"hack_tag\" varchar(255) null, \"bio\" text null, \"pronouns\" varchar(255) null, \"skills\" jsonb not null default '[]', \"is_profile_searchable\" boolean not null default true, \"discord_display_handle\" varchar(255) null, \"role_id\" varchar(255) null, \"is_approved\" boolean not null default false, \"checked_in_at\" timestamptz null, \"created_at\" timestamptz not null, \"updated_at\" timestamptz not null, primary key (\"id\"));"); - this.addSql("alter table \"core_user\" add constraint \"core_user_email_unique\" unique (\"email\");"); - this.addSql("alter table \"core_user\" add constraint \"core_user_hack_tag_unique\" unique (\"hack_tag\");"); - this.addSql("create index \"core_user_hack_tag_index\" on \"core_user\" (\"hack_tag\");"); - this.addSql("create index \"core_user_role_id_index\" on \"core_user\" (\"role_id\");"); - this.addSql("create index \"core_user_created_at_index\" on \"core_user\" (\"created_at\");"); - this.addSql("create table \"discord_verification\" (\"code\" varchar(255) not null, \"discord_user_id\" varchar(255) not null, \"guild_id\" varchar(255) not null, \"username\" varchar(255) not null, \"avatar_hash\" varchar(255) null, \"auth_id\" varchar(255) null, \"status\" text not null default 'pending', \"expires_at\" timestamptz not null, \"created_at\" timestamptz not null, \"accepted_at\" timestamptz null, primary key (\"code\"));"); - this.addSql("create index \"discord_verification_discord_user_id_index\" on \"discord_verification\" (\"discord_user_id\");"); - this.addSql("create index \"discord_verification_guild_id_index\" on \"discord_verification\" (\"guild_id\");"); - this.addSql("create index \"discord_verification_auth_id_index\" on \"discord_verification\" (\"auth_id\");"); - this.addSql("create index \"discord_verification_status_index\" on \"discord_verification\" (\"status\");"); - this.addSql("create index \"discord_verification_created_at_index\" on \"discord_verification\" (\"created_at\");"); - this.addSql("alter table \"discord_verification\" add constraint \"discord_verification_status_check\" check (\"status\" in ('pending', 'accepted', 'rejected', 'expired'));"); - this.addSql("create table \"discord_role_sync_attempt\" (\"id\" varchar(255) not null, \"auth_id\" varchar(255) not null, \"discord_user_id\" varchar(255) not null, \"guild_id\" varchar(255) not null, \"status\" text not null, \"role_ids\" jsonb not null default '[]', \"role_names\" jsonb not null default '[]', \"error\" text null, \"created_at\" timestamptz not null, primary key (\"id\"));"); - this.addSql("create index \"discord_role_sync_attempt_auth_id_index\" on \"discord_role_sync_attempt\" (\"auth_id\");"); - this.addSql("create index \"discord_role_sync_attempt_discord_user_id_index\" on \"discord_role_sync_attempt\" (\"discord_user_id\");"); - this.addSql("create index \"discord_role_sync_attempt_status_index\" on \"discord_role_sync_attempt\" (\"status\");"); - this.addSql("create index \"discord_role_sync_attempt_created_at_index\" on \"discord_role_sync_attempt\" (\"created_at\");"); - this.addSql("alter table \"discord_role_sync_attempt\" add constraint \"discord_role_sync_attempt_status_check\" check (\"status\" in ('synced', 'failed', 'skipped'));"); - this.addSql("create table \"discord_member\" (\"auth_id\" varchar(255) not null, \"discord_user_id\" varchar(255) not null, \"guild_id\" varchar(255) not null, \"username\" varchar(255) not null, \"avatar_hash\" varchar(255) null, \"verified_at\" timestamptz not null, \"updated_at\" timestamptz not null, \"last_role_sync_at\" timestamptz null, primary key (\"auth_id\"));"); - this.addSql("alter table \"discord_member\" add constraint \"discord_member_discord_user_id_unique\" unique (\"discord_user_id\");"); - this.addSql("create index \"discord_member_discord_user_id_index\" on \"discord_member\" (\"discord_user_id\");"); - this.addSql("create index \"discord_member_guild_id_index\" on \"discord_member\" (\"guild_id\");"); - this.addSql("create index \"discord_member_updated_at_index\" on \"discord_member\" (\"updated_at\");"); - this.addSql("create table \"core_user_data\" (\"auth_id\" varchar(255) not null, \"age\" int not null, \"gender\" varchar(255) not null, \"race\" varchar(255) not null, \"ethnicity\" varchar(255) not null, \"shirt_size\" varchar(255) not null, \"dietary_restrictions\" jsonb not null default '[]', \"accommodation_note\" text null, \"phone_number\" varchar(255) null, \"country_of_residence\" varchar(255) null, \"has_accepted_mlhcode_of_conduct\" boolean not null, \"has_shared_data_with_mlh\" boolean not null, \"is_emailable\" boolean not null, \"completed_at\" timestamptz not null, \"updated_at\" timestamptz not null, primary key (\"auth_id\"));"); - this.addSql("create table \"core_user_ban\" (\"auth_id\" varchar(255) not null, \"reason\" varchar(255) null, \"banned_by_auth_id\" varchar(255) not null, \"created_at\" timestamptz not null, primary key (\"auth_id\"));"); - this.addSql("create table \"core_setting\" (\"key\" varchar(255) not null, \"value\" jsonb not null, \"created_at\" timestamptz not null, \"created_by_auth_id\" varchar(255) null, \"updated_at\" timestamptz not null, \"updated_by_auth_id\" varchar(255) null, primary key (\"key\"));"); - this.addSql("create index \"core_setting_updated_at_index\" on \"core_setting\" (\"updated_at\");"); - this.addSql("create index \"core_setting_updated_by_auth_id_index\" on \"core_setting\" (\"updated_by_auth_id\");"); - this.addSql("create table \"core_rsvp\" (\"auth_id\" varchar(255) not null, \"status\" text not null, \"waitlist_position\" int null, \"created_at\" timestamptz not null, \"updated_at\" timestamptz not null, \"confirmed_at\" timestamptz null, \"waitlisted_at\" timestamptz null, \"cancelled_at\" timestamptz null, \"cancelled_by_auth_id\" varchar(255) null, \"promoted_at\" timestamptz null, \"promoted_by_auth_id\" varchar(255) null, primary key (\"auth_id\"));"); - this.addSql("create index \"core_rsvp_status_index\" on \"core_rsvp\" (\"status\");"); - this.addSql("create index \"core_rsvp_waitlist_position_index\" on \"core_rsvp\" (\"waitlist_position\");"); - this.addSql("create index \"core_rsvp_created_at_index\" on \"core_rsvp\" (\"created_at\");"); - this.addSql("create index \"core_rsvp_updated_at_index\" on \"core_rsvp\" (\"updated_at\");"); - this.addSql("alter table \"core_rsvp\" add constraint \"core_rsvp_status_check\" check (\"status\" in ('confirmed', 'waitlisted', 'cancelled'));"); - this.addSql("create table \"core_notification_intent\" (\"id\" varchar(255) not null, \"kind\" varchar(255) not null, \"recipient_auth_id\" varchar(255) null, \"payload\" jsonb not null, \"status\" text not null default 'pending', \"idempotency_key\" varchar(255) null, \"created_at\" timestamptz not null, \"updated_at\" timestamptz not null, primary key (\"id\"));"); - this.addSql("alter table \"core_notification_intent\" add constraint \"core_notification_intent_idempotency_key_unique\" unique (\"idempotency_key\");"); - this.addSql("create index \"core_notification_intent_kind_index\" on \"core_notification_intent\" (\"kind\");"); - this.addSql("create index \"core_notification_intent_recipient_auth_id_index\" on \"core_notification_intent\" (\"recipient_auth_id\");"); - this.addSql("create index \"core_notification_intent_status_index\" on \"core_notification_intent\" (\"status\");"); - this.addSql("create index \"core_notification_intent_created_at_index\" on \"core_notification_intent\" (\"created_at\");"); - this.addSql("alter table \"core_notification_intent\" add constraint \"core_notification_intent_status_check\" check (\"status\" in ('pending', 'processing', 'delivered', 'failed', 'skipped'));"); - this.addSql("create table \"core_notification_delivery_attempt\" (\"id\" varchar(255) not null, \"intent_id\" varchar(255) not null, \"channel\" varchar(255) not null, \"provider\" varchar(255) null, \"status\" text not null, \"recipient\" varchar(255) null, \"external_id\" varchar(255) null, \"error\" text null, \"metadata\" jsonb not null, \"attempted_at\" timestamptz not null, primary key (\"id\"));"); - this.addSql("create index \"core_notification_delivery_attempt_intent_id_index\" on \"core_notification_delivery_attempt\" (\"intent_id\");"); - this.addSql("create index \"core_notification_delivery_attempt_channel_index\" on \"core_notification_delivery_attempt\" (\"channel\");"); - this.addSql("create index \"core_notification_delivery_attempt_status_index\" on \"core_notification_delivery_attempt\" (\"status\");"); - this.addSql("create index \"core_notification_delivery_attempt_attempted_at_index\" on \"core_notification_delivery_attempt\" (\"attempted_at\");"); - this.addSql("alter table \"core_notification_delivery_attempt\" add constraint \"core_notification_delivery_attempt_status_check\" check (\"status\" in ('delivered', 'failed', 'skipped'));"); - this.addSql("create table \"core_hacker\" (\"auth_id\" varchar(255) not null, \"university\" varchar(255) not null, \"major\" varchar(255) not null, \"school_id\" varchar(255) null, \"level_of_study\" varchar(255) not null, \"hackathons_attended\" int not null, \"software_experience\" varchar(255) not null, \"heard_from\" varchar(255) null, \"github_url\" text null, \"linked_in_url\" text null, \"personal_website_url\" text null, \"resume_url\" text null, \"group\" varchar(255) null, \"registered_at\" timestamptz not null, \"updated_at\" timestamptz not null, primary key (\"auth_id\"));"); - this.addSql("create index \"core_hacker_registered_at_index\" on \"core_hacker\" (\"registered_at\");"); - this.addSql("create table \"core_event_scan\" (\"id\" varchar(255) not null, \"event_id\" varchar(255) not null, \"auth_id\" varchar(255) not null, \"scanned_by_auth_id\" varchar(255) not null, \"scanned_at\" timestamptz not null, primary key (\"id\"));"); - this.addSql("create index \"core_event_scan_event_id_index\" on \"core_event_scan\" (\"event_id\");"); - this.addSql("create index \"core_event_scan_auth_id_index\" on \"core_event_scan\" (\"auth_id\");"); - this.addSql("create index \"core_event_scan_event_id_auth_id_index\" on \"core_event_scan\" (\"event_id\", \"auth_id\");"); - this.addSql("create index \"core_event_scan_scanned_at_index\" on \"core_event_scan\" (\"scanned_at\");"); - this.addSql("create table \"session\" (\"id\" varchar(255) not null, \"expires_at\" timestamptz not null, \"token\" varchar(255) not null, \"created_at\" timestamptz not null, \"updated_at\" timestamptz not null, \"ip_address\" varchar(255) null, \"user_agent\" text null, \"user_id\" varchar(255) not null, primary key (\"id\"));"); - this.addSql("alter table \"session\" add constraint \"session_token_unique\" unique (\"token\");"); - this.addSql("create index \"session_user_id_index\" on \"session\" (\"user_id\");"); - this.addSql("create table \"account\" (\"id\" varchar(255) not null, \"account_id\" varchar(255) not null, \"provider_id\" varchar(255) not null, \"user_id\" varchar(255) not null, \"access_token\" text null, \"refresh_token\" text null, \"id_token\" text null, \"access_token_expires_at\" timestamptz null, \"refresh_token_expires_at\" timestamptz null, \"scope\" text null, \"password\" varchar(255) null, \"created_at\" timestamptz not null, \"updated_at\" timestamptz not null, primary key (\"id\"));"); - this.addSql("create index \"account_user_id_index\" on \"account\" (\"user_id\");"); - this.addSql("create table \"teams_team\" (\"id\" varchar(255) not null, \"name\" varchar(255) not null, \"tag\" varchar(255) not null, \"owner_auth_id\" varchar(255) not null, \"created_at\" timestamptz not null, primary key (\"id\"));"); - this.addSql("alter table \"teams_team\" add constraint \"teams_team_tag_unique\" unique (\"tag\");"); - this.addSql("create index \"teams_team_tag_index\" on \"teams_team\" (\"tag\");"); - this.addSql("create index \"teams_team_owner_auth_id_index\" on \"teams_team\" (\"owner_auth_id\");"); - this.addSql("create table \"teams_member\" (\"id\" varchar(255) not null, \"team_id\" varchar(255) not null, \"auth_id\" varchar(255) not null, \"joined_at\" timestamptz not null, primary key (\"id\"));"); - this.addSql("alter table \"teams_member\" add constraint \"teams_member_auth_id_unique\" unique (\"auth_id\");"); - this.addSql("create index \"teams_member_team_id_index\" on \"teams_member\" (\"team_id\");"); - this.addSql("create index \"teams_member_auth_id_index\" on \"teams_member\" (\"auth_id\");"); - this.addSql("create table \"teams_invite\" (\"id\" varchar(255) not null, \"team_id\" varchar(255) not null, \"invitee_auth_id\" varchar(255) not null, \"status\" text not null default 'pending', \"created_at\" timestamptz not null, primary key (\"id\"));"); - this.addSql("create index \"teams_invite_team_id_index\" on \"teams_invite\" (\"team_id\");"); - this.addSql("create index \"teams_invite_invitee_auth_id_index\" on \"teams_invite\" (\"invitee_auth_id\");"); - this.addSql("create index \"teams_invite_team_id_invitee_auth_id_index\" on \"teams_invite\" (\"team_id\", \"invitee_auth_id\");"); - this.addSql("alter table \"teams_invite\" add constraint \"teams_invite_status_check\" check (\"status\" in ('pending', 'accepted', 'declined'));"); - this.addSql("alter table \"core_user\" add constraint \"core_user_role_id_foreign\" foreign key (\"role_id\") references \"core_role\" (\"id\") on delete set null;"); - this.addSql("alter table \"discord_verification\" add constraint \"discord_verification_auth_id_foreign\" foreign key (\"auth_id\") references \"core_user\" (\"id\") on delete set null;"); - this.addSql("alter table \"discord_role_sync_attempt\" add constraint \"discord_role_sync_attempt_auth_id_foreign\" foreign key (\"auth_id\") references \"core_user\" (\"id\") on delete cascade;"); - this.addSql("alter table \"discord_member\" add constraint \"discord_member_auth_id_foreign\" foreign key (\"auth_id\") references \"core_user\" (\"id\") on update cascade on delete cascade;"); - this.addSql("alter table \"core_user_data\" add constraint \"core_user_data_auth_id_foreign\" foreign key (\"auth_id\") references \"core_user\" (\"id\") on update cascade on delete cascade;"); - this.addSql("alter table \"core_user_ban\" add constraint \"core_user_ban_auth_id_foreign\" foreign key (\"auth_id\") references \"core_user\" (\"id\") on update cascade on delete cascade;"); - this.addSql("alter table \"core_user_ban\" add constraint \"core_user_ban_banned_by_auth_id_foreign\" foreign key (\"banned_by_auth_id\") references \"core_user\" (\"id\");"); - this.addSql("alter table \"core_setting\" add constraint \"core_setting_created_by_auth_id_foreign\" foreign key (\"created_by_auth_id\") references \"core_user\" (\"id\") on delete set null;"); - this.addSql("alter table \"core_setting\" add constraint \"core_setting_updated_by_auth_id_foreign\" foreign key (\"updated_by_auth_id\") references \"core_user\" (\"id\") on delete set null;"); - this.addSql("alter table \"core_rsvp\" add constraint \"core_rsvp_auth_id_foreign\" foreign key (\"auth_id\") references \"core_user\" (\"id\") on update cascade on delete cascade;"); - this.addSql("alter table \"core_rsvp\" add constraint \"core_rsvp_cancelled_by_auth_id_foreign\" foreign key (\"cancelled_by_auth_id\") references \"core_user\" (\"id\") on delete set null;"); - this.addSql("alter table \"core_rsvp\" add constraint \"core_rsvp_promoted_by_auth_id_foreign\" foreign key (\"promoted_by_auth_id\") references \"core_user\" (\"id\") on delete set null;"); - this.addSql("alter table \"core_notification_intent\" add constraint \"core_notification_intent_recipient_auth_id_foreign\" foreign key (\"recipient_auth_id\") references \"core_user\" (\"id\") on delete set null;"); - this.addSql("alter table \"core_notification_delivery_attempt\" add constraint \"core_notification_delivery_attempt_intent_id_foreign\" foreign key (\"intent_id\") references \"core_notification_intent\" (\"id\") on delete cascade;"); - this.addSql("alter table \"core_hacker\" add constraint \"core_hacker_auth_id_foreign\" foreign key (\"auth_id\") references \"core_user\" (\"id\") on update cascade on delete cascade;"); - this.addSql("alter table \"core_event_scan\" add constraint \"core_event_scan_event_id_foreign\" foreign key (\"event_id\") references \"core_event\" (\"id\") on delete cascade;"); - this.addSql("alter table \"core_event_scan\" add constraint \"core_event_scan_auth_id_foreign\" foreign key (\"auth_id\") references \"core_user\" (\"id\") on delete cascade;"); - this.addSql("alter table \"core_event_scan\" add constraint \"core_event_scan_scanned_by_auth_id_foreign\" foreign key (\"scanned_by_auth_id\") references \"core_user\" (\"id\");"); - this.addSql("alter table \"session\" add constraint \"session_user_id_foreign\" foreign key (\"user_id\") references \"core_user\" (\"id\") on delete cascade;"); - this.addSql("alter table \"account\" add constraint \"account_user_id_foreign\" foreign key (\"user_id\") references \"core_user\" (\"id\") on delete cascade;"); - this.addSql("alter table \"teams_team\" add constraint \"teams_team_owner_auth_id_foreign\" foreign key (\"owner_auth_id\") references \"core_user\" (\"id\") on delete cascade;"); - this.addSql("alter table \"teams_member\" add constraint \"teams_member_team_id_foreign\" foreign key (\"team_id\") references \"teams_team\" (\"id\") on delete cascade;"); - this.addSql("alter table \"teams_member\" add constraint \"teams_member_auth_id_foreign\" foreign key (\"auth_id\") references \"core_user\" (\"id\") on delete cascade;"); - this.addSql("alter table \"teams_invite\" add constraint \"teams_invite_team_id_foreign\" foreign key (\"team_id\") references \"teams_team\" (\"id\") on delete cascade;"); - this.addSql("alter table \"teams_invite\" add constraint \"teams_invite_invitee_auth_id_foreign\" foreign key (\"invitee_auth_id\") references \"core_user\" (\"id\") on delete cascade;"); - } - - override down(): void | Promise { - this.addSql(`alter table "session" drop constraint "session_user_id_foreign";`); - this.addSql(`alter table "account" drop constraint "account_user_id_foreign";`); - this.addSql(`alter table "core_event_scan" drop constraint "core_event_scan_event_id_foreign";`); - this.addSql(`alter table "core_user" drop constraint "core_user_role_id_foreign";`); - this.addSql(`alter table "discord_verification" drop constraint "discord_verification_auth_id_foreign";`); - this.addSql(`alter table "discord_role_sync_attempt" drop constraint "discord_role_sync_attempt_auth_id_foreign";`); - this.addSql(`alter table "discord_member" drop constraint "discord_member_auth_id_foreign";`); - this.addSql(`alter table "core_user_data" drop constraint "core_user_data_auth_id_foreign";`); - this.addSql(`alter table "core_user_ban" drop constraint "core_user_ban_auth_id_foreign";`); - this.addSql(`alter table "core_user_ban" drop constraint "core_user_ban_banned_by_auth_id_foreign";`); - this.addSql(`alter table "core_setting" drop constraint "core_setting_created_by_auth_id_foreign";`); - this.addSql(`alter table "core_setting" drop constraint "core_setting_updated_by_auth_id_foreign";`); - this.addSql(`alter table "core_rsvp" drop constraint "core_rsvp_auth_id_foreign";`); - this.addSql(`alter table "core_rsvp" drop constraint "core_rsvp_cancelled_by_auth_id_foreign";`); - this.addSql(`alter table "core_rsvp" drop constraint "core_rsvp_promoted_by_auth_id_foreign";`); - this.addSql(`alter table "core_notification_intent" drop constraint "core_notification_intent_recipient_auth_id_foreign";`); - this.addSql(`alter table "core_hacker" drop constraint "core_hacker_auth_id_foreign";`); - this.addSql(`alter table "core_event_scan" drop constraint "core_event_scan_auth_id_foreign";`); - this.addSql(`alter table "core_event_scan" drop constraint "core_event_scan_scanned_by_auth_id_foreign";`); - this.addSql(`alter table "teams_team" drop constraint "teams_team_owner_auth_id_foreign";`); - this.addSql(`alter table "teams_member" drop constraint "teams_member_auth_id_foreign";`); - this.addSql(`alter table "teams_invite" drop constraint "teams_invite_invitee_auth_id_foreign";`); - this.addSql(`alter table "core_notification_delivery_attempt" drop constraint "core_notification_delivery_attempt_intent_id_foreign";`); - this.addSql(`alter table "teams_member" drop constraint "teams_member_team_id_foreign";`); - this.addSql(`alter table "teams_invite" drop constraint "teams_invite_team_id_foreign";`); - - this.addSql(`drop table if exists "session" cascade;`); - this.addSql(`drop table if exists "account" cascade;`); - this.addSql(`drop table if exists "verification" cascade;`); - this.addSql(`drop table if exists "core_event" cascade;`); - this.addSql(`drop table if exists "core_operation_lock" cascade;`); - this.addSql(`drop table if exists "core_role" cascade;`); - this.addSql(`drop table if exists "core_user" cascade;`); - this.addSql(`drop table if exists "discord_verification" cascade;`); - this.addSql(`drop table if exists "discord_role_sync_attempt" cascade;`); - this.addSql(`drop table if exists "discord_member" cascade;`); - this.addSql(`drop table if exists "core_user_data" cascade;`); - this.addSql(`drop table if exists "core_user_ban" cascade;`); - this.addSql(`drop table if exists "core_setting" cascade;`); - this.addSql(`drop table if exists "core_rsvp" cascade;`); - this.addSql(`drop table if exists "core_notification_intent" cascade;`); - this.addSql(`drop table if exists "core_notification_delivery_attempt" cascade;`); - this.addSql(`drop table if exists "core_hacker" cascade;`); - this.addSql(`drop table if exists "core_event_scan" cascade;`); - this.addSql(`drop table if exists "teams_team" cascade;`); - this.addSql(`drop table if exists "teams_member" cascade;`); - this.addSql(`drop table if exists "teams_invite" cascade;`); - } - -} diff --git a/templates/nextjs-full/db/migrations/sqlite/.snapshot.json b/templates/nextjs-full/db/migrations/sqlite/.snapshot.json deleted file mode 100644 index 94c45c417..000000000 --- a/templates/nextjs-full/db/migrations/sqlite/.snapshot.json +++ /dev/null @@ -1,4525 +0,0 @@ -{ - "namespaces": [], - "tables": [ - { - "name": "account", - "columns": { - "access_token": { - "name": "access_token", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "access_token_expires_at": { - "name": "access_token_expires_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "account_id": { - "name": "account_id", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "created_at": { - "name": "created_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "id": { - "name": "id", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": true, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "id_token": { - "name": "id_token", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "password": { - "name": "password", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "provider_id": { - "name": "provider_id", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "refresh_token": { - "name": "refresh_token", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "refresh_token_expires_at": { - "name": "refresh_token_expires_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "scope": { - "name": "scope", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "updated_at": { - "name": "updated_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "user_id": { - "name": "user_id", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - } - }, - "indexes": [ - { - "columnNames": [ - "user_id" - ], - "composite": false, - "constraint": false, - "keyName": "account_user_id_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "id" - ], - "composite": false, - "constraint": true, - "keyName": "primary", - "primary": true, - "unique": true - } - ], - "checks": [], - "triggers": [], - "foreignKeys": { - "account_user_id_foreign": { - "columnNames": [ - "user_id" - ], - "constraintName": "account_user_id_foreign", - "localTableName": "account", - "referencedColumnNames": [ - "id" - ], - "referencedTableName": "core_user", - "deleteRule": "cascade" - } - }, - "comment": null - }, - { - "name": "core_event", - "columns": { - "created_at": { - "name": "created_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "description": { - "name": "description", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "end_time": { - "name": "end_time", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "hidden": { - "name": "hidden", - "type": "integer", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": "false", - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "integer" - }, - "host": { - "name": "host", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "id": { - "name": "id", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": true, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "location": { - "name": "location", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": "'TBD'", - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "start_time": { - "name": "start_time", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "title": { - "name": "title", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "type": { - "name": "type", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "updated_at": { - "name": "updated_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - } - }, - "indexes": [ - { - "columnNames": [ - "hidden" - ], - "composite": false, - "constraint": false, - "keyName": "core_event_hidden_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "start_time" - ], - "composite": false, - "constraint": false, - "keyName": "core_event_start_time_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "type" - ], - "composite": false, - "constraint": false, - "keyName": "core_event_type_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "id" - ], - "composite": false, - "constraint": true, - "keyName": "primary", - "primary": true, - "unique": true - } - ], - "checks": [], - "triggers": [], - "foreignKeys": {}, - "comment": null - }, - { - "name": "core_event_scan", - "columns": { - "auth_id": { - "name": "auth_id", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "event_id": { - "name": "event_id", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "id": { - "name": "id", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": true, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "scanned_at": { - "name": "scanned_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "scanned_by_auth_id": { - "name": "scanned_by_auth_id", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - } - }, - "indexes": [ - { - "columnNames": [ - "auth_id" - ], - "composite": false, - "constraint": false, - "keyName": "core_event_scan_auth_id_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "event_id", - "auth_id" - ], - "composite": true, - "constraint": false, - "keyName": "core_event_scan_event_id_auth_id_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "event_id" - ], - "composite": false, - "constraint": false, - "keyName": "core_event_scan_event_id_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "scanned_at" - ], - "composite": false, - "constraint": false, - "keyName": "core_event_scan_scanned_at_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "scanned_by_auth_id" - ], - "composite": false, - "constraint": false, - "keyName": "core_event_scan_scanned_by_auth_id_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "id" - ], - "composite": false, - "constraint": true, - "keyName": "primary", - "primary": true, - "unique": true - } - ], - "checks": [], - "triggers": [], - "foreignKeys": { - "core_event_scan_auth_id_foreign": { - "columnNames": [ - "auth_id" - ], - "constraintName": "core_event_scan_auth_id_foreign", - "localTableName": "core_event_scan", - "referencedColumnNames": [ - "id" - ], - "referencedTableName": "core_user", - "deleteRule": "cascade" - }, - "core_event_scan_event_id_foreign": { - "columnNames": [ - "event_id" - ], - "constraintName": "core_event_scan_event_id_foreign", - "localTableName": "core_event_scan", - "referencedColumnNames": [ - "id" - ], - "referencedTableName": "core_event", - "deleteRule": "cascade" - }, - "core_event_scan_scanned_by_auth_id_foreign": { - "columnNames": [ - "scanned_by_auth_id" - ], - "constraintName": "core_event_scan_scanned_by_auth_id_foreign", - "localTableName": "core_event_scan", - "referencedColumnNames": [ - "id" - ], - "referencedTableName": "core_user" - } - }, - "comment": null - }, - { - "name": "core_hacker", - "columns": { - "auth_id": { - "name": "auth_id", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": true, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "github_url": { - "name": "github_url", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "group": { - "name": "group", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "hackathons_attended": { - "name": "hackathons_attended", - "type": "integer", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "integer" - }, - "heard_from": { - "name": "heard_from", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "level_of_study": { - "name": "level_of_study", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "linked_in_url": { - "name": "linked_in_url", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "major": { - "name": "major", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "personal_website_url": { - "name": "personal_website_url", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "registered_at": { - "name": "registered_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "resume_url": { - "name": "resume_url", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "school_id": { - "name": "school_id", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "software_experience": { - "name": "software_experience", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "university": { - "name": "university", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "updated_at": { - "name": "updated_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - } - }, - "indexes": [ - { - "columnNames": [ - "auth_id" - ], - "composite": false, - "constraint": false, - "keyName": "core_hacker_auth_id_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "registered_at" - ], - "composite": false, - "constraint": false, - "keyName": "core_hacker_registered_at_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "auth_id" - ], - "composite": false, - "constraint": true, - "keyName": "primary", - "primary": true, - "unique": true - } - ], - "checks": [], - "triggers": [], - "foreignKeys": { - "core_hacker_auth_id_foreign": { - "columnNames": [ - "auth_id" - ], - "constraintName": "core_hacker_auth_id_foreign", - "localTableName": "core_hacker", - "referencedColumnNames": [ - "id" - ], - "referencedTableName": "core_user", - "updateRule": "cascade", - "deleteRule": "cascade" - } - }, - "comment": null - }, - { - "name": "core_notification_delivery_attempt", - "columns": { - "attempted_at": { - "name": "attempted_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "channel": { - "name": "channel", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "error": { - "name": "error", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "external_id": { - "name": "external_id", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "id": { - "name": "id", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": true, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "intent_id": { - "name": "intent_id", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "metadata": { - "name": "metadata", - "type": "json", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "json" - }, - "provider": { - "name": "provider", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "recipient": { - "name": "recipient", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "status": { - "name": "status", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [ - "delivered", - "failed", - "skipped" - ], - "mappedType": "enum" - } - }, - "indexes": [ - { - "columnNames": [ - "attempted_at" - ], - "composite": false, - "constraint": false, - "keyName": "core_notification_delivery_attempt_attempted_at_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "channel" - ], - "composite": false, - "constraint": false, - "keyName": "core_notification_delivery_attempt_channel_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "intent_id" - ], - "composite": false, - "constraint": false, - "keyName": "core_notification_delivery_attempt_intent_id_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "status" - ], - "composite": false, - "constraint": false, - "keyName": "core_notification_delivery_attempt_status_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "id" - ], - "composite": false, - "constraint": true, - "keyName": "primary", - "primary": true, - "unique": true - } - ], - "checks": [ - { - "name": "core_notification_delivery_attempt_status_check", - "expression": "`status` in ('delivered', 'failed', 'skipped')", - "definition": "check (`status` in ('delivered', 'failed', 'skipped'))", - "columnName": "status" - } - ], - "triggers": [], - "foreignKeys": { - "core_notification_delivery_attempt_intent_id_foreign": { - "columnNames": [ - "intent_id" - ], - "constraintName": "core_notification_delivery_attempt_intent_id_foreign", - "localTableName": "core_notification_delivery_attempt", - "referencedColumnNames": [ - "id" - ], - "referencedTableName": "core_notification_intent", - "deleteRule": "cascade" - } - }, - "comment": null - }, - { - "name": "core_notification_intent", - "columns": { - "created_at": { - "name": "created_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "id": { - "name": "id", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": true, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "idempotency_key": { - "name": "idempotency_key", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": true, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "kind": { - "name": "kind", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "payload": { - "name": "payload", - "type": "json", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "json" - }, - "recipient_auth_id": { - "name": "recipient_auth_id", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "status": { - "name": "status", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": "'pending'", - "comment": null, - "collation": null, - "enumItems": [ - "pending", - "processing", - "delivered", - "failed", - "skipped" - ], - "mappedType": "enum" - }, - "updated_at": { - "name": "updated_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - } - }, - "indexes": [ - { - "columnNames": [ - "created_at" - ], - "composite": false, - "constraint": false, - "keyName": "core_notification_intent_created_at_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "idempotency_key" - ], - "composite": false, - "constraint": true, - "keyName": "core_notification_intent_idempotency_key_unique", - "primary": false, - "unique": true - }, - { - "columnNames": [ - "kind" - ], - "composite": false, - "constraint": false, - "keyName": "core_notification_intent_kind_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "recipient_auth_id" - ], - "composite": false, - "constraint": false, - "keyName": "core_notification_intent_recipient_auth_id_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "status" - ], - "composite": false, - "constraint": false, - "keyName": "core_notification_intent_status_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "id" - ], - "composite": false, - "constraint": true, - "keyName": "primary", - "primary": true, - "unique": true - } - ], - "checks": [ - { - "name": "core_notification_intent_status_check", - "expression": "`status` in ('pending', 'processing', 'delivered', 'failed', 'skipped')", - "definition": "check (`status` in ('pending', 'processing', 'delivered', 'failed', 'skipped'))", - "columnName": "status" - } - ], - "triggers": [], - "foreignKeys": { - "core_notification_intent_recipient_auth_id_foreign": { - "columnNames": [ - "recipient_auth_id" - ], - "constraintName": "core_notification_intent_recipient_auth_id_foreign", - "localTableName": "core_notification_intent", - "referencedColumnNames": [ - "id" - ], - "referencedTableName": "core_user", - "deleteRule": "set null" - } - }, - "comment": null - }, - { - "name": "core_operation_lock", - "columns": { - "key": { - "name": "key", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": true, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "token": { - "name": "token", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - } - }, - "indexes": [ - { - "columnNames": [ - "key" - ], - "composite": false, - "constraint": true, - "keyName": "primary", - "primary": true, - "unique": true - } - ], - "checks": [], - "triggers": [], - "foreignKeys": {}, - "comment": null - }, - { - "name": "core_role", - "columns": { - "color": { - "name": "color", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "created_at": { - "name": "created_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "id": { - "name": "id", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": true, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "name": { - "name": "name", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": true, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "permissions": { - "name": "permissions", - "type": "json", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": "'[]'", - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "json" - }, - "position": { - "name": "position", - "type": "integer", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "integer" - }, - "updated_at": { - "name": "updated_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - } - }, - "indexes": [ - { - "columnNames": [ - "name" - ], - "composite": false, - "constraint": true, - "keyName": "core_role_name_unique", - "primary": false, - "unique": true - }, - { - "columnNames": [ - "position" - ], - "composite": false, - "constraint": false, - "keyName": "core_role_position_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "id" - ], - "composite": false, - "constraint": true, - "keyName": "primary", - "primary": true, - "unique": true - } - ], - "checks": [], - "triggers": [], - "foreignKeys": {}, - "comment": null - }, - { - "name": "core_rsvp", - "columns": { - "auth_id": { - "name": "auth_id", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": true, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "cancelled_at": { - "name": "cancelled_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "cancelled_by_auth_id": { - "name": "cancelled_by_auth_id", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "confirmed_at": { - "name": "confirmed_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "created_at": { - "name": "created_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "promoted_at": { - "name": "promoted_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "promoted_by_auth_id": { - "name": "promoted_by_auth_id", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "status": { - "name": "status", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [ - "confirmed", - "waitlisted", - "cancelled" - ], - "mappedType": "enum" - }, - "updated_at": { - "name": "updated_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "waitlist_position": { - "name": "waitlist_position", - "type": "integer", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "integer" - }, - "waitlisted_at": { - "name": "waitlisted_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - } - }, - "indexes": [ - { - "columnNames": [ - "auth_id" - ], - "composite": false, - "constraint": false, - "keyName": "core_rsvp_auth_id_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "cancelled_by_auth_id" - ], - "composite": false, - "constraint": false, - "keyName": "core_rsvp_cancelled_by_auth_id_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "created_at" - ], - "composite": false, - "constraint": false, - "keyName": "core_rsvp_created_at_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "promoted_by_auth_id" - ], - "composite": false, - "constraint": false, - "keyName": "core_rsvp_promoted_by_auth_id_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "status" - ], - "composite": false, - "constraint": false, - "keyName": "core_rsvp_status_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "updated_at" - ], - "composite": false, - "constraint": false, - "keyName": "core_rsvp_updated_at_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "waitlist_position" - ], - "composite": false, - "constraint": false, - "keyName": "core_rsvp_waitlist_position_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "auth_id" - ], - "composite": false, - "constraint": true, - "keyName": "primary", - "primary": true, - "unique": true - } - ], - "checks": [ - { - "name": "core_rsvp_status_check", - "expression": "`status` in ('confirmed', 'waitlisted', 'cancelled')", - "definition": "check (`status` in ('confirmed', 'waitlisted', 'cancelled'))", - "columnName": "status" - } - ], - "triggers": [], - "foreignKeys": { - "core_rsvp_auth_id_foreign": { - "columnNames": [ - "auth_id" - ], - "constraintName": "core_rsvp_auth_id_foreign", - "localTableName": "core_rsvp", - "referencedColumnNames": [ - "id" - ], - "referencedTableName": "core_user", - "updateRule": "cascade", - "deleteRule": "cascade" - }, - "core_rsvp_cancelled_by_auth_id_foreign": { - "columnNames": [ - "cancelled_by_auth_id" - ], - "constraintName": "core_rsvp_cancelled_by_auth_id_foreign", - "localTableName": "core_rsvp", - "referencedColumnNames": [ - "id" - ], - "referencedTableName": "core_user", - "deleteRule": "set null" - }, - "core_rsvp_promoted_by_auth_id_foreign": { - "columnNames": [ - "promoted_by_auth_id" - ], - "constraintName": "core_rsvp_promoted_by_auth_id_foreign", - "localTableName": "core_rsvp", - "referencedColumnNames": [ - "id" - ], - "referencedTableName": "core_user", - "deleteRule": "set null" - } - }, - "comment": null - }, - { - "name": "core_setting", - "columns": { - "created_at": { - "name": "created_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "created_by_auth_id": { - "name": "created_by_auth_id", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "key": { - "name": "key", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": true, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "updated_at": { - "name": "updated_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "updated_by_auth_id": { - "name": "updated_by_auth_id", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "value": { - "name": "value", - "type": "json", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "json" - } - }, - "indexes": [ - { - "columnNames": [ - "created_by_auth_id" - ], - "composite": false, - "constraint": false, - "keyName": "core_setting_created_by_auth_id_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "updated_at" - ], - "composite": false, - "constraint": false, - "keyName": "core_setting_updated_at_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "updated_by_auth_id" - ], - "composite": false, - "constraint": false, - "keyName": "core_setting_updated_by_auth_id_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "key" - ], - "composite": false, - "constraint": true, - "keyName": "primary", - "primary": true, - "unique": true - } - ], - "checks": [], - "triggers": [], - "foreignKeys": { - "core_setting_created_by_auth_id_foreign": { - "columnNames": [ - "created_by_auth_id" - ], - "constraintName": "core_setting_created_by_auth_id_foreign", - "localTableName": "core_setting", - "referencedColumnNames": [ - "id" - ], - "referencedTableName": "core_user", - "deleteRule": "set null" - }, - "core_setting_updated_by_auth_id_foreign": { - "columnNames": [ - "updated_by_auth_id" - ], - "constraintName": "core_setting_updated_by_auth_id_foreign", - "localTableName": "core_setting", - "referencedColumnNames": [ - "id" - ], - "referencedTableName": "core_user", - "deleteRule": "set null" - } - }, - "comment": null - }, - { - "name": "core_user", - "columns": { - "bio": { - "name": "bio", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "checked_in_at": { - "name": "checked_in_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "created_at": { - "name": "created_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "discord_display_handle": { - "name": "discord_display_handle", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "email": { - "name": "email", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": true, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "email_verified": { - "name": "email_verified", - "type": "integer", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": "false", - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "integer" - }, - "hack_tag": { - "name": "hack_tag", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": true, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "id": { - "name": "id", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": true, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "is_approved": { - "name": "is_approved", - "type": "integer", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": "false", - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "integer" - }, - "is_profile_searchable": { - "name": "is_profile_searchable", - "type": "integer", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": "true", - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "integer" - }, - "name": { - "name": "name", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "profile_photo_url": { - "name": "profile_photo_url", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "pronouns": { - "name": "pronouns", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "role_id": { - "name": "role_id", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "skills": { - "name": "skills", - "type": "json", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": "'[]'", - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "json" - }, - "updated_at": { - "name": "updated_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - } - }, - "indexes": [ - { - "columnNames": [ - "created_at" - ], - "composite": false, - "constraint": false, - "keyName": "core_user_created_at_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "email" - ], - "composite": false, - "constraint": true, - "keyName": "core_user_email_unique", - "primary": false, - "unique": true - }, - { - "columnNames": [ - "hack_tag" - ], - "composite": false, - "constraint": false, - "keyName": "core_user_hack_tag_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "hack_tag" - ], - "composite": false, - "constraint": true, - "keyName": "core_user_hack_tag_unique", - "primary": false, - "unique": true - }, - { - "columnNames": [ - "role_id" - ], - "composite": false, - "constraint": false, - "keyName": "core_user_role_id_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "id" - ], - "composite": false, - "constraint": true, - "keyName": "primary", - "primary": true, - "unique": true - } - ], - "checks": [], - "triggers": [], - "foreignKeys": { - "core_user_role_id_foreign": { - "columnNames": [ - "role_id" - ], - "constraintName": "core_user_role_id_foreign", - "localTableName": "core_user", - "referencedColumnNames": [ - "id" - ], - "referencedTableName": "core_role", - "deleteRule": "set null" - } - }, - "comment": null - }, - { - "name": "core_user_ban", - "columns": { - "auth_id": { - "name": "auth_id", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": true, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "banned_by_auth_id": { - "name": "banned_by_auth_id", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "created_at": { - "name": "created_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "reason": { - "name": "reason", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - } - }, - "indexes": [ - { - "columnNames": [ - "auth_id" - ], - "composite": false, - "constraint": false, - "keyName": "core_user_ban_auth_id_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "banned_by_auth_id" - ], - "composite": false, - "constraint": false, - "keyName": "core_user_ban_banned_by_auth_id_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "auth_id" - ], - "composite": false, - "constraint": true, - "keyName": "primary", - "primary": true, - "unique": true - } - ], - "checks": [], - "triggers": [], - "foreignKeys": { - "core_user_ban_auth_id_foreign": { - "columnNames": [ - "auth_id" - ], - "constraintName": "core_user_ban_auth_id_foreign", - "localTableName": "core_user_ban", - "referencedColumnNames": [ - "id" - ], - "referencedTableName": "core_user", - "updateRule": "cascade", - "deleteRule": "cascade" - }, - "core_user_ban_banned_by_auth_id_foreign": { - "columnNames": [ - "banned_by_auth_id" - ], - "constraintName": "core_user_ban_banned_by_auth_id_foreign", - "localTableName": "core_user_ban", - "referencedColumnNames": [ - "id" - ], - "referencedTableName": "core_user" - } - }, - "comment": null - }, - { - "name": "core_user_data", - "columns": { - "accommodation_note": { - "name": "accommodation_note", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "age": { - "name": "age", - "type": "integer", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "integer" - }, - "auth_id": { - "name": "auth_id", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": true, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "completed_at": { - "name": "completed_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "country_of_residence": { - "name": "country_of_residence", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "dietary_restrictions": { - "name": "dietary_restrictions", - "type": "json", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": "'[]'", - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "json" - }, - "ethnicity": { - "name": "ethnicity", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "gender": { - "name": "gender", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "has_accepted_mlhcode_of_conduct": { - "name": "has_accepted_mlhcode_of_conduct", - "type": "integer", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "integer" - }, - "has_shared_data_with_mlh": { - "name": "has_shared_data_with_mlh", - "type": "integer", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "integer" - }, - "is_emailable": { - "name": "is_emailable", - "type": "integer", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "integer" - }, - "phone_number": { - "name": "phone_number", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "race": { - "name": "race", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "shirt_size": { - "name": "shirt_size", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "updated_at": { - "name": "updated_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - } - }, - "indexes": [ - { - "columnNames": [ - "auth_id" - ], - "composite": false, - "constraint": false, - "keyName": "core_user_data_auth_id_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "auth_id" - ], - "composite": false, - "constraint": true, - "keyName": "primary", - "primary": true, - "unique": true - } - ], - "checks": [], - "triggers": [], - "foreignKeys": { - "core_user_data_auth_id_foreign": { - "columnNames": [ - "auth_id" - ], - "constraintName": "core_user_data_auth_id_foreign", - "localTableName": "core_user_data", - "referencedColumnNames": [ - "id" - ], - "referencedTableName": "core_user", - "updateRule": "cascade", - "deleteRule": "cascade" - } - }, - "comment": null - }, - { - "name": "discord_member", - "columns": { - "auth_id": { - "name": "auth_id", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": true, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "avatar_hash": { - "name": "avatar_hash", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "discord_user_id": { - "name": "discord_user_id", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": true, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "guild_id": { - "name": "guild_id", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "last_role_sync_at": { - "name": "last_role_sync_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "updated_at": { - "name": "updated_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "username": { - "name": "username", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "verified_at": { - "name": "verified_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - } - }, - "indexes": [ - { - "columnNames": [ - "auth_id" - ], - "composite": false, - "constraint": false, - "keyName": "discord_member_auth_id_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "discord_user_id" - ], - "composite": false, - "constraint": false, - "keyName": "discord_member_discord_user_id_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "discord_user_id" - ], - "composite": false, - "constraint": true, - "keyName": "discord_member_discord_user_id_unique", - "primary": false, - "unique": true - }, - { - "columnNames": [ - "guild_id" - ], - "composite": false, - "constraint": false, - "keyName": "discord_member_guild_id_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "updated_at" - ], - "composite": false, - "constraint": false, - "keyName": "discord_member_updated_at_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "auth_id" - ], - "composite": false, - "constraint": true, - "keyName": "primary", - "primary": true, - "unique": true - } - ], - "checks": [], - "triggers": [], - "foreignKeys": { - "discord_member_auth_id_foreign": { - "columnNames": [ - "auth_id" - ], - "constraintName": "discord_member_auth_id_foreign", - "localTableName": "discord_member", - "referencedColumnNames": [ - "id" - ], - "referencedTableName": "core_user", - "updateRule": "cascade", - "deleteRule": "cascade" - } - }, - "comment": null - }, - { - "name": "discord_role_sync_attempt", - "columns": { - "auth_id": { - "name": "auth_id", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "created_at": { - "name": "created_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "discord_user_id": { - "name": "discord_user_id", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "error": { - "name": "error", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "guild_id": { - "name": "guild_id", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "id": { - "name": "id", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": true, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "role_ids": { - "name": "role_ids", - "type": "json", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": "'[]'", - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "json" - }, - "role_names": { - "name": "role_names", - "type": "json", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": "'[]'", - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "json" - }, - "status": { - "name": "status", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [ - "synced", - "failed", - "skipped" - ], - "mappedType": "enum" - } - }, - "indexes": [ - { - "columnNames": [ - "auth_id" - ], - "composite": false, - "constraint": false, - "keyName": "discord_role_sync_attempt_auth_id_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "created_at" - ], - "composite": false, - "constraint": false, - "keyName": "discord_role_sync_attempt_created_at_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "discord_user_id" - ], - "composite": false, - "constraint": false, - "keyName": "discord_role_sync_attempt_discord_user_id_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "status" - ], - "composite": false, - "constraint": false, - "keyName": "discord_role_sync_attempt_status_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "id" - ], - "composite": false, - "constraint": true, - "keyName": "primary", - "primary": true, - "unique": true - } - ], - "checks": [ - { - "name": "discord_role_sync_attempt_status_check", - "expression": "`status` in ('synced', 'failed', 'skipped')", - "definition": "check (`status` in ('synced', 'failed', 'skipped'))", - "columnName": "status" - } - ], - "triggers": [], - "foreignKeys": { - "discord_role_sync_attempt_auth_id_foreign": { - "columnNames": [ - "auth_id" - ], - "constraintName": "discord_role_sync_attempt_auth_id_foreign", - "localTableName": "discord_role_sync_attempt", - "referencedColumnNames": [ - "id" - ], - "referencedTableName": "core_user", - "deleteRule": "cascade" - } - }, - "comment": null - }, - { - "name": "discord_verification", - "columns": { - "accepted_at": { - "name": "accepted_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "auth_id": { - "name": "auth_id", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "avatar_hash": { - "name": "avatar_hash", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "code": { - "name": "code", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": true, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "created_at": { - "name": "created_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "discord_user_id": { - "name": "discord_user_id", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "expires_at": { - "name": "expires_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "guild_id": { - "name": "guild_id", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "status": { - "name": "status", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": "'pending'", - "comment": null, - "collation": null, - "enumItems": [ - "pending", - "accepted", - "rejected", - "expired" - ], - "mappedType": "enum" - }, - "username": { - "name": "username", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - } - }, - "indexes": [ - { - "columnNames": [ - "auth_id" - ], - "composite": false, - "constraint": false, - "keyName": "discord_verification_auth_id_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "created_at" - ], - "composite": false, - "constraint": false, - "keyName": "discord_verification_created_at_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "discord_user_id" - ], - "composite": false, - "constraint": false, - "keyName": "discord_verification_discord_user_id_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "guild_id" - ], - "composite": false, - "constraint": false, - "keyName": "discord_verification_guild_id_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "status" - ], - "composite": false, - "constraint": false, - "keyName": "discord_verification_status_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "code" - ], - "composite": false, - "constraint": true, - "keyName": "primary", - "primary": true, - "unique": true - } - ], - "checks": [ - { - "name": "discord_verification_status_check", - "expression": "`status` in ('pending', 'accepted', 'rejected', 'expired')", - "definition": "check (`status` in ('pending', 'accepted', 'rejected', 'expired'))", - "columnName": "status" - } - ], - "triggers": [], - "foreignKeys": { - "discord_verification_auth_id_foreign": { - "columnNames": [ - "auth_id" - ], - "constraintName": "discord_verification_auth_id_foreign", - "localTableName": "discord_verification", - "referencedColumnNames": [ - "id" - ], - "referencedTableName": "core_user", - "deleteRule": "set null" - } - }, - "comment": null - }, - { - "name": "session", - "columns": { - "created_at": { - "name": "created_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "expires_at": { - "name": "expires_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "id": { - "name": "id", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": true, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "ip_address": { - "name": "ip_address", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "token": { - "name": "token", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": true, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "updated_at": { - "name": "updated_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "user_agent": { - "name": "user_agent", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "user_id": { - "name": "user_id", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - } - }, - "indexes": [ - { - "columnNames": [ - "id" - ], - "composite": false, - "constraint": true, - "keyName": "primary", - "primary": true, - "unique": true - }, - { - "columnNames": [ - "token" - ], - "composite": false, - "constraint": true, - "keyName": "session_token_unique", - "primary": false, - "unique": true - }, - { - "columnNames": [ - "user_id" - ], - "composite": false, - "constraint": false, - "keyName": "session_user_id_index", - "primary": false, - "unique": false - } - ], - "checks": [], - "triggers": [], - "foreignKeys": { - "session_user_id_foreign": { - "columnNames": [ - "user_id" - ], - "constraintName": "session_user_id_foreign", - "localTableName": "session", - "referencedColumnNames": [ - "id" - ], - "referencedTableName": "core_user", - "deleteRule": "cascade" - } - }, - "comment": null - }, - { - "name": "teams_invite", - "columns": { - "created_at": { - "name": "created_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "id": { - "name": "id", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": true, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "invitee_auth_id": { - "name": "invitee_auth_id", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "status": { - "name": "status", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": "'pending'", - "comment": null, - "collation": null, - "enumItems": [ - "pending", - "accepted", - "declined" - ], - "mappedType": "enum" - }, - "team_id": { - "name": "team_id", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - } - }, - "indexes": [ - { - "columnNames": [ - "id" - ], - "composite": false, - "constraint": true, - "keyName": "primary", - "primary": true, - "unique": true - }, - { - "columnNames": [ - "invitee_auth_id" - ], - "composite": false, - "constraint": false, - "keyName": "teams_invite_invitee_auth_id_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "team_id" - ], - "composite": false, - "constraint": false, - "keyName": "teams_invite_team_id_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "team_id", - "invitee_auth_id" - ], - "composite": true, - "constraint": false, - "keyName": "teams_invite_team_id_invitee_auth_id_index", - "primary": false, - "unique": false - } - ], - "checks": [ - { - "name": "teams_invite_status_check", - "expression": "`status` in ('pending', 'accepted', 'declined')", - "definition": "check (`status` in ('pending', 'accepted', 'declined'))", - "columnName": "status" - } - ], - "triggers": [], - "foreignKeys": { - "teams_invite_invitee_auth_id_foreign": { - "columnNames": [ - "invitee_auth_id" - ], - "constraintName": "teams_invite_invitee_auth_id_foreign", - "localTableName": "teams_invite", - "referencedColumnNames": [ - "id" - ], - "referencedTableName": "core_user", - "deleteRule": "cascade" - }, - "teams_invite_team_id_foreign": { - "columnNames": [ - "team_id" - ], - "constraintName": "teams_invite_team_id_foreign", - "localTableName": "teams_invite", - "referencedColumnNames": [ - "id" - ], - "referencedTableName": "teams_team", - "deleteRule": "cascade" - } - }, - "comment": null - }, - { - "name": "teams_member", - "columns": { - "auth_id": { - "name": "auth_id", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": true, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "id": { - "name": "id", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": true, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "joined_at": { - "name": "joined_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "team_id": { - "name": "team_id", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - } - }, - "indexes": [ - { - "columnNames": [ - "id" - ], - "composite": false, - "constraint": true, - "keyName": "primary", - "primary": true, - "unique": true - }, - { - "columnNames": [ - "auth_id" - ], - "composite": false, - "constraint": false, - "keyName": "teams_member_auth_id_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "auth_id" - ], - "composite": false, - "constraint": true, - "keyName": "teams_member_auth_id_unique", - "primary": false, - "unique": true - }, - { - "columnNames": [ - "team_id" - ], - "composite": false, - "constraint": false, - "keyName": "teams_member_team_id_index", - "primary": false, - "unique": false - } - ], - "checks": [], - "triggers": [], - "foreignKeys": { - "teams_member_auth_id_foreign": { - "columnNames": [ - "auth_id" - ], - "constraintName": "teams_member_auth_id_foreign", - "localTableName": "teams_member", - "referencedColumnNames": [ - "id" - ], - "referencedTableName": "core_user", - "deleteRule": "cascade" - }, - "teams_member_team_id_foreign": { - "columnNames": [ - "team_id" - ], - "constraintName": "teams_member_team_id_foreign", - "localTableName": "teams_member", - "referencedColumnNames": [ - "id" - ], - "referencedTableName": "teams_team", - "deleteRule": "cascade" - } - }, - "comment": null - }, - { - "name": "teams_team", - "columns": { - "created_at": { - "name": "created_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "id": { - "name": "id", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": true, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "name": { - "name": "name", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "owner_auth_id": { - "name": "owner_auth_id", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "tag": { - "name": "tag", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": true, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - } - }, - "indexes": [ - { - "columnNames": [ - "id" - ], - "composite": false, - "constraint": true, - "keyName": "primary", - "primary": true, - "unique": true - }, - { - "columnNames": [ - "owner_auth_id" - ], - "composite": false, - "constraint": false, - "keyName": "teams_team_owner_auth_id_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "tag" - ], - "composite": false, - "constraint": false, - "keyName": "teams_team_tag_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "tag" - ], - "composite": false, - "constraint": true, - "keyName": "teams_team_tag_unique", - "primary": false, - "unique": true - } - ], - "checks": [], - "triggers": [], - "foreignKeys": { - "teams_team_owner_auth_id_foreign": { - "columnNames": [ - "owner_auth_id" - ], - "constraintName": "teams_team_owner_auth_id_foreign", - "localTableName": "teams_team", - "referencedColumnNames": [ - "id" - ], - "referencedTableName": "core_user", - "deleteRule": "cascade" - } - }, - "comment": null - }, - { - "name": "verification", - "columns": { - "created_at": { - "name": "created_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "expires_at": { - "name": "expires_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "id": { - "name": "id", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": true, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "identifier": { - "name": "identifier", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "updated_at": { - "name": "updated_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "value": { - "name": "value", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - } - }, - "indexes": [ - { - "columnNames": [ - "id" - ], - "composite": false, - "constraint": true, - "keyName": "primary", - "primary": true, - "unique": true - }, - { - "columnNames": [ - "identifier" - ], - "composite": false, - "constraint": false, - "keyName": "verification_identifier_index", - "primary": false, - "unique": false - } - ], - "checks": [], - "triggers": [], - "foreignKeys": {}, - "comment": null - } - ], - "views": [], - "nativeEnums": {} -} \ No newline at end of file diff --git a/templates/nextjs-full/db/migrations/sqlite/Migration20260927180400_initial.ts b/templates/nextjs-full/db/migrations/sqlite/Migration20260927180400_initial.ts deleted file mode 100644 index 7adbaced8..000000000 --- a/templates/nextjs-full/db/migrations/sqlite/Migration20260927180400_initial.ts +++ /dev/null @@ -1,119 +0,0 @@ -import { Migration } from "@mikro-orm/migrations"; - -export class Migration20260927180400_initial extends Migration { - override name = "Migration20260927180400_initial"; - - override up(): void { - this.addSql("create table `verification` (`id` text not null primary key, `identifier` text not null, `value` text not null, `expires_at` datetime not null, `created_at` datetime null, `updated_at` datetime null);"); - this.addSql("create index `verification_identifier_index` on `verification` (`identifier`);"); - this.addSql("create table `core_event` (`id` text not null primary key, `title` text not null, `start_time` datetime not null, `end_time` datetime not null, `location` text not null default 'TBD', `description` text not null, `type` text not null, `host` text null, `hidden` integer not null default false, `created_at` datetime not null, `updated_at` datetime not null);"); - this.addSql("create index `core_event_start_time_index` on `core_event` (`start_time`);"); - this.addSql("create index `core_event_type_index` on `core_event` (`type`);"); - this.addSql("create index `core_event_hidden_index` on `core_event` (`hidden`);"); - this.addSql("create table `core_operation_lock` (`key` text not null primary key, `token` text not null);"); - this.addSql("create table `core_role` (`id` text not null primary key, `name` text not null, `position` integer not null, `permissions` json not null default '[]', `color` text null, `created_at` datetime not null, `updated_at` datetime not null);"); - this.addSql("create unique index `core_role_name_unique` on `core_role` (`name`);"); - this.addSql("create index `core_role_position_index` on `core_role` (`position`);"); - this.addSql("create table `core_user` (`id` text not null primary key, `name` text not null, `email` text not null, `email_verified` integer not null default false, `profile_photo_url` text null, `hack_tag` text null, `bio` text null, `pronouns` text null, `skills` json not null default '[]', `is_profile_searchable` integer not null default true, `discord_display_handle` text null, `role_id` text null, `is_approved` integer not null default false, `checked_in_at` datetime null, `created_at` datetime not null, `updated_at` datetime not null, constraint `core_user_role_id_foreign` foreign key (`role_id`) references `core_role` (`id`) on delete set null);"); - this.addSql("create unique index `core_user_email_unique` on `core_user` (`email`);"); - this.addSql("create unique index `core_user_hack_tag_unique` on `core_user` (`hack_tag`);"); - this.addSql("create index `core_user_hack_tag_index` on `core_user` (`hack_tag`);"); - this.addSql("create index `core_user_role_id_index` on `core_user` (`role_id`);"); - this.addSql("create index `core_user_created_at_index` on `core_user` (`created_at`);"); - this.addSql("create table `discord_verification` (`code` text not null primary key, `discord_user_id` text not null, `guild_id` text not null, `username` text not null, `avatar_hash` text null, `auth_id` text null, `status` text check (`status` in ('pending', 'accepted', 'rejected', 'expired')) not null default 'pending', `expires_at` datetime not null, `created_at` datetime not null, `accepted_at` datetime null, constraint `discord_verification_auth_id_foreign` foreign key (`auth_id`) references `core_user` (`id`) on delete set null);"); - this.addSql("create index `discord_verification_discord_user_id_index` on `discord_verification` (`discord_user_id`);"); - this.addSql("create index `discord_verification_guild_id_index` on `discord_verification` (`guild_id`);"); - this.addSql("create index `discord_verification_auth_id_index` on `discord_verification` (`auth_id`);"); - this.addSql("create index `discord_verification_status_index` on `discord_verification` (`status`);"); - this.addSql("create index `discord_verification_created_at_index` on `discord_verification` (`created_at`);"); - this.addSql("create table `discord_role_sync_attempt` (`id` text not null primary key, `auth_id` text not null, `discord_user_id` text not null, `guild_id` text not null, `status` text check (`status` in ('synced', 'failed', 'skipped')) not null, `role_ids` json not null default '[]', `role_names` json not null default '[]', `error` text null, `created_at` datetime not null, constraint `discord_role_sync_attempt_auth_id_foreign` foreign key (`auth_id`) references `core_user` (`id`) on delete cascade);"); - this.addSql("create index `discord_role_sync_attempt_auth_id_index` on `discord_role_sync_attempt` (`auth_id`);"); - this.addSql("create index `discord_role_sync_attempt_discord_user_id_index` on `discord_role_sync_attempt` (`discord_user_id`);"); - this.addSql("create index `discord_role_sync_attempt_status_index` on `discord_role_sync_attempt` (`status`);"); - this.addSql("create index `discord_role_sync_attempt_created_at_index` on `discord_role_sync_attempt` (`created_at`);"); - this.addSql("create table `discord_member` (`auth_id` text not null primary key, `discord_user_id` text not null, `guild_id` text not null, `username` text not null, `avatar_hash` text null, `verified_at` datetime not null, `updated_at` datetime not null, `last_role_sync_at` datetime null, constraint `discord_member_auth_id_foreign` foreign key (`auth_id`) references `core_user` (`id`) on update cascade on delete cascade);"); - this.addSql("create index `discord_member_auth_id_index` on `discord_member` (`auth_id`);"); - this.addSql("create unique index `discord_member_discord_user_id_unique` on `discord_member` (`discord_user_id`);"); - this.addSql("create index `discord_member_discord_user_id_index` on `discord_member` (`discord_user_id`);"); - this.addSql("create index `discord_member_guild_id_index` on `discord_member` (`guild_id`);"); - this.addSql("create index `discord_member_updated_at_index` on `discord_member` (`updated_at`);"); - this.addSql("create table `core_user_data` (`auth_id` text not null primary key, `age` integer not null, `gender` text not null, `race` text not null, `ethnicity` text not null, `shirt_size` text not null, `dietary_restrictions` json not null default '[]', `accommodation_note` text null, `phone_number` text null, `country_of_residence` text null, `has_accepted_mlhcode_of_conduct` integer not null, `has_shared_data_with_mlh` integer not null, `is_emailable` integer not null, `completed_at` datetime not null, `updated_at` datetime not null, constraint `core_user_data_auth_id_foreign` foreign key (`auth_id`) references `core_user` (`id`) on update cascade on delete cascade);"); - this.addSql("create index `core_user_data_auth_id_index` on `core_user_data` (`auth_id`);"); - this.addSql("create table `core_user_ban` (`auth_id` text not null primary key, `reason` text null, `banned_by_auth_id` text not null, `created_at` datetime not null, constraint `core_user_ban_auth_id_foreign` foreign key (`auth_id`) references `core_user` (`id`) on update cascade on delete cascade, constraint `core_user_ban_banned_by_auth_id_foreign` foreign key (`banned_by_auth_id`) references `core_user` (`id`));"); - this.addSql("create index `core_user_ban_auth_id_index` on `core_user_ban` (`auth_id`);"); - this.addSql("create index `core_user_ban_banned_by_auth_id_index` on `core_user_ban` (`banned_by_auth_id`);"); - this.addSql("create table `core_setting` (`key` text not null primary key, `value` json not null, `created_at` datetime not null, `created_by_auth_id` text null, `updated_at` datetime not null, `updated_by_auth_id` text null, constraint `core_setting_created_by_auth_id_foreign` foreign key (`created_by_auth_id`) references `core_user` (`id`) on delete set null, constraint `core_setting_updated_by_auth_id_foreign` foreign key (`updated_by_auth_id`) references `core_user` (`id`) on delete set null);"); - this.addSql("create index `core_setting_created_by_auth_id_index` on `core_setting` (`created_by_auth_id`);"); - this.addSql("create index `core_setting_updated_at_index` on `core_setting` (`updated_at`);"); - this.addSql("create index `core_setting_updated_by_auth_id_index` on `core_setting` (`updated_by_auth_id`);"); - this.addSql("create table `core_rsvp` (`auth_id` text not null primary key, `status` text check (`status` in ('confirmed', 'waitlisted', 'cancelled')) not null, `waitlist_position` integer null, `created_at` datetime not null, `updated_at` datetime not null, `confirmed_at` datetime null, `waitlisted_at` datetime null, `cancelled_at` datetime null, `cancelled_by_auth_id` text null, `promoted_at` datetime null, `promoted_by_auth_id` text null, constraint `core_rsvp_auth_id_foreign` foreign key (`auth_id`) references `core_user` (`id`) on update cascade on delete cascade, constraint `core_rsvp_cancelled_by_auth_id_foreign` foreign key (`cancelled_by_auth_id`) references `core_user` (`id`) on delete set null, constraint `core_rsvp_promoted_by_auth_id_foreign` foreign key (`promoted_by_auth_id`) references `core_user` (`id`) on delete set null);"); - this.addSql("create index `core_rsvp_auth_id_index` on `core_rsvp` (`auth_id`);"); - this.addSql("create index `core_rsvp_cancelled_by_auth_id_index` on `core_rsvp` (`cancelled_by_auth_id`);"); - this.addSql("create index `core_rsvp_promoted_by_auth_id_index` on `core_rsvp` (`promoted_by_auth_id`);"); - this.addSql("create index `core_rsvp_status_index` on `core_rsvp` (`status`);"); - this.addSql("create index `core_rsvp_waitlist_position_index` on `core_rsvp` (`waitlist_position`);"); - this.addSql("create index `core_rsvp_created_at_index` on `core_rsvp` (`created_at`);"); - this.addSql("create index `core_rsvp_updated_at_index` on `core_rsvp` (`updated_at`);"); - this.addSql("create table `core_notification_intent` (`id` text not null primary key, `kind` text not null, `recipient_auth_id` text null, `payload` json not null, `status` text check (`status` in ('pending', 'processing', 'delivered', 'failed', 'skipped')) not null default 'pending', `idempotency_key` text null, `created_at` datetime not null, `updated_at` datetime not null, constraint `core_notification_intent_recipient_auth_id_foreign` foreign key (`recipient_auth_id`) references `core_user` (`id`) on delete set null);"); - this.addSql("create unique index `core_notification_intent_idempotency_key_unique` on `core_notification_intent` (`idempotency_key`);"); - this.addSql("create index `core_notification_intent_kind_index` on `core_notification_intent` (`kind`);"); - this.addSql("create index `core_notification_intent_recipient_auth_id_index` on `core_notification_intent` (`recipient_auth_id`);"); - this.addSql("create index `core_notification_intent_status_index` on `core_notification_intent` (`status`);"); - this.addSql("create index `core_notification_intent_created_at_index` on `core_notification_intent` (`created_at`);"); - this.addSql("create table `core_notification_delivery_attempt` (`id` text not null primary key, `intent_id` text not null, `channel` text not null, `provider` text null, `status` text check (`status` in ('delivered', 'failed', 'skipped')) not null, `recipient` text null, `external_id` text null, `error` text null, `metadata` json not null, `attempted_at` datetime not null, constraint `core_notification_delivery_attempt_intent_id_foreign` foreign key (`intent_id`) references `core_notification_intent` (`id`) on delete cascade);"); - this.addSql("create index `core_notification_delivery_attempt_intent_id_index` on `core_notification_delivery_attempt` (`intent_id`);"); - this.addSql("create index `core_notification_delivery_attempt_channel_index` on `core_notification_delivery_attempt` (`channel`);"); - this.addSql("create index `core_notification_delivery_attempt_status_index` on `core_notification_delivery_attempt` (`status`);"); - this.addSql("create index `core_notification_delivery_attempt_attempted_at_index` on `core_notification_delivery_attempt` (`attempted_at`);"); - this.addSql("create table `core_hacker` (`auth_id` text not null primary key, `university` text not null, `major` text not null, `school_id` text null, `level_of_study` text not null, `hackathons_attended` integer not null, `software_experience` text not null, `heard_from` text null, `github_url` text null, `linked_in_url` text null, `personal_website_url` text null, `resume_url` text null, `group` text null, `registered_at` datetime not null, `updated_at` datetime not null, constraint `core_hacker_auth_id_foreign` foreign key (`auth_id`) references `core_user` (`id`) on update cascade on delete cascade);"); - this.addSql("create index `core_hacker_auth_id_index` on `core_hacker` (`auth_id`);"); - this.addSql("create index `core_hacker_registered_at_index` on `core_hacker` (`registered_at`);"); - this.addSql("create table `core_event_scan` (`id` text not null primary key, `event_id` text not null, `auth_id` text not null, `scanned_by_auth_id` text not null, `scanned_at` datetime not null, constraint `core_event_scan_event_id_foreign` foreign key (`event_id`) references `core_event` (`id`) on delete cascade, constraint `core_event_scan_auth_id_foreign` foreign key (`auth_id`) references `core_user` (`id`) on delete cascade, constraint `core_event_scan_scanned_by_auth_id_foreign` foreign key (`scanned_by_auth_id`) references `core_user` (`id`));"); - this.addSql("create index `core_event_scan_scanned_by_auth_id_index` on `core_event_scan` (`scanned_by_auth_id`);"); - this.addSql("create index `core_event_scan_event_id_index` on `core_event_scan` (`event_id`);"); - this.addSql("create index `core_event_scan_auth_id_index` on `core_event_scan` (`auth_id`);"); - this.addSql("create index `core_event_scan_event_id_auth_id_index` on `core_event_scan` (`event_id`, `auth_id`);"); - this.addSql("create index `core_event_scan_scanned_at_index` on `core_event_scan` (`scanned_at`);"); - this.addSql("create table `session` (`id` text not null primary key, `expires_at` datetime not null, `token` text not null, `created_at` datetime not null, `updated_at` datetime not null, `ip_address` text null, `user_agent` text null, `user_id` text not null, constraint `session_user_id_foreign` foreign key (`user_id`) references `core_user` (`id`) on delete cascade);"); - this.addSql("create unique index `session_token_unique` on `session` (`token`);"); - this.addSql("create index `session_user_id_index` on `session` (`user_id`);"); - this.addSql("create table `account` (`id` text not null primary key, `account_id` text not null, `provider_id` text not null, `user_id` text not null, `access_token` text null, `refresh_token` text null, `id_token` text null, `access_token_expires_at` datetime null, `refresh_token_expires_at` datetime null, `scope` text null, `password` text null, `created_at` datetime not null, `updated_at` datetime not null, constraint `account_user_id_foreign` foreign key (`user_id`) references `core_user` (`id`) on delete cascade);"); - this.addSql("create index `account_user_id_index` on `account` (`user_id`);"); - this.addSql("create table `teams_team` (`id` text not null primary key, `name` text not null, `tag` text not null, `owner_auth_id` text not null, `created_at` datetime not null, constraint `teams_team_owner_auth_id_foreign` foreign key (`owner_auth_id`) references `core_user` (`id`) on delete cascade);"); - this.addSql("create unique index `teams_team_tag_unique` on `teams_team` (`tag`);"); - this.addSql("create index `teams_team_tag_index` on `teams_team` (`tag`);"); - this.addSql("create index `teams_team_owner_auth_id_index` on `teams_team` (`owner_auth_id`);"); - this.addSql("create table `teams_member` (`id` text not null primary key, `team_id` text not null, `auth_id` text not null, `joined_at` datetime not null, constraint `teams_member_team_id_foreign` foreign key (`team_id`) references `teams_team` (`id`) on delete cascade, constraint `teams_member_auth_id_foreign` foreign key (`auth_id`) references `core_user` (`id`) on delete cascade);"); - this.addSql("create unique index `teams_member_auth_id_unique` on `teams_member` (`auth_id`);"); - this.addSql("create index `teams_member_team_id_index` on `teams_member` (`team_id`);"); - this.addSql("create index `teams_member_auth_id_index` on `teams_member` (`auth_id`);"); - this.addSql("create table `teams_invite` (`id` text not null primary key, `team_id` text not null, `invitee_auth_id` text not null, `status` text check (`status` in ('pending', 'accepted', 'declined')) not null default 'pending', `created_at` datetime not null, constraint `teams_invite_team_id_foreign` foreign key (`team_id`) references `teams_team` (`id`) on delete cascade, constraint `teams_invite_invitee_auth_id_foreign` foreign key (`invitee_auth_id`) references `core_user` (`id`) on delete cascade);"); - this.addSql("create index `teams_invite_team_id_index` on `teams_invite` (`team_id`);"); - this.addSql("create index `teams_invite_invitee_auth_id_index` on `teams_invite` (`invitee_auth_id`);"); - this.addSql("create index `teams_invite_team_id_invitee_auth_id_index` on `teams_invite` (`team_id`, `invitee_auth_id`);"); - } - - override down(): void { - this.addSql("drop table if exists `teams_invite`;"); - this.addSql("drop table if exists `teams_member`;"); - this.addSql("drop table if exists `teams_team`;"); - this.addSql("drop table if exists `account`;"); - this.addSql("drop table if exists `session`;"); - this.addSql("drop table if exists `core_event_scan`;"); - this.addSql("drop table if exists `core_hacker`;"); - this.addSql("drop table if exists `core_notification_delivery_attempt`;"); - this.addSql("drop table if exists `core_notification_intent`;"); - this.addSql("drop table if exists `core_rsvp`;"); - this.addSql("drop table if exists `core_setting`;"); - this.addSql("drop table if exists `core_user_ban`;"); - this.addSql("drop table if exists `core_user_data`;"); - this.addSql("drop table if exists `discord_member`;"); - this.addSql("drop table if exists `discord_role_sync_attempt`;"); - this.addSql("drop table if exists `discord_verification`;"); - this.addSql("drop table if exists `core_user`;"); - this.addSql("drop table if exists `core_role`;"); - this.addSql("drop table if exists `core_operation_lock`;"); - this.addSql("drop table if exists `core_event`;"); - this.addSql("drop table if exists `verification`;"); - } -} diff --git a/templates/nextjs-full/env.ts b/templates/nextjs-full/env.ts index d31148b4d..f72160359 100644 --- a/templates/nextjs-full/env.ts +++ b/templates/nextjs-full/env.ts @@ -11,6 +11,7 @@ type TestWebEnv = { betterAuthTrustedOrigins: string[]; databaseUrl: string; databaseDialect: DatabaseDialect; + migrationsPath?: string; tursoAuthToken?: string; blobAdapter: BlobAdapter; localBlobBaseDir: string; @@ -185,6 +186,7 @@ export function resolveTestWebEnv(): TestWebEnv { betterAuthTrustedOrigins: readList("BETTER_AUTH_TRUSTED_ORIGINS"), databaseUrl, databaseDialect: resolveDatabaseDialect(databaseUrl), + migrationsPath: read("HACKKIT_MIGRATIONS_PATH"), tursoAuthToken: read("TURSO_AUTH_TOKEN"), blobAdapter, localBlobBaseDir: diff --git a/templates/nextjs-full/lib/database-config.ts b/templates/nextjs-full/lib/database-config.ts index ddecb4c38..07802116f 100644 --- a/templates/nextjs-full/lib/database-config.ts +++ b/templates/nextjs-full/lib/database-config.ts @@ -11,8 +11,8 @@ const appDirectory = process.cwd(); const migrations = { path: resolve( appDirectory, - "db/migrations", - env.databaseDialect === "libsql" ? "sqlite" : env.databaseDialect, + env.migrationsPath ?? + `db/migrations/${env.databaseDialect === "libsql" ? "sqlite" : env.databaseDialect}`, ), emit: "ts" as const, snapshot: true, diff --git a/templates/nextjs-minimal/.env.example b/templates/nextjs-minimal/.env.example index 1fa06f751..7a82b8ed9 100644 --- a/templates/nextjs-minimal/.env.example +++ b/templates/nextjs-minimal/.env.example @@ -16,3 +16,6 @@ BETTER_AUTH_SECRET= # BETTER_AUTH_TRUSTED_ORIGINS=https://another-origin.example.com # Optional: local upload directory, relative to this template or absolute. # HACKKIT_LOCAL_BLOB_BASE_DIR=.data/uploads + +# Optional: migration history directory, relative to this template or absolute. +# HACKKIT_MIGRATIONS_PATH=db/migrations/sqlite diff --git a/templates/nextjs-minimal/README.md b/templates/nextjs-minimal/README.md index 916df9b1d..cb8671e0c 100644 --- a/templates/nextjs-minimal/README.md +++ b/templates/nextjs-minimal/README.md @@ -9,9 +9,11 @@ Use Node.js 22.17 or newer and the repository-pinned pnpm 12.15.0. From the repo 1. Run `corepack pnpm install`. 2. Build dependencies with `corepack pnpm exec turbo run build --filter=@hackkit/template-nextjs-minimal^...`. 3. Run `corepack pnpm --filter @hackkit/template-nextjs-minimal sync`. -4. Run `corepack pnpm --filter @hackkit/template-nextjs-minimal db:migrate`. -5. Run `corepack pnpm --filter @hackkit/template-nextjs-minimal db:seed`. -6. Run `corepack pnpm dev:minimal` and open `http://localhost:3000`. +4. Configure this template using `.env.example` and `hackkit.config.ts`. Use an empty SQLite development database. +5. Run `corepack pnpm --filter @hackkit/template-nextjs-minimal db:generate --name initial`. +6. Review the generated migration and snapshot, then run `corepack pnpm --filter @hackkit/template-nextjs-minimal db:migrate`. +7. Run `corepack pnpm --filter @hackkit/template-nextjs-minimal db:seed`. +8. Commit the migration and snapshot in your application repository. Run `corepack pnpm dev:minimal` and open `http://localhost:3000`. The local `.env` starts empty and is ignored by Git. On a fresh checkout, copy [`.env.example`](.env.example) to `.env` to configure this template. The example lists production requirements and comments out optional integrations. An empty `.env` uses local development defaults. Never commit populated environment files. @@ -23,7 +25,9 @@ Sign up and complete HackTag, user data, and hacker registration. Organizers can Run `corepack pnpm --filter @hackkit/template-nextjs-minimal db:` from the repository root. Commands are `generate`, `migrate`, `seed`, `status`, `check`, `rollback`, and `reset`. Arguments are forwarded, for example `db:generate --name add_field` or `db:rollback --to MigrationName`. -Reviewed SQLite migrations and snapshots belong to this app. `db:check` fails on pending migrations or schema drift. `db:reset` drops the selected database's registered tables and migration history, then migrates and seeds; it is restricted to local SQLite in development/tests. Use only disposable data for reset. +The template ships without migration history or snapshots. Generate a baseline once during new-project setup, after choosing your configuration. Commit the reviewed SQLite migration and snapshot under `db/migrations/sqlite` in your application repository. Later clones apply this history without generating another baseline. Future entity changes produce additional migrations. Existing databases must retain the history that created them. + +`HACKKIT_MIGRATIONS_PATH` optionally overrides the migration directory, relative to this application or absolute. `db:check` fails on pending migrations or schema drift. `db:reset` drops the selected database's registered tables and migration history, then migrates and seeds; it is restricted to local SQLite in development/tests. Use only disposable data for reset. ## Production diff --git a/templates/nextjs-minimal/app/app-bar.tsx b/templates/nextjs-minimal/app/app-bar.tsx index 8586046f1..cd6feb548 100644 --- a/templates/nextjs-minimal/app/app-bar.tsx +++ b/templates/nextjs-minimal/app/app-bar.tsx @@ -42,7 +42,7 @@ export async function AppBar() { name={session.user.name} email={session.user.email} image={ - currentUser?.profilePhotoUrl ?? + currentUser?.image ?? session.user.image } isAdmin={isAdmin} diff --git a/templates/nextjs-minimal/db/migrations/sqlite/.snapshot.json b/templates/nextjs-minimal/db/migrations/sqlite/.snapshot.json deleted file mode 100644 index 371c01ff6..000000000 --- a/templates/nextjs-minimal/db/migrations/sqlite/.snapshot.json +++ /dev/null @@ -1,3334 +0,0 @@ -{ - "namespaces": [], - "tables": [ - { - "name": "account", - "columns": { - "access_token": { - "name": "access_token", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "access_token_expires_at": { - "name": "access_token_expires_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "account_id": { - "name": "account_id", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "created_at": { - "name": "created_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "id": { - "name": "id", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": true, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "id_token": { - "name": "id_token", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "password": { - "name": "password", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "provider_id": { - "name": "provider_id", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "refresh_token": { - "name": "refresh_token", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "refresh_token_expires_at": { - "name": "refresh_token_expires_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "scope": { - "name": "scope", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "updated_at": { - "name": "updated_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "user_id": { - "name": "user_id", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - } - }, - "indexes": [ - { - "columnNames": [ - "user_id" - ], - "composite": false, - "constraint": false, - "keyName": "account_user_id_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "id" - ], - "composite": false, - "constraint": true, - "keyName": "primary", - "primary": true, - "unique": true - } - ], - "checks": [], - "triggers": [], - "foreignKeys": { - "account_user_id_foreign": { - "columnNames": [ - "user_id" - ], - "constraintName": "account_user_id_foreign", - "localTableName": "account", - "referencedColumnNames": [ - "id" - ], - "referencedTableName": "core_user", - "deleteRule": "cascade" - } - }, - "comment": null - }, - { - "name": "core_event", - "columns": { - "created_at": { - "name": "created_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "description": { - "name": "description", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "end_time": { - "name": "end_time", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "hidden": { - "name": "hidden", - "type": "integer", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": "false", - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "integer" - }, - "host": { - "name": "host", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "id": { - "name": "id", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": true, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "location": { - "name": "location", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": "'TBD'", - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "start_time": { - "name": "start_time", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "title": { - "name": "title", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "type": { - "name": "type", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "updated_at": { - "name": "updated_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - } - }, - "indexes": [ - { - "columnNames": [ - "hidden" - ], - "composite": false, - "constraint": false, - "keyName": "core_event_hidden_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "start_time" - ], - "composite": false, - "constraint": false, - "keyName": "core_event_start_time_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "type" - ], - "composite": false, - "constraint": false, - "keyName": "core_event_type_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "id" - ], - "composite": false, - "constraint": true, - "keyName": "primary", - "primary": true, - "unique": true - } - ], - "checks": [], - "triggers": [], - "foreignKeys": {}, - "comment": null - }, - { - "name": "core_event_scan", - "columns": { - "auth_id": { - "name": "auth_id", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "event_id": { - "name": "event_id", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "id": { - "name": "id", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": true, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "scanned_at": { - "name": "scanned_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "scanned_by_auth_id": { - "name": "scanned_by_auth_id", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - } - }, - "indexes": [ - { - "columnNames": [ - "auth_id" - ], - "composite": false, - "constraint": false, - "keyName": "core_event_scan_auth_id_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "event_id", - "auth_id" - ], - "composite": true, - "constraint": false, - "keyName": "core_event_scan_event_id_auth_id_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "event_id" - ], - "composite": false, - "constraint": false, - "keyName": "core_event_scan_event_id_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "scanned_at" - ], - "composite": false, - "constraint": false, - "keyName": "core_event_scan_scanned_at_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "scanned_by_auth_id" - ], - "composite": false, - "constraint": false, - "keyName": "core_event_scan_scanned_by_auth_id_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "id" - ], - "composite": false, - "constraint": true, - "keyName": "primary", - "primary": true, - "unique": true - } - ], - "checks": [], - "triggers": [], - "foreignKeys": { - "core_event_scan_auth_id_foreign": { - "columnNames": [ - "auth_id" - ], - "constraintName": "core_event_scan_auth_id_foreign", - "localTableName": "core_event_scan", - "referencedColumnNames": [ - "id" - ], - "referencedTableName": "core_user", - "deleteRule": "cascade" - }, - "core_event_scan_event_id_foreign": { - "columnNames": [ - "event_id" - ], - "constraintName": "core_event_scan_event_id_foreign", - "localTableName": "core_event_scan", - "referencedColumnNames": [ - "id" - ], - "referencedTableName": "core_event", - "deleteRule": "cascade" - }, - "core_event_scan_scanned_by_auth_id_foreign": { - "columnNames": [ - "scanned_by_auth_id" - ], - "constraintName": "core_event_scan_scanned_by_auth_id_foreign", - "localTableName": "core_event_scan", - "referencedColumnNames": [ - "id" - ], - "referencedTableName": "core_user" - } - }, - "comment": null - }, - { - "name": "core_hacker", - "columns": { - "auth_id": { - "name": "auth_id", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": true, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "github_url": { - "name": "github_url", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "group": { - "name": "group", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "hackathons_attended": { - "name": "hackathons_attended", - "type": "integer", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "integer" - }, - "heard_from": { - "name": "heard_from", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "level_of_study": { - "name": "level_of_study", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "linked_in_url": { - "name": "linked_in_url", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "major": { - "name": "major", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "personal_website_url": { - "name": "personal_website_url", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "registered_at": { - "name": "registered_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "resume_url": { - "name": "resume_url", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "school_id": { - "name": "school_id", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "software_experience": { - "name": "software_experience", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "university": { - "name": "university", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "updated_at": { - "name": "updated_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - } - }, - "indexes": [ - { - "columnNames": [ - "auth_id" - ], - "composite": false, - "constraint": false, - "keyName": "core_hacker_auth_id_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "registered_at" - ], - "composite": false, - "constraint": false, - "keyName": "core_hacker_registered_at_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "auth_id" - ], - "composite": false, - "constraint": true, - "keyName": "primary", - "primary": true, - "unique": true - } - ], - "checks": [], - "triggers": [], - "foreignKeys": { - "core_hacker_auth_id_foreign": { - "columnNames": [ - "auth_id" - ], - "constraintName": "core_hacker_auth_id_foreign", - "localTableName": "core_hacker", - "referencedColumnNames": [ - "id" - ], - "referencedTableName": "core_user", - "updateRule": "cascade", - "deleteRule": "cascade" - } - }, - "comment": null - }, - { - "name": "core_notification_delivery_attempt", - "columns": { - "attempted_at": { - "name": "attempted_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "channel": { - "name": "channel", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "error": { - "name": "error", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "external_id": { - "name": "external_id", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "id": { - "name": "id", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": true, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "intent_id": { - "name": "intent_id", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "metadata": { - "name": "metadata", - "type": "json", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "json" - }, - "provider": { - "name": "provider", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "recipient": { - "name": "recipient", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "status": { - "name": "status", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [ - "delivered", - "failed", - "skipped" - ], - "mappedType": "enum" - } - }, - "indexes": [ - { - "columnNames": [ - "attempted_at" - ], - "composite": false, - "constraint": false, - "keyName": "core_notification_delivery_attempt_attempted_at_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "channel" - ], - "composite": false, - "constraint": false, - "keyName": "core_notification_delivery_attempt_channel_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "intent_id" - ], - "composite": false, - "constraint": false, - "keyName": "core_notification_delivery_attempt_intent_id_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "status" - ], - "composite": false, - "constraint": false, - "keyName": "core_notification_delivery_attempt_status_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "id" - ], - "composite": false, - "constraint": true, - "keyName": "primary", - "primary": true, - "unique": true - } - ], - "checks": [ - { - "name": "core_notification_delivery_attempt_status_check", - "expression": "`status` in ('delivered', 'failed', 'skipped')", - "definition": "check (`status` in ('delivered', 'failed', 'skipped'))", - "columnName": "status" - } - ], - "triggers": [], - "foreignKeys": { - "core_notification_delivery_attempt_intent_id_foreign": { - "columnNames": [ - "intent_id" - ], - "constraintName": "core_notification_delivery_attempt_intent_id_foreign", - "localTableName": "core_notification_delivery_attempt", - "referencedColumnNames": [ - "id" - ], - "referencedTableName": "core_notification_intent", - "deleteRule": "cascade" - } - }, - "comment": null - }, - { - "name": "core_notification_intent", - "columns": { - "created_at": { - "name": "created_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "id": { - "name": "id", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": true, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "idempotency_key": { - "name": "idempotency_key", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": true, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "kind": { - "name": "kind", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "payload": { - "name": "payload", - "type": "json", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "json" - }, - "recipient_auth_id": { - "name": "recipient_auth_id", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "status": { - "name": "status", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": "'pending'", - "comment": null, - "collation": null, - "enumItems": [ - "pending", - "processing", - "delivered", - "failed", - "skipped" - ], - "mappedType": "enum" - }, - "updated_at": { - "name": "updated_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - } - }, - "indexes": [ - { - "columnNames": [ - "created_at" - ], - "composite": false, - "constraint": false, - "keyName": "core_notification_intent_created_at_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "idempotency_key" - ], - "composite": false, - "constraint": true, - "keyName": "core_notification_intent_idempotency_key_unique", - "primary": false, - "unique": true - }, - { - "columnNames": [ - "kind" - ], - "composite": false, - "constraint": false, - "keyName": "core_notification_intent_kind_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "recipient_auth_id" - ], - "composite": false, - "constraint": false, - "keyName": "core_notification_intent_recipient_auth_id_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "status" - ], - "composite": false, - "constraint": false, - "keyName": "core_notification_intent_status_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "id" - ], - "composite": false, - "constraint": true, - "keyName": "primary", - "primary": true, - "unique": true - } - ], - "checks": [ - { - "name": "core_notification_intent_status_check", - "expression": "`status` in ('pending', 'processing', 'delivered', 'failed', 'skipped')", - "definition": "check (`status` in ('pending', 'processing', 'delivered', 'failed', 'skipped'))", - "columnName": "status" - } - ], - "triggers": [], - "foreignKeys": { - "core_notification_intent_recipient_auth_id_foreign": { - "columnNames": [ - "recipient_auth_id" - ], - "constraintName": "core_notification_intent_recipient_auth_id_foreign", - "localTableName": "core_notification_intent", - "referencedColumnNames": [ - "id" - ], - "referencedTableName": "core_user", - "deleteRule": "set null" - } - }, - "comment": null - }, - { - "name": "core_operation_lock", - "columns": { - "key": { - "name": "key", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": true, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "token": { - "name": "token", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - } - }, - "indexes": [ - { - "columnNames": [ - "key" - ], - "composite": false, - "constraint": true, - "keyName": "primary", - "primary": true, - "unique": true - } - ], - "checks": [], - "triggers": [], - "foreignKeys": {}, - "comment": null - }, - { - "name": "core_role", - "columns": { - "color": { - "name": "color", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "created_at": { - "name": "created_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "id": { - "name": "id", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": true, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "name": { - "name": "name", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": true, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "permissions": { - "name": "permissions", - "type": "json", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": "'[]'", - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "json" - }, - "position": { - "name": "position", - "type": "integer", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "integer" - }, - "updated_at": { - "name": "updated_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - } - }, - "indexes": [ - { - "columnNames": [ - "name" - ], - "composite": false, - "constraint": true, - "keyName": "core_role_name_unique", - "primary": false, - "unique": true - }, - { - "columnNames": [ - "position" - ], - "composite": false, - "constraint": false, - "keyName": "core_role_position_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "id" - ], - "composite": false, - "constraint": true, - "keyName": "primary", - "primary": true, - "unique": true - } - ], - "checks": [], - "triggers": [], - "foreignKeys": {}, - "comment": null - }, - { - "name": "core_rsvp", - "columns": { - "auth_id": { - "name": "auth_id", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": true, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "cancelled_at": { - "name": "cancelled_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "cancelled_by_auth_id": { - "name": "cancelled_by_auth_id", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "confirmed_at": { - "name": "confirmed_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "created_at": { - "name": "created_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "promoted_at": { - "name": "promoted_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "promoted_by_auth_id": { - "name": "promoted_by_auth_id", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "status": { - "name": "status", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [ - "confirmed", - "waitlisted", - "cancelled" - ], - "mappedType": "enum" - }, - "updated_at": { - "name": "updated_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "waitlist_position": { - "name": "waitlist_position", - "type": "integer", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "integer" - }, - "waitlisted_at": { - "name": "waitlisted_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - } - }, - "indexes": [ - { - "columnNames": [ - "auth_id" - ], - "composite": false, - "constraint": false, - "keyName": "core_rsvp_auth_id_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "cancelled_by_auth_id" - ], - "composite": false, - "constraint": false, - "keyName": "core_rsvp_cancelled_by_auth_id_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "created_at" - ], - "composite": false, - "constraint": false, - "keyName": "core_rsvp_created_at_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "promoted_by_auth_id" - ], - "composite": false, - "constraint": false, - "keyName": "core_rsvp_promoted_by_auth_id_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "status" - ], - "composite": false, - "constraint": false, - "keyName": "core_rsvp_status_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "updated_at" - ], - "composite": false, - "constraint": false, - "keyName": "core_rsvp_updated_at_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "waitlist_position" - ], - "composite": false, - "constraint": false, - "keyName": "core_rsvp_waitlist_position_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "auth_id" - ], - "composite": false, - "constraint": true, - "keyName": "primary", - "primary": true, - "unique": true - } - ], - "checks": [ - { - "name": "core_rsvp_status_check", - "expression": "`status` in ('confirmed', 'waitlisted', 'cancelled')", - "definition": "check (`status` in ('confirmed', 'waitlisted', 'cancelled'))", - "columnName": "status" - } - ], - "triggers": [], - "foreignKeys": { - "core_rsvp_auth_id_foreign": { - "columnNames": [ - "auth_id" - ], - "constraintName": "core_rsvp_auth_id_foreign", - "localTableName": "core_rsvp", - "referencedColumnNames": [ - "id" - ], - "referencedTableName": "core_user", - "updateRule": "cascade", - "deleteRule": "cascade" - }, - "core_rsvp_cancelled_by_auth_id_foreign": { - "columnNames": [ - "cancelled_by_auth_id" - ], - "constraintName": "core_rsvp_cancelled_by_auth_id_foreign", - "localTableName": "core_rsvp", - "referencedColumnNames": [ - "id" - ], - "referencedTableName": "core_user", - "deleteRule": "set null" - }, - "core_rsvp_promoted_by_auth_id_foreign": { - "columnNames": [ - "promoted_by_auth_id" - ], - "constraintName": "core_rsvp_promoted_by_auth_id_foreign", - "localTableName": "core_rsvp", - "referencedColumnNames": [ - "id" - ], - "referencedTableName": "core_user", - "deleteRule": "set null" - } - }, - "comment": null - }, - { - "name": "core_setting", - "columns": { - "created_at": { - "name": "created_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "created_by_auth_id": { - "name": "created_by_auth_id", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "key": { - "name": "key", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": true, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "updated_at": { - "name": "updated_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "updated_by_auth_id": { - "name": "updated_by_auth_id", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "value": { - "name": "value", - "type": "json", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "json" - } - }, - "indexes": [ - { - "columnNames": [ - "created_by_auth_id" - ], - "composite": false, - "constraint": false, - "keyName": "core_setting_created_by_auth_id_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "updated_at" - ], - "composite": false, - "constraint": false, - "keyName": "core_setting_updated_at_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "updated_by_auth_id" - ], - "composite": false, - "constraint": false, - "keyName": "core_setting_updated_by_auth_id_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "key" - ], - "composite": false, - "constraint": true, - "keyName": "primary", - "primary": true, - "unique": true - } - ], - "checks": [], - "triggers": [], - "foreignKeys": { - "core_setting_created_by_auth_id_foreign": { - "columnNames": [ - "created_by_auth_id" - ], - "constraintName": "core_setting_created_by_auth_id_foreign", - "localTableName": "core_setting", - "referencedColumnNames": [ - "id" - ], - "referencedTableName": "core_user", - "deleteRule": "set null" - }, - "core_setting_updated_by_auth_id_foreign": { - "columnNames": [ - "updated_by_auth_id" - ], - "constraintName": "core_setting_updated_by_auth_id_foreign", - "localTableName": "core_setting", - "referencedColumnNames": [ - "id" - ], - "referencedTableName": "core_user", - "deleteRule": "set null" - } - }, - "comment": null - }, - { - "name": "core_user", - "columns": { - "bio": { - "name": "bio", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "checked_in_at": { - "name": "checked_in_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "created_at": { - "name": "created_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "discord_display_handle": { - "name": "discord_display_handle", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "email": { - "name": "email", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": true, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "email_verified": { - "name": "email_verified", - "type": "integer", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": "false", - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "integer" - }, - "hack_tag": { - "name": "hack_tag", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": true, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "id": { - "name": "id", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": true, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "is_approved": { - "name": "is_approved", - "type": "integer", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": "false", - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "integer" - }, - "is_profile_searchable": { - "name": "is_profile_searchable", - "type": "integer", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": "true", - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "integer" - }, - "name": { - "name": "name", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "profile_photo_url": { - "name": "profile_photo_url", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "pronouns": { - "name": "pronouns", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "role_id": { - "name": "role_id", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "skills": { - "name": "skills", - "type": "json", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": "'[]'", - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "json" - }, - "updated_at": { - "name": "updated_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - } - }, - "indexes": [ - { - "columnNames": [ - "created_at" - ], - "composite": false, - "constraint": false, - "keyName": "core_user_created_at_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "email" - ], - "composite": false, - "constraint": true, - "keyName": "core_user_email_unique", - "primary": false, - "unique": true - }, - { - "columnNames": [ - "hack_tag" - ], - "composite": false, - "constraint": false, - "keyName": "core_user_hack_tag_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "hack_tag" - ], - "composite": false, - "constraint": true, - "keyName": "core_user_hack_tag_unique", - "primary": false, - "unique": true - }, - { - "columnNames": [ - "role_id" - ], - "composite": false, - "constraint": false, - "keyName": "core_user_role_id_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "id" - ], - "composite": false, - "constraint": true, - "keyName": "primary", - "primary": true, - "unique": true - } - ], - "checks": [], - "triggers": [], - "foreignKeys": { - "core_user_role_id_foreign": { - "columnNames": [ - "role_id" - ], - "constraintName": "core_user_role_id_foreign", - "localTableName": "core_user", - "referencedColumnNames": [ - "id" - ], - "referencedTableName": "core_role", - "deleteRule": "set null" - } - }, - "comment": null - }, - { - "name": "core_user_ban", - "columns": { - "auth_id": { - "name": "auth_id", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": true, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "banned_by_auth_id": { - "name": "banned_by_auth_id", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "created_at": { - "name": "created_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "reason": { - "name": "reason", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - } - }, - "indexes": [ - { - "columnNames": [ - "auth_id" - ], - "composite": false, - "constraint": false, - "keyName": "core_user_ban_auth_id_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "banned_by_auth_id" - ], - "composite": false, - "constraint": false, - "keyName": "core_user_ban_banned_by_auth_id_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "auth_id" - ], - "composite": false, - "constraint": true, - "keyName": "primary", - "primary": true, - "unique": true - } - ], - "checks": [], - "triggers": [], - "foreignKeys": { - "core_user_ban_auth_id_foreign": { - "columnNames": [ - "auth_id" - ], - "constraintName": "core_user_ban_auth_id_foreign", - "localTableName": "core_user_ban", - "referencedColumnNames": [ - "id" - ], - "referencedTableName": "core_user", - "updateRule": "cascade", - "deleteRule": "cascade" - }, - "core_user_ban_banned_by_auth_id_foreign": { - "columnNames": [ - "banned_by_auth_id" - ], - "constraintName": "core_user_ban_banned_by_auth_id_foreign", - "localTableName": "core_user_ban", - "referencedColumnNames": [ - "id" - ], - "referencedTableName": "core_user" - } - }, - "comment": null - }, - { - "name": "core_user_data", - "columns": { - "accommodation_note": { - "name": "accommodation_note", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "age": { - "name": "age", - "type": "integer", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "integer" - }, - "auth_id": { - "name": "auth_id", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": true, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "completed_at": { - "name": "completed_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "country_of_residence": { - "name": "country_of_residence", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "dietary_restrictions": { - "name": "dietary_restrictions", - "type": "json", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": "'[]'", - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "json" - }, - "ethnicity": { - "name": "ethnicity", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "gender": { - "name": "gender", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "has_accepted_mlhcode_of_conduct": { - "name": "has_accepted_mlhcode_of_conduct", - "type": "integer", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "integer" - }, - "has_shared_data_with_mlh": { - "name": "has_shared_data_with_mlh", - "type": "integer", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "integer" - }, - "is_emailable": { - "name": "is_emailable", - "type": "integer", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "integer" - }, - "phone_number": { - "name": "phone_number", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "race": { - "name": "race", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "shirt_size": { - "name": "shirt_size", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "updated_at": { - "name": "updated_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - } - }, - "indexes": [ - { - "columnNames": [ - "auth_id" - ], - "composite": false, - "constraint": false, - "keyName": "core_user_data_auth_id_index", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "auth_id" - ], - "composite": false, - "constraint": true, - "keyName": "primary", - "primary": true, - "unique": true - } - ], - "checks": [], - "triggers": [], - "foreignKeys": { - "core_user_data_auth_id_foreign": { - "columnNames": [ - "auth_id" - ], - "constraintName": "core_user_data_auth_id_foreign", - "localTableName": "core_user_data", - "referencedColumnNames": [ - "id" - ], - "referencedTableName": "core_user", - "updateRule": "cascade", - "deleteRule": "cascade" - } - }, - "comment": null - }, - { - "name": "session", - "columns": { - "created_at": { - "name": "created_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "expires_at": { - "name": "expires_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "id": { - "name": "id", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": true, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "ip_address": { - "name": "ip_address", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "token": { - "name": "token", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": true, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "updated_at": { - "name": "updated_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "user_agent": { - "name": "user_agent", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "user_id": { - "name": "user_id", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - } - }, - "indexes": [ - { - "columnNames": [ - "id" - ], - "composite": false, - "constraint": true, - "keyName": "primary", - "primary": true, - "unique": true - }, - { - "columnNames": [ - "token" - ], - "composite": false, - "constraint": true, - "keyName": "session_token_unique", - "primary": false, - "unique": true - }, - { - "columnNames": [ - "user_id" - ], - "composite": false, - "constraint": false, - "keyName": "session_user_id_index", - "primary": false, - "unique": false - } - ], - "checks": [], - "triggers": [], - "foreignKeys": { - "session_user_id_foreign": { - "columnNames": [ - "user_id" - ], - "constraintName": "session_user_id_foreign", - "localTableName": "session", - "referencedColumnNames": [ - "id" - ], - "referencedTableName": "core_user", - "deleteRule": "cascade" - } - }, - "comment": null - }, - { - "name": "verification", - "columns": { - "created_at": { - "name": "created_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "expires_at": { - "name": "expires_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "id": { - "name": "id", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": true, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "identifier": { - "name": "identifier", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - }, - "updated_at": { - "name": "updated_at", - "type": "datetime", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "datetime" - }, - "value": { - "name": "value", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "unique": false, - "length": null, - "precision": null, - "scale": null, - "default": null, - "comment": null, - "collation": null, - "enumItems": [], - "mappedType": "text" - } - }, - "indexes": [ - { - "columnNames": [ - "id" - ], - "composite": false, - "constraint": true, - "keyName": "primary", - "primary": true, - "unique": true - }, - { - "columnNames": [ - "identifier" - ], - "composite": false, - "constraint": false, - "keyName": "verification_identifier_index", - "primary": false, - "unique": false - } - ], - "checks": [], - "triggers": [], - "foreignKeys": {}, - "comment": null - } - ], - "views": [], - "nativeEnums": {} -} \ No newline at end of file diff --git a/templates/nextjs-minimal/db/migrations/sqlite/Migration20261020200349_initial.ts b/templates/nextjs-minimal/db/migrations/sqlite/Migration20261020200349_initial.ts deleted file mode 100644 index cacf644bf..000000000 --- a/templates/nextjs-minimal/db/migrations/sqlite/Migration20261020200349_initial.ts +++ /dev/null @@ -1,101 +0,0 @@ -import { Migration } from '@mikro-orm/migrations'; - -export class Migration20261020200349_initial extends Migration { - - override name = 'Migration20261020200349_initial'; - - override up(): void | Promise { - this.addSql(`create table \`verification\` (\`id\` text not null primary key, \`identifier\` text not null, \`value\` text not null, \`expires_at\` datetime not null, \`created_at\` datetime null, \`updated_at\` datetime null);`); - this.addSql(`create index \`verification_identifier_index\` on \`verification\` (\`identifier\`);`); - - this.addSql(`create table \`core_event\` (\`id\` text not null primary key, \`title\` text not null, \`start_time\` datetime not null, \`end_time\` datetime not null, \`location\` text not null default 'TBD', \`description\` text not null, \`type\` text not null, \`host\` text null, \`hidden\` integer not null default false, \`created_at\` datetime not null, \`updated_at\` datetime not null);`); - this.addSql(`create index \`core_event_start_time_index\` on \`core_event\` (\`start_time\`);`); - this.addSql(`create index \`core_event_type_index\` on \`core_event\` (\`type\`);`); - this.addSql(`create index \`core_event_hidden_index\` on \`core_event\` (\`hidden\`);`); - - this.addSql(`create table \`core_operation_lock\` (\`key\` text not null primary key, \`token\` text not null);`); - - this.addSql(`create table \`core_role\` (\`id\` text not null primary key, \`name\` text not null, \`position\` integer not null, \`permissions\` json not null default '[]', \`color\` text null, \`created_at\` datetime not null, \`updated_at\` datetime not null);`); - this.addSql(`create unique index \`core_role_name_unique\` on \`core_role\` (\`name\`);`); - this.addSql(`create index \`core_role_position_index\` on \`core_role\` (\`position\`);`); - - this.addSql(`create table \`core_user\` (\`id\` text not null primary key, \`name\` text not null, \`email\` text not null, \`email_verified\` integer not null default false, \`profile_photo_url\` text null, \`hack_tag\` text null, \`bio\` text null, \`pronouns\` text null, \`skills\` json not null default '[]', \`is_profile_searchable\` integer not null default true, \`discord_display_handle\` text null, \`role_id\` text null, \`is_approved\` integer not null default false, \`checked_in_at\` datetime null, \`created_at\` datetime not null, \`updated_at\` datetime not null, constraint \`core_user_role_id_foreign\` foreign key (\`role_id\`) references \`core_role\` (\`id\`) on delete set null);`); - this.addSql(`create unique index \`core_user_email_unique\` on \`core_user\` (\`email\`);`); - this.addSql(`create unique index \`core_user_hack_tag_unique\` on \`core_user\` (\`hack_tag\`);`); - this.addSql(`create index \`core_user_hack_tag_index\` on \`core_user\` (\`hack_tag\`);`); - this.addSql(`create index \`core_user_role_id_index\` on \`core_user\` (\`role_id\`);`); - this.addSql(`create index \`core_user_created_at_index\` on \`core_user\` (\`created_at\`);`); - - this.addSql(`create table \`core_user_data\` (\`auth_id\` text not null primary key, \`age\` integer not null, \`gender\` text not null, \`race\` text not null, \`ethnicity\` text not null, \`shirt_size\` text not null, \`dietary_restrictions\` json not null default '[]', \`accommodation_note\` text null, \`phone_number\` text null, \`country_of_residence\` text null, \`has_accepted_mlhcode_of_conduct\` integer not null, \`has_shared_data_with_mlh\` integer not null, \`is_emailable\` integer not null, \`completed_at\` datetime not null, \`updated_at\` datetime not null, constraint \`core_user_data_auth_id_foreign\` foreign key (\`auth_id\`) references \`core_user\` (\`id\`) on update cascade on delete cascade);`); - this.addSql(`create index \`core_user_data_auth_id_index\` on \`core_user_data\` (\`auth_id\`);`); - - this.addSql(`create table \`core_user_ban\` (\`auth_id\` text not null primary key, \`reason\` text null, \`banned_by_auth_id\` text not null, \`created_at\` datetime not null, constraint \`core_user_ban_auth_id_foreign\` foreign key (\`auth_id\`) references \`core_user\` (\`id\`) on update cascade on delete cascade, constraint \`core_user_ban_banned_by_auth_id_foreign\` foreign key (\`banned_by_auth_id\`) references \`core_user\` (\`id\`));`); - this.addSql(`create index \`core_user_ban_auth_id_index\` on \`core_user_ban\` (\`auth_id\`);`); - this.addSql(`create index \`core_user_ban_banned_by_auth_id_index\` on \`core_user_ban\` (\`banned_by_auth_id\`);`); - - this.addSql(`create table \`core_setting\` (\`key\` text not null primary key, \`value\` json not null, \`created_at\` datetime not null, \`created_by_auth_id\` text null, \`updated_at\` datetime not null, \`updated_by_auth_id\` text null, constraint \`core_setting_created_by_auth_id_foreign\` foreign key (\`created_by_auth_id\`) references \`core_user\` (\`id\`) on delete set null, constraint \`core_setting_updated_by_auth_id_foreign\` foreign key (\`updated_by_auth_id\`) references \`core_user\` (\`id\`) on delete set null);`); - this.addSql(`create index \`core_setting_created_by_auth_id_index\` on \`core_setting\` (\`created_by_auth_id\`);`); - this.addSql(`create index \`core_setting_updated_at_index\` on \`core_setting\` (\`updated_at\`);`); - this.addSql(`create index \`core_setting_updated_by_auth_id_index\` on \`core_setting\` (\`updated_by_auth_id\`);`); - - this.addSql(`create table \`core_rsvp\` (\`auth_id\` text not null primary key, \`status\` text check (\`status\` in ('confirmed', 'waitlisted', 'cancelled')) not null, \`waitlist_position\` integer null, \`created_at\` datetime not null, \`updated_at\` datetime not null, \`confirmed_at\` datetime null, \`waitlisted_at\` datetime null, \`cancelled_at\` datetime null, \`cancelled_by_auth_id\` text null, \`promoted_at\` datetime null, \`promoted_by_auth_id\` text null, constraint \`core_rsvp_auth_id_foreign\` foreign key (\`auth_id\`) references \`core_user\` (\`id\`) on update cascade on delete cascade, constraint \`core_rsvp_cancelled_by_auth_id_foreign\` foreign key (\`cancelled_by_auth_id\`) references \`core_user\` (\`id\`) on delete set null, constraint \`core_rsvp_promoted_by_auth_id_foreign\` foreign key (\`promoted_by_auth_id\`) references \`core_user\` (\`id\`) on delete set null);`); - this.addSql(`create index \`core_rsvp_auth_id_index\` on \`core_rsvp\` (\`auth_id\`);`); - this.addSql(`create index \`core_rsvp_cancelled_by_auth_id_index\` on \`core_rsvp\` (\`cancelled_by_auth_id\`);`); - this.addSql(`create index \`core_rsvp_promoted_by_auth_id_index\` on \`core_rsvp\` (\`promoted_by_auth_id\`);`); - this.addSql(`create index \`core_rsvp_status_index\` on \`core_rsvp\` (\`status\`);`); - this.addSql(`create index \`core_rsvp_waitlist_position_index\` on \`core_rsvp\` (\`waitlist_position\`);`); - this.addSql(`create index \`core_rsvp_created_at_index\` on \`core_rsvp\` (\`created_at\`);`); - this.addSql(`create index \`core_rsvp_updated_at_index\` on \`core_rsvp\` (\`updated_at\`);`); - - this.addSql(`create table \`core_notification_intent\` (\`id\` text not null primary key, \`kind\` text not null, \`recipient_auth_id\` text null, \`payload\` json not null, \`status\` text check (\`status\` in ('pending', 'processing', 'delivered', 'failed', 'skipped')) not null default 'pending', \`idempotency_key\` text null, \`created_at\` datetime not null, \`updated_at\` datetime not null, constraint \`core_notification_intent_recipient_auth_id_foreign\` foreign key (\`recipient_auth_id\`) references \`core_user\` (\`id\`) on delete set null);`); - this.addSql(`create unique index \`core_notification_intent_idempotency_key_unique\` on \`core_notification_intent\` (\`idempotency_key\`);`); - this.addSql(`create index \`core_notification_intent_kind_index\` on \`core_notification_intent\` (\`kind\`);`); - this.addSql(`create index \`core_notification_intent_recipient_auth_id_index\` on \`core_notification_intent\` (\`recipient_auth_id\`);`); - this.addSql(`create index \`core_notification_intent_status_index\` on \`core_notification_intent\` (\`status\`);`); - this.addSql(`create index \`core_notification_intent_created_at_index\` on \`core_notification_intent\` (\`created_at\`);`); - - this.addSql(`create table \`core_notification_delivery_attempt\` (\`id\` text not null primary key, \`intent_id\` text not null, \`channel\` text not null, \`provider\` text null, \`status\` text check (\`status\` in ('delivered', 'failed', 'skipped')) not null, \`recipient\` text null, \`external_id\` text null, \`error\` text null, \`metadata\` json not null, \`attempted_at\` datetime not null, constraint \`core_notification_delivery_attempt_intent_id_foreign\` foreign key (\`intent_id\`) references \`core_notification_intent\` (\`id\`) on delete cascade);`); - this.addSql(`create index \`core_notification_delivery_attempt_intent_id_index\` on \`core_notification_delivery_attempt\` (\`intent_id\`);`); - this.addSql(`create index \`core_notification_delivery_attempt_channel_index\` on \`core_notification_delivery_attempt\` (\`channel\`);`); - this.addSql(`create index \`core_notification_delivery_attempt_status_index\` on \`core_notification_delivery_attempt\` (\`status\`);`); - this.addSql(`create index \`core_notification_delivery_attempt_attempted_at_index\` on \`core_notification_delivery_attempt\` (\`attempted_at\`);`); - - this.addSql(`create table \`core_hacker\` (\`auth_id\` text not null primary key, \`university\` text not null, \`major\` text not null, \`school_id\` text null, \`level_of_study\` text not null, \`hackathons_attended\` integer not null, \`software_experience\` text not null, \`heard_from\` text null, \`github_url\` text null, \`linked_in_url\` text null, \`personal_website_url\` text null, \`resume_url\` text null, \`group\` text null, \`registered_at\` datetime not null, \`updated_at\` datetime not null, constraint \`core_hacker_auth_id_foreign\` foreign key (\`auth_id\`) references \`core_user\` (\`id\`) on update cascade on delete cascade);`); - this.addSql(`create index \`core_hacker_auth_id_index\` on \`core_hacker\` (\`auth_id\`);`); - this.addSql(`create index \`core_hacker_registered_at_index\` on \`core_hacker\` (\`registered_at\`);`); - - this.addSql(`create table \`core_event_scan\` (\`id\` text not null primary key, \`event_id\` text not null, \`auth_id\` text not null, \`scanned_by_auth_id\` text not null, \`scanned_at\` datetime not null, constraint \`core_event_scan_event_id_foreign\` foreign key (\`event_id\`) references \`core_event\` (\`id\`) on delete cascade, constraint \`core_event_scan_auth_id_foreign\` foreign key (\`auth_id\`) references \`core_user\` (\`id\`) on delete cascade, constraint \`core_event_scan_scanned_by_auth_id_foreign\` foreign key (\`scanned_by_auth_id\`) references \`core_user\` (\`id\`));`); - this.addSql(`create index \`core_event_scan_scanned_by_auth_id_index\` on \`core_event_scan\` (\`scanned_by_auth_id\`);`); - this.addSql(`create index \`core_event_scan_event_id_index\` on \`core_event_scan\` (\`event_id\`);`); - this.addSql(`create index \`core_event_scan_auth_id_index\` on \`core_event_scan\` (\`auth_id\`);`); - this.addSql(`create index \`core_event_scan_event_id_auth_id_index\` on \`core_event_scan\` (\`event_id\`, \`auth_id\`);`); - this.addSql(`create index \`core_event_scan_scanned_at_index\` on \`core_event_scan\` (\`scanned_at\`);`); - - this.addSql(`create table \`session\` (\`id\` text not null primary key, \`expires_at\` datetime not null, \`token\` text not null, \`created_at\` datetime not null, \`updated_at\` datetime not null, \`ip_address\` text null, \`user_agent\` text null, \`user_id\` text not null, constraint \`session_user_id_foreign\` foreign key (\`user_id\`) references \`core_user\` (\`id\`) on delete cascade);`); - this.addSql(`create unique index \`session_token_unique\` on \`session\` (\`token\`);`); - this.addSql(`create index \`session_user_id_index\` on \`session\` (\`user_id\`);`); - - this.addSql(`create table \`account\` (\`id\` text not null primary key, \`account_id\` text not null, \`provider_id\` text not null, \`user_id\` text not null, \`access_token\` text null, \`refresh_token\` text null, \`id_token\` text null, \`access_token_expires_at\` datetime null, \`refresh_token_expires_at\` datetime null, \`scope\` text null, \`password\` text null, \`created_at\` datetime not null, \`updated_at\` datetime not null, constraint \`account_user_id_foreign\` foreign key (\`user_id\`) references \`core_user\` (\`id\`) on delete cascade);`); - this.addSql(`create index \`account_user_id_index\` on \`account\` (\`user_id\`);`); - } - - override down(): void | Promise { - - this.addSql(`drop table if exists \`verification\`;`); - this.addSql(`drop table if exists \`core_event\`;`); - this.addSql(`drop table if exists \`core_operation_lock\`;`); - this.addSql(`drop table if exists \`core_role\`;`); - this.addSql(`drop table if exists \`core_user\`;`); - this.addSql(`drop table if exists \`core_user_data\`;`); - this.addSql(`drop table if exists \`core_user_ban\`;`); - this.addSql(`drop table if exists \`core_setting\`;`); - this.addSql(`drop table if exists \`core_rsvp\`;`); - this.addSql(`drop table if exists \`core_notification_intent\`;`); - this.addSql(`drop table if exists \`core_notification_delivery_attempt\`;`); - this.addSql(`drop table if exists \`core_hacker\`;`); - this.addSql(`drop table if exists \`core_event_scan\`;`); - this.addSql(`drop table if exists \`session\`;`); - this.addSql(`drop table if exists \`account\`;`); - } - -} diff --git a/templates/nextjs-minimal/env.ts b/templates/nextjs-minimal/env.ts index 3811d9ef0..4b0a303d9 100644 --- a/templates/nextjs-minimal/env.ts +++ b/templates/nextjs-minimal/env.ts @@ -42,6 +42,7 @@ export function resolveTemplateEnv() { .map((value) => value.trim()) .filter(Boolean) ?? [], databaseUrl, + migrationsPath: read("HACKKIT_MIGRATIONS_PATH"), localBlobBaseDir: read("HACKKIT_LOCAL_BLOB_BASE_DIR") ?? ".data/uploads", }; diff --git a/templates/nextjs-minimal/lib/database-config.ts b/templates/nextjs-minimal/lib/database-config.ts index 9f94a44c9..67b5d4f77 100644 --- a/templates/nextjs-minimal/lib/database-config.ts +++ b/templates/nextjs-minimal/lib/database-config.ts @@ -10,7 +10,7 @@ export const databaseOptions = { ? ":memory:" : resolve(env.databaseUrl.replace(/^file:/, "")), migrations: { - path: resolve("db/migrations/sqlite"), + path: resolve(env.migrationsPath ?? "db/migrations/sqlite"), emit: "ts" as const, snapshot: true, snapshotName: ".snapshot", diff --git a/turbo.json b/turbo.json index e7e1fc478..d4dfbfaab 100644 --- a/turbo.json +++ b/turbo.json @@ -42,6 +42,7 @@ "HACKKIT_EMAIL_PROVIDER", "HACKKIT_EMAIL_REPLY_TO", "HACKKIT_LOCAL_BLOB_BASE_DIR", + "HACKKIT_MIGRATIONS_PATH", "HACKKIT_S3_ACCESS_KEY_ID", "HACKKIT_S3_BUCKET", "HACKKIT_S3_ENDPOINT", From c6d02533104d58dffe0223790c089195e60b96be Mon Sep 17 00:00:00 2001 From: joshuasilva414 Date: Wed, 28 Oct 2026 12:30:33 -0500 Subject: [PATCH 3/5] pnpm format --- .agents/skills/ask-matt/SKILL.md | 26 +- .agents/skills/code-review/SKILL.md | 48 ++-- .agents/skills/codebase-design/DEEPENING.md | 12 +- .../skills/codebase-design/DESIGN-IT-TWICE.md | 14 +- .agents/skills/codebase-design/SKILL.md | 34 +-- .agents/skills/diagnosing-bugs/SKILL.md | 30 +-- .agents/skills/domain-modeling/ADR-FORMAT.md | 20 +- .../skills/domain-modeling/CONTEXT-FORMAT.md | 26 +- .../HTML-REPORT.md | 37 ++- .../improve-codebase-architecture/SKILL.md | 38 +-- .agents/skills/prototype/LOGIC.md | 26 +- .agents/skills/prototype/SKILL.md | 4 +- .agents/skills/prototype/UI.md | 40 +-- .../skills/setup-matt-pocock-skills/SKILL.md | 50 ++-- .../skills/setup-matt-pocock-skills/domain.md | 6 +- .../issue-tracker-github.md | 30 +-- .../issue-tracker-gitlab.md | 32 +-- .../issue-tracker-local.md | 22 +- .agents/skills/tdd/SKILL.md | 12 +- .agents/skills/tdd/mocking.md | 22 +- .agents/skills/tdd/tests.md | 22 +- .agents/skills/teach/GLOSSARY-FORMAT.md | 14 +- .../skills/teach/LEARNING-RECORD-FORMAT.md | 12 +- .agents/skills/teach/MISSION-FORMAT.md | 20 +- .agents/skills/teach/RESOURCES-FORMAT.md | 28 +- .agents/skills/teach/SKILL.md | 50 ++-- .agents/skills/to-spec/SKILL.md | 20 +- .agents/skills/to-tickets/SKILL.md | 34 +-- .agents/skills/triage/AGENT-BRIEF.md | 122 ++++----- .agents/skills/triage/OUT-OF-SCOPE.md | 12 +- .agents/skills/triage/SKILL.md | 34 +-- .agents/skills/wayfinder/SKILL.md | 14 +- .../skills/writing-great-skills/GLOSSARY.md | 6 +- .agents/skills/writing-great-skills/SKILL.md | 30 +-- CONTEXT.md | 244 +++++++++--------- apps/demo/README.md | 6 +- apps/demo/app/app-bar.tsx | 5 +- apps/docs/README.md | 8 +- contributions.md | 10 +- docs/adr/0007-event-pass-qr-in-hackkit-ui.md | 14 +- docs/adr/0010-hackkit-logger.md | 34 +-- ...blob-storage-and-stored-file-references.md | 34 +-- docs/guides/package-schema-upgrades.md | 18 +- idea.md | 10 +- packages/core/src/notifications.ts | 3 +- packages/core/src/settings.ts | 7 +- packages/plugin-discord/src/api.ts | 2 +- packages/ui/src/components/ui/button.tsx | 3 +- packages/ui/src/lib/onboarding-steps.ts | 5 +- templates/nextjs-full/app/app-bar.tsx | 5 +- templates/nextjs-minimal/app/app-bar.tsx | 5 +- 51 files changed, 674 insertions(+), 686 deletions(-) diff --git a/.agents/skills/ask-matt/SKILL.md b/.agents/skills/ask-matt/SKILL.md index 793caca7c..df014dc36 100644 --- a/.agents/skills/ask-matt/SKILL.md +++ b/.agents/skills/ask-matt/SKILL.md @@ -36,13 +36,13 @@ The limit on this is the **[smart zone](https://www.aihero.dev/ai-coding-diction A starting situation that generates work, then merges onto the main flow. -- **Bugs and requests piling up** → **`/triage`**. It moves issues through triage roles and produces agent-ready issues, which **`/implement`** later picks up. +- **Bugs and requests piling up** → **`/triage`**. It moves issues through triage roles and produces agent-ready issues, which **`/implement`** later picks up. Triage is only for issues **you didn't create** — bug reports, incoming feature requests, anything that arrives raw. Tickets that `/to-tickets` produced are already agent-ready, so **don't triage them**. -- **Something's broken** → **`/diagnosing-bugs`**. For the hard ones: the bug that resists a first glance, the intermittent flake, the regression that crept in between two known-good states. It refuses to theorise until it has a **tight feedback loop** — one command that already goes red on _this_ bug — then fixes with a regression test. Its post-mortem hands off to **`/improve-codebase-architecture`** when the real finding is that there's no good seam to lock the bug down. +- **Something's broken** → **`/diagnosing-bugs`**. For the hard ones: the bug that resists a first glance, the intermittent flake, the regression that crept in between two known-good states. It refuses to theorise until it has a **tight feedback loop** — one command that already goes red on _this_ bug — then fixes with a regression test. Its post-mortem hands off to **`/improve-codebase-architecture`** when the real finding is that there's no good seam to lock the bug down. -- **A huge, foggy effort — a greenfield project or a huge feature build, too big for one session** → **`/wayfinder`**, the most cognitively demanding flow here. When the way from here to the destination isn't visible yet, it charts a **shared map** of **decision tickets** on the issue tracker and resolves them one at a time — producing **decisions, not deliverables** — until the fog is pushed back and the way is clear. Where **`/grill-with-docs`** sharpens an idea you can hold in one session, wayfinder is for the idea you can't — and it's slower and denser, so save it for exactly that, never a well-scoped feature. +- **A huge, foggy effort — a greenfield project or a huge feature build, too big for one session** → **`/wayfinder`**, the most cognitively demanding flow here. When the way from here to the destination isn't visible yet, it charts a **shared map** of **decision tickets** on the issue tracker and resolves them one at a time — producing **decisions, not deliverables** — until the fog is pushed back and the way is clear. Where **`/grill-with-docs`** sharpens an idea you can hold in one session, wayfinder is for the idea you can't — and it's slower and denser, so save it for exactly that, never a well-scoped feature. When the map clears, **it hands off, it doesn't build**: merge onto the main flow at **`/to-spec`**, which collapses the map's linked decisions into a buildable plan, then `/to-tickets` and `/implement` as usual. Looping the map straight into `/implement` skips that collapse and throws the linked detail away — go straight to `/implement` only when the effort turned out genuinely small. @@ -50,29 +50,29 @@ A starting situation that generates work, then merges onto the main flow. Not feature work — upkeep. -- **`/improve-codebase-architecture`** — run whenever you have a spare moment to keep the codebase good for agents to operate in. It surfaces **deepening opportunities**; picking one _generates an idea_ you can take into the main flow at `/grill-with-docs`. It's the survey that finds the candidates; **`/codebase-design`** (below) is the bench you design the chosen one on. +- **`/improve-codebase-architecture`** — run whenever you have a spare moment to keep the codebase good for agents to operate in. It surfaces **deepening opportunities**; picking one _generates an idea_ you can take into the main flow at `/grill-with-docs`. It's the survey that finds the candidates; **`/codebase-design`** (below) is the bench you design the chosen one on. ## Vocabulary underneath Two model-invoked references that run _beneath_ the other skills — each the single source of truth for its vocabulary. Reach for them directly when the **words**, not the process, are the problem; or let the skills above pull them in. -- **`/domain-modeling`** — sharpen the project's _domain_ language: challenge a fuzzy term, resolve an overloaded word ("account" doing three jobs), record a hard-to-reverse decision as an ADR. It's the active discipline `/grill-with-docs` drives to keep `CONTEXT.md` a clean glossary. -- **`/codebase-design`** — the deep-module vocabulary (module, interface, depth, seam, adapter, leverage, locality) for designing a module's _shape_: a lot of behaviour behind a small interface at a clean seam. `/tdd` and `/improve-codebase-architecture` both speak it. +- **`/domain-modeling`** — sharpen the project's _domain_ language: challenge a fuzzy term, resolve an overloaded word ("account" doing three jobs), record a hard-to-reverse decision as an ADR. It's the active discipline `/grill-with-docs` drives to keep `CONTEXT.md` a clean glossary. +- **`/codebase-design`** — the deep-module vocabulary (module, interface, depth, seam, adapter, leverage, locality) for designing a module's _shape_: a lot of behaviour behind a small interface at a clean seam. `/tdd` and `/improve-codebase-architecture` both speak it. ## Crossing sessions -- **`/handoff`** — when a thread is full or you need to branch off (e.g. into a `/prototype` session), this compacts the conversation into a markdown file. You don't continue in place — you **open a new session and reference that file** to carry the context across. It's the bridge between context windows, in either direction. Use it when you want a **fresh session** but need the **current conversation preserved**. -- **`/compact`** (built-in) — stay in the **same conversation**, letting the earlier turns be summarized. Use it at **intentional breaks between phases**, when you don't mind losing the verbatim history. Don't compact mid-phase — the agent can lose its way. `/handoff` forks; `/compact` continues. +- **`/handoff`** — when a thread is full or you need to branch off (e.g. into a `/prototype` session), this compacts the conversation into a markdown file. You don't continue in place — you **open a new session and reference that file** to carry the context across. It's the bridge between context windows, in either direction. Use it when you want a **fresh session** but need the **current conversation preserved**. +- **`/compact`** (built-in) — stay in the **same conversation**, letting the earlier turns be summarized. Use it at **intentional breaks between phases**, when you don't mind losing the verbatim history. Don't compact mid-phase — the agent can lose its way. `/handoff` forks; `/compact` continues. ## Standalone Off the main flow entirely. -- **`/grill-me`** — the same relentless interview as `/grill-with-docs`, but for when you have **no codebase**. Stateless: it saves nothing locally, builds no `CONTEXT.md`. Reach for it to sharpen any plan or design that doesn't live in a repo. -- **`/prototype`** — a small, throwaway program that answers one design question: does this state model feel right, or what should this UI look like. Throwaway from day one — keep the answer, delete the code. It's the detour in step 2 of the main flow, but reach for it any time a design question is hard to settle on paper. -- **`/research`** — delegate reading legwork to a **background agent**: it investigates a question against **primary sources**, then leaves a cited Markdown file in the repo. Keep working while it reads. The file it produces is something to take _into_ the main flow at `/grill-with-docs` — research feeds the thinking, it doesn't replace it. -- **`/teach`** — learn a concept over multiple sessions, using the current directory as a stateful workspace. -- **`/writing-great-skills`** — reference for writing and editing skills well. +- **`/grill-me`** — the same relentless interview as `/grill-with-docs`, but for when you have **no codebase**. Stateless: it saves nothing locally, builds no `CONTEXT.md`. Reach for it to sharpen any plan or design that doesn't live in a repo. +- **`/prototype`** — a small, throwaway program that answers one design question: does this state model feel right, or what should this UI look like. Throwaway from day one — keep the answer, delete the code. It's the detour in step 2 of the main flow, but reach for it any time a design question is hard to settle on paper. +- **`/research`** — delegate reading legwork to a **background agent**: it investigates a question against **primary sources**, then leaves a cited Markdown file in the repo. Keep working while it reads. The file it produces is something to take _into_ the main flow at `/grill-with-docs` — research feeds the thinking, it doesn't replace it. +- **`/teach`** — learn a concept over multiple sessions, using the current directory as a stateful workspace. +- **`/writing-great-skills`** — reference for writing and editing skills well. ## Precondition diff --git a/.agents/skills/code-review/SKILL.md b/.agents/skills/code-review/SKILL.md index eaf823678..fe4fefb44 100644 --- a/.agents/skills/code-review/SKILL.md +++ b/.agents/skills/code-review/SKILL.md @@ -5,8 +5,8 @@ description: Review the changes since a fixed point (commit, branch, tag, or mer Two-axis review of the diff between `HEAD` and a fixed point the user supplies: -- **Standards** — does the code conform to this repo's documented coding standards? -- **Spec** — does the code faithfully implement the originating issue / PRD / spec? +- **Standards** — does the code conform to this repo's documented coding standards? +- **Spec** — does the code faithfully implement the originating issue / PRD / spec? Both axes run as **parallel sub-agents** so they don't pollute each other's context, then this skill aggregates their findings. @@ -37,23 +37,23 @@ Anything in the repo that documents how code should be written, such as `CODING_ On top of whatever the repo documents, the Standards axis always carries the **smell baseline** below — a fixed set of Fowler code smells (_Refactoring_, ch.3) that applies even when a repo documents nothing. Two rules bind it: -- **The repo overrides.** A documented repo standard always wins; where it endorses something the baseline would flag, suppress the smell. -- **Always a judgement call.** Each smell is a labelled heuristic ("possible Feature Envy"), never a hard violation — and, like any standard here, skip anything tooling already enforces. +- **The repo overrides.** A documented repo standard always wins; where it endorses something the baseline would flag, suppress the smell. +- **Always a judgement call.** Each smell is a labelled heuristic ("possible Feature Envy"), never a hard violation — and, like any standard here, skip anything tooling already enforces. Each smell reads _what it is_ → _how to fix_; match it against the diff: -- **Mysterious Name** — a function, variable, or type whose name doesn't reveal what it does or holds. → rename it; if no honest name comes, the design's murky. -- **Duplicated Code** — the same logic shape appears in more than one hunk or file in the change. → extract the shared shape, call it from both. -- **Feature Envy** — a method that reaches into another object's data more than its own. → move the method onto the data it envies. -- **Data Clumps** — the same few fields or params keep travelling together (a type wanting to be born). → bundle them into one type, pass that. -- **Primitive Obsession** — a primitive or string standing in for a domain concept that deserves its own type. → give the concept its own small type. -- **Repeated Switches** — the same `switch`/`if`-cascade on the same type recurs across the change. → replace with polymorphism, or one map both sites share. -- **Shotgun Surgery** — one logical change forces scattered edits across many files in the diff. → gather what changes together into one module. -- **Divergent Change** — one file or module is edited for several unrelated reasons. → split so each module changes for one reason. -- **Speculative Generality** — abstraction, parameters, or hooks added for needs the spec doesn't have. → delete it; inline back until a real need shows. -- **Message Chains** — long `a.b().c().d()` navigation the caller shouldn't depend on. → hide the walk behind one method on the first object. -- **Middle Man** — a class or function that mostly just delegates onward. → cut it, call the real target direct. -- **Refused Bequest** — a subclass or implementer that ignores or overrides most of what it inherits. → drop the inheritance, use composition. +- **Mysterious Name** — a function, variable, or type whose name doesn't reveal what it does or holds. → rename it; if no honest name comes, the design's murky. +- **Duplicated Code** — the same logic shape appears in more than one hunk or file in the change. → extract the shared shape, call it from both. +- **Feature Envy** — a method that reaches into another object's data more than its own. → move the method onto the data it envies. +- **Data Clumps** — the same few fields or params keep travelling together (a type wanting to be born). → bundle them into one type, pass that. +- **Primitive Obsession** — a primitive or string standing in for a domain concept that deserves its own type. → give the concept its own small type. +- **Repeated Switches** — the same `switch`/`if`-cascade on the same type recurs across the change. → replace with polymorphism, or one map both sites share. +- **Shotgun Surgery** — one logical change forces scattered edits across many files in the diff. → gather what changes together into one module. +- **Divergent Change** — one file or module is edited for several unrelated reasons. → split so each module changes for one reason. +- **Speculative Generality** — abstraction, parameters, or hooks added for needs the spec doesn't have. → delete it; inline back until a real need shows. +- **Message Chains** — long `a.b().c().d()` navigation the caller shouldn't depend on. → hide the walk behind one method on the first object. +- **Middle Man** — a class or function that mostly just delegates onward. → cut it, call the real target direct. +- **Refused Bequest** — a subclass or implementer that ignores or overrides most of what it inherits. → drop the inheritance, use composition. ### 4. Spawn both sub-agents in parallel @@ -61,15 +61,15 @@ Send a single message with two `Agent` tool calls. Use the `general-purpose` sub **Standards sub-agent prompt** — include: -- The full diff command and commit list. -- The list of standards-source files you found in step 3, **plus the smell baseline from step 3** pasted in full — the sub-agent has no other access to it. -- The brief: "Report — per file/hunk where relevant — (a) every place the diff violates a documented standard: cite the standard (file + the rule); and (b) any baseline smell you spot: name it and quote the hunk. Distinguish hard violations from judgement calls — documented-standard breaches can be hard, but baseline smells are always judgement calls, and a documented repo standard overrides the baseline. Skip anything tooling enforces. Under 400 words." +- The full diff command and commit list. +- The list of standards-source files you found in step 3, **plus the smell baseline from step 3** pasted in full — the sub-agent has no other access to it. +- The brief: "Report — per file/hunk where relevant — (a) every place the diff violates a documented standard: cite the standard (file + the rule); and (b) any baseline smell you spot: name it and quote the hunk. Distinguish hard violations from judgement calls — documented-standard breaches can be hard, but baseline smells are always judgement calls, and a documented repo standard overrides the baseline. Skip anything tooling enforces. Under 400 words." **Spec sub-agent prompt** — include: -- The diff command and commit list. -- The path or fetched contents of the spec. -- The brief: "Report: (a) requirements the spec asked for that are missing or partial; (b) behaviour in the diff that wasn't asked for (scope creep); (c) requirements that look implemented but where the implementation looks wrong. Quote the spec line for each finding. Under 400 words." +- The diff command and commit list. +- The path or fetched contents of the spec. +- The brief: "Report: (a) requirements the spec asked for that are missing or partial; (b) behaviour in the diff that wasn't asked for (scope creep); (c) requirements that look implemented but where the implementation looks wrong. Quote the spec line for each finding. Under 400 words." If the spec is missing, skip the Spec sub-agent and note this in the final report. @@ -83,7 +83,7 @@ End with a one-line summary: total findings per axis, and the worst issue _withi A change can pass one axis and fail the other: -- Code that follows every standard but implements the wrong thing → **Standards pass, Spec fail.** -- Code that does exactly what the issue asked but breaks the project's conventions → **Spec pass, Standards fail.** +- Code that follows every standard but implements the wrong thing → **Standards pass, Spec fail.** +- Code that does exactly what the issue asked but breaks the project's conventions → **Spec pass, Standards fail.** Reporting them separately stops one axis from masking the other. diff --git a/.agents/skills/codebase-design/DEEPENING.md b/.agents/skills/codebase-design/DEEPENING.md index 7f73de4d1..a3b75c671 100644 --- a/.agents/skills/codebase-design/DEEPENING.md +++ b/.agents/skills/codebase-design/DEEPENING.md @@ -26,12 +26,12 @@ Third-party services (Stripe, Twilio, etc.) you don't control. The deepened modu ## Seam discipline -- **One adapter means a hypothetical seam. Two adapters means a real one.** Don't introduce a port unless at least two adapters are justified (typically production + test). A single-adapter seam is just indirection. -- **Internal seams vs external seams.** A deep module can have internal seams (private to its implementation, used by its own tests) as well as the external seam at its interface. Don't expose internal seams through the interface just because tests use them. +- **One adapter means a hypothetical seam. Two adapters means a real one.** Don't introduce a port unless at least two adapters are justified (typically production + test). A single-adapter seam is just indirection. +- **Internal seams vs external seams.** A deep module can have internal seams (private to its implementation, used by its own tests) as well as the external seam at its interface. Don't expose internal seams through the interface just because tests use them. ## Testing strategy: replace, don't layer -- Old unit tests on shallow modules become waste once tests at the deepened module's interface exist — delete them. -- Write new tests at the deepened module's interface. The **interface is the test surface**. -- Tests assert on observable outcomes through the interface, not internal state. -- Tests should survive internal refactors — they describe behaviour, not implementation. If a test has to change when the implementation changes, it's testing past the interface. +- Old unit tests on shallow modules become waste once tests at the deepened module's interface exist — delete them. +- Write new tests at the deepened module's interface. The **interface is the test surface**. +- Tests assert on observable outcomes through the interface, not internal state. +- Tests should survive internal refactors — they describe behaviour, not implementation. If a test has to change when the implementation changes, it's testing past the interface. diff --git a/.agents/skills/codebase-design/DESIGN-IT-TWICE.md b/.agents/skills/codebase-design/DESIGN-IT-TWICE.md index 106ab66f8..49a7c42a2 100644 --- a/.agents/skills/codebase-design/DESIGN-IT-TWICE.md +++ b/.agents/skills/codebase-design/DESIGN-IT-TWICE.md @@ -10,9 +10,9 @@ Uses the vocabulary in [SKILL.md](SKILL.md) — **module**, **interface**, **sea Before spawning sub-agents, write a user-facing explanation of the problem space for the chosen candidate: -- The constraints any new interface would need to satisfy -- The dependencies it would rely on, and which category they fall into (see [DEEPENING.md](DEEPENING.md)) -- A rough illustrative code sketch to ground the constraints — not a proposal, just a way to make the constraints concrete +- The constraints any new interface would need to satisfy +- The dependencies it would rely on, and which category they fall into (see [DEEPENING.md](DEEPENING.md)) +- A rough illustrative code sketch to ground the constraints — not a proposal, just a way to make the constraints concrete Show this to the user, then immediately proceed to Step 2. The user reads and thinks while the sub-agents work in parallel. @@ -22,10 +22,10 @@ Spawn 3+ sub-agents in parallel using the Agent tool. Each must produce a **radi Prompt each sub-agent with a separate technical brief (file paths, coupling details, dependency category from [DEEPENING.md](DEEPENING.md), what sits behind the seam). The brief is independent of the user-facing problem-space explanation in Step 1. Give each agent a different design constraint: -- Agent 1: "Minimize the interface — aim for 1–3 entry points max. Maximise leverage per entry point." -- Agent 2: "Maximise flexibility — support many use cases and extension." -- Agent 3: "Optimise for the most common caller — make the default case trivial." -- Agent 4 (if applicable): "Design around ports & adapters for cross-seam dependencies." +- Agent 1: "Minimize the interface — aim for 1–3 entry points max. Maximise leverage per entry point." +- Agent 2: "Maximise flexibility — support many use cases and extension." +- Agent 3: "Optimise for the most common caller — make the default case trivial." +- Agent 4 (if applicable): "Design around ports & adapters for cross-seam dependencies." Include both [SKILL.md](SKILL.md) vocabulary and CONTEXT.md vocabulary in the brief so each sub-agent names things consistently with the architecture language and the project's domain language. diff --git a/.agents/skills/codebase-design/SKILL.md b/.agents/skills/codebase-design/SKILL.md index 0cd34b53c..814e97eb0 100644 --- a/.agents/skills/codebase-design/SKILL.md +++ b/.agents/skills/codebase-design/SKILL.md @@ -53,16 +53,16 @@ Use these terms exactly — don't substitute "component," "service," "API," or " When designing an interface, ask: -- Can I reduce the number of methods? -- Can I simplify the parameters? -- Can I hide more complexity inside? +- Can I reduce the number of methods? +- Can I simplify the parameters? +- Can I hide more complexity inside? ## Principles -- **Depth is a property of the interface, not the implementation.** A deep module can be internally composed of small, mockable, swappable parts — they just aren't part of the interface. A module can have **internal seams** (private to its implementation, used by its own tests) as well as the **external seam** at its interface. -- **The deletion test.** Imagine deleting the module. If complexity vanishes, it was a pass-through. If complexity reappears across N callers, it was earning its keep. -- **The interface is the test surface.** Callers and tests cross the same seam. If you want to test _past_ the interface, the module is probably the wrong shape. -- **One adapter means a hypothetical seam. Two adapters means a real one.** Don't introduce a seam unless something actually varies across it. +- **Depth is a property of the interface, not the implementation.** A deep module can be internally composed of small, mockable, swappable parts — they just aren't part of the interface. A module can have **internal seams** (private to its implementation, used by its own tests) as well as the **external seam** at its interface. +- **The deletion test.** Imagine deleting the module. If complexity vanishes, it was a pass-through. If complexity reappears across N callers, it was earning its keep. +- **The interface is the test surface.** Callers and tests cross the same seam. If you want to test _past_ the interface, the module is probably the wrong shape. +- **One adapter means a hypothetical seam. Two adapters means a real one.** Don't introduce a seam unless something actually varies across it. ## Designing for testability @@ -96,19 +96,19 @@ Good interfaces make testing natural: ## Relationships -- A **Module** has exactly one **Interface** (the surface it presents to callers and tests). -- **Depth** is a property of a **Module**, measured against its **Interface**. -- A **Seam** is where a **Module**'s **Interface** lives. -- An **Adapter** sits at a **Seam** and satisfies the **Interface**. -- **Depth** produces **Leverage** for callers and **Locality** for maintainers. +- A **Module** has exactly one **Interface** (the surface it presents to callers and tests). +- **Depth** is a property of a **Module**, measured against its **Interface**. +- A **Seam** is where a **Module**'s **Interface** lives. +- An **Adapter** sits at a **Seam** and satisfies the **Interface**. +- **Depth** produces **Leverage** for callers and **Locality** for maintainers. ## Rejected framings -- **Depth as ratio of implementation-lines to interface-lines** (Ousterhout): rewards padding the implementation. We use depth-as-leverage instead. -- **"Interface" as the TypeScript `interface` keyword or a class's public methods**: too narrow — interface here includes every fact a caller must know. -- **"Boundary"**: overloaded with DDD's bounded context. Say **seam** or **interface**. +- **Depth as ratio of implementation-lines to interface-lines** (Ousterhout): rewards padding the implementation. We use depth-as-leverage instead. +- **"Interface" as the TypeScript `interface` keyword or a class's public methods**: too narrow — interface here includes every fact a caller must know. +- **"Boundary"**: overloaded with DDD's bounded context. Say **seam** or **interface**. ## Going deeper -- **Deepening a cluster given its dependencies** — see [DEEPENING.md](DEEPENING.md): dependency categories, seam discipline, and replace-don't-layer testing. -- **Exploring alternative interfaces** — see [DESIGN-IT-TWICE.md](DESIGN-IT-TWICE.md): spin up parallel sub-agents to design the interface several radically different ways, then compare on depth, locality, and seam placement. +- **Deepening a cluster given its dependencies** — see [DEEPENING.md](DEEPENING.md): dependency categories, seam discipline, and replace-don't-layer testing. +- **Exploring alternative interfaces** — see [DESIGN-IT-TWICE.md](DESIGN-IT-TWICE.md): spin up parallel sub-agents to design the interface several radically different ways, then compare on depth, locality, and seam placement. diff --git a/.agents/skills/diagnosing-bugs/SKILL.md b/.agents/skills/diagnosing-bugs/SKILL.md index 5c0bfdb54..f400de7c1 100644 --- a/.agents/skills/diagnosing-bugs/SKILL.md +++ b/.agents/skills/diagnosing-bugs/SKILL.md @@ -34,9 +34,9 @@ Build the right feedback loop, and the bug is 90% fixed. Treat the loop as a product. Once you have _a_ loop, **tighten** it: -- Can I make it faster? (Cache setup, skip unrelated init, narrow the test scope.) -- Can I make the signal sharper? (Assert on the specific symptom, not "didn't crash".) -- Can I make it more deterministic? (Pin time, seed RNG, isolate filesystem, freeze network.) +- Can I make it faster? (Cache setup, skip unrelated init, narrow the test scope.) +- Can I make the signal sharper? (Assert on the specific symptom, not "didn't crash".) +- Can I make it more deterministic? (Pin time, seed RNG, isolate filesystem, freeze network.) A 30-second flaky loop is barely better than no loop; a 2-second deterministic one is tight — a debugging superpower. @@ -52,10 +52,10 @@ Stop and say so explicitly. List what you tried. Ask the user for: (a) access to Phase 1 is done when the loop is **tight** and **red-capable**: you can name **one command** — a script path, a test invocation, a curl — that you have **already run at least once** (paste the invocation and its output), and that is: -- [ ] **Red-capable** — it drives the actual bug code path and asserts the **user's exact symptom**, so it can go red on this bug and green once fixed. Not "runs without erroring" — it must be able to _catch this specific bug_. -- [ ] **Deterministic** — same verdict every run (flaky bugs: a pinned, high reproduction rate, per above). -- [ ] **Fast** — seconds, not minutes. -- [ ] **Agent-runnable** — you can run it unattended; a human in the loop only via `scripts/hitl-loop.template.sh`. +- [ ] **Red-capable** — it drives the actual bug code path and asserts the **user's exact symptom**, so it can go red on this bug and green once fixed. Not "runs without erroring" — it must be able to _catch this specific bug_. +- [ ] **Deterministic** — same verdict every run (flaky bugs: a pinned, high reproduction rate, per above). +- [ ] **Fast** — seconds, not minutes. +- [ ] **Agent-runnable** — you can run it unattended; a human in the loop only via `scripts/hitl-loop.template.sh`. If you catch yourself reading code to build a theory before this command exists, **stop — jumping straight to a hypothesis is the exact failure this skill prevents.** No red-capable command, no Phase 2. @@ -65,9 +65,9 @@ Run the loop. Watch it go red — the bug appears. Confirm: -- [ ] The loop produces the failure mode the **user** described — not a different failure that happens to be nearby. Wrong bug = wrong fix. -- [ ] The failure is reproducible across multiple runs (or, for non-deterministic bugs, reproducible at a high enough rate to debug against). -- [ ] You have captured the exact symptom (error message, wrong output, slow timing) so later phases can verify the fix actually addresses it. +- [ ] The loop produces the failure mode the **user** described — not a different failure that happens to be nearby. Wrong bug = wrong fix. +- [ ] The failure is reproducible across multiple runs (or, for non-deterministic bugs, reproducible at a high enough rate to debug against). +- [ ] You have captured the exact symptom (error message, wrong output, slow timing) so later phases can verify the fix actually addresses it. ### Minimise @@ -125,10 +125,10 @@ If a correct seam exists: Required before declaring done: -- [ ] Original repro no longer reproduces (re-run the Phase 1 loop) -- [ ] Regression test passes (or absence of seam is documented) -- [ ] All `[DEBUG-...]` instrumentation removed (`grep` the prefix) -- [ ] Throwaway prototypes deleted (or moved to a clearly-marked debug location) -- [ ] The hypothesis that turned out correct is stated in the commit / PR message — so the next debugger learns +- [ ] Original repro no longer reproduces (re-run the Phase 1 loop) +- [ ] Regression test passes (or absence of seam is documented) +- [ ] All `[DEBUG-...]` instrumentation removed (`grep` the prefix) +- [ ] Throwaway prototypes deleted (or moved to a clearly-marked debug location) +- [ ] The hypothesis that turned out correct is stated in the commit / PR message — so the next debugger learns **Then ask: what would have prevented this bug?** If the answer involves architectural change (no good test seam, tangled callers, hidden coupling) hand off to the `/improve-codebase-architecture` skill with the specifics. Make the recommendation **after** the fix is in, not before — you have more information now than when you started. diff --git a/.agents/skills/domain-modeling/ADR-FORMAT.md b/.agents/skills/domain-modeling/ADR-FORMAT.md index 862f385c7..dc90176fa 100644 --- a/.agents/skills/domain-modeling/ADR-FORMAT.md +++ b/.agents/skills/domain-modeling/ADR-FORMAT.md @@ -18,9 +18,9 @@ That's it. An ADR can be a single paragraph. The value is in recording _that_ a Only include these when they add genuine value. Most ADRs won't need them. -- **Status** frontmatter (`proposed | accepted | deprecated | superseded by ADR-NNNN`) — useful when decisions are revisited -- **Considered Options** — only when the rejected alternatives are worth remembering -- **Consequences** — only when non-obvious downstream effects need to be called out +- **Status** frontmatter (`proposed | accepted | deprecated | superseded by ADR-NNNN`) — useful when decisions are revisited +- **Considered Options** — only when the rejected alternatives are worth remembering +- **Consequences** — only when non-obvious downstream effects need to be called out ## Numbering @@ -38,10 +38,10 @@ If a decision is easy to reverse, skip it — you'll just reverse it. If it's no ### What qualifies -- **Architectural shape.** "We're using a monorepo." "The write model is event-sourced, the read model is projected into Postgres." -- **Integration patterns between contexts.** "Ordering and Billing communicate via domain events, not synchronous HTTP." -- **Technology choices that carry lock-in.** Database, message bus, auth provider, deployment target. Not every library — just the ones that would take a quarter to swap out. -- **Boundary and scope decisions.** "Customer data is owned by the Customer context; other contexts reference it by ID only." The explicit no-s are as valuable as the yes-s. -- **Deliberate deviations from the obvious path.** "We're using manual SQL instead of an ORM because X." Anything where a reasonable reader would assume the opposite. These stop the next engineer from "fixing" something that was deliberate. -- **Constraints not visible in the code.** "We can't use AWS because of compliance requirements." "Response times must be under 200ms because of the partner API contract." -- **Rejected alternatives when the rejection is non-obvious.** If you considered GraphQL and picked REST for subtle reasons, record it — otherwise someone will suggest GraphQL again in six months. +- **Architectural shape.** "We're using a monorepo." "The write model is event-sourced, the read model is projected into Postgres." +- **Integration patterns between contexts.** "Ordering and Billing communicate via domain events, not synchronous HTTP." +- **Technology choices that carry lock-in.** Database, message bus, auth provider, deployment target. Not every library — just the ones that would take a quarter to swap out. +- **Boundary and scope decisions.** "Customer data is owned by the Customer context; other contexts reference it by ID only." The explicit no-s are as valuable as the yes-s. +- **Deliberate deviations from the obvious path.** "We're using manual SQL instead of an ORM because X." Anything where a reasonable reader would assume the opposite. These stop the next engineer from "fixing" something that was deliberate. +- **Constraints not visible in the code.** "We can't use AWS because of compliance requirements." "Response times must be under 200ms because of the partner API contract." +- **Rejected alternatives when the rejection is non-obvious.** If you considered GraphQL and picked REST for subtle reasons, record it — otherwise someone will suggest GraphQL again in six months. diff --git a/.agents/skills/domain-modeling/CONTEXT-FORMAT.md b/.agents/skills/domain-modeling/CONTEXT-FORMAT.md index d1a9e818b..eaf2a1857 100644 --- a/.agents/skills/domain-modeling/CONTEXT-FORMAT.md +++ b/.agents/skills/domain-modeling/CONTEXT-FORMAT.md @@ -24,10 +24,10 @@ _Avoid_: Client, buyer, account ## Rules -- **Be opinionated.** When multiple words exist for the same concept, pick the best one and list the others under `_Avoid_`. -- **Keep definitions tight.** One or two sentences max. Define what it IS, not what it does. -- **Only include terms specific to this project's context.** General programming concepts (timeouts, error types, utility patterns) don't belong even if the project uses them extensively. Before adding a term, ask: is this a concept unique to this context, or a general programming concept? Only the former belongs. -- **Group terms under subheadings** when natural clusters emerge. If all terms belong to a single cohesive area, a flat list is fine. +- **Be opinionated.** When multiple words exist for the same concept, pick the best one and list the others under `_Avoid_`. +- **Keep definitions tight.** One or two sentences max. Define what it IS, not what it does. +- **Only include terms specific to this project's context.** General programming concepts (timeouts, error types, utility patterns) don't belong even if the project uses them extensively. Before adding a term, ask: is this a concept unique to this context, or a general programming concept? Only the former belongs. +- **Group terms under subheadings** when natural clusters emerge. If all terms belong to a single cohesive area, a flat list is fine. ## Single vs multi-context repos @@ -40,21 +40,21 @@ _Avoid_: Client, buyer, account ## Contexts -- [Ordering](./src/ordering/CONTEXT.md) — receives and tracks customer orders -- [Billing](./src/billing/CONTEXT.md) — generates invoices and processes payments -- [Fulfillment](./src/fulfillment/CONTEXT.md) — manages warehouse picking and shipping +- [Ordering](./src/ordering/CONTEXT.md) — receives and tracks customer orders +- [Billing](./src/billing/CONTEXT.md) — generates invoices and processes payments +- [Fulfillment](./src/fulfillment/CONTEXT.md) — manages warehouse picking and shipping ## Relationships -- **Ordering → Fulfillment**: Ordering emits `OrderPlaced` events; Fulfillment consumes them to start picking -- **Fulfillment → Billing**: Fulfillment emits `ShipmentDispatched` events; Billing consumes them to generate invoices -- **Ordering ↔ Billing**: Shared types for `CustomerId` and `Money` +- **Ordering → Fulfillment**: Ordering emits `OrderPlaced` events; Fulfillment consumes them to start picking +- **Fulfillment → Billing**: Fulfillment emits `ShipmentDispatched` events; Billing consumes them to generate invoices +- **Ordering ↔ Billing**: Shared types for `CustomerId` and `Money` ``` The skill infers which structure applies: -- If `CONTEXT-MAP.md` exists, read it to find contexts -- If only a root `CONTEXT.md` exists, single context -- If neither exists, create a root `CONTEXT.md` lazily when the first term is resolved +- If `CONTEXT-MAP.md` exists, read it to find contexts +- If only a root `CONTEXT.md` exists, single context +- If neither exists, create a root `CONTEXT.md` lazily when the first term is resolved When multiple contexts exist, infer which one the current topic relates to. If unclear, ask. diff --git a/.agents/skills/improve-codebase-architecture/HTML-REPORT.md b/.agents/skills/improve-codebase-architecture/HTML-REPORT.md index a0ef381d0..568b0a431 100644 --- a/.agents/skills/improve-codebase-architecture/HTML-REPORT.md +++ b/.agents/skills/improve-codebase-architecture/HTML-REPORT.md @@ -53,14 +53,14 @@ The diagrams carry the weight. Prose is sparse, plain, and uses the glossary ter Each candidate is one `
`: -- **Title** — short, names the deepening (e.g. "Collapse the Order intake pipeline"). -- **Badge row** — recommendation strength (`Strong` = emerald, `Worth exploring` = amber, `Speculative` = slate), plus a tag for the dependency category (`in-process`, `local-substitutable`, `ports & adapters`, `mock`). -- **Files** — monospaced list, `font-mono text-sm`. -- **Before / After diagram** — the centrepiece. Two columns, side by side. See patterns below. -- **Problem** — one sentence. What hurts. -- **Solution** — one sentence. What changes. -- **Wins** — bullets, ≤6 words each. e.g. "Tests hit one interface", "Pricing logic stops leaking", "Delete 4 shallow wrappers". -- **ADR callout** (if applicable) — one line in an amber-tinted box. +- **Title** — short, names the deepening (e.g. "Collapse the Order intake pipeline"). +- **Badge row** — recommendation strength (`Strong` = emerald, `Worth exploring` = amber, `Speculative` = slate), plus a tag for the dependency category (`in-process`, `local-substitutable`, `ports & adapters`, `mock`). +- **Files** — monospaced list, `font-mono text-sm`. +- **Before / After diagram** — the centrepiece. Two columns, side by side. See patterns below. +- **Problem** — one sentence. What hurts. +- **Solution** — one sentence. What changes. +- **Wins** — bullets, ≤6 words each. e.g. "Tests hit one interface", "Pricing logic stops leaking", "Delete 4 shallow wrappers". +- **ADR callout** (if applicable) — one line in an amber-tinted box. No paragraphs of explanation. If the diagram needs a paragraph to be understood, redraw the diagram. @@ -81,8 +81,7 @@ Use a Mermaid `flowchart` or `graph` when the point is "X calls Y calls Z, and l C -.leak.-> D[PricingClient] classDef leak stroke:#dc2626,stroke-width:2px; class C,D leak - +
``` @@ -104,11 +103,11 @@ Before: a tree of function calls rendered as nested boxes. After: the same tree ## Style guidance -- Lean editorial, not corporate-dashboard. Generous whitespace. Serif optional for headings (`font-serif` works well with stone/slate). -- Colour sparingly: one accent (emerald or indigo) plus red for leakage and amber for warnings. -- Keep diagrams ~320px tall so before/after sits comfortably side by side without scrolling. -- Use `text-xs uppercase tracking-wider` for module labels inside diagrams — they should read as schematic, not as UI. -- The only scripts are the Tailwind CDN and the Mermaid ESM import. The report is otherwise static — no app code, no interactivity beyond Mermaid's own rendering. +- Lean editorial, not corporate-dashboard. Generous whitespace. Serif optional for headings (`font-serif` works well with stone/slate). +- Colour sparingly: one accent (emerald or indigo) plus red for leakage and amber for warnings. +- Keep diagrams ~320px tall so before/after sits comfortably side by side without scrolling. +- Use `text-xs uppercase tracking-wider` for module labels inside diagrams — they should read as schematic, not as UI. +- The only scripts are the Tailwind CDN and the Mermaid ESM import. The report is otherwise static — no app code, no interactivity beyond Mermaid's own rendering. ## Top recommendation section @@ -124,10 +123,10 @@ Plain English, concise — but the architectural nouns and verbs come straight f **Phrasings that fit the style:** -- "Order intake module is shallow — interface nearly matches the implementation." -- "Pricing leaks across the seam." -- "Deepen: one interface, one place to test." -- "Two adapters justify the seam: HTTP in prod, in-memory in tests." +- "Order intake module is shallow — interface nearly matches the implementation." +- "Pricing leaks across the seam." +- "Deepen: one interface, one place to test." +- "Two adapters justify the seam: HTTP in prod, in-memory in tests." **Wins bullets** name the gain in glossary terms: _"locality: bugs concentrate in one module"_, _"leverage: one interface, N call sites"_, _"interface shrinks; implementation absorbs the wrappers"_. Don't write _"easier to maintain"_ or _"cleaner code"_ — those terms aren't in the glossary and don't earn their place. diff --git a/.agents/skills/improve-codebase-architecture/SKILL.md b/.agents/skills/improve-codebase-architecture/SKILL.md index a84b66825..a7a5954fd 100644 --- a/.agents/skills/improve-codebase-architecture/SKILL.md +++ b/.agents/skills/improve-codebase-architecture/SKILL.md @@ -10,8 +10,8 @@ Surface architectural friction and propose **deepening opportunities** — refac This command is _informed_ by the project's domain model and built on a shared design vocabulary: -- Run the `/codebase-design` skill for the architecture vocabulary (**module**, **interface**, **depth**, **seam**, **adapter**, **leverage**, **locality**) and its principles (the deletion test, "the interface is the test surface", "one adapter = hypothetical seam, two = real"). Use these terms exactly in every suggestion — don't drift into "component," "service," "API," or "boundary." -- The domain language in `CONTEXT.md` gives names to good seams; ADRs in `docs/adr/` record decisions this command should not re-litigate. +- Run the `/codebase-design` skill for the architecture vocabulary (**module**, **interface**, **depth**, **seam**, **adapter**, **leverage**, **locality**) and its principles (the deletion test, "the interface is the test surface", "one adapter = hypothetical seam, two = real"). Use these terms exactly in every suggestion — don't drift into "component," "service," "API," or "boundary." +- The domain language in `CONTEXT.md` gives names to good seams; ADRs in `docs/adr/` record decisions this command should not re-litigate. ## Process @@ -19,18 +19,18 @@ This command is _informed_ by the project's domain model and built on a shared d **Scope before you scan — YAGNI.** Deepening a module pays off by making future changes to it easier, so put extra weight on the parts of the codebase that have recently changed. Decide _where_ to look before you look: -- If the user named a direction — a module, a subsystem, a pain point — take it, and skip the inference below. -- Otherwise, walk back a good stretch of the commit history (`git log --oneline`) to find the codebase's hot spots — the files and areas that keep coming up — and let those paths pull your attention first. If the changes are scattered with no clear hot spot, widen the net. +- If the user named a direction — a module, a subsystem, a pain point — take it, and skip the inference below. +- Otherwise, walk back a good stretch of the commit history (`git log --oneline`) to find the codebase's hot spots — the files and areas that keep coming up — and let those paths pull your attention first. If the changes are scattered with no clear hot spot, widen the net. Read the project's domain glossary (`CONTEXT.md`) and any ADRs in the area you're touching first. Then use the Agent tool with `subagent_type=Explore` to walk the codebase. Don't follow rigid heuristics — explore organically and note where you experience friction: -- Where does understanding one concept require bouncing between many small modules? -- Where are modules **shallow** — interface nearly as complex as the implementation? -- Where have pure functions been extracted just for testability, but the real bugs hide in how they're called (no **locality**)? -- Where do tightly-coupled modules leak across their seams? -- Which parts of the codebase are untested, or hard to test through their current interface? +- Where does understanding one concept require bouncing between many small modules? +- Where are modules **shallow** — interface nearly as complex as the implementation? +- Where have pure functions been extracted just for testability, but the real bugs hide in how they're called (no **locality**)? +- Where do tightly-coupled modules leak across their seams? +- Which parts of the codebase are untested, or hard to test through their current interface? Apply the **deletion test** to anything you suspect is shallow: would deleting it concentrate complexity, or just move it? A "yes, concentrates" is the signal you want. @@ -42,12 +42,12 @@ The report uses **Tailwind via CDN** for layout and styling, and **Mermaid via C For each candidate, render a card with: -- **Files** — which files/modules are involved -- **Problem** — why the current architecture is causing friction -- **Solution** — plain English description of what would change -- **Benefits** — explained in terms of locality and leverage, and how tests would improve -- **Before / After diagram** — side-by-side, custom-drawn, illustrating the shallowness and the deepening -- **Recommendation strength** — one of `Strong`, `Worth exploring`, `Speculative`, rendered as a badge +- **Files** — which files/modules are involved +- **Problem** — why the current architecture is causing friction +- **Solution** — plain English description of what would change +- **Benefits** — explained in terms of locality and leverage, and how tests would improve +- **Before / After diagram** — side-by-side, custom-drawn, illustrating the shallowness and the deepening +- **Recommendation strength** — one of `Strong`, `Worth exploring`, `Speculative`, rendered as a badge End the report with a **Top recommendation** section: which candidate you'd tackle first and why. @@ -65,7 +65,7 @@ Once the user picks a candidate, run the `/grilling` skill to walk the decision Side effects happen inline as decisions crystallize — run the `/domain-modeling` skill to keep the domain model current as you go: -- **Naming a deepened module after a concept not in `CONTEXT.md`?** Add the term to `CONTEXT.md`. Create the file lazily if it doesn't exist. -- **Sharpening a fuzzy term during the conversation?** Update `CONTEXT.md` right there. -- **User rejects the candidate with a load-bearing reason?** Offer an ADR, framed as: _"Want me to record this as an ADR so future architecture reviews don't re-suggest it?"_ Only offer when the reason would actually be needed by a future explorer to avoid re-suggesting the same thing — skip ephemeral reasons ("not worth it right now") and self-evident ones. -- **Want to explore alternative interfaces for the deepened module?** Run the `/codebase-design` skill and use its design-it-twice parallel sub-agent pattern. +- **Naming a deepened module after a concept not in `CONTEXT.md`?** Add the term to `CONTEXT.md`. Create the file lazily if it doesn't exist. +- **Sharpening a fuzzy term during the conversation?** Update `CONTEXT.md` right there. +- **User rejects the candidate with a load-bearing reason?** Offer an ADR, framed as: _"Want me to record this as an ADR so future architecture reviews don't re-suggest it?"_ Only offer when the reason would actually be needed by a future explorer to avoid re-suggesting the same thing — skip ephemeral reasons ("not worth it right now") and self-evident ones. +- **Want to explore alternative interfaces for the deepened module?** Run the `/codebase-design` skill and use its design-it-twice parallel sub-agent pattern. diff --git a/.agents/skills/prototype/LOGIC.md b/.agents/skills/prototype/LOGIC.md index d16e77e2c..f83724469 100644 --- a/.agents/skills/prototype/LOGIC.md +++ b/.agents/skills/prototype/LOGIC.md @@ -4,10 +4,10 @@ A tiny interactive terminal app that lets the user drive a state model by hand. ## When this is the right shape -- "I'm not sure if this state machine handles the edge case where X then Y." -- "Does this data model actually let me represent the case where..." -- "I want to feel out what the API should look like before writing it." -- Anything where the user wants to **press buttons and watch state change**. +- "I'm not sure if this state machine handles the edge case where X then Y." +- "Does this data model actually let me represent the case where..." +- "I want to feel out what the API should look like before writing it." +- Anything where the user wants to **press buttons and watch state change**. If the question is "what should this look like" — wrong branch. Use [UI.md](UI.md). @@ -29,10 +29,10 @@ Put the actual logic — the bit that's answering the question — behind a smal The right shape depends on the question: -- **A pure reducer** — `(state, action) => state`. Good when actions are discrete events and state is a single value. -- **A state machine** — explicit states and transitions. Good when "which actions are even legal right now" is part of the question. -- **A small set of pure functions** over a plain data type. Good when there's no implicit current state — just transformations. -- **A class or module with a clear method surface** when the logic genuinely owns ongoing internal state. +- **A pure reducer** — `(state, action) => state`. Good when actions are discrete events and state is a single value. +- **A state machine** — explicit states and transitions. Good when "which actions are even legal right now" is part of the question. +- **A small set of pure functions** over a plain data type. Good when there's no implicit current state — just transformations. +- **A class or module with a clear method surface** when the logic genuinely owns ongoing internal state. Pick whichever shape best fits the question being asked, _not_ whichever is easiest to wire to a TUI. Keep it pure: no I/O, no terminal code, no `console.log` for control flow. The TUI imports it and calls into it; nothing flows the other direction. @@ -72,8 +72,8 @@ Once the prototype has answered its question, capture the answer, then capture t ## Anti-patterns -- **Don't add tests.** A prototype that needs tests is no longer a prototype. -- **Don't wire it to the real database.** Use an in-memory store unless the question is specifically about persistence. -- **Don't generalise.** No "what if we wanted to support X later." The prototype answers one question. -- **Don't blur the logic and the TUI together.** If the reducer / state machine references `console.log`, prompts, or terminal escape codes, it's no longer portable. Keep the TUI as a thin shell over a pure module. -- **Don't ship the TUI shell into production.** The shell is optimised for being driven by hand from a terminal. The logic module behind it is the bit worth keeping. +- **Don't add tests.** A prototype that needs tests is no longer a prototype. +- **Don't wire it to the real database.** Use an in-memory store unless the question is specifically about persistence. +- **Don't generalise.** No "what if we wanted to support X later." The prototype answers one question. +- **Don't blur the logic and the TUI together.** If the reducer / state machine references `console.log`, prompts, or terminal escape codes, it's no longer portable. Keep the TUI as a thin shell over a pure module. +- **Don't ship the TUI shell into production.** The shell is optimised for being driven by hand from a terminal. The logic module behind it is the bit worth keeping. diff --git a/.agents/skills/prototype/SKILL.md b/.agents/skills/prototype/SKILL.md index 5f5ff323c..e75d5331c 100644 --- a/.agents/skills/prototype/SKILL.md +++ b/.agents/skills/prototype/SKILL.md @@ -11,8 +11,8 @@ A prototype is **throwaway code that answers a question**. The question decides Identify which question is being answered — from the user's prompt, the surrounding code, or by asking if the user is around: -- **"Does this logic / state model feel right?"** → [LOGIC.md](LOGIC.md). Build a tiny interactive terminal app that pushes the state machine through cases that are hard to reason about on paper. -- **"What should this look like?"** → [UI.md](UI.md). Generate several radically different UI variations on a single route, switchable via a URL search param and a floating bottom bar. +- **"Does this logic / state model feel right?"** → [LOGIC.md](LOGIC.md). Build a tiny interactive terminal app that pushes the state machine through cases that are hard to reason about on paper. +- **"What should this look like?"** → [UI.md](UI.md). Generate several radically different UI variations on a single route, switchable via a URL search param and a floating bottom bar. The two branches produce very different artifacts — getting this wrong wastes the whole prototype. If the question is genuinely ambiguous and the user isn't reachable, default to whichever branch better matches the surrounding code (a backend module → logic; a page or component → UI) and state the assumption at the top of the prototype. diff --git a/.agents/skills/prototype/UI.md b/.agents/skills/prototype/UI.md index 5c9154b74..e6b73ab24 100644 --- a/.agents/skills/prototype/UI.md +++ b/.agents/skills/prototype/UI.md @@ -6,10 +6,10 @@ If the question is about logic/state rather than what something looks like — w ## When this is the right shape -- "What should this page look like?" -- "I want to see a few options for this dashboard before committing." -- "Try a different layout for the settings screen." -- Any time the user would otherwise spend a day picking between three vague mockups in their head. +- "What should this page look like?" +- "I want to see a few options for this dashboard before committing." +- "Try a different layout for the settings screen." +- Any time the user would otherwise spend a day picking between three vague mockups in their head. ## Two sub-shapes — strongly prefer sub-shape A @@ -47,9 +47,9 @@ This works whether the user is here to push back or not. Draft each variant. Hold each one to: -- The page's purpose and the data it has access to. -- The project's component library / styling system (TailwindCSS, shadcn, MUI, plain CSS, whatever). -- A clear exported component name, e.g. `VariantA`, `VariantB`, `VariantC`. +- The page's purpose and the data it has access to. +- The project's component library / styling system (TailwindCSS, shadcn, MUI, plain CSS, whatever). +- A clear exported component name, e.g. `VariantA`, `VariantB`, `VariantC`. Variants must be **structurally different** — different layout, different information hierarchy, different primary affordance, not just different colours. Three slightly-tweaked card grids isn't a UI prototype, it's wallpaper. If two drafts come out too similar, redo one with explicit "do not use a card grid" guidance. @@ -78,16 +78,16 @@ For sub-shape B (new page): the throwaway route under `/prototype/` mounts A small fixed-position bar at the bottom-centre of the screen with three pieces: -- **Left arrow** — cycles to the previous variant (wraps around). -- **Variant label** — shows the current variant key and, if the variant exports a name, that name too. e.g. `B — Sidebar layout`. -- **Right arrow** — cycles forward (wraps around). +- **Left arrow** — cycles to the previous variant (wraps around). +- **Variant label** — shows the current variant key and, if the variant exports a name, that name too. e.g. `B — Sidebar layout`. +- **Right arrow** — cycles forward (wraps around). Behaviour: -- Clicking an arrow updates the URL search param (use the framework's router — `router.replace` on Next, `navigate` on React Router, etc) so the variant is shareable and reload-stable. -- Keyboard: `←` and `→` arrow keys also cycle. Don't intercept arrow keys when an ``, `